feat: add --js and --pascalCaseFiles flags to core,node,express schematics (#3683)
This commit is contained in:
parent
a1615e8346
commit
842455bbd7
@ -21,6 +21,7 @@ module.exports = {
|
|||||||
{ name: 'nextjs', description: 'anything Next specific' },
|
{ name: 'nextjs', description: 'anything Next specific' },
|
||||||
{ name: 'nest', description: 'anything Nest specific' },
|
{ name: 'nest', description: 'anything Nest specific' },
|
||||||
{ name: 'node', description: 'anything Node specific' },
|
{ name: 'node', description: 'anything Node specific' },
|
||||||
|
{ name: 'express', description: 'anything Express specific' },
|
||||||
{ name: 'nx-plugin', description: 'anything Nx Plugin specific' },
|
{ name: 'nx-plugin', description: 'anything Nx Plugin specific' },
|
||||||
{ name: 'react', description: 'anything React specific' },
|
{ name: 'react', description: 'anything React specific' },
|
||||||
{ name: 'web', description: 'anything Web specific' },
|
{ name: 'web', description: 'anything Web specific' },
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -66,6 +66,14 @@ Type: `string`
|
|||||||
|
|
||||||
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -82,6 +90,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|||||||
@ -80,6 +80,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -66,6 +66,14 @@ Type: `string`
|
|||||||
|
|
||||||
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -82,6 +90,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|||||||
@ -80,6 +80,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -48,6 +48,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -64,6 +72,16 @@ Type: `string`
|
|||||||
|
|
||||||
The name of the application.
|
The name of the application.
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -66,6 +66,14 @@ Type: `string`
|
|||||||
|
|
||||||
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name.
|
||||||
|
|
||||||
|
### js
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Generate JavaScript files rather than TypeScript files.
|
||||||
|
|
||||||
### linter
|
### linter
|
||||||
|
|
||||||
Default: `eslint`
|
Default: `eslint`
|
||||||
@ -82,6 +90,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|||||||
@ -80,6 +80,16 @@ Type: `string`
|
|||||||
|
|
||||||
Library name
|
Library name
|
||||||
|
|
||||||
|
### pascalCaseFiles
|
||||||
|
|
||||||
|
Alias(es): P
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Use pascal case file names.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|||||||
@ -60,9 +60,7 @@ forEachCli('nx', () => {
|
|||||||
expect(workspaceJson).not.toContain('libs/');
|
expect(workspaceJson).not.toContain('libs/');
|
||||||
|
|
||||||
const libTestResults = await runCLIAsync(`test ${expressLib}`);
|
const libTestResults = await runCLIAsync(`test ${expressLib}`);
|
||||||
expect(libTestResults.stdout).toContain(
|
expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`);
|
||||||
'No tests found, exiting with code 0'
|
|
||||||
);
|
|
||||||
|
|
||||||
const appBuildResults = await runCLIAsync(`build ${expressApp}`);
|
const appBuildResults = await runCLIAsync(`build ${expressApp}`);
|
||||||
expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`);
|
expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`);
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
|||||||
import { runSchematic } from '../../utils/testing';
|
import { runSchematic } from '../../utils/testing';
|
||||||
import { readJsonInTree } from '@nrwl/workspace';
|
import { readJsonInTree } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
import { Schema } from './schema.d';
|
||||||
|
|
||||||
describe('app', () => {
|
describe('app', () => {
|
||||||
let appTree: Tree;
|
let appTree: Tree;
|
||||||
|
|
||||||
@ -12,26 +14,88 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should generate files', async () => {
|
it('should generate files', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
const tree = await runSchematic(
|
||||||
expect(tree.readContent('apps/my-node-app/src/main.ts')).toContain(
|
'app',
|
||||||
`import * as express from 'express';`
|
{ name: 'myNodeApp' } as Schema,
|
||||||
|
appTree
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mainFile = tree.readContent('apps/my-node-app/src/main.ts');
|
||||||
|
expect(mainFile).toContain(`import * as express from 'express';`);
|
||||||
|
|
||||||
|
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
||||||
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"files": Array [],
|
||||||
|
"include": Array [],
|
||||||
|
"references": Array [
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add types to the tsconfig.app.json', async () => {
|
it('should add types to the tsconfig.app.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
const tree = await runSchematic(
|
||||||
|
'app',
|
||||||
|
{ name: 'myNodeApp' } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.app.json');
|
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.app.json');
|
||||||
expect(tsconfig.compilerOptions.types).toContain('express');
|
expect(tsconfig.compilerOptions.types).toContain('express');
|
||||||
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"compilerOptions": Object {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"types": Array [
|
||||||
|
"node",
|
||||||
|
"express",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": Array [
|
||||||
|
"**/*.spec.ts",
|
||||||
|
],
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": Array [
|
||||||
|
"**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update tsconfig', async () => {
|
describe('--js flag', () => {
|
||||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
it('should generate js files instead of ts files', async () => {
|
||||||
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
const tree = await runSchematic(
|
||||||
expect(tsconfig.references).toContainEqual({
|
'app',
|
||||||
path: './tsconfig.app.json',
|
{
|
||||||
});
|
name: 'myNodeApp',
|
||||||
expect(tsconfig.references).toContainEqual({
|
js: true,
|
||||||
path: './tsconfig.spec.json',
|
} as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tree.exists('apps/my-node-app/src/main.js')).toBeTruthy();
|
||||||
|
expect(tree.readContent('apps/my-node-app/src/main.js')).toContain(
|
||||||
|
`import * as express from 'express';`
|
||||||
|
);
|
||||||
|
|
||||||
|
const tsConfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
||||||
|
expect(tsConfig.compilerOptions).toEqual({
|
||||||
|
allowJs: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tsConfigApp = readJsonInTree(
|
||||||
|
tree,
|
||||||
|
'apps/my-node-app/tsconfig.app.json'
|
||||||
|
);
|
||||||
|
expect(tsConfigApp.include).toEqual(['**/*.ts', '**/*.js']);
|
||||||
|
expect(tsConfigApp.exclude).toEqual(['**/*.spec.ts', '**/*.spec.js']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { updateJsonInTree } from '@nrwl/workspace';
|
|||||||
import { toFileName, formatFiles } from '@nrwl/workspace';
|
import { toFileName, formatFiles } from '@nrwl/workspace';
|
||||||
import init from '../init/init';
|
import init from '../init/init';
|
||||||
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
|
import { maybeJs } from '@nrwl/workspace/src/utils/rules/to-js';
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: Path;
|
appProjectRoot: Path;
|
||||||
@ -24,10 +25,10 @@ function addTypes(options: NormalizedSchema): Rule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMainFile(options: NormalizedSchema): Rule {
|
function addAppFiles(options: NormalizedSchema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
host.overwrite(
|
host.overwrite(
|
||||||
join(options.appProjectRoot, 'src/main.ts'),
|
maybeJs(options, join(options.appProjectRoot, 'src/main.ts')),
|
||||||
`/**
|
`/**
|
||||||
* This is not a production server yet!
|
* This is not a production server yet!
|
||||||
* This is only a minimal backend to get started.
|
* This is only a minimal backend to get started.
|
||||||
@ -57,7 +58,7 @@ export default function (schema: Schema): Rule {
|
|||||||
return chain([
|
return chain([
|
||||||
init({ ...options, skipFormat: true }),
|
init({ ...options, skipFormat: true }),
|
||||||
externalSchematic('@nrwl/node', 'application', schema),
|
externalSchematic('@nrwl/node', 'application', schema),
|
||||||
addMainFile(options),
|
addAppFiles(options),
|
||||||
addTypes(options),
|
addTypes(options),
|
||||||
formatFiles(options),
|
formatFiles(options),
|
||||||
])(host, context);
|
])(host, context);
|
||||||
|
|||||||
@ -11,4 +11,6 @@ export interface Schema {
|
|||||||
linter: Linter;
|
linter: Linter;
|
||||||
frontendProject?: string;
|
frontendProject?: string;
|
||||||
babelJest?: boolean;
|
babelJest?: boolean;
|
||||||
|
js: boolean;
|
||||||
|
pascalCaseFiles: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,17 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Use babel instead ts-jest",
|
"description": "Use babel instead ts-jest",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"pascalCaseFiles": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use pascal case file names.",
|
||||||
|
"alias": "P",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export default function updatePackageJson(
|
|||||||
options: NormalizedBuilderOptions,
|
options: NormalizedBuilderOptions,
|
||||||
context: BuilderContext
|
context: BuilderContext
|
||||||
) {
|
) {
|
||||||
const mainFile = basename(options.main, '.ts');
|
const mainFile = basename(options.main).replace(/\.[tj]s$/, '');
|
||||||
const typingsFile = `${mainFile}.d.ts`;
|
const typingsFile = `${mainFile}.d.ts`;
|
||||||
const mainJsFile = `${mainFile}.js`;
|
const mainJsFile = `${mainFile}.js`;
|
||||||
const packageJson = readJsonFile(
|
const packageJson = readJsonFile(
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
import * as stripJsonComments from 'strip-json-comments';
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
import { createEmptyWorkspace, getFileContent } from '@nrwl/workspace/testing';
|
|
||||||
import { runSchematic } from '../../utils/testing';
|
import { runSchematic } from '../../utils/testing';
|
||||||
import { NxJson, readJsonInTree } from '@nrwl/workspace';
|
import { NxJson, readJsonInTree } from '@nrwl/workspace';
|
||||||
// to break the dependency
|
// to break the dependency
|
||||||
@ -24,7 +23,7 @@ describe('app', () => {
|
|||||||
const project = workspaceJson.projects['my-node-app'];
|
const project = workspaceJson.projects['my-node-app'];
|
||||||
expect(project.root).toEqual('apps/my-node-app');
|
expect(project.root).toEqual('apps/my-node-app');
|
||||||
expect(project.architect).toEqual(
|
expect(project.architect).toEqual(
|
||||||
jasmine.objectContaining({
|
expect.objectContaining({
|
||||||
build: {
|
build: {
|
||||||
builder: '@nrwl/node:build',
|
builder: '@nrwl/node:build',
|
||||||
options: {
|
options: {
|
||||||
@ -85,37 +84,31 @@ describe('app', () => {
|
|||||||
expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy();
|
expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-node-app/src/main.ts')).toBeTruthy();
|
expect(tree.exists('apps/my-node-app/src/main.ts')).toBeTruthy();
|
||||||
|
|
||||||
expect(tree.readContent('apps/my-node-app/tsconfig.json'))
|
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
||||||
.toMatchInlineSnapshot(`
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
"{
|
Object {
|
||||||
\\"extends\\": \\"../../tsconfig.base.json\\",
|
"extends": "../../tsconfig.base.json",
|
||||||
\\"files\\": [],
|
"files": Array [],
|
||||||
\\"include\\": [],
|
"include": Array [],
|
||||||
\\"references\\": [
|
"references": Array [
|
||||||
{
|
Object {
|
||||||
\\"path\\": \\"./tsconfig.app.json\\"
|
"path": "./tsconfig.app.json",
|
||||||
},
|
},
|
||||||
{
|
Object {
|
||||||
\\"path\\": \\"./tsconfig.spec.json\\"
|
"path": "./tsconfig.spec.json",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
"
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const tsconfigApp = JSON.parse(
|
const tsconfigApp = readJsonInTree(
|
||||||
stripJsonComments(
|
tree,
|
||||||
getFileContent(tree, 'apps/my-node-app/tsconfig.app.json')
|
'apps/my-node-app/tsconfig.app.json'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||||
|
|
||||||
const eslintrc = JSON.parse(
|
const eslintrc = readJsonInTree(tree, 'apps/my-node-app/.eslintrc.json');
|
||||||
stripJsonComments(
|
|
||||||
getFileContent(tree, 'apps/my-node-app/.eslintrc.json')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
expect(eslintrc.extends).toEqual('../../.eslintrc.json');
|
expect(eslintrc.extends).toEqual('../../.eslintrc.json');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -162,8 +155,7 @@ describe('app', () => {
|
|||||||
|
|
||||||
it('should generate files', async () => {
|
it('should generate files', async () => {
|
||||||
const hasJsonValue = ({ path, expectedValue, lookupFn }) => {
|
const hasJsonValue = ({ path, expectedValue, lookupFn }) => {
|
||||||
const content = getFileContent(tree, path);
|
const config = readJsonInTree(tree, path);
|
||||||
const config = JSON.parse(stripJsonComments(content));
|
|
||||||
|
|
||||||
expect(lookupFn(config)).toEqual(expectedValue);
|
expect(lookupFn(config)).toEqual(expectedValue);
|
||||||
};
|
};
|
||||||
@ -243,7 +235,7 @@ describe('app', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = JSON.parse(tree.readContent('workspace.json')).projects[
|
const serve = readJsonInTree(tree, 'workspace.json').projects[
|
||||||
'my-frontend'
|
'my-frontend'
|
||||||
].architect.serve;
|
].architect.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual(
|
||||||
@ -261,7 +253,7 @@ describe('app', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = JSON.parse(tree.readContent('workspace.json')).projects[
|
const serve = readJsonInTree(tree, 'workspace.json').projects[
|
||||||
'my-frontend'
|
'my-frontend'
|
||||||
].architect.serve;
|
].architect.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual(
|
||||||
@ -313,4 +305,75 @@ describe('app', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('--js flag', () => {
|
||||||
|
it('should generate js files instead of ts files', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'app',
|
||||||
|
{
|
||||||
|
name: 'myNodeApp',
|
||||||
|
js: true,
|
||||||
|
} as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tree.exists(`apps/my-node-app/jest.config.js`)).toBeTruthy();
|
||||||
|
expect(tree.exists('apps/my-node-app/src/main.js')).toBeTruthy();
|
||||||
|
|
||||||
|
const tsConfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
||||||
|
expect(tsConfig.compilerOptions).toEqual({
|
||||||
|
allowJs: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tsConfigApp = readJsonInTree(
|
||||||
|
tree,
|
||||||
|
'apps/my-node-app/tsconfig.app.json'
|
||||||
|
);
|
||||||
|
expect(tsConfigApp.include).toEqual(['**/*.ts', '**/*.js']);
|
||||||
|
expect(tsConfigApp.exclude).toEqual(['**/*.spec.ts', '**/*.spec.js']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update workspace.json', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'app',
|
||||||
|
{ name: 'myNodeApp', js: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
const project = workspaceJson.projects['my-node-app'];
|
||||||
|
const buildTarget = project.architect.build;
|
||||||
|
|
||||||
|
expect(buildTarget.options.main).toEqual('apps/my-node-app/src/main.js');
|
||||||
|
expect(buildTarget.configurations.production.fileReplacements).toEqual([
|
||||||
|
{
|
||||||
|
replace: 'apps/my-node-app/src/environments/environment.js',
|
||||||
|
with: 'apps/my-node-app/src/environments/environment.prod.js',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate js files for nested libs as well', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'app',
|
||||||
|
{ name: 'myNodeApp', directory: 'myDir', js: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
tree.exists(`apps/my-dir/my-node-app/jest.config.js`)
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(tree.exists('apps/my-dir/my-node-app/src/main.js')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--pascalCaseFiles', () => {
|
||||||
|
it(`should notify that this flag doesn't do anything`, async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'app',
|
||||||
|
{ name: 'myNodeApp', pascalCaseFiles: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
|
||||||
|
// @TODO how to spy on context ?
|
||||||
|
// expect(contextLoggerSpy).toHaveBeenCalledWith('NOTE: --pascalCaseFiles is a noop')
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,6 +25,11 @@ import { getProjectConfig } from '@nrwl/workspace';
|
|||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
import { offsetFromRoot } from '@nrwl/workspace';
|
||||||
import init from '../init/init';
|
import init from '../init/init';
|
||||||
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
|
import {
|
||||||
|
toJS,
|
||||||
|
updateTsConfigsToJs,
|
||||||
|
maybeJs,
|
||||||
|
} from '@nrwl/workspace/src/utils/rules/to-js';
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: Path;
|
appProjectRoot: Path;
|
||||||
@ -48,7 +53,7 @@ function getBuildConfig(project: any, options: NormalizedSchema) {
|
|||||||
builder: '@nrwl/node:build',
|
builder: '@nrwl/node:build',
|
||||||
options: {
|
options: {
|
||||||
outputPath: join(normalize('dist'), options.appProjectRoot),
|
outputPath: join(normalize('dist'), options.appProjectRoot),
|
||||||
main: join(project.sourceRoot, 'main.ts'),
|
main: maybeJs(options, join(project.sourceRoot, 'main.ts')),
|
||||||
tsConfig: join(options.appProjectRoot, 'tsconfig.app.json'),
|
tsConfig: join(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
assets: [join(project.sourceRoot, 'assets')],
|
assets: [join(project.sourceRoot, 'assets')],
|
||||||
},
|
},
|
||||||
@ -59,8 +64,14 @@ function getBuildConfig(project: any, options: NormalizedSchema) {
|
|||||||
inspect: false,
|
inspect: false,
|
||||||
fileReplacements: [
|
fileReplacements: [
|
||||||
{
|
{
|
||||||
replace: join(project.sourceRoot, 'environments/environment.ts'),
|
replace: maybeJs(
|
||||||
with: join(project.sourceRoot, 'environments/environment.prod.ts'),
|
options,
|
||||||
|
join(project.sourceRoot, 'environments/environment.ts')
|
||||||
|
),
|
||||||
|
with: maybeJs(
|
||||||
|
options,
|
||||||
|
join(project.sourceRoot, 'environments/environment.prod.ts')
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -106,17 +117,26 @@ function updateWorkspaceJson(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addAppFiles(options: NormalizedSchema): Rule {
|
function addAppFiles(options: NormalizedSchema): Rule {
|
||||||
return mergeWith(
|
return chain([
|
||||||
apply(url(`./files/app`), [
|
mergeWith(
|
||||||
template({
|
apply(url(`./files/app`), [
|
||||||
tmpl: '',
|
template({
|
||||||
name: options.name,
|
tmpl: '',
|
||||||
root: options.appProjectRoot,
|
name: options.name,
|
||||||
offset: offsetFromRoot(options.appProjectRoot),
|
root: options.appProjectRoot,
|
||||||
}),
|
offset: offsetFromRoot(options.appProjectRoot),
|
||||||
move(options.appProjectRoot),
|
}),
|
||||||
])
|
move(options.appProjectRoot),
|
||||||
);
|
options.js ? toJS() : noop(),
|
||||||
|
])
|
||||||
|
),
|
||||||
|
options.pascalCaseFiles
|
||||||
|
? (tree, context) => {
|
||||||
|
context.logger.warn('NOTE: --pascalCaseFiles is a noop');
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
: noop(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addProxy(options: NormalizedSchema): Rule {
|
function addProxy(options: NormalizedSchema): Rule {
|
||||||
@ -147,6 +167,18 @@ function addProxy(options: NormalizedSchema): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addJest(options: NormalizedSchema) {
|
||||||
|
return options.unitTestRunner === 'jest'
|
||||||
|
? externalSchematic('@nrwl/jest', 'jest-project', {
|
||||||
|
project: options.name,
|
||||||
|
setupFile: 'none',
|
||||||
|
skipSerializers: true,
|
||||||
|
supportTsx: options.js,
|
||||||
|
babelJest: options.babelJest,
|
||||||
|
})
|
||||||
|
: noop();
|
||||||
|
}
|
||||||
|
|
||||||
export default function (schema: Schema): Rule {
|
export default function (schema: Schema): Rule {
|
||||||
return (host: Tree, context: SchematicContext) => {
|
return (host: Tree, context: SchematicContext) => {
|
||||||
const options = normalizeOptions(host, schema);
|
const options = normalizeOptions(host, schema);
|
||||||
@ -157,16 +189,12 @@ export default function (schema: Schema): Rule {
|
|||||||
}),
|
}),
|
||||||
addLintFiles(options.appProjectRoot, options.linter),
|
addLintFiles(options.appProjectRoot, options.linter),
|
||||||
addAppFiles(options),
|
addAppFiles(options),
|
||||||
|
options.js
|
||||||
|
? updateTsConfigsToJs({ projectRoot: options.appProjectRoot })
|
||||||
|
: noop,
|
||||||
updateWorkspaceJson(options),
|
updateWorkspaceJson(options),
|
||||||
updateNxJson(options),
|
updateNxJson(options),
|
||||||
options.unitTestRunner === 'jest'
|
addJest(options),
|
||||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
|
||||||
project: options.name,
|
|
||||||
setupFile: 'none',
|
|
||||||
skipSerializers: true,
|
|
||||||
babelJest: options.babelJest,
|
|
||||||
})
|
|
||||||
: noop(),
|
|
||||||
options.frontendProject ? addProxy(options) : noop(),
|
options.frontendProject ? addProxy(options) : noop(),
|
||||||
formatFiles(options),
|
formatFiles(options),
|
||||||
])(host, context);
|
])(host, context);
|
||||||
|
|||||||
@ -10,4 +10,6 @@ export interface Schema {
|
|||||||
tags?: string;
|
tags?: string;
|
||||||
frontendProject?: string;
|
frontendProject?: string;
|
||||||
babelJest?: boolean;
|
babelJest?: boolean;
|
||||||
|
js: boolean;
|
||||||
|
pascalCaseFiles: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,17 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Use babel instead ts-jest",
|
"description": "Use babel instead ts-jest",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"pascalCaseFiles": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use pascal case file names.",
|
||||||
|
"alias": "P",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -71,15 +71,21 @@ describe('lib', () => {
|
|||||||
it('should create a local tsconfig.json', async () => {
|
it('should create a local tsconfig.json', async () => {
|
||||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||||
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
||||||
expect(tsconfigJson.extends).toEqual('../../tsconfig.base.json');
|
expect(tsconfigJson).toMatchInlineSnapshot(`
|
||||||
expect(tsconfigJson.references).toEqual([
|
Object {
|
||||||
{
|
"extends": "../../tsconfig.base.json",
|
||||||
path: './tsconfig.lib.json',
|
"files": Array [],
|
||||||
},
|
"include": Array [],
|
||||||
{
|
"references": Array [
|
||||||
path: './tsconfig.spec.json',
|
Object {
|
||||||
},
|
"path": "./tsconfig.lib.json",
|
||||||
]);
|
},
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
|
it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
|
||||||
@ -280,7 +286,21 @@ describe('lib', () => {
|
|||||||
|
|
||||||
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||||
|
|
||||||
expect(workspaceJson.projects['my-lib'].architect.build).toBeDefined();
|
expect(workspaceJson.projects['my-lib'].architect.build)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"builder": "@nrwl/node:package",
|
||||||
|
"options": Object {
|
||||||
|
"assets": Array [
|
||||||
|
"libs/my-lib/*.md",
|
||||||
|
],
|
||||||
|
"main": "libs/my-lib/src/index.ts",
|
||||||
|
"outputPath": "dist/libs/my-lib",
|
||||||
|
"packageJson": "libs/my-lib/package.json",
|
||||||
|
"tsConfig": "libs/my-lib/tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -413,4 +433,102 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('--js flag', () => {
|
||||||
|
it('should generate js files instead of ts files', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{
|
||||||
|
name: 'myLib',
|
||||||
|
js: true,
|
||||||
|
} as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/index.js')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.js')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJsonInTree(tree, 'libs/my-lib/tsconfig.json').compilerOptions
|
||||||
|
).toEqual({
|
||||||
|
allowJs: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
readJsonInTree(tree, 'libs/my-lib/tsconfig.lib.json').include
|
||||||
|
).toEqual(['**/*.ts', '**/*.js']);
|
||||||
|
expect(
|
||||||
|
readJsonInTree(tree, 'libs/my-lib/tsconfig.lib.json').exclude
|
||||||
|
).toEqual(['**/*.spec.ts', '**/*.spec.js']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update root tsconfig.json with a js file path', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', js: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const tsconfigJson = readJsonInTree(tree, '/tsconfig.base.json');
|
||||||
|
expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([
|
||||||
|
'libs/my-lib/src/index.js',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update architect builder when --buildable', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', buildable: true, js: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
|
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
workspaceJson.projects['my-lib'].architect.build.options.main
|
||||||
|
).toEqual('libs/my-lib/src/index.js');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate js files for nested libs as well', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', directory: 'myDir', js: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(tree.exists(`libs/my-dir/my-lib/jest.config.js`)).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-dir/my-lib/src/index.js')).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.js')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.spec.js')
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--pascalCaseFiles', () => {
|
||||||
|
it('should generate files with upper case names', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', pascalCaseFiles: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/MyLib.ts')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/MyLib.spec.ts')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate files with upper case names for nested libs as well', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', directory: 'myDir', pascalCaseFiles: true } as Schema,
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/MyDirMyLib.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/MyDirMyLib.spec.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,6 +25,11 @@ import {
|
|||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { libsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
import { libsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
|
import {
|
||||||
|
toJS,
|
||||||
|
updateTsConfigsToJs,
|
||||||
|
maybeJs,
|
||||||
|
} from '@nrwl/workspace/src/utils/rules/to-js';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -51,6 +56,7 @@ export default function (schema: NormalizedSchema): Rule {
|
|||||||
importPath: options.importPath,
|
importPath: options.importPath,
|
||||||
}),
|
}),
|
||||||
createFiles(options),
|
createFiles(options),
|
||||||
|
options.js ? updateTsConfigsToJs(options) : noop(),
|
||||||
addProject(options),
|
addProject(options),
|
||||||
formatFiles(options),
|
formatFiles(options),
|
||||||
]);
|
]);
|
||||||
@ -103,6 +109,7 @@ function createFiles(options: NormalizedSchema): Rule {
|
|||||||
options.publishable || options.buildable
|
options.publishable || options.buildable
|
||||||
? noop()
|
? noop()
|
||||||
: filter((file) => !file.endsWith('package.json')),
|
: filter((file) => !file.endsWith('package.json')),
|
||||||
|
options.js ? toJS() : noop(),
|
||||||
]),
|
]),
|
||||||
MergeStrategy.Overwrite
|
MergeStrategy.Overwrite
|
||||||
);
|
);
|
||||||
@ -122,7 +129,7 @@ function addProject(options: NormalizedSchema): Rule {
|
|||||||
outputPath: `dist/${libsDir(host)}/${options.projectDirectory}`,
|
outputPath: `dist/${libsDir(host)}/${options.projectDirectory}`,
|
||||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||||
packageJson: `${options.projectRoot}/package.json`,
|
packageJson: `${options.projectRoot}/package.json`,
|
||||||
main: `${options.projectRoot}/src/index.ts`,
|
main: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||||
assets: [`${options.projectRoot}/*.md`],
|
assets: [`${options.projectRoot}/*.md`],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,4 +14,6 @@ export interface Schema {
|
|||||||
testEnvironment: 'jsdom' | 'node';
|
testEnvironment: 'jsdom' | 'node';
|
||||||
rootDir?: string;
|
rootDir?: string;
|
||||||
babelJest?: boolean;
|
babelJest?: boolean;
|
||||||
|
js: boolean;
|
||||||
|
pascalCaseFiles: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,17 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Use babel instead ts-jest",
|
"description": "Use babel instead ts-jest",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"pascalCaseFiles": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use pascal case file names.",
|
||||||
|
"alias": "P",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Generate JavaScript files rather than TypeScript files.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { <%= propertyName %> } from './<%= fileName %>';
|
||||||
|
|
||||||
|
describe('<%= propertyName %>', () => {
|
||||||
|
it('should work', () => {
|
||||||
|
expect(<%= propertyName %>()).toEqual('<%= name %>');
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export function <%= propertyName %>(): string {
|
||||||
|
return '<%= name %>';
|
||||||
|
}
|
||||||
@ -70,14 +70,21 @@ describe('lib', () => {
|
|||||||
it('should create a local tsconfig.json', async () => {
|
it('should create a local tsconfig.json', async () => {
|
||||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||||
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
||||||
expect(tsconfigJson.references).toEqual([
|
expect(tsconfigJson).toMatchInlineSnapshot(`
|
||||||
{
|
Object {
|
||||||
path: './tsconfig.lib.json',
|
"extends": "../../tsconfig.base.json",
|
||||||
},
|
"files": Array [],
|
||||||
{
|
"include": Array [],
|
||||||
path: './tsconfig.spec.json',
|
"references": Array [
|
||||||
},
|
Object {
|
||||||
]);
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
|
it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
|
||||||
@ -126,6 +133,7 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy();
|
expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/src/lib/my-lib.ts')).toBeTruthy();
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.ts')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.ts')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/README.md')).toBeTruthy();
|
expect(tree.exists('libs/my-lib/README.md')).toBeTruthy();
|
||||||
|
|
||||||
const ReadmeContent = tree.readContent('libs/my-lib/README.md');
|
const ReadmeContent = tree.readContent('libs/my-lib/README.md');
|
||||||
@ -183,6 +191,9 @@ describe('lib', () => {
|
|||||||
expect(
|
expect(
|
||||||
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.ts')
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.ts')
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.spec.ts')
|
||||||
|
).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy();
|
expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy();
|
||||||
expect(tree.exists(`libs/my-dir/my-lib/.eslintrc.json`)).toBeTruthy();
|
expect(tree.exists(`libs/my-dir/my-lib/.eslintrc.json`)).toBeTruthy();
|
||||||
});
|
});
|
||||||
@ -255,14 +266,19 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('--unit-test-runner none', () => {
|
describe('--unit-test-runner none', () => {
|
||||||
it('should not generate test configuration', async () => {
|
it('should not generate test configuration nor spec file', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'lib',
|
'lib',
|
||||||
{ name: 'myLib', unitTestRunner: 'none' },
|
{ name: 'myLib', unitTestRunner: 'none' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
||||||
|
expect(
|
||||||
|
resultTree.exists('libs/my-lib/src/lib/my-lib.spec.ts')
|
||||||
|
).toBeFalsy();
|
||||||
|
|
||||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||||
expect(workspaceJson.projects['my-lib'].architect.lint)
|
expect(workspaceJson.projects['my-lib'].architect.lint)
|
||||||
@ -334,6 +350,31 @@ describe('lib', () => {
|
|||||||
expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy();
|
expect(tree.exists(`libs/my-lib/jest.config.js`)).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/src/index.js')).toBeTruthy();
|
expect(tree.exists('libs/my-lib/src/index.js')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/src/lib/my-lib.js')).toBeTruthy();
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.js')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update tsconfig.json with compilerOptions.allowJs: true', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', js: true },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
readJsonInTree(tree, 'libs/my-lib/tsconfig.json').compilerOptions
|
||||||
|
).toEqual({
|
||||||
|
allowJs: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update tsconfig.lib.json include with **/*.js glob', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', js: true },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
readJsonInTree(tree, 'libs/my-lib/tsconfig.lib.json').include
|
||||||
|
).toEqual(['**/*.ts', '**/*.js']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update root tsconfig.json with a js file path', async () => {
|
it('should update root tsconfig.json with a js file path', async () => {
|
||||||
@ -359,6 +400,9 @@ describe('lib', () => {
|
|||||||
expect(
|
expect(
|
||||||
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.js')
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.js')
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.spec.js')
|
||||||
|
).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-dir/my-lib/src/index.js')).toBeTruthy();
|
expect(tree.exists('libs/my-dir/my-lib/src/index.js')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -407,4 +451,29 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('--pascalCaseFiles', () => {
|
||||||
|
it('should generate files with upper case names', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', pascalCaseFiles: true },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/MyLib.ts')).toBeTruthy();
|
||||||
|
expect(tree.exists('libs/my-lib/src/lib/MyLib.spec.ts')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate files with upper case names for nested libs as well', async () => {
|
||||||
|
const tree = await runSchematic(
|
||||||
|
'lib',
|
||||||
|
{ name: 'myLib', directory: 'myDir', pascalCaseFiles: true },
|
||||||
|
appTree
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/MyDirMyLib.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
expect(
|
||||||
|
tree.exists('libs/my-dir/my-lib/src/lib/MyDirMyLib.spec.ts')
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,20 +11,25 @@ import {
|
|||||||
move,
|
move,
|
||||||
noop,
|
noop,
|
||||||
SchematicsException,
|
SchematicsException,
|
||||||
|
filter,
|
||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
import { updateWorkspaceInTree, getNpmScope } from '@nrwl/workspace';
|
import {
|
||||||
import { updateJsonInTree } from '@nrwl/workspace';
|
updateWorkspaceInTree,
|
||||||
import { toFileName, names } from '@nrwl/workspace';
|
getNpmScope,
|
||||||
import { formatFiles } from '@nrwl/workspace';
|
toFileName,
|
||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
names,
|
||||||
|
updateJsonInTree,
|
||||||
|
formatFiles,
|
||||||
|
offsetFromRoot,
|
||||||
|
} from '@nrwl/workspace';
|
||||||
|
|
||||||
import { generateProjectLint, addLintFiles } from '../../utils/lint';
|
import { generateProjectLint, addLintFiles } from '../../utils/lint';
|
||||||
import { addProjectToNxJsonInTree, libsDir } from '../../utils/ast-utils';
|
import { addProjectToNxJsonInTree, libsDir } from '../../utils/ast-utils';
|
||||||
import { cliCommand } from '../../core/file-utils';
|
import { cliCommand } from '../../core/file-utils';
|
||||||
import { toJS } from '../../utils/rules/to-js';
|
import { toJS, updateTsConfigsToJs, maybeJs } from '../../utils/rules/to-js';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
name: string;
|
||||||
@ -82,17 +87,22 @@ function updateTsConfig(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createFiles(options: NormalizedSchema): Rule {
|
function createFiles(options: NormalizedSchema): Rule {
|
||||||
|
const { className, name, propertyName } = names(options.name);
|
||||||
|
|
||||||
return mergeWith(
|
return mergeWith(
|
||||||
apply(url(`./files/lib`), [
|
apply(url(`./files/lib`), [
|
||||||
template({
|
template({
|
||||||
...options,
|
...options,
|
||||||
...names(options.name),
|
className,
|
||||||
|
name,
|
||||||
|
propertyName,
|
||||||
cliCommand: cliCommand(),
|
cliCommand: cliCommand(),
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||||
hasUnitTestRunner: options.unitTestRunner !== 'none',
|
hasUnitTestRunner: options.unitTestRunner !== 'none',
|
||||||
}),
|
}),
|
||||||
move(options.projectRoot),
|
move(options.projectRoot),
|
||||||
|
addTestFiles(options),
|
||||||
options.js ? toJS() : noop(),
|
options.js ? toJS() : noop(),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
@ -102,6 +112,19 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
|||||||
return addProjectToNxJsonInTree(options.name, { tags: options.parsedTags });
|
return addProjectToNxJsonInTree(options.name, { tags: options.parsedTags });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addJest(options: NormalizedSchema) {
|
||||||
|
return options.unitTestRunner !== 'none'
|
||||||
|
? externalSchematic('@nrwl/jest', 'jest-project', {
|
||||||
|
project: options.name,
|
||||||
|
setupFile: 'none',
|
||||||
|
supportTsx: true,
|
||||||
|
babelJest: options.babelJest,
|
||||||
|
skipSerializers: true,
|
||||||
|
testEnvironment: options.testEnvironment,
|
||||||
|
})
|
||||||
|
: noop();
|
||||||
|
}
|
||||||
|
|
||||||
export default function (schema: Schema): Rule {
|
export default function (schema: Schema): Rule {
|
||||||
return (host: Tree, context: SchematicContext) => {
|
return (host: Tree, context: SchematicContext) => {
|
||||||
const options = normalizeOptions(host, schema);
|
const options = normalizeOptions(host, schema);
|
||||||
@ -109,19 +132,11 @@ export default function (schema: Schema): Rule {
|
|||||||
return chain([
|
return chain([
|
||||||
addLintFiles(options.projectRoot, options.linter),
|
addLintFiles(options.projectRoot, options.linter),
|
||||||
createFiles(options),
|
createFiles(options),
|
||||||
|
options.js ? updateTsConfigsToJs(options) : noop(),
|
||||||
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
||||||
addProject(options),
|
addProject(options),
|
||||||
updateNxJson(options),
|
updateNxJson(options),
|
||||||
options.unitTestRunner !== 'none'
|
addJest(options),
|
||||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
|
||||||
project: options.name,
|
|
||||||
setupFile: 'none',
|
|
||||||
supportTsx: true,
|
|
||||||
babelJest: options.babelJest,
|
|
||||||
skipSerializers: true,
|
|
||||||
testEnvironment: options.testEnvironment,
|
|
||||||
})
|
|
||||||
: noop(),
|
|
||||||
formatFiles(options),
|
formatFiles(options),
|
||||||
])(host, context);
|
])(host, context);
|
||||||
};
|
};
|
||||||
@ -134,9 +149,11 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
: name;
|
: name;
|
||||||
|
|
||||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
const fileName = options.simpleModuleName ? name : projectName;
|
const fileName = getCaseAwareFileName({
|
||||||
|
fileName: options.simpleModuleName ? name : projectName,
|
||||||
|
pascalCaseFiles: options.pascalCaseFiles,
|
||||||
|
});
|
||||||
|
|
||||||
// const projectRoot = `libs/${projectDirectory}`;
|
|
||||||
const projectRoot = `${libsDir(host)}/${projectDirectory}`;
|
const projectRoot = `${libsDir(host)}/${projectDirectory}`;
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
@ -157,8 +174,17 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeJs(options: NormalizedSchema, path: string): string {
|
function getCaseAwareFileName(options: {
|
||||||
return options.js && (path.endsWith('.ts') || path.endsWith('.tsx'))
|
pascalCaseFiles: boolean;
|
||||||
? path.replace(/\.tsx?$/, '.js')
|
fileName: string;
|
||||||
: path;
|
}) {
|
||||||
|
const normalized = names(options.fileName);
|
||||||
|
|
||||||
|
return options.pascalCaseFiles ? normalized.className : normalized.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTestFiles(options: Pick<Schema, 'unitTestRunner'>) {
|
||||||
|
return options.unitTestRunner === 'none'
|
||||||
|
? filter((path) => !(path.endsWith('.ts') || path.endsWith('.tsx')))
|
||||||
|
: noop();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export interface Schema {
|
|||||||
linter: Linter;
|
linter: Linter;
|
||||||
testEnvironment: 'jsdom' | 'node';
|
testEnvironment: 'jsdom' | 'node';
|
||||||
importPath?: string;
|
importPath?: string;
|
||||||
js?: boolean;
|
js: boolean;
|
||||||
babelJest?: boolean;
|
babelJest?: boolean;
|
||||||
|
pascalCaseFiles: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,8 +47,8 @@
|
|||||||
},
|
},
|
||||||
"skipTsConfig": {
|
"skipTsConfig": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"description": "Do not update tsconfig.json for development experience.",
|
||||||
"description": "Do not update tsconfig.json for development experience."
|
"default": false
|
||||||
},
|
},
|
||||||
"testEnvironment": {
|
"testEnvironment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -65,6 +65,12 @@
|
|||||||
"description": "Use babel instead ts-jest",
|
"description": "Use babel instead ts-jest",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"pascalCaseFiles": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use pascal case file names.",
|
||||||
|
"alias": "P",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"js": {
|
"js": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate JavaScript files rather than TypeScript files",
|
"description": "Generate JavaScript files rather than TypeScript files",
|
||||||
|
|||||||
@ -1,23 +1,94 @@
|
|||||||
import { transpile, JsxEmit, ScriptTarget } from 'typescript';
|
import { transpile, JsxEmit, ScriptTarget } from 'typescript';
|
||||||
import { forEach, Rule, when } from '@angular-devkit/schematics';
|
import {
|
||||||
|
forEach,
|
||||||
|
Rule,
|
||||||
|
when,
|
||||||
|
chain,
|
||||||
|
Tree,
|
||||||
|
SchematicsException,
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
import { normalize } from '@angular-devkit/core';
|
import { normalize } from '@angular-devkit/core';
|
||||||
|
import { updateJsonInTree } from '../ast-utils';
|
||||||
|
|
||||||
export function toJS(): Rule {
|
export function toJS(): Rule {
|
||||||
return forEach(
|
return chain([
|
||||||
when(
|
forEach(
|
||||||
(path) => path.endsWith('.ts') || path.endsWith('.tsx'),
|
when(
|
||||||
(entry) => {
|
(path) => path.endsWith('.ts') || path.endsWith('.tsx'),
|
||||||
const original = entry.content.toString('utf-8');
|
(entry) => {
|
||||||
const result = transpile(original, {
|
const original = entry.content.toString('utf-8');
|
||||||
allowJs: true,
|
const result = transpile(original, {
|
||||||
jsx: JsxEmit.Preserve,
|
allowJs: true,
|
||||||
target: ScriptTarget.ESNext,
|
jsx: JsxEmit.Preserve,
|
||||||
});
|
target: ScriptTarget.ESNext,
|
||||||
return {
|
});
|
||||||
content: Buffer.from(result, 'utf-8'),
|
return {
|
||||||
path: normalize(entry.path.replace(/\.tsx?$/, '.js')),
|
content: Buffer.from(result, 'utf-8'),
|
||||||
};
|
path: normalize(entry.path.replace(/\.tsx?$/, '.js')),
|
||||||
}
|
};
|
||||||
)
|
}
|
||||||
);
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTsConfigsToJs(options: { projectRoot: string }): Rule {
|
||||||
|
const paths = {
|
||||||
|
tsConfig: normalize(`${options.projectRoot}/tsconfig.json`),
|
||||||
|
tsConfigLib: normalize(`${options.projectRoot}/tsconfig.lib.json`),
|
||||||
|
tsConfigApp: normalize(`${options.projectRoot}/tsconfig.app.json`),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProjectType = (tree: Tree) => {
|
||||||
|
if (tree.exists(paths.tsConfigApp)) {
|
||||||
|
return 'application';
|
||||||
|
}
|
||||||
|
if (tree.exists(paths.tsConfigLib)) {
|
||||||
|
return 'library';
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new SchematicsException(
|
||||||
|
`project is missing tsconfig.lib.json or tsconfig.app.json`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getConfigFileForUpdate = (tree: Tree) => {
|
||||||
|
const projectType = getProjectType(tree);
|
||||||
|
if (projectType === 'library') {
|
||||||
|
return paths.tsConfigLib;
|
||||||
|
}
|
||||||
|
if (projectType === 'application') {
|
||||||
|
return paths.tsConfigApp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return chain([
|
||||||
|
updateJsonInTree(paths.tsConfig, (json) => {
|
||||||
|
if (json.compilerOptions) {
|
||||||
|
json.compilerOptions.allowJs = true;
|
||||||
|
} else {
|
||||||
|
json.compilerOptions = { allowJs: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}),
|
||||||
|
(tree) => {
|
||||||
|
const updateConfigPath = getConfigFileForUpdate(tree);
|
||||||
|
|
||||||
|
return updateJsonInTree(updateConfigPath, (json) => {
|
||||||
|
json.include = uniq([...json.include, '**/*.js']);
|
||||||
|
json.exclude = uniq([...json.exclude, '**/*.spec.js']);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniq = <T extends string[]>(value: T) => [...new Set(value)] as T;
|
||||||
|
|
||||||
|
export function maybeJs(options: { js: boolean }, path: string): string {
|
||||||
|
return options.js && (path.endsWith('.ts') || path.endsWith('.tsx'))
|
||||||
|
? path.replace(/\.tsx?$/, '.js')
|
||||||
|
: path;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user