feat(angular): support for Angular 15 (#12112)

This commit is contained in:
Colum Ferry 2022-11-17 14:31:45 +00:00 committed by GitHub
parent 032a9d17d6
commit b084dddff0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 2098 additions and 1629 deletions

View File

@ -184,13 +184,13 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
// check project configuration
const projectConfig = readJson(`apps/${project}/project.json`);
expect(projectConfig.sourceRoot).toEqual(`apps/${project}/src`);
expect(projectConfig.targets.build).toEqual({
expect(projectConfig.targets.build).toStrictEqual({
executor: '@angular-devkit/build-angular:browser',
options: {
outputPath: `dist/apps/${project}`,
index: `apps/${project}/src/index.html`,
main: `apps/${project}/src/main.ts`,
polyfills: `apps/${project}/src/polyfills.ts`,
polyfills: [`zone.js`],
tsConfig: `apps/${project}/tsconfig.app.json`,
assets: [
`apps/${project}/src/favicon.ico`,
@ -201,12 +201,6 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
},
configurations: {
production: {
fileReplacements: [
{
replace: `apps/${project}/src/environments/environment.ts`,
with: `apps/${project}/src/environments/environment.prod.ts`,
},
],
budgets: [
{
type: 'initial',
@ -240,13 +234,11 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
},
defaultConfiguration: 'development',
});
expect(projectConfig.targets.test).toEqual({
expect(projectConfig.targets.test).toStrictEqual({
executor: '@angular-devkit/build-angular:karma',
options: {
main: `apps/${project}/src/test.ts`,
polyfills: `apps/${project}/src/polyfills.ts`,
polyfills: [`zone.js`, `zone.js/testing`],
tsConfig: `apps/${project}/tsconfig.spec.json`,
karmaConfig: `apps/${project}/karma.conf.js`,
assets: [
`apps/${project}/src/favicon.ico`,
`apps/${project}/src/assets`,

View File

@ -35,7 +35,6 @@ describe('Move Angular Project', () => {
// just check the output
expect(moveOutput).toContain(`DELETE apps/${app1}`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/.browserslistrc`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`);
@ -44,7 +43,6 @@ describe('Move Angular Project', () => {
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/favicon.ico`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/index.html`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/main.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/polyfills.ts`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/styles.css`);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/test-setup.ts`);
expect(moveOutput).toContain(
@ -54,12 +52,6 @@ describe('Move Angular Project', () => {
`CREATE apps/${newPath}/src/app/app.module.ts`
);
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/assets/.gitkeep`);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.prod.ts`
);
expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.ts`
);
});
/**

View File

@ -26,19 +26,19 @@
"echo": "echo 123458"
},
"devDependencies": {
"@angular-devkit/architect": "~0.1402.0",
"@angular-devkit/build-angular": "~14.2.0",
"@angular-devkit/core": "~14.2.0",
"@angular-devkit/schematics": "~14.2.0",
"@angular-devkit/architect": "~0.1500.0",
"@angular-devkit/build-angular": "~15.0.0",
"@angular-devkit/core": "~15.0.0",
"@angular-devkit/schematics": "~15.0.0",
"@angular-eslint/eslint-plugin": "~14.0.4",
"@angular-eslint/eslint-plugin-template": "~14.0.4",
"@angular-eslint/template-parser": "~14.0.4",
"@angular/cli": "~14.2.0",
"@angular/common": "~14.2.0",
"@angular/compiler": "~14.2.0",
"@angular/compiler-cli": "~14.2.0",
"@angular/core": "~14.2.0",
"@angular/router": "~14.2.0",
"@angular/cli": "~15.0.0",
"@angular/common": "~15.0.0",
"@angular/compiler": "~15.0.0",
"@angular/compiler-cli": "~15.0.0",
"@angular/core": "~15.0.0",
"@angular/router": "~15.0.0",
"@babel/core": "^7.15.0",
"@babel/helper-create-regexp-features-plugin": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
@ -74,7 +74,7 @@
"@rollup/plugin-image": "^2.1.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@schematics/angular": "~14.2.0",
"@schematics/angular": "~15.0.0",
"@storybook/addon-essentials": "~6.5.9",
"@storybook/angular": "^6.5.12",
"@storybook/builder-webpack5": "~6.5.9",
@ -121,6 +121,7 @@
"autoprefixer": "10.4.12",
"babel-jest": "28.1.3",
"babel-loader": "^8.2.2",
"browserslist": "^4.21.4",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"commitizen": "^4.0.3",
@ -185,7 +186,7 @@
"mini-css-extract-plugin": "~2.4.7",
"minimatch": "3.0.5",
"next-sitemap": "^3.1.10",
"ng-packagr": "~14.2.0",
"ng-packagr": "~15.0.0",
"node-fetch": "^2.6.7",
"nx": "15.1.0-beta.2",
"open": "^8.4.0",
@ -241,7 +242,7 @@
"url-loader": "^4.1.1",
"verdaccio": "^5.0.4",
"vite": "^3.2.3",
"webpack": "^5.58.1",
"webpack": "^5.75.0",
"webpack-dev-server": "^4.9.3",
"webpack-merge": "^5.8.0",
"webpack-node-externals": "^3.0.0",

View File

@ -190,6 +190,42 @@
"version": "15.0.0-beta.1",
"description": "Stop hashing karma spec files and config files for build targets and dependent tasks",
"factory": "./src/migrations/update-15-0-0/add-karma-inputs"
},
"update-angular-cli-version-15-0-0": {
"cli": "nx",
"version": "15.2.0-beta.0",
"description": "Update the @angular/cli package version to ~15.0.0.",
"factory": "./src/migrations/update-15-2-0/update-angular-cli"
},
"remove-browserlist-config": {
"cli": "nx",
"version": "15.2.0-beta.0",
"description": "Remove browserlist config as it's handled by build-angular",
"factory": "./src/migrations/update-15-2-0/remove-browserlist-config"
},
"update-typescript-target": {
"cli": "nx",
"version": "15.2.0-beta.0",
"description": "Update typescript target to ES2022",
"factory": "./src/migrations/update-15-2-0/update-typescript-target"
},
"update-workspace-config": {
"cli": "nx",
"version": "15.2.0-beta.0",
"description": "Remove bundleDependencies from server targets",
"factory": "./src/migrations/update-15-2-0/update-workspace-config"
},
"update-platform-server-exports": {
"cli": "ng",
"version": "15.2.0-beta.0",
"description": "Remove exported `@angular/platform-server` `renderModule` method. The `renderModule` method is now exported by the Angular CLI.",
"factory": "./src/migrations/update-15-2-0/remove-platform-server-exports"
},
"update-karma-main-file": {
"cli": "ng",
"version": "15.2.0-beta.0",
"description": "Remove no longer needed require calls in Karma builder main file.",
"factory": "./src/migrations/update-15-2-0/update-karma-main-file"
}
},
"packageJsonUpdates": {
@ -1557,6 +1593,63 @@
"alwaysAddToPackageJson": false
}
}
},
"15.2.0": {
"version": "15.2.0-beta.0",
"packages": {
"@angular-devkit/architect": {
"version": "~0.1500.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1500.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~15.0.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/common": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/express-engine": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/builders": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
}
}
}
}
}

View File

@ -39,7 +39,7 @@
"migrations": "./migrations.json"
},
"dependencies": {
"@angular-devkit/schematics": "~14.2.0",
"@angular-devkit/schematics": "~15.0.0",
"@nrwl/cypress": "file:../cypress",
"@nrwl/devkit": "file:../devkit",
"@nrwl/jest": "file:../jest",
@ -48,7 +48,7 @@
"@nrwl/webpack": "file:../webpack",
"@nrwl/workspace": "file:../workspace",
"@phenomnomnominal/tsquery": "4.1.1",
"@schematics/angular": "~14.2.0",
"@schematics/angular": "~15.0.0",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"http-server": "^14.1.0",
@ -58,7 +58,7 @@
"semver": "7.3.4",
"ts-node": "10.9.1",
"tsconfig-paths": "^3.9.0",
"webpack": "^5.58.1",
"webpack": "^5.75.0",
"webpack-merge": "5.7.3"
},
"publishConfig": {

View File

@ -167,7 +167,12 @@ function normalizeBuildTargetOptions(
const buildOptions = withSchemaDefaults(options);
// paths need to be unix paths for angular devkit
buildOptions.polyfills = joinPathFragments(offset, buildOptions.polyfills);
buildOptions.polyfills =
Array.isArray(buildOptions.polyfills) && buildOptions.polyfills.length > 0
? (buildOptions.polyfills as string[]).map((p) =>
joinPathFragments(offset, p)
)
: joinPathFragments(offset, buildOptions.polyfills as string);
buildOptions.main = joinPathFragments(offset, buildOptions.main);
buildOptions.index =
typeof buildOptions.index === 'string'

View File

@ -37,8 +37,22 @@
"description": "The full path for the main entry point to the app, relative to the current workspace."
},
"polyfills": {
"description": "Polyfills to be included in the build.",
"oneOf": [
{
"type": "array",
"description": "A list of polyfills to include in the build. Can be a full path for a file, relative to the current workspace or module specifier. Example: 'zone.js'.",
"items": {
"type": "string",
"description": "The full path for the polyfills file, relative to the current workspace."
"uniqueItems": true
},
"default": []
},
{
"type": "string",
"description": "The full path for the polyfills file, relative to the current workspace or a module specifier. Example: 'zone.js'."
}
]
},
"tsConfig": {
"type": "string",

View File

@ -17,7 +17,7 @@ import {
saveCacheEntry,
} from 'ng-packagr/lib/utils/cache';
import * as log from 'ng-packagr/lib/utils/log';
import { dirname, extname, join, resolve } from 'path';
import { dirname, extname, join } from 'path';
import * as postcssPresetEnv from 'postcss-preset-env';
import * as postcssUrl from 'postcss-url';
import {
@ -26,6 +26,7 @@ import {
tailwindDirectives,
TailwindSetup,
} from '../../../utilities/tailwindcss';
import { pathToFileURL } from 'url';
const postcss = require('postcss');
@ -250,12 +251,10 @@ export class StylesheetProcessor {
case '.sass':
case '.scss': {
return (await import('sass'))
.renderSync({
file: filePath,
data: css,
indentedSyntax: '.sass' === ext,
importer: customSassImporter,
includePaths: this.styleIncludePaths,
.compileString(css, {
url: pathToFileURL(filePath),
syntax: '.sass' === ext ? 'indented' : 'scss',
loadPaths: this.styleIncludePaths,
})
.css.toString();
}
@ -271,27 +270,6 @@ export class StylesheetProcessor {
return content;
}
case '.styl':
case '.stylus': {
const stylus = (await import('stylus')).default;
return (
stylus(css)
// add paths for resolve
.set('paths', [
this.basePath,
'.',
...this.styleIncludePaths,
'node_modules',
])
// add support for resolving plugins from node_modules
.set('filename', filePath)
// turn on url resolver in stylus, same as flag --resolve-url
.set('resolve url', true)
.define('url', stylus.resolver(undefined))
.render()
);
}
case '.css':
default:
return css;
@ -340,19 +318,3 @@ function transformSupportedBrowsersToTargets(
return transformed.length ? transformed : undefined;
}
function customSassImporter(
url: string,
prev: string
): { file: string; prev: string } | undefined {
// NB: Sass importer should always be sync as otherwise it will cause
// sass to go in the async path which is slower.
if (url[0] !== '~') {
return undefined;
}
return {
file: url.substring(1),
prev,
};
}

View File

@ -26,6 +26,7 @@ import {
tailwindDirectives,
TailwindSetup,
} from '../../../utilities/tailwindcss';
import { pathToFileURL } from 'url';
const postcss = require('postcss');
@ -243,12 +244,10 @@ export class StylesheetProcessor {
case '.sass':
case '.scss': {
return (await import('sass'))
.renderSync({
file: filePath,
data: css,
indentedSyntax: '.sass' === ext,
importer: customSassImporter,
includePaths: this.styleIncludePaths,
.compileString(css, {
url: pathToFileURL(filePath),
syntax: '.sass' === ext ? 'indented' : 'scss',
loadPaths: this.styleIncludePaths,
})
.css.toString();
}
@ -264,27 +263,6 @@ export class StylesheetProcessor {
return content;
}
case '.styl':
case '.stylus': {
const stylus = await import('stylus');
return (
stylus(css)
// add paths for resolve
.set('paths', [
this.basePath,
'.',
...this.styleIncludePaths,
'node_modules',
])
// add support for resolving plugins from node_modules
.set('filename', filePath)
// turn on url resolver in stylus, same as flag --resolve-url
.set('resolve url', true)
.define('url', stylus.resolver(undefined))
.render()
);
}
case '.css':
default:
return css;
@ -333,19 +311,3 @@ function transformSupportedBrowsersToTargets(
return transformed.length ? transformed : undefined;
}
function customSassImporter(
url: string,
prev: string
): { file: string; prev: string } | undefined {
// NB: Sass importer should always be sync as otherwise it will cause
// sass to go in the async path which is slower.
if (url[0] !== '~') {
return undefined;
}
return {
file: url.substring(1),
prev,
};
}

View File

@ -1,17 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`app --standalone should generate a standalone app correctly with routing 1`] = `
"import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
"import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
import { AppComponent } from './app/app.component';
import { environment } from './environments/environment';
import { appRoutes } from './app/app.routes';
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())],
}).catch((err) => console.error(err));"
@ -74,16 +68,10 @@ describe('AppComponent', () => {
`;
exports[`app --standalone should generate a standalone app correctly without routing 1`] = `
"import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';;
"import { bootstrapApplication } from '@angular/platform-browser';;
import { AppComponent } from './app/app.component';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent).catch((err) => console.error(err));"
`;
@ -164,12 +152,6 @@ Object {
"type": "anyComponentStyle",
},
],
"fileReplacements": Array [
Object {
"replace": "apps/my-dir/my-app/src/environments/environment.ts",
"with": "apps/my-dir/my-app/src/environments/environment.prod.ts",
},
],
"outputHashing": "all",
},
},
@ -182,7 +164,9 @@ Object {
"index": "apps/my-dir/my-app/src/index.html",
"main": "apps/my-dir/my-app/src/main.ts",
"outputPath": "dist/apps/my-dir/my-app",
"polyfills": "apps/my-dir/my-app/src/polyfills.ts",
"polyfills": Array [
"zone.js",
],
"scripts": Array [],
"styles": Array [
"apps/my-dir/my-app/src/styles.css",
@ -336,12 +320,6 @@ Object {
"type": "anyComponentStyle",
},
],
"fileReplacements": Array [
Object {
"replace": "apps/my-app/src/environments/environment.ts",
"with": "apps/my-app/src/environments/environment.prod.ts",
},
],
"outputHashing": "all",
},
},
@ -354,7 +332,9 @@ Object {
"index": "apps/my-app/src/index.html",
"main": "apps/my-app/src/main.ts",
"outputPath": "dist/apps/my-app",
"polyfills": "apps/my-app/src/polyfills.ts",
"polyfills": Array [
"zone.js",
],
"scripts": Array [],
"styles": Array [
"apps/my-app/src/styles.css",

View File

@ -1038,6 +1038,24 @@ describe('app', () => {
).toContain('standalone: true');
});
});
it('should generate correct main.ts', async () => {
// ACT
await generateApp(appTree, 'myapp');
// ASSERT
expect(appTree.read('apps/myapp/src/main.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
"
`);
});
});
async function generateApp(

View File

@ -45,21 +45,15 @@ function updateMainEntrypoint(
const standaloneComponentMainContents = (
routerModuleSetup
) => `import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';${
) => `import { bootstrapApplication } from '@angular/platform-browser';${
routerModuleSetup
? `
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router'`
: ``
};
import { AppComponent } from './app/app.component';
import { environment } from './environments/environment';
${routerModuleSetup ? `import { appRoutes } from './app/app.routes';` : ''}
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent${
routerModuleSetup
? `, {

View File

@ -38,7 +38,11 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) {
// tsconfig.json
updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({
...json,
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
compilerOptions: {
...json.compilerOptions,
target: 'es2022',
useDefineForClassFields: false, // This will eventually need updated when Angular switch to using TC39 Compliant code
},
}));
}
@ -116,8 +120,4 @@ function updateAppAndE2EProjectConfigurations(
removeProjectConfiguration(host, options.e2eProjectName);
}
}
// delete some default test configs
host.delete(`${options.appProjectRoot}/karma.conf.js`);
host.delete(`${options.appProjectRoot}/src/test.ts`);
}

View File

@ -1,76 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`component Generator --flat should create the component correctly and export it in the entry point 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator --flat should create the component correctly and not export it when "export=false" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator --path should create the component correctly and export it in the entry point 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator secondary entry points should create the component correctly and export it in the entry point 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
@ -82,19 +62,14 @@ export * from \\"./lib/example/example.component\\";"
`;
exports[`component Generator should create the component correctly and export it in the entry point when "export=true" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
@ -106,7 +81,7 @@ export * from \\"./lib/example/example.component\\";"
`;
exports[`component Generator should create the component correctly and export it in the entry point when is standalone and "export=true" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -116,38 +91,28 @@ import { CommonModule } from '@angular/common';
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator should create the component correctly and not export it in the entry point when "export=false" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator should create the component correctly and not export it in the entry point when is standalone and "export=false" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -157,50 +122,35 @@ import { CommonModule } from '@angular/common';
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator should create the component correctly and not export it when "--skip-import=true" 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"
`;
exports[`component Generator should create the component correctly but not export it in the entry point when it does not exist 1`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
"

View File

@ -16,14 +16,7 @@ describe(SomethingOneComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingOneComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingOneComponent,);
})
})
@ -46,14 +39,7 @@ describe(SomethingTwoComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingTwoComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingTwoComponent,);
})
})
@ -76,14 +62,7 @@ describe(SomethingThreeComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingThreeComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingThreeComponent,);
})
})
@ -106,14 +85,7 @@ describe(SomethingOneComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingOneComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingOneComponent,);
})
})
@ -136,14 +108,7 @@ describe(SomethingTwoComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingTwoComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingTwoComponent,);
})
})
@ -166,14 +131,7 @@ describe(SomethingThreeComponent.name, () => {
})
it('renders', () => {
cy.mount(SomethingThreeComponent, {
componentProperties: {
type: 'button',
style: 'default',
age: 0,
isOn: false,
}
});
cy.mount(SomethingThreeComponent,);
})
})

View File

@ -19,17 +19,11 @@ module.exports = withModuleFederation(config);"
`;
exports[`Host App Generator should generate a host with remotes using standalone components 1`] = `
"import { enableProdMode } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
"import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
import { AppComponent } from './app/app.component';
import { environment } from './environments/environment';
import { appRoutes } from './app/app.routes';
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())],
}).catch((err) => console.error(err));"

View File

@ -3,7 +3,7 @@
exports[`lib --standalone should generate a library with a standalone component and have it flat 1`] = `"export * from \\"./lib/my-lib.component\\";"`;
exports[`lib --standalone should generate a library with a standalone component and have it flat 2`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -13,12 +13,7 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css']
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -57,7 +52,7 @@ exports[`lib --standalone should generate a library with a standalone component
`;
exports[`lib --standalone should generate a library with a standalone component and have it flat with routing setup 2`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -67,12 +62,7 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css']
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -117,7 +107,7 @@ exports[`lib --standalone should generate a library with a standalone component
exports[`lib --standalone should generate a library with a standalone component as entry point 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
exports[`lib --standalone should generate a library with a standalone component as entry point 2`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -127,12 +117,7 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css']
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -168,7 +153,7 @@ describe('MyLibComponent', () => {
exports[`lib --standalone should generate a library with a standalone component as entry point and set up view encapsulation and change detection 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
exports[`lib --standalone should generate a library with a standalone component as entry point and set up view encapsulation and change detection 2`] = `
"import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
"import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -185,12 +170,7 @@ import { CommonModule } from '@angular/common';
encapsulation: ViewEncapsulation.ShadowDom,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -199,7 +179,7 @@ export class MyLibComponent implements OnInit {
exports[`lib --standalone should generate a library with a standalone component as entry point and skip tests 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
exports[`lib --standalone should generate a library with a standalone component as entry point and skip tests 2`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -214,12 +194,7 @@ import { CommonModule } from '@angular/common';
styles: [
]
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -228,7 +203,7 @@ export class MyLibComponent implements OnInit {
exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 1`] = `"export * from \\"./lib/my-lib/my-lib.component\\";"`;
exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 2`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -243,12 +218,7 @@ import { CommonModule } from '@angular/common';
styles: [
]
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"
@ -296,7 +266,7 @@ exports[`lib --standalone should generate a library with a standalone component
`;
exports[`lib --standalone should generate a library with a standalone component as entry point with routing setup 3`] = `
"import { Component, OnInit } from '@angular/core';
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -306,12 +276,7 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css']
})
export class MyLibComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class MyLibComponent {
}
"

View File

@ -1,7 +1,6 @@
import {
addProjectConfiguration,
generateFiles,
getWorkspaceLayout,
joinPathFragments,
offsetFromRoot,
readProjectConfiguration,
@ -11,9 +10,9 @@ import {
} from '@nrwl/devkit';
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils';
import * as path from 'path';
import { NormalizedSchema } from './normalized-schema';
import { updateNgPackage } from './update-ng-package';
import { join } from 'path';
export async function updateProject(
host: Tree,
@ -28,41 +27,48 @@ export async function updateProject(
function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
const libRoot = `${options.projectRoot}/src/lib/`;
const serviceSpecPath = path.join(libRoot, `${options.name}.service.spec.ts`);
const componentSpecPath = path.join(
const serviceSpecPath = joinPathFragments(
libRoot,
`${options.name}.service.spec.ts`
);
const componentSpecPath = joinPathFragments(
libRoot,
`${options.name}.component.spec.ts`
);
host.delete(path.join(libRoot, `${options.name}.service.ts`));
host.delete(joinPathFragments(libRoot, `${options.name}.service.ts`));
if (host.exists(serviceSpecPath)) {
host.delete(serviceSpecPath);
}
host.delete(path.join(libRoot, `${options.name}.component.ts`));
host.delete(joinPathFragments(libRoot, `${options.name}.component.ts`));
if (host.exists(componentSpecPath)) {
host.delete(path.join(libRoot, `${options.name}.component.spec.ts`));
host.delete(
joinPathFragments(libRoot, `${options.name}.component.spec.ts`)
);
}
if (!options.publishable && !options.buildable) {
host.delete(path.join(options.projectRoot, 'ng-package.json'));
host.delete(path.join(options.projectRoot, 'package.json'));
host.delete(path.join(options.projectRoot, 'tsconfig.lib.prod.json'));
host.delete(path.join(options.projectRoot, '.browserslistrc'));
host.delete(joinPathFragments(options.projectRoot, 'ng-package.json'));
host.delete(joinPathFragments(options.projectRoot, 'package.json'));
host.delete(
joinPathFragments(options.projectRoot, 'tsconfig.lib.prod.json')
);
host.delete(joinPathFragments(options.projectRoot, '.browserslistrc'));
}
host.delete(path.join(options.projectRoot, 'karma.conf.js'));
host.delete(path.join(options.projectRoot, 'src/test.ts'));
host.delete(path.join(options.projectRoot, 'tsconfig.spec.json'));
host.delete(joinPathFragments(options.projectRoot, 'karma.conf.js'));
host.delete(joinPathFragments(options.projectRoot, 'src/test.ts'));
host.delete(joinPathFragments(options.projectRoot, 'tsconfig.spec.json'));
if (options.name !== options.fileName) {
host.delete(path.join(libRoot, `${options.name}.module.ts`));
host.delete(joinPathFragments(libRoot, `${options.name}.module.ts`));
}
if (!options.skipModule && !options.standalone) {
host.write(
path.join(libRoot, `${options.fileName}.module.ts`),
joinPathFragments(libRoot, `${options.fileName}.module.ts`),
`
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@ -78,7 +84,7 @@ function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
if (options.unitTestRunner !== 'none' && options.addModuleSpec) {
host.write(
path.join(libRoot, `${options.fileName}.module.spec.ts`),
joinPathFragments(libRoot, `${options.fileName}.module.spec.ts`),
`
import { async, TestBed } from '@angular/core/testing';
import { ${options.moduleName} } from './${options.fileName}.module';
@ -117,19 +123,11 @@ function updateFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
}
function createFiles(host: Tree, options: NormalizedSchema['libraryOptions']) {
generateFiles(
host,
path.join(__dirname, '../files/lib'),
options.projectRoot,
{
generateFiles(host, join(__dirname, '../files/lib'), options.projectRoot, {
...options,
rootTsConfigPath: getRelativePathToRootTsConfig(
host,
options.projectRoot
),
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
tpl: '',
}
);
});
}
function fixProjectWorkspaceConfig(

View File

@ -54,7 +54,11 @@ function updateProjectConfig(
// tsconfig.json
updateJson(host, `${options.projectRoot}/tsconfig.json`, (json) => ({
...json,
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
compilerOptions: {
...json.compilerOptions,
target: 'es2022',
useDefineForClassFields: false,
},
}));
}

View File

@ -288,7 +288,8 @@ describe('lib', () => {
noImplicitOverride: true,
noImplicitReturns: true,
strict: true,
target: 'es2020',
target: 'es2022',
useDefineForClassFields: false,
},
files: [],
include: [],
@ -397,7 +398,6 @@ describe('lib', () => {
// ASSERT
const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.lib.json');
expect(tsconfigJson.exclude).toEqual([
'src/test.ts',
'**/*.spec.ts',
'jest.config.ts',
'**/*.test.ts',
@ -677,7 +677,8 @@ describe('lib', () => {
noImplicitOverride: true,
noImplicitReturns: true,
strict: true,
target: 'es2020',
target: 'es2022',
useDefineForClassFields: false,
},
files: [],
include: [],

View File

@ -1,11 +1,11 @@
import {
joinPathFragments,
offsetFromRoot,
ProjectConfiguration,
TargetConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { offsetFromRoot } from '@nrwl/devkit';
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
import { basename } from 'path';
import type {
@ -88,8 +88,9 @@ export class AngularDevkitKarmaMigrator extends BuilderMigrator {
target.options.main =
target.options.main && this.convertAsset(target.options.main);
target.options.polyfills =
target.options.polyfills && this.convertAsset(target.options.polyfills);
target.options.polyfills = Array.isArray(target.options.polyfills)
? target.options.polyfills.map((p) => this.convertAsset(p))
: target.options.polyfills && this.convertAsset(target.options.polyfills);
target.options.tsConfig =
target.options.tsConfig &&
joinPathFragments(

View File

@ -722,6 +722,56 @@ describe('app migrator', () => {
});
});
it('should update build target with array of polyfills', async () => {
const project = addProject('app1', {
root: '',
sourceRoot: 'src',
architect: {
build: {
builder: '@angular-devkit/build-angular:browser',
options: {
outputPath: 'dist/app1',
index: 'src/index.html',
main: 'src/main.ts',
polyfills: ['zone.js'],
tsConfig: 'tsconfig.app.json',
assets: ['src/favicon.ico', 'src/assets'],
styles: ['src/styles.css'],
scripts: [],
},
configurations: {
production: {},
development: {},
},
defaultConfiguration: 'production',
},
},
});
const migrator = new AppMigrator(tree, {}, project);
await migrator.migrate();
const { targets } = readProjectConfiguration(tree, 'app1');
expect(targets.build).toStrictEqual({
executor: '@angular-devkit/build-angular:browser',
options: {
outputPath: 'dist/apps/app1',
index: 'apps/app1/src/index.html',
main: 'apps/app1/src/main.ts',
polyfills: ['zone.js'],
tsConfig: 'apps/app1/tsconfig.app.json',
assets: ['apps/app1/src/favicon.ico', 'apps/app1/src/assets'],
styles: ['apps/app1/src/styles.css'],
scripts: [],
},
configurations: {
production: {},
development: {},
},
defaultConfiguration: 'production',
});
});
it('should update build target when using a target name different than "build"', async () => {
const project = addProject('app1', {
root: '',

View File

@ -197,7 +197,10 @@ export class AppMigrator extends ProjectMigrator<SupportedTargets> {
buildOptions.main =
buildOptions.main && this.convertAsset(buildOptions.main);
buildOptions.polyfills =
buildOptions.polyfills && this.convertAsset(buildOptions.polyfills);
buildOptions.polyfills &&
(Array.isArray(buildOptions.polyfills)
? buildOptions.polyfills.map((asset) => this.convertAsset(asset))
: this.convertAsset(buildOptions.polyfills as string));
buildOptions.tsConfig =
buildOptions.tsConfig &&
joinPathFragments(this.project.newRoot, basename(buildOptions.tsConfig));

View File

@ -257,17 +257,15 @@ import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import * as fromUsers from './+state/users.reducer';
import { UsersEffects } from './+state/users.effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { StoreRouterConnectingModule } from '@ngrx/router-store';
@NgModule({
imports: [BrowserModule, RouterModule.forRoot([]), StoreModule.forRoot({}, {
metaReducers: !environment.production ? [] : [],
metaReducers: [],
runtimeChecks: {
strictActionImmutability: true,
strictStateImmutability: true
}
}), EffectsModule.forRoot([UsersEffects]), !environment.production ? StoreDevtoolsModule.instrument() : [], StoreRouterConnectingModule.forRoot(), StoreModule.forFeature(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer)],
}), EffectsModule.forRoot([UsersEffects]), StoreRouterConnectingModule.forRoot(), StoreModule.forFeature(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer)],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
@ -283,17 +281,15 @@ exports[`ngrx should add an empty root module when minimal and root are set to t
import { AppComponent } from './app.component';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { StoreRouterConnectingModule } from '@ngrx/router-store';
@NgModule({
imports: [BrowserModule, RouterModule.forRoot([]), StoreModule.forRoot({}, {
metaReducers: !environment.production ? [] : [],
metaReducers: [],
runtimeChecks: {
strictActionImmutability: true,
strictStateImmutability: true
}
}), EffectsModule.forRoot([]), !environment.production ? StoreDevtoolsModule.instrument() : [], StoreRouterConnectingModule.forRoot()],
}), EffectsModule.forRoot([]), StoreRouterConnectingModule.forRoot()],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
@ -332,7 +328,7 @@ export const loadUsersFailure = createAction(
`;
exports[`ngrx should generate the ngrx effects 1`] = `
"import { Injectable } from '@angular/core';
"import { Injectable, inject } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';
import { fetch } from '@nrwl/angular';
@ -341,6 +337,8 @@ import * as UsersFeature from './users.reducer';
@Injectable()
export class UsersEffects {
private actions$ = inject(Actions);
init$ = createEffect(() => this.actions$.pipe(
ofType(UsersActions.initUsers),
fetch({
@ -354,14 +352,12 @@ export class UsersEffects {
}
})
));
constructor(private readonly actions$: Actions) {}
}
"
`;
exports[`ngrx should generate the ngrx facade 1`] = `
"import { Injectable } from '@angular/core';
"import { Injectable, inject } from '@angular/core';
import { select, Store, Action } from '@ngrx/store';
import * as UsersActions from './users.actions';
@ -370,6 +366,8 @@ import * as UsersSelectors from './users.selectors';
@Injectable()
export class UsersFacade {
private readonly store = inject(Store);
/**
* Combine pieces of state using createSelector,
* and expose them as observables through the facade.
@ -378,8 +376,6 @@ export class UsersFacade {
allUsers$ = this.store.pipe(select(UsersSelectors.getAllUsers));
selectedUsers$ = this.store.pipe(select(UsersSelectors.getSelected));
constructor(private readonly store: Store) {}
/**
* Use the initialization action to perform one
* or more tasks in your Effects.

View File

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { createEffect, Actions, ofType } from '@ngrx/effects';
import { fetch } from '@nrwl/angular';
@ -7,6 +7,8 @@ import * as <%= className %>Feature from './<%= fileName %>.reducer';
@Injectable()
export class <%= className %>Effects {
private actions$ = inject(Actions);
init$ = createEffect(() => this.actions$.pipe(
ofType(<%= className %>Actions.init<%= className %>),
fetch({
@ -20,6 +22,4 @@ export class <%= className %>Effects {
}
})
));
constructor(private readonly actions$: Actions) {}
}

View File

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { select, Store, Action } from '@ngrx/store';
import * as <%= className %>Actions from './<%= fileName %>.actions';
@ -7,6 +7,8 @@ import * as <%= className %>Selectors from './<%= fileName %>.selectors';
@Injectable()
export class <%= className %>Facade {
private readonly store = inject(Store);
/**
* Combine pieces of state using createSelector,
* and expose them as observables through the facade.
@ -15,8 +17,6 @@ export class <%= className %>Facade {
all<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.getAll<%= className %>));
selected<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.getSelected));
constructor(private readonly store: Store) {}
/**
* Use the initialization action to perform one
* or more tasks in your Effects.

View File

@ -50,7 +50,7 @@ export function addImportsToModule(
const propertyName = `${names(options.name).propertyName}`;
const reducerImports = `* as from${className}`;
const storeMetaReducers = `metaReducers: !environment.production ? [] : []`;
const storeMetaReducers = `metaReducers: []`;
const storeForRoot = `StoreModule.forRoot({}, {
${storeMetaReducers},
@ -63,7 +63,6 @@ export function addImportsToModule(
const effectsForEmptyRoot = `EffectsModule.forRoot([])`;
const storeForFeature = `StoreModule.forFeature(from${className}.${constantName}_FEATURE_KEY, from${className}.${propertyName}Reducer)`;
const effectsForFeature = `EffectsModule.forFeature([${effectsName}])`;
const devTools = `!environment.production ? StoreDevtoolsModule.instrument() : []`;
const storeRouterModule = 'StoreRouterConnectingModule.forRoot()';
// this is just a heuristic
@ -73,17 +72,6 @@ export function addImportsToModule(
sourceFile = addImport(sourceFile, 'EffectsModule', '@ngrx/effects');
if (options.minimal && options.root) {
sourceFile = addImport(
sourceFile,
'StoreDevtoolsModule',
'@ngrx/store-devtools'
);
sourceFile = addImport(
sourceFile,
'environment',
'../environments/environment'
);
sourceFile = addImportToModule(tree, sourceFile, modulePath, storeForRoot);
sourceFile = addImportToModule(
tree,
@ -91,7 +79,6 @@ export function addImportsToModule(
modulePath,
effectsForEmptyRoot
);
sourceFile = addImportToModule(tree, sourceFile, modulePath, devTools);
if (hasRouter) {
sourceFile = addImport(
@ -127,17 +114,6 @@ export function addImportsToModule(
if (options.root) {
sourceFile = addCommonImports();
sourceFile = addImport(
sourceFile,
'StoreDevtoolsModule',
'@ngrx/store-devtools'
);
sourceFile = addImport(
sourceFile,
'environment',
'../environments/environment'
);
sourceFile = addImportToModule(
tree,
sourceFile,
@ -150,7 +126,6 @@ export function addImportsToModule(
modulePath,
effectsForRoot
);
sourceFile = addImportToModule(tree, sourceFile, modulePath, devTools);
if (hasRouter) {
sourceFile = addImport(

View File

@ -26,7 +26,7 @@ describe('scam-to-standalone', () => {
expect(tree.read('apps/foo/src/app/bar/bar.component.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -36,12 +36,7 @@ describe('scam-to-standalone', () => {
templateUrl: './bar.component.html',
styleUrls: ['./bar.component.css']
})
export class BarComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class BarComponent {
}
"

View File

@ -48,7 +48,7 @@ describe('convertComponentToScam', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -56,12 +56,7 @@ describe('convertComponentToScam', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
@ -177,7 +172,7 @@ describe('convertComponentToScam', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -185,12 +180,7 @@ describe('convertComponentToScam', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
@ -310,7 +300,7 @@ describe('convertComponentToScam', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -318,12 +308,7 @@ describe('convertComponentToScam', () => {
templateUrl: './example.random.html',
styleUrls: ['./example.random.css']
})
export class ExampleRandom implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleRandom {
}
@ -444,7 +429,7 @@ describe('convertComponentToScam', () => {
'utf-8'
);
expect(componentModuleSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -452,12 +437,7 @@ describe('convertComponentToScam', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
@ -517,7 +497,7 @@ describe('convertComponentToScam', () => {
'utf-8'
);
expect(componentModuleSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -525,12 +505,7 @@ describe('convertComponentToScam', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}

View File

@ -25,7 +25,7 @@ describe('SCAM Generator', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -33,12 +33,7 @@ describe('SCAM Generator', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
@ -159,7 +154,7 @@ describe('SCAM Generator', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -167,12 +162,7 @@ describe('SCAM Generator', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}
@ -208,7 +198,7 @@ describe('SCAM Generator', () => {
'utf-8'
);
expect(componentSource).toMatchInlineSnapshot(`
"import { Component, OnInit, NgModule } from '@angular/core';
"import { Component, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
@ -216,12 +206,7 @@ describe('SCAM Generator', () => {
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
export class ExampleComponent {
}

View File

@ -0,0 +1,81 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import type { Tree } from '@nrwl/devkit';
import removeBrowserlistConfig, {
DEFAULT_BROWSERS,
} from './remove-browserlist-config';
import applicationGenerator from '../../generators/application/application';
describe('Migration to delete Browserslist configurations', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name: 'test',
});
});
describe('given the Browserslist config matches the default', () => {
it('should delete ".browserslistrc" file', async () => {
tree.write(
'apps/test/src/app/.browserslistrc',
DEFAULT_BROWSERS.join('\n')
);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
await removeBrowserlistConfig(tree);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeFalsy();
});
it(`should not delete "browserslist" in 'node_modules'`, async () => {
tree.write('node_modules/browserslist', DEFAULT_BROWSERS.join('\n'));
tree.write('node_modules/.browserslistrc', DEFAULT_BROWSERS.join('\n'));
await removeBrowserlistConfig(tree);
expect(tree.exists('node_modules/browserslist')).toBeTruthy();
expect(tree.exists('node_modules/.browserslistrc')).toBeTruthy();
});
});
describe('given the Browserslist config does not match the default', () => {
it('should not delete "browserslist"', async () => {
tree.write('apps/test/src/app/browserslist', 'last 1 Chrome version');
await removeBrowserlistConfig(tree);
expect(tree.exists('apps/test/src/app/browserslist')).toBeTruthy();
});
it('should not delete ".browserslistrc"', async () => {
tree.write('apps/test/src/app/.browserslistrc', 'last 1 Chrome version');
await removeBrowserlistConfig(tree);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
});
it('should delete ".browserslistrc" file when it only includes non supported ES5 browsers', async () => {
tree.write(
'apps/test/src/app/.browserslistrc',
[...DEFAULT_BROWSERS, 'IE 10'].join('\n')
);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
await removeBrowserlistConfig(tree);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeFalsy();
});
it('should not delete ".browserslistrc" file when it includes additional config sections', async () => {
tree.write(
'apps/test/src/app/.browserslistrc',
`
${DEFAULT_BROWSERS.join('\n')}
[modern]
last 1 chrome version
`
);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
await removeBrowserlistConfig(tree);
expect(tree.exists('apps/test/src/app/.browserslistrc')).toBeTruthy();
});
});
});

View File

@ -0,0 +1,77 @@
import type { Tree } from '@nrwl/devkit';
import { logger, visitNotIgnoredFiles } from '@nrwl/devkit';
import { basename } from 'path';
const validBrowserslistConfigFilenames = new Set([
'browserslist',
'.browserslistrc',
]);
export const DEFAULT_BROWSERS = [
'last 1 Chrome version',
'last 1 Firefox version',
'last 2 Edge major versions',
'last 2 Safari major versions',
'last 2 iOS major versions',
'Firefox ESR',
];
export default async function removeBrowserlistConfig(tree: Tree) {
let browserslist: any;
try {
browserslist = await import('browserslist');
} catch {
logger.warn(
'Skipping migration because the "browserslist" package could not be loaded.'
);
return;
}
// Set the defaults to match the defaults in build-angular.
browserslist.defaults = DEFAULT_BROWSERS;
const defaultSupportedBrowsers = new Set(browserslist(DEFAULT_BROWSERS));
const es5Browsers = new Set(browserslist(['supports es6-module']));
visitNotIgnoredFiles(tree, '/', (path) => {
const fileName = basename(path);
if (
!validBrowserslistConfigFilenames.has(fileName) ||
path.startsWith('node_modules')
) {
return;
}
const { defaults: browsersListConfig, ...otherConfigs } =
browserslist.parseConfig(tree.read(path, 'utf-8'));
if (Object.keys(otherConfigs).length) {
// The config contains additional sections.
return;
}
const browserslistInProject = browserslist(
// Exclude from the list ES5 browsers which are not supported.
browsersListConfig.map((s) => `${s} and supports es6-module`),
{
ignoreUnknownVersions: true,
}
);
if (defaultSupportedBrowsers.size !== browserslistInProject.length) {
return;
}
const shouldDelete = browserslistInProject.every((browser) =>
defaultSupportedBrowsers.has(browser)
);
if (shouldDelete) {
// All browsers are the same as the default config.
// Delete file as it's redundant.
tree.delete(path);
}
});
}

View File

@ -0,0 +1,109 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { DirEntry, Rule, UpdateRecorder } from '@angular-devkit/schematics';
import * as ts from 'typescript';
function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
for (const path of directory.subfiles) {
if (path.endsWith('.ts') && !path.endsWith('.d.ts')) {
const entry = directory.file(path);
if (entry) {
const content = entry.content;
if (
content.includes('@angular/platform-server') &&
content.includes('renderModule')
) {
const source = ts.createSourceFile(
entry.path,
content.toString().replace(/^\uFEFF/, ''),
ts.ScriptTarget.Latest,
true
);
yield source;
}
}
}
}
for (const path of directory.subdirs) {
if (path === 'node_modules' || path.startsWith('.')) {
continue;
}
yield* visit(directory.dir(path));
}
}
export default function (): Rule {
return (tree) => {
for (const sourceFile of visit(tree.root)) {
let recorder: UpdateRecorder | undefined;
let printer: ts.Printer | undefined;
ts.forEachChild(sourceFile, function analyze(node) {
if (
!(
ts.isExportDeclaration(node) &&
node.moduleSpecifier &&
ts.isStringLiteral(node.moduleSpecifier) &&
node.moduleSpecifier.text === '@angular/platform-server' &&
node.exportClause &&
ts.isNamedExports(node.exportClause)
)
) {
// Not a @angular/platform-server named export.
return;
}
const exportClause = node.exportClause;
const newElements: ts.ExportSpecifier[] = [];
for (const element of exportClause.elements) {
if (element.name.text !== 'renderModule') {
newElements.push(element);
}
}
if (newElements.length === exportClause.elements.length) {
// No changes
return;
}
recorder ??= tree.beginUpdate(sourceFile.fileName);
if (newElements.length) {
// Update named exports as there are leftovers.
const newExportClause = ts.factory.updateNamedExports(
exportClause,
newElements
);
printer ??= ts.createPrinter();
const fix = printer.printNode(
ts.EmitHint.Unspecified,
newExportClause,
sourceFile
);
const index = exportClause.getStart();
const length = exportClause.getWidth();
recorder.remove(index, length).insertLeft(index, fix);
} else {
// Delete export as no exports remain.
recorder.remove(node.getStart(), node.getWidth());
}
ts.forEachChild(node, analyze);
});
if (recorder) {
tree.commitUpdate(recorder);
}
}
};
}

View File

@ -0,0 +1,42 @@
import { readJson, Tree, writeJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import updateAngularCli from './update-angular-cli';
describe('update-angular-cli migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
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']).toEqual('~15.0.0');
});
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']).toEqual('~15.0.0');
});
it('should 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 '@nrwl/devkit';
const angularCliVersion = '~15.0.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

@ -0,0 +1,115 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { Rule, Tree } from '@angular-devkit/schematics';
import * as ts from 'typescript';
import { readWorkspace } from '@schematics/angular/utility';
import { Builders } from '@schematics/angular/utility/workspace-models';
import { allTargetOptions } from '@schematics/angular/utility/workspace';
export default function (): Rule {
return async (host) => {
for (const file of await findTestMainFiles(host)) {
updateTestFile(host, file);
}
};
}
async function findTestMainFiles(host: Tree): Promise<Set<string>> {
const testFiles = new Set<string>();
const workspace = await readWorkspace(host);
// find all test.ts files.
for (const project of workspace.projects.values()) {
for (const target of project.targets.values()) {
if (target.builder !== Builders.Karma) {
continue;
}
for (const [, options] of allTargetOptions(target)) {
if (typeof options.main === 'string' && host.exists(options.main)) {
testFiles.add(options.main);
}
}
}
}
return testFiles;
}
function updateTestFile(host: Tree, file: string): void {
const content = host.readText(file);
if (!content.includes('require.context')) {
return;
}
const sourceFile = ts.createSourceFile(
file,
content.replace(/^\uFEFF/, ''),
ts.ScriptTarget.Latest,
true
);
const usedVariableNames = new Set<string>();
const recorder = host.beginUpdate(sourceFile.fileName);
ts.forEachChild(sourceFile, (node) => {
if (ts.isVariableStatement(node)) {
const variableDeclaration = node.declarationList.declarations[0];
if (
ts
.getModifiers(node)
?.some((m) => m.kind === ts.SyntaxKind.DeclareKeyword)
) {
// `declare const require`
if (variableDeclaration.name.getText() !== 'require') {
return;
}
} else {
// `const context = require.context('./', true, /\.spec\.ts$/);`
if (
!variableDeclaration.initializer
?.getText()
.startsWith('require.context')
) {
return;
}
// add variable name as used.
usedVariableNames.add(variableDeclaration.name.getText());
}
// Delete node.
recorder.remove(node.getFullStart(), node.getFullWidth());
}
if (
usedVariableNames.size &&
ts.isExpressionStatement(node) && // context.keys().map(context);
ts.isCallExpression(node.expression) && // context.keys().map(context);
ts.isPropertyAccessExpression(node.expression.expression) && // context.keys().map
ts.isCallExpression(node.expression.expression.expression) && // context.keys()
ts.isPropertyAccessExpression(
node.expression.expression.expression.expression
) && // context.keys
ts.isIdentifier(
node.expression.expression.expression.expression.expression
) && // context
usedVariableNames.has(
node.expression.expression.expression.expression.expression.getText()
)
) {
// `context.keys().map(context);`
// `context.keys().forEach(context);`
recorder.remove(node.getFullStart(), node.getFullWidth());
}
});
host.commitUpdate(recorder);
}

View File

@ -0,0 +1,86 @@
import {
readJson,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
writeJson,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import applicationGenerator from '../../generators/application/application';
import updateTypescriptTarget from './update-typescript-target';
import { UnitTestRunner } from '@nrwl/angular/src/utils/test-runners';
describe('Migration to update target and add useDefineForClassFields', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name: 'test',
});
await applicationGenerator(tree, {
name: 'karma',
unitTestRunner: UnitTestRunner.Karma,
});
// Create tsconfigs
const compilerOptions = { target: 'es2015', module: 'es2020' };
const configWithExtends = {
extends: '../../tsconfig.base.json',
compilerOptions,
};
// Workspace
writeJson(tree, 'tsconfig.base.json', { compilerOptions });
// Application
writeJson(tree, 'apps/test/tsconfig.app.json', configWithExtends);
writeJson(tree, 'apps/test/tsconfig.app.prod.json', configWithExtends);
writeJson(tree, 'apps/test/tsconfig.spec.json', { compilerOptions });
writeJson(tree, 'apps/karma/tsconfig.spec.json', { compilerOptions });
});
it(`should not update target and not add useDefineForClassFields in workspace 'tsconfig.base.json'`, async () => {
await updateTypescriptTarget(tree);
const compilerOptions = readJson(
tree,
'tsconfig.base.json'
).compilerOptions;
expect(compilerOptions).toMatchInlineSnapshot(`
Object {
"module": "es2020",
"target": "es2015",
}
`);
});
it(`should add correct target value and useDefineForClassFields from tsconfig referenced in options and configuration`, async () => {
const project = readProjectConfiguration(tree, 'test');
project.targets.build.configurations.production.tsConfig =
'apps/test/tsconfig.app.prod.json';
updateProjectConfiguration(tree, 'test', project);
await updateTypescriptTarget(tree);
const compilerOptions = readJson(
tree,
'apps/test/tsconfig.app.prod.json'
).compilerOptions;
expect(compilerOptions['target']).toEqual('ES2022');
expect(compilerOptions['useDefineForClassFields']).toBeFalsy();
});
it('should add target and useDefineForClassFields when tsconfig is not extended', async () => {
await updateTypescriptTarget(tree);
const compilerOptions = readJson(
tree,
'apps/karma/tsconfig.spec.json'
).compilerOptions;
expect(compilerOptions).toMatchInlineSnapshot(`
Object {
"module": "es2020",
"target": "ES2022",
"useDefineForClassFields": false,
}
`);
});
});

View File

@ -0,0 +1,53 @@
import type { Tree } from '@nrwl/devkit';
import { getProjects, updateJson } from '@nrwl/devkit';
import { Builders } from '@schematics/angular/utility/workspace-models';
function updateTarget(tree: Tree, tsconfigPath: string) {
updateJson(tree, tsconfigPath, (json) => ({
...json,
compilerOptions: {
...(json.compilerOptions ?? {}),
target: 'ES2022',
useDefineForClassFields: false,
},
}));
}
export default async function updateTypescriptTarget(tree: Tree) {
const projects = getProjects(tree);
for (const [, project] of projects) {
for (const [, target] of Object.entries(project.targets)) {
// Update all other known CLI builders that use a tsconfig
const tsConfigs = [
target.options || {},
...Object.values(target.configurations || {}),
]
.filter((opt) => typeof opt?.tsConfig === 'string')
.map((opt) => (opt as { tsConfig: string }).tsConfig);
const uniqueTsConfigs = [...new Set(tsConfigs)];
if (uniqueTsConfigs.length < 1) {
continue;
}
const supportedExecutors = new Set([
Builders.Server,
Builders.Karma,
Builders.Browser,
Builders.NgPackagr,
'@nrwl/angular:webpack-browser',
'@nrwl/angular:ng-packagr-lite',
'@nrwl/angular:package',
'@nrwl/angular:delegate-build',
'@nrwl/jest:jest',
]);
if (supportedExecutors.has(target.executor)) {
for (const tsConfig of uniqueTsConfigs) {
updateTarget(tree, tsConfig);
}
}
}
}
}

View File

@ -0,0 +1,49 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import applicationGenerator from '../../generators/application/application';
import updateWorkspaceConfig from './update-workspace-config';
import {
readProjectConfiguration,
updateProjectConfiguration,
} from 'nx/src/generators/utils/project-configuration';
import { Builders } from '@schematics/angular/utility/workspace-models';
describe(`Migration to remove bundleDependencies`, () => {
it(`should remove 'bundleDependencies'`, async () => {
const tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name: 'test',
});
const project = readProjectConfiguration(tree, 'test');
project.targets.server = {
executor: Builders.Server,
options: {
main: './server.ts',
bundleDependencies: false,
sourceMaps: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
configurations: {
one: {
aot: true,
},
two: {
bundleDependencies: true,
aot: true,
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
};
updateProjectConfiguration(tree, 'test', project);
await updateWorkspaceConfig(tree);
const updatedProject = readProjectConfiguration(tree, 'test');
const { options, configurations } = updatedProject.targets.server;
expect(options.bundleDependencies).toBeUndefined();
expect(configurations).toBeDefined();
expect(configurations?.one.bundleDependencies).toBeUndefined();
expect(configurations?.two.bundleDependencies).toBeUndefined();
});
});

View File

@ -0,0 +1,28 @@
import type { Tree } from '@nrwl/devkit';
import { getProjects, updateProjectConfiguration } from '@nrwl/devkit';
import { Builders } from '@schematics/angular/utility/workspace-models';
export default function updateWorkspaceConfigurations(tree: Tree) {
const projects = getProjects(tree);
const supportedExecutors: Set<string> = new Set([Builders.Server]);
for (const [name, project] of projects) {
for (const [targetName, target] of Object.entries(project.targets)) {
if (!supportedExecutors.has(target.executor)) {
continue;
}
target.options.bundleDependencies = undefined;
for (const [configurationName, configuration] of Object.entries(
target.configurations
)) {
configuration.bundleDependencies = undefined;
target[configurationName] = configuration;
}
project.targets[targetName] = target;
updateProjectConfiguration(tree, name, project);
}
}
}

View File

@ -1,15 +1,15 @@
export const nxVersion = require('../../package.json').version;
export const angularVersion = '~14.2.0';
export const angularDevkitVersion = '~14.2.0';
export const ngPackagrVersion = '~14.2.0';
export const ngrxVersion = '~14.0.0';
export const angularVersion = '~15.0.0';
export const angularDevkitVersion = '~15.0.0';
export const ngPackagrVersion = '~15.0.0';
export const ngrxVersion = '~15.0.0-beta.0';
export const rxjsVersion = '~7.5.0';
export const zoneJsVersion = '~0.11.4';
export const angularJsVersion = '1.7.9';
export const tsLibVersion = '^2.3.0';
export const ngUniversalVersion = '~14.2.0';
export const ngUniversalVersion = '~15.0.0';
export const angularEslintVersion = '~14.0.4';
export const tailwindVersion = '^3.0.2';

View File

@ -1,7 +1,6 @@
export const nxVersion = require('../../package.json').version;
export const tslintToEslintConfigVersion = '^2.13.0';
export const buildAngularVersion = '~14.2.0';
export const typescriptESLintVersion = '^5.36.1';
export const eslintVersion = '~8.15.0';

View File

@ -18,6 +18,7 @@ const latestVersionWithOldFlag = '13.8.3';
const nxAngularVersionMap: Record<number, { range: string; max?: string }> = {
13: { range: '>= 13.2.0 < 14.2.0', max: '~14.1.0' },
14: { range: '>= 14.2.0' },
15: { range: '>= 15.0.0' },
};
// latest major version of Angular that is compatible with Nx, based on the map above
const latestCompatibleAngularMajorVersion = Math.max(

View File

@ -1,6 +1,6 @@
export const nxVersion = require('../../package.json').version;
export const angularCliVersion = '~14.2.0';
export const angularCliVersion = '~15.0.0';
export const typescriptVersion = '~4.8.2';
export const prettierVersion = '^2.6.2';
export const typescriptESLintVersion = '^5.36.1';

View File

@ -54,7 +54,7 @@
"stylus": "^0.55.0",
"stylus-loader": "^7.1.0",
"url-loader": "^4.1.1",
"webpack": "^5.58.1",
"webpack": "^5.75.0",
"webpack-merge": "^5.8.0"
},
"publishConfig": {

View File

@ -34,7 +34,7 @@
"@nrwl/workspace": "file:../workspace",
"autoprefixer": "^10.4.9",
"babel-loader": "^8.2.2",
"browserslist": "^4.16.6",
"browserslist": "^4.21.4",
"caniuse-lite": "^1.0.30001394",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
@ -70,7 +70,7 @@
"tsconfig-paths": "^3.9.0",
"tsconfig-paths-webpack-plugin": "3.5.2",
"tslib": "^2.3.0",
"webpack": "^5.58.1",
"webpack": "^5.75.0",
"webpack-dev-server": "^4.9.3",
"webpack-merge": "^5.8.0",
"webpack-node-externals": "^3.0.0",

View File

@ -2,7 +2,6 @@
exports[`preset should create files (preset = angular) 1`] = `
Array [
".browserslistrc",
"tsconfig.app.json",
"tsconfig.spec.json",
"src",
@ -18,10 +17,8 @@ Array [
"favicon.ico",
"index.html",
"main.ts",
"polyfills.ts",
"styles.css",
"assets",
"environments",
"app",
"test-setup.ts",
]

View File

@ -94,7 +94,7 @@ describe('renameNpmPackages Rule', () => {
tree = await runSchematic('lib', { name: 'library-1' }, tree);
tree = await runSchematic('lib', { name: 'library-2' }, tree);
tree = await runExternalSchematic(
'@nrwl/angular',
'@nrwl/react',
'application',
{ name: 'app-one' },
tree

View File

@ -1,7 +1,7 @@
import { Tree } from '@angular-devkit/schematics';
import { UnitTestTree } from '@angular-devkit/schematics/testing';
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
import { callRule, runSchematic, runExternalSchematic } from '../testing';
import { callRule, runExternalSchematic, runSchematic } from '../testing';
import { renamePackageImports } from './rename-package-imports';
describe('renamePackageImports Rule', () => {

View File

@ -1,6 +1,6 @@
export const nxVersion = require('../../package.json').version;
export const angularCliVersion = '~14.2.0';
export const angularCliVersion = '~15.0.0';
export const typescriptVersion = '~4.8.2';
export const prettierVersion = '^2.6.2';
export const typescriptESLintVersion = '^5.36.1';

2198
yarn.lock

File diff suppressed because it is too large Load Diff