Skip to content

Commit

Permalink
fix(core): unparse ovverrids for command line output
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukasz Gawrys authored and Lukasz Gawrys committed Oct 14, 2022
1 parent 9788393 commit a3f7e0c
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,11 @@ export async function createRunManyDynamicOutputRenderer({
);
Object.entries(overrides)
.map(([flag, value]) =>
output.dim.cyan(formatFlags(leftPadding, flag, value))
formatFlags(leftPadding, flag, value).map((flag) =>
output.dim.cyan(flag)
)
)
.forEach((arg) => taskOverridesRows.push(arg));
.forEach((arg) => taskOverridesRows.push(...arg));
}

const pinnedFooterLines = [
Expand Down Expand Up @@ -340,9 +342,11 @@ export async function createRunManyDynamicOutputRenderer({
);
Object.entries(overrides)
.map(([flag, value]) =>
output.dim.green(formatFlags(leftPadding, flag, value))
formatFlags(leftPadding, flag, value).map((flag) =>
output.dim.green(flag)
)
)
.forEach((arg) => taskOverridesRows.push(arg));
.forEach((arg) => taskOverridesRows.push(...arg));
}

const pinnedFooterLines = [
Expand Down Expand Up @@ -379,9 +383,11 @@ export async function createRunManyDynamicOutputRenderer({
);
Object.entries(overrides)
.map(([flag, value]) =>
output.dim.red(formatFlags(leftPadding, flag, value))
formatFlags(leftPadding, flag, value).map((flag) =>
output.dim.red(flag)
)
)
.forEach((arg) => taskOverridesRows.push(arg));
.forEach((arg) => taskOverridesRows.push(...arg));
}

const numFailedToPrint = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,11 @@ export async function createRunOneDynamicOutputRenderer({
);
Object.entries(overrides)
.map(([flag, value]) =>
output.dim.green(formatFlags(leftPadding, flag, value))
formatFlags(leftPadding, flag, value).map((flag) =>
output.dim.green(flag)
)
)
.forEach((arg) => taskOverridesLines.push(arg));
.forEach((arg) => taskOverridesLines.push(...arg));
}

const pinnedFooterLines = [
Expand Down Expand Up @@ -330,9 +332,11 @@ export async function createRunOneDynamicOutputRenderer({
);
Object.entries(overrides)
.map(([flag, value]) =>
output.dim.red(formatFlags(leftPadding, flag, value))
formatFlags(leftPadding, flag, value).map((flag) =>
output.dim.red(flag)
)
)
.forEach((arg) => taskOverridesLines.push(arg));
.forEach((arg) => taskOverridesLines.push(...arg));
}

renderLines(
Expand Down
48 changes: 26 additions & 22 deletions packages/nx/src/tasks-runner/life-cycles/formatting-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,47 @@ import { formatFlags } from './formatting-utils';

describe('formatFlags', () => {
it('should properly show string values', () => {
expect(formatFlags('', 'myflag', 'myvalue')).toBe(' --myflag=myvalue');
expect(formatFlags('', 'myflag', 'myvalue')).toStrictEqual([
' --myflag=myvalue',
]);
});
it('should properly show number values', () => {
expect(formatFlags('', 'myflag', 123)).toBe(' --myflag=123');
expect(formatFlags('', 'myflag', 123)).toStrictEqual([' --myflag=123']);
});
it('should properly show boolean values', () => {
expect(formatFlags('', 'myflag', true)).toBe(' --myflag=true');
expect(formatFlags('', 'myflag', true)).toStrictEqual([' --myflag']);
});
it('should properly show array values', () => {
expect(formatFlags('', 'myflag', [1, 23, 'abc'])).toBe(
' --myflag=[1,23,abc]'
);
expect(formatFlags('', 'myflag', [1, 23, 'abc'])).toStrictEqual([
' --myflag=1',
' --myflag=23',
' --myflag=abc',
]);
});
it('should properly show object values', () => {
expect(formatFlags('', 'myflag', { abc: 'def', ghi: { jkl: 42 } })).toBe(
' --myflag={"abc":"def","ghi":{"jkl":42}}'
);
expect(
formatFlags('', 'myflag', { abc: 'def', ghi: { jkl: 42 } })
).toStrictEqual([' --myflag.abc=def', ' --myflag.ghi.jkl=42']);
});
it('should not break on invalid inputs', () => {
expect(formatFlags('', 'myflag', (abc) => abc)).toBe(
' --myflag=(abc) => abc'
);
expect(formatFlags('', 'myflag', NaN)).toBe(' --myflag=NaN');
expect(formatFlags('', 'myflag', (abc) => abc)).toStrictEqual([
' --myflag=(abc) => abc',
]);
expect(formatFlags('', 'myflag', NaN)).toStrictEqual([' --myflag=NaN']);
});
it('should decompose positional values', () => {
expect(formatFlags('', '_', ['foo', 'bar', 42, 'baz'])).toBe(
' foo bar 42 baz'
);
expect(formatFlags('', '_', ['foo', 'bar', 42, 'baz'])).toStrictEqual([
' foo bar 42 baz',
]);
});
it('should handle indentation', () => {
expect(formatFlags('_____', 'myflag', 'myvalue')).toBe(
'_____ --myflag=myvalue'
);
expect(formatFlags('_____', 'myflag', 'myvalue')).toStrictEqual([
'_____ --myflag=myvalue',
]);
});
it('should handle indentation with positionals', () => {
expect(formatFlags('_____', '_', ['foo', 'bar', 42, 'baz'])).toBe(
'_____ foo bar 42 baz'
);
expect(formatFlags('_____', '_', ['foo', 'bar', 42, 'baz'])).toStrictEqual([
'_____ foo bar 42 baz',
]);
});
});
22 changes: 9 additions & 13 deletions packages/nx/src/tasks-runner/life-cycles/formatting-utils.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { serializeSingleOverride } from 'nx/src/utils/serialize-overrides-into-command-line';

export function formatFlags(
leftPadding: string,
flag: string,
value: any
): string {
return flag == '_'
? `${leftPadding} ${(value as string[]).join(' ')}`
: `${leftPadding} --${flag}=${formatValue(value)}`;
}

function formatValue(value: any) {
if (Array.isArray(value)) {
return `[${value.join(',')}]`;
} else if (typeof value === 'object') {
return JSON.stringify(value);
} else {
return value;
): string[] {
if (flag === '_') {
return [`${leftPadding} ${(value as string[]).join(' ')}`];
}

return serializeSingleOverride(flag, value).map(
(s) => `${leftPadding} ${s}`
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle {
bodyLines.push(`${output.dim('With additional flags:')}`);
Object.entries(this.taskOverrides)
.map(([flag, value]) => formatFlags('', flag, value))
.forEach((arg) => bodyLines.push(arg));
.forEach((arg) => bodyLines.push(...arg));
}

let title = `Running target ${output.bold(
Expand Down
57 changes: 49 additions & 8 deletions packages/nx/src/utils/command-line-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,42 @@ describe('splitArgs', () => {
});
});

it('should split non nx specific arguments into target args', () => {
it('should split non nx specific arguments into target args (with boolean args)', () => {
expect(
splitArgsIntoNxArgsAndOverrides(
{
files: [''],
notNxArg: true,
notNxArgObject: { objectKey: 'my value' },
firstNotNxArg: true,
secondNotNxArg: false,
__positional_overrides__: [],
$0: '',
},
'affected',
{} as any,
{} as any
).overrides
).toEqual({
__overrides_unparsed__: ['--firstNotNxArg', '--no-secondNotNxArg'],
firstNotNxArg: true,
secondNotNxArg: false,
});
});

it('should split non nx specific arguments into target args (with object args)', () => {
expect(
splitArgsIntoNxArgsAndOverrides(
{
files: [''],
firstNotNxArgObject: { firstKey: 'first', secondKey: 'second' },
secondNotNxArgObject: {
firstObjectKey: {
firstNestedKey: 'nested value',
},
secondObjectKey: {
secondNestedKey: 'nested value2',
},
},
notNxArgArray: ['item1', 'item2'],
__positional_overrides__: [],
$0: '',
},
Expand All @@ -109,11 +138,23 @@ describe('splitArgs', () => {
).overrides
).toEqual({
__overrides_unparsed__: [
'--notNxArg=true',
'--notNxArgObject={"objectKey":"my value"}',
'--firstNotNxArgObject.firstKey=first',
'--firstNotNxArgObject.secondKey=second',
'--secondNotNxArgObject.firstObjectKey.firstNestedKey="nested value"',
'--secondNotNxArgObject.secondObjectKey.secondNestedKey="nested value2"',
'--notNxArgArray=item1',
'--notNxArgArray=item2',
],
notNxArg: true,
notNxArgObject: { objectKey: 'my value' },
firstNotNxArgObject: { firstKey: 'first', secondKey: 'second' },
secondNotNxArgObject: {
firstObjectKey: {
firstNestedKey: 'nested value',
},
secondObjectKey: {
secondNestedKey: 'nested value2',
},
},
notNxArgArray: ['item1', 'item2'],
});
});

Expand All @@ -132,7 +173,7 @@ describe('splitArgs', () => {
).overrides
).toEqual({
_: ['positional'],
__overrides_unparsed__: ['positional', '--notNxArg=true'],
__overrides_unparsed__: ['positional', '--notNxArg'],
notNxArg: true,
});
});
Expand Down
53 changes: 42 additions & 11 deletions packages/nx/src/utils/serialize-overrides-into-command-line.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
import { flatten } from 'flat';

export function serializeOverridesIntoCommandLine(args: {
[k: string]: any;
}): string[] {
const r = args['_'] ? [...args['_']] : [];
Object.keys(args).forEach((a) => {
if (a !== '_') {
r.push(
typeof args[a] === 'string' && args[a].includes(' ')
? `--${a}="${args[a].replace(/"/g, '"')}"`
: `--${a}=${
typeof args[a] === 'object' ? JSON.stringify(args[a]) : args[a]
}`
);
}
});

Object.keys(args)
.filter((a) => a !== '_')
.forEach((a) => r.push(...serializeSingleOverride(a, args[a])));

return r;
}

export function serializeSingleOverride(key: string, value: any): string[] {
if (value === true) {
return [`--${key}`];
} else if (value === false) {
return [`--no-${key}`];
} else if (Array.isArray(value)) {
return value
.map((item) => serializeSingleOverride(key, item))
.flat() as string[];
} else if (typeof value === 'object') {
const flattened = flatten<any, any>(value, { safe: true });

return Object.keys(flattened)
.map((flattenedKey) => {
return serializeSingleOverride(
`${key}.${flattenedKey}`,
flattened[flattenedKey]
);
})
.flat();
} else if (
typeof value === 'string' &&
stringShouldBeWrappedIntoQuotes(value)
) {
const sanitized = value.replace(/"/g, String.raw`\"`);
return [`--${key}="${sanitized}"`];
} else if (value != null) {
return [`--${key}=${value}`];
}
}

function stringShouldBeWrappedIntoQuotes(str: string) {
return str.includes(' ') || str.includes('{') || str.includes('"');
}

0 comments on commit a3f7e0c

Please sign in to comment.