mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-25 17:57:06 +00:00
fix: skip Docker Compose $$ escaped variables in Anatomy parser (#1450)
The Anatomy view's interpolation regex did not skip Compose's $$ escape
syntax, so $${VAR} (a literal, not a reference) was incorrectly flagged as
a missing variable. Add the (?<!\$) negative lookbehind that the backend
parser already uses, matching its behaviour.
This commit is contained in:
@@ -56,6 +56,17 @@ describe('parseAnatomy', () => {
|
|||||||
expect(a.referencedVars).not.toContain('HAS');
|
expect(a.referencedVars).not.toContain('HAS');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('skips the $${ESCAPED} literal (Compose escape)', () => {
|
||||||
|
const a = parseAnatomy('services:\n app:\n image: x\n labels:\n - template=$${ESCAPED}\n')!;
|
||||||
|
expect(a.referencedVars).not.toContain('ESCAPED');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips $$ escaped vars but still catches real interpolations', () => {
|
||||||
|
const a = parseAnatomy('services:\n app:\n image: x\n environment:\n - A=${REAL}\n - B=$${ESCAPED}\n')!;
|
||||||
|
expect(a.referencedVars).toContain('REAL');
|
||||||
|
expect(a.referencedVars).not.toContain('ESCAPED');
|
||||||
|
});
|
||||||
|
|
||||||
it('marks container-only short-form ports as not published', () => {
|
it('marks container-only short-form ports as not published', () => {
|
||||||
const a = parseAnatomy('services:\n web:\n image: x\n ports:\n - "80"\n')!;
|
const a = parseAnatomy('services:\n web:\n image: x\n ports:\n - "80"\n')!;
|
||||||
expect(a.ports.web).toEqual([{ host: '80', container: '80', proto: 'tcp', published: false }]);
|
expect(a.ports.web).toEqual([{ host: '80', container: '80', proto: 'tcp', published: false }]);
|
||||||
@@ -143,6 +154,18 @@ describe('assembleAnatomyInput', () => {
|
|||||||
expect(input.gitSource).toBe('github.com/acme/plex#main');
|
expect(input.gitSource).toBe('github.com/acme/plex#main');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('excludes $$ escaped vars from missingVars while real refs still appear', () => {
|
||||||
|
const input = assembleAnatomyInput({
|
||||||
|
stackName: 'test',
|
||||||
|
content: 'services:\n app:\n image: x\n labels:\n - template=$${ESCAPED}\n environment:\n - TOKEN=${REAL}\n',
|
||||||
|
envContent: '',
|
||||||
|
selectedEnvFile: null,
|
||||||
|
gitSource: null,
|
||||||
|
})!;
|
||||||
|
expect(input.missingVars).toContain('REAL');
|
||||||
|
expect(input.missingVars).not.toContain('ESCAPED');
|
||||||
|
});
|
||||||
|
|
||||||
it('returns null when compose cannot be parsed', () => {
|
it('returns null when compose cannot be parsed', () => {
|
||||||
expect(assembleAnatomyInput({
|
expect(assembleAnatomyInput({
|
||||||
stackName: 's', content: '', envContent: '', selectedEnvFile: null, gitSource: null,
|
stackName: 's', content: '', envContent: '', selectedEnvFile: null, gitSource: null,
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ export interface Anatomy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Matches ${VAR}, ${VAR:-default}, ${VAR-default}, ${VAR:?err}, ${VAR?err}.
|
// Matches ${VAR}, ${VAR:-default}, ${VAR-default}, ${VAR:?err}, ${VAR?err}.
|
||||||
|
// The leading (?<!\$) skips Compose's `$${VAR}` escape (a literal, not a ref).
|
||||||
// Capture group 1 is the variable name, group 2 (optional) is the modifier form.
|
// Capture group 1 is the variable name, group 2 (optional) is the modifier form.
|
||||||
const INTERPOLATION_REGEX = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-?])[^}]*)?\}/g;
|
const INTERPOLATION_REGEX = /(?<!\$)\$\{([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-?])[^}]*)?\}/g;
|
||||||
|
|
||||||
function parsePortMapping(raw: unknown): PortRow | null {
|
function parsePortMapping(raw: unknown): PortRow | null {
|
||||||
if (typeof raw === 'string') {
|
if (typeof raw === 'string') {
|
||||||
|
|||||||
Reference in New Issue
Block a user