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

123 lines (122 loc) 5.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const devkit_1 = require("@nx/devkit"); const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript"); const project_graph_1 = require("nx/src/config/project-graph"); const nx_deps_cache_1 = require("nx/src/project-graph/nx-deps-cache"); const version_utils_1 = require("../../generators/utils/version-utils"); const file_change_recorder_1 = require("../../utils/file-change-recorder"); const projects_1 = require("../utils/projects"); let tsquery; const angularPluginTargetNames = ['npm:@nx/angular', 'npm:@nrwl/angular']; const dataPersistenceOperators = [ 'fetch', 'navigation', 'optimisticUpdate', 'pessimisticUpdate', ]; const newImportPath = '@ngrx/router-store/data-persistence'; async function default_1(tree) { const projects = await (0, projects_1.getProjectsFilteredByDependencies)(angularPluginTargetNames); if (!projects.length) { return; } (0, ensure_typescript_1.ensureTypescript)(); tsquery = require('@phenomnomnominal/tsquery').tsquery; const cachedFileMap = (0, nx_deps_cache_1.readFileMapCache)().fileMap.projectFileMap; const filesWithNxAngularImports = []; for (const graphNode of projects) { const files = filterFilesWithNxAngularDep(cachedFileMap[graphNode.name] || []); filesWithNxAngularImports.push(...files); } let isAnyFileUsingDataPersistence = false; for (const { file } of filesWithNxAngularImports) { const updated = replaceDataPersistenceInFile(tree, file); isAnyFileUsingDataPersistence ||= updated; } if (isAnyFileUsingDataPersistence) { addNgrxRouterStoreIfNotInstalled(tree); await (0, devkit_1.formatFiles)(tree); } } function replaceDataPersistenceInFile(tree, file) { const fileContents = tree.read(file, 'utf-8'); const fileAst = tsquery.ast(fileContents); // "\\u002F" is the unicode code for "/", there's an issue with the query parser // that prevents using "/" directly in regex queries // https://github.com/estools/esquery/issues/68#issuecomment-415597670 const NX_ANGULAR_IMPORT_SELECTOR = 'ImportDeclaration:has(StringLiteral[value=/@(nx|nrwl)\\u002Fangular$/])'; const nxAngularImports = tsquery(fileAst, NX_ANGULAR_IMPORT_SELECTOR, { visitAllChildren: true }); if (!nxAngularImports.length) { return false; } const recorder = new file_change_recorder_1.FileChangeRecorder(tree, file); const IMPORT_SPECIFIERS_SELECTOR = 'ImportClause NamedImports ImportSpecifier'; for (const importDeclaration of nxAngularImports) { const importSpecifiers = tsquery(importDeclaration, IMPORT_SPECIFIERS_SELECTOR, { visitAllChildren: true }); if (!importSpecifiers.length) { continue; } // no imported symbol is a data persistence operator, skip if (importSpecifiers.every((i) => !isOperatorImport(i))) { continue; } // all imported symbols are data persistence operators, change import path if (importSpecifiers.every((i) => isOperatorImport(i))) { const IMPORT_PATH_SELECTOR = `${NX_ANGULAR_IMPORT_SELECTOR} > StringLiteral`; const importPathNode = tsquery(importDeclaration, IMPORT_PATH_SELECTOR, { visitAllChildren: true, }); recorder.replace(importPathNode[0], `'${newImportPath}'`); continue; } // mixed imports, split data persistence operators to a separate import const operatorImportSpecifiers = []; for (const importSpecifier of importSpecifiers) { if (isOperatorImport(importSpecifier)) { operatorImportSpecifiers.push(importSpecifier.getText()); recorder.remove(importSpecifier.getStart(), importSpecifier.getEnd() + (hasTrailingComma(recorder.originalContent, importSpecifier) ? 1 : 0)); } } recorder.insertLeft(importDeclaration.getStart(), `import { ${operatorImportSpecifiers.join(', ')} } from '${newImportPath}';`); } if (recorder.hasChanged()) { recorder.applyChanges(); return true; } return false; } function hasTrailingComma(content, node) { return content[node.getEnd()] === ','; } function isOperatorImport(importSpecifier) { return dataPersistenceOperators.includes(getOriginalIdentifierTextFromImportSpecifier(importSpecifier)); } function getOriginalIdentifierTextFromImportSpecifier(importSpecifier) { const children = importSpecifier.getChildren(); if (!children.length) { return importSpecifier.getText(); } return children[0].getText(); } function addNgrxRouterStoreIfNotInstalled(tree) { const { dependencies, devDependencies } = (0, devkit_1.readJson)(tree, 'package.json'); if (dependencies?.['@ngrx/router-store'] || devDependencies?.['@ngrx/router-store']) { return; } (0, devkit_1.addDependenciesToPackageJson)(tree, { '@ngrx/router-store': (0, version_utils_1.versions)(tree).ngrxVersion }, {}); } function filterFilesWithNxAngularDep(files) { const filteredFiles = []; for (const file of files) { if (file.deps?.some((dep) => angularPluginTargetNames.includes((0, project_graph_1.fileDataDepTarget)(dep)))) { filteredFiles.push(file); } } return filteredFiles; }