Skip to content

Commit

Permalink
fixup! feat(core): add schematics to move deprecated DOCUMENT import
Browse files Browse the repository at this point in the history
  • Loading branch information
CaerusKaru committed Apr 18, 2019
1 parent 7327824 commit 1e00a5d
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 298 deletions.
Expand Up @@ -8,22 +8,20 @@

import * as ts from 'typescript';

const COMMON_IMPORT = '@angular/common';
const PLATFORM_BROWSER_IMPORT = '@angular/platform-browser';
export const COMMON_IMPORT = '@angular/common';
export const PLATFORM_BROWSER_IMPORT = '@angular/platform-browser';
export const DOCUMENT_TOKEN_NAME = 'DOCUMENT';

export interface Imports {
/** This contains the metadata necessary to move items from one import to another */
export interface ResolvedDocumentImport {
platformBrowserImport: ts.NamedImports|null;
commonImport: ts.NamedImports|null;
replaceText: string|null;
documentElement: ts.ImportSpecifier|null;
}

/**
* Visitor that can be used to find a set of imports in a TypeScript file.
*/
/** Visitor that can be used to find a set of imports in a TypeScript file. */
export class DocumentImportVisitor {
importsMap: Map<ts.SourceFile, Imports> = new Map();
importsMap: Map<ts.SourceFile, ResolvedDocumentImport> = new Map();

constructor(public typeChecker: ts.TypeChecker) {}

Expand All @@ -49,20 +47,20 @@ export class DocumentImportVisitor {
imports = {
platformBrowserImport: null,
commonImport: null,
replaceText: null,
documentElement: null,
};
}

if (moduleSpecifier.text === PLATFORM_BROWSER_IMPORT) {
const documentElement = this.getDocumentElement(node);
if (documentElement) {
imports.replaceText = this.getReplaceText(documentElement);
imports.platformBrowserImport = node;
imports.documentElement = documentElement;
}
} else if (moduleSpecifier.text === COMMON_IMPORT) {
imports.commonImport = node;
} else {
return;
}
this.importsMap.set(sourceFile, imports);
}
Expand All @@ -71,10 +69,4 @@ export class DocumentImportVisitor {
const elements = node.elements;
return elements.find(el => (el.propertyName || el.name).escapedText === DOCUMENT_TOKEN_NAME);
}

private getReplaceText(documentElement: ts.ImportSpecifier): string {
return documentElement.propertyName ?
`${DOCUMENT_TOKEN_NAME} as ${documentElement.name.escapedText}` :
DOCUMENT_TOKEN_NAME;
}
}

This file was deleted.

This file was deleted.

18 changes: 9 additions & 9 deletions packages/core/schematics/migrations/move-document/index.ts
Expand Up @@ -12,8 +12,8 @@ import * as ts from 'typescript';

import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig';
import {DOCUMENT_TOKEN_NAME, DocumentImportVisitor, Imports} from './document_import_visitor';
import {addToImport, removeFromImport} from './move-import';
import {COMMON_IMPORT, DOCUMENT_TOKEN_NAME, DocumentImportVisitor, ResolvedDocumentImport} from './document_import_visitor';
import {addToImport, createImport, removeFromImport} from './move-import';


/** Entry point for the V8 move-document migration. */
Expand Down Expand Up @@ -65,17 +65,19 @@ function runMoveDocumentMigration(tree: Tree, tsconfigPath: string, basePath: st
// the source files if needed. Note that we need to update multiple queries
// within a source file within the same recorder in order to not throw off
// the TypeScript node offsets.
importsMap.forEach((imports: Imports, sourceFile: ts.SourceFile) => {
const {platformBrowserImport, commonImport, documentElement, replaceText} = imports;
if (!documentElement || !replaceText || !platformBrowserImport) {
importsMap.forEach((resolvedImport: ResolvedDocumentImport, sourceFile: ts.SourceFile) => {
const {platformBrowserImport, commonImport, documentElement} = resolvedImport;
if (!documentElement || !platformBrowserImport) {
return;
}
const update = tree.beginUpdate(relative(basePath, sourceFile.fileName));

const platformBrowserDeclaration = platformBrowserImport.parent.parent;
const newPlatformBrowserText = removeFromImport(platformBrowserImport, DOCUMENT_TOKEN_NAME);
const newPlatformBrowserText = removeFromImport(platformBrowserImport, sourceFile, DOCUMENT_TOKEN_NAME);
const newCommonText =
commonImport ? addToImport(commonImport, DOCUMENT_TOKEN_NAME) : NEW_COMMON_TEXT;
commonImport ? addToImport(commonImport, sourceFile,
documentElement.name, documentElement.propertyName) :
createImport(COMMON_IMPORT, sourceFile, documentElement.name, documentElement.propertyName);

// Replace the existing query decorator call expression with the updated
// call expression node.
Expand All @@ -93,5 +95,3 @@ function runMoveDocumentMigration(tree: Tree, tsconfigPath: string, basePath: st
tree.commitUpdate(update);
});
}

const NEW_COMMON_TEXT = `\nimport {DOCUMENT} from '@angular/common';`;
61 changes: 42 additions & 19 deletions packages/core/schematics/migrations/move-document/move-import.ts
Expand Up @@ -7,25 +7,48 @@
*/
import * as ts from 'typescript';

export function removeFromImport(importNode: ts.NamedImports, ...keys: string[]): string {
const elements = importNode.elements;
const getName = (el: ts.ImportSpecifier) => el.propertyName ?
`${el.propertyName.escapedText} as ${el.name.escapedText}` :
String(el.name.escapedText);
const elementsMap = elements.map(getName).filter(el => keys.indexOf(el) === -1);
const importDeclaration = importNode.parent.parent;
return elementsMap.length > 0 ?
`import { ${elementsMap.join(', ')} } from ${importDeclaration.moduleSpecifier.getText()};` :
'';
export function removeFromImport(importNode: ts.NamedImports, sourceFile: ts.SourceFile, importName: string): string {
const printer = ts.createPrinter();
const elements = importNode.elements.filter(el => String((el.propertyName || el.name).escapedText) !== importName);

if (!elements.length) {
return '';
}

const oldDeclaration = importNode.parent.parent;
const newImport = ts.createNamedImports(elements);
const importClause = ts.createImportClause(undefined, newImport);
const newDeclaration = ts.createImportDeclaration(undefined, undefined, importClause, oldDeclaration.moduleSpecifier);

return printer.printNode(ts.EmitHint.Unspecified, newDeclaration, sourceFile);
}

export function addToImport(importNode: ts.NamedImports, ...keys: string[]): string {
const elements = importNode.elements;
const getName = (el: ts.ImportSpecifier) => el.propertyName ?
`${el.propertyName.escapedText} as ${el.name.escapedText}` :
el.name.escapedText + '';
const elementsMap = elements.map(getName);
elementsMap.push(...keys);
const importDeclaration = importNode.parent.parent;
return `import { ${elementsMap.join(', ')} } from ${importDeclaration.moduleSpecifier.getText()};`;
export function addToImport(importNode: ts.NamedImports, sourceFile: ts.SourceFile, name: ts.Identifier, propertyName?: ts.Identifier): string {
const printer = ts.createPrinter();
const propertyNameIdentifier = propertyName ? ts.createIdentifier(String(propertyName.escapedText)) : undefined;
const nameIdentifier = ts.createIdentifier(String(name.escapedText));
const newSpecfier = ts.createImportSpecifier(propertyNameIdentifier, nameIdentifier);
const elements = [...importNode.elements];

elements.push(newSpecfier);

const oldDeclaration = importNode.parent.parent;
const newImport = ts.createNamedImports(elements);
const importClause = ts.createImportClause(undefined, newImport);
const newDeclaration = ts.createImportDeclaration(undefined, undefined, importClause, oldDeclaration.moduleSpecifier);

return printer.printNode(ts.EmitHint.Unspecified, newDeclaration, sourceFile);
}

export function createImport(importSource: string, sourceFile: ts.SourceFile, name: ts.Identifier, propertyName?: ts.Identifier) {
const printer = ts.createPrinter();
const propertyNameIdentifier = propertyName ? ts.createIdentifier(String(propertyName.escapedText)) : undefined;
const nameIdentifier = ts.createIdentifier(String(name.escapedText));
const newSpecfier = ts.createImportSpecifier(propertyNameIdentifier, nameIdentifier);
const newNamedImports = ts.createNamedImports([newSpecfier]);
const importClause = ts.createImportClause(undefined, newNamedImports);
const moduleSpecifier = ts.createStringLiteral(importSource);
const newImport = ts.createImportDeclaration(undefined, undefined, importClause, moduleSpecifier);

return printer.printNode(ts.EmitHint.Unspecified, newImport, sourceFile);
}
1 change: 0 additions & 1 deletion packages/core/schematics/test/BUILD.bazel
Expand Up @@ -9,7 +9,6 @@ ts_library(
],
deps = [
"//packages/core/schematics/migrations/move-document",
"//packages/core/schematics/migrations/move-document/google3",
"//packages/core/schematics/migrations/static-queries",
"//packages/core/schematics/migrations/static-queries/google3",
"//packages/core/schematics/migrations/template-var-assignment",
Expand Down

0 comments on commit 1e00a5d

Please sign in to comment.