184 lines
5.4 KiB
TypeScript
184 lines
5.4 KiB
TypeScript
import { Tree } from '@nx/devkit';
|
|
import { insertImport } from '@nx/js';
|
|
import { addRouteToNgModule } from './ast-utils';
|
|
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
|
|
|
|
let tsModule: typeof import('typescript');
|
|
|
|
/**
|
|
* Add a new route to a routes definition
|
|
* @param tree Virtual Tree
|
|
* @param routesFile File containing the routes definition
|
|
* @param route Route to add
|
|
* @param lazy If Route should be lazy-loaded
|
|
* @param routesConst Used when eager-loading a route: Class name of the Component
|
|
* @param importPath Used when eager-loading a route: The import path to the Component
|
|
*/
|
|
export function addRoute(
|
|
tree: Tree,
|
|
routesFile: string,
|
|
route: string,
|
|
lazy: boolean = true,
|
|
routesConst?: string,
|
|
importPath?: string
|
|
) {
|
|
if (!tree.exists(routesFile)) {
|
|
throw new Error(
|
|
`Path to parent routing declaration (${routesFile}) does not exist. Please ensure path is correct.`
|
|
);
|
|
}
|
|
if (!tsModule) {
|
|
tsModule = ensureTypescript();
|
|
}
|
|
const { tsquery } = require('@phenomnomnominal/tsquery');
|
|
|
|
let routesFileContents = tree.read(routesFile, 'utf-8');
|
|
|
|
if (!lazy) {
|
|
let parentSourceFile = tsModule.createSourceFile(
|
|
routesFile,
|
|
routesFileContents,
|
|
tsModule.ScriptTarget.Latest,
|
|
true
|
|
);
|
|
|
|
parentSourceFile = insertImport(
|
|
tree,
|
|
parentSourceFile,
|
|
routesFile,
|
|
routesConst,
|
|
importPath
|
|
);
|
|
|
|
routesFileContents = tree.read(routesFile, 'utf-8');
|
|
}
|
|
|
|
const ast = tsquery.ast(routesFileContents);
|
|
|
|
const ROUTES_ARRAY_SELECTOR =
|
|
'VariableDeclaration:has(ArrayType > TypeReference > Identifier[name=Route], Identifier[name=Routes]) > ArrayLiteralExpression';
|
|
|
|
const routesArrayNodes = tsquery(ast, ROUTES_ARRAY_SELECTOR, {
|
|
visitAllChildren: true,
|
|
});
|
|
const isRoutesArray = routesArrayNodes.length > 0;
|
|
|
|
if (!isRoutesArray) {
|
|
if (routesFileContents.includes('@NgModule')) {
|
|
const sourceFile = tsModule.createSourceFile(
|
|
routesFile,
|
|
routesFileContents,
|
|
tsModule.ScriptTarget.Latest,
|
|
true
|
|
);
|
|
|
|
addRouteToNgModule(tree, routesFile, sourceFile, route);
|
|
return;
|
|
} else {
|
|
throw new Error(
|
|
`Routing file (${routesFile}) does not a routing configuration. Please ensure the parent contains a routing configuration.`
|
|
);
|
|
}
|
|
}
|
|
|
|
const newRoutesFileContents = `${routesFileContents.slice(
|
|
0,
|
|
routesArrayNodes[0].getStart() + 1
|
|
)}
|
|
${route},${routesFileContents.slice(routesArrayNodes[0].getStart() + 1)}`;
|
|
|
|
tree.write(routesFile, newRoutesFileContents);
|
|
}
|
|
|
|
/**
|
|
* Add a provider to a standalone routes definition
|
|
* @param tree Virtual Tree
|
|
* @param routesFile The file containing the routes definition
|
|
* @param routeToAddProviderTo The route to add the provider to
|
|
* @param providerToAdd The provider to add to the route
|
|
*/
|
|
export function addProviderToRoute(
|
|
tree: Tree,
|
|
routesFile: string,
|
|
routeToAddProviderTo: string,
|
|
providerToAdd: string
|
|
) {
|
|
if (!tree.exists(routesFile)) {
|
|
throw new Error(
|
|
`Path to parent routing declaration (${routesFile}) does not exist. Please ensure path is correct.`
|
|
);
|
|
}
|
|
|
|
ensureTypescript();
|
|
const { tsquery } = require('@phenomnomnominal/tsquery');
|
|
let routesFileContents = tree.read(routesFile, 'utf-8');
|
|
|
|
const ast = tsquery.ast(routesFileContents);
|
|
|
|
const ROUTES_ARRAY_SELECTOR =
|
|
'VariableDeclaration:has(ArrayType > TypeReference > Identifier[name=Route], Identifier[name=Routes]) > ArrayLiteralExpression';
|
|
|
|
const routesArrayNodes = tsquery(ast, ROUTES_ARRAY_SELECTOR, {
|
|
visitAllChildren: true,
|
|
});
|
|
const isRoutesArray = routesArrayNodes.length > 0;
|
|
|
|
if (!isRoutesArray) {
|
|
throw new Error(
|
|
`Routing file (${routesFile}) does not a routing configuration. Please ensure the parent contains a routing configuration.`
|
|
);
|
|
}
|
|
|
|
const ROUTE_SELECTOR = `ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=path]) > StringLiteral[value=${routeToAddProviderTo}]):last-child`;
|
|
const ROUTE_PATH_PROVIDERS_SELECTOR =
|
|
'ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=providers])';
|
|
|
|
const selectedRouteNodes = tsquery(routesArrayNodes[0], ROUTE_SELECTOR, {
|
|
visitAllChildren: true,
|
|
});
|
|
if (selectedRouteNodes.length === 0) {
|
|
throw new Error(
|
|
`Could not find '${routeToAddProviderTo}' in routes definition.`
|
|
);
|
|
}
|
|
|
|
for (const selectedRouteNode of selectedRouteNodes) {
|
|
const routeProivdersNodes = tsquery(
|
|
selectedRouteNode,
|
|
ROUTE_PATH_PROVIDERS_SELECTOR,
|
|
{
|
|
visitAllChildren: true,
|
|
}
|
|
);
|
|
|
|
if (routeProivdersNodes.length === 0) {
|
|
const newFileContents = `${routesFileContents.slice(
|
|
0,
|
|
selectedRouteNode.getEnd() - 1
|
|
)}${
|
|
routesFileContents
|
|
.slice(0, selectedRouteNode.getEnd() - 1)
|
|
.trim()
|
|
.endsWith(',')
|
|
? ''
|
|
: ', '
|
|
}providers: [${providerToAdd}]${routesFileContents.slice(
|
|
selectedRouteNode.getEnd() - 1,
|
|
routesFileContents.length
|
|
)}`;
|
|
|
|
tree.write(routesFile, newFileContents);
|
|
} else {
|
|
const newFileContents = `${routesFileContents.slice(
|
|
0,
|
|
routeProivdersNodes[0].getEnd() - 1
|
|
)}, ${providerToAdd}${routesFileContents.slice(
|
|
routeProivdersNodes[0].getEnd() - 1,
|
|
routesFileContents.length
|
|
)}`;
|
|
|
|
tree.write(routesFile, newFileContents);
|
|
}
|
|
}
|
|
}
|