feat(angular): support angular v14.0.0-rc.2 (#8883)

This commit is contained in:
Leosvel Pérez Espinosa 2022-05-30 21:09:00 +01:00 committed by GitHub
parent daddcde73c
commit 62afcb79b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 3421 additions and 1431 deletions

View File

@ -299,6 +299,11 @@
"default": false, "default": false,
"alias": "t" "alias": "t"
}, },
"standalone": {
"description": "Whether the generated component is standalone.",
"type": "boolean",
"default": false
},
"viewEncapsulation": { "viewEncapsulation": {
"description": "The view encapsulation strategy to use in the new component.", "description": "The view encapsulation strategy to use in the new component.",
"enum": ["Emulated", "None", "ShadowDom"], "enum": ["Emulated", "None", "ShadowDom"],
@ -2304,7 +2309,8 @@
"properties": { "properties": {
"input": { "input": {
"type": "string", "type": "string",
"description": "The file to include." "description": "The file to include.",
"pattern": "\\.[cm]?jsx?$"
}, },
"bundleName": { "bundleName": {
"type": "string", "type": "string",
@ -2320,7 +2326,11 @@
"additionalProperties": false, "additionalProperties": false,
"required": ["input"] "required": ["input"]
}, },
{ "type": "string", "description": "The file to include." } {
"type": "string",
"description": "The file to include.",
"pattern": "\\.[cm]?jsx?$"
}
] ]
} }
}, },
@ -2335,7 +2345,8 @@
"properties": { "properties": {
"input": { "input": {
"type": "string", "type": "string",
"description": "The file to include." "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$"
}, },
"bundleName": { "bundleName": {
"type": "string", "type": "string",
@ -2351,7 +2362,11 @@
"additionalProperties": false, "additionalProperties": false,
"required": ["input"] "required": ["input"]
}, },
{ "type": "string", "description": "The file to include." } {
"type": "string",
"description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$"
}
] ]
} }
}, },
@ -2606,15 +2621,9 @@
"description": "Extract all licenses in a separate file.", "description": "Extract all licenses in a separate file.",
"default": true "default": true
}, },
"showCircularDependencies": {
"type": "boolean",
"description": "Show circular dependency warnings on builds.",
"default": false,
"x-deprecated": "The recommended method to detect circular dependencies in project code is to use either a lint rule or other external tooling."
},
"buildOptimizer": { "buildOptimizer": {
"type": "boolean", "type": "boolean",
"description": "Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option.", "description": "Enables advanced build optimizations when using the 'aot' option.",
"default": true "default": true
}, },
"namedChunks": { "namedChunks": {
@ -2829,32 +2838,6 @@
} }
] ]
}, },
"extraEntryPoint": {
"oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include."
},
"bundleName": {
"type": "string",
"pattern": "^[\\w\\-.]*$",
"description": "The bundle name for this extra entry point."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": ["input"]
},
{ "type": "string", "description": "The file to include." }
]
},
"budget": { "budget": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -85,13 +85,13 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
updateFile('tsconfig.json', JSON.stringify(tsConfig, null, 2)); updateFile('tsconfig.json', JSON.stringify(tsConfig, null, 2));
// add an extra script file // add an extra script file
updateFile('src/scripts.ts', 'const x = 1;'); updateFile('src/scripts.js', 'const x = 1;');
// update angular.json // update angular.json
const angularJson = readJson('angular.json'); const angularJson = readJson('angular.json');
angularJson.projects[project].architect.build.options.scripts = angularJson.projects[project].architect.build.options.scripts =
angularJson.projects[project].architect.test.options.scripts = [ angularJson.projects[project].architect.test.options.scripts = [
'src/scripts.ts', 'src/scripts.js',
]; ];
angularJson.projects[project].architect.test.options.styles = [ angularJson.projects[project].architect.test.options.styles = [
'src/styles.css', 'src/styles.css',
@ -144,7 +144,6 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
defaultCollection: '@nrwl/angular', defaultCollection: '@nrwl/angular',
packageManager: packageManager, packageManager: packageManager,
}, },
defaultProject: project,
implicitDependencies: { implicitDependencies: {
'.eslintrc.json': '*', '.eslintrc.json': '*',
'package.json': { 'package.json': {
@ -196,7 +195,7 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
`apps/${project}/src/assets`, `apps/${project}/src/assets`,
], ],
styles: [`apps/${project}/src/styles.css`], styles: [`apps/${project}/src/styles.css`],
scripts: [`apps/${project}/src/scripts.ts`], scripts: [`apps/${project}/src/scripts.js`],
}, },
configurations: { configurations: {
production: { production: {
@ -251,7 +250,7 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
`apps/${project}/src/assets`, `apps/${project}/src/assets`,
], ],
styles: [`apps/${project}/src/styles.css`], styles: [`apps/${project}/src/styles.css`],
scripts: [`apps/${project}/src/scripts.ts`], scripts: [`apps/${project}/src/scripts.js`],
}, },
}); });
expect(projectConfig.targets.e2e).toBeUndefined(); expect(projectConfig.targets.e2e).toBeUndefined();
@ -271,7 +270,7 @@ describe('convert Angular CLI workspace to an Nx workspace', () => {
}, },
}); });
runCLI('build --configuration production --outputHashing none'); runCLI(`build ${project} --configuration production --outputHashing none`);
checkFilesExist(`dist/apps/${project}/main.js`); checkFilesExist(`dist/apps/${project}/main.js`);
}); });

View File

@ -193,44 +193,9 @@ describe('Angular Projects', () => {
runCLI( runCLI(
`generate @nrwl/angular:library ${childLib} --publishable=true --importPath=@${proj}/${childLib} --no-interactive` `generate @nrwl/angular:library ${childLib} --publishable=true --importPath=@${proj}/${childLib} --no-interactive`
); );
runCLI(
// create secondary entrypoint `generate @nrwl/angular:secondary-entry-point --name=sub --library=${childLib} --no-interactive`
updateFile(
`libs/${childLib}/sub/package.json`,
`
{
"ngPackage": {}
}
`
); );
updateFile(
`libs/${childLib}/sub/src/lib/sub.module.ts`,
`
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({ imports: [CommonModule] })
export class SubModule {}
`
);
updateFile(
`libs/${childLib}/sub/src/public_api.ts`,
`export * from './lib/sub.module';`
);
updateFile(
`libs/${childLib}/sub/src/index.ts`,
`export * from './public_api';`
);
updateFile(`tsconfig.base.json`, (s) => {
return s.replace(
`"@${proj}/${childLib}": ["libs/${childLib}/src/index.ts"],`,
`"@${proj}/${childLib}": ["libs/${childLib}/src/index.ts"],
"@${proj}/${childLib}/sub": ["libs/${childLib}/sub/src/index.ts"],
`
);
});
const moduleContent = ` const moduleContent = `
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';

View File

@ -260,14 +260,10 @@ export function runNgNew(
): string { ): string {
projName = projectName; projName = projectName;
// Use the latest version of the currently supported @angular/cli major version
// to cover existing usage out there while avoiding the tests to fail when a new
// major comes out and is still not supported
const ngCliMajorVersion = coerce(angularCliVersion).major;
const npmMajorVersion = getNpmMajorVersion(); const npmMajorVersion = getNpmMajorVersion();
const command = `npx ${ const command = `npx ${
+npmMajorVersion >= 7 ? '--yes' : '' +npmMajorVersion >= 7 ? '--yes' : ''
} @angular/cli@${ngCliMajorVersion} new ${projectName} --package-manager=${packageManager}`; } @angular/cli@${angularCliVersion} new ${projectName} --package-manager=${packageManager}`;
return execSync(command, { return execSync(command, {
cwd: e2eCwd, cwd: e2eCwd,

View File

@ -469,7 +469,6 @@ describe('Move Angular Project', () => {
expect(moveOutput).toContain( expect(moveOutput).toContain(
`CREATE apps/${newPath}/src/environments/environment.ts` `CREATE apps/${newPath}/src/environments/environment.ts`
); );
expect(moveOutput).toContain(`UPDATE nx.json`);
expect(moveOutput).toContain(`UPDATE workspace.json`); expect(moveOutput).toContain(`UPDATE workspace.json`);
}); });

View File

@ -25,24 +25,24 @@
"prepare": "is-ci || husky install" "prepare": "is-ci || husky install"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/architect": "~0.1303.0", "@angular-devkit/architect": "~0.1400.0-rc.2",
"@angular-devkit/build-angular": "~13.3.0", "@angular-devkit/build-angular": "~14.0.0-rc.2",
"@angular-devkit/core": "~13.3.0", "@angular-devkit/core": "~14.0.0-rc.2",
"@angular-devkit/schematics": "~13.3.0", "@angular-devkit/schematics": "~14.0.0-rc.2",
"@angular-eslint/eslint-plugin": "~13.1.0", "@angular-eslint/eslint-plugin": "~13.2.1",
"@angular-eslint/eslint-plugin-template": "~13.1.0", "@angular-eslint/eslint-plugin-template": "~13.2.1",
"@angular-eslint/template-parser": "~13.1.0", "@angular-eslint/template-parser": "~13.2.1",
"@angular/cli": "~13.3.0", "@angular/cli": "~14.0.0-rc.2",
"@angular/common": "~13.3.0", "@angular/common": "~14.0.0-rc.2",
"@angular/compiler": "~13.3.0", "@angular/compiler": "~14.0.0-rc.2",
"@angular/compiler-cli": "~13.3.0", "@angular/compiler-cli": "~14.0.0-rc.2",
"@angular/core": "~13.3.0", "@angular/core": "~14.0.0-rc.2",
"@angular/forms": "~13.3.0", "@angular/forms": "~14.0.0-rc.2",
"@angular/platform-browser": "~13.3.0", "@angular/platform-browser": "~14.0.0-rc.2",
"@angular/platform-browser-dynamic": "~13.3.0", "@angular/platform-browser-dynamic": "~14.0.0-rc.2",
"@angular/router": "~13.3.0", "@angular/router": "~14.0.0-rc.2",
"@angular/service-worker": "~13.3.0", "@angular/service-worker": "~14.0.0-rc.2",
"@angular/upgrade": "~13.3.0", "@angular/upgrade": "~14.0.0-rc.2",
"@babel/helper-create-regexp-features-plugin": "^7.14.5", "@babel/helper-create-regexp-features-plugin": "^7.14.5",
"@cypress/webpack-preprocessor": "^5.9.1", "@cypress/webpack-preprocessor": "^5.9.1",
"@nestjs/common": "^8.0.0", "@nestjs/common": "^8.0.0",
@ -51,13 +51,13 @@
"@nestjs/schematics": "^8.0.0", "@nestjs/schematics": "^8.0.0",
"@nestjs/swagger": "^5.0.9", "@nestjs/swagger": "^5.0.9",
"@nestjs/testing": "^8.0.0", "@nestjs/testing": "^8.0.0",
"@ngrx/component-store": "~13.0.0", "@ngrx/component-store": "~13.2.0",
"@ngrx/effects": "~13.0.0", "@ngrx/effects": "~13.2.0",
"@ngrx/entity": "~13.0.0", "@ngrx/entity": "~13.2.0",
"@ngrx/router-store": "~13.0.0", "@ngrx/router-store": "~13.2.0",
"@ngrx/schematics": "~13.0.0", "@ngrx/schematics": "~13.2.0",
"@ngrx/store": "~13.0.0", "@ngrx/store": "~13.2.0",
"@ngrx/store-devtools": "~13.0.0", "@ngrx/store-devtools": "~13.2.0",
"@nrwl/eslint-plugin-nx": "14.1.9-beta.1", "@nrwl/eslint-plugin-nx": "14.1.9-beta.1",
"@nrwl/jest": "14.1.9-beta.1", "@nrwl/jest": "14.1.9-beta.1",
"@nrwl/next": "14.1.9-beta.1", "@nrwl/next": "14.1.9-beta.1",
@ -74,7 +74,7 @@
"@rollup/plugin-image": "^2.1.0", "@rollup/plugin-image": "^2.1.0",
"@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",
"@schematics/angular": "~13.3.0", "@schematics/angular": "~14.0.0-rc.2",
"@storybook/addon-essentials": "~6.5.4", "@storybook/addon-essentials": "~6.5.4",
"@storybook/addon-knobs": "~6.3.0", "@storybook/addon-knobs": "~6.3.0",
"@storybook/angular": "~6.5.4", "@storybook/angular": "~6.5.4",
@ -107,9 +107,9 @@
"@types/tar-stream": "^2.2.2", "@types/tar-stream": "^2.2.2",
"@types/tmp": "^0.2.0", "@types/tmp": "^0.2.0",
"@types/yargs": "^17.0.10", "@types/yargs": "^17.0.10",
"@typescript-eslint/eslint-plugin": "5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/experimental-utils": "5.18.0", "@typescript-eslint/experimental-utils": "~5.24.0",
"@typescript-eslint/parser": "5.18.0", "@typescript-eslint/parser": "~5.24.0",
"@xstate/immer": "^0.2.0", "@xstate/immer": "^0.2.0",
"@xstate/inspect": "^0.5.1", "@xstate/inspect": "^0.5.1",
"@xstate/react": "^1.6.3", "@xstate/react": "^1.6.3",
@ -135,7 +135,7 @@
"dotenv": "~10.0.0", "dotenv": "~10.0.0",
"ejs": "^3.1.7", "ejs": "^3.1.7",
"enhanced-resolve": "^5.8.3", "enhanced-resolve": "^5.8.3",
"eslint": "8.12.0", "eslint": "8.15.0",
"eslint-config-next": "12.1.5", "eslint-config-next": "12.1.5",
"eslint-config-prettier": "^8.1.0", "eslint-config-prettier": "^8.1.0",
"eslint-plugin-cypress": "^2.10.3", "eslint-plugin-cypress": "^2.10.3",
@ -164,7 +164,7 @@
"jasmine-spec-reporter": "~4.2.1", "jasmine-spec-reporter": "~4.2.1",
"jest": "27.5.1", "jest": "27.5.1",
"jest-circus": "27.2.3", "jest-circus": "27.2.3",
"jest-preset-angular": "11.1.1", "jest-preset-angular": "~11.1.2",
"jsonc-eslint-parser": "^2.1.0", "jsonc-eslint-parser": "^2.1.0",
"jsonc-parser": "3.0.0", "jsonc-parser": "3.0.0",
"karma": "~4.0.0", "karma": "~4.0.0",
@ -185,7 +185,7 @@
"mini-css-extract-plugin": "~2.4.7", "mini-css-extract-plugin": "~2.4.7",
"minimatch": "3.0.5", "minimatch": "3.0.5",
"next-sitemap": "^1.6.108", "next-sitemap": "^1.6.108",
"ng-packagr": "~13.3.0", "ng-packagr": "~14.0.0-rc.0",
"ngrx-store-freeze": "0.2.4", "ngrx-store-freeze": "0.2.4",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"nx": "14.1.9-beta.1", "nx": "14.1.9-beta.1",
@ -301,7 +301,6 @@
"weak-napi": "^2.0.2" "weak-napi": "^2.0.2"
}, },
"resolutions": { "resolutions": {
"ng-packagr/rxjs": "6.6.7",
"**/xmlhttprequest-ssl": "~1.6.2", "**/xmlhttprequest-ssl": "~1.6.2",
"minimist": "^1.2.6" "minimist": "^1.2.6"
} }

View File

@ -112,6 +112,36 @@
"version": "14.0.0-beta.1", "version": "14.0.0-beta.1",
"description": "Rename mfe.config.js to module-federation.config.js for consistent terminology.", "description": "Rename mfe.config.js to module-federation.config.js for consistent terminology.",
"factory": "./src/migrations/update-14-0-0/rename-mf-config" "factory": "./src/migrations/update-14-0-0/rename-mf-config"
},
"remove-show-circular-dependencies-option": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Remove 'showCircularDependencies' option from browser and server executors.",
"factory": "./src/migrations/update-14-2-0/remove-show-circular-dependencies-option"
},
"update-angular-cli-version": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update the @angular/cli package version.",
"factory": "./src/migrations/update-14-2-0/update-angular-cli"
},
"update-libraries-secondary-entrypoints": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Remove 'package.json' files from library projects secondary entrypoints.",
"factory": "./src/migrations/update-14-2-0/update-libraries-secondary-entrypoints"
},
"update-postinstall-script-ngcc-target": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update postinstall script running ngcc to use ES2020 target.",
"factory": "./src/migrations/update-14-2-0/update-ngcc-target"
},
"update-tsconfig-target": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update TypeScript compilation target to 'ES2020'.",
"factory": "./src/migrations/update-14-2-0/update-tsconfig-target"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {
@ -1088,6 +1118,87 @@
"alwaysAddToPackageJson": false "alwaysAddToPackageJson": false
} }
} }
},
"14.2.0": {
"version": "14.2.0-beta.0",
"packages": {
"@angular-devkit/architect": {
"version": "~0.1400.0-rc.2",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~14.0.0-rc.2",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1400.0-rc.2",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~14.0.0-rc.2",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~14.0.0-rc.2",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~14.0.0-rc.2",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~14.0.0-rc.1",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~14.0.0-rc.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin-template": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@angular-eslint/template-parser": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@ngrx/store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/effects": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/entity": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/router-store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/schematics": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/store-devtools": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/component-store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"jest-preset-angular": {
"version": "~11.1.2",
"alwaysAddToPackageJson": false
}
}
} }
} }
} }

View File

@ -37,7 +37,7 @@
"migrations": "./migrations.json" "migrations": "./migrations.json"
}, },
"dependencies": { "dependencies": {
"@angular-devkit/schematics": "~13.3.0", "@angular-devkit/schematics": "~14.0.0-rc.2",
"@nrwl/cypress": "file:../cypress", "@nrwl/cypress": "file:../cypress",
"@nrwl/devkit": "file:../devkit", "@nrwl/devkit": "file:../devkit",
"@nrwl/jest": "file:../jest", "@nrwl/jest": "file:../jest",
@ -45,7 +45,7 @@
"@nrwl/storybook": "file:../storybook", "@nrwl/storybook": "file:../storybook",
"@nrwl/workspace": "file:../workspace", "@nrwl/workspace": "file:../workspace",
"@phenomnomnominal/tsquery": "4.1.1", "@phenomnomnominal/tsquery": "4.1.1",
"@schematics/angular": "~13.3.0", "@schematics/angular": "~14.0.0-rc.2",
"chalk": "4.1.0", "chalk": "4.1.0",
"chokidar": "^3.5.1", "chokidar": "^3.5.1",
"http-server": "^14.1.0", "http-server": "^14.1.0",

View File

@ -47,7 +47,35 @@
"type": "array", "type": "array",
"default": [], "default": [],
"items": { "items": {
"$ref": "#/definitions/extraEntryPoint" "oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include.",
"pattern": "\\.[cm]?jsx?$"
},
"bundleName": {
"type": "string",
"pattern": "^[\\w\\-.]*$",
"description": "The bundle name for this extra entry point."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": ["input"]
},
{
"type": "string",
"description": "The file to include.",
"pattern": "\\.[cm]?jsx?$"
}
]
} }
}, },
"styles": { "styles": {
@ -55,7 +83,35 @@
"type": "array", "type": "array",
"default": [], "default": [],
"items": { "items": {
"$ref": "#/definitions/extraEntryPoint" "oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$"
},
"bundleName": {
"type": "string",
"pattern": "^[\\w\\-.]*$",
"description": "The bundle name for this extra entry point."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": ["input"]
},
{
"type": "string",
"description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$"
}
]
} }
}, },
"inlineStyleLanguage": { "inlineStyleLanguage": {
@ -291,15 +347,9 @@
"description": "Extract all licenses in a separate file.", "description": "Extract all licenses in a separate file.",
"default": true "default": true
}, },
"showCircularDependencies": {
"type": "boolean",
"description": "Show circular dependency warnings on builds.",
"default": false,
"x-deprecated": "The recommended method to detect circular dependencies in project code is to use either a lint rule or other external tooling."
},
"buildOptimizer": { "buildOptimizer": {
"type": "boolean", "type": "boolean",
"description": "Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option.", "description": "Enables advanced build optimizations when using the 'aot' option.",
"default": true "default": true
}, },
"namedChunks": { "namedChunks": {
@ -471,35 +521,6 @@
} }
] ]
}, },
"extraEntryPoint": {
"oneOf": [
{
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The file to include."
},
"bundleName": {
"type": "string",
"pattern": "^[\\w\\-.]*$",
"description": "The bundle name for this extra entry point."
},
"inject": {
"type": "boolean",
"description": "If the bundle will be referenced in the HTML file.",
"default": true
}
},
"additionalProperties": false,
"required": ["input"]
},
{
"type": "string",
"description": "The file to include."
}
]
},
"budget": { "budget": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -7,6 +7,7 @@
*/ */
import { logger } from '@nrwl/devkit'; import { logger } from '@nrwl/devkit';
import { BuildGraph } from 'ng-packagr/lib/graph/build-graph';
import { Node } from 'ng-packagr/lib/graph/node'; import { Node } from 'ng-packagr/lib/graph/node';
import { transformFromPromise } from 'ng-packagr/lib/graph/transform'; import { transformFromPromise } from 'ng-packagr/lib/graph/transform';
import { NgEntryPoint } from 'ng-packagr/lib/ng-package/entry-point/entry-point'; import { NgEntryPoint } from 'ng-packagr/lib/ng-package/entry-point/entry-point';
@ -22,6 +23,7 @@ import { NgPackage } from 'ng-packagr/lib/ng-package/package';
import { copyFile, rmdir, stat, writeFile } from 'ng-packagr/lib/utils/fs'; import { copyFile, rmdir, stat, writeFile } from 'ng-packagr/lib/utils/fs';
import { globFiles } from 'ng-packagr/lib/utils/glob'; import { globFiles } from 'ng-packagr/lib/utils/glob';
import { ensureUnixPath } from 'ng-packagr/lib/utils/path'; import { ensureUnixPath } from 'ng-packagr/lib/utils/path';
import { AssetPattern } from 'ng-packagr/ng-package.schema';
import * as path from 'path'; import * as path from 'path';
export const nxWritePackageTransform = (options: NgPackagrOptions) => export const nxWritePackageTransform = (options: NgPackagrOptions) =>
@ -31,93 +33,133 @@ export const nxWritePackageTransform = (options: NgPackagrOptions) =>
const ngPackageNode: PackageNode = graph.find(isPackage); const ngPackageNode: PackageNode = graph.find(isPackage);
const ngPackage = ngPackageNode.data; const ngPackage = ngPackageNode.data;
const { destinationFiles } = entryPoint.data; const { destinationFiles } = entryPoint.data;
const ignorePaths: string[] = [
'.gitkeep',
'**/.DS_Store',
'**/Thumbs.db',
'**/node_modules/**',
`${ngPackage.dest}/**`,
];
if (!ngEntryPoint.isSecondaryEntryPoint) { if (!ngEntryPoint.isSecondaryEntryPoint) {
const assetFiles: string[] = [];
// COPY ASSET FILES TO DESTINATION
logger.log('Copying assets'); logger.log('Copying assets');
try { try {
for (const asset of ngPackage.assets) { await copyAssets(graph, entryPoint, ngPackageNode);
let assetFullPath = path.join(ngPackage.src, asset);
try {
const stats = await stat(assetFullPath);
if (stats.isFile()) {
assetFiles.push(assetFullPath);
continue;
}
if (stats.isDirectory()) {
assetFullPath = path.join(assetFullPath, '**/*');
}
} catch {}
const files = await globFiles(assetFullPath, {
ignore: ignorePaths,
cache: ngPackageNode.cache.globCache,
dot: true,
nodir: true,
});
if (files.length) {
assetFiles.push(...files);
}
}
for (const file of assetFiles) {
const relativePath = path.relative(ngPackage.src, file);
const destination = path.resolve(ngPackage.dest, relativePath);
const nodeUri = fileUrl(ensureUnixPath(file));
let node = graph.get(nodeUri);
if (!node) {
node = new Node(nodeUri);
graph.put(node);
}
entryPoint.dependsOn(node);
await copyFile(file, destination);
}
} catch (error) { } catch (error) {
throw error; throw error;
} }
} }
// 6. WRITE PACKAGE.JSON // 6. WRITE PACKAGE.JSON
try { // As of APF 14 only the primary entrypoint has a package.json
logger.info('Writing package metadata'); if (!ngEntryPoint.isSecondaryEntryPoint) {
const relativeUnixFromDestPath = (filePath: string) => try {
ensureUnixPath(path.relative(ngEntryPoint.destinationPath, filePath)); logger.info('Writing package manifest');
const relativeUnixFromDestPath = (filePath: string) =>
ensureUnixPath(path.relative(ngEntryPoint.destinationPath, filePath));
await writePackageJson( await writePackageJson(
ngEntryPoint, ngEntryPoint,
ngPackage, ngPackage,
{ {
module: relativeUnixFromDestPath(destinationFiles.esm2020), module: relativeUnixFromDestPath(destinationFiles.esm2020),
es2020: relativeUnixFromDestPath(destinationFiles.esm2020), es2020: relativeUnixFromDestPath(destinationFiles.esm2020),
esm2020: relativeUnixFromDestPath(destinationFiles.esm2020), esm2020: relativeUnixFromDestPath(destinationFiles.esm2020),
typings: relativeUnixFromDestPath(destinationFiles.declarations), typings: relativeUnixFromDestPath(destinationFiles.declarations),
// webpack v4+ specific flag to enable advanced optimizations and code splitting // webpack v4+ specific flag to enable advanced optimizations and code splitting
sideEffects: ngEntryPoint.packageJson.sideEffects ?? false, sideEffects: ngEntryPoint.packageJson.sideEffects ?? false,
}, },
!!options.watch !!options.watch
); );
} catch (error) { } catch (error) {
throw error; throw error;
}
} }
logger.info(`Built ${ngEntryPoint.moduleId}`); logger.info(`Built ${ngEntryPoint.moduleId}`);
return graph; return graph;
}); });
type AssetEntry = Exclude<AssetPattern, string>;
async function copyAssets(
graph: BuildGraph,
entryPointNode: EntryPointNode,
ngPackageNode: PackageNode
): Promise<void> {
const ngPackage = ngPackageNode.data;
const globsForceIgnored: string[] = [
'.gitkeep',
'**/.DS_Store',
'**/Thumbs.db',
`${ngPackage.dest}/**`,
];
const assets: AssetEntry[] = [];
for (const item of ngPackage.assets) {
const asset: Partial<AssetEntry> = {};
if (typeof item == 'object') {
asset.glob = item.glob;
asset.input = path.join(ngPackage.src, item.input);
asset.output = path.join(ngPackage.dest, item.output);
asset.ignore = item.ignore;
} else {
const assetPath = item; // might be a glob
const assetFullPath = path.join(ngPackage.src, assetPath);
const [isDir, isFile] = await stat(assetFullPath)
.then((stats) => [stats.isDirectory(), stats.isFile()])
.catch(() => [false, false]);
if (isDir) {
asset.glob = '**/*';
asset.input = assetFullPath;
asset.output = path.join(ngPackage.dest, assetPath);
} else if (isFile) {
asset.glob = path.basename(assetFullPath); // filenames are their own glob
asset.input = path.dirname(assetFullPath);
asset.output = path.dirname(path.join(ngPackage.dest, assetPath));
} else {
asset.glob = assetPath;
asset.input = ngPackage.src;
asset.output = ngPackage.dest;
}
}
const isAncestorPath = (target: string, datum: string) =>
path.relative(datum, target).startsWith('..');
if (isAncestorPath(asset.input, ngPackage.src)) {
throw new Error(
'Cannot read assets from a location outside of the project root.'
);
}
if (isAncestorPath(asset.output, ngPackage.dest)) {
throw new Error(
'Cannot write assets to a location outside of the output path.'
);
}
assets.push(asset as AssetEntry);
}
for (const asset of assets) {
const filePaths = await globFiles(asset.glob, {
cwd: asset.input,
ignore: [...(asset.ignore ?? []), ...globsForceIgnored],
cache: ngPackageNode.cache.globCache,
dot: true,
nodir: true,
follow: asset.followSymlinks,
});
for (const filePath of filePaths) {
const fileSrcFullPath = path.join(asset.input, filePath);
const fileDestFullPath = path.join(asset.output, filePath);
const nodeUri = fileUrl(ensureUnixPath(fileSrcFullPath));
let node = graph.get(nodeUri);
if (!node) {
node = new Node(nodeUri);
graph.put(node);
}
entryPointNode.dependsOn(node);
await copyFile(fileSrcFullPath, fileDestFullPath);
}
}
}
/** /**
* Creates and writes a `package.json` file of the entry point used by the `node_module` * Creates and writes a `package.json` file of the entry point used by the `node_module`
* resolution strategies. * resolution strategies.
@ -146,41 +188,39 @@ async function writePackageJson(
// version at least matches that of angular if we use require('tslib').version // version at least matches that of angular if we use require('tslib').version
// it will get what installed and not the minimum version nor if it is a `~` or `^` // it will get what installed and not the minimum version nor if it is a `~` or `^`
// this is only required for primary // this is only required for primary
if (!entryPoint.isSecondaryEntryPoint) { if (isWatchMode) {
if (isWatchMode) { // Needed because of Webpack's 5 `cachemanagedpaths`
// Needed because of Webpack's 5 `cachemanagedpaths` // https://github.com/angular/angular-cli/issues/20962
// https://github.com/angular/angular-cli/issues/20962 packageJson.version = `0.0.0-watch+${Date.now()}`;
packageJson.version = `0.0.0-watch+${Date.now()}`; }
}
if ( if (
!packageJson.peerDependencies?.tslib && !packageJson.peerDependencies?.tslib &&
!packageJson.dependencies?.tslib !packageJson.dependencies?.tslib
) { ) {
const { const {
peerDependencies: angularPeerDependencies = {}, peerDependencies: angularPeerDependencies = {},
dependencies: angularDependencies = {}, dependencies: angularDependencies = {},
} = require('@angular/compiler/package.json'); } = require('@angular/compiler/package.json');
const tsLibVersion = const tsLibVersion =
angularPeerDependencies.tslib || angularDependencies.tslib; angularPeerDependencies.tslib || angularDependencies.tslib;
if (tsLibVersion) { if (tsLibVersion) {
packageJson.dependencies = {
...packageJson.dependencies,
tslib: tsLibVersion,
};
}
} else if (packageJson.peerDependencies?.tslib) {
logger.warn(
`'tslib' is no longer recommended to be used as a 'peerDependencies'. Moving it to 'dependencies'.`
);
packageJson.dependencies = { packageJson.dependencies = {
...(packageJson.dependencies || {}), ...packageJson.dependencies,
tslib: packageJson.peerDependencies.tslib, tslib: tsLibVersion,
}; };
delete packageJson.peerDependencies.tslib;
} }
} else if (packageJson.peerDependencies?.tslib) {
logger.warn(
`'tslib' is no longer recommended to be used as a 'peerDependencies'. Moving it to 'dependencies'.`
);
packageJson.dependencies = {
...(packageJson.dependencies || {}),
tslib: packageJson.peerDependencies.tslib,
};
delete packageJson.peerDependencies.tslib;
} }
// Verify non-peerDependencies as they can easily lead to duplicate installs or version conflicts // Verify non-peerDependencies as they can easily lead to duplicate installs or version conflicts

View File

@ -12,12 +12,10 @@ import { BuildGraph } from 'ng-packagr/lib/graph/build-graph';
import { Node } from 'ng-packagr/lib/graph/node'; import { Node } from 'ng-packagr/lib/graph/node';
import { EntryPointNode, fileUrl } from 'ng-packagr/lib/ng-package/nodes'; import { EntryPointNode, fileUrl } from 'ng-packagr/lib/ng-package/nodes';
import { ensureUnixPath } from 'ng-packagr/lib/utils/path'; import { ensureUnixPath } from 'ng-packagr/lib/utils/path';
import { NgPackageConfig } from 'ng-packagr/ng-package.schema';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
import { import { StylesheetProcessor } from '../styles/stylesheet-processor';
InlineStyleLanguage,
StylesheetProcessor,
} from '../styles/stylesheet-processor';
export function cacheCompilerHost( export function cacheCompilerHost(
graph: BuildGraph, graph: BuildGraph,
@ -25,7 +23,7 @@ export function cacheCompilerHost(
compilerOptions: CompilerOptions, compilerOptions: CompilerOptions,
moduleResolutionCache: ts.ModuleResolutionCache, moduleResolutionCache: ts.ModuleResolutionCache,
stylesheetProcessor?: StylesheetProcessor, stylesheetProcessor?: StylesheetProcessor,
inlineStyleLanguage?: InlineStyleLanguage, inlineStyleLanguage?: NgPackageConfig['inlineStyleLanguage'],
sourcesFileCache: FileCache = entryPoint.cache.sourcesFileCache sourcesFileCache: FileCache = entryPoint.cache.sourcesFileCache
): CompilerHost { ): CompilerHost {
const compilerHost = ts.createIncrementalCompilerHost(compilerOptions); const compilerHost = ts.createIncrementalCompilerHost(compilerOptions);
@ -47,6 +45,11 @@ export function cacheCompilerHost(
entryPoint.dependsOn(node); entryPoint.dependsOn(node);
}; };
const { flatModuleFile, entryFile } = entryPoint.data.entryPoint;
const flatModuleFileDtsFilename = `${flatModuleFile}.d.ts`;
const hasIndexEntryFile =
path.basename(entryFile.toLowerCase()) === 'index.ts';
return { return {
...compilerHost, ...compilerHost,
@ -82,6 +85,18 @@ export function cacheCompilerHost(
sourceFiles?: ReadonlyArray<ts.SourceFile> sourceFiles?: ReadonlyArray<ts.SourceFile>
) => { ) => {
if (fileName.endsWith('.d.ts')) { if (fileName.endsWith('.d.ts')) {
if (
hasIndexEntryFile &&
path.basename(fileName) === flatModuleFileDtsFilename
) {
// In case the entry file is index.ts, we should not emit the `d.ts` which are a re-export of the `index.ts`.
// Because it will cause a conflict.
return;
}
// Rename file to index.d.ts so that TypeScript can resolve types without
// them needing to be referenced in the package.json manifest.
fileName = fileName.replace(flatModuleFileDtsFilename, 'index.d.ts');
sourceFiles.forEach((source) => { sourceFiles.forEach((source) => {
const cache = sourcesFileCache.getOrCreate(source.fileName); const cache = sourcesFileCache.getOrCreate(source.fileName);
if (!cache.declarationFileName) { if (!cache.declarationFileName) {

View File

@ -17,7 +17,7 @@ import {
saveCacheEntry, saveCacheEntry,
} from 'ng-packagr/lib/utils/cache'; } from 'ng-packagr/lib/utils/cache';
import * as log from 'ng-packagr/lib/utils/log'; 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 postcssPresetEnv from 'postcss-preset-env';
import * as postcssUrl from 'postcss-url'; import * as postcssUrl from 'postcss-url';
import { import {
@ -34,13 +34,6 @@ export enum CssUrl {
none = 'none', none = 'none',
} }
export enum InlineStyleLanguage {
sass = 'sass',
scss = 'scss',
css = 'css',
less = 'less',
}
export interface Result { export interface Result {
css: string; css: string;
warnings: string[]; warnings: string[];

View File

@ -12,12 +12,10 @@ import { BuildGraph } from 'ng-packagr/lib/graph/build-graph';
import { Node } from 'ng-packagr/lib/graph/node'; import { Node } from 'ng-packagr/lib/graph/node';
import { EntryPointNode, fileUrl } from 'ng-packagr/lib/ng-package/nodes'; import { EntryPointNode, fileUrl } from 'ng-packagr/lib/ng-package/nodes';
import { ensureUnixPath } from 'ng-packagr/lib/utils/path'; import { ensureUnixPath } from 'ng-packagr/lib/utils/path';
import { NgPackageConfig } from 'ng-packagr/ng-package.schema';
import * as path from 'path'; import * as path from 'path';
import * as ts from 'typescript'; import * as ts from 'typescript';
import { import { StylesheetProcessor } from '../styles/stylesheet-processor';
InlineStyleLanguage,
StylesheetProcessor,
} from '../styles/stylesheet-processor';
export function cacheCompilerHost( export function cacheCompilerHost(
graph: BuildGraph, graph: BuildGraph,
@ -25,7 +23,7 @@ export function cacheCompilerHost(
compilerOptions: CompilerOptions, compilerOptions: CompilerOptions,
moduleResolutionCache: ts.ModuleResolutionCache, moduleResolutionCache: ts.ModuleResolutionCache,
stylesheetProcessor?: StylesheetProcessor, stylesheetProcessor?: StylesheetProcessor,
inlineStyleLanguage?: InlineStyleLanguage, inlineStyleLanguage?: NgPackageConfig['inlineStyleLanguage'],
sourcesFileCache: FileCache = entryPoint.cache.sourcesFileCache sourcesFileCache: FileCache = entryPoint.cache.sourcesFileCache
): CompilerHost { ): CompilerHost {
const compilerHost = ts.createIncrementalCompilerHost(compilerOptions); const compilerHost = ts.createIncrementalCompilerHost(compilerOptions);
@ -47,6 +45,11 @@ export function cacheCompilerHost(
entryPoint.dependsOn(node); entryPoint.dependsOn(node);
}; };
const { flatModuleFile, entryFile } = entryPoint.data.entryPoint;
const flatModuleFileDtsFilename = `${flatModuleFile}.d.ts`;
const hasIndexEntryFile =
path.basename(entryFile.toLowerCase()) === 'index.ts';
return { return {
...compilerHost, ...compilerHost,
@ -82,6 +85,18 @@ export function cacheCompilerHost(
sourceFiles?: ReadonlyArray<ts.SourceFile> sourceFiles?: ReadonlyArray<ts.SourceFile>
) => { ) => {
if (fileName.endsWith('.d.ts')) { if (fileName.endsWith('.d.ts')) {
if (
hasIndexEntryFile &&
path.basename(fileName) === flatModuleFileDtsFilename
) {
// In case the entry file is index.ts, we should not emit the `d.ts` which are a re-export of the `index.ts`.
// Because it will cause a conflict.
return;
}
// Rename file to index.d.ts so that TypeScript can resolve types without
// them needing to be referenced in the package.json manifest.
fileName = fileName.replace(flatModuleFileDtsFilename, 'index.d.ts');
sourceFiles.forEach((source) => { sourceFiles.forEach((source) => {
const cache = sourcesFileCache.getOrCreate(source.fileName); const cache = sourcesFileCache.getOrCreate(source.fileName);
if (!cache.declarationFileName) { if (!cache.declarationFileName) {

View File

@ -168,6 +168,7 @@ Object {
exports[`app not nested should generate files 1`] = ` exports[`app not nested should generate files 1`] = `
Object { Object {
"angularCompilerOptions": Object { "angularCompilerOptions": Object {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true, "strictInjectionParameters": true,
"strictInputAccessModifiers": true, "strictInputAccessModifiers": true,
"strictTemplates": true, "strictTemplates": true,

View File

@ -34,6 +34,7 @@ export function enableStrictTypeChecking(
// update Angular Template Settings // update Angular Template Settings
json.angularCompilerOptions = { json.angularCompilerOptions = {
...(json.angularCompilerOptions ?? {}), ...(json.angularCompilerOptions ?? {}),
enableI18nLegacyMessageIdFormat: false,
strictInjectionParameters: true, strictInjectionParameters: true,
strictInputAccessModifiers: true, strictInputAccessModifiers: true,
strictTemplates: true, strictTemplates: true,

View File

@ -25,12 +25,17 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) {
compilerOptions: { compilerOptions: {
...json.compilerOptions, ...json.compilerOptions,
outDir: `${offsetFromRoot(options.appProjectRoot)}dist/out-tsc`, outDir: `${offsetFromRoot(options.appProjectRoot)}dist/out-tsc`,
target: 'ES2017',
}, },
exclude: [ exclude: [
...new Set([...(json.exclude || []), '**/*.test.ts', '**/*.spec.ts']), ...new Set([...(json.exclude || []), '**/*.test.ts', '**/*.spec.ts']),
], ],
})); }));
// tsconfig.json
updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({
...json,
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
}));
} }
function updateAppAndE2EProjectConfigurations( function updateAppAndE2EProjectConfigurations(

View File

@ -60,10 +60,6 @@ function exportComponent(tree: Tree, schema: Schema) {
); );
if (projectType === 'application') { if (projectType === 'application') {
logger.warn(
'--export=true was ignored as the project the component being generated in is not a library.'
);
return; return;
} }

View File

@ -5,6 +5,7 @@ export interface Schema {
displayBlock?: boolean; displayBlock?: boolean;
inlineStyle?: boolean; inlineStyle?: boolean;
inlineTemplate?: boolean; inlineTemplate?: boolean;
standalone?: boolean;
viewEncapsulation?: 'Emulated' | 'None' | 'ShadowDom'; viewEncapsulation?: 'Emulated' | 'None' | 'ShadowDom';
changeDetection?: 'Default' | 'OnPush'; changeDetection?: 'Default' | 'OnPush';
style?: 'css' | 'scss' | 'sass' | 'less' | 'none'; style?: 'css' | 'scss' | 'sass' | 'less' | 'none';

View File

@ -47,6 +47,11 @@
"default": false, "default": false,
"alias": "t" "alias": "t"
}, },
"standalone": {
"description": "Whether the generated component is standalone.",
"type": "boolean",
"default": false
},
"viewEncapsulation": { "viewEncapsulation": {
"description": "The view encapsulation strategy to use in the new component.", "description": "The view encapsulation strategy to use in the new component.",
"enum": ["Emulated", "None", "ShadowDom"], "enum": ["Emulated", "None", "ShadowDom"],

View File

@ -573,14 +573,14 @@ exports[`convert-tslint-to-eslint should work for Angular applications 1`] = `
Object { Object {
"dependencies": Object {}, "dependencies": Object {},
"devDependencies": Object { "devDependencies": Object {
"@angular-eslint/eslint-plugin": "~13.1.0", "@angular-eslint/eslint-plugin": "~13.2.1",
"@angular-eslint/eslint-plugin-template": "~13.1.0", "@angular-eslint/eslint-plugin-template": "~13.2.1",
"@angular-eslint/template-parser": "~13.1.0", "@angular-eslint/template-parser": "~13.2.1",
"@nrwl/eslint-plugin-nx": "0.0.1", "@nrwl/eslint-plugin-nx": "0.0.1",
"@nrwl/linter": "0.0.1", "@nrwl/linter": "0.0.1",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint": "~8.12.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",
"eslint-plugin-import": "latest", "eslint-plugin-import": "latest",
}, },
@ -931,14 +931,14 @@ exports[`convert-tslint-to-eslint should work for Angular libraries 1`] = `
Object { Object {
"dependencies": Object {}, "dependencies": Object {},
"devDependencies": Object { "devDependencies": Object {
"@angular-eslint/eslint-plugin": "~13.1.0", "@angular-eslint/eslint-plugin": "~13.2.1",
"@angular-eslint/eslint-plugin-template": "~13.1.0", "@angular-eslint/eslint-plugin-template": "~13.2.1",
"@angular-eslint/template-parser": "~13.1.0", "@angular-eslint/template-parser": "~13.2.1",
"@nrwl/eslint-plugin-nx": "0.0.1", "@nrwl/eslint-plugin-nx": "0.0.1",
"@nrwl/linter": "0.0.1", "@nrwl/linter": "0.0.1",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint": "~8.12.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",
"eslint-plugin-import": "latest", "eslint-plugin-import": "latest",
}, },

View File

@ -54,7 +54,7 @@ describe('init', () => {
// ASSERT // ASSERT
expect(packageJson.scripts.postinstall).toEqual( expect(packageJson.scripts.postinstall).toEqual(
'ngcc --properties es2015 browser module main' 'ngcc --properties es2020 browser module main'
); );
}); });

View File

@ -87,7 +87,7 @@ function setDefaults(host: Tree, options: Schema) {
function addPostInstall(host: Tree) { function addPostInstall(host: Tree) {
updateJson(host, 'package.json', (pkgJson) => { updateJson(host, 'package.json', (pkgJson) => {
pkgJson.scripts = pkgJson.scripts ?? {}; pkgJson.scripts = pkgJson.scripts ?? {};
const command = 'ngcc --properties es2015 browser module main'; const command = 'ngcc --properties es2020 browser module main';
if (!pkgJson.scripts.postinstall) { if (!pkgJson.scripts.postinstall) {
pkgJson.scripts.postinstall = command; pkgJson.scripts.postinstall = command;
} else if (!pkgJson.scripts.postinstall.includes('ngcc')) { } else if (!pkgJson.scripts.postinstall.includes('ngcc')) {

View File

@ -49,6 +49,7 @@ function updateTsConfig(host: Tree, options: NormalizedSchema) {
// update Angular Template Settings // update Angular Template Settings
json.angularCompilerOptions = { json.angularCompilerOptions = {
...(json.angularCompilerOptions ?? {}), ...(json.angularCompilerOptions ?? {}),
enableI18nLegacyMessageIdFormat: false,
strictInjectionParameters: true, strictInjectionParameters: true,
strictInputAccessModifiers: true, strictInputAccessModifiers: true,
strictTemplates: true, strictTemplates: true,

View File

@ -39,6 +39,12 @@ function updateProjectConfig(host: Tree, options: NormalizedSchema) {
]; ];
return json; return json;
}); });
// tsconfig.json
updateJson(host, `${options.projectRoot}/tsconfig.json`, (json) => ({
...json,
compilerOptions: { ...json.compilerOptions, target: 'es2020' },
}));
} }
function updateProjectIvyConfig(host: Tree, options: NormalizedSchema) { function updateProjectIvyConfig(host: Tree, options: NormalizedSchema) {

View File

@ -287,6 +287,7 @@ describe('lib', () => {
expect(tsconfigJson).toEqual({ expect(tsconfigJson).toEqual({
extends: '../../tsconfig.base.json', extends: '../../tsconfig.base.json',
angularCompilerOptions: { angularCompilerOptions: {
enableI18nLegacyMessageIdFormat: false,
strictInjectionParameters: true, strictInjectionParameters: true,
strictInputAccessModifiers: true, strictInputAccessModifiers: true,
strictTemplates: true, strictTemplates: true,
@ -298,6 +299,7 @@ describe('lib', () => {
noImplicitOverride: true, noImplicitOverride: true,
noImplicitReturns: true, noImplicitReturns: true,
strict: true, strict: true,
target: 'es2020',
}, },
files: [], files: [],
include: [], include: [],
@ -653,6 +655,7 @@ describe('lib', () => {
expect(tsconfigJson).toEqual({ expect(tsconfigJson).toEqual({
extends: '../../../tsconfig.base.json', extends: '../../../tsconfig.base.json',
angularCompilerOptions: { angularCompilerOptions: {
enableI18nLegacyMessageIdFormat: false,
strictInjectionParameters: true, strictInjectionParameters: true,
strictInputAccessModifiers: true, strictInputAccessModifiers: true,
strictTemplates: true, strictTemplates: true,
@ -664,6 +667,7 @@ describe('lib', () => {
noImplicitOverride: true, noImplicitOverride: true,
noImplicitReturns: true, noImplicitReturns: true,
strict: true, strict: true,
target: 'es2020',
}, },
files: [], files: [],
include: [], include: [],

View File

@ -1,7 +1,9 @@
import { import {
addDependenciesToPackageJson,
formatFiles, formatFiles,
installPackagesTask, installPackagesTask,
moveFilesToNewDirectory, moveFilesToNewDirectory,
removeDependenciesFromPackageJson,
Tree, Tree,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter'; import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
@ -9,6 +11,7 @@ import { jestProjectGenerator } from '@nrwl/jest';
import { Linter } from '@nrwl/linter'; import { Linter } from '@nrwl/linter';
import { convertToNxProjectGenerator } from '@nrwl/workspace/generators'; import { convertToNxProjectGenerator } from '@nrwl/workspace/generators';
import init from '../../generators/init/init'; import init from '../../generators/init/init';
import { ngPackagrVersion } from '../../utils/versions';
import addLintingGenerator from '../add-linting/add-linting'; import addLintingGenerator from '../add-linting/add-linting';
import karmaProjectGenerator from '../karma-project/karma-project'; import karmaProjectGenerator from '../karma-project/karma-project';
import setupTailwindGenerator from '../setup-tailwind/setup-tailwind'; import setupTailwindGenerator from '../setup-tailwind/setup-tailwind';
@ -86,6 +89,14 @@ export async function libraryGenerator(host: Tree, schema: Partial<Schema>) {
} }
if (options.buildable || options.publishable) { if (options.buildable || options.publishable) {
removeDependenciesFromPackageJson(host, [], ['ng-packagr']);
addDependenciesToPackageJson(
host,
{},
{
'ng-packagr': ngPackagrVersion,
}
);
addBuildableLibrariesPostCssDependencies(host); addBuildableLibrariesPostCssDependencies(host);
} }

View File

@ -1,8 +1,12 @@
import type { Tree } from '@nrwl/devkit'; import {
import { joinPathFragments, logger } from '@nrwl/devkit'; joinPathFragments,
logger,
Tree,
visitNotIgnoredFiles,
} from '@nrwl/devkit';
import { tsquery } from '@phenomnomnominal/tsquery'; import { tsquery } from '@phenomnomnominal/tsquery';
import { basename, dirname } from 'path'; import { basename, dirname, extname, relative } from 'path';
import type { SourceFile, Statement } from 'typescript'; import type { Identifier, SourceFile, Statement } from 'typescript';
import { SyntaxKind } from 'typescript'; import { SyntaxKind } from 'typescript';
import { getTsSourceFile } from '../../../utils/nx-devkit/ast-utils'; import { getTsSourceFile } from '../../../utils/nx-devkit/ast-utils';
import { getModuleDeclaredComponents } from './module-info'; import { getModuleDeclaredComponents } from './module-info';
@ -43,6 +47,47 @@ export function getComponentsInfo(
}); });
} }
export function getStandaloneComponentsInfo(
tree: Tree,
projectPath: string
): ComponentInfo[] {
const componentsInfo: ComponentInfo[] = [];
visitNotIgnoredFiles(tree, projectPath, (filePath: string) => {
if (extname(filePath) !== '.ts') {
return;
}
const standaloneComponents = getStandaloneComponents(tree, filePath);
if (!standaloneComponents.length) {
return;
}
standaloneComponents.forEach((componentName) => {
componentsInfo.push({
componentFileName: basename(filePath, '.ts'),
moduleFolderPath: projectPath,
name: componentName,
path: dirname(relative(projectPath, filePath)),
});
});
});
return componentsInfo;
}
function getStandaloneComponents(tree: Tree, filePath: string): string[] {
const fileContent = tree.read(filePath, 'utf-8');
const ast = tsquery.ast(fileContent);
const components = tsquery<Identifier>(
ast,
'ClassDeclaration:has(Decorator > CallExpression:has(Identifier[name=Component]) ObjectLiteralExpression PropertyAssignment Identifier[name=standalone] ~ TrueKeyword) > Identifier',
{ visitAllChildren: true }
);
return components.map((component) => component.getText());
}
function getComponentImportPath( function getComponentImportPath(
componentName: string, componentName: string,
imports: Statement[] imports: Statement[]

View File

@ -3,7 +3,10 @@ import { logger } from '@nrwl/devkit';
import { getProjectRootPath } from '@nrwl/workspace/src/utilities/project-type'; import { getProjectRootPath } from '@nrwl/workspace/src/utilities/project-type';
import componentCypressSpecGenerator from '../component-cypress-spec/component-cypress-spec'; import componentCypressSpecGenerator from '../component-cypress-spec/component-cypress-spec';
import componentStoryGenerator from '../component-story/component-story'; import componentStoryGenerator from '../component-story/component-story';
import { getComponentsInfo } from './lib/component-info'; import {
getComponentsInfo,
getStandaloneComponentsInfo,
} from './lib/component-info';
import { getE2EProject } from './lib/get-e2e-project'; import { getE2EProject } from './lib/get-e2e-project';
import { getModuleFilePaths } from './lib/module-info'; import { getModuleFilePaths } from './lib/module-info';
import type { StoriesGeneratorOptions } from './schema'; import type { StoriesGeneratorOptions } from './schema';
@ -16,7 +19,11 @@ export function angularStoriesGenerator(
const e2eProject = getE2EProject(tree, e2eProjectName); const e2eProject = getE2EProject(tree, e2eProjectName);
const projectPath = getProjectRootPath(tree, options.name); const projectPath = getProjectRootPath(tree, options.name);
const moduleFilePaths = getModuleFilePaths(tree, projectPath); const moduleFilePaths = getModuleFilePaths(tree, projectPath);
const componentsInfo = getComponentsInfo(tree, moduleFilePaths, options.name); const componentsInfo = [
...getComponentsInfo(tree, moduleFilePaths, options.name),
// TODO(leo): uncomment once Storybook supports standalone components https://github.com/storybookjs/storybook/pull/18272
// ...getStandaloneComponentsInfo(tree, projectPath),
];
if (options.generateCypressSpecs && !e2eProject) { if (options.generateCypressSpecs && !e2eProject) {
logger.info( logger.info(

View File

@ -0,0 +1,86 @@
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import removeShowCircularDependencies from './remove-show-circular-dependencies-option';
describe('remove-show-circular-dependencies-option migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace(2);
});
it.each([
'@angular-devkit/build-angular:browser',
'@angular-devkit/build-angular:server',
'@nrwl/angular:webpack-browser',
])(
'should remove "showCircularDependencies" option from target using the "%s" executor',
async (executor) => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: {
executor,
options: { extractCss: false, showCircularDependencies: true },
configurations: {
one: { showCircularDependencies: false, aot: true },
two: { showCircularDependencies: false, aot: true },
},
},
},
});
await removeShowCircularDependencies(tree);
const project = readProjectConfiguration(tree, 'app1');
expect(
project.targets.build.options.showCircularDependencies
).toBeUndefined();
expect(project.targets.build.configurations).toBeDefined();
expect(
project.targets.build.configurations.one.showCircularDependencies
).toBeUndefined();
expect(
project.targets.build.configurations.two.showCircularDependencies
).toBeUndefined();
}
);
it('should not remove "showCircularDependencies" from target not using the relevant executors', async () => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: {
executor: '@org/awesome-plugin:executor',
options: { extractCss: false, showCircularDependencies: true },
configurations: {
one: { showCircularDependencies: false, aot: true },
two: { showCircularDependencies: false, aot: true },
},
},
},
});
await removeShowCircularDependencies(tree);
const project = readProjectConfiguration(tree, 'app1');
expect(
project.targets.build.options.showCircularDependencies
).toBeDefined();
expect(project.targets.build.configurations).toBeDefined();
expect(
project.targets.build.configurations.one.showCircularDependencies
).toBeDefined();
expect(
project.targets.build.configurations.two.showCircularDependencies
).toBeDefined();
});
});

View File

@ -0,0 +1,37 @@
import {
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
const executors = [
'@angular-devkit/build-angular:browser',
'@angular-devkit/build-angular:server',
'@nrwl/angular:webpack-browser',
];
export default async function (tree: Tree) {
executors.forEach((executor) => {
forEachExecutorOptions(
tree,
executor,
(_options, projectName, targetName, configurationName) => {
const projectConfiguration = readProjectConfiguration(
tree,
projectName
);
const config = configurationName
? projectConfiguration.targets[targetName].configurations[
configurationName
]
: projectConfiguration.targets[targetName].options;
delete config.showCircularDependencies;
updateProjectConfiguration(tree, projectName, projectConfiguration);
}
);
});
await formatFiles(tree);
}

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(2);
});
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('~14.0.0-rc.2');
});
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('~14.0.0-rc.2');
});
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,21 @@
import { formatFiles, Tree, updateJson } from '@nrwl/devkit';
export default async function (tree: Tree) {
let shouldFormat = false;
updateJson(tree, 'package.json', (json) => {
if (json.devDependencies?.['@angular/cli']) {
json.devDependencies['@angular/cli'] = '~14.0.0-rc.2';
shouldFormat = true;
} else if (json.dependencies?.['@angular/cli']) {
json.dependencies['@angular/cli'] = '~14.0.0-rc.2';
shouldFormat = true;
}
return json;
});
if (shouldFormat) {
await formatFiles(tree);
}
}

View File

@ -0,0 +1,97 @@
import {
addProjectConfiguration,
readJson,
Tree,
writeJson,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import updateLibrariesSecondaryEntrypoints from './update-libraries-secondary-entrypoints';
const libraryExecutors = [
'@angular-devkit/build-angular:ng-packagr',
'@nrwl/angular:ng-packagr-lite',
'@nrwl/angular:package',
];
describe('update-libraries-secondary-entrypoints migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace(2);
});
it.each(libraryExecutors)(
'should not delete "package.json" of the primary entrypoint (%s)',
async (executor) => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
targets: { build: { executor } },
});
writeJson(tree, 'libs/lib1/package.json', { version: '0.0.0' });
await updateLibrariesSecondaryEntrypoints(tree);
expect(tree.exists('libs/lib1/package.json')).toBe(true);
}
);
it.each(libraryExecutors)(
'should delete "package.json" of the secondary entrypoint (%s)',
async (executor) => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
targets: { build: { executor } },
});
writeJson(tree, 'libs/lib1/package.json', { version: '0.0.0' });
writeJson(tree, 'libs/lib1/secondary/package.json', {
version: '0.0.0',
ngPackage: { lib: { entryFile: 'src/index.ts' } },
});
await updateLibrariesSecondaryEntrypoints(tree);
expect(tree.exists('libs/lib1/secondary/package.json')).toBe(false);
}
);
it.each(libraryExecutors)(
'should move ng-packagr configuration from "package.json" to "ng-package.json" (%s)',
async (executor) => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
targets: { build: { executor } },
});
writeJson(tree, 'libs/lib1/package.json', { version: '0.0.0' });
writeJson(tree, 'libs/lib1/secondary/package.json', {
version: '0.0.0',
ngPackage: { lib: { entryFile: 'src/index.ts' } },
});
await updateLibrariesSecondaryEntrypoints(tree);
expect(
readJson(tree, 'libs/lib1/secondary/ng-package.json')
).toStrictEqual({
lib: { entryFile: 'src/index.ts' },
});
}
);
it('should do nothing when not using any of the relevant executors', async () => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
targets: { test: { executor: '@nrwl/jest:jest' } },
});
writeJson(tree, 'libs/lib1/package.json', { version: '0.0.0' });
writeJson(tree, 'libs/lib1/secondary/package.json', {
version: '0.0.0',
ngPackage: { lib: { entryFile: 'src/index.ts' } },
});
await updateLibrariesSecondaryEntrypoints(tree);
expect(tree.exists('libs/lib1/package.json')).toBe(true);
expect(tree.exists('libs/lib1/secondary/package.json')).toBe(true);
expect(tree.exists('libs/lib1/secondary/ng-package.json')).toBe(false);
});
});

View File

@ -0,0 +1,54 @@
import {
formatFiles,
getProjects,
joinPathFragments,
readJson,
Tree,
visitNotIgnoredFiles,
writeJson,
} from '@nrwl/devkit';
import { basename, dirname } from 'path';
const libraryExecutors = [
'@angular-devkit/build-angular:ng-packagr',
'@nrwl/angular:ng-packagr-lite',
'@nrwl/angular:package',
];
export default async function (tree: Tree) {
const projects = getProjects(tree);
for (const [, project] of projects) {
if (
!Object.values(project.targets ?? {}).some((target) =>
libraryExecutors.includes(target.executor)
)
) {
continue;
}
visitNotIgnoredFiles(tree, project.root, (filePath) => {
if (
basename(filePath) !== 'package.json' ||
filePath === joinPathFragments(project.root, 'package.json')
) {
return;
}
const json = readJson(tree, filePath);
if (json.ngPackage) {
// Migrate ng-packagr config to an ng-packagr config file.
const configFilePath = joinPathFragments(
dirname(filePath),
'ng-package.json'
);
writeJson(tree, configFilePath, json.ngPackage);
}
// Delete package.json as it is no longer needed in APF 14.
tree.delete(filePath);
});
}
await formatFiles(tree);
}

View File

@ -0,0 +1,60 @@
import { readJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import updateNgccTarget from './update-ngcc-target';
describe('update-ngcc-postinstall-target migration', () => {
[
{
test: 'node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main',
expected:
'node ./decorate-angular-cli.js && ngcc --properties es2020 browser module main',
},
{
test: 'node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main && echo "hi"',
expected:
'node ./decorate-angular-cli.js && ngcc --properties es2020 browser module main && echo "hi"',
},
{
test: 'ngcc --properties es2015 browser module main && node ./decorate-angular-cli.js && echo "hi"',
expected:
'ngcc --properties es2020 browser module main && node ./decorate-angular-cli.js && echo "hi"',
},
].forEach((testEntry) => {
it(`should adjust ngcc target for: "${testEntry.test}"`, async () => {
const tree = createTreeWithEmptyWorkspace();
tree.write(
'/package.json',
JSON.stringify({ scripts: { postinstall: testEntry.test } })
);
await updateNgccTarget(tree);
const packageJson = readJson(tree, 'package.json');
expect(packageJson.scripts.postinstall).toEqual(testEntry.expected);
});
});
[
{
test: 'node ngcc.js',
expected: 'node ngcc.js',
},
{
test: 'any random postinstall script',
expected: 'any random postinstall script',
},
].forEach((testEntry) => {
it(`should not update postinstall script: "${testEntry.test}"`, async () => {
const tree = createTreeWithEmptyWorkspace();
tree.write(
'/package.json',
JSON.stringify({ scripts: { postinstall: testEntry.test } })
);
await updateNgccTarget(tree);
const packageJson = readJson(tree, 'package.json');
expect(packageJson.scripts.postinstall).toEqual(testEntry.expected);
});
});
});

View File

@ -0,0 +1,21 @@
import { formatFiles, Tree, updateJson } from '@nrwl/devkit';
export default async function (tree: Tree) {
let shouldFormat = false;
updateJson(tree, 'package.json', (json) => {
if (json.scripts?.postinstall?.includes('ngcc ')) {
json.scripts.postinstall = json.scripts.postinstall.replace(
/(.*)(ngcc --properties es2015 )(.*)/,
'$1ngcc --properties es2020 $3'
);
shouldFormat = true;
}
return json;
});
if (shouldFormat) {
await formatFiles(tree);
}
}

View File

@ -0,0 +1,608 @@
import { logger, ProjectGraph, Tree } from '@nrwl/devkit';
import {
addProjectConfiguration,
DependencyType,
readJson,
writeJson,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import updateTsConfigTarget from './update-tsconfig-target';
let projectGraph: ProjectGraph;
jest.mock('@nrwl/devkit', () => ({
...jest.requireActual<any>('@nrwl/devkit'),
createProjectGraphAsync: jest
.fn()
.mockImplementation(async () => projectGraph),
}));
describe('update-tsconfig-target migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace(2);
});
it('should update target in "tsconfig.json" at the project root when it is an Angular project', async () => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: {
executor: '@nrwl/angular:webpack-browser',
options: { tsConfig: 'apps/app1/tsconfig.app.json' },
},
},
});
projectGraph = {
dependencies: {
app1: [
{
type: DependencyType.static,
source: 'app1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'apps/app1/tsconfig.json', {
compilerOptions: { target: 'es2017' },
});
writeJson(tree, 'apps/app1/tsconfig.app.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
expect(compilerOptions.target).toBe('es2020');
const optionTsConfig = readJson(tree, 'apps/app1/tsconfig.app.json');
expect(optionTsConfig.compilerOptions.target).toBe('es2020');
});
it('should not update target in a tsconfig file referenced by a target option when it does not have the target set and there is a "tsconfig.json" at the project root', async () => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: {
executor: '@nrwl/angular:webpack-browser',
options: { tsConfig: 'apps/app1/tsconfig.app.json' },
},
},
});
projectGraph = {
dependencies: {
app1: [
{
type: DependencyType.static,
source: 'app1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'apps/app1/tsconfig.json', {
compilerOptions: { target: 'es2017' },
});
writeJson(tree, 'apps/app1/tsconfig.app.json', {
compilerOptions: {},
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
expect(compilerOptions.target).toBe('es2020');
const optionTsConfig = readJson(tree, 'apps/app1/tsconfig.app.json');
expect(optionTsConfig.compilerOptions).toStrictEqual({});
});
it.each([
['@angular-devkit/build-angular:browser', 'tsconfig.app.json'],
['@angular-devkit/build-angular:karma', 'tsconfig.spec.json'],
['@nrwl/angular:webpack-browser', 'tsconfig.app.json'],
['@nrwl/angular:delegate-build', 'tsconfig.app.json'],
])(
'should update target in the tsconfig file referenced by the target configuration when using the "%s" executor and there is no "tsconfig.json" at the project root',
async (executor, tsConfig) => {
const tsConfigPath = `apps/app1/${tsConfig}`;
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: { executor, options: { tsConfig: tsConfigPath } },
},
});
projectGraph = {
dependencies: {
app1: [
{
type: DependencyType.static,
source: 'app1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, tsConfigPath, {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, tsConfigPath);
expect(compilerOptions.target).toBe('es2020');
}
);
it.each([
'@angular-devkit/build-angular:ng-packagr',
'@nrwl/angular:ng-packagr-lite',
'@nrwl/angular:package',
])(
'should update target in the tsconfig file referenced by the target configuration when using the "%s" executor and there is no "tsconfig.json" at the project root',
async (executor) => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
build: {
executor,
options: { tsConfig: 'libs/lib1/tsconfig.lib.json' },
configurations: {
production: { tsConfig: 'libs/lib1/tsconfig.lib.prod.json' },
},
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'libs/lib1/tsconfig.lib.json', {
compilerOptions: { target: 'es2017' },
});
writeJson(tree, 'libs/lib1/tsconfig.lib.prod.json', {});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.lib.json');
expect(compilerOptions.target).toBe('es2020');
const tsConfigProd = readJson(tree, 'libs/lib1/tsconfig.lib.prod.json');
expect(tsConfigProd.compilerOptions.target).toBe('es2020');
}
);
it('should not error and log a warning when the tsconfig file specified in target does not exist', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
build: {
executor: '@nrwl/angular:package',
options: { tsConfig: 'libs/lib1/tsconfig.lib.json' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
`The "libs/lib1/tsconfig.lib.json" file specified in the "build" target of the "lib1" project could not be found.`
)
);
});
it('should update target in tsconfig file specified in the jest config when it is an Angular project', async () => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
build: {
executor: '@nrwl/jest:jest',
options: { jestConfig: 'libs/lib1/jest.config.ts' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
tree.write(
'libs/lib1/jest.config.ts',
`export default {
displayName: 'lib1',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
},
coverageDirectory: '../../coverage/libs/lib1',
transform: {
'^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular',
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};`
);
writeJson(tree, 'libs/lib1/tsconfig.spec.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.spec.json');
expect(compilerOptions.target).toBe('es2020');
});
it('should not error and log a warning when the tsconfig file specified in the jest configuration does not exist', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
test: {
executor: '@nrwl/jest:jest',
options: { jestConfig: 'libs/lib1/jest.config.ts' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
tree.write(
'libs/lib1/jest.config.ts',
`export default {
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
},
};`
);
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
`The "<rootDir>/tsconfig.spec.json" file specified in the Jest configuration file "libs/lib1/jest.config.ts" of the "test" target of the "lib1" project could not be found.`
)
);
});
it('should not error and log a warning when the jest configuration does not specify the "tsconfig"', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
test: {
executor: '@nrwl/jest:jest',
options: { jestConfig: 'libs/lib1/jest.config.ts' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
tree.write('libs/lib1/jest.config.ts', `export default {};`);
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
`Couldn't find the "tsconfig" property for "ts-jest" in the Jest configuration file "libs/lib1/jest.config.ts" specified in the "test" target of the "lib1" project.`
)
);
});
it('should not error and log a warning when the jest configuration file does not exist', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
test: {
executor: '@nrwl/jest:jest',
options: { jestConfig: 'libs/lib1/jest.config.ts' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
`The "libs/lib1/jest.config.ts" file specified in the "test" target of the "lib1" project could not be found.`
)
);
});
it('should not error and log a warning when the jest configuration file is not specified', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: { test: { executor: '@nrwl/jest:jest', options: {} } },
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
await expect(updateTsConfigTarget(tree)).resolves.not.toThrow();
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
`The "test" target of the "lib1" project is using the "@nrwl/jest:jest" executor but no "jestConfig" property was specified.`
)
);
});
it.each(['es2021', 'es2022', 'esnext'])(
'should not update target when it is already set to a target greater than es2020 ("%s")',
async (target) => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'library',
targets: {
build: {
executor: '@angular-devkit/build-angular:browser',
options: { tsConfig: 'apps/app1/tsconfig.other.json' },
},
},
});
projectGraph = {
dependencies: {
app1: [
{
type: DependencyType.static,
source: 'app1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'apps/app1/tsconfig.json', {
compilerOptions: { target },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'apps/app1/tsconfig.json');
expect(compilerOptions.target).toBe(target);
}
);
it('should not update target in "tsconfig.json" at the project root when it is not an angular project', async () => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:lodash',
},
],
},
nodes: {},
};
writeJson(tree, 'libs/lib1/tsconfig.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.json');
expect(compilerOptions.target).toBe('es2017');
});
it('should not update target in a tsconfig file referenced by a target option when not using the relevant executors', async () => {
jest.spyOn(logger, 'warn');
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
build: {
executor: '@org/awesome-plugin:executor',
options: { tsConfig: 'libs/lib1/tsconfig.other.json' },
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'libs/lib1/tsconfig.other.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.other.json');
expect(compilerOptions.target).toBe('es2017');
expect(logger.warn).toHaveBeenCalledWith(
expect.stringContaining(
'The "build" target of the "lib1" project is using an executor not supported by the migration.'
)
);
});
it('should not update target in a tsconfig file referenced by a target configuration when not using the relevant executors', async () => {
addProjectConfiguration(tree, 'lib1', {
root: 'libs/lib1',
sourceRoot: 'libs/lib1/src',
projectType: 'library',
targets: {
build: {
executor: '@org/awesome-plugin:executor',
configurations: {
production: { tsConfig: 'libs/lib1/tsconfig.other.json' },
},
},
},
});
projectGraph = {
dependencies: {
lib1: [
{
type: DependencyType.static,
source: 'lib1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'libs/lib1/tsconfig.other.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'libs/lib1/tsconfig.other.json');
expect(compilerOptions.target).toBe('es2017');
});
it('should not update target in workspace "tsconfig.base.json"', async () => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
sourceRoot: 'apps/app1/src',
projectType: 'application',
targets: {
build: {
executor: '@nrwl/angular:webpack-browser',
options: { tsConfig: 'apps/app1/tsconfig.json' },
},
},
});
projectGraph = {
dependencies: {
app1: [
{
type: DependencyType.static,
source: 'app1',
target: 'npm:@angular/core',
},
],
},
nodes: {},
};
writeJson(tree, 'apps/app1/tsconfig.json', {
compilerOptions: { target: 'es2017' },
});
writeJson(tree, 'tsconfig.base.json', {
compilerOptions: { target: 'es2017' },
});
await updateTsConfigTarget(tree);
const { compilerOptions } = readJson(tree, 'tsconfig.base.json');
expect(compilerOptions.target).toBe('es2017');
});
});

View File

@ -0,0 +1,247 @@
import {
ProjectConfiguration,
readJson,
TargetConfiguration,
Tree,
} from '@nrwl/devkit';
import {
createProjectGraphAsync,
formatFiles,
joinPathFragments,
logger,
readProjectConfiguration,
updateJson,
} from '@nrwl/devkit';
import { tsquery } from '@phenomnomnominal/tsquery';
import { dirname } from 'path';
import type { StringLiteral } from 'typescript';
const jestExecutor = '@nrwl/jest:jest';
const executors = [
'@angular-devkit/build-angular:browser',
'@angular-devkit/build-angular:karma',
'@angular-devkit/build-angular:ng-packagr',
'@nrwl/angular:webpack-browser',
'@nrwl/angular:delegate-build',
'@nrwl/angular:ng-packagr-lite',
'@nrwl/angular:package',
];
const skipTargets = ['es2020', 'es2021', 'es2022', 'esnext'];
export default async function (tree: Tree) {
const tsConfigPaths = await collectTsConfigPaths(tree);
for (const tsConfigPath of tsConfigPaths) {
updateJson(tree, tsConfigPath, (json) => {
if (
!json.compilerOptions?.target ||
(json.compilerOptions?.target &&
!skipTargets.includes(json.compilerOptions.target.toLowerCase()))
) {
json.compilerOptions ??= {};
json.compilerOptions.target = 'es2020';
}
return json;
});
}
await formatFiles(tree);
}
async function collectTsConfigPaths(tree: Tree): Promise<string[]> {
const uniqueTsConfigs = new Set([]);
const projectGraph = await createProjectGraphAsync();
const angularProjects = Object.entries(projectGraph.dependencies)
.filter(([, dep]) =>
dep.some(({ target }) => target === 'npm:@angular/core')
)
.map(([projectName]) => ({
projectName,
project: readProjectConfiguration(tree, projectName),
}));
for (const { projectName, project } of angularProjects) {
const tsConfigPath = joinPathFragments(project.root, 'tsconfig.json');
if (tree.exists(tsConfigPath)) {
uniqueTsConfigs.add(tsConfigPath);
const targetTsConfigPaths = getProjectTsConfigPaths(
tree,
project,
projectName,
false
);
targetTsConfigPaths.forEach((tsConfigPath) => {
const tsConfig = readJson(tree, tsConfigPath);
if (tsConfig.compilerOptions?.target) {
uniqueTsConfigs.add(tsConfigPath);
}
});
continue;
}
const tsConfigPaths = getProjectTsConfigPaths(tree, project, projectName);
for (const tsConfigPath of tsConfigPaths) {
uniqueTsConfigs.add(tsConfigPath);
}
}
return Array.from(uniqueTsConfigs);
}
function getProjectTsConfigPaths(
tree: Tree,
project: ProjectConfiguration,
projectName: string,
shouldWarn: boolean = true
): string[] {
const tsConfigPaths = new Set<string>();
for (const [targetName, target] of Object.entries(project.targets || {})) {
if (executors.includes(target.executor)) {
const tsConfigPathsFromTarget = getPathValuesFromTarget(
target,
'tsConfig'
);
tsConfigPathsFromTarget.forEach((tsConfigPath) => {
if (tree.exists(tsConfigPath)) {
tsConfigPaths.add(tsConfigPath);
} else if (shouldWarn) {
logger.warn(
`The "${tsConfigPath}" file specified in the "${targetName}" target of the "${projectName}" project could not be found. ` +
'Skipping setting the target to ES2020.'
);
}
});
} else if (target.executor === jestExecutor) {
const tsConfigPathsFromJestTarget = getTsConfigPathsFromJestTarget(
tree,
target,
targetName,
projectName,
shouldWarn
);
tsConfigPathsFromJestTarget.forEach((tsConfigPath) => {
tsConfigPaths.add(tsConfigPath);
});
} else if (shouldWarn) {
logger.warn(
`The "${targetName}" target of the "${projectName}" project is using an executor not supported by the migration. ` +
'Skipping setting the TS target to ES2020 for the project.'
);
}
}
return Array.from(tsConfigPaths);
}
function getTsConfigPathsFromJestTarget(
tree: Tree,
target: TargetConfiguration,
targetName: string,
projectName: string,
shouldWarn: boolean
): string[] {
const tsConfigPaths: string[] = [];
const jestConfigPaths = getPathValuesFromTarget(target, 'jestConfig');
if (!jestConfigPaths.length && shouldWarn) {
logger.warn(
`The "${targetName}" target of the "${projectName}" project is using the "${jestExecutor}" executor but no "jestConfig" property was specified. ` +
'Skipping setting the TS compilation target to ES2020 for the project.'
);
}
for (const jestConfigPath of jestConfigPaths) {
const tsConfigPath = getTsConfigFromJestConfig(
tree,
jestConfigPath,
targetName,
projectName,
shouldWarn
);
if (tsConfigPath) {
tsConfigPaths.push(tsConfigPath);
}
}
return tsConfigPaths;
}
function getTsConfigFromJestConfig(
tree: Tree,
jestConfigPath: string,
targetName: string,
projectName: string,
shouldWarn: boolean
): string {
if (!tree.exists(jestConfigPath)) {
if (shouldWarn) {
logger.warn(
`The "${jestConfigPath}" file specified in the "${targetName}" target of the "${projectName}" project could not be found. ` +
`The TS config file used by the target can't be determined. Skipping setting the target to ES2020.`
);
}
return undefined;
}
const jestConfig = tree.read(jestConfigPath, 'utf-8');
const jestConfigAst = tsquery.ast(jestConfig);
const tsJestTsConfigStringLiteral = tsquery(
jestConfigAst,
'PropertyAssignment:has(Identifier[name=globals]) PropertyAssignment:has(StringLiteral[value=ts-jest]) PropertyAssignment Identifier[name=tsconfig] ~ StringLiteral',
{ visitAllChildren: true }
)[0] as StringLiteral;
if (!tsJestTsConfigStringLiteral) {
if (shouldWarn) {
logger.warn(
`Couldn't find the "tsconfig" property for "ts-jest" in the Jest configuration file "${jestConfigPath}" specified in the ` +
`"${targetName}" target of the "${projectName}" project. The TS config file used by the target can't be determined. ` +
'Skipping setting the target to ES2020.'
);
}
return undefined;
}
const tsJestTsConfigValue = tsJestTsConfigStringLiteral
.getText()
.replace(/['"]/g, '');
const tsConfigPath = tsJestTsConfigValue.replace(
'<rootDir>',
dirname(jestConfigPath)
);
if (!tree.exists(tsConfigPath)) {
if (shouldWarn) {
logger.warn(
`The "${tsJestTsConfigValue}" file specified in the Jest configuration file "${jestConfigPath}" of the "${targetName}" target ` +
`of the "${projectName}" project could not be found. Skipping setting the target to ES2020.`
);
}
return undefined;
}
return tsConfigPath;
}
function getPathValuesFromTarget(
target: TargetConfiguration,
option: string
): string[] {
const values: string[] = [];
if (target.options?.[option]) {
values.push(target.options[option]);
}
Object.values(target.configurations ?? {}).forEach((options) => {
if (options[option]) {
values.push(options[option]);
}
});
return values;
}

View File

@ -232,6 +232,78 @@ describe('MFE Webpack Utils', () => {
}); });
}); });
it('should collect secondary entry points from exports and fall back to lookinp up for package.json', () => {
// ARRANGE
(fs.existsSync as jest.Mock).mockImplementation(
(path) => !path.endsWith('/secondary/package.json')
);
jest.spyOn(devkit, 'readJsonFile').mockImplementation((file) => {
if (file.endsWith('pkg1/package.json')) {
return {
name: 'pkg1',
version: '1.0.0',
exports: {
'.': './index.js',
'./package.json': './package.json',
'./secondary': './secondary/index.js',
},
};
}
// @angular/core/package.json won't have exports, so it looks up for package.json
return {
name: file
.replace(/\\/g, '/')
.replace(/^.*node_modules[/]/, '')
.replace('/package.json', ''),
dependencies: { pkg1: '1.0.0', '@angular/core': '~13.2.0' },
};
});
(fs.readdirSync as jest.Mock).mockImplementation(
(directoryPath: string) => {
const packages = {
pkg1: ['secondary'],
'@angular/core': ['testing'],
};
for (const key of Object.keys(packages)) {
if (directoryPath.endsWith(key)) {
return packages[key];
}
}
return [];
}
);
(fs.lstatSync as jest.Mock).mockReturnValue({ isDirectory: () => true });
// ACT
const packages = sharePackages(['pkg1', '@angular/core']);
// ASSERT
expect(packages).toStrictEqual({
pkg1: {
singleton: true,
strictVersion: true,
requiredVersion: '1.0.0',
},
'pkg1/secondary': {
singleton: true,
strictVersion: true,
requiredVersion: '1.0.0',
},
'@angular/core': {
singleton: true,
strictVersion: true,
requiredVersion: '~13.2.0',
},
'@angular/core/testing': {
singleton: true,
strictVersion: true,
requiredVersion: '~13.2.0',
},
});
});
it('should not throw when the main entry point package.json cannot be required', () => { it('should not throw when the main entry point package.json cannot be required', () => {
// ARRANGE // ARRANGE
(fs.existsSync as jest.Mock).mockImplementation( (fs.existsSync as jest.Mock).mockImplementation(

View File

@ -102,27 +102,36 @@ function recursivelyCollectSecondaryEntryPointsFromDirectory(
pkgName: string, pkgName: string,
pkgVersion: string, pkgVersion: string,
pkgRoot: string, pkgRoot: string,
mainEntryPointExports: any | undefined,
directories: string[], directories: string[],
collectedPackages: { name: string; version: string }[] collectedPackages: { name: string; version: string }[]
): void { ): void {
for (const directory of directories) { for (const directory of directories) {
const packageJsonPath = join(directory, 'package.json'); const packageJsonPath = join(directory, 'package.json');
const relativeEntryPointPath = relative(pkgRoot, directory);
const entryPointName = joinPathFragments(pkgName, relativeEntryPointPath);
if (existsSync(packageJsonPath)) { if (existsSync(packageJsonPath)) {
const importName = joinPathFragments(
pkgName,
relative(pkgRoot, directory)
);
try { try {
// require the secondary entry point to try to rule out sample code // require the secondary entry point to try to rule out sample code
require.resolve(importName, { paths: [workspaceRoot] }); require.resolve(entryPointName, { paths: [workspaceRoot] });
const { name } = readJsonFile(packageJsonPath); const { name } = readJsonFile(packageJsonPath);
// further check to make sure what we were able to require is the // further check to make sure what we were able to require is the
// same as the package name // same as the package name
if (name === importName) { if (name === entryPointName) {
collectedPackages.push({ name, version: pkgVersion }); collectedPackages.push({ name, version: pkgVersion });
} }
} catch {} } catch {}
} else if (mainEntryPointExports) {
// if the package.json doesn't exist, check if the directory is
// exported by the main entry point
const entryPointExportKey = `./${relativeEntryPointPath}`;
const entryPointInfo = mainEntryPointExports[entryPointExportKey];
if (entryPointInfo) {
collectedPackages.push({
name: entryPointName,
version: pkgVersion,
});
}
} }
const subDirs = getNonNodeModulesSubDirs(directory); const subDirs = getNonNodeModulesSubDirs(directory);
@ -130,6 +139,7 @@ function recursivelyCollectSecondaryEntryPointsFromDirectory(
pkgName, pkgName,
pkgVersion, pkgVersion,
pkgRoot, pkgRoot,
mainEntryPointExports,
subDirs, subDirs,
collectedPackages collectedPackages
); );
@ -142,8 +152,9 @@ function collectPackageSecondaryEntryPoints(
collectedPackages: { name: string; version: string }[] collectedPackages: { name: string; version: string }[]
): void { ): void {
let pathToPackage: string; let pathToPackage: string;
let packageJsonPath: string;
try { try {
const packageJsonPath = require.resolve(`${pkgName}/package.json`, { packageJsonPath = require.resolve(`${pkgName}/package.json`, {
paths: [workspaceRoot], paths: [workspaceRoot],
}); });
pathToPackage = dirname(packageJsonPath); pathToPackage = dirname(packageJsonPath);
@ -152,17 +163,20 @@ function collectPackageSecondaryEntryPoints(
// entry and is not exporting the package.json file, fall back to trying // entry and is not exporting the package.json file, fall back to trying
// to find it from the top-level node_modules // to find it from the top-level node_modules
pathToPackage = join(workspaceRoot, 'node_modules', pkgName); pathToPackage = join(workspaceRoot, 'node_modules', pkgName);
if (!existsSync(join(pathToPackage, 'package.json'))) { packageJsonPath = join(pathToPackage, 'package.json');
if (!existsSync(packageJsonPath)) {
// might not exist if it's nested in another package, just return here // might not exist if it's nested in another package, just return here
return; return;
} }
} }
const { exports } = readJsonFile(packageJsonPath);
const subDirs = getNonNodeModulesSubDirs(pathToPackage); const subDirs = getNonNodeModulesSubDirs(pathToPackage);
recursivelyCollectSecondaryEntryPointsFromDirectory( recursivelyCollectSecondaryEntryPointsFromDirectory(
pkgName, pkgName,
pkgVersion, pkgVersion,
pathToPackage, pathToPackage,
exports,
subDirs, subDirs,
collectedPackages collectedPackages
); );

View File

@ -32,7 +32,7 @@ const migrationTestRunner = new SchematicTestRunner(
join(__dirname, '../../migrations.json') join(__dirname, '../../migrations.json')
); );
export function runMigration<SchemaOptions = any>( export function runMigration<SchemaOptions extends object = any>(
schematicName: string, schematicName: string,
options: SchemaOptions, options: SchemaOptions,
tree: Tree tree: Tree

View File

@ -1,11 +1,12 @@
export const nxVersion = require('../../package.json').version; export const nxVersion = require('../../package.json').version;
export const angularVersion = '~13.3.0'; export const angularVersion = '~14.0.0-rc.2';
export const angularDevkitVersion = '~13.3.0'; export const angularDevkitVersion = '~14.0.0-rc.2';
export const ngPackagrVersion = '~14.0.0-rc.0';
export const angularJsVersion = '1.7.9'; export const angularJsVersion = '1.7.9';
export const ngrxVersion = '~13.0.0'; export const ngrxVersion = '~13.2.0';
export const rxjsVersion = '~7.4.0'; export const rxjsVersion = '~7.4.0';
export const jestPresetAngularVersion = '11.1.1'; export const jestPresetAngularVersion = '~11.1.2';
export const angularEslintVersion = '~13.1.0'; export const angularEslintVersion = '~13.2.1';
export const tailwindVersion = '^3.0.2'; export const tailwindVersion = '^3.0.2';
export const postcssVersion = '^8.4.5'; export const postcssVersion = '^8.4.5';
export const autoprefixerVersion = '^10.4.0'; export const autoprefixerVersion = '^10.4.0';

View File

@ -6,9 +6,9 @@ Object {
"devDependencies": Object { "devDependencies": Object {
"@nrwl/eslint-plugin-nx": "0.0.1", "@nrwl/eslint-plugin-nx": "0.0.1",
"@nrwl/linter": "0.0.1", "@nrwl/linter": "0.0.1",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint": "~8.12.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",
"eslint-plugin-cypress": "^2.10.3", "eslint-plugin-cypress": "^2.10.3",
"eslint-plugin-import": "latest", "eslint-plugin-import": "latest",

View File

@ -23,7 +23,7 @@
}, },
"homepage": "https://nx.dev", "homepage": "https://nx.dev",
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint-config-prettier": "^8.1.0" "eslint-config-prettier": "^8.1.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
@ -34,7 +34,7 @@
"dependencies": { "dependencies": {
"@nrwl/devkit": "file:../devkit", "@nrwl/devkit": "file:../devkit",
"@nrwl/workspace": "file:../workspace", "@nrwl/workspace": "file:../workspace",
"@typescript-eslint/experimental-utils": "~5.18.0", "@typescript-eslint/experimental-utils": "~5.24.0",
"chalk": "4.1.0", "chalk": "4.1.0",
"confusing-browser-globals": "^1.0.9" "confusing-browser-globals": "^1.0.9"
} }

View File

@ -12,7 +12,7 @@ const migrationTestRunner = new SchematicTestRunner(
join(__dirname, '../../migrations.json') join(__dirname, '../../migrations.json')
); );
export function runSchematic<T = any>( export function runSchematic<T extends object = any>(
schematicName: string, schematicName: string,
options: T, options: T,
tree: Tree tree: Tree
@ -26,9 +26,9 @@ export function callRule(rule: Rule, tree: Tree) {
return testRunner.callRule(rule, tree).toPromise(); return testRunner.callRule(rule, tree).toPromise();
} }
export function runMigration( export function runMigration<T extends object = any>(
migrationName: string, migrationName: string,
options: unknown, options: T,
tree: Tree tree: Tree
) { ) {
return migrationTestRunner return migrationTestRunner

View File

@ -208,6 +208,23 @@
"version": "~8.12.0" "version": "~8.12.0"
} }
} }
},
"14.2.0": {
"version": "14.2.0-beta.0",
"packages": {
"@typescript-eslint/parser": {
"version": "~5.24.0"
},
"@typescript-eslint/eslint-plugin": {
"version": "~5.24.0"
},
"@typescript-eslint/experimental-utils": {
"version": "~5.24.0"
},
"eslint": {
"version": "~8.15.0"
}
}
} }
} }
} }

View File

@ -7,7 +7,7 @@ const migrationTestRunner = new SchematicTestRunner(
join(__dirname, '../../migrations.json') join(__dirname, '../../migrations.json')
); );
export function runMigration<T = any>( export function runMigration<T extends object = any>(
migrationName: string, migrationName: string,
options: T, options: T,
tree: Tree tree: Tree

View File

@ -2,8 +2,8 @@ export const nxVersion = require('../../package.json').version;
export const tslintVersion = '~6.1.0'; export const tslintVersion = '~6.1.0';
export const tslintToEslintConfigVersion = '^2.4.0'; export const tslintToEslintConfigVersion = '^2.4.0';
export const buildAngularVersion = '~13.3.0'; export const buildAngularVersion = '~14.0.0-rc.2';
export const typescriptESLintVersion = '~5.18.0'; export const typescriptESLintVersion = '~5.24.0';
export const eslintVersion = '~8.12.0'; export const eslintVersion = '~8.15.0';
export const eslintConfigPrettierVersion = '8.1.0'; export const eslintConfigPrettierVersion = '8.1.0';

View File

@ -6,9 +6,9 @@ Object {
"devDependencies": Object { "devDependencies": Object {
"@nrwl/eslint-plugin-nx": "0.0.1", "@nrwl/eslint-plugin-nx": "0.0.1",
"@nrwl/linter": "0.0.1", "@nrwl/linter": "0.0.1",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint": "~8.12.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",
"eslint-plugin-import": "latest", "eslint-plugin-import": "latest",
}, },
@ -299,9 +299,9 @@ Object {
"devDependencies": Object { "devDependencies": Object {
"@nrwl/eslint-plugin-nx": "0.0.1", "@nrwl/eslint-plugin-nx": "0.0.1",
"@nrwl/linter": "0.0.1", "@nrwl/linter": "0.0.1",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.24.0",
"@typescript-eslint/parser": "~5.18.0", "@typescript-eslint/parser": "~5.24.0",
"eslint": "~8.12.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",
"eslint-plugin-import": "latest", "eslint-plugin-import": "latest",
}, },

View File

@ -71,8 +71,6 @@ function getProjects(projectGraph: ProjectGraph, project: string): any {
const targetAliases = { const targetAliases = {
b: 'build', b: 'build',
e: 'e2e', e: 'e2e',
'i18n-extract': 'extract-i18n',
xi18n: 'extract-i18n',
l: 'lint', l: 'lint',
s: 'serve', s: 'serve',
t: 'test', t: 'test',

View File

@ -1,11 +1,11 @@
export const nxVersion = require('../../package.json').version; export const nxVersion = require('../../package.json').version;
export const angularCliVersion = '~13.2.0'; export const angularCliVersion = '~14.0.0-rc.2';
export const typescriptVersion = '~4.5.2'; export const typescriptVersion = '~4.6.2';
export const prettierVersion = '^2.5.1'; export const prettierVersion = '^2.5.1';
export const tslintVersion = '~6.1.0'; export const tslintVersion = '~6.1.0';
export const typescriptESLintVersion = '~5.18.0'; export const typescriptESLintVersion = '~5.24.0';
export const eslintVersion = '~8.12.0'; export const eslintVersion = '~8.15.0';
export const eslintConfigPrettierVersion = '8.1.0'; export const eslintConfigPrettierVersion = '8.1.0';
export const swcNodeVersion = '^1.4.2'; export const swcNodeVersion = '^1.4.2';
export const swcCoreVersion = '^1.2.173'; export const swcCoreVersion = '^1.2.173';

View File

@ -63,7 +63,7 @@ const migrationTestRunner = new SchematicTestRunner(
join(__dirname, '../../migrations.json') join(__dirname, '../../migrations.json')
); );
export function runExternalSchematic<T = any>( export function runExternalSchematic<T extends object = any>(
collectionName: string, collectionName: string,
schematicName: string, schematicName: string,
options: T, options: T,
@ -74,7 +74,7 @@ export function runExternalSchematic<T = any>(
.toPromise(); .toPromise();
} }
export function runSchematic<T = any>( export function runSchematic<T extends object = any>(
schematicName: string, schematicName: string,
options: T, options: T,
tree: Tree tree: Tree

View File

@ -1,9 +1,9 @@
export const nxVersion = require('../../package.json').version; export const nxVersion = require('../../package.json').version;
export const angularCliVersion = '~13.3.0'; export const angularCliVersion = '~14.0.0-rc.2';
export const typescriptVersion = '~4.6.2'; export const typescriptVersion = '~4.6.2';
export const prettierVersion = '^2.5.1'; export const prettierVersion = '^2.5.1';
export const tslintVersion = '~6.1.0'; export const tslintVersion = '~6.1.0';
export const typescriptESLintVersion = '~5.18.0'; export const typescriptESLintVersion = '~5.24.0';
export const eslintVersion = '~8.12.0'; export const eslintVersion = '~8.15.0';
export const eslintConfigPrettierVersion = '8.1.0'; export const eslintConfigPrettierVersion = '8.1.0';

2568
yarn.lock

File diff suppressed because it is too large Load Diff