@yolkai/nx-schematics
Version:
228 lines (227 loc) • 10.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
const ts = require("typescript");
const nx_workspace_1 = require("@yolkai/nx-workspace");
const ast_utils_1 = require("@yolkai/nx-workspace/src/utils/ast-utils");
const addExtensionRecommendations = nx_workspace_1.updateJsonInTree('.vscode/extensions.json', (json) => {
json.recommendations = json.recommendations || [];
[
'nrwl.angular-console',
'angular.ng-template',
'esbenp.prettier-vscode'
].forEach(extension => {
if (!json.recommendations.includes(extension)) {
json.recommendations.push(extension);
}
});
return json;
});
function addItemToImport(path, sourceFile, printer, importStatement, symbol) {
const newImport = ts.createImportDeclaration(importStatement.decorators, importStatement.modifiers, ts.createImportClause(importStatement.importClause.name, ts.createNamedImports([
...importStatement.importClause.namedBindings
.elements,
ts.createImportSpecifier(undefined, ts.createIdentifier(symbol))
])), importStatement.moduleSpecifier);
return new ast_utils_1.ReplaceChange(path, importStatement.getStart(sourceFile), importStatement.getText(sourceFile), printer.printNode(ts.EmitHint.Unspecified, newImport, sourceFile));
}
function isEffectDecorator(decorator) {
return (ts.isCallExpression(decorator.expression) &&
ts.isIdentifier(decorator.expression.expression) &&
decorator.expression.expression.text === 'Effect');
}
function getImport(sourceFile, path, symbol) {
return sourceFile.statements
.filter(ts.isImportDeclaration)
.filter(statement => statement.moduleSpecifier.getText(sourceFile).includes(path))
.find(statement => {
if (!ts.isNamedImports(statement.importClause.namedBindings)) {
return false;
}
return statement.importClause.namedBindings.elements.some(element => element.getText(sourceFile) === symbol);
});
}
function updateOfTypeCode(path, sourceFile) {
const effectsImport = getImport(sourceFile, '@ngrx/effects', 'Effect');
if (!effectsImport) {
return [];
}
const effects = [];
const changes = [];
const printer = ts.createPrinter();
sourceFile.statements
.filter(ts.isClassDeclaration)
.map(clazz => clazz.members
.filter(ts.isPropertyDeclaration)
.filter(member => member.decorators && member.decorators.some(isEffectDecorator)))
.forEach(properties => {
effects.push(...properties);
});
effects.forEach(effect => {
if (ts.isCallExpression(effect.initializer) &&
ts.isPropertyAccessExpression(effect.initializer.expression) &&
effect.initializer.expression.name.text === 'pipe' &&
ts.isCallExpression(effect.initializer.expression.expression) &&
ts.isPropertyAccessExpression(effect.initializer.expression.expression.expression) &&
effect.initializer.expression.expression.expression.name.text === 'ofType') {
const originalText = effect.initializer.getText(sourceFile);
const ofTypeExpression = ts.createCall(ts.createIdentifier('ofType'), effect.initializer.expression.expression.typeArguments, effect.initializer.expression.expression.arguments);
const node = ts.createCall(ts.createPropertyAccess(effect.initializer.expression.expression.expression.expression, 'pipe'), effect.initializer.typeArguments, ts.createNodeArray([
ofTypeExpression,
...effect.initializer.arguments
]));
const newEffect = printer.printNode(ts.EmitHint.Expression, node, sourceFile);
const change = new ast_utils_1.ReplaceChange(path, effect.initializer.getStart(sourceFile), originalText, newEffect);
changes.push(change);
}
});
if (changes.length > 0) {
changes.unshift(addItemToImport(path, sourceFile, printer, effectsImport, 'ofType'));
}
return changes;
}
function getConstructor(classDeclaration) {
return classDeclaration.members.find(ts.isConstructorDeclaration);
}
function getStoreProperty(sourceFile, constructor) {
const storeParameter = constructor.parameters.find(parameter => parameter.type && parameter.type.getText(sourceFile).includes('Store'));
return storeParameter ? storeParameter.name.getText(sourceFile) : null;
}
function updateSelectorCode(path, sourceFile) {
const storeImport = getImport(sourceFile, '@ngrx/store', 'Store');
if (!storeImport) {
return [];
}
const changes = [];
const printer = ts.createPrinter();
sourceFile.statements
.filter(ts.isClassDeclaration)
.forEach(classDeclaration => {
const constructor = getConstructor(classDeclaration);
if (!constructor) {
return;
}
const storeProperty = getStoreProperty(sourceFile, constructor);
ast_utils_1.getSourceNodes(sourceFile).forEach(node => {
if (ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression) &&
ts.isPropertyAccessExpression(node.expression.expression) &&
ts.isIdentifier(node.expression.name) &&
ts.isIdentifier(node.expression.expression.name) &&
node.expression.name.getText(sourceFile) === 'select' &&
node.expression.expression.name.getText(sourceFile) ===
storeProperty &&
node.expression.expression.expression.kind ===
ts.SyntaxKind.ThisKeyword) {
const newExpression = ts.createCall(ts.createPropertyAccess(ts.createPropertyAccess(ts.createIdentifier('this'), ts.createIdentifier(storeProperty)), ts.createIdentifier('pipe')), [], [
ts.createCall(ts.createIdentifier('select'), node.typeArguments, node.arguments)
]);
const newNode = printer.printNode(ts.EmitHint.Expression, newExpression, sourceFile);
changes.push(new ast_utils_1.ReplaceChange(path, node.getStart(sourceFile), node.getText(sourceFile), newNode));
}
});
});
if (changes.length > 0) {
changes.unshift(addItemToImport(path, sourceFile, printer, storeImport, 'select'));
}
return changes;
}
function migrateNgrx(host) {
const ngrxVersion = nx_workspace_1.readJsonInTree(host, 'package.json').dependencies['@ngrx/store'];
if (ngrxVersion &&
!(ngrxVersion.startsWith('6.') ||
ngrxVersion.startsWith('~6.') ||
ngrxVersion.startsWith('^6.'))) {
return host;
}
host.visit(path => {
if (!path.endsWith('.ts')) {
return;
}
let sourceFile = ts.createSourceFile(path, host.read(path).toString(), ts.ScriptTarget.Latest);
if (sourceFile.isDeclarationFile) {
return;
}
nx_workspace_1.insert(host, path, updateOfTypeCode(path, sourceFile));
sourceFile = ts.createSourceFile(path, host.read(path).toString(), ts.ScriptTarget.Latest);
nx_workspace_1.insert(host, path, updateSelectorCode(path, sourceFile));
sourceFile = ts.createSourceFile(path, host.read(path).toString(), ts.ScriptTarget.Latest);
nx_workspace_1.insert(host, path, cleanUpDoublePipes(path, sourceFile));
});
}
function cleanUpDoublePipes(path, sourceFile) {
const changes = [];
const printer = ts.createPrinter();
ast_utils_1.getSourceNodes(sourceFile).forEach(node => {
if (ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression) &&
ts.isCallExpression(node.expression.expression) &&
ts.isPropertyAccessExpression(node.expression.expression.expression) &&
node.expression.name.text === 'pipe' &&
node.expression.expression.expression.name.text === 'pipe') {
const singlePipe = ts.createCall(node.expression.expression.expression, node.typeArguments, [...node.expression.expression.arguments, ...node.arguments]);
changes.push(new ast_utils_1.ReplaceChange(path, node.getStart(sourceFile), node.getText(sourceFile), printer.printNode(ts.EmitHint.Expression, singlePipe, sourceFile)));
}
});
return changes;
}
const updateNgrx = nx_workspace_1.updateJsonInTree('package.json', json => {
json.devDependencies = json.devDependencies || {};
json.dependencies = json.dependencies || {};
json.dependencies = Object.assign({}, json.dependencies, { '@ngrx/effects': '7.2.0', '@ngrx/router-store': '7.2.0', '@ngrx/store': '7.2.0' });
json.devDependencies = Object.assign({}, json.devDependencies, { '@ngrx/schematics': '7.2.0', '@ngrx/store-devtools': '7.2.0' });
return json;
});
const addDotEnv = nx_workspace_1.updateJsonInTree('package.json', json => {
json.devDependencies = json.devDependencies || {};
json.devDependencies = Object.assign({}, json.devDependencies, { dotenv: '6.2.0' });
return json;
});
const setDefaults = nx_workspace_1.updateWorkspaceInTree(json => {
if (!json.schematics) {
json.schematics = {};
}
if (!json.schematics['@yolkai/nx-schematics:library']) {
json.schematics['@yolkai/nx-schematics:library'] = {};
}
if (!json.schematics['@yolkai/nx-schematics:library'].unitTestRunner) {
json.schematics['@yolkai/nx-schematics:library'].unitTestRunner = 'karma';
}
if (!json.schematics['@yolkai/nx-schematics:application']) {
json.schematics['@yolkai/nx-schematics:application'] = {};
}
if (!json.schematics['@yolkai/nx-schematics:application'].unitTestRunner) {
json.schematics['@yolkai/nx-schematics:application'].unitTestRunner =
'karma';
}
if (!json.schematics['@yolkai/nx-schematics:application'].e2eTestRunner) {
json.schematics['@yolkai/nx-schematics:application'].e2eTestRunner =
'protractor';
}
if (!json.schematics['@yolkai/nx-schematics:node-application']) {
json.schematics['@yolkai/nx-schematics:node-application'] = {};
}
if (!json.schematics['@yolkai/nx-schematics:node-application'].framework) {
json.schematics['@yolkai/nx-schematics:node-application'].framework =
'express';
}
return json;
});
const updateAngularCLI = schematics_1.chain([
nx_workspace_1.addUpdateTask('@angular/cli', '7.3.1'),
nx_workspace_1.addDepsToPackageJson({}, {
'@angular-devkit/build-angular': '~0.13.1'
})
]);
function default_1() {
return schematics_1.chain([
addExtensionRecommendations,
addDotEnv,
updateAngularCLI,
migrateNgrx,
updateNgrx,
setDefaults,
nx_workspace_1.formatFiles()
]);
}
exports.default = default_1;