Skip to content

Commit

Permalink
feat(core): add presetVersion flag for the CNW
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry-stepanenko authored and FrozenPandaz committed Apr 14, 2023
1 parent 5f86929 commit bcf8876
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 19 deletions.
6 changes: 6 additions & 0 deletions docs/generated/cli/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ Type: `string`

Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset

### presetVersion

Type: `string`

Version of the custom preset to be used.

### routing

Type: `boolean`
Expand Down
6 changes: 6 additions & 0 deletions docs/generated/packages/nx/documents/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ Type: `string`

Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-standalone"]. To build your own see https://nx.dev/packages/nx-plugin#preset

### presetVersion

Type: `string`

Version of the custom preset to be used.

### routing

Type: `boolean`
Expand Down
4 changes: 4 additions & 0 deletions docs/generated/packages/workspace/generators/new.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
"description": "What to create in the new workspace.",
"type": "string"
},
"presetVersion": {
"description": "Version of the custom preset to be used.",
"oneOf": [{ "type": "string" }, { "type": "number" }]
},
"appName": { "type": "string", "description": "Application name." },
"nxCloud": {
"description": "Connect the workspace to the free tier of the distributed cache provided by Nx Cloud.",
Expand Down
5 changes: 5 additions & 0 deletions packages/create-nx-workspace/bin/create-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {

interface Arguments extends CreateWorkspaceOptions {
preset: string;
presetVersion: string;
appName: string;
style: string;
framework: Framework;
Expand Down Expand Up @@ -67,6 +68,10 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
)}]. To build your own see https://nx.dev/packages/nx-plugin#preset`,
type: 'string',
})
.option('presetVersion', {
describe: chalk.dim`Version of the custom preset to be used.`,
type: 'string',
})
.option('appName', {
describe: chalk.dim`The name of the application when a preset with pregenerated app is selected`,
type: 'string',
Expand Down
2 changes: 1 addition & 1 deletion packages/workspace/src/generators/new/generate-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function getPresetDependencies({
return {
dev: {},
dependencies: {
[preset]: presetVersion ?? getNpmPackageVersion(preset),
[preset]: getNpmPackageVersion(preset, presetVersion),
},
};
}
Expand Down
50 changes: 50 additions & 0 deletions packages/workspace/src/generators/new/new.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import {
import { Preset } from '../utils/presets';
import { newGenerator, NormalizedSchema } from './new';

const DEFAULT_PACKAGE_VERSION = '1.0.0';
jest.mock('./../utils/get-npm-package-version', () => ({
...jest.requireActual<any>('./../utils/get-npm-package-version'),
getNpmPackageVersion: jest
.fn()
.mockImplementation((name, version) => version ?? DEFAULT_PACKAGE_VERSION),
}));

const defaultOptions: Omit<
NormalizedSchema,
'name' | 'directory' | 'appName' | 'isCustomPreset'
Expand Down Expand Up @@ -94,6 +102,48 @@ describe('new', () => {
typescript: typescriptVersion,
});
});

describe('custom presets', () => {
// the process of actual resolving of a version relies on npm and is mocked here,
// thus "package@2" is expected to be resolved with version "2" instead of "2.0.0"
const versionAsPath =
'/Users/username/3rd-party-pkg/dist/packages/3rd-party-pkg-1.12.5.tgz';
test.each`
preset | presetVersion | expectedVersion
${'3rd-party-package'} | ${undefined} | ${DEFAULT_PACKAGE_VERSION}
${'[email protected]'} | ${undefined} | ${'1.1.2'}
${'3rd-party-package@2'} | ${undefined} | ${'2'}
${'3rd-party-package'} | ${'latest'} | ${'latest'}
${'3rd-party-package'} | ${'1.1.1'} | ${'1.1.1'}
${'3rd-party-package'} | ${versionAsPath} | ${versionAsPath}
${'[email protected]'} | ${'1.1.1'} | ${'1.1.1'}
`(
'should add custom preset "$preset" with a correct expectedVersion "$expectedVersion" when presetVersion is "$presetVersion"',
async ({ presetVersion, preset, expectedVersion }) => {
await newGenerator(tree, {
...defaultOptions,
name: 'my-workspace',
directory: 'my-workspace',
npmScope: 'npmScope',
appName: 'app',
preset,
presetVersion,
});

const { devDependencies, dependencies } = readJson(
tree,
'my-workspace/package.json'
);
expect(dependencies).toStrictEqual({
'3rd-party-package': expectedVersion,
});
expect(devDependencies).toStrictEqual({
'@nrwl/workspace': nxVersion,
nx: nxVersion,
});
}
);
});
});

it('should not modify any existing files', async () => {
Expand Down
38 changes: 27 additions & 11 deletions packages/workspace/src/generators/new/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface Schema {
style?: string;
nxCloud?: boolean;
preset: string;
presetVersion?: string | number; // number is needed so that generator doesn't fail on numeric-like strings (e.g. "14")
defaultBase: string;
framework?: string;
docker?: boolean;
Expand Down Expand Up @@ -92,23 +93,38 @@ function validateOptions(options: Schema, host: Tree) {
}
}

function parsePresetName(input: string): { package: string; version?: string } {
// If the preset already contains a version in the name
// -- [email protected]
// -- @scope/package@version
const SCOPED_PACKAGE = /^(@[^\/]+\/[^@\/]+)(?:@([^\/]+))?$/;
const NON_SCOPED_PACKAGE = /^([^@\/]+)(?:@([^\/]+))?$/;
const match = input.match(SCOPED_PACKAGE) || input.match(NON_SCOPED_PACKAGE);
if (!match?.[0]) {
throw new Error(`Invalid package name: ${input}`);
}
return {
package: match[1],
version: match[2],
};
}

function normalizeOptions(options: Schema): NormalizedSchema {
const normalized: Partial<NormalizedSchema> = { ...options };
const normalized: Partial<NormalizedSchema> = {
...options,
presetVersion: options.presetVersion?.toString(),
};

normalized.name = names(options.name).fileName;
if (!options.directory) {
normalized.directory = options.name;
}

// If the preset already contains a version in the name
// -- [email protected]
// -- @scope/package@version
const match = options.preset.match(
/^(?<package>(@.+\/)?[^@]+)(@(?<version>\d+\.\d+\.\d+))?$/
);
if (match) {
normalized.preset = match.groups.package;
normalized.presetVersion = match.groups.version;
}
const parsed = parsePresetName(options.preset);

normalized.preset = parsed.package;
// explicitly specified "presetVersion" takes priority over the one from the package name
normalized.presetVersion ??= parsed.version;

normalized.isCustomPreset = !Object.values(Preset).includes(
options.preset as any
Expand Down
4 changes: 4 additions & 0 deletions packages/workspace/src/generators/new/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
"description": "What to create in the new workspace.",
"type": "string"
},
"presetVersion": {
"description": "Version of the custom preset to be used.",
"oneOf": [{ "type": "string" }, { "type": "number" }]
},
"appName": {
"type": "string",
"description": "Application name."
Expand Down
24 changes: 17 additions & 7 deletions packages/workspace/src/generators/utils/get-npm-package-version.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
export function getNpmPackageVersion(packageName: string): string | null {
export function getNpmPackageVersion(
packageName: string,
packageVersion?: string
): string | null {
try {
const version = require('child_process').execSync(
`npm view ${packageName} version`,
`npm view ${packageName}${
packageVersion ? '@' + packageVersion : ''
} version --json`,
{ stdio: ['pipe', 'pipe', 'ignore'] }
);

if (version) {
return version
.toString()
.trim()
.replace(/^\n*|\n*$/g, '');
// [email protected] => ["1.12.0", "1.12.1"]
// [email protected] => "1.12.1"
// package@latest => "1.12.1"
const versionOrArray = JSON.parse(version.toString());

if (typeof versionOrArray === 'string') {
return versionOrArray;
}
return versionOrArray.pop();
}
} catch (err) {}
return null;
return packageVersion ?? null;
}

0 comments on commit bcf8876

Please sign in to comment.