UNPKG

@nx/angular

Version:

The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. It provides: - Integration with libraries such as Storybook, Jest, ESLint, Tailwind CSS, Playwright and Cypre

93 lines (92 loc) 5.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.setRouterInitialNavigation = setRouterInitialNavigation; const devkit_1 = require("@nx/devkit"); const js_1 = require("@nx/js"); const tsquery_1 = require("@phenomnomnominal/tsquery"); const typescript_1 = require("typescript"); function setRouterInitialNavigation(tree, options) { const printer = (0, typescript_1.createPrinter)(); const project = (0, devkit_1.readProjectConfiguration)(tree, options.project); (0, devkit_1.visitNotIgnoredFiles)(tree, project.root, (filePath) => { // we are only interested in .ts files if (!filePath.endsWith('.ts')) { return; } if (options.standalone) { processFileWithStandaloneSetup(tree, filePath, printer); } else { processFileWithNgModuleSetup(tree, filePath, printer); } }); } function processFileWithStandaloneSetup(tree, filePath, printer) { let content = tree.read(filePath, 'utf-8'); let sourceFile = tsquery_1.tsquery.ast(content); const provideRouterCallExpression = getProvideRouterCallExpression(sourceFile); if (!provideRouterCallExpression) { return; } if (provideRouterCallExpression.arguments.some((arg) => (0, typescript_1.isCallExpression)(arg) && (0, typescript_1.isIdentifier)(arg.expression) && arg.expression.text === 'withEnabledBlockingInitialNavigation')) { return; } const updatedProvideRouterCallExpression = printer.printNode(typescript_1.EmitHint.Unspecified, updateProvideRouterCallExpression(provideRouterCallExpression), sourceFile); content = `${content.slice(0, provideRouterCallExpression.getStart())}${updatedProvideRouterCallExpression}${content.slice(provideRouterCallExpression.getEnd())}`; tree.write(filePath, content); sourceFile = tsquery_1.tsquery.ast(content); sourceFile = (0, js_1.insertImport)(tree, sourceFile, filePath, 'withEnabledBlockingInitialNavigation', '@angular/router'); const withDisabledInitialNavigationImportNode = (0, tsquery_1.tsquery)(sourceFile, 'ImportDeclaration ImportSpecifier:has(Identifier[name=withDisabledInitialNavigation])')[0]; if (!withDisabledInitialNavigationImportNode) { return; } const hasTrailingComma = withDisabledInitialNavigationImportNode.parent.elements.hasTrailingComma; content = tree.read(filePath, 'utf-8'); tree.write(filePath, `${content.slice(0, withDisabledInitialNavigationImportNode.getStart())}${content.slice(withDisabledInitialNavigationImportNode.getEnd() + (hasTrailingComma ? 1 : 0))}`); } function updateProvideRouterCallExpression(node) { const filteredArgs = node.arguments.filter((arg) => !((0, typescript_1.isCallExpression)(arg) && (0, typescript_1.isIdentifier)(arg.expression) && arg.expression.text === 'withDisabledInitialNavigation')); const initialNavigationFeatureArg = typescript_1.factory.createCallExpression(typescript_1.factory.createIdentifier('withEnabledBlockingInitialNavigation'), [], []); return typescript_1.factory.updateCallExpression(node, node.expression, node.typeArguments, [...filteredArgs, initialNavigationFeatureArg]); } function processFileWithNgModuleSetup(tree, filePath, printer) { const content = tree.read(filePath, 'utf-8'); const sourceFile = tsquery_1.tsquery.ast(content); const routerModuleForRootCallExpression = getRouterModuleForRootCallExpression(sourceFile); if (!routerModuleForRootCallExpression) { return; } const updatedRouterModuleForRootCallExpression = printer.printNode(typescript_1.EmitHint.Unspecified, updateRouterModuleForRootCallExpression(routerModuleForRootCallExpression), sourceFile); tree.write(filePath, `${content.slice(0, routerModuleForRootCallExpression.getStart())}${updatedRouterModuleForRootCallExpression}${content.slice(routerModuleForRootCallExpression.getEnd())}`); } function updateRouterModuleForRootCallExpression(node) { const existingOptions = node.arguments[1]; const existingProperties = existingOptions?.properties ? typescript_1.factory.createNodeArray(existingOptions.properties.filter((exp) => !((0, typescript_1.isPropertyAssignment)(exp) && (0, typescript_1.isIdentifier)(exp.name) && exp.name.text === 'initialNavigation'))) : typescript_1.factory.createNodeArray(); const enabledLiteral = typescript_1.factory.createStringLiteral('enabledBlocking', true); const initialNavigationProperty = typescript_1.factory.createPropertyAssignment('initialNavigation', enabledLiteral); const routerOptions = existingOptions ? typescript_1.factory.updateObjectLiteralExpression(existingOptions, typescript_1.factory.createNodeArray([ ...existingProperties, initialNavigationProperty, ])) : typescript_1.factory.createObjectLiteralExpression(typescript_1.factory.createNodeArray([initialNavigationProperty])); const args = [node.arguments[0], routerOptions]; return typescript_1.factory.createCallExpression(node.expression, node.typeArguments, args); } function getProvideRouterCallExpression(sourceFile) { const routerModuleForRootCalls = (0, tsquery_1.tsquery)(sourceFile, 'PropertyAssignment:has(Identifier[name=providers]) > ArrayLiteralExpression CallExpression:has(Identifier[name=provideRouter])', { visitAllChildren: true }); return routerModuleForRootCalls.length ? routerModuleForRootCalls[0] : null; } function getRouterModuleForRootCallExpression(sourceFile) { const routerModuleForRootCalls = (0, tsquery_1.tsquery)(sourceFile, 'Decorator > CallExpression:has(Identifier[name=NgModule]) PropertyAssignment:has(Identifier[name=imports]) > ArrayLiteralExpression CallExpression:has(Identifier[name=forRoot])', { visitAllChildren: true }); return routerModuleForRootCalls.length ? routerModuleForRootCalls[0] : null; }