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: 'nest', description: 'anything Nest specific' },
|
||||
{ name: 'node', description: 'anything Node specific' },
|
||||
{ name: 'express', description: 'anything Express specific' },
|
||||
{ name: 'nx-plugin', description: 'anything Nx Plugin specific' },
|
||||
{ name: 'react', description: 'anything React 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.
|
||||
|
||||
### js
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate JavaScript files rather than TypeScript files.
|
||||
|
||||
### linter
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -48,6 +48,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
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.
|
||||
|
||||
### js
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate JavaScript files rather than TypeScript files.
|
||||
|
||||
### linter
|
||||
|
||||
Default: `eslint`
|
||||
@ -82,6 +90,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### publishable
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -80,6 +80,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -48,6 +48,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -48,6 +48,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
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.
|
||||
|
||||
### js
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate JavaScript files rather than TypeScript files.
|
||||
|
||||
### linter
|
||||
|
||||
Default: `eslint`
|
||||
@ -82,6 +90,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### publishable
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -80,6 +80,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -48,6 +48,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -48,6 +48,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Default: `eslint`
|
||||
@ -64,6 +72,16 @@ Type: `string`
|
||||
|
||||
The name of the application.
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
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.
|
||||
|
||||
### js
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Generate JavaScript files rather than TypeScript files.
|
||||
|
||||
### linter
|
||||
|
||||
Default: `eslint`
|
||||
@ -82,6 +90,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### publishable
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -80,6 +80,16 @@ Type: `string`
|
||||
|
||||
Library name
|
||||
|
||||
### pascalCaseFiles
|
||||
|
||||
Alias(es): P
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Use pascal case file names.
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
@ -60,9 +60,7 @@ forEachCli('nx', () => {
|
||||
expect(workspaceJson).not.toContain('libs/');
|
||||
|
||||
const libTestResults = await runCLIAsync(`test ${expressLib}`);
|
||||
expect(libTestResults.stdout).toContain(
|
||||
'No tests found, exiting with code 0'
|
||||
);
|
||||
expect(libTestResults.stdout).toContain(`nx run ${expressLib}:test`);
|
||||
|
||||
const appBuildResults = await runCLIAsync(`build ${expressApp}`);
|
||||
expect(appBuildResults.stdout).toContain(`nx run ${expressApp}:build`);
|
||||
|
||||
@ -3,6 +3,8 @@ import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { runSchematic } from '../../utils/testing';
|
||||
import { readJsonInTree } from '@nrwl/workspace';
|
||||
|
||||
import { Schema } from './schema.d';
|
||||
|
||||
describe('app', () => {
|
||||
let appTree: Tree;
|
||||
|
||||
@ -12,26 +14,88 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
it('should generate files', async () => {
|
||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
||||
expect(tree.readContent('apps/my-node-app/src/main.ts')).toContain(
|
||||
`import * as express from 'express';`
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ 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 () => {
|
||||
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');
|
||||
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 () => {
|
||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
||||
const tsconfig = readJsonInTree(tree, 'apps/my-node-app/tsconfig.json');
|
||||
expect(tsconfig.references).toContainEqual({
|
||||
path: './tsconfig.app.json',
|
||||
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/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,
|
||||
});
|
||||
expect(tsconfig.references).toContainEqual({
|
||||
path: './tsconfig.spec.json',
|
||||
|
||||
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 init from '../init/init';
|
||||
import { appsDir } from '@nrwl/workspace/src/utils/ast-utils';
|
||||
import { maybeJs } from '@nrwl/workspace/src/utils/rules/to-js';
|
||||
|
||||
interface NormalizedSchema extends Schema {
|
||||
appProjectRoot: Path;
|
||||
@ -24,10 +25,10 @@ function addTypes(options: NormalizedSchema): Rule {
|
||||
});
|
||||
}
|
||||
|
||||
function addMainFile(options: NormalizedSchema): Rule {
|
||||
function addAppFiles(options: NormalizedSchema): Rule {
|
||||
return (host: Tree) => {
|
||||
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 only a minimal backend to get started.
|
||||
@ -57,7 +58,7 @@ export default function (schema: Schema): Rule {
|
||||
return chain([
|
||||
init({ ...options, skipFormat: true }),
|
||||
externalSchematic('@nrwl/node', 'application', schema),
|
||||
addMainFile(options),
|
||||
addAppFiles(options),
|
||||
addTypes(options),
|
||||
formatFiles(options),
|
||||
])(host, context);
|
||||
|
||||
@ -11,4 +11,6 @@ export interface Schema {
|
||||
linter: Linter;
|
||||
frontendProject?: string;
|
||||
babelJest?: boolean;
|
||||
js: boolean;
|
||||
pascalCaseFiles: boolean;
|
||||
}
|
||||
|
||||
@ -52,6 +52,17 @@
|
||||
"type": "boolean",
|
||||
"description": "Use babel instead ts-jest",
|
||||
"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": []
|
||||
|
||||
@ -8,7 +8,7 @@ export default function updatePackageJson(
|
||||
options: NormalizedBuilderOptions,
|
||||
context: BuilderContext
|
||||
) {
|
||||
const mainFile = basename(options.main, '.ts');
|
||||
const mainFile = basename(options.main).replace(/\.[tj]s$/, '');
|
||||
const typingsFile = `${mainFile}.d.ts`;
|
||||
const mainJsFile = `${mainFile}.js`;
|
||||
const packageJson = readJsonFile(
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import * as stripJsonComments from 'strip-json-comments';
|
||||
import { createEmptyWorkspace, getFileContent } from '@nrwl/workspace/testing';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { runSchematic } from '../../utils/testing';
|
||||
import { NxJson, readJsonInTree } from '@nrwl/workspace';
|
||||
// to break the dependency
|
||||
@ -24,7 +23,7 @@ describe('app', () => {
|
||||
const project = workspaceJson.projects['my-node-app'];
|
||||
expect(project.root).toEqual('apps/my-node-app');
|
||||
expect(project.architect).toEqual(
|
||||
jasmine.objectContaining({
|
||||
expect.objectContaining({
|
||||
build: {
|
||||
builder: '@nrwl/node:build',
|
||||
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/src/main.ts')).toBeTruthy();
|
||||
|
||||
expect(tree.readContent('apps/my-node-app/tsconfig.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
\\"extends\\": \\"../../tsconfig.base.json\\",
|
||||
\\"files\\": [],
|
||||
\\"include\\": [],
|
||||
\\"references\\": [
|
||||
{
|
||||
\\"path\\": \\"./tsconfig.app.json\\"
|
||||
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",
|
||||
},
|
||||
{
|
||||
\\"path\\": \\"./tsconfig.spec.json\\"
|
||||
Object {
|
||||
"path": "./tsconfig.spec.json",
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
"
|
||||
`);
|
||||
|
||||
const tsconfigApp = JSON.parse(
|
||||
stripJsonComments(
|
||||
getFileContent(tree, 'apps/my-node-app/tsconfig.app.json')
|
||||
)
|
||||
const tsconfigApp = readJsonInTree(
|
||||
tree,
|
||||
'apps/my-node-app/tsconfig.app.json'
|
||||
);
|
||||
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||
|
||||
const eslintrc = JSON.parse(
|
||||
stripJsonComments(
|
||||
getFileContent(tree, 'apps/my-node-app/.eslintrc.json')
|
||||
)
|
||||
);
|
||||
const eslintrc = readJsonInTree(tree, 'apps/my-node-app/.eslintrc.json');
|
||||
expect(eslintrc.extends).toEqual('../../.eslintrc.json');
|
||||
});
|
||||
});
|
||||
@ -162,8 +155,7 @@ describe('app', () => {
|
||||
|
||||
it('should generate files', async () => {
|
||||
const hasJsonValue = ({ path, expectedValue, lookupFn }) => {
|
||||
const content = getFileContent(tree, path);
|
||||
const config = JSON.parse(stripJsonComments(content));
|
||||
const config = readJsonInTree(tree, path);
|
||||
|
||||
expect(lookupFn(config)).toEqual(expectedValue);
|
||||
};
|
||||
@ -243,7 +235,7 @@ describe('app', () => {
|
||||
);
|
||||
|
||||
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'
|
||||
].architect.serve;
|
||||
expect(serve.options.proxyConfig).toEqual(
|
||||
@ -261,7 +253,7 @@ describe('app', () => {
|
||||
);
|
||||
|
||||
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'
|
||||
].architect.serve;
|
||||
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 init from '../init/init';
|
||||
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 {
|
||||
appProjectRoot: Path;
|
||||
@ -48,7 +53,7 @@ function getBuildConfig(project: any, options: NormalizedSchema) {
|
||||
builder: '@nrwl/node:build',
|
||||
options: {
|
||||
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'),
|
||||
assets: [join(project.sourceRoot, 'assets')],
|
||||
},
|
||||
@ -59,8 +64,14 @@ function getBuildConfig(project: any, options: NormalizedSchema) {
|
||||
inspect: false,
|
||||
fileReplacements: [
|
||||
{
|
||||
replace: join(project.sourceRoot, 'environments/environment.ts'),
|
||||
with: join(project.sourceRoot, 'environments/environment.prod.ts'),
|
||||
replace: maybeJs(
|
||||
options,
|
||||
join(project.sourceRoot, 'environments/environment.ts')
|
||||
),
|
||||
with: maybeJs(
|
||||
options,
|
||||
join(project.sourceRoot, 'environments/environment.prod.ts')
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -106,7 +117,8 @@ function updateWorkspaceJson(options: NormalizedSchema): Rule {
|
||||
}
|
||||
|
||||
function addAppFiles(options: NormalizedSchema): Rule {
|
||||
return mergeWith(
|
||||
return chain([
|
||||
mergeWith(
|
||||
apply(url(`./files/app`), [
|
||||
template({
|
||||
tmpl: '',
|
||||
@ -115,8 +127,16 @@ function addAppFiles(options: NormalizedSchema): Rule {
|
||||
offset: offsetFromRoot(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 {
|
||||
@ -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 {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const options = normalizeOptions(host, schema);
|
||||
@ -157,16 +189,12 @@ export default function (schema: Schema): Rule {
|
||||
}),
|
||||
addLintFiles(options.appProjectRoot, options.linter),
|
||||
addAppFiles(options),
|
||||
options.js
|
||||
? updateTsConfigsToJs({ projectRoot: options.appProjectRoot })
|
||||
: noop,
|
||||
updateWorkspaceJson(options),
|
||||
updateNxJson(options),
|
||||
options.unitTestRunner === 'jest'
|
||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
||||
project: options.name,
|
||||
setupFile: 'none',
|
||||
skipSerializers: true,
|
||||
babelJest: options.babelJest,
|
||||
})
|
||||
: noop(),
|
||||
addJest(options),
|
||||
options.frontendProject ? addProxy(options) : noop(),
|
||||
formatFiles(options),
|
||||
])(host, context);
|
||||
|
||||
@ -10,4 +10,6 @@ export interface Schema {
|
||||
tags?: string;
|
||||
frontendProject?: string;
|
||||
babelJest?: boolean;
|
||||
js: boolean;
|
||||
pascalCaseFiles: boolean;
|
||||
}
|
||||
|
||||
@ -51,6 +51,17 @@
|
||||
"type": "boolean",
|
||||
"description": "Use babel instead ts-jest",
|
||||
"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": []
|
||||
|
||||
@ -71,15 +71,21 @@ describe('lib', () => {
|
||||
it('should create a local tsconfig.json', async () => {
|
||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
||||
expect(tsconfigJson.extends).toEqual('../../tsconfig.base.json');
|
||||
expect(tsconfigJson.references).toEqual([
|
||||
{
|
||||
path: './tsconfig.lib.json',
|
||||
expect(tsconfigJson).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": Array [],
|
||||
"include": Array [],
|
||||
"references": Array [
|
||||
Object {
|
||||
"path": "./tsconfig.lib.json",
|
||||
},
|
||||
{
|
||||
path: './tsconfig.spec.json',
|
||||
Object {
|
||||
"path": "./tsconfig.spec.json",
|
||||
},
|
||||
]);
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
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'].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';
|
||||
import { Schema } from './schema';
|
||||
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 {
|
||||
name: string;
|
||||
@ -51,6 +56,7 @@ export default function (schema: NormalizedSchema): Rule {
|
||||
importPath: options.importPath,
|
||||
}),
|
||||
createFiles(options),
|
||||
options.js ? updateTsConfigsToJs(options) : noop(),
|
||||
addProject(options),
|
||||
formatFiles(options),
|
||||
]);
|
||||
@ -103,6 +109,7 @@ function createFiles(options: NormalizedSchema): Rule {
|
||||
options.publishable || options.buildable
|
||||
? noop()
|
||||
: filter((file) => !file.endsWith('package.json')),
|
||||
options.js ? toJS() : noop(),
|
||||
]),
|
||||
MergeStrategy.Overwrite
|
||||
);
|
||||
@ -122,7 +129,7 @@ function addProject(options: NormalizedSchema): Rule {
|
||||
outputPath: `dist/${libsDir(host)}/${options.projectDirectory}`,
|
||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||
packageJson: `${options.projectRoot}/package.json`,
|
||||
main: `${options.projectRoot}/src/index.ts`,
|
||||
main: maybeJs(options, `${options.projectRoot}/src/index.ts`),
|
||||
assets: [`${options.projectRoot}/*.md`],
|
||||
},
|
||||
};
|
||||
|
||||
@ -14,4 +14,6 @@ export interface Schema {
|
||||
testEnvironment: 'jsdom' | 'node';
|
||||
rootDir?: string;
|
||||
babelJest?: boolean;
|
||||
js: boolean;
|
||||
pascalCaseFiles: boolean;
|
||||
}
|
||||
|
||||
@ -79,6 +79,17 @@
|
||||
"type": "boolean",
|
||||
"description": "Use babel instead ts-jest",
|
||||
"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"]
|
||||
|
||||
@ -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 () => {
|
||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||
const tsconfigJson = readJsonInTree(tree, 'libs/my-lib/tsconfig.json');
|
||||
expect(tsconfigJson.references).toEqual([
|
||||
{
|
||||
path: './tsconfig.lib.json',
|
||||
expect(tsconfigJson).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": Array [],
|
||||
"include": Array [],
|
||||
"references": Array [
|
||||
Object {
|
||||
"path": "./tsconfig.lib.json",
|
||||
},
|
||||
{
|
||||
path: './tsconfig.spec.json',
|
||||
Object {
|
||||
"path": "./tsconfig.spec.json",
|
||||
},
|
||||
]);
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
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/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();
|
||||
|
||||
const ReadmeContent = tree.readContent('libs/my-lib/README.md');
|
||||
@ -183,6 +191,9 @@ describe('lib', () => {
|
||||
expect(
|
||||
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.ts')
|
||||
).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/.eslintrc.json`)).toBeTruthy();
|
||||
});
|
||||
@ -255,14 +266,19 @@ describe('lib', () => {
|
||||
});
|
||||
|
||||
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(
|
||||
'lib',
|
||||
{ name: 'myLib', unitTestRunner: 'none' },
|
||||
appTree
|
||||
);
|
||||
|
||||
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/src/lib/my-lib.spec.ts')
|
||||
).toBeFalsy();
|
||||
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||
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/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();
|
||||
});
|
||||
|
||||
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 () => {
|
||||
@ -359,6 +400,9 @@ describe('lib', () => {
|
||||
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();
|
||||
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,
|
||||
noop,
|
||||
SchematicsException,
|
||||
filter,
|
||||
} from '@angular-devkit/schematics';
|
||||
import { join, normalize } from '@angular-devkit/core';
|
||||
import { Schema } from './schema';
|
||||
|
||||
import { updateWorkspaceInTree, getNpmScope } from '@nrwl/workspace';
|
||||
import { updateJsonInTree } from '@nrwl/workspace';
|
||||
import { toFileName, names } from '@nrwl/workspace';
|
||||
import { formatFiles } from '@nrwl/workspace';
|
||||
import { offsetFromRoot } from '@nrwl/workspace';
|
||||
import {
|
||||
updateWorkspaceInTree,
|
||||
getNpmScope,
|
||||
toFileName,
|
||||
names,
|
||||
updateJsonInTree,
|
||||
formatFiles,
|
||||
offsetFromRoot,
|
||||
} from '@nrwl/workspace';
|
||||
|
||||
import { generateProjectLint, addLintFiles } from '../../utils/lint';
|
||||
import { addProjectToNxJsonInTree, libsDir } from '../../utils/ast-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 {
|
||||
name: string;
|
||||
@ -82,17 +87,22 @@ function updateTsConfig(options: NormalizedSchema): Rule {
|
||||
}
|
||||
|
||||
function createFiles(options: NormalizedSchema): Rule {
|
||||
const { className, name, propertyName } = names(options.name);
|
||||
|
||||
return mergeWith(
|
||||
apply(url(`./files/lib`), [
|
||||
template({
|
||||
...options,
|
||||
...names(options.name),
|
||||
className,
|
||||
name,
|
||||
propertyName,
|
||||
cliCommand: cliCommand(),
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
hasUnitTestRunner: options.unitTestRunner !== 'none',
|
||||
}),
|
||||
move(options.projectRoot),
|
||||
addTestFiles(options),
|
||||
options.js ? toJS() : noop(),
|
||||
])
|
||||
);
|
||||
@ -102,17 +112,8 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
||||
return addProjectToNxJsonInTree(options.name, { tags: options.parsedTags });
|
||||
}
|
||||
|
||||
export default function (schema: Schema): Rule {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const options = normalizeOptions(host, schema);
|
||||
|
||||
return chain([
|
||||
addLintFiles(options.projectRoot, options.linter),
|
||||
createFiles(options),
|
||||
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
||||
addProject(options),
|
||||
updateNxJson(options),
|
||||
options.unitTestRunner !== 'none'
|
||||
function addJest(options: NormalizedSchema) {
|
||||
return options.unitTestRunner !== 'none'
|
||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
||||
project: options.name,
|
||||
setupFile: 'none',
|
||||
@ -121,7 +122,21 @@ export default function (schema: Schema): Rule {
|
||||
skipSerializers: true,
|
||||
testEnvironment: options.testEnvironment,
|
||||
})
|
||||
: noop(),
|
||||
: noop();
|
||||
}
|
||||
|
||||
export default function (schema: Schema): Rule {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const options = normalizeOptions(host, schema);
|
||||
|
||||
return chain([
|
||||
addLintFiles(options.projectRoot, options.linter),
|
||||
createFiles(options),
|
||||
options.js ? updateTsConfigsToJs(options) : noop(),
|
||||
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
||||
addProject(options),
|
||||
updateNxJson(options),
|
||||
addJest(options),
|
||||
formatFiles(options),
|
||||
])(host, context);
|
||||
};
|
||||
@ -134,9 +149,11 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
: name;
|
||||
|
||||
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 parsedTags = options.tags
|
||||
@ -157,8 +174,17 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
};
|
||||
}
|
||||
|
||||
function maybeJs(options: NormalizedSchema, path: string): string {
|
||||
return options.js && (path.endsWith('.ts') || path.endsWith('.tsx'))
|
||||
? path.replace(/\.tsx?$/, '.js')
|
||||
: path;
|
||||
function getCaseAwareFileName(options: {
|
||||
pascalCaseFiles: boolean;
|
||||
fileName: string;
|
||||
}) {
|
||||
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;
|
||||
testEnvironment: 'jsdom' | 'node';
|
||||
importPath?: string;
|
||||
js?: boolean;
|
||||
js: boolean;
|
||||
babelJest?: boolean;
|
||||
pascalCaseFiles: boolean;
|
||||
}
|
||||
|
||||
@ -47,8 +47,8 @@
|
||||
},
|
||||
"skipTsConfig": {
|
||||
"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": {
|
||||
"type": "string",
|
||||
@ -65,6 +65,12 @@
|
||||
"description": "Use babel instead ts-jest",
|
||||
"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",
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
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 { updateJsonInTree } from '../ast-utils';
|
||||
|
||||
export function toJS(): Rule {
|
||||
return forEach(
|
||||
return chain([
|
||||
forEach(
|
||||
when(
|
||||
(path) => path.endsWith('.ts') || path.endsWith('.tsx'),
|
||||
(entry) => {
|
||||
@ -19,5 +28,67 @@ export function toJS(): Rule {
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
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