Skip to content

Commit

Permalink
fix(core): parse aliases in target configuration and coerce aliased o…
Browse files Browse the repository at this point in the history
…ptions (#6705)
  • Loading branch information
FrozenPandaz committed Aug 17, 2021
1 parent c3dc161 commit c86eec7
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 23 deletions.
191 changes: 191 additions & 0 deletions packages/tao/src/shared/params.spec.ts
Expand Up @@ -3,6 +3,7 @@ import { logger } from './logger';
import {
applyVerbosity,
coerceTypesInOptions,
combineOptionsForExecutor,
convertAliases,
convertSmartDefaultsIntoNamedParams,
convertToCamelCase,
Expand All @@ -12,8 +13,185 @@ import {
validateOptsAgainstSchema,
warnDeprecations,
} from './params';
import { TargetConfiguration } from './workspace';

describe('params', () => {
describe('combineOptionsForExecutor', () => {
let schema: Schema;
beforeEach(() => {
schema = {
properties: {
overriddenOpt: {
type: 'string',
alias: 'overriddenOptAlias',
},
},
};
});

it('should use target options', () => {
const commandLineOpts = {};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
options: {
overriddenOpt: 'target value',
},
configurations: {
production: {},
},
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({
overriddenOpt: 'target value',
});
});

it('should combine target, configuration', () => {
const commandLineOpts = {};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
options: {
overriddenOpt: 'target value',
},
configurations: {
production: {
overriddenOpt: 'config value',
},
},
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({
overriddenOpt: 'config value',
});
});

it('should combine target, configuration, and passed options', () => {
const commandLineOpts = {
overriddenOpt: 'command value',
};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
options: {
overriddenOpt: 'target value',
},
configurations: {
production: {
overriddenOpt: 'config value',
},
},
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({
overriddenOpt: 'command value',
});
});

it('should convert aliases in target configuration', () => {
const commandLineOpts = {
overriddenOpt: 'command value',
};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
options: {
overriddenOptAlias: 'target value',
},
configurations: {
production: {
overriddenOptAlias: 'config value',
},
},
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({
overriddenOpt: 'command value',
});
});

it('should convert aliases in command line arguments', () => {
const commandLineOpts = {
overriddenOptAlias: 'command value',
};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
options: {
overriddenOpt: 'target value',
},
configurations: {
production: {
overriddenOpt: 'config value',
},
},
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({
overriddenOpt: 'command value',
});
});

it('should handle targets without options', () => {
const commandLineOpts = {};
const target: TargetConfiguration = {
executor: '@nrwl/do:stuff',
};

const options = combineOptionsForExecutor(
commandLineOpts,
'production',
target,
schema,
'proj',
process.cwd()
);

expect(options).toEqual({});
});
});

describe('coerceTypes', () => {
it('should handle booleans', () => {
const opts = coerceTypesInOptions(
Expand Down Expand Up @@ -78,6 +256,19 @@ describe('params', () => {
});
});

it('should handle options with aliases', () => {
const schema: Schema = {
properties: {
name: { type: 'array', alias: 'n' },
},
};
const opts = coerceTypesInOptions({ n: 'one,two' }, schema);

expect(opts).toEqual({
n: ['one', 'two'],
});
});

it('should handle oneOf', () => {
const opts = coerceTypesInOptions(
{ a: 'false' } as any,
Expand Down
66 changes: 43 additions & 23 deletions packages/tao/src/shared/params.ts
Expand Up @@ -103,7 +103,9 @@ export function convertToCamelCase(parsed: Arguments): Options {
*/
export function coerceTypesInOptions(opts: Options, schema: Schema): Options {
Object.keys(opts).forEach((k) => {
opts[k] = coerceType(schema.properties[k], opts[k]);
const prop = findSchemaForProperty(k, schema);

opts[k] = coerceType(prop?.description, opts[k]);
});
return opts;
}
Expand Down Expand Up @@ -150,26 +152,19 @@ export function convertAliases(
excludeUnmatched: boolean
): Options {
return Object.keys(opts).reduce((acc, k) => {
if (schema.properties[k]) {
acc[k] = opts[k];
} else {
const found = Object.entries(schema.properties).find(
([_, d]) =>
d.alias === k || (Array.isArray(d.aliases) && d.aliases.includes(k))
);
if (found) {
acc[found[0]] = opts[k];
} else if (excludeUnmatched) {
if (!acc['--']) {
acc['--'] = [];
}
acc['--'].push({
name: k,
possible: [],
});
} else {
acc[k] = opts[k];
const prop = findSchemaForProperty(k, schema);
if (prop) {
acc[prop.name] = opts[k];
} else if (excludeUnmatched) {
if (!acc['--']) {
acc['--'] = [];
}
acc['--'].push({
name: k,
possible: [],
});
} else {
acc[k] = opts[k];
}
return acc;
}, {});
Expand Down Expand Up @@ -471,9 +466,12 @@ export function combineOptionsForExecutor(
schema,
false
);
const configOpts =
config && target.configurations ? target.configurations[config] || {} : {};
const combined = { ...target.options, ...configOpts, ...r };
let combined = target.options || {};
if (config && target.configurations && target.configurations[config]) {
Object.assign(combined, target.configurations[config]);
}
combined = convertAliases(combined, schema, false);
Object.assign(combined, r);
convertSmartDefaultsIntoNamedParams(
combined,
schema,
Expand Down Expand Up @@ -713,6 +711,28 @@ export function lookupUnmatched(opts: Options, schema: Schema): Options {
return opts;
}

function findSchemaForProperty(
propName: string,
schema: Schema
): { name: string; description: PropertyDescription } | null {
if (propName in schema.properties) {
return {
name: propName,
description: schema.properties[propName],
};
}
const found = Object.entries(schema.properties).find(
([_, d]) =>
d.alias === propName ||
(Array.isArray(d.aliases) && d.aliases.includes(propName))
);
if (found) {
const [name, description] = found;
return { name, description };
}
return null;
}

function levenshtein(a: string, b: string) {
if (a.length == 0) {
return b.length;
Expand Down

0 comments on commit c86eec7

Please sign in to comment.