Skip to content

Commit 5e10833

Browse files
crisbetojelbourn
authored andcommitted
fix(schematics): secondary entry point migration not working against v9 (#17452)
Currently the secondary entry point migration uses the type checker to figure out which Material module a symbol belongs to. This won't work in v9, because we removed the top-level `@angular/material`. These changes fall back to looking up the name of the symbol in a list of known symbols and their module names. Fixes #17433.
1 parent 1ab4b77 commit 5e10833

File tree

9 files changed

+634
-39
lines changed

9 files changed

+634
-39
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {sync as glob} from 'glob';
2+
import {readFileSync, writeFileSync} from 'fs';
3+
import {join, basename} from 'path';
4+
import * as ts from 'typescript';
5+
6+
// Script that generates mappings from our publicly-exported symbols to their entry points. The
7+
// mappings are intended to be used by the secondary entry points schematic and should be committed
8+
// next to the relevant schematic file.
9+
// Can be run using `ts-node --project scripts scripts/generate-schematic-imports-map.ts`.
10+
const mappings: {[symbolName: string]: string} = {};
11+
const outputPath = join(__dirname, '../temp-entry-points-mapping.json');
12+
13+
glob('**/*.d.ts', {
14+
absolute: true,
15+
cwd: join(__dirname, '../tools/public_api_guard/material')
16+
}).forEach(fileName => {
17+
const content = readFileSync(fileName, 'utf8');
18+
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5);
19+
const moduleName = basename(fileName, '.d.ts');
20+
21+
// We only care about the top-level symbols.
22+
sourceFile.forEachChild((node: ts.Node & {name?: ts.Identifier}) => {
23+
// Most of the exports are named nodes (e.g. classes, types, interfaces) so we can use the
24+
// `name` property to extract the name. The one exception are variable declarations for
25+
// which we need to loop through the list of declarations.
26+
if (node.name) {
27+
addMapping(moduleName, node.name.text);
28+
} else if (ts.isVariableStatement(node)) {
29+
node.declarationList.declarations.forEach(declaration => {
30+
if (ts.isIdentifier(declaration.name)) {
31+
addMapping(moduleName, declaration.name.text);
32+
} else {
33+
throw Error('Unsupported variable kind.');
34+
}
35+
});
36+
} else if (node.kind !== ts.SyntaxKind.EndOfFileToken) {
37+
throw Error(`Unhandled node kind ${node.kind} in ${fileName}.`);
38+
}
39+
});
40+
});
41+
42+
/** Adds a symbol to the mappings. */
43+
function addMapping(moduleName: string, symbolName: string) {
44+
if (mappings[symbolName] && mappings[symbolName] !== moduleName) {
45+
throw Error(`Duplicate symbol name ${symbolName}.`);
46+
}
47+
48+
mappings[symbolName] = moduleName;
49+
}
50+
51+
writeFileSync(outputPath, JSON.stringify(mappings, null, 2));
52+
console.log(`Generated mappings to ${outputPath}. You should move the file to the ` +
53+
`proper place yourself.`);

src/material/schematics/ng-update/test-cases/misc/material-imports.spec.ts renamed to src/material/schematics/ng-update/test-cases/v8/material-imports.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {createTestCaseSetup, readFileContent} from '@angular/cdk/schematics/test
22
import {migrationCollection} from '../index.spec';
33

44
describe('v8 material imports', () => {
5-
it('should report imports for deleted animation constants', async () => {
5+
it('should re-map top-level material imports to the proper entry points', async () => {
66
const {runFixers, appTree, writeFile, removeTempDir} = await createTestCaseSetup(
77
'migration-v8', migrationCollection, [require.resolve('./material-imports_input.ts')]);
88
const materialPath = '/node_modules/@angular/material';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {createTestCaseSetup, readFileContent} from '@angular/cdk/schematics/testing';
2+
import {migrationCollection} from '../index.spec';
3+
4+
describe('v9 material imports', () => {
5+
it('should re-map top-level material imports to the proper entry points when top-level ' +
6+
'@angular/material package does not exist', async () => {
7+
const {runFixers, appTree, removeTempDir} = await createTestCaseSetup(
8+
'migration-v9', migrationCollection, [require.resolve('./material-imports_input.ts')]);
9+
10+
// Note: don't create a fake @angular/material package here, because
11+
// we're testing what would happen if it doesn't exist anymore.
12+
await runFixers();
13+
14+
expect(appTree.readContent('/projects/cdk-testing/src/test-cases/material-imports_input.ts'))
15+
.toBe(readFileContent(require.resolve('./material-imports_expected_output.ts')));
16+
17+
removeTempDir();
18+
});
19+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { MatDialogContainer as DialogContainer } from '@angular/material/dialog';
2+
import { MatAccordion, MatExpansionPanel, MatExpansionPanelHeader } from '@angular/material/expansion';
3+
import { MAT_PROGRESS_SPINNER_DEFAULT_OPTIONS as SPINNER_DEFAULTS } from '@angular/material/progress-spinner';
4+
5+
// unsorted
6+
import { MatTreeNodeToggle, MatTreeNodeDef, MatTree } from '@angular/material/tree';
7+
8+
import { /* comment */ MatTooltip as Tooltip } from '@angular/material/tooltip';
9+
10+
// primary entry-point export
11+
import { VERSION } from '@angular/material/core';
12+
13+
// type import
14+
import { MatMenuPanel } from "@angular/material/menu";
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {MatDialogContainer as DialogContainer} from '@angular/material';
2+
import {MatAccordion, MatExpansionPanel, MatExpansionPanelHeader} from '@angular/material';
3+
import {MAT_PROGRESS_SPINNER_DEFAULT_OPTIONS as SPINNER_DEFAULTS} from '@angular/material';
4+
5+
// unsorted
6+
import {MatTreeNodeToggle, MatTreeNodeDef, MatTree} from '@angular/material';
7+
8+
import {/* comment */ MatTooltip as Tooltip} from '@angular/material';
9+
10+
// primary entry-point export
11+
import {VERSION} from '@angular/material';
12+
13+
// type import
14+
import {MatMenuPanel} from "@angular/material";

0 commit comments

Comments
 (0)