feat(angular): support angular 17.2.0 (#21671)

This commit is contained in:
Leosvel Pérez Espinosa 2024-02-15 18:13:57 +01:00 committed by GitHub
parent e4b9248d05
commit 8963c4c538
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 2315 additions and 1117 deletions

View File

@ -14,6 +14,7 @@ We provide a recommended version, and it is usually the latest minor version of
| Angular Version | **Nx Version _(recommended)_** | Nx Version _(range)_ | | Angular Version | **Nx Version _(recommended)_** | Nx Version _(range)_ |
| --------------- | ------------------------------ | -------------------------------------- | | --------------- | ------------------------------ | -------------------------------------- |
| ~17.2.0 | **latest** | 18.1.0 <= latest |
| ~17.1.0 | **latest** | 17.3.0 <= latest | | ~17.1.0 | **latest** | 17.3.0 <= latest |
| ~17.0.0 | **latest** | 17.1.0 <= latest | | ~17.0.0 | **latest** | 17.1.0 <= latest |
| ~16.2.0 | **latest** | 16.7.0 <= latest | | ~16.2.0 | **latest** | 16.7.0 <= latest |

View File

@ -162,6 +162,11 @@
"items": { "type": "string" }, "items": { "type": "string" },
"default": [] "default": []
}, },
"clearScreen": {
"type": "boolean",
"default": false,
"description": "Automatically clear the terminal screen during rebuilds. _Note: this is only supported in Angular versions >= 17.2.0_."
},
"optimization": { "optimization": {
"description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For more information, see https://angular.io/guide/workspace-config#optimization-configuration.", "description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For more information, see https://angular.io/guide/workspace-config#optimization-configuration.",
"default": true, "default": true,
@ -234,6 +239,11 @@
"^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] } "^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] }
} }
}, },
"define": {
"description": "Defines global identifiers that will be replaced with a specified constant value when found in any JavaScript or TypeScript code including libraries. The value will be used directly. String values must be put in quotes. Identifiers within Angular metadata such as Component Decorators will not be replaced. _Note: this is only supported in Angular versions >= 17.2.0_.",
"type": "object",
"additionalProperties": { "type": "string" }
},
"fileReplacements": { "fileReplacements": {
"description": "Replace compilation source files with other compilation source files in the build.", "description": "Replace compilation source files with other compilation source files in the build.",
"type": "array", "type": "array",

View File

@ -110,6 +110,24 @@
"description": "Force the development server to use the 'browser-esbuild' builder when building. This is a developer preview option for the esbuild-based build system. _Note: this is only supported in Angular versions >= 16.1.0_.", "description": "Force the development server to use the 'browser-esbuild' builder when building. This is a developer preview option for the esbuild-based build system. _Note: this is only supported in Angular versions >= 16.1.0_.",
"default": false "default": false
}, },
"prebundle": {
"description": "Enable and control the Vite-based development server's prebundling capabilities. To enable prebundling, the Angular CLI cache must also be enabled. This option has no effect when using the 'browser' or other Webpack-based builders. _Note: this is only supported in Angular versions >= 17.2.0_.",
"oneOf": [
{ "type": "boolean" },
{
"type": "object",
"properties": {
"exclude": {
"description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself.",
"type": "array",
"items": { "type": "string" }
}
},
"additionalProperties": false,
"required": ["exclude"]
}
]
},
"buildLibsFromSource": { "buildLibsFromSource": {
"type": "boolean", "type": "boolean",
"description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.", "description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.",

View File

@ -14,6 +14,7 @@ We provide a recommended version, and it is usually the latest minor version of
| Angular Version | **Nx Version _(recommended)_** | Nx Version _(range)_ | | Angular Version | **Nx Version _(recommended)_** | Nx Version _(range)_ |
| --------------- | ------------------------------ | -------------------------------------- | | --------------- | ------------------------------ | -------------------------------------- |
| ~17.2.0 | **latest** | 18.1.0 <= latest |
| ~17.1.0 | **latest** | 17.3.0 <= latest | | ~17.1.0 | **latest** | 17.3.0 <= latest |
| ~17.0.0 | **latest** | 17.1.0 <= latest | | ~17.0.0 | **latest** | 17.1.0 <= latest |
| ~16.2.0 | **latest** | 16.7.0 <= latest | | ~16.2.0 | **latest** | 16.7.0 <= latest |

View File

@ -26,19 +26,19 @@
}, },
"devDependencies": { "devDependencies": {
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@angular-devkit/architect": "~0.1701.0", "@angular-devkit/architect": "~0.1702.0",
"@angular-devkit/build-angular": "~17.1.0", "@angular-devkit/build-angular": "~17.2.0",
"@angular-devkit/core": "~17.1.0", "@angular-devkit/core": "~17.2.0",
"@angular-devkit/schematics": "~17.1.0", "@angular-devkit/schematics": "~17.2.0",
"@angular-eslint/eslint-plugin": "17.0.1", "@angular-eslint/eslint-plugin": "17.0.1",
"@angular-eslint/eslint-plugin-template": "17.0.1", "@angular-eslint/eslint-plugin-template": "17.0.1",
"@angular-eslint/template-parser": "17.0.1", "@angular-eslint/template-parser": "17.0.1",
"@angular/cli": "~17.1.0", "@angular/cli": "~17.2.0",
"@angular/common": "~17.1.0", "@angular/common": "~17.2.0",
"@angular/compiler": "~17.1.0", "@angular/compiler": "~17.2.0",
"@angular/compiler-cli": "~17.1.0", "@angular/compiler-cli": "~17.2.0",
"@angular/core": "~17.1.0", "@angular/core": "~17.2.0",
"@angular/router": "~17.1.0", "@angular/router": "~17.2.0",
"@babel/core": "^7.23.2", "@babel/core": "^7.23.2",
"@babel/helper-create-regexp-features-plugin": "^7.22.9", "@babel/helper-create-regexp-features-plugin": "^7.22.9",
"@babel/plugin-transform-runtime": "^7.23.2", "@babel/plugin-transform-runtime": "^7.23.2",
@ -93,7 +93,7 @@
"@rollup/plugin-json": "^4.1.0", "@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-node-resolve": "^13.0.4",
"@rollup/plugin-url": "^7.0.0", "@rollup/plugin-url": "^7.0.0",
"@schematics/angular": "~17.1.0", "@schematics/angular": "~17.2.0",
"@side/jest-runtime": "^1.1.0", "@side/jest-runtime": "^1.1.0",
"@storybook/addon-essentials": "7.5.3", "@storybook/addon-essentials": "7.5.3",
"@storybook/core-server": "7.5.3", "@storybook/core-server": "7.5.3",
@ -228,7 +228,7 @@
"mini-css-extract-plugin": "~2.4.7", "mini-css-extract-plugin": "~2.4.7",
"minimatch": "9.0.3", "minimatch": "9.0.3",
"next-sitemap": "^3.1.10", "next-sitemap": "^3.1.10",
"ng-packagr": "~17.1.0", "ng-packagr": "~17.2.0",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"npm-package-arg": "11.0.1", "npm-package-arg": "11.0.1",
"nuxt": "^3.10.0", "nuxt": "^3.10.0",
@ -374,4 +374,3 @@
] ]
} }
} }

View File

@ -362,6 +362,15 @@
"version": "18.0.0-beta.0", "version": "18.0.0-beta.0",
"description": "Add NX_MF_DEV_SERVER_STATIC_REMOTES to inputs for task hashing when '@nx/angular:webpack-browser' is used for Module Federation.", "description": "Add NX_MF_DEV_SERVER_STATIC_REMOTES to inputs for task hashing when '@nx/angular:webpack-browser' is used for Module Federation.",
"factory": "./src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults" "factory": "./src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults"
},
"update-angular-cli-version-17-2-0": {
"cli": "nx",
"version": "18.1.0-beta.1",
"requires": {
"@angular/core": ">=17.2.0"
},
"description": "Update the @angular/cli package version to ~17.2.0.",
"factory": "./src/migrations/update-18-1-0/update-angular-cli"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {
@ -1646,6 +1655,59 @@
"alwaysAddToPackageJson": false "alwaysAddToPackageJson": false
} }
} }
},
"18.1.0": {
"version": "18.1.0-beta.1",
"packages": {
"@angular-devkit/build-angular": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular/ssr": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/architect": {
"version": "~0.1702.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1702.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~17.2.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~17.2.0",
"alwaysAddToPackageJson": false
}
}
} }
} }
} }

View File

@ -16,4 +16,9 @@ export function validateOptions(options: Schema): void {
throw new Error(stripIndents`The "esbuildMiddleware" option is only supported in Angular >= 17.0.0. You are currently using "${angularVersion}". throw new Error(stripIndents`The "esbuildMiddleware" option is only supported in Angular >= 17.0.0. You are currently using "${angularVersion}".
You can resolve this error by removing the "esbuildMiddleware" option or by migrating to Angular 17.0.0.`); You can resolve this error by removing the "esbuildMiddleware" option or by migrating to Angular 17.0.0.`);
} }
if (lt(angularVersion, '17.2.0') && options.prebundle) {
throw new Error(stripIndents`The "prebundle" option is only supported in Angular >= 17.2.0. You are currently using "${angularVersion}".
You can resolve this error by removing the "prebundle" option or by migrating to Angular 17.2.0.`);
}
} }

View File

@ -17,6 +17,7 @@ interface BaseSchema {
watch?: boolean; watch?: boolean;
poll?: number; poll?: number;
forceEsbuild?: boolean; forceEsbuild?: boolean;
prebundle?: boolean | { exclude: string[] };
buildLibsFromSource?: boolean; buildLibsFromSource?: boolean;
esbuildMiddleware?: string[]; esbuildMiddleware?: string[];
} }

View File

@ -116,6 +116,24 @@
"description": "Force the development server to use the 'browser-esbuild' builder when building. This is a developer preview option for the esbuild-based build system. _Note: this is only supported in Angular versions >= 16.1.0_.", "description": "Force the development server to use the 'browser-esbuild' builder when building. This is a developer preview option for the esbuild-based build system. _Note: this is only supported in Angular versions >= 16.1.0_.",
"default": false "default": false
}, },
"prebundle": {
"description": "Enable and control the Vite-based development server's prebundling capabilities. To enable prebundling, the Angular CLI cache must also be enabled. This option has no effect when using the 'browser' or other Webpack-based builders. _Note: this is only supported in Angular versions >= 17.2.0_.",
"oneOf": [
{ "type": "boolean" },
{
"type": "object",
"properties": {
"exclude": {
"description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself.",
"type": "array",
"items": { "type": "string" }
}
},
"additionalProperties": false,
"required": ["exclude"]
}
]
},
"buildLibsFromSource": { "buildLibsFromSource": {
"type": "boolean", "type": "boolean",
"description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.", "description": "Read buildable libraries from source instead of building them separately. If not set, it will take the value specified in the `browserTarget` options, or it will default to `true` if it's also not set in the `browserTarget` options.",

View File

@ -20,6 +20,7 @@ export default async function* applicationExecutor(
const { const {
buildLibsFromSource = true, buildLibsFromSource = true,
plugins: pluginPaths, plugins: pluginPaths,
indexHtmlTransformer: indexHtmlTransformerPath,
...delegateExecutorOptions ...delegateExecutorOptions
} = options; } = options;
@ -36,11 +37,8 @@ export default async function* applicationExecutor(
} }
const plugins = await loadPlugins(pluginPaths, options.tsConfig); const plugins = await loadPlugins(pluginPaths, options.tsConfig);
const indexHtmlTransformer = options.indexHtmlTransformer const indexHtmlTransformer = indexHtmlTransformerPath
? await loadIndexHtmlTransformer( ? await loadIndexHtmlTransformer(indexHtmlTransformerPath, options.tsConfig)
options.indexHtmlTransformer,
options.tsConfig
)
: undefined; : undefined;
const { buildApplication } = await import('@angular-devkit/build-angular'); const { buildApplication } = await import('@angular-devkit/build-angular');

View File

@ -135,6 +135,11 @@
}, },
"default": [] "default": []
}, },
"clearScreen": {
"type": "boolean",
"default": false,
"description": "Automatically clear the terminal screen during rebuilds. _Note: this is only supported in Angular versions >= 17.2.0_."
},
"optimization": { "optimization": {
"description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For more information, see https://angular.io/guide/workspace-config#optimization-configuration.", "description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For more information, see https://angular.io/guide/workspace-config#optimization-configuration.",
"default": true, "default": true,
@ -213,6 +218,13 @@
"^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] } "^\\.\\S+$": { "enum": ["text", "binary", "file", "empty"] }
} }
}, },
"define": {
"description": "Defines global identifiers that will be replaced with a specified constant value when found in any JavaScript or TypeScript code including libraries. The value will be used directly. String values must be put in quotes. Identifiers within Angular metadata such as Component Decorators will not be replaced. _Note: this is only supported in Angular versions >= 17.2.0_.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"fileReplacements": { "fileReplacements": {
"description": "Replace compilation source files with other compilation source files in the build.", "description": "Replace compilation source files with other compilation source files in the build.",
"type": "array", "type": "array",

View File

@ -12,48 +12,62 @@ export function validateOptions(options: ApplicationExecutorOptions): void {
); );
} }
if (options.loader && lt(angularVersion, '17.1.0')) { if (lt(angularVersion, '17.1.0')) {
throw new Error( if (options.loader) {
`The "loader" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (options.indexHtmlTransformer && lt(angularVersion, '17.1.0')) {
throw new Error(
`The "indexHtmlTransformer" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (
typeof options.index === 'object' &&
options.index.preloadInitial !== undefined &&
lt(angularVersion, '17.1.0')
) {
throw new Error(
`The "index.preloadInitial" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (
options.optimization &&
typeof options.optimization !== 'boolean' &&
options.optimization.styles &&
typeof options.optimization.styles !== 'boolean' &&
lt(angularVersion, '17.1.0')
) {
if (options.optimization.styles.removeSpecialComments === false) {
throw new Error( throw new Error(
`The "optimization.styles.removeSpecialComments" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.` `The "loader" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (options.indexHtmlTransformer) {
throw new Error(
`The "indexHtmlTransformer" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (
typeof options.index === 'object' &&
options.index.preloadInitial !== undefined
) {
throw new Error(
`The "index.preloadInitial" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (
options.optimization &&
typeof options.optimization !== 'boolean' &&
options.optimization.styles &&
typeof options.optimization.styles !== 'boolean'
) {
if (options.optimization.styles.removeSpecialComments === false) {
throw new Error(
`The "optimization.styles.removeSpecialComments" option requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
);
} else if (options.optimization.styles.removeSpecialComments === true) {
// silently remove the option, as it was the default before 17.1.0
delete options.optimization.styles.removeSpecialComments;
}
}
if (typeof options.outputPath === 'object') {
throw new Error(
`The "outputPath" option as an object requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.`
); );
} else if (options.optimization.styles.removeSpecialComments === true) {
// silently remove the option, as it was the default before 17.1.0
delete options.optimization.styles.removeSpecialComments;
} }
} }
if (typeof options.outputPath === 'object' && lt(angularVersion, '17.1.0')) { if (lt(angularVersion, '17.2.0')) {
throw new Error( if (options.define) {
`The "outputPath" option as an object requires Angular version 17.1.0 or greater. You are currently using version ${angularVersion}.` throw new Error(
); `The "define" option requires Angular version 17.2.0 or greater. You are currently using version ${angularVersion}.`
);
}
if (options.clearScreen !== undefined) {
throw new Error(
`The "clearScreen" option requires Angular version 17.2.0 or greater. You are currently using version ${angularVersion}.`
);
}
} }
} }

View File

@ -1,13 +1,16 @@
import { NgPackagr, ngPackagr } from 'ng-packagr'; import { NgPackagr, ngPackagr } from 'ng-packagr';
import type { BuildAngularLibraryExecutorOptions } from '../../package/schema'; import type { BuildAngularLibraryExecutorOptions } from '../../package/schema';
import { getInstalledAngularVersionInfo } from '../../utilities/angular-version-utils'; import { getInstalledAngularVersionInfo } from '../../utilities/angular-version-utils';
import { STYLESHEET_PROCESSOR } from '../../utilities/ng-packagr/stylesheet-processor.di';
export async function getNgPackagrInstance( export async function getNgPackagrInstance(
options: BuildAngularLibraryExecutorOptions options: BuildAngularLibraryExecutorOptions
): Promise<NgPackagr> { ): Promise<NgPackagr> {
const { major: angularMajorVersion } = getInstalledAngularVersionInfo(); const { major: angularMajorVersion } = getInstalledAngularVersionInfo();
if (angularMajorVersion >= 17) { if (angularMajorVersion >= 17) {
const { STYLESHEET_PROCESSOR } = await import(
'../../utilities/ng-packagr/stylesheet-processor.di'
);
const packagr = ngPackagr(); const packagr = ngPackagr();
packagr.withProviders([STYLESHEET_PROCESSOR]); packagr.withProviders([STYLESHEET_PROCESSOR]);
return packagr; return packagr;

View File

@ -14,6 +14,9 @@ import { colors } from 'ng-packagr/lib/utils/color';
// using this instead of the one from ng-packagr // using this instead of the one from ng-packagr
import { getTailwindConfigPath } from './tailwindcss'; import { getTailwindConfigPath } from './tailwindcss';
import { workspaceRoot } from '@nx/devkit'; import { workspaceRoot } from '@nx/devkit';
import type { PostcssConfiguration } from 'ng-packagr/lib/styles/postcss-configuration';
import { gte } from 'semver';
import { getInstalledPackageVersionInfo } from '../angular-version-utils';
const maxWorkersVariable = process.env['NG_BUILD_MAX_WORKERS']; const maxWorkersVariable = process.env['NG_BUILD_MAX_WORKERS'];
const maxThreads = const maxThreads =
@ -57,7 +60,7 @@ export class StylesheetProcessor {
filePath: string; filePath: string;
content: string; content: string;
}): Promise<string> { }): Promise<string> {
this.createRenderWorker(); await this.createRenderWorker();
return this.renderWorker.run({ content, filePath }); return this.renderWorker.run({ content, filePath });
} }
@ -67,7 +70,7 @@ export class StylesheetProcessor {
void this.renderWorker?.destroy(); void this.renderWorker?.destroy();
} }
private createRenderWorker(): void { private async createRenderWorker(): Promise<void> {
if (this.renderWorker) { if (this.renderWorker) {
return; return;
} }
@ -88,6 +91,18 @@ export class StylesheetProcessor {
const browserslistData = browserslist(undefined, { path: this.basePath }); const browserslistData = browserslist(undefined, { path: this.basePath });
const { version: ngPackagrVersion } =
getInstalledPackageVersionInfo('ng-packagr');
let postcssConfiguration: PostcssConfiguration | undefined;
if (gte(ngPackagrVersion, '17.2.0')) {
const { loadPostcssConfiguration } = await import(
'ng-packagr/lib/styles/postcss-configuration'
);
postcssConfiguration = await loadPostcssConfiguration(
this.projectBasePath
);
}
this.renderWorker = new Piscina({ this.renderWorker = new Piscina({
filename: require.resolve( filename: require.resolve(
'ng-packagr/lib/styles/stylesheet-processor-worker' 'ng-packagr/lib/styles/stylesheet-processor-worker'
@ -98,6 +113,7 @@ export class StylesheetProcessor {
FORCE_COLOR: '' + colors.enabled, FORCE_COLOR: '' + colors.enabled,
}, },
workerData: { workerData: {
postcssConfiguration,
tailwindConfigPath: getTailwindConfigPath( tailwindConfigPath: getTailwindConfigPath(
this.projectBasePath, this.projectBasePath,
workspaceRoot workspaceRoot

View File

@ -0,0 +1,42 @@
import { readJson, Tree, writeJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import updateAngularCli, { angularCliVersion } from './update-angular-cli';
describe('update-angular-cli migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should update @angular/cli version when defined as a dev dependency', async () => {
writeJson(tree, 'package.json', {
devDependencies: { '@angular/cli': '~13.3.0' },
});
await updateAngularCli(tree);
const { devDependencies } = readJson(tree, 'package.json');
expect(devDependencies['@angular/cli']).toBe(angularCliVersion);
});
it('should update @angular/cli version when defined as a dependency', async () => {
writeJson(tree, 'package.json', {
dependencies: { '@angular/cli': '~13.3.0' },
});
await updateAngularCli(tree);
const { dependencies } = readJson(tree, 'package.json');
expect(dependencies['@angular/cli']).toBe(angularCliVersion);
});
it('should not add @angular/cli to package.json when it is not set', async () => {
const initialPackageJson = readJson(tree, 'package.json');
await updateAngularCli(tree);
const packageJson = readJson(tree, 'package.json');
expect(packageJson).toStrictEqual(initialPackageJson);
});
});

View File

@ -0,0 +1,23 @@
import { formatFiles, Tree, updateJson } from '@nx/devkit';
export const angularCliVersion = '~17.2.0';
export default async function (tree: Tree) {
let shouldFormat = false;
updateJson(tree, 'package.json', (json) => {
if (json.devDependencies?.['@angular/cli']) {
json.devDependencies['@angular/cli'] = angularCliVersion;
shouldFormat = true;
} else if (json.dependencies?.['@angular/cli']) {
json.dependencies['@angular/cli'] = angularCliVersion;
shouldFormat = true;
}
return json;
});
if (shouldFormat) {
await formatFiles(tree);
}
}

View File

@ -1,8 +1,8 @@
export const nxVersion = require('../../package.json').version; export const nxVersion = require('../../package.json').version;
export const angularVersion = '~17.1.0'; export const angularVersion = '~17.2.0';
export const angularDevkitVersion = '~17.1.0'; export const angularDevkitVersion = '~17.2.0';
export const ngPackagrVersion = '~17.1.0'; export const ngPackagrVersion = '~17.2.0';
export const ngrxVersion = '~17.0.0'; export const ngrxVersion = '~17.0.0';
export const rxjsVersion = '~7.8.0'; export const rxjsVersion = '~7.8.0';
export const zoneJsVersion = '~0.14.3'; export const zoneJsVersion = '~0.14.3';

View File

@ -953,20 +953,13 @@ describe('params', () => {
it('should throw if property name matching pattern is not valid', () => { it('should throw if property name matching pattern is not valid', () => {
expect(() => expect(() =>
validateOptsAgainstSchema( validateOptsAgainstSchema(
{ { a: true, b: false },
a: true,
b: false,
},
{ {
properties: { properties: {
a: { a: { type: 'boolean' },
type: 'boolean',
},
}, },
patternProperties: { patternProperties: {
'^b$': { '^b$': { type: 'number' },
type: 'number',
},
}, },
additionalProperties: false, additionalProperties: false,
} }
@ -976,6 +969,63 @@ describe('params', () => {
); );
}); });
it('should handle properties matching patternProperties schema', () => {
expect(() =>
validateOptsAgainstSchema(
{ a: true, b: false },
{
properties: {
a: { type: 'boolean' },
},
patternProperties: {
'^b$': { type: 'boolean' },
},
additionalProperties: false,
}
)
).not.toThrow();
});
it('should throw if additional property does not match schema', () => {
expect(() =>
validateOptsAgainstSchema(
{ a: true, b: 'b', c: 'c' },
{
properties: {
a: { type: 'boolean' },
},
patternProperties: {
'^b$': { type: 'string' },
},
additionalProperties: {
type: 'number',
},
}
)
).toThrow(
"Property 'c' does not match the schema. 'c' should be a 'number'."
);
});
it('should handle additional properties when they match the additionalProperties schema', () => {
expect(() =>
validateOptsAgainstSchema(
{ a: true, b: 'b', c: 1, d: 2 },
{
properties: {
a: { type: 'boolean' },
},
patternProperties: {
'^b$': { type: 'string' },
},
additionalProperties: {
type: 'number',
},
}
)
).not.toThrow();
});
it('should throw if found unsupported positional property', () => { it('should throw if found unsupported positional property', () => {
expect(() => expect(() =>
validateOptsAgainstSchema( validateOptsAgainstSchema(

View File

@ -35,7 +35,7 @@ type PropertyDescription = {
| { $source: 'projectName' } | { $source: 'projectName' }
| { $source: 'unparsed' } | { $source: 'unparsed' }
| { $source: 'workingDirectory' }; | { $source: 'workingDirectory' };
additionalProperties?: boolean; additionalProperties?: boolean | PropertyDescription;
const?: any; const?: any;
'x-prompt'?: 'x-prompt'?:
| string | string
@ -72,7 +72,7 @@ export type Schema = {
oneOf?: Partial<Schema>[]; oneOf?: Partial<Schema>[];
description?: string; description?: string;
definitions?: Properties; definitions?: Properties;
additionalProperties?: boolean; additionalProperties?: boolean | PropertyDescription;
examples?: { command: string; description?: string }[]; examples?: { command: string; description?: string }[];
patternProperties?: { patternProperties?: {
[pattern: string]: PropertyDescription; [pattern: string]: PropertyDescription;
@ -284,7 +284,10 @@ export function validateObject(
} }
}); });
if (schema.additionalProperties === false) { if (
schema.additionalProperties !== undefined &&
schema.additionalProperties !== true
) {
Object.keys(opts).find((p) => { Object.keys(opts).find((p) => {
if ( if (
Object.keys(schema.properties).indexOf(p) === -1 && Object.keys(schema.properties).indexOf(p) === -1 &&
@ -297,8 +300,15 @@ export function validateObject(
throw new SchemaError( throw new SchemaError(
`Schema does not support positional arguments. Argument '${opts[p]}' found` `Schema does not support positional arguments. Argument '${opts[p]}' found`
); );
} else { } else if (schema.additionalProperties === false) {
throw new SchemaError(`'${p}' is not found in schema`); throw new SchemaError(`'${p}' is not found in schema`);
} else if (typeof schema.additionalProperties === 'object') {
validateProperty(
p,
opts[p],
schema.additionalProperties,
definitions
);
} }
} }
}); });
@ -595,7 +605,7 @@ export function applyVerbosity(
isVerbose: boolean isVerbose: boolean
) { ) {
if ( if (
(schema.additionalProperties || 'verbose' in schema.properties) && (schema.additionalProperties === true || 'verbose' in schema.properties) &&
isVerbose isVerbose
) { ) {
options['verbose'] = true; options['verbose'] = true;

View File

@ -4,4 +4,4 @@ export const typescriptVersion = '~5.3.2';
// TODO: remove when preset generation is reworked and // TODO: remove when preset generation is reworked and
// deps are not installed from workspace // deps are not installed from workspace
export const angularCliVersion = '~17.1.0'; export const angularCliVersion = '~17.2.0';

2993
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff