fix(@schematics/angular): remove solution style tsconfig from new projects

Following the issues highlighted in https://docs.google.com/document/d/1eB6cGCG_2ircfS5GzpDC9dBgikeYYcMxghVH5sDESHw/edit?usp=sharing and discussions held with the TypeScript team. The best course of action is to rollback this feature.

In future, it is not excluded that solution style tsconfigs are re-introduced..

Closes #18040 and closes #18170
This commit is contained in:
Alan Agius 2020-08-07 14:33:20 +02:00 committed by Filipe Silva
parent fc5d2b3ff2
commit 8b96e52d83
27 changed files with 72 additions and 344 deletions

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/app",
"types": []

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/spec",
"types": [

View File

@ -35,7 +35,6 @@ import { JSONFile } from '../utility/json-file';
import { latestVersions } from '../utility/latest-versions';
import { applyLintFix } from '../utility/lint-fix';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { addTsConfigProjectReferences, verifyBaseTsConfigExists } from '../utility/tsconfig';
import { validateProjectName } from '../utility/validation';
import { getWorkspace, updateWorkspace } from '../utility/workspace';
import { Builders, ProjectType } from '../utility/workspace-models';
@ -280,7 +279,6 @@ export default function (options: ApplicationOptions): Rule {
}
validateProjectName(options.name);
verifyBaseTsConfigExists(host);
const appRootSelector = `${options.prefix}-root`;
const componentOptions: Partial<ComponentOptions> = !options.minimal ?
@ -363,10 +361,6 @@ export default function (options: ApplicationOptions): Rule {
}),
move(sourceDir),
]), MergeStrategy.Overwrite),
addTsConfigProjectReferences([
join(appDir, 'tsconfig.app.json'),
... options.minimal ? [] : [join(appDir, 'tsconfig.spec.json')],
]),
options.minimal ? noop() : schematic('e2e', e2eOptions),
options.skipPackageJson ? noop() : addDependenciesToPackageJson(options),
options.lintFix ? applyLintFix(appDir) : noop(),

View File

@ -80,28 +80,6 @@ describe('Application Schematic', () => {
expect(workspace.defaultProject).toBe('foo');
});
it('should add references in solution style tsconfig', async () => {
const tree = await schematicRunner.runSchematicAsync('application', defaultOptions, workspaceTree)
.toPromise();
const { references } = readJsonFile(tree, '/tsconfig.json');
expect(references).toEqual([
{ path: './projects/foo/tsconfig.app.json' },
{ path: './projects/foo/tsconfig.spec.json' },
]);
});
it('minimal=true should add correct reference in tsconfig', async () => {
const options = { ...defaultOptions, minimal: true };
const tree = await schematicRunner.runSchematicAsync('application', options, workspaceTree)
.toPromise();
const { references } = readJsonFile(tree, '/tsconfig.json');
expect(references).toEqual([
{ path: './projects/foo/tsconfig.app.json' },
]);
});
it('should set the prefix to app if none is set', async () => {
const options = { ...defaultOptions };
@ -166,7 +144,7 @@ describe('Application Schematic', () => {
.toPromise();
const { files, extends: _extends } = readJsonFile(tree, '/projects/foo/tsconfig.app.json');
expect(files).toEqual(['src/main.ts', 'src/polyfills.ts']);
expect(_extends).toBe('../../tsconfig.base.json');
expect(_extends).toBe('../../tsconfig.json');
});
it('should set the right paths in the tsconfig.spec.json', async () => {
@ -174,7 +152,7 @@ describe('Application Schematic', () => {
.toPromise();
const { files, extends: _extends } = readJsonFile(tree, '/projects/foo/tsconfig.spec.json');
expect(files).toEqual(['src/test.ts', 'src/polyfills.ts']);
expect(_extends).toBe('../../tsconfig.base.json');
expect(_extends).toBe('../../tsconfig.json');
});
it('should set the right path and prefix in the tslint file', async () => {
@ -401,9 +379,9 @@ describe('Application Schematic', () => {
const tree = await schematicRunner.runSchematicAsync('application', options, workspaceTree)
.toPromise();
const appTsConfig = readJsonFile(tree, '/tsconfig.app.json');
expect(appTsConfig.extends).toEqual('./tsconfig.base.json');
expect(appTsConfig.extends).toEqual('./tsconfig.json');
const specTsConfig = readJsonFile(tree, '/tsconfig.spec.json');
expect(specTsConfig.extends).toEqual('./tsconfig.base.json');
expect(specTsConfig.extends).toEqual('./tsconfig.json');
expect(specTsConfig.files).toEqual(['src/test.ts', 'src/polyfills.ts']);
});
@ -447,9 +425,9 @@ describe('Application Schematic', () => {
expect(buildOpt.tsConfig).toEqual('foo/tsconfig.app.json');
const appTsConfig = readJsonFile(tree, '/foo/tsconfig.app.json');
expect(appTsConfig.extends).toEqual('../tsconfig.base.json');
expect(appTsConfig.extends).toEqual('../tsconfig.json');
const specTsConfig = readJsonFile(tree, '/foo/tsconfig.spec.json');
expect(specTsConfig.extends).toEqual('../tsconfig.base.json');
expect(specTsConfig.extends).toEqual('../tsconfig.json');
});
});

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/e2e",
"module": "commonjs",

View File

@ -18,7 +18,6 @@ import {
url,
} from '@angular-devkit/schematics';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { verifyBaseTsConfigExists } from '../utility/tsconfig';
import { getWorkspace, updateWorkspace } from '../utility/workspace';
import { Builders } from '../utility/workspace-models';
import { Schema as E2eOptions } from './schema';
@ -32,8 +31,6 @@ export default function (options: E2eOptions): Rule {
throw new SchematicsException(`Project name "${appProject}" doesn't not exist.`);
}
verifyBaseTsConfigExists(host);
const root = join(normalize(project.root), 'e2e');
project.targets.add({

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/lib",
"target": "es2015",

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/spec",
"types": [

View File

@ -25,7 +25,6 @@ import { NodeDependencyType, addPackageJsonDependency } from '../utility/depende
import { latestVersions } from '../utility/latest-versions';
import { applyLintFix } from '../utility/lint-fix';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { addTsConfigProjectReferences, verifyBaseTsConfigExists } from '../utility/tsconfig';
import { validateProjectName } from '../utility/validation';
import { getWorkspace, updateWorkspace } from '../utility/workspace';
import { Builders, ProjectType } from '../utility/workspace-models';
@ -59,9 +58,9 @@ function updateJsonFile<T>(host: Tree, path: string, callback: UpdateJsonFn<T>):
function updateTsConfig(packageName: string, ...paths: string[]) {
return (host: Tree) => {
if (!host.exists('tsconfig.base.json')) { return host; }
if (!host.exists('tsconfig.json')) { return host; }
return updateJsonFile(host, 'tsconfig.base.json', (tsconfig: TsConfigPartialType) => {
return updateJsonFile(host, 'tsconfig.json', (tsconfig: TsConfigPartialType) => {
if (!tsconfig.compilerOptions.paths) {
tsconfig.compilerOptions.paths = {};
}
@ -174,7 +173,6 @@ export default function (options: LibraryOptions): Rule {
const prefix = options.prefix;
validateProjectName(options.name);
verifyBaseTsConfigExists(host);
// If scoped project (i.e. "@foo/bar"), convert projectDir to "foo/bar".
const projectName = options.name;
@ -240,10 +238,6 @@ export default function (options: LibraryOptions): Rule {
path: sourceDir,
project: options.name,
}),
addTsConfigProjectReferences([
`${projectRoot}/tsconfig.lib.json`,
`${projectRoot}/tsconfig.spec.json`,
]),
options.lintFix ? applyLintFix(sourceDir) : noop(),
(_tree: Tree, context: SchematicContext) => {
if (!options.skipPackageJson && !options.skipInstall) {

View File

@ -202,11 +202,11 @@ describe('Library Schematic', () => {
});
});
describe(`update tsconfig.base.json`, () => {
describe(`update tsconfig.json`, () => {
it(`should add paths mapping to empty tsconfig`, async () => {
const tree = await schematicRunner.runSchematicAsync('library', defaultOptions, workspaceTree).toPromise();
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.base.json');
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.json');
expect(tsConfigJson.compilerOptions.paths.foo).toBeTruthy();
expect(tsConfigJson.compilerOptions.paths.foo.length).toEqual(2);
expect(tsConfigJson.compilerOptions.paths.foo[0]).toEqual('dist/foo/foo');
@ -214,7 +214,7 @@ describe('Library Schematic', () => {
});
it(`should append to existing paths mappings`, async () => {
workspaceTree.overwrite('tsconfig.base.json', JSON.stringify({
workspaceTree.overwrite('tsconfig.json', JSON.stringify({
compilerOptions: {
paths: {
'unrelated': ['./something/else.ts'],
@ -224,7 +224,7 @@ describe('Library Schematic', () => {
}));
const tree = await schematicRunner.runSchematicAsync('library', defaultOptions, workspaceTree).toPromise();
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.base.json');
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.json');
expect(tsConfigJson.compilerOptions.paths.foo).toBeTruthy();
expect(tsConfigJson.compilerOptions.paths.foo.length).toEqual(3);
expect(tsConfigJson.compilerOptions.paths.foo[1]).toEqual('dist/foo/foo');
@ -237,7 +237,7 @@ describe('Library Schematic', () => {
skipTsConfig: true,
}, workspaceTree).toPromise();
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.base.json');
const tsConfigJson = getJsonFileContent(tree, 'tsconfig.json');
expect(tsConfigJson.compilerOptions.paths).toBeUndefined();
});
});
@ -266,12 +266,12 @@ describe('Library Schematic', () => {
expect(pkgJson.name).toEqual(scopedName);
const tsConfigJson = getJsonFileContent(tree, '/projects/myscope/mylib/tsconfig.spec.json');
expect(tsConfigJson.extends).toEqual('../../../tsconfig.base.json');
expect(tsConfigJson.extends).toEqual('../../../tsconfig.json');
const cfg = JSON.parse(tree.readContent('/angular.json'));
expect(cfg.projects['@myscope/mylib']).toBeDefined();
const rootTsCfg = getJsonFileContent(tree, '/tsconfig.base.json');
const rootTsCfg = getJsonFileContent(tree, '/tsconfig.json');
expect(rootTsCfg.compilerOptions.paths['@myscope/mylib']).toEqual(['dist/myscope/mylib/myscope-mylib', 'dist/myscope/mylib']);
const karmaConf = getFileContent(tree, '/projects/myscope/mylib/karma.conf.js');
@ -316,9 +316,9 @@ describe('Library Schematic', () => {
expect(buildOpt.tsConfig).toEqual('foo/tsconfig.lib.json');
const appTsConfig = getJsonFileContent(tree, '/foo/tsconfig.lib.json');
expect(appTsConfig.extends).toEqual('../tsconfig.base.json');
expect(appTsConfig.extends).toEqual('../tsconfig.json');
const specTsConfig = getJsonFileContent(tree, '/foo/tsconfig.spec.json');
expect(specTsConfig.extends).toEqual('../tsconfig.base.json');
expect(specTsConfig.extends).toEqual('../tsconfig.json');
});
it(`should add 'production' configuration`, async () => {
@ -328,16 +328,4 @@ describe('Library Schematic', () => {
const workspace = JSON.parse(tree.readContent('/angular.json'));
expect(workspace.projects.foo.architect.build.configurations.production).toBeDefined();
});
it('should add reference in solution style tsconfig', async () => {
const tree = await schematicRunner.runSchematicAsync('library', defaultOptions, workspaceTree)
.toPromise();
// tslint:disable-next-line:no-any
const { references } = getJsonFileContent(tree, '/tsconfig.json');
expect(references).toEqual([
{ path: './projects/foo/tsconfig.lib.json' },
{ path: './projects/foo/tsconfig.spec.json' },
]);
});
});

View File

@ -41,7 +41,7 @@
"skipTsConfig": {
"type": "boolean",
"default": false,
"description": "When true, does not update \"tsconfig.base.json\" to add a path mapping for the new library. The path mapping is needed to use the library in an app, but can be disabled here to simplify development."
"description": "When true, does not update \"tsconfig.json\" to add a path mapping for the new library. The path mapping is needed to use the library in an app, but can be disabled here to simplify development."
},
"lintFix": {
"type": "boolean",

View File

@ -73,9 +73,9 @@ function updateTsconfigExtendsRule(): Rule {
}
// Rename workspace tsconfig to base tsconfig.
host.rename('tsconfig.json', 'tsconfig.base.json');
host.rename('tsconfig.json', 'tsconfig.json');
// Iterate over all tsconfig files and change the extends from 'tsconfig.json' 'tsconfig.base.json'
// Iterate over all tsconfig files and change the extends from 'tsconfig.json' 'tsconfig.json'
for (const [tsconfigPath, extendsAst] of visitExtendedJsonFiles(host.root, context.logger)) {
const tsConfigDir = dirname(normalize(tsconfigPath));
if ('/tsconfig.json' !== resolve(tsConfigDir, normalize(extendsAst.value))) {
@ -127,7 +127,7 @@ export default function (): Rule {
return (host, context) => {
const logger = context.logger;
if (host.exists('tsconfig.base.json')) {
if (host.exists('tsconfig.json')) {
logger.info('Migration has already been executed.');
return;

View File

@ -79,16 +79,16 @@ describe('Migration to create "Solution Style" tsconfig', () => {
createJsonFile(tree, 'src/tsconfig.worker.json', { extends: './../tsconfig.json', compilerOptions });
});
it(`should rename 'tsconfig.json' to 'tsconfig.base.json'`, async () => {
it(`should rename 'tsconfig.json' to 'tsconfig.json'`, async () => {
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
expect(newTree.exists('tsconfig.base.json')).toBeTrue();
expect(newTree.exists('tsconfig.json')).toBeTrue();
});
it(`should update extends from 'tsconfig.json' to 'tsconfig.base.json'`, async () => {
it(`should update extends from 'tsconfig.json' to 'tsconfig.json'`, async () => {
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
expect(readJsonFile(newTree, 'src/tsconfig.json').extends).toEqual('./../tsconfig.base.json');
expect(readJsonFile(newTree, 'src/tsconfig.spec.json').extends).toEqual('./../tsconfig.base.json');
expect(readJsonFile(newTree, 'src/tsconfig.worker.json').extends).toEqual('./../tsconfig.base.json');
expect(readJsonFile(newTree, 'src/tsconfig.json').extends).toEqual('./../tsconfig.json');
expect(readJsonFile(newTree, 'src/tsconfig.spec.json').extends).toEqual('./../tsconfig.json');
expect(readJsonFile(newTree, 'src/tsconfig.worker.json').extends).toEqual('./../tsconfig.json');
});
it('should not update extends if not extended the root tsconfig', async () => {
@ -118,7 +118,7 @@ describe('Migration to create "Solution Style" tsconfig', () => {
it('should not error out when a JSON file is a blank', async () => {
tree.create('blank.json', '');
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
expect(readJsonFile(newTree, 'src/tsconfig.json').extends).toEqual('./../tsconfig.base.json');
expect(readJsonFile(newTree, 'src/tsconfig.json').extends).toEqual('./../tsconfig.json');
});
it('should show warning with full path when parsing invalid JSON', async () => {

View File

@ -23,13 +23,13 @@ export default function (): Rule {
return async (host, { logger }) => {
// Workspace level tsconfig
try {
updateModuleAndTarget(host, 'tsconfig.base.json', {
updateModuleAndTarget(host, 'tsconfig.json', {
oldModule: 'esnext',
newModule: 'es2020',
});
} catch (error) {
logger.warn(
`Unable to update 'tsconfig.base.json' module option from 'esnext' to 'es2020': ${
`Unable to update 'tsconfig.json' module option from 'esnext' to 'es2020': ${
error.message || error
}`,
);

View File

@ -91,7 +91,7 @@ describe('Migration to update target and module compiler options', () => {
const compilerOptions = { target: 'es2015', module: 'esnext' };
// Workspace
createJsonFile(tree, 'tsconfig.base.json', { compilerOptions });
createJsonFile(tree, 'tsconfig.json', { compilerOptions });
// Application
createJsonFile(tree, 'src/tsconfig.app.json', { compilerOptions });
@ -106,19 +106,19 @@ describe('Migration to update target and module compiler options', () => {
createJsonFile(tree, 'src/tsconfig.server.json', { compilerOptions: { module: 'commonjs' } });
});
it(`should update module and target in workspace 'tsconfig.base.json'`, async () => {
it(`should update module and target in workspace 'tsconfig.json'`, async () => {
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
const { module } = readJsonFile(newTree, 'tsconfig.base.json').compilerOptions;
const { module } = readJsonFile(newTree, 'tsconfig.json').compilerOptions;
expect(module).toBe('es2020');
});
it(`should update module and target in 'tsconfig.base.json' which is referenced in option`, async () => {
it(`should update module and target in 'tsconfig.json' which is referenced in option`, async () => {
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
const { module } = readJsonFile(newTree, 'src/tsconfig.spec.json').compilerOptions;
expect(module).toBe('es2020');
});
it(`should update module and target in 'tsconfig.base.json' which is referenced in a configuration`, async () => {
it(`should update module and target in 'tsconfig.json' which is referenced in a configuration`, async () => {
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
const { module } = readJsonFile(newTree, 'src/tsconfig.app.prod.json').compilerOptions;
expect(module).toBe('es2020');

View File

@ -62,7 +62,7 @@ describe('Migration to version 9', () => {
.toPromise();
// Pre version 9 - tsconfig.json was the base tsconfig file.
tree.overwrite('tsconfig.json', tree.readContent('tsconfig.base.json'));
tree.overwrite('tsconfig.json', tree.readContent('tsconfig.json'));
});
it('should update apps tsConfig with stricter files inclusions', async () => {

View File

@ -82,7 +82,7 @@ describe('Migration to version 9', () => {
.toPromise();
// Pre version 9 - tsconfig.json was the base tsconfig file.
tree.overwrite('tsconfig.json', tree.readContent('tsconfig.base.json'));
tree.overwrite('tsconfig.json', tree.readContent('tsconfig.json'));
const tsConfig = JSON.stringify(
{

View File

@ -34,7 +34,6 @@ import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/d
import { findBootstrapModuleCall, findBootstrapModulePath } from '../utility/ng-ast-utils';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { targetBuildNotFoundError } from '../utility/project-targets';
import { addTsConfigProjectReferences, verifyBaseTsConfigExists } from '../utility/tsconfig';
import { getWorkspace, updateWorkspace } from '../utility/workspace';
import { BrowserBuilderOptions, Builders, OutputHashing } from '../utility/workspace-models';
import { Schema as UniversalOptions } from './schema';
@ -240,8 +239,6 @@ export default function (options: UniversalOptions): Rule {
throw targetBuildNotFoundError();
}
verifyBaseTsConfigExists(host);
const clientBuildOptions =
(clientBuildTarget.options || {}) as unknown as BrowserBuilderOptions;
@ -285,9 +282,6 @@ export default function (options: UniversalOptions): Rule {
updateConfigFile(options, tsConfigDirectory),
wrapBootstrapCall(clientBuildOptions.main),
addServerTransition(options, clientBuildOptions.main, clientProject.root),
addTsConfigProjectReferences([
join(tsConfigDirectory, 'tsconfig.server.json'),
]),
]);
};
}

View File

@ -263,19 +263,4 @@ describe('Universal Schematic', () => {
const contents = tree.readContent(filePath);
expect(contents).toContain('@angular/localize/init');
});
it('should add reference in solution style tsconfig', async () => {
const tree = await schematicRunner.runSchematicAsync('universal', workspaceUniversalOptions, appTree)
.toPromise();
// tslint:disable-next-line:no-any
const { references } = parseJson(tree.readContent('/tsconfig.json').toString(), JsonParseMode.Loose) as any;
expect(references).toEqual([
{ path: './tsconfig.app.json' },
{ path: './tsconfig.spec.json' },
{ path: './projects/bar/tsconfig.app.json' },
{ path: './projects/bar/tsconfig.spec.json' },
{ path: './tsconfig.server.json' },
]);
});
});

View File

@ -1,70 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { JsonParseMode, parseJsonAst } from '@angular-devkit/core';
import { Rule, SchematicsException, Tree } from '@angular-devkit/schematics';
import { appendValueInAstArray, findPropertyInAstObject } from './json-utils';
const SOLUTION_TSCONFIG_PATH = 'tsconfig.json';
/**
* Add project references in "Solution Style" tsconfig.
*/
export function addTsConfigProjectReferences(paths: string[]): Rule {
return (host, context) => {
const logger = context.logger;
// We need to read after each write to avoid missing `,` when appending multiple items.
for (const path of paths) {
const source = host.read(SOLUTION_TSCONFIG_PATH);
if (!source) {
// Solution tsconfig doesn't exist.
logger.warn(`Cannot add reference '${path}' in '${SOLUTION_TSCONFIG_PATH}'. File doesn't exists.`);
return;
}
const jsonAst = parseJsonAst(source.toString(), JsonParseMode.Loose);
if (jsonAst?.kind !== 'object') {
// Invalid JSON
throw new SchematicsException(`Invalid JSON AST Object '${SOLUTION_TSCONFIG_PATH}'.`);
}
// Solutions style tsconfig can contain 2 properties:
// - 'files' with a value of empty array
// - 'references'
const filesAst = findPropertyInAstObject(jsonAst, 'files');
const referencesAst = findPropertyInAstObject(jsonAst, 'references');
if (
filesAst?.kind !== 'array' ||
filesAst.elements.length !== 0 ||
referencesAst?.kind !== 'array'
) {
logger.warn(`Cannot add reference '${path}' in '${SOLUTION_TSCONFIG_PATH}'. It appears to be an invalid solution style tsconfig.`);
return;
}
// Append new paths
const recorder = host.beginUpdate(SOLUTION_TSCONFIG_PATH);
appendValueInAstArray(recorder, referencesAst, { 'path': `./${path}` }, 4);
host.commitUpdate(recorder);
}
};
}
/**
* Throws an exception when the base tsconfig doesn't exists.
*/
export function verifyBaseTsConfigExists(host: Tree): void {
if (host.exists('tsconfig.base.json')) {
return;
}
throw new SchematicsException(`Cannot find base TypeScript configuration file 'tsconfig.base.json'.`);
}

View File

@ -1,101 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { EmptyTree, SchematicContext, Tree, callRule } from '@angular-devkit/schematics';
import { addTsConfigProjectReferences } from './tsconfig';
const SOLUTION_TSCONFIG_PATH = 'tsconfig.json';
describe('addTsConfigProjectReference', () => {
const context = {
// tslint:disable-next-line:no-any
logger: {} as any,
} as SchematicContext;
const createTsConfig = (content: object) =>
tree.create(SOLUTION_TSCONFIG_PATH, JSON.stringify(content, undefined, 2));
const parseTsConfig = (tree: Tree) =>
// tslint:disable-next-line:no-non-null-assertion
JSON.parse(tree.read(SOLUTION_TSCONFIG_PATH)!.toString());
let tree: Tree;
beforeEach(() => {
tree = new EmptyTree();
});
it('works when references is an empty array', async () => {
createTsConfig({
files: [],
references: [],
});
const result = await callRule(
addTsConfigProjectReferences(['foo/tsconfig.app.json']),
tree,
context,
)
.toPromise();
// tslint:disable-next-line:no-non-null-assertion
const { references } = parseTsConfig(result);
expect(references).toEqual([
{ path: './foo/tsconfig.app.json' },
]);
});
it('works when references contains an element', async () => {
createTsConfig({
files: [],
references: [
{ path: './foo/tsconfig.spec.json' },
],
});
const result = await callRule(
addTsConfigProjectReferences(['foo/tsconfig.app.json']),
tree,
context,
)
.toPromise();
// tslint:disable-next-line:no-non-null-assertion
const { references } = parseTsConfig(result);
expect(references).toEqual([
{ path: './foo/tsconfig.spec.json' },
{ path: './foo/tsconfig.app.json' },
]);
});
it('works when adding multiple references and contains an element', async () => {
createTsConfig({
files: [],
references: [
{ path: './foo/tsconfig.spec.json' },
],
});
const result = await callRule(
addTsConfigProjectReferences([
'foo/tsconfig.app.json',
'foo/tsconfig.server.json',
]),
tree,
context,
)
.toPromise();
// tslint:disable-next-line:no-non-null-assertion
const { references } = parseTsConfig(result);
expect(references).toEqual([
{ path: './foo/tsconfig.spec.json' },
{ path: './foo/tsconfig.app.json' },
{ path: './foo/tsconfig.server.json' },
]);
});
});

View File

@ -1,6 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.base.json",
"extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json",
"compilerOptions": {
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/worker",
"lib": [

View File

@ -19,7 +19,6 @@ import {
import { JSONFile } from '../utility/json-file';
import { parseName } from '../utility/parse-name';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { addTsConfigProjectReferences, verifyBaseTsConfigExists } from '../utility/tsconfig';
import { buildDefaultPath, getWorkspace, updateWorkspace } from '../utility/workspace';
import { BrowserBuilderOptions, LintBuilderOptions } from '../utility/workspace-models';
import { Schema as WebWorkerOptions } from './schema';
@ -118,8 +117,6 @@ export default function (options: WebWorkerOptions): Rule {
throw new SchematicsException(`Web Worker requires a project type of "application".`);
}
verifyBaseTsConfigExists(host);
const projectTarget = project.targets.get(options.target);
if (!projectTarget) {
throw new Error(`Target is not defined for this project.`);
@ -160,9 +157,6 @@ export default function (options: WebWorkerOptions): Rule {
options.snippet ? addSnippet(options) : noop(),
// Add the worker.
mergeWith(templateSource),
addTsConfigProjectReferences([
`${root}/tsconfig.worker.json`,
]),
]);
};
}

View File

@ -136,7 +136,7 @@ describe('Web Worker Schematic', () => {
appTree.overwrite('/angular.json', JSON.stringify(workspace));
const oldTsConfig = {
extends: '../../../tsconfig.base.json',
extends: '../../../tsconfig.json',
include: [
'**/*.ts',
],
@ -152,17 +152,4 @@ describe('Web Worker Schematic', () => {
const { exclude } = JSON.parse(tree.readContent(tsConfigPath));
expect(exclude).toContain('**/*.worker.ts');
});
it('should add reference in solution style tsconfig', async () => {
const tree = await schematicRunner.runSchematicAsync('web-worker', defaultOptions, appTree)
.toPromise();
// tslint:disable-next-line:no-any
const { references } = parseJson(tree.readContent('/tsconfig.json').toString(), JsonParseMode.Loose) as any;
expect(references).toEqual([
{ path: './projects/bar/tsconfig.app.json' },
{ path: './projects/bar/tsconfig.spec.json' },
{ path: './projects/bar/tsconfig.worker.json' },
]);
});
});

View File

@ -1,28 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",<% if (strict) { %>
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,<% } %>
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
}<% if (strict) { %>,
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictTemplates": true
}<% } %>
}

View File

@ -1,10 +1,28 @@
/*
This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScripts language server to improve development experience.
It is not intended to be used to perform a compilation.
To learn more about this file see: https://angular.io/config/solution-tsconfig.
*/
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"files": [],
"references": []
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",<% if (strict) { %>
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,<% } %>
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
}<% if (strict) { %>,
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictTemplates": true
}<% } %>
}

View File

@ -33,7 +33,6 @@ describe('Workspace Schematic', () => {
'/package.json',
'/README.md',
'/tsconfig.json',
'/tsconfig.base.json',
'/tslint.json',
]));
});
@ -68,7 +67,6 @@ describe('Workspace Schematic', () => {
'/package.json',
'/README.md',
'/tsconfig.json',
'/tsconfig.base.json',
]));
expect(files).not.toContain('/tslint.json');
@ -79,7 +77,7 @@ describe('Workspace Schematic', () => {
const tree = await schematicRunner.runSchematicAsync('workspace', { ...defaultOptions, strict: false }).toPromise();
const { compilerOptions, angularCompilerOptions } =
// tslint:disable-next-line: no-any
parseJson(tree.readContent('tsconfig.base.json').toString(), JsonParseMode.Loose) as any;
parseJson(tree.readContent('tsconfig.json').toString(), JsonParseMode.Loose) as any;
expect(compilerOptions.strict).toBeUndefined();
expect(angularCompilerOptions).toBeUndefined();
});
@ -88,7 +86,7 @@ describe('Workspace Schematic', () => {
const tree = await schematicRunner.runSchematicAsync('workspace', { ...defaultOptions, strict: true }).toPromise();
const { compilerOptions, angularCompilerOptions } =
// tslint:disable-next-line: no-any
parseJson(tree.readContent('tsconfig.base.json').toString(), JsonParseMode.Loose) as any;
parseJson(tree.readContent('tsconfig.json').toString(), JsonParseMode.Loose) as any;
expect(compilerOptions.strict).toBe(true);
expect(angularCompilerOptions.strictTemplates).toBe(true);
});