Skip to content

Commit 3a0bdc0

Browse files
authored
refactor: restore @angular/cdk clone (#35)
* refactor: restore CDK clone * build: remove @angular/cdk * refactor: update cdk sources * fix: type mismatch
1 parent 8b3a1ab commit 3a0bdc0

20 files changed

+745
-24
lines changed

package-lock.json

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
"dependencies": {
3838
"@angular-devkit/core": "^8.3.8",
3939
"@angular-devkit/schematics": "^8.3.8",
40-
"@angular/cdk": "^8.2.3",
4140
"@schematics/angular": "^8.3.8",
4241
"@schematics/update": "^0.803.8",
4342
"rxjs": "^6.4.0",

src/cdk/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export * from './ng-add/package-config';
2+
export * from './utils/ast';
3+
export * from './utils/build-component';
4+
export * from './utils/get-project';
5+
export * from './utils/html-head-element';
6+
export * from './utils/project-main-file';
7+
export * from './utils/project-targets';
8+
export * from './utils/version-agnostic-typescript';

src/cdk/ng-add/package-config.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { Tree } from '@angular-devkit/schematics';
10+
11+
/**
12+
* Sorts the keys of the given object.
13+
* @returns A new object instance with sorted keys
14+
*/
15+
function sortObjectByKeys(obj: object) {
16+
return Object.keys(obj)
17+
.sort()
18+
.reduce((result, key) => (result[key] = obj[key]) && result, {});
19+
}
20+
21+
/** Adds a package to the package.json in the given host tree. */
22+
export function addPackageToPackageJson(host: Tree, pkg: string, version: string): Tree {
23+
if (host.exists('package.json')) {
24+
const sourceText = host.read('package.json')!.toString('utf-8');
25+
const json = JSON.parse(sourceText);
26+
27+
if (!json.dependencies) {
28+
json.dependencies = {};
29+
}
30+
31+
if (!json.dependencies[pkg]) {
32+
json.dependencies[pkg] = version;
33+
json.dependencies = sortObjectByKeys(json.dependencies);
34+
}
35+
36+
host.overwrite('package.json', JSON.stringify(json, null, 2));
37+
}
38+
39+
return host;
40+
}

src/cdk/utils/ast.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { WorkspaceProject } from '@angular-devkit/core/src/experimental/workspace';
10+
import { SchematicsException, Tree } from '@angular-devkit/schematics';
11+
import { Schema as ComponentOptions } from '@schematics/angular/component/schema';
12+
import { addImportToModule } from '@schematics/angular/utility/ast-utils';
13+
import { InsertChange } from '@schematics/angular/utility/change';
14+
import { getWorkspace } from '@schematics/angular/utility/config';
15+
import { findModuleFromOptions as internalFindModule } from '@schematics/angular/utility/find-module';
16+
import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils';
17+
import { getProjectMainFile } from './project-main-file';
18+
import { ts, typescript } from './version-agnostic-typescript';
19+
20+
/** Reads file given path and returns TypeScript source file. */
21+
export function getSourceFile(host: Tree, path: string): typescript.SourceFile {
22+
const buffer = host.read(path);
23+
if (!buffer) {
24+
throw new SchematicsException(`Could not find file for path: ${path}`);
25+
}
26+
return ts.createSourceFile(path, buffer.toString(), ts.ScriptTarget.Latest, true);
27+
}
28+
29+
/** Import and add module to root app module. */
30+
export function addModuleImportToRootModule(host: Tree, moduleName: string, src: string, project: WorkspaceProject) {
31+
const modulePath = getAppModulePath(host, getProjectMainFile(project));
32+
addModuleImportToModule(host, modulePath, moduleName, src);
33+
}
34+
35+
/**
36+
* Import and add module to specific module path.
37+
* @param host the tree we are updating
38+
* @param modulePath src location of the module to import
39+
* @param moduleName name of module to import
40+
* @param src src location to import
41+
*/
42+
export function addModuleImportToModule(host: Tree, modulePath: string, moduleName: string, src: string) {
43+
const moduleSource: any = getSourceFile(host, modulePath);
44+
45+
if (!moduleSource) {
46+
throw new SchematicsException(`Module not found: ${modulePath}`);
47+
}
48+
49+
const changes = addImportToModule(moduleSource, modulePath, moduleName, src);
50+
const recorder = host.beginUpdate(modulePath);
51+
52+
changes.forEach(change => {
53+
if (change instanceof InsertChange) {
54+
recorder.insertLeft(change.pos, change.toAdd);
55+
}
56+
});
57+
58+
host.commitUpdate(recorder);
59+
}
60+
61+
/** Wraps the internal find module from options with undefined path handling */
62+
export function findModuleFromOptions(host: Tree, options: ComponentOptions): string | undefined {
63+
const workspace = getWorkspace(host);
64+
65+
if (!options.project) {
66+
options.project = Object.keys(workspace.projects)[0];
67+
}
68+
69+
const project = workspace.projects[options.project];
70+
71+
if (options.path === undefined) {
72+
options.path = `/${project.root}/src/app`;
73+
}
74+
75+
return internalFindModule(host, options);
76+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { SchematicsException, Tree } from '@angular-devkit/schematics';
10+
import * as ts from 'typescript';
11+
12+
/**
13+
* Whether the Angular module in the given path imports the specified module class name.
14+
*/
15+
export function hasNgModuleImport(tree: Tree, modulePath: string, className: string): boolean {
16+
const moduleFileContent = tree.read(modulePath);
17+
18+
if (!moduleFileContent) {
19+
throw new SchematicsException(`Could not read Angular module file: ${modulePath}`);
20+
}
21+
22+
const parsedFile = ts.createSourceFile(modulePath, moduleFileContent.toString(), ts.ScriptTarget.Latest, true);
23+
const ngModuleMetadata = findNgModuleMetadata(parsedFile);
24+
25+
if (!ngModuleMetadata) {
26+
throw new SchematicsException(`Could not find NgModule declaration inside: "${modulePath}"`);
27+
}
28+
29+
for (let property of ngModuleMetadata!.properties) {
30+
if (
31+
!ts.isPropertyAssignment(property) ||
32+
property.name.getText() !== 'imports' ||
33+
!ts.isArrayLiteralExpression(property.initializer)
34+
) {
35+
continue;
36+
}
37+
38+
if (property.initializer.elements.some(element => element.getText() === className)) {
39+
return true;
40+
}
41+
}
42+
43+
return false;
44+
}
45+
46+
/**
47+
* Resolves the last identifier that is part of the given expression. This helps resolving
48+
* identifiers of nested property access expressions (e.g. myNamespace.core.NgModule).
49+
*/
50+
function resolveIdentifierOfExpression(expression: ts.Expression): ts.Identifier | null {
51+
if (ts.isIdentifier(expression)) {
52+
return expression;
53+
} else if (ts.isPropertyAccessExpression(expression)) {
54+
return expression.name;
55+
}
56+
return null;
57+
}
58+
59+
/**
60+
* Finds a NgModule declaration within the specified TypeScript node and returns the
61+
* corresponding metadata for it. This function searches breadth first because
62+
* NgModule's are usually not nested within other expressions or declarations.
63+
*/
64+
function findNgModuleMetadata(rootNode: ts.Node): ts.ObjectLiteralExpression | null {
65+
// Add immediate child nodes of the root node to the queue.
66+
const nodeQueue: ts.Node[] = [...rootNode.getChildren()];
67+
68+
while (nodeQueue.length) {
69+
const node = nodeQueue.shift()!;
70+
71+
if (ts.isDecorator(node) && ts.isCallExpression(node.expression) && isNgModuleCallExpression(node.expression)) {
72+
return node.expression.arguments[0] as ts.ObjectLiteralExpression;
73+
} else {
74+
nodeQueue.push(...node.getChildren());
75+
}
76+
}
77+
78+
return null;
79+
}
80+
81+
/** Whether the specified call expression is referring to a NgModule definition. */
82+
function isNgModuleCallExpression(callExpression: ts.CallExpression): boolean {
83+
if (!callExpression.arguments.length || !ts.isObjectLiteralExpression(callExpression.arguments[0])) {
84+
return false;
85+
}
86+
87+
const decoratorIdentifier = resolveIdentifierOfExpression(callExpression.expression);
88+
return decoratorIdentifier ? decoratorIdentifier.text === 'NgModule' : false;
89+
}

0 commit comments

Comments
 (0)