fix(js): refactor ensurePackage (#15074)

This commit is contained in:
Jason Jean 2023-02-22 18:47:40 -05:00 committed by GitHub
parent 73bc2e1c91
commit fa6e8ea987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 661 additions and 428 deletions

View File

@ -134,7 +134,7 @@ It only uses language primitives and immutable objects
- [output](../../devkit/documents/nrwl_devkit#output) - [output](../../devkit/documents/nrwl_devkit#output)
- [workspaceRoot](../../devkit/documents/nrwl_devkit#workspaceroot) - [workspaceRoot](../../devkit/documents/nrwl_devkit#workspaceroot)
### Functions ### Other Functions
- [addDependenciesToPackageJson](../../devkit/documents/nrwl_devkit#adddependenciestopackagejson) - [addDependenciesToPackageJson](../../devkit/documents/nrwl_devkit#adddependenciestopackagejson)
- [addProjectConfiguration](../../devkit/documents/nrwl_devkit#addprojectconfiguration) - [addProjectConfiguration](../../devkit/documents/nrwl_devkit#addprojectconfiguration)
@ -149,7 +149,6 @@ It only uses language primitives and immutable objects
- [defaultTasksRunner](../../devkit/documents/nrwl_devkit#defaulttasksrunner) - [defaultTasksRunner](../../devkit/documents/nrwl_devkit#defaulttasksrunner)
- [detectPackageManager](../../devkit/documents/nrwl_devkit#detectpackagemanager) - [detectPackageManager](../../devkit/documents/nrwl_devkit#detectpackagemanager)
- [detectWorkspaceScope](../../devkit/documents/nrwl_devkit#detectworkspacescope) - [detectWorkspaceScope](../../devkit/documents/nrwl_devkit#detectworkspacescope)
- [ensurePackage](../../devkit/documents/nrwl_devkit#ensurepackage)
- [extractLayoutDirectory](../../devkit/documents/nrwl_devkit#extractlayoutdirectory) - [extractLayoutDirectory](../../devkit/documents/nrwl_devkit#extractlayoutdirectory)
- [formatFiles](../../devkit/documents/nrwl_devkit#formatfiles) - [formatFiles](../../devkit/documents/nrwl_devkit#formatfiles)
- [generateFiles](../../devkit/documents/nrwl_devkit#generatefiles) - [generateFiles](../../devkit/documents/nrwl_devkit#generatefiles)
@ -203,6 +202,10 @@ It only uses language primitives and immutable objects
- [writeJson](../../devkit/documents/nrwl_devkit#writejson) - [writeJson](../../devkit/documents/nrwl_devkit#writejson)
- [writeJsonFile](../../devkit/documents/nrwl_devkit#writejsonfile) - [writeJsonFile](../../devkit/documents/nrwl_devkit#writejsonfile)
### Utils Functions
- [ensurePackage](../../devkit/documents/nrwl_devkit#ensurepackage)
## Project Graph Enumerations ## Project Graph Enumerations
### DependencyType ### DependencyType
@ -823,7 +826,7 @@ Implementation of a target of a project that handles multiple projects to be bat
**workspaceRoot**: `string` **workspaceRoot**: `string`
## Functions ## Other Functions
### addDependenciesToPackageJson ### addDependenciesToPackageJson
@ -1182,39 +1185,6 @@ Detect workspace scope from the package.json name
--- ---
### ensurePackage
**ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void`
Ensure that dependencies and devDependencies from package.json are installed at the required versions.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
This will check that @nrwl/jest@<nxVersion> exists in devDependencies.
If it exists then function returns, otherwise it will install the package before continuing.
When running with --dryRun, the function will throw when dependencies are missing.
#### Parameters
| Name | Type | Description |
| :------------------------ | :------------------------------------------------ | :----------------------------------------------------------------- |
| `tree` | [`Tree`](../../devkit/documents/nrwl_devkit#tree) | the file system tree |
| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |
| `requiredVersion` | `string` | the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0) |
| `options` | `Object` | |
| `options.dev?` | `boolean` | - |
| `options.throwOnMissing?` | `boolean` | - |
#### Returns
`void`
---
### extractLayoutDirectory ### extractLayoutDirectory
**extractLayoutDirectory**(`directory`): `Object` **extractLayoutDirectory**(`directory`): `Object`
@ -2431,3 +2401,66 @@ Serializes the given data to JSON and writes it to a file.
#### Returns #### Returns
`void` `void`
---
## Utils Functions
### ensurePackage
**ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void`
**`deprecated`** Use the other function signature without a Tree
Use a package that has not been installed as a dependency.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
This install the @nrwl/jest@<nxVersion> and return the module
When running with --dryRun, the function will throw when dependencies are missing.
#### Parameters
| Name | Type | Description |
| :------------------------ | :------------------------------------------------ | :----------------------------------------------------------------- |
| `tree` | [`Tree`](../../devkit/documents/nrwl_devkit#tree) | the file system tree |
| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |
| `requiredVersion` | `string` | the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0) |
| `options?` | `Object` | - |
| `options.dev?` | `boolean` | - |
| `options.throwOnMissing?` | `boolean` | - |
#### Returns
`void`
**ensurePackage**<`T`\>(`pkg`, `version`): `T`
Ensure that dependencies and devDependencies from package.json are installed at the required versions.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
#### Type parameters
| Name | Type |
| :--- | :------------------------ |
| `T` | extends `unknown` = `any` |
#### Parameters
| Name | Type | Description |
| :-------- | :------- | :---------------------------------------------------------- |
| `pkg` | `string` | the package to install and require |
| `version` | `string` | the version to install if the package doesn't exist already |
#### Returns
`T`

View File

@ -134,7 +134,7 @@ It only uses language primitives and immutable objects
- [output](../../devkit/documents/nrwl_devkit#output) - [output](../../devkit/documents/nrwl_devkit#output)
- [workspaceRoot](../../devkit/documents/nrwl_devkit#workspaceroot) - [workspaceRoot](../../devkit/documents/nrwl_devkit#workspaceroot)
### Functions ### Other Functions
- [addDependenciesToPackageJson](../../devkit/documents/nrwl_devkit#adddependenciestopackagejson) - [addDependenciesToPackageJson](../../devkit/documents/nrwl_devkit#adddependenciestopackagejson)
- [addProjectConfiguration](../../devkit/documents/nrwl_devkit#addprojectconfiguration) - [addProjectConfiguration](../../devkit/documents/nrwl_devkit#addprojectconfiguration)
@ -149,7 +149,6 @@ It only uses language primitives and immutable objects
- [defaultTasksRunner](../../devkit/documents/nrwl_devkit#defaulttasksrunner) - [defaultTasksRunner](../../devkit/documents/nrwl_devkit#defaulttasksrunner)
- [detectPackageManager](../../devkit/documents/nrwl_devkit#detectpackagemanager) - [detectPackageManager](../../devkit/documents/nrwl_devkit#detectpackagemanager)
- [detectWorkspaceScope](../../devkit/documents/nrwl_devkit#detectworkspacescope) - [detectWorkspaceScope](../../devkit/documents/nrwl_devkit#detectworkspacescope)
- [ensurePackage](../../devkit/documents/nrwl_devkit#ensurepackage)
- [extractLayoutDirectory](../../devkit/documents/nrwl_devkit#extractlayoutdirectory) - [extractLayoutDirectory](../../devkit/documents/nrwl_devkit#extractlayoutdirectory)
- [formatFiles](../../devkit/documents/nrwl_devkit#formatfiles) - [formatFiles](../../devkit/documents/nrwl_devkit#formatfiles)
- [generateFiles](../../devkit/documents/nrwl_devkit#generatefiles) - [generateFiles](../../devkit/documents/nrwl_devkit#generatefiles)
@ -203,6 +202,10 @@ It only uses language primitives and immutable objects
- [writeJson](../../devkit/documents/nrwl_devkit#writejson) - [writeJson](../../devkit/documents/nrwl_devkit#writejson)
- [writeJsonFile](../../devkit/documents/nrwl_devkit#writejsonfile) - [writeJsonFile](../../devkit/documents/nrwl_devkit#writejsonfile)
### Utils Functions
- [ensurePackage](../../devkit/documents/nrwl_devkit#ensurepackage)
## Project Graph Enumerations ## Project Graph Enumerations
### DependencyType ### DependencyType
@ -823,7 +826,7 @@ Implementation of a target of a project that handles multiple projects to be bat
**workspaceRoot**: `string` **workspaceRoot**: `string`
## Functions ## Other Functions
### addDependenciesToPackageJson ### addDependenciesToPackageJson
@ -1182,39 +1185,6 @@ Detect workspace scope from the package.json name
--- ---
### ensurePackage
**ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void`
Ensure that dependencies and devDependencies from package.json are installed at the required versions.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
This will check that @nrwl/jest@<nxVersion> exists in devDependencies.
If it exists then function returns, otherwise it will install the package before continuing.
When running with --dryRun, the function will throw when dependencies are missing.
#### Parameters
| Name | Type | Description |
| :------------------------ | :------------------------------------------------ | :----------------------------------------------------------------- |
| `tree` | [`Tree`](../../devkit/documents/nrwl_devkit#tree) | the file system tree |
| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |
| `requiredVersion` | `string` | the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0) |
| `options` | `Object` | |
| `options.dev?` | `boolean` | - |
| `options.throwOnMissing?` | `boolean` | - |
#### Returns
`void`
---
### extractLayoutDirectory ### extractLayoutDirectory
**extractLayoutDirectory**(`directory`): `Object` **extractLayoutDirectory**(`directory`): `Object`
@ -2431,3 +2401,66 @@ Serializes the given data to JSON and writes it to a file.
#### Returns #### Returns
`void` `void`
---
## Utils Functions
### ensurePackage
**ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `void`
**`deprecated`** Use the other function signature without a Tree
Use a package that has not been installed as a dependency.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
This install the @nrwl/jest@<nxVersion> and return the module
When running with --dryRun, the function will throw when dependencies are missing.
#### Parameters
| Name | Type | Description |
| :------------------------ | :------------------------------------------------ | :----------------------------------------------------------------- |
| `tree` | [`Tree`](../../devkit/documents/nrwl_devkit#tree) | the file system tree |
| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |
| `requiredVersion` | `string` | the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0) |
| `options?` | `Object` | - |
| `options.dev?` | `boolean` | - |
| `options.throwOnMissing?` | `boolean` | - |
#### Returns
`void`
**ensurePackage**<`T`\>(`pkg`, `version`): `T`
Ensure that dependencies and devDependencies from package.json are installed at the required versions.
For example:
```typescript
ensurePackage(tree, '@nrwl/jest', nxVersion);
```
#### Type parameters
| Name | Type |
| :--- | :------------------------ |
| `T` | extends `unknown` = `any` |
#### Parameters
| Name | Type | Description |
| :-------- | :------- | :---------------------------------------------------------- |
| `pkg` | `string` | the package to install and require |
| `version` | `string` | the version to install if the package doesn't exist already |
#### Returns
`T`

View File

@ -17,7 +17,11 @@
"type": "boolean", "type": "boolean",
"aliases": ["skip-format"], "aliases": ["skip-format"],
"description": "Skip formatting files.", "description": "Skip formatting files.",
"default": true, "x-priority": "internal"
},
"skipPackageJson": {
"type": "boolean",
"description": "Skip adding package.json dependencies",
"x-priority": "internal" "x-priority": "internal"
}, },
"tsConfigName": { "tsConfigName": {

View File

@ -34,6 +34,10 @@ describe('nx init (for CRA)', () => {
}); });
it('should convert to an integrated workspace with Vite', () => { it('should convert to an integrated workspace with Vite', () => {
// TODO investigate why this is broken
const originalPM = process.env.SELECTED_PM;
process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM;
const appName = 'my-app'; const appName = 'my-app';
createReactApp(appName); createReactApp(appName);
@ -53,9 +57,13 @@ describe('nx init (for CRA)', () => {
const unitTestsOutput = runCLI(`test ${appName}`); const unitTestsOutput = runCLI(`test ${appName}`);
expect(unitTestsOutput).toContain('Successfully ran target test'); expect(unitTestsOutput).toContain('Successfully ran target test');
process.env.SELECTED_PM = originalPM;
}); });
it('should convert to an integrated workspace with Vite with custom port', () => { it('should convert to an integrated workspace with Vite with custom port', () => {
// TODO investigate why this is broken
const originalPM = process.env.SELECTED_PM;
process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM;
const appName = 'my-app'; const appName = 'my-app';
createReactApp(appName); createReactApp(appName);
updateFile(`.env`, `NOT_THE_PORT=8000\nPORT=3000\nSOMETHING_ELSE=whatever`); updateFile(`.env`, `NOT_THE_PORT=8000\nPORT=3000\nSOMETHING_ELSE=whatever`);
@ -71,6 +79,7 @@ describe('nx init (for CRA)', () => {
const unitTestsOutput = runCLI(`test ${appName}`); const unitTestsOutput = runCLI(`test ${appName}`);
expect(unitTestsOutput).toContain('Successfully ran target test'); expect(unitTestsOutput).toContain('Successfully ran target test');
process.env.SELECTED_PM = originalPM;
}); });
it('should convert to a standalone workspace with craco (webpack)', () => { it('should convert to a standalone workspace with craco (webpack)', () => {

View File

@ -1,6 +1,7 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { joinPathFragments } from '@nrwl/devkit'; import { joinPathFragments } from '@nrwl/devkit';
import type { NormalizedSchema } from './normalized-schema'; import type { NormalizedSchema } from './normalized-schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) { export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) {
const pathToAppModule = joinPathFragments( const pathToAppModule = joinPathFragments(
@ -23,6 +24,7 @@ function updateMainEntrypoint(
) { ) {
let routerModuleSetup: string; let routerModuleSetup: string;
if (options.routing) { if (options.routing) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const appModuleContents = tree.read(pathToAppModule, 'utf-8'); const appModuleContents = tree.read(pathToAppModule, 'utf-8');
const ast = tsquery.ast(appModuleContents); const ast = tsquery.ast(appModuleContents);
@ -73,6 +75,7 @@ function updateAppComponent(tree: Tree, options: NormalizedSchema) {
); );
const appComponentContents = tree.read(pathToAppComponent, 'utf-8'); const appComponentContents = tree.read(pathToAppComponent, 'utf-8');
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const ast = tsquery.ast(appComponentContents); const ast = tsquery.ast(appComponentContents);
const COMPONENT_DECORATOR_SELECTOR = const COMPONENT_DECORATOR_SELECTOR =

View File

@ -1,6 +1,7 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { joinPathFragments } from '@nrwl/devkit'; import { joinPathFragments } from '@nrwl/devkit';
import type { NormalizedSchema } from './normalized-schema'; import type { NormalizedSchema } from './normalized-schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) { export function convertToStandaloneApp(tree: Tree, options: NormalizedSchema) {
const pathToAppModule = joinPathFragments( const pathToAppModule = joinPathFragments(
@ -21,6 +22,7 @@ function updateMainEntrypoint(
tree: Tree, tree: Tree,
pathToAppModule: string pathToAppModule: string
) { ) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
let routerModuleSetup: string; let routerModuleSetup: string;
if (options.routing) { if (options.routing) {
@ -63,6 +65,7 @@ bootstrapApplication(AppComponent${
}).catch((err) => console.error(err));`; }).catch((err) => console.error(err));`;
function updateAppComponent(tree: Tree, options: NormalizedSchema) { function updateAppComponent(tree: Tree, options: NormalizedSchema) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const pathToAppComponent = joinPathFragments( const pathToAppComponent = joinPathFragments(
options.appProjectRoot, options.appProjectRoot,

View File

@ -3,6 +3,7 @@ import type { NormalizedSchema } from './normalized-schema';
import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -14,7 +15,7 @@ export function addRouterRootConfiguration(
const moduleSource = host.read(modulePath, 'utf-8'); const moduleSource = host.read(modulePath, 'utf-8');
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
let sourceFile = tsModule.createSourceFile( let sourceFile = tsModule.createSourceFile(
modulePath, modulePath,

View File

@ -5,6 +5,7 @@ import { replaceNodeValue } from '@nrwl/workspace/src/utilities/ast-utils';
import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils'; import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils';
import { nrwlHomeTemplate } from './nrwl-home-tpl'; import { nrwlHomeTemplate } from './nrwl-home-tpl';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -13,7 +14,7 @@ export async function updateAppComponentTemplate(
options: NormalizedSchema options: NormalizedSchema
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const content = options.routing const content = options.routing

View File

@ -5,12 +5,13 @@ import {
replaceIntoToTestBed, replaceIntoToTestBed,
} from '../../../utils/nx-devkit/ast-utils'; } from '../../../utils/nx-devkit/ast-utils';
import type { NormalizedSchema } from './normalized-schema'; import type { NormalizedSchema } from './normalized-schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
export function updateComponentSpec(host: Tree, options: NormalizedSchema) { export function updateComponentSpec(host: Tree, options: NormalizedSchema) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
if (options.skipTests !== true) { if (options.skipTests !== true) {

View File

@ -7,6 +7,7 @@ import {
} from '@nrwl/workspace/src/utilities/ast-utils'; } from '@nrwl/workspace/src/utilities/ast-utils';
import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils'; import { getDecoratorPropertyValueNode } from '../../../utils/nx-devkit/ast-utils';
import { nrwlHomeTemplate } from './nrwl-home-tpl'; import { nrwlHomeTemplate } from './nrwl-home-tpl';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -15,7 +16,7 @@ export function updateNxComponentTemplate(
options: NormalizedSchema options: NormalizedSchema
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const componentPath = `${options.appProjectRoot}/src/app/nx-welcome.component.ts`; const componentPath = `${options.appProjectRoot}/src/app/nx-welcome.component.ts`;

View File

@ -1,6 +1,7 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import type { StringLiteral } from 'typescript'; import type { StringLiteral } from 'typescript';
import { getRelativeImportToFile } from '../../utils/path'; import { getRelativeImportToFile } from '../../utils/path';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function shouldExportInEntryPoint( export function shouldExportInEntryPoint(
tree: Tree, tree: Tree,
@ -11,6 +12,7 @@ export function shouldExportInEntryPoint(
return false; return false;
} }
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const moduleImportPath = getRelativeImportToFile(entryPoint, modulePath); const moduleImportPath = getRelativeImportToFile(entryPoint, modulePath);
const entryPointContent = tree.read(entryPoint, 'utf-8'); const entryPointContent = tree.read(entryPoint, 'utf-8');

View File

@ -1,9 +1,11 @@
import type { SourceFile } from 'typescript'; import type { SourceFile } from 'typescript';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function checkOutputNameMatchesProjectName( export function checkOutputNameMatchesProjectName(
ast: SourceFile, ast: SourceFile,
projectName: string projectName: string
) { ) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const OUTPUT_SELECTOR = const OUTPUT_SELECTOR =
'PropertyAssignment:has(Identifier[name=output]) > ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=uniqueName]))'; 'PropertyAssignment:has(Identifier[name=output]) > ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=uniqueName]))';

View File

@ -1,6 +1,8 @@
import type { SourceFile, Node } from 'typescript'; import type { SourceFile, Node } from 'typescript';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function checkSharedNpmPackagesMatchExpected(ast: SourceFile) { export function checkSharedNpmPackagesMatchExpected(ast: SourceFile) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const SHARE_HELPER_SELECTOR = const SHARE_HELPER_SELECTOR =
'PropertyAssignment:has(Identifier[name=shared]) > CallExpression:has(Identifier[name=share])'; 'PropertyAssignment:has(Identifier[name=shared]) > CallExpression:has(Identifier[name=share])';

View File

@ -1,4 +1,5 @@
import type { SourceFile } from 'typescript'; import type { SourceFile } from 'typescript';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export type IsHostRemoteConfigResult = 'host' | 'remote' | 'both' | false; export type IsHostRemoteConfigResult = 'host' | 'remote' | 'both' | false;
@ -11,6 +12,7 @@ const PROPERTY_SELECTOR = 'ObjectLiteralExpression > PropertyAssignment';
export function isHostRemoteConfig(ast: SourceFile): IsHostRemoteConfigResult { export function isHostRemoteConfig(ast: SourceFile): IsHostRemoteConfigResult {
let isHost = false; let isHost = false;
let isRemote = false; let isRemote = false;
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const remotesNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, { const remotesNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, {
@ -33,6 +35,7 @@ export function isHostRemoteConfig(ast: SourceFile): IsHostRemoteConfigResult {
} }
export function getRemotesFromHost(ast: SourceFile) { export function getRemotesFromHost(ast: SourceFile) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const remotesObjectNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, { const remotesObjectNodes = tsquery(ast, REMOTES_EXPRESSION_SELECTOR, {
visitAllChildren: true, visitAllChildren: true,
@ -63,6 +66,7 @@ export function getRemotesFromHost(ast: SourceFile) {
} }
export function getExposedModulesFromRemote(ast: SourceFile) { export function getExposedModulesFromRemote(ast: SourceFile) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const exposesObjectNodes = tsquery(ast, EXPOSES_EXPRESSION_SELECTOR, { const exposesObjectNodes = tsquery(ast, EXPOSES_EXPRESSION_SELECTOR, {
visitAllChildren: true, visitAllChildren: true,

View File

@ -1,4 +1,5 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function parseASTOfWebpackConfig( export function parseASTOfWebpackConfig(
tree: Tree, tree: Tree,
@ -9,6 +10,7 @@ export function parseASTOfWebpackConfig(
`Cannot migrate webpack config at \`${pathToWebpackConfig}\` as it does not exist. Please ensure this file exists and that the path to the file is correct.` `Cannot migrate webpack config at \`${pathToWebpackConfig}\` as it does not exist. Please ensure this file exists and that the path to the file is correct.`
); );
} }
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const source = tree.read(pathToWebpackConfig, 'utf-8'); const source = tree.read(pathToWebpackConfig, 'utf-8');

View File

@ -1,5 +1,6 @@
import { cypressInitGenerator } from '@nrwl/cypress'; import { cypressInitGenerator } from '@nrwl/cypress';
import { import {
addDependenciesToPackageJson,
ensurePackage, ensurePackage,
formatFiles, formatFiles,
GeneratorCallback, GeneratorCallback,
@ -27,13 +28,6 @@ export async function angularInitGenerator(
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
const options = normalizeOptions(rawOptions); const options = normalizeOptions(rawOptions);
setDefaults(host, options); setDefaults(host, options);
await jsInitGenerator(host, {
...options,
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
js: false,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
const peerDepsToInstall = [ const peerDepsToInstall = [
@ -49,17 +43,36 @@ export async function angularInitGenerator(
devkitVersion ??= devkitVersion ??=
getInstalledPackageVersion(host, '@angular-devkit/build-angular') ?? getInstalledPackageVersion(host, '@angular-devkit/build-angular') ??
backwardCompatibleVersions.angularV14.angularDevkitVersion; backwardCompatibleVersions.angularV14.angularDevkitVersion;
ensurePackage(host, pkg, devkitVersion);
try {
ensurePackage(pkg, devkitVersion);
} catch {
// @schematics/angular cannot be required so this fails but this will still allow wrapping the schematic later on
}
if (!options.skipPackageJson) {
tasks.push(
addDependenciesToPackageJson(host, {}, { [pkg]: devkitVersion })
);
}
} }
}); });
const jsTask = await jsInitGenerator(host, {
...options,
js: false,
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
skipFormat: true,
});
tasks.push(jsTask);
if (!options.skipPackageJson) { if (!options.skipPackageJson) {
tasks.push(updateDependencies(host)); tasks.push(updateDependencies(host));
} }
const unitTestTask = await addUnitTestRunner(host, options); const unitTestTask = await addUnitTestRunner(host, options);
tasks.push(unitTestTask); tasks.push(unitTestTask);
const e2eTask = addE2ETestRunner(host, options); const e2eTask = await addE2ETestRunner(host, options);
tasks.push(e2eTask); tasks.push(e2eTask);
addGitIgnoreEntry(host, '.angular'); addGitIgnoreEntry(host, '.angular');
@ -169,7 +182,10 @@ async function addUnitTestRunner(
} }
} }
function addE2ETestRunner(tree: Tree, options: Schema): GeneratorCallback { async function addE2ETestRunner(
tree: Tree,
options: Schema
): Promise<GeneratorCallback> {
switch (options.e2eTestRunner) { switch (options.e2eTestRunner) {
case E2eTestRunner.Protractor: case E2eTestRunner.Protractor:
return !options.skipPackageJson return !options.skipPackageJson
@ -193,7 +209,7 @@ function addE2ETestRunner(tree: Tree, options: Schema): GeneratorCallback {
) )
: () => {}; : () => {};
case E2eTestRunner.Cypress: case E2eTestRunner.Cypress:
return cypressInitGenerator(tree, { return await cypressInitGenerator(tree, {
skipPackageJson: options.skipPackageJson, skipPackageJson: options.skipPackageJson,
}); });
default: default:

View File

@ -2,21 +2,8 @@ jest.mock('@nrwl/devkit', () => ({
...jest.requireActual('@nrwl/devkit'), ...jest.requireActual('@nrwl/devkit'),
// need to mock so it doesn't resolve what the workspace has installed // need to mock so it doesn't resolve what the workspace has installed
// and be able to test with different versions // and be able to test with different versions
ensurePackage: jest.fn().mockImplementation((tree, pkg, version, options) => { ensurePackage: jest.fn(),
updateJson(tree, 'package.json', (json) => ({
...json,
dependencies: {
...json.dependencies,
...(options?.dev === false ? { [pkg]: version } : {}),
},
devDependencies: {
...json.devDependencies,
...(options?.dev ?? true ? { [pkg]: version } : {}),
},
}));
}),
})); }));
import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nrwl/devkit'; import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { Linter } from '@nrwl/linter'; import { Linter } from '@nrwl/linter';
@ -30,6 +17,7 @@ describe('init', () => {
beforeEach(() => { beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
require('@nrwl/devkit').ensurePackage.mockImplementation(() => {});
}); });
it('should add angular dependencies', async () => { it('should add angular dependencies', async () => {

View File

@ -1,5 +1,6 @@
import { cypressInitGenerator } from '@nrwl/cypress'; import { cypressInitGenerator } from '@nrwl/cypress';
import { import {
addDependenciesToPackageJson,
ensurePackage, ensurePackage,
formatFiles, formatFiles,
GeneratorCallback, GeneratorCallback,
@ -50,6 +51,9 @@ export async function angularInitGenerator(
return; return;
} }
const tasks: GeneratorCallback[] = [];
const options = normalizeOptions(rawOptions);
const peerDepsToInstall = [ const peerDepsToInstall = [
'@angular-devkit/core', '@angular-devkit/core',
'@angular-devkit/schematics', '@angular-devkit/schematics',
@ -63,27 +67,36 @@ export async function angularInitGenerator(
devkitVersion ??= devkitVersion ??=
getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ?? getInstalledPackageVersion(tree, '@angular-devkit/build-angular') ??
angularDevkitVersion; angularDevkitVersion;
ensurePackage(tree, pkg, devkitVersion);
try {
ensurePackage(pkg, devkitVersion);
} catch {
// @schematics/angular cannot be required so this fails but this will still allow wrapping the schematic later on
}
if (!options.skipPackageJson) {
tasks.push(
addDependenciesToPackageJson(tree, {}, { [pkg]: devkitVersion })
);
}
} }
}); });
const options = normalizeOptions(rawOptions);
setDefaults(tree, options); setDefaults(tree, options);
await jsInitGenerator(tree, {
const jsTask = await jsInitGenerator(tree, {
...options, ...options,
tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json', tsConfigName: options.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
js: false, js: false,
skipFormat: true, skipFormat: true,
}); });
tasks.push(jsTask);
const tasks: GeneratorCallback[] = [];
if (!options.skipPackageJson) { if (!options.skipPackageJson) {
tasks.push(updateDependencies(tree)); tasks.push(updateDependencies(tree));
} }
const unitTestTask = await addUnitTestRunner(tree, options); const unitTestTask = await addUnitTestRunner(tree, options);
tasks.push(unitTestTask); tasks.push(unitTestTask);
const e2eTask = addE2ETestRunner(tree, options); const e2eTask = await addE2ETestRunner(tree, options);
tasks.push(e2eTask); tasks.push(e2eTask);
addGitIgnoreEntry(tree, '.angular'); addGitIgnoreEntry(tree, '.angular');
@ -191,7 +204,10 @@ async function addUnitTestRunner(
} }
} }
function addE2ETestRunner(tree: Tree, options: Schema): GeneratorCallback { async function addE2ETestRunner(
tree: Tree,
options: Schema
): Promise<GeneratorCallback> {
switch (options.e2eTestRunner) { switch (options.e2eTestRunner) {
case E2eTestRunner.Protractor: case E2eTestRunner.Protractor:
return !options.skipPackageJson return !options.skipPackageJson

View File

@ -8,6 +8,7 @@ import {
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { getInstalledAngularVersionInfo } from '../../utils/version-utils'; import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
import { v14TestFile } from './v14-test-file'; import { v14TestFile } from './v14-test-file';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function generateKarmaProjectFiles(tree: Tree, project: string): void { export function generateKarmaProjectFiles(tree: Tree, project: string): void {
const projectConfig = readProjectConfiguration(tree, project); const projectConfig = readProjectConfiguration(tree, project);
@ -75,6 +76,7 @@ function isUsingConfigSetInBaseKarmaConfig(tree: Tree) {
if (!tree.exists('karma.conf.js')) { if (!tree.exists('karma.conf.js')) {
return false; return false;
} }
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const CONFIG_SET_SELECTOR = const CONFIG_SET_SELECTOR =

View File

@ -3,6 +3,7 @@ import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils';
import { NormalizedSchema } from './normalized-schema'; import { NormalizedSchema } from './normalized-schema';
import { addRoute } from '../../../utils/nx-devkit/route-utils'; import { addRoute } from '../../../utils/nx-devkit/route-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -14,7 +15,7 @@ export function addChildren(
throw new Error(`Cannot find '${options.parent}'`); throw new Error(`Cannot find '${options.parent}'`);
} }
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const routeFileSource = tree.read(options.parent, 'utf-8'); const routeFileSource = tree.read(options.parent, 'utf-8');

View File

@ -3,6 +3,7 @@ import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils';
import { NormalizedSchema } from './normalized-schema'; import { NormalizedSchema } from './normalized-schema';
import { dirname } from 'path'; import { dirname } from 'path';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -11,7 +12,7 @@ export function addLazyLoadedRouterConfiguration(
options: NormalizedSchema['libraryOptions'] options: NormalizedSchema['libraryOptions']
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const constName = `${names(options.fileName).propertyName}Routes`; const constName = `${names(options.fileName).propertyName}Routes`;
tree.write( tree.write(

View File

@ -1,6 +1,7 @@
import { names, Tree } from '@nrwl/devkit'; import { names, Tree } from '@nrwl/devkit';
import { NormalizedSchema } from './normalized-schema'; import { NormalizedSchema } from './normalized-schema';
import { addRoute } from '../../../utils/nx-devkit/route-utils'; import { addRoute } from '../../../utils/nx-devkit/route-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -12,7 +13,7 @@ export function addLoadChildren(
throw new Error(`Cannot find '${options.parent}'`); throw new Error(`Cannot find '${options.parent}'`);
} }
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const moduleSource = tree.read(options.parent, 'utf-8'); const moduleSource = tree.read(options.parent, 'utf-8');

View File

@ -4,6 +4,7 @@ import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addImportToModule } from '../../../utils/nx-devkit/ast-utils'; import { addImportToModule } from '../../../utils/nx-devkit/ast-utils';
import { NormalizedSchema } from './normalized-schema'; import { NormalizedSchema } from './normalized-schema';
import { dirname } from 'path'; import { dirname } from 'path';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -12,7 +13,7 @@ export function addRouterConfiguration(
options: NormalizedSchema['libraryOptions'] options: NormalizedSchema['libraryOptions']
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const constName = `${names(options.fileName).propertyName}Routes`; const constName = `${names(options.fileName).propertyName}Routes`;
const moduleSource = tree.read(options.modulePath, 'utf-8'); const moduleSource = tree.read(options.modulePath, 'utf-8');

View File

@ -29,21 +29,7 @@ jest.mock('@nrwl/devkit', () => {
createProjectGraphAsync: jest.fn().mockImplementation(() => projectGraph), createProjectGraphAsync: jest.fn().mockImplementation(() => projectGraph),
// need to mock so it doesn't resolve what the workspace has installed // need to mock so it doesn't resolve what the workspace has installed
// and be able to test with different versions // and be able to test with different versions
ensurePackage: jest ensurePackage: jest.fn().mockImplementation((pkg) => require(pkg)),
.fn()
.mockImplementation((tree, pkg, version, options) => {
updateJson(tree, 'package.json', (json) => ({
...json,
dependencies: {
...json.dependencies,
...(options?.dev === false ? { [pkg]: version } : {}),
},
devDependencies: {
...json.devDependencies,
...(options?.dev ?? true ? { [pkg]: version } : {}),
},
}));
}),
}; };
}); });

View File

@ -45,6 +45,7 @@ import type {
} from '../../utilities'; } from '../../utilities';
import { FileChangeRecorder } from '../../utilities'; import { FileChangeRecorder } from '../../utilities';
import { ProjectMigrator } from './project.migrator'; import { ProjectMigrator } from './project.migrator';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
type SupportedTargets = 'e2e'; type SupportedTargets = 'e2e';
const supportedTargets: Record<SupportedTargets, Target> = { const supportedTargets: Record<SupportedTargets, Target> = {
@ -577,6 +578,7 @@ export class E2eMigrator extends ProjectMigrator<SupportedTargets> {
} }
private updateCypress10ConfigFile(configFilePath: string): void { private updateCypress10ConfigFile(configFilePath: string): void {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
this.cypressPreset = nxE2EPreset(configFilePath); this.cypressPreset = nxE2EPreset(configFilePath);
@ -657,6 +659,7 @@ export class E2eMigrator extends ProjectMigrator<SupportedTargets> {
recorder: FileChangeRecorder, recorder: FileChangeRecorder,
{ ...globalConfig }: CypressCommonConfig { ...globalConfig }: CypressCommonConfig
): void { ): void {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const e2eConfig = {}; const e2eConfig = {};
const presetSpreadAssignment = `...nxE2EPreset(__dirname),`; const presetSpreadAssignment = `...nxE2EPreset(__dirname),`;

View File

@ -12,6 +12,7 @@ import type * as ts from 'typescript';
import { ArrayLiteralExpression } from 'typescript'; import { ArrayLiteralExpression } from 'typescript';
import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addRoute } from '../../../utils/nx-devkit/route-utils'; import { addRoute } from '../../../utils/nx-devkit/route-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -121,7 +122,7 @@ function addLazyLoadedRouteToHostAppModule(
hostFederationType: 'dynamic' | 'static' hostFederationType: 'dynamic' | 'static'
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const hostAppConfig = readProjectConfiguration(tree, options.host); const hostAppConfig = readProjectConfiguration(tree, options.host);

View File

@ -1,8 +1,10 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { joinPathFragments, readProjectConfiguration } from '@nrwl/devkit'; import { joinPathFragments, readProjectConfiguration } from '@nrwl/devkit';
import type { Schema } from '../schema'; import type { Schema } from '../schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function updateAppModule(tree: Tree, schema: Schema) { export function updateAppModule(tree: Tree, schema: Schema) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
// read the content of app module // read the content of app module
const projectConfig = readProjectConfiguration(tree, schema.project); const projectConfig = readProjectConfiguration(tree, schema.project);

View File

@ -1,9 +1,8 @@
import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version'; import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
import { ensurePackage, Tree } from '@nrwl/devkit'; import { Tree } from '@nrwl/devkit';
import { writeJson } from '@nrwl/devkit'; import { writeJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { Linter } from '@nrwl/linter'; import { Linter } from '@nrwl/linter';
import { nxVersion } from '../../utils/versions';
import { componentGenerator } from '../component/component'; import { componentGenerator } from '../component/component';
import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry-point/library-secondary-entry-point'; import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry-point/library-secondary-entry-point';
import { libraryGenerator } from '../library/library'; import { libraryGenerator } from '../library/library';
@ -48,7 +47,6 @@ describe('angularStories generator: libraries', () => {
beforeEach(async () => { beforeEach(async () => {
tree = await createStorybookTestWorkspaceForLib(libName); tree = await createStorybookTestWorkspaceForLib(libName);
ensurePackage(tree, '@nrwl/storybook', nxVersion);
cypressProjectGenerator = await ( cypressProjectGenerator = await (
await import('@nrwl/storybook') await import('@nrwl/storybook')
).cypressProjectGenerator; ).cypressProjectGenerator;

View File

@ -6,8 +6,10 @@ export async function generateStorybookConfiguration(
tree: Tree, tree: Tree,
options: StorybookConfigurationOptions options: StorybookConfigurationOptions
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(tree, '@nrwl/storybook', nxVersion); const { configurationGenerator } = ensurePackage(
const { configurationGenerator } = await import('@nrwl/storybook'); '@nrwl/storybook',
nxVersion
);
return await configurationGenerator(tree, { return await configurationGenerator(tree, {
name: options.name, name: options.name,
uiFramework: '@storybook/angular', uiFramework: '@storybook/angular',

View File

@ -16,6 +16,7 @@ import type {
import { SyntaxKind } from 'typescript'; import { SyntaxKind } from 'typescript';
import { getDecoratorMetadata } from '../../../utils/nx-devkit/ast-utils'; import { getDecoratorMetadata } from '../../../utils/nx-devkit/ast-utils';
import type { EntryPoint } from './entry-point'; import type { EntryPoint } from './entry-point';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export function getModuleDeclaredComponents( export function getModuleDeclaredComponents(
file: SourceFile, file: SourceFile,
@ -78,6 +79,7 @@ export function getModuleFilePaths(
} }
function hasNgModule(tree: Tree, filePath: string): boolean { function hasNgModule(tree: Tree, filePath: string): boolean {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const fileContent = tree.read(filePath, 'utf-8'); const fileContent = tree.read(filePath, 'utf-8');
const ast = tsquery.ast(fileContent); const ast = tsquery.ast(fileContent);

View File

@ -9,6 +9,7 @@ import {
removeChange, removeChange,
replaceChange, replaceChange,
} from '@nrwl/workspace/src/utilities/ast-utils'; } from '@nrwl/workspace/src/utilities/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -19,7 +20,7 @@ function _angularImportsFromNode(
_sourceFile: ts.SourceFile _sourceFile: ts.SourceFile
): { [name: string]: string } { ): { [name: string]: string } {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const ms = node.moduleSpecifier; const ms = node.moduleSpecifier;
let modulePath: string; let modulePath: string;
@ -89,7 +90,7 @@ export function getDecoratorMetadata(
module: string module: string
): ts.Node[] { ): ts.Node[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const angularImports: { [name: string]: string } = findNodes( const angularImports: { [name: string]: string } = findNodes(
source, source,
@ -169,7 +170,7 @@ function _addSymbolToDecoratorMetadata(
return source; return source;
} }
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
// Get all the children property assignment of object literals. // Get all the children property assignment of object literals.
const matchingProperties: ts.ObjectLiteralElement[] = ( const matchingProperties: ts.ObjectLiteralElement[] = (
@ -415,7 +416,7 @@ export function addImportToTestBed(
symbolName: string symbolName: string
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allCalls: ts.CallExpression[] = <any>( const allCalls: ts.CallExpression[] = <any>(
findNodes(source, tsModule.SyntaxKind.CallExpression) findNodes(source, tsModule.SyntaxKind.CallExpression)
@ -456,7 +457,7 @@ export function addDeclarationsToTestBed(
symbolName: string[] symbolName: string[]
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allCalls: ts.CallExpression[] = <any>( const allCalls: ts.CallExpression[] = <any>(
findNodes(source, tsModule.SyntaxKind.CallExpression) findNodes(source, tsModule.SyntaxKind.CallExpression)
@ -498,7 +499,7 @@ export function replaceIntoToTestBed(
previousSymbol: string previousSymbol: string
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allCalls: ts.CallExpression[] = <any>( const allCalls: ts.CallExpression[] = <any>(
findNodes(source, tsModule.SyntaxKind.CallExpression) findNodes(source, tsModule.SyntaxKind.CallExpression)
@ -592,7 +593,7 @@ function getListOfRoutes(
source: ts.SourceFile source: ts.SourceFile
): ts.NodeArray<ts.Expression> | null { ): ts.NodeArray<ts.Expression> | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const imports: any = getMatchingProperty( const imports: any = getMatchingProperty(
source, source,
@ -647,6 +648,7 @@ export function addProviderToBootstrapApplication(
filePath: string, filePath: string,
providerToAdd: string providerToAdd: string
) { ) {
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
const PROVIDERS_ARRAY_SELECTOR = const PROVIDERS_ARRAY_SELECTOR =
'CallExpression:has(Identifier[name=bootstrapApplication]) ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=providers]) > ArrayLiteralExpression'; 'CallExpression:has(Identifier[name=bootstrapApplication]) ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=providers]) > ArrayLiteralExpression';
@ -749,7 +751,7 @@ export function readBootstrapInfo(
bootstrapComponentFileName: string; bootstrapComponentFileName: string;
} { } {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const config = readProjectConfiguration(host, app); const config = readProjectConfiguration(host, app);
@ -831,7 +833,7 @@ export function getDecoratorPropertyValueNode(
module: string module: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const moduleSourceText = host.read(modulePath)!.toString('utf-8'); const moduleSourceText = host.read(modulePath)!.toString('utf-8');
const moduleSource = tsModule.createSourceFile( const moduleSource = tsModule.createSourceFile(
@ -856,7 +858,7 @@ function getMatchingObjectLiteralElement(
property: string property: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
return ( return (
(node as ts.ObjectLiteralExpression).properties (node as ts.ObjectLiteralExpression).properties
@ -878,7 +880,7 @@ function getMatchingObjectLiteralElement(
export function getTsSourceFile(host: Tree, path: string): ts.SourceFile { export function getTsSourceFile(host: Tree, path: string): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const buffer = host.read(path); const buffer = host.read(path);
if (!buffer) { if (!buffer) {

View File

@ -1,6 +1,7 @@
import { Tree } from '@nrwl/devkit'; import { Tree } from '@nrwl/devkit';
import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils'; import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
import { addRouteToNgModule } from './ast-utils'; import { addRouteToNgModule } from './ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -20,6 +21,7 @@ export function addRoute(
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = require('typescript');
} }
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
let routesFileContents = tree.read(routesFile, 'utf-8'); let routesFileContents = tree.read(routesFile, 'utf-8');
@ -92,6 +94,7 @@ export function addProviderToRoute(
); );
} }
ensureTypescript();
const { tsquery } = require('@phenomnomnominal/tsquery'); const { tsquery } = require('@phenomnomnominal/tsquery');
let routesFileContents = tree.read(routesFile, 'utf-8'); let routesFileContents = tree.read(routesFile, 'utf-8');

View File

@ -265,16 +265,12 @@ export async function addLinter(host: Tree, options: CypressProjectSchema) {
export async function cypressProjectGenerator(host: Tree, schema: Schema) { export async function cypressProjectGenerator(host: Tree, schema: Schema) {
const options = normalizeOptions(host, schema); const options = normalizeOptions(host, schema);
await jsInitGenerator(host, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
const cypressVersion = installedCypressVersion(); const cypressVersion = installedCypressVersion();
// if there is an installed cypress version, then we don't call // if there is an installed cypress version, then we don't call
// init since we want to keep the existing version that is installed // init since we want to keep the existing version that is installed
if (!cypressVersion) { if (!cypressVersion) {
tasks.push(cypressInitGenerator(host, options)); tasks.push(await cypressInitGenerator(host, options));
} }
if (schema.bundler === 'vite') { if (schema.bundler === 'vite') {

View File

@ -21,7 +21,7 @@ describe('init', () => {
json.devDependencies[existing] = existingVersion; json.devDependencies[existing] = existingVersion;
return json; return json;
}); });
cypressInitGenerator(tree, {}); await cypressInitGenerator(tree, {});
const packageJson = readJson(tree, 'package.json'); const packageJson = readJson(tree, 'package.json');
expect(packageJson.devDependencies.cypress).toBeDefined(); expect(packageJson.devDependencies.cypress).toBeDefined();
@ -39,7 +39,7 @@ describe('init', () => {
return json; return json;
}); });
cypressInitGenerator(tree, {}); await cypressInitGenerator(tree, {});
expect( expect(
readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults.e2e readJson<NxJsonConfiguration>(tree, 'nx.json').targetDefaults.e2e

View File

@ -1,6 +1,7 @@
import { import {
addDependenciesToPackageJson, addDependenciesToPackageJson,
convertNxGenerator, convertNxGenerator,
GeneratorCallback,
readNxJson, readNxJson,
removeDependenciesFromPackageJson, removeDependenciesFromPackageJson,
Tree, Tree,
@ -12,6 +13,8 @@ import {
typesNodeVersion, typesNodeVersion,
} from '../../utils/versions'; } from '../../utils/versions';
import { Schema } from './schema'; import { Schema } from './schema';
import { initGenerator } from '@nrwl/js';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
function setupE2ETargetDefaults(tree: Tree) { function setupE2ETargetDefaults(tree: Tree) {
const nxJson = readNxJson(tree); const nxJson = readNxJson(tree);
@ -47,9 +50,23 @@ function updateDependencies(tree: Tree) {
); );
} }
export function cypressInitGenerator(tree: Tree, options: Schema) { export async function cypressInitGenerator(tree: Tree, options: Schema) {
setupE2ETargetDefaults(tree); setupE2ETargetDefaults(tree);
return !options.skipPackageJson ? updateDependencies(tree) : () => {};
const tasks: GeneratorCallback[] = [];
tasks.push(
await initGenerator(tree, {
...options,
skipFormat: true,
})
);
if (!options.skipPackageJson) {
tasks.push(updateDependencies(tree));
}
return runTasksInSerial(...tasks);
} }
export default cypressInitGenerator; export default cypressInitGenerator;

View File

@ -1,3 +1,5 @@
export interface Schema { export interface Schema {
skipPackageJson?: boolean; skipPackageJson?: boolean;
skipFormat?: boolean;
} }

View File

@ -10,6 +10,7 @@ import {
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { basename, dirname, extname, relative } from 'path'; import { basename, dirname, extname, relative } from 'path';
import type { StringLiteral } from 'typescript'; import type { StringLiteral } from 'typescript';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
let tsquery: typeof import('@phenomnomnominal/tsquery').tsquery; let tsquery: typeof import('@phenomnomnominal/tsquery').tsquery;
@ -269,11 +270,12 @@ export function updateImports(
oldImportPath: string, oldImportPath: string,
newImportPath: string newImportPath: string
) { ) {
if (!tsquery) {
tsquery = require('@phenomnomnominal/tsquery').tsquery;
}
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
}
if (!tsquery) {
ensureTypescript();
tsquery = require('@phenomnomnominal/tsquery').tsquery;
} }
const { isCallExpression, isExportDeclaration, isImportDeclaration } = const { isCallExpression, isExportDeclaration, isImportDeclaration } =
tsModule; tsModule;

View File

@ -30,6 +30,7 @@
"dependencies": { "dependencies": {
"ejs": "^3.1.7", "ejs": "^3.1.7",
"ignore": "^5.0.4", "ignore": "^5.0.4",
"tmp": "~0.2.1",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"@phenomnomnominal/tsquery": "4.1.1", "@phenomnomnominal/tsquery": "4.1.1",
"semver": "7.3.4" "semver": "7.3.4"

View File

@ -456,30 +456,11 @@ describe('ensurePackage', () => {
tree = createTree(); tree = createTree();
}); });
it('should return successfully when package is present', async () => { it('should return package when present', async () => {
writeJson(tree, 'package.json', {}); writeJson(tree, 'package.json', {});
expect( expect(ensurePackage('@nrwl/devkit', '>=15.0.0')).toEqual(
ensurePackage(tree, '@nrwl/devkit', '>=15.0.0', { require('@nrwl/devkit')
throwOnMissing: true, ); // return void
})
).toBeUndefined(); // return void
});
it('should throw when dependencies are missing', async () => {
writeJson(tree, 'package.json', {});
expect(() =>
ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', {
throwOnMissing: true,
})
).toThrow(/-D( -W)? @nrwl\/does-not-exist@>=15.0.0/);
expect(() =>
ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', {
dev: false,
throwOnMissing: true,
})
).toThrow('@nrwl/does-not-exist@>=15.0.0');
}); });
}); });

View File

@ -1,15 +1,17 @@
import { execSync } from 'child_process'; import { execSync } from 'child_process';
import { Module } from 'module';
import type { Tree } from 'nx/src/generators/tree'; import type { Tree } from 'nx/src/generators/tree';
import type { GeneratorCallback } from 'nx/src/config/misc-interfaces'; import type { GeneratorCallback } from 'nx/src/config/misc-interfaces';
import { clean, coerce, gt, satisfies } from 'semver'; import { clean, coerce, gt } from 'semver';
import { installPackagesTask } from '../tasks/install-packages-task'; import { installPackagesTask } from '../tasks/install-packages-task';
import { requireNx } from '../../nx'; import { requireNx } from '../../nx';
import { dirSync } from 'tmp';
import { join } from 'path';
const { readJson, updateJson, getPackageManagerCommand, workspaceRoot } = const { readJson, updateJson, getPackageManagerCommand } = requireNx();
requireNx();
const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION'; const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION';
const NON_SEMVER_TAGS = { const NON_SEMVER_TAGS = {
@ -360,6 +362,8 @@ function requiresRemovingOfPackages(
return needsDepsUpdate || needsDevDepsUpdate; return needsDepsUpdate || needsDevDepsUpdate;
} }
const packageMapCache = new Map<string, any>();
/** /**
* @typedef EnsurePackageOptions * @typedef EnsurePackageOptions
* @type {object} * @type {object}
@ -367,6 +371,30 @@ function requiresRemovingOfPackages(
* @property {throwOnMissing} boolean throws an error when the package is missing * @property {throwOnMissing} boolean throws an error when the package is missing
*/ */
/**
* @deprecated Use the other function signature without a Tree
*
* Use a package that has not been installed as a dependency.
*
* For example:
* ```typescript
* ensurePackage(tree, '@nrwl/jest', nxVersion)
* ```
* This install the @nrwl/jest@<nxVersion> and return the module
* When running with --dryRun, the function will throw when dependencies are missing.
*
* @param tree the file system tree
* @param pkg the package to check (e.g. @nrwl/jest)
* @param requiredVersion the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0)
* @param {EnsurePackageOptions} options?
*/
export function ensurePackage(
tree: Tree,
pkg: string,
requiredVersion: string,
options?: { dev?: boolean; throwOnMissing?: boolean }
): void;
/** /**
* Ensure that dependencies and devDependencies from package.json are installed at the required versions. * Ensure that dependencies and devDependencies from package.json are installed at the required versions.
* *
@ -374,85 +402,86 @@ function requiresRemovingOfPackages(
* ```typescript * ```typescript
* ensurePackage(tree, '@nrwl/jest', nxVersion) * ensurePackage(tree, '@nrwl/jest', nxVersion)
* ``` * ```
* This will check that @nrwl/jest@<nxVersion> exists in devDependencies. * @param pkg the package to install and require
* If it exists then function returns, otherwise it will install the package before continuing. * @param version the version to install if the package doesn't exist already
* When running with --dryRun, the function will throw when dependencies are missing.
*
* @param tree the file system tree
* @param pkg the package to check (e.g. @nrwl/jest)
* @param requiredVersion the version or semver range to check (e.g. ~1.0.0, >=1.0.0 <2.0.0)
* @param {EnsurePackageOptions} options
*/ */
export function ensurePackage( export function ensurePackage<T extends any = any>(
tree: Tree,
pkg: string, pkg: string,
requiredVersion: string, version: string
options: { ): T;
dev?: boolean; export function ensurePackage<T extends any = any>(
throwOnMissing?: boolean; pkgOrTree: string | Tree,
} = {} requiredVersionOrPackage: string,
): void { maybeRequiredVersion?: string,
// Read package and version from root package.json file. _?: never
const dev = options.dev ?? true; ): T {
const throwOnMissing = let pkg: string;
options.throwOnMissing ?? process.env.NX_DRY_RUN === 'true'; // NX_DRY_RUN is set in `packages/nx/src/command-line/nx-commands.ts` let requiredVersion: string;
const pmc = getPackageManagerCommand(); if (typeof pkgOrTree === 'string') {
pkg = pkgOrTree;
let version = getPackageVersion(pkg); requiredVersion = requiredVersionOrPackage;
} else {
// Otherwise try to read in from package.json. This is needed for E2E tests to pass. // Old Signature
if (!version) { pkg = requiredVersionOrPackage;
const packageJson = readJson(tree, 'package.json'); requiredVersion = maybeRequiredVersion;
const field = dev ? 'devDependencies' : 'dependencies';
version = packageJson[field]?.[pkg];
} }
if ( if (packageMapCache.has(pkg)) {
// Special case: When running Nx unit tests, the version read from package.json is "0.0.1". return packageMapCache.get(pkg) as T;
!( }
pkg.startsWith('@nrwl/') &&
(version === '0.0.1' || requiredVersion === '0.0.1') try {
) && return require(pkg);
// Normal case } catch (e) {
!satisfies(version, requiredVersion, { includePrerelease: true }) if (e.code !== 'MODULE_NOT_FOUND') {
) { throw e;
const installCmd = `${ }
dev ? pmc.addDev : pmc.add }
} ${pkg}@${requiredVersion}`;
if (throwOnMissing) { if (process.env.NX_DRY_RUN && process.env.NX_DRY_RUN !== 'false') {
throw new Error( throw new Error(
`Cannot install required package ${pkg} during a dry run. Run the generator without --dryRun, or install the package with "${installCmd}" and try again.` 'NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Run" button.\n'
); );
} else { }
execSync(installCmd, {
cwd: tree.root, const tempDir = dirSync().name;
execSync(`${getPackageManagerCommand().addDev} ${pkg}@${requiredVersion}`, {
cwd: tempDir,
stdio: [0, 1, 2], stdio: [0, 1, 2],
}); });
}
} addToNodePath(join(tempDir, 'node_modules'));
// Re-initialize the added paths into require
(Module as any)._initPaths();
const result = require(require.resolve(pkg, {
paths: [tempDir],
}));
packageMapCache.set(pkg, result);
return result;
} }
/** function addToNodePath(dir: string) {
* Use another process to resolve the package.json path of the package (if it exists). // NODE_PATH is a delimited list of paths.
* Cannot use `require.resolve` here since there is an unclearable internal cache used by Node that can lead to issues // The delimiter is different for windows.
* when resolving the package after installation. const delimiter = require('os').platform() === 'win32' ? ';' : ':';
*
* See: https://github.com/nodejs/node/issues/31803 const paths = process.env.NODE_PATH
*/ ? process.env.NODE_PATH.split(delimiter)
function getPackageVersion(pkg: string): undefined | string { : [];
try {
return execSync( // Add the tmp path
`node -e "console.log(require('${pkg}/package.json').version)"`, paths.push(dir);
{
cwd: workspaceRoot, // Update the env variable.
stdio: ['pipe', 'pipe', 'ignore'], process.env.NODE_PATH = paths.join(delimiter);
} }
)
.toString() function getPackageVersion(pkg: string): string {
.trim(); return require(join(pkg, 'package.json')).version;
} catch (e) {
return undefined;
}
} }
/** /**

View File

@ -43,13 +43,16 @@ import { initRootBabelConfig } from './lib/init-root-babel-config';
export async function expoInitGenerator(host: Tree, schema: Schema) { export async function expoInitGenerator(host: Tree, schema: Schema) {
addGitIgnoreEntry(host); addGitIgnoreEntry(host);
initRootBabelConfig(host); initRootBabelConfig(host);
await jsInitGenerator(host, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(host, {
...schema,
skipFormat: true,
})
);
if (!schema.skipPackageJson) { if (!schema.skipPackageJson) {
tasks.push(moveDependency(host)); tasks.push(moveDependency(host));
tasks.push(updateDependencies(host)); tasks.push(updateDependencies(host));

View File

@ -191,12 +191,15 @@ export async function jestInitGenerator(
schema: JestInitSchema schema: JestInitSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
const options = normalizeOptions(schema); const options = normalizeOptions(schema);
await jsInitGenerator(tree, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(tree, {
...schema,
skipFormat: true,
})
);
createJestConfig(tree, options); createJestConfig(tree, options);
if (!options.skipPackageJson) { if (!options.skipPackageJson) {

View File

@ -3,6 +3,7 @@ import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit';
import { Config } from '@jest/types'; import { Config } from '@jest/types';
import { createContext, runInContext } from 'vm'; import { createContext, runInContext } from 'vm';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -18,7 +19,7 @@ function findPropertyAssignment(
propertyName: string propertyName: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
return object.properties.find((prop) => { return object.properties.find((prop) => {
@ -42,7 +43,7 @@ export function addOrUpdateProperty(
path: string path: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const { SyntaxKind } = tsModule; const { SyntaxKind } = tsModule;
@ -153,7 +154,7 @@ export function removeProperty(
properties: string[] properties: string[]
): ts.PropertyAssignment | null { ): ts.PropertyAssignment | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const propertyName = properties.shift(); const propertyName = properties.shift();
@ -178,7 +179,7 @@ export function removeProperty(
function isModuleExport(node: ts.Statement) { function isModuleExport(node: ts.Statement) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
return ( return (
@ -192,7 +193,7 @@ function isModuleExport(node: ts.Statement) {
function isDefaultExport(node: ts.Statement) { function isDefaultExport(node: ts.Statement) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
return ( return (
@ -210,7 +211,7 @@ export function jestConfigObjectAst(
fileContent: string fileContent: string
): ts.ObjectLiteralExpression { ): ts.ObjectLiteralExpression {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const sourceFile = tsModule.createSourceFile( const sourceFile = tsModule.createSourceFile(

View File

@ -1,33 +1,43 @@
import { import {
addDependenciesToPackageJson,
convertNxGenerator, convertNxGenerator,
ensurePackage,
formatFiles, formatFiles,
generateFiles, generateFiles,
GeneratorCallback,
joinPathFragments, joinPathFragments,
Tree, Tree,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { getRootTsConfigFileName } from '../../utils/typescript/ts-config'; import { getRootTsConfigFileName } from '../../utils/typescript/ts-config';
import { typescriptVersion } from '../../utils/versions'; import { typescriptVersion, nxVersion } from '../../utils/versions';
import { InitSchema } from './schema'; import { InitSchema } from './schema';
export async function initGenerator( export async function initGenerator(
host: Tree, tree: Tree,
schema: InitSchema schema: InitSchema
): Promise<void> { ): Promise<GeneratorCallback> {
if (!schema.js) {
ensurePackage(host, 'typescript', typescriptVersion);
}
// add tsconfig.base.json // add tsconfig.base.json
if (!getRootTsConfigFileName(host)) { if (!getRootTsConfigFileName(tree)) {
generateFiles(host, joinPathFragments(__dirname, './files'), '.', { generateFiles(tree, joinPathFragments(__dirname, './files'), '.', {
fileName: schema.tsConfigName ?? 'tsconfig.base.json', fileName: schema.tsConfigName ?? 'tsconfig.base.json',
}); });
} }
const devDependencies = {
'@nrwl/js': nxVersion,
};
if (!schema.js) {
devDependencies['typescript'] = typescriptVersion;
}
const installTask = !schema.skipPackageJson
? addDependenciesToPackageJson(tree, {}, devDependencies)
: () => {};
if (!schema.skipFormat) { if (!schema.skipFormat) {
await formatFiles(host); await formatFiles(tree);
} }
return installTask;
} }
export default initGenerator; export default initGenerator;

View File

@ -1,5 +1,6 @@
export interface InitSchema { export interface InitSchema {
js?: boolean; js?: boolean;
skipFormat?: boolean; skipFormat?: boolean;
skipPackageJson?: boolean;
tsConfigName?: string; tsConfigName?: string;
} }

View File

@ -14,7 +14,11 @@
"type": "boolean", "type": "boolean",
"aliases": ["skip-format"], "aliases": ["skip-format"],
"description": "Skip formatting files.", "description": "Skip formatting files.",
"default": true, "x-priority": "internal"
},
"skipPackageJson": {
"type": "boolean",
"description": "Skip adding package.json dependencies",
"x-priority": "internal" "x-priority": "internal"
}, },
"tsConfigName": { "tsConfigName": {

View File

@ -54,11 +54,13 @@ export async function projectGenerator(
destinationDir: string, destinationDir: string,
filesDir: string filesDir: string
) { ) {
await jsInitGenerator(tree, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(tree, {
...schema,
skipFormat: true,
})
);
const options = normalizeOptions(tree, schema, destinationDir); const options = normalizeOptions(tree, schema, destinationDir);
createFiles(tree, options, `${filesDir}/lib`); createFiles(tree, options, `${filesDir}/lib`);
@ -68,9 +70,10 @@ export async function projectGenerator(
tasks.push(addProjectDependencies(tree, options)); tasks.push(addProjectDependencies(tree, options));
if (options.bundler === 'vite') { if (options.bundler === 'vite') {
ensurePackage(tree, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = ensurePackage(
// nx-ignore-next-line '@nrwl/vite',
const { viteConfigurationGenerator } = require('@nrwl/vite'); nxVersion
);
const viteTask = await viteConfigurationGenerator(tree, { const viteTask = await viteConfigurationGenerator(tree, {
project: options.name, project: options.name,
newProject: true, newProject: true,
@ -98,9 +101,7 @@ export async function projectGenerator(
options.unitTestRunner === 'vitest' && options.unitTestRunner === 'vitest' &&
options.bundler !== 'vite' // Test would have been set up already options.bundler !== 'vite' // Test would have been set up already
) { ) {
ensurePackage(tree, '@nrwl/vite', nxVersion); const { vitestGenerator } = ensurePackage('@nrwl/vite', nxVersion);
// nx-ignore-next-line
const { vitestGenerator } = require('@nrwl/vite');
const vitestTask = await vitestGenerator(tree, { const vitestTask = await vitestGenerator(tree, {
project: options.name, project: options.name,
uiFramework: 'none', uiFramework: 'none',
@ -196,8 +197,7 @@ export async function addLint(
tree: Tree, tree: Tree,
options: NormalizedSchema options: NormalizedSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(tree, '@nrwl/linter', nxVersion); const { lintProjectGenerator } = ensurePackage('@nrwl/linter', nxVersion);
const { lintProjectGenerator } = require('@nrwl/linter');
return lintProjectGenerator(tree, { return lintProjectGenerator(tree, {
project: options.name, project: options.name,
linter: options.linter, linter: options.linter,
@ -299,8 +299,7 @@ async function addJest(
tree: Tree, tree: Tree,
options: NormalizedSchema options: NormalizedSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(tree, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = ensurePackage('@nrwl/jest', nxVersion);
const { jestProjectGenerator } = require('@nrwl/jest');
return await jestProjectGenerator(tree, { return await jestProjectGenerator(tree, {
...options, ...options,
project: options.name, project: options.name,

View File

@ -0,0 +1,9 @@
import { ensurePackage } from '@nrwl/devkit';
import { typescriptVersion } from '../versions';
export function ensureTypescript() {
return ensurePackage<typeof import('typescript')>(
'typescript',
typescriptVersion
);
}

View File

@ -24,9 +24,9 @@ export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules';
export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules'; export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules';
export async function lintWorkspaceRulesProjectGenerator(tree: Tree) { export async function lintWorkspaceRulesProjectGenerator(tree: Tree) {
ensurePackage(tree, '@nrwl/jest/', nxVersion); const { addPropertyToJestConfig, jestProjectGenerator } = ensurePackage(
const { addPropertyToJestConfig, jestProjectGenerator } = await import( '@nrwl/jest',
'@nrwl/jest' nxVersion
); );
// Noop if the workspace rules project already exists // Noop if the workspace rules project already exists

View File

@ -10,8 +10,7 @@ import { nxVersion } from '../../utils/versions';
export default async function eslint8Updates(tree: Tree) { export default async function eslint8Updates(tree: Tree) {
try { try {
ensurePackage(tree, '@nrwl/jest/', nxVersion); const { addPropertyToJestConfig } = ensurePackage('@nrwl/jest', nxVersion);
const { addPropertyToJestConfig } = await import('@nrwl/jest');
const existingJestConfigPath = normalizePath( const existingJestConfigPath = normalizePath(
'tools/eslint-rules/jest.config.js' 'tools/eslint-rules/jest.config.js'
); );

View File

@ -4,6 +4,7 @@ import {
removeChange, removeChange,
} from '@nrwl/workspace/src/utilities/ast-utils'; } from '@nrwl/workspace/src/utilities/ast-utils';
import type { NormalizedOptions } from '../schema'; import type { NormalizedOptions } from '../schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -12,7 +13,7 @@ export function addExportsToBarrelFile(
options: NormalizedOptions options: NormalizedOptions
): void { ): void {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const indexPath = `${options.projectRoot}/src/index.ts`; const indexPath = `${options.projectRoot}/src/index.ts`;
const indexContent = tree.read(indexPath, 'utf-8'); const indexContent = tree.read(indexPath, 'utf-8');

View File

@ -37,18 +37,21 @@ function updateDependencies(host: Tree) {
} }
export async function nextInitGenerator(host: Tree, schema: InitSchema) { export async function nextInitGenerator(host: Tree, schema: InitSchema) {
await jsInitGenerator(host, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(host, {
...schema,
skipFormat: true,
})
);
if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') { if (!schema.unitTestRunner || schema.unitTestRunner === 'jest') {
const jestTask = await jestInitGenerator(host, schema); const jestTask = await jestInitGenerator(host, schema);
tasks.push(jestTask); tasks.push(jestTask);
} }
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
const cypressTask = cypressInitGenerator(host, {}); const cypressTask = await cypressInitGenerator(host, {});
tasks.push(cypressTask); tasks.push(cypressTask);
} }

View File

@ -37,14 +37,15 @@ function normalizeOptions(schema: Schema) {
export async function initGenerator(tree: Tree, schema: Schema) { export async function initGenerator(tree: Tree, schema: Schema) {
const options = normalizeOptions(schema); const options = normalizeOptions(schema);
const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(tree, { await jsInitGenerator(tree, {
...schema, ...schema,
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json', tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
js: schema.js,
skipFormat: true, skipFormat: true,
}); })
);
const tasks: GeneratorCallback[] = [];
if (options.unitTestRunner === 'jest') { if (options.unitTestRunner === 'jest') {
tasks.push(await jestInitGenerator(tree, schema)); tasks.push(await jestInitGenerator(tree, schema));
} }

View File

@ -43,12 +43,15 @@ import { addGitIgnoreEntry } from './lib/add-git-ignore-entry';
export async function reactNativeInitGenerator(host: Tree, schema: Schema) { export async function reactNativeInitGenerator(host: Tree, schema: Schema) {
addGitIgnoreEntry(host); addGitIgnoreEntry(host);
addBabelInputs(host); addBabelInputs(host);
await jsInitGenerator(host, {
js: schema.js,
skipFormat: true,
});
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(host, {
...schema,
skipFormat: true,
})
);
if (!schema.skipPackageJson) { if (!schema.skipPackageJson) {
const installTask = updateDependencies(host); const installTask = updateDependencies(host);

View File

@ -20,7 +20,7 @@ export async function createAllStories(
projectName: string, projectName: string,
ignorePaths?: string[] ignorePaths?: string[]
) { ) {
ensurePackage(tree, '@nrwl/storybook', nxVersion); ensurePackage('@nrwl/storybook', nxVersion);
const { isTheFileAStory } = await import( const { isTheFileAStory } = await import(
'@nrwl/storybook/src/utils/utilities' '@nrwl/storybook/src/utils/utilities'
); );

View File

@ -27,8 +27,10 @@ export async function storybookConfigurationGenerator(
host: Tree, host: Tree,
schema: StorybookConfigureSchema schema: StorybookConfigureSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(host, '@nrwl/storybook', nxVersion); const { configurationGenerator } = ensurePackage(
const { configurationGenerator } = await import('@nrwl/storybook'); '@nrwl/storybook',
nxVersion
);
const installTask = await configurationGenerator(host, { const installTask = await configurationGenerator(host, {
name: schema.name, name: schema.name,

View File

@ -105,8 +105,10 @@ export async function applicationGenerator(
addProject(host, options); addProject(host, options);
if (options.bundler === 'vite') { if (options.bundler === 'vite') {
ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = ensurePackage(
const { viteConfigurationGenerator } = await import('@nrwl/vite'); '@nrwl/vite',
nxVersion
);
// We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development. // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
// See: https://vitejs.dev/guide/env-and-mode.html // See: https://vitejs.dev/guide/env-and-mode.html
if ( if (
@ -126,9 +128,7 @@ export async function applicationGenerator(
}); });
tasks.push(viteTask); tasks.push(viteTask);
} else if (options.bundler === 'webpack') { } else if (options.bundler === 'webpack') {
ensurePackage(host, '@nrwl/webpack', nxVersion); const { webpackInitGenerator } = ensurePackage('@nrwl/webpack', nxVersion);
const { webpackInitGenerator } = await import('@nrwl/webpack');
const webpackInitTask = await webpackInitGenerator(host, { const webpackInitTask = await webpackInitGenerator(host, {
uiFramework: 'react', uiFramework: 'react',
}); });
@ -136,8 +136,7 @@ export async function applicationGenerator(
} }
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = ensurePackage('@nrwl/vite', nxVersion);
const { vitestGenerator } = await import('@nrwl/vite');
const vitestTask = await vitestGenerator(host, { const vitestTask = await vitestGenerator(host, {
uiFramework: 'react', uiFramework: 'react',

View File

@ -7,8 +7,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) {
return () => {}; return () => {};
} }
ensurePackage(host, '@nrwl/cypress', nxVersion); const { cypressProjectGenerator } = ensurePackage('@nrwl/cypress', nxVersion);
const { cypressProjectGenerator } = await import('@nrwl/cypress');
return await cypressProjectGenerator(host, { return await cypressProjectGenerator(host, {
...options, ...options,

View File

@ -6,8 +6,7 @@ export async function addJest(
host: Tree, host: Tree,
options: NormalizedSchema options: NormalizedSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(host, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = ensurePackage('@nrwl/jest', nxVersion);
const { jestProjectGenerator } = await import('@nrwl/jest');
if (options.unitTestRunner !== 'jest') { if (options.unitTestRunner !== 'jest') {
return () => {}; return () => {};

View File

@ -10,6 +10,7 @@ import {
applyChangesToString, applyChangesToString,
addDependenciesToPackageJson, addDependenciesToPackageJson,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -19,7 +20,7 @@ export function addRouting(host: Tree, options: NormalizedSchema) {
} }
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const appPath = joinPathFragments( const appPath = joinPathFragments(
options.appProjectRoot, options.appProjectRoot,

View File

@ -12,6 +12,7 @@ import {
getComponentNode, getComponentNode,
getComponentPropsInterface, getComponentPropsInterface,
} from '../../utils/ast-utils'; } from '../../utils/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -32,7 +33,7 @@ export function componentCypressGenerator(
// TODO: candidate to refactor with the angular component story // TODO: candidate to refactor with the angular component story
export function getArgsDefaultValue(property: ts.SyntaxKind): string { export function getArgsDefaultValue(property: ts.SyntaxKind): string {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const typeNameToDefault: Record<number, any> = { const typeNameToDefault: Record<number, any> = {
[tsModule.SyntaxKind.StringKeyword]: '', [tsModule.SyntaxKind.StringKeyword]: '',
@ -55,7 +56,7 @@ export function createComponentSpecFile(
{ project, componentPath, js, cypressProject }: CreateComponentSpecFileSchema { project, componentPath, js, cypressProject }: CreateComponentSpecFileSchema
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const e2eProjectName = cypressProject || `${project}-e2e`; const e2eProjectName = cypressProject || `${project}-e2e`;
const projects = getProjects(tree); const projects = getProjects(tree);

View File

@ -13,6 +13,7 @@ import {
getComponentNode, getComponentNode,
} from '../../utils/ast-utils'; } from '../../utils/ast-utils';
import { getDefaultsForComponent } from '../../utils/component-props'; import { getDefaultsForComponent } from '../../utils/component-props';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -26,7 +27,7 @@ export function createComponentStoriesFile(
{ project, componentPath }: CreateComponentStoriesFileSchema { project, componentPath }: CreateComponentStoriesFileSchema
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const proj = getProjects(host).get(project); const proj = getProjects(host).get(project);
const sourceRoot = proj.sourceRoot; const sourceRoot = proj.sourceRoot;

View File

@ -13,6 +13,7 @@ import {
import { getDefaultsForComponent } from '../../utils/component-props'; import { getDefaultsForComponent } from '../../utils/component-props';
import { nxVersion } from '../../utils/versions'; import { nxVersion } from '../../utils/versions';
import { ComponentTestSchema } from './schema'; import { ComponentTestSchema } from './schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -20,7 +21,7 @@ export async function componentTestGenerator(
tree: Tree, tree: Tree,
options: ComponentTestSchema options: ComponentTestSchema
) { ) {
ensurePackage(tree, '@nrwl/cypress', nxVersion); ensurePackage('@nrwl/cypress', nxVersion);
const { assertMinimumCypressVersion } = await import( const { assertMinimumCypressVersion } = await import(
'@nrwl/cypress/src/utils/cypress-version' '@nrwl/cypress/src/utils/cypress-version'
); );
@ -46,7 +47,7 @@ export async function componentTestGenerator(
function generateSpecsForComponents(tree: Tree, filePath: string) { function generateSpecsForComponents(tree: Tree, filePath: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const sourceFile = tsModule.createSourceFile( const sourceFile = tsModule.createSourceFile(

View File

@ -24,6 +24,7 @@ import {
import { getComponentTests } from './get-component-tests'; import { getComponentTests } from './get-component-tests';
import { NormalizedSchema } from './noramlized-schema'; import { NormalizedSchema } from './noramlized-schema';
import { Schema } from './schema'; import { Schema } from './schema';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
export async function componentGenerator(host: Tree, schema: Schema) { export async function componentGenerator(host: Tree, schema: Schema) {
const options = await normalizeOptions(host, schema); const options = await normalizeOptions(host, schema);
@ -105,7 +106,7 @@ function createComponentFiles(host: Tree, options: NormalizedSchema) {
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
function addExportsToBarrel(host: Tree, options: NormalizedSchema) { function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const workspace = getProjects(host); const workspace = getProjects(host);
const isApp = workspace.get(options.project).projectType === 'application'; const isApp = workspace.get(options.project).projectType === 'application';

View File

@ -18,8 +18,7 @@ export async function cypressComponentConfigGenerator(
tree: Tree, tree: Tree,
options: CypressComponentConfigurationSchema options: CypressComponentConfigurationSchema
) { ) {
ensurePackage(tree, '@nrwl/cypress', nxVersion); const { cypressComponentProject } = ensurePackage('@nrwl/cypress', nxVersion);
const { cypressComponentProject } = await import('@nrwl/cypress');
const projectConfig = readProjectConfiguration(tree, options.project); const projectConfig = readProjectConfiguration(tree, options.project);
const installTask = await cypressComponentProject(tree, { const installTask = await cypressComponentProject(tree, {
project: options.project, project: options.project,

View File

@ -1,4 +1,5 @@
import { import {
addDependenciesToPackageJson,
createProjectGraphAsync, createProjectGraphAsync,
ensurePackage, ensurePackage,
generateFiles, generateFiles,
@ -15,6 +16,7 @@ import { getComponentNode } from '../../../utils/ast-utils';
import { componentTestGenerator } from '../../component-test/component-test'; import { componentTestGenerator } from '../../component-test/component-test';
import { CypressComponentConfigurationSchema } from '../schema'; import { CypressComponentConfigurationSchema } from '../schema';
import { FoundTarget } from './update-configs'; import { FoundTarget } from './update-configs';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -58,7 +60,7 @@ export async function addFiles(
options.bundler === 'webpack' || options.bundler === 'webpack' ||
(!options.bundler && actualBundler === 'webpack') (!options.bundler && actualBundler === 'webpack')
) { ) {
ensurePackage(tree, '@nrwl/webpack', nxVersion); addDependenciesToPackageJson(tree, {}, { '@nrwl/webpack': nxVersion });
} }
if (options.generateTests) { if (options.generateTests) {
@ -98,7 +100,7 @@ async function getBundler(
function isComponent(tree: Tree, filePath: string): boolean { function isComponent(tree: Tree, filePath: string): boolean {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
if (isSpecFile.test(filePath) || !allowedFileExt.test(filePath)) { if (isSpecFile.test(filePath) || !allowedFileExt.test(filePath)) {

View File

@ -14,6 +14,7 @@ import {
import { Schema } from './schema'; import { Schema } from './schema';
import { addImport } from '../../utils/ast-utils'; import { addImport } from '../../utils/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
interface NormalizedSchema extends Schema { interface NormalizedSchema extends Schema {
projectSourceRoot: string; projectSourceRoot: string;
@ -62,7 +63,7 @@ function createFiles(host: Tree, options: NormalizedSchema) {
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
function addExportsToBarrel(host: Tree, options: NormalizedSchema) { function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const workspace = getProjects(host); const workspace = getProjects(host);
const isApp = workspace.get(options.project).projectType === 'application'; const isApp = workspace.get(options.project).projectType === 'application';

View File

@ -86,22 +86,24 @@ function initRootBabelConfig(tree: Tree, schema: InitSchema) {
} }
export async function reactInitGenerator(host: Tree, schema: InitSchema) { export async function reactInitGenerator(host: Tree, schema: InitSchema) {
await jsInitGenerator(host, { const tasks: GeneratorCallback[] = [];
const jsInitTask = await jsInitGenerator(host, {
...schema, ...schema,
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json', tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
js: schema.js,
skipFormat: true, skipFormat: true,
}); });
const tasks: GeneratorCallback[] = [];
tasks.push(jsInitTask);
setDefault(host); setDefault(host);
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
ensurePackage(host, '@nrwl/cypress', nxVersion); ensurePackage('@nrwl/cypress', nxVersion);
const { cypressInitGenerator } = await import( const { cypressInitGenerator } = await import(
'@nrwl/cypress/src/generators/init/init' '@nrwl/cypress/src/generators/init/init'
); );
const cypressTask = cypressInitGenerator(host, {}); const cypressTask = await cypressInitGenerator(host, {});
tasks.push(cypressTask); tasks.push(cypressTask);
} }

View File

@ -20,8 +20,7 @@ export async function addRollupBuildTarget(
host: Tree, host: Tree,
options: NormalizedSchema options: NormalizedSchema
) { ) {
ensurePackage(host, '@nrwl/rollup', nxVersion); const { rollupInitGenerator } = ensurePackage('@nrwl/rollup', nxVersion);
const { rollupInitGenerator } = await import('@nrwl/rollup');
// These are used in `@nrwl/react/plugins/bundle-rollup` // These are used in `@nrwl/react/plugins/bundle-rollup`
addDependenciesToPackageJson( addDependenciesToPackageJson(

View File

@ -20,6 +20,7 @@ import {
reactRouterDomVersion, reactRouterDomVersion,
typesReactRouterDomVersion, typesReactRouterDomVersion,
} from '../../../utils/versions'; } from '../../../utils/versions';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -100,7 +101,7 @@ function readComponent(
throw new Error(`Cannot find ${path}`); throw new Error(`Cannot find ${path}`);
} }
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const content = host.read(path, 'utf-8'); const content = host.read(path, 'utf-8');

View File

@ -62,8 +62,10 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
// Set up build target // Set up build target
if (options.buildable && options.bundler === 'vite') { if (options.buildable && options.bundler === 'vite') {
ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = ensurePackage(
const { viteConfigurationGenerator } = await import('@nrwl/vite'); '@nrwl/vite',
nxVersion
);
const viteTask = await viteConfigurationGenerator(host, { const viteTask = await viteConfigurationGenerator(host, {
uiFramework: 'react', uiFramework: 'react',
project: options.name, project: options.name,
@ -80,8 +82,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
// Set up test target // Set up test target
if (options.unitTestRunner === 'jest') { if (options.unitTestRunner === 'jest') {
ensurePackage(host, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = ensurePackage('@nrwl/jest', nxVersion);
const { jestProjectGenerator } = await import('@nrwl/jest');
const jestTask = await jestProjectGenerator(host, { const jestTask = await jestProjectGenerator(host, {
...options, ...options,
@ -106,8 +107,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
options.unitTestRunner === 'vitest' && options.unitTestRunner === 'vitest' &&
options.bundler !== 'vite' // tests are already configured if bundler is vite options.bundler !== 'vite' // tests are already configured if bundler is vite
) { ) {
ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = ensurePackage('@nrwl/vite', nxVersion);
const { vitestGenerator } = await import('@nrwl/vite');
const vitestTask = await vitestGenerator(host, { const vitestTask = await vitestGenerator(host, {
uiFramework: 'react', uiFramework: 'react',
project: options.name, project: options.name,

View File

@ -20,6 +20,7 @@ import {
Tree, Tree,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { getRootTsConfigPathInTree } from '@nrwl/js'; import { getRootTsConfigPathInTree } from '@nrwl/js';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -65,7 +66,7 @@ function addReduxPackageDependencies(host: Tree) {
function addExportsToBarrel(host: Tree, options: NormalizedSchema) { function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const indexFilePath = path.join( const indexFilePath = path.join(
@ -116,7 +117,7 @@ function addStoreConfiguration(host: Tree, options: NormalizedSchema) {
function updateReducerConfiguration(host: Tree, options: NormalizedSchema) { function updateReducerConfiguration(host: Tree, options: NormalizedSchema) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
if (!options.appProjectSourcePath) { if (!options.appProjectSourcePath) {

View File

@ -11,6 +11,7 @@ import {
addRemoteRoute, addRemoteRoute,
addRemoteToConfig, addRemoteToConfig,
} from '../../../module-federation/ast-utils'; } from '../../../module-federation/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -20,7 +21,7 @@ export function updateHostWithRemote(
remoteName: string remoteName: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const hostConfig = readProjectConfiguration(host, hostName); const hostConfig = readProjectConfiguration(host, hostName);

View File

@ -23,6 +23,7 @@ import {
typesExpressVersion, typesExpressVersion,
} from '../../utils/versions'; } from '../../utils/versions';
import { addStaticRouter } from '../../utils/ast-utils'; import { addStaticRouter } from '../../utils/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -31,7 +32,7 @@ function readEntryFile(
path: string path: string
): { content: string; source: ts.SourceFile } { ): { content: string; source: ts.SourceFile } {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const content = host.read(path, 'utf-8'); const content = host.read(path, 'utf-8');

View File

@ -15,6 +15,7 @@ import {
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { basename, join } from 'path'; import { basename, join } from 'path';
import minimatch = require('minimatch'); import minimatch = require('minimatch');
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -57,7 +58,7 @@ export function containsComponentDeclaration(
componentPath: string componentPath: string
): boolean { ): boolean {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const contents = tree.read(componentPath, 'utf-8'); const contents = tree.read(componentPath, 'utf-8');

View File

@ -10,7 +10,7 @@ import {
import { nxVersion } from '../../utils/versions'; import { nxVersion } from '../../utils/versions';
async function generateStories(host: Tree, schema: StorybookConfigureSchema) { async function generateStories(host: Tree, schema: StorybookConfigureSchema) {
ensurePackage(host, '@nrwl/cypress', nxVersion); ensurePackage('@nrwl/cypress', nxVersion);
const { getE2eProjectName } = await import( const { getE2eProjectName } = await import(
'@nrwl/cypress/src/utils/project-name' '@nrwl/cypress/src/utils/project-name'
); );
@ -34,8 +34,10 @@ export async function storybookConfigurationGenerator(
host: Tree, host: Tree,
schema: StorybookConfigureSchema schema: StorybookConfigureSchema
) { ) {
ensurePackage(host, '@nrwl/storybook', nxVersion); const { configurationGenerator } = ensurePackage(
const { configurationGenerator } = await import('@nrwl/storybook'); '@nrwl/storybook',
nxVersion
);
let bundler = schema.bundler ?? 'webpack'; let bundler = schema.bundler ?? 'webpack';
const projectConfig = readProjectConfiguration(host, schema.name); const projectConfig = readProjectConfiguration(host, schema.name);

View File

@ -6,6 +6,7 @@ import {
findElements, findElements,
addImport, addImport,
} from '../utils/ast-utils'; } from '../utils/ast-utils';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -14,7 +15,7 @@ export function addRemoteToConfig(
app: string app: string
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const assignments = findNodes( const assignments = findNodes(

View File

@ -6,6 +6,7 @@ import {
StringChange, StringChange,
StringInsertion, StringInsertion,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -14,7 +15,7 @@ export function addImport(
statement: string statement: string
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration);
@ -42,7 +43,7 @@ export function findMainRenderStatement(
source: ts.SourceFile source: ts.SourceFile
): ts.CallExpression | null { ): ts.CallExpression | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
// 1. Try to find ReactDOM.render. // 1. Try to find ReactDOM.render.
@ -117,7 +118,7 @@ export function findDefaultExportDeclaration(
| ts.ClassDeclaration | ts.ClassDeclaration
| null { | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const identifier = findDefaultExportIdentifier(source); const identifier = findDefaultExportIdentifier(source);
if (identifier) { if (identifier) {
@ -147,7 +148,7 @@ export function findExportDeclarationsForJsx(
ts.VariableDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration ts.VariableDeclaration | ts.FunctionDeclaration | ts.ClassDeclaration
> | null { > | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const variables = findNodes(source, tsModule.SyntaxKind.VariableDeclaration); const variables = findNodes(source, tsModule.SyntaxKind.VariableDeclaration);
const variableStatements = findNodes( const variableStatements = findNodes(
@ -231,7 +232,7 @@ export function findDefaultExportIdentifier(
source: ts.SourceFile source: ts.SourceFile
): ts.Identifier | null { ): ts.Identifier | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const exports = findNodes( const exports = findNodes(
source, source,
@ -248,7 +249,7 @@ export function findDefaultClassOrFunction(
source: ts.SourceFile | null source: ts.SourceFile | null
): ts.FunctionDeclaration | ts.ClassDeclaration | null { ): ts.FunctionDeclaration | ts.ClassDeclaration | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const fns = findNodes( const fns = findNodes(
source, source,
@ -270,7 +271,7 @@ function hasDefaultExportModifier(
x: ts.ClassDeclaration | ts.FunctionDeclaration x: ts.ClassDeclaration | ts.FunctionDeclaration
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
return ( return (
x.modifiers && x.modifiers &&
@ -284,7 +285,7 @@ export function findComponentImportPath(
source: ts.SourceFile source: ts.SourceFile
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes( const allImports = findNodes(
source, source,
@ -308,7 +309,7 @@ export function findComponentImportPath(
export function findElements(source: ts.SourceFile, tagName: string) { export function findElements(source: ts.SourceFile, tagName: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const nodes = findNodes(source, [ const nodes = findNodes(source, [
tsModule.SyntaxKind.JsxSelfClosingElement, tsModule.SyntaxKind.JsxSelfClosingElement,
@ -331,7 +332,7 @@ export function findClosestOpening(tagName: string, node: ts.Node) {
export function isTag(tagName: string, node: ts.Node) { export function isTag(tagName: string, node: ts.Node) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
if (tsModule.isJsxOpeningLikeElement(node)) { if (tsModule.isJsxOpeningLikeElement(node)) {
return ( return (
@ -355,7 +356,7 @@ export function addInitialRoutes(
source: ts.SourceFile source: ts.SourceFile
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const jsxClosingElements = findNodes(source, [ const jsxClosingElements = findNodes(source, [
@ -581,7 +582,7 @@ export function updateReduxStore(
} }
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const calls = findNodes( const calls = findNodes(
source, source,
@ -651,7 +652,7 @@ export function updateReduxStore(
export function getComponentNode(sourceFile: ts.SourceFile): ts.Node | null { export function getComponentNode(sourceFile: ts.SourceFile): ts.Node | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const defaultExport = findDefaultExport(sourceFile); const defaultExport = findDefaultExport(sourceFile);
@ -674,7 +675,7 @@ export function getComponentPropsInterface(
cmpDeclaration: ts.Node cmpDeclaration: ts.Node
): ts.InterfaceDeclaration | null { ): ts.InterfaceDeclaration | null {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
let propsTypeName: string = null; let propsTypeName: string = null;

View File

@ -1,3 +1,4 @@
import { ensureTypescript } from '@nrwl/js/src/utils/typescript/ensure-typescript';
import type * as ts from 'typescript'; import type * as ts from 'typescript';
import { getComponentPropsInterface } from './ast-utils'; import { getComponentPropsInterface } from './ast-utils';
@ -6,7 +7,7 @@ let tsModule: typeof import('typescript');
// TODO: candidate to refactor with the angular component story // TODO: candidate to refactor with the angular component story
export function getArgsDefaultValue(property: ts.SyntaxKind): string { export function getArgsDefaultValue(property: ts.SyntaxKind): string {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const typeNameToDefault: Record<number, any> = { const typeNameToDefault: Record<number, any> = {
[tsModule.SyntaxKind.StringKeyword]: "''", [tsModule.SyntaxKind.StringKeyword]: "''",
@ -27,7 +28,7 @@ export function getDefaultsForComponent(
cmpDeclaration: ts.Node cmpDeclaration: ts.Node
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const propsInterface = getComponentPropsInterface(sourceFile, cmpDeclaration); const propsInterface = getComponentPropsInterface(sourceFile, cmpDeclaration);

View File

@ -44,7 +44,7 @@ export async function cypressProjectGenerator(
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
if (!projectAlreadyHasCypress(tree)) { if (!projectAlreadyHasCypress(tree)) {
tasks.push(_cypressInitGenerator(tree, {})); tasks.push(await _cypressInitGenerator(tree, {}));
} }
const installTask = await _cypressProjectGenerator(tree, { const installTask = await _cypressProjectGenerator(tree, {

View File

@ -7,6 +7,7 @@ Object {
}, },
"devDependencies": Object { "devDependencies": Object {
"@angular/forms": "*", "@angular/forms": "*",
"@nrwl/js": "0.0.1",
"@nrwl/storybook": "^6.5.15", "@nrwl/storybook": "^6.5.15",
"@storybook/addon-essentials": "^6.5.15", "@storybook/addon-essentials": "^6.5.15",
"@storybook/angular": "^6.5.15", "@storybook/angular": "^6.5.15",
@ -15,6 +16,7 @@ Object {
"@storybook/manager-webpack5": "^6.5.15", "@storybook/manager-webpack5": "^6.5.15",
"existing": "1.0.0", "existing": "1.0.0",
"html-webpack-plugin": "^5.5.0", "html-webpack-plugin": "^5.5.0",
"typescript": "~4.9.5",
"webpack": "^5.64.0", "webpack": "^5.64.0",
}, },
"name": "test-name", "name": "test-name",

View File

@ -1,6 +1,7 @@
import { import {
addDependenciesToPackageJson, addDependenciesToPackageJson,
convertNxGenerator, convertNxGenerator,
GeneratorCallback,
readJson, readJson,
readNxJson, readNxJson,
Tree, Tree,
@ -26,6 +27,7 @@ import {
webpack5Version, webpack5Version,
} from '../../utils/versions'; } from '../../utils/versions';
import { Schema } from './schema'; import { Schema } from './schema';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
function checkDependenciesInstalled(host: Tree, schema: Schema) { function checkDependenciesInstalled(host: Tree, schema: Schema) {
const packageJson = readJson(host, 'package.json'); const packageJson = readJson(host, 'package.json');
@ -212,15 +214,18 @@ function editRootTsConfig(tree: Tree) {
} }
export async function initGenerator(tree: Tree, schema: Schema) { export async function initGenerator(tree: Tree, schema: Schema) {
const tasks: GeneratorCallback[] = [];
tasks.push(
await jsInitGenerator(tree, { await jsInitGenerator(tree, {
js: schema.js, ...schema,
skipFormat: true, skipFormat: true,
}); })
const installTask = checkDependenciesInstalled(tree, schema); );
tasks.push(checkDependenciesInstalled(tree, schema));
moveToDevDependencies(tree); moveToDevDependencies(tree);
editRootTsConfig(tree); editRootTsConfig(tree);
addCacheableOperation(tree); addCacheableOperation(tree);
return installTask; return runTasksInSerial(...tasks);
} }
export default initGenerator; export default initGenerator;

View File

@ -74,8 +74,10 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
]; ];
if (options.bundler === 'webpack') { if (options.bundler === 'webpack') {
ensurePackage(tree, '@nrwl/webpack', nxVersion); const { webpackProjectGenerator } = ensurePackage(
const { webpackProjectGenerator } = require('@nrwl/webpack'); '@nrwl/webpack',
nxVersion
);
await webpackProjectGenerator(tree, { await webpackProjectGenerator(tree, {
project: options.projectName, project: options.projectName,
main, main,
@ -200,8 +202,10 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
await addProject(host, options); await addProject(host, options);
if (options.bundler === 'vite') { if (options.bundler === 'vite') {
ensurePackage(host, '@nrwl/vite', nxVersion); const { viteConfigurationGenerator } = ensurePackage(
const { viteConfigurationGenerator } = require('@nrwl/vite'); '@nrwl/vite',
nxVersion
);
// We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development. // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
// See: https://vitejs.dev/guide/env-and-mode.html // See: https://vitejs.dev/guide/env-and-mode.html
if ( if (
@ -223,8 +227,7 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
} }
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
ensurePackage(host, '@nrwl/vite', nxVersion); const { vitestGenerator } = ensurePackage('@nrwl/vite', nxVersion);
const { vitestGenerator } = require('@nrwl/vite');
const vitestTask = await vitestGenerator(host, { const vitestTask = await vitestGenerator(host, {
uiFramework: 'none', uiFramework: 'none',
project: options.projectName, project: options.projectName,

View File

@ -50,7 +50,7 @@ export async function webInitGenerator(tree: Tree, schema: Schema) {
tasks.push(jestTask); tasks.push(jestTask);
} }
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
const cypressTask = cypressInitGenerator(tree, { const cypressTask = await cypressInitGenerator(tree, {
skipPackageJson: schema.skipPackageJson, skipPackageJson: schema.skipPackageJson,
}); });
tasks.push(cypressTask); tasks.push(cypressTask);

View File

@ -70,8 +70,7 @@ export async function addLint(
tree: Tree, tree: Tree,
options: NormalizedSchema options: NormalizedSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(tree, '@nrwl/linter', nxVersion); const { lintProjectGenerator } = ensurePackage('@nrwl/linter', nxVersion);
const { lintProjectGenerator } = require('@nrwl/linter');
return lintProjectGenerator(tree, { return lintProjectGenerator(tree, {
project: options.name, project: options.name,
linter: options.linter, linter: options.linter,
@ -172,8 +171,7 @@ async function addJest(
tree: Tree, tree: Tree,
options: NormalizedSchema options: NormalizedSchema
): Promise<GeneratorCallback> { ): Promise<GeneratorCallback> {
ensurePackage(tree, '@nrwl/jest', nxVersion); const { jestProjectGenerator } = ensurePackage('@nrwl/jest', nxVersion);
const { jestProjectGenerator } = require('@nrwl/jest');
return await jestProjectGenerator(tree, { return await jestProjectGenerator(tree, {
...options, ...options,
project: options.name, project: options.name,
@ -187,14 +185,14 @@ async function addJest(
} }
function addTypescript(tree: Tree, options: NormalizedSchema) { function addTypescript(tree: Tree, options: NormalizedSchema) {
if (!options.js) {
ensurePackage(tree, 'typescript', typescriptVersion);
}
// add tsconfig.base.json // add tsconfig.base.json
if (!options.skipTsConfig && !getRootTsConfigFileName()) { if (!options.skipTsConfig && !getRootTsConfigFileName()) {
generateFiles(tree, joinPathFragments(__dirname, './files/root'), '.', {}); generateFiles(tree, joinPathFragments(__dirname, './files/root'), '.', {});
} }
return !options.js
? addDependenciesToPackageJson(tree, {}, { typescript: typescriptVersion })
: () => {};
} }
export async function libraryGenerator(tree: Tree, schema: Schema) { export async function libraryGenerator(tree: Tree, schema: Schema) {

View File

@ -18,6 +18,7 @@ import { findNodes } from 'nx/src/utils/typescript';
import { NormalizedSchema } from '../schema'; import { NormalizedSchema } from '../schema';
import { normalizeSlashes } from './utils'; import { normalizeSlashes } from './utils';
import { relative } from 'path'; import { relative } from 'path';
import { ensureTypescript } from '../../../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -121,7 +122,7 @@ export function updateImports(
*/ */
function updateImportPaths(tree: Tree, path: string, from: string, to: string) { function updateImportPaths(tree: Tree, path: string, from: string, to: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const contents = tree.read(path, 'utf-8'); const contents = tree.read(path, 'utf-8');
const sourceFile = tsModule.createSourceFile( const sourceFile = tsModule.createSourceFile(
@ -149,7 +150,7 @@ function updateImportDeclarations(
to: string to: string
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const importDecls = findNodes( const importDecls = findNodes(
sourceFile, sourceFile,
@ -176,7 +177,7 @@ function updateDynamicImports(
to: string to: string
): StringChange[] { ): StringChange[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const expressions = findNodes( const expressions = findNodes(
sourceFile, sourceFile,

View File

@ -13,6 +13,7 @@ import type {
StringLiteral, StringLiteral,
} from 'typescript'; } from 'typescript';
import { join } from 'path'; import { join } from 'path';
import { ensureTypescript } from '../../../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -29,7 +30,7 @@ export function updateJestConfig(
projectConfig: ProjectConfiguration projectConfig: ProjectConfiguration
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const { const {
createSourceFile, createSourceFile,

View File

@ -1,6 +1,7 @@
import { insertStatement } from './insert-statement'; import { insertStatement } from './insert-statement';
import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit';
import type { NamedImports } from 'typescript'; import type { NamedImports } from 'typescript';
import { ensureTypescript } from '../../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -11,7 +12,7 @@ export function insertImport(
modulePath: string modulePath: string
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const { const {
createSourceFile, createSourceFile,

View File

@ -1,4 +1,5 @@
import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit'; import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit';
import { ensureTypescript } from '../../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -7,7 +8,7 @@ let tsModule: typeof import('typescript');
*/ */
export function insertStatement(tree: Tree, path: string, statement: string) { export function insertStatement(tree: Tree, path: string, statement: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const { createSourceFile, isImportDeclaration, ScriptTarget } = tsModule; const { createSourceFile, isImportDeclaration, ScriptTarget } = tsModule;

View File

@ -1,6 +1,6 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import type * as ts from 'typescript'; import type * as ts from 'typescript';
import { getSourceNodes } from './typescript'; import { ensureTypescript, getSourceNodes } from './typescript';
import { findNodes } from 'nx/src/utils/typescript'; import { findNodes } from 'nx/src/utils/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -89,7 +89,7 @@ export function insertImport(
isDefault = false isDefault = false
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const rootNode = source; const rootNode = source;
const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration);
@ -216,7 +216,7 @@ export function addGlobal(
statement: string statement: string
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration);
if (allImports.length > 0) { if (allImports.length > 0) {
@ -238,7 +238,7 @@ export function getImport(
predicate: (a: any) => boolean predicate: (a: any) => boolean
): { moduleSpec: string; bindings: string[] }[] { ): { moduleSpec: string; bindings: string[] }[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration);
const matching = allImports.filter((i: ts.ImportDeclaration) => const matching = allImports.filter((i: ts.ImportDeclaration) =>
@ -283,7 +283,7 @@ export function addParameterToConstructor(
opts: { className: string; param: string } opts: { className: string; param: string }
): ts.SourceFile { ): ts.SourceFile {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const clazz = findClass(source, opts.className); const clazz = findClass(source, opts.className);
const constructor = clazz.members.filter( const constructor = clazz.members.filter(
@ -326,7 +326,7 @@ export function findClass(
silent: boolean = false silent: boolean = false
): ts.ClassDeclaration { ): ts.ClassDeclaration {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const nodes = getSourceNodes(source); const nodes = getSourceNodes(source);

View File

@ -12,6 +12,7 @@ import type * as ts from 'typescript';
import { unlinkSync } from 'fs'; import { unlinkSync } from 'fs';
import { output } from './output'; import { output } from './output';
import { isNpmProject } from 'nx/src/project-graph/operators'; import { isNpmProject } from 'nx/src/project-graph/operators';
import { ensureTypescript } from './typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -194,7 +195,7 @@ export function computeCompilerOptionsPaths(
function readPaths(tsConfig: string | ts.ParsedCommandLine) { function readPaths(tsConfig: string | ts.ParsedCommandLine) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
try { try {
let config: ts.ParsedCommandLine; let config: ts.ParsedCommandLine;

View File

@ -1,12 +1,13 @@
import { offsetFromRoot, Tree, workspaceRoot } from '@nrwl/devkit'; import { offsetFromRoot, Tree, workspaceRoot } from '@nrwl/devkit';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { ensureTypescript } from './typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
export function readTsConfig(tsConfigPath: string) { export function readTsConfig(tsConfigPath: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const readResult = tsModule.readConfigFile( const readResult = tsModule.readConfigFile(
tsConfigPath, tsConfigPath,

View File

@ -1,6 +1,7 @@
import { workspaceRoot } from '@nrwl/devkit'; import { ensurePackage, workspaceRoot } from '@nrwl/devkit';
import { dirname } from 'path'; import { dirname } from 'path';
import type * as ts from 'typescript'; import type * as ts from 'typescript';
import { typescriptVersion } from '../utils/versions';
export { compileTypeScript } from './typescript/compilation'; export { compileTypeScript } from './typescript/compilation';
export type { TypeScriptCompilationOptions } from './typescript/compilation'; export type { TypeScriptCompilationOptions } from './typescript/compilation';
export { findNodes } from './typescript/find-nodes'; // TODO(v16): remove this export { findNodes } from './typescript/find-nodes'; // TODO(v16): remove this
@ -12,7 +13,7 @@ let tsModule: typeof import('typescript');
function readTsConfigOptions(tsConfigPath: string) { function readTsConfigOptions(tsConfigPath: string) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const readResult = tsModule.readConfigFile( const readResult = tsModule.readConfigFile(
@ -79,3 +80,10 @@ function getCompilerHost(tsConfigPath: string) {
); );
return { options, host, moduleResolutionCache }; return { options, host, moduleResolutionCache };
} }
export function ensureTypescript() {
return ensurePackage<typeof import('typescript')>(
'typescript',
typescriptVersion
);
}

View File

@ -3,6 +3,7 @@ import { rmSync } from 'fs';
import type * as ts from 'typescript'; import type * as ts from 'typescript';
import type { CustomTransformers, Diagnostic, Program } from 'typescript'; import type { CustomTransformers, Diagnostic, Program } from 'typescript';
import { readTsConfig } from '../ts-config'; import { readTsConfig } from '../ts-config';
import { ensureTypescript } from '../typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -47,7 +48,7 @@ export function compileTypeScriptWatcher(
) => void | Promise<void> ) => void | Promise<void>
) { ) {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const normalizedOptions = normalizeOptions(options); const normalizedOptions = normalizeOptions(options);
const tsConfig = getNormalizedTsConfig(normalizedOptions); const tsConfig = getNormalizedTsConfig(normalizedOptions);
@ -159,7 +160,7 @@ function createProgram(
{ projectName, getCustomTransformers }: TypeScriptCompilationOptions { projectName, getCustomTransformers }: TypeScriptCompilationOptions
): { success: boolean } { ): { success: boolean } {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const host = tsModule.createCompilerHost(tsconfig.options); const host = tsModule.createCompilerHost(tsconfig.options);
const program = tsModule.createProgram({ const program = tsModule.createProgram({

View File

@ -20,6 +20,7 @@ import type { NxJsonConfiguration } from '@nrwl/devkit';
import { addInstallTask } from './rules/add-install-task'; import { addInstallTask } from './rules/add-install-task';
import { findNodes } from 'nx/src/utils/typescript'; import { findNodes } from 'nx/src/utils/typescript';
import { getSourceNodes } from '../utilities/typescript/get-source-nodes'; import { getSourceNodes } from '../utilities/typescript/get-source-nodes';
import { ensureTypescript } from '../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
@ -174,7 +175,7 @@ export function addParameterToConstructor(
opts: { className: string; param: string } opts: { className: string; param: string }
): Change[] { ): Change[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const clazz = findClass(source, opts.className); const clazz = findClass(source, opts.className);
const constructor = clazz.members.filter( const constructor = clazz.members.filter(
@ -217,7 +218,7 @@ export function findClass(
silent: boolean = false silent: boolean = false
): ts.ClassDeclaration { ): ts.ClassDeclaration {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const nodes = getSourceNodes(source); const nodes = getSourceNodes(source);
@ -275,7 +276,7 @@ export function getImport(
predicate: (a: any) => boolean predicate: (a: any) => boolean
): { moduleSpec: string; bindings: string[] }[] { ): { moduleSpec: string; bindings: string[] }[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration);
const matching = allImports.filter((i: ts.ImportDeclaration) => const matching = allImports.filter((i: ts.ImportDeclaration) =>
@ -302,7 +303,7 @@ export function addGlobal(
statement: string statement: string
): Change[] { ): Change[] {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(source, tsModule.SyntaxKind.ImportDeclaration);
if (allImports.length > 0) { if (allImports.length > 0) {
@ -581,7 +582,7 @@ export function insertImport(
isDefault = false isDefault = false
): Change { ): Change {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const rootNode = source; const rootNode = source;
const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration); const allImports = findNodes(rootNode, tsModule.SyntaxKind.ImportDeclaration);

View File

@ -8,12 +8,13 @@ import {
} from '@angular-devkit/schematics'; } from '@angular-devkit/schematics';
import { normalize } from '@angular-devkit/core'; import { normalize } from '@angular-devkit/core';
import { updateJsonInTree } from '../ast-utils'; import { updateJsonInTree } from '../ast-utils';
import { ensureTypescript } from '../../utilities/typescript';
let tsModule: typeof import('typescript'); let tsModule: typeof import('typescript');
export function toJS(): Rule { export function toJS(): Rule {
if (!tsModule) { if (!tsModule) {
tsModule = require('typescript'); tsModule = ensureTypescript();
} }
const { transpile, JsxEmit, ScriptTarget } = tsModule; const { transpile, JsxEmit, ScriptTarget } = tsModule;