diff --git a/npm/ng-packs/packages/schematics/src/utils/ast.ts b/npm/ng-packs/packages/schematics/src/utils/ast.ts new file mode 100644 index 0000000000..a1ffe5a319 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/utils/ast.ts @@ -0,0 +1,37 @@ +import * as ts from 'typescript'; +import { findNodes } from './angular/ast-utils'; + +export function findEnvironmentExpression(source: ts.SourceFile) { + const expressions = findNodes(source, ts.isObjectLiteralExpression); + return expressions.find(expr => expr.getText().includes('production')); +} + +export function getAssignedPropertyFromObjectliteral( + expression: ts.ObjectLiteralExpression, + variableSelector: string[], +) { + const expressions = findNodes(expression, isBooleanStringOrNumberLiteral); + + const literal = expressions.find(node => + Boolean( + variableSelector.reduceRight( + (acc: ts.PropertyAssignment, key) => + acc?.name?.getText() === key ? acc.parent.parent : undefined, + node.parent, + ), + ), + ); + + return literal ? literal.getText() : undefined; +} + +export function isBooleanStringOrNumberLiteral( + node: ts.Node, +): node is ts.StringLiteral | ts.NumericLiteral | ts.BooleanLiteral { + return ( + ts.isStringLiteral(node) || + ts.isNumericLiteral(node) || + node.kind === ts.SyntaxKind.TrueKeyword || + node.kind === ts.SyntaxKind.FalseKeyword + ); +} diff --git a/npm/ng-packs/packages/schematics/src/utils/index.ts b/npm/ng-packs/packages/schematics/src/utils/index.ts index f489303b89..c2acec4d47 100644 --- a/npm/ng-packs/packages/schematics/src/utils/index.ts +++ b/npm/ng-packs/packages/schematics/src/utils/index.ts @@ -1,5 +1,6 @@ export * from './angular'; +export * from './ast'; export * from './common'; -export * from './project'; +export * from './source'; export * from './text'; export * from './workspace'; diff --git a/npm/ng-packs/packages/schematics/src/utils/project.ts b/npm/ng-packs/packages/schematics/src/utils/project.ts deleted file mode 100644 index 79bb79c796..0000000000 --- a/npm/ng-packs/packages/schematics/src/utils/project.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ProjectDefinition } from '@angular-devkit/core/src/workspace'; -import { SchematicsException, Tree } from '@angular-devkit/schematics'; -import { Exception } from '../enums'; -import { getWorkspace } from './angular/workspace'; -import { readWorkspaceSchema } from './workspace'; - -export async function resolveProject( - tree: Tree, - name: string, -): Promise<{ name: string; definition: ProjectDefinition }> { - const workspace = await getWorkspace(tree); - let definition = workspace.projects.get(name); - - if (!definition) { - name = readWorkspaceSchema(tree).defaultProject!; - definition = workspace.projects.get(name); - } - - if (!definition) throw new SchematicsException(Exception.NoProject); - - return { name, definition }; -} diff --git a/npm/ng-packs/packages/schematics/src/utils/source.ts b/npm/ng-packs/packages/schematics/src/utils/source.ts new file mode 100644 index 0000000000..45de5b00c9 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/utils/source.ts @@ -0,0 +1,34 @@ +import type { workspaces } from '@angular-devkit/core'; +import { SchematicsException, Tree } from '@angular-devkit/schematics'; +import got from 'got'; +import { Exception } from '../enums'; +import { getAssignedPropertyFromObjectliteral } from './ast'; +import { readEnvironment } from './workspace'; + +export async function getSourceJson(url: string) { + let body: any; + + try { + ({ body } = await got(url, { + responseType: 'json', + https: { rejectUnauthorized: false }, + })); + } catch (e) { + throw new SchematicsException(Exception.NoApi); + } + + return body; +} + +export function getSourceUrl(tree: Tree, projectDefinition: workspaces.ProjectDefinition) { + const environmentExpr = readEnvironment(tree, projectDefinition); + let assignment: string | undefined; + + if (environmentExpr) { + assignment = getAssignedPropertyFromObjectliteral(environmentExpr, ['apis', 'default', 'url']); + } + + if (!assignment) throw new SchematicsException(Exception.RequiredApiUrl); + + return assignment.replace(/[`'"]/g, ''); +} diff --git a/npm/ng-packs/packages/schematics/src/utils/workspace.ts b/npm/ng-packs/packages/schematics/src/utils/workspace.ts index 69aae2e726..ccae346835 100644 --- a/npm/ng-packs/packages/schematics/src/utils/workspace.ts +++ b/npm/ng-packs/packages/schematics/src/utils/workspace.ts @@ -1,6 +1,23 @@ -import { experimental } from '@angular-devkit/core'; -import { SchematicsException, Tree } from '@angular-devkit/schematics'; +import type { experimental, workspaces } from '@angular-devkit/core'; +import { SchematicsException } from '@angular-devkit/schematics'; +import type { Tree } from '@angular-devkit/schematics'; import { Exception } from '../enums'; +import { getWorkspace, ProjectType } from './angular'; +import { findEnvironmentExpression } from './ast'; +import { readFileInTree } from './common'; + +export function isLibrary(project: workspaces.ProjectDefinition): boolean { + return project.extensions['projectType'] === ProjectType.Library; +} + +export function readEnvironment(tree: Tree, project: workspaces.ProjectDefinition) { + if (isLibrary(project)) return undefined; + + const srcPath = project.sourceRoot || `${project.root}/src`; + const envPath = srcPath + '/environments/environment.ts'; + const source = readFileInTree(tree, envPath); + return findEnvironmentExpression(source); +} export function readWorkspaceSchema(tree: Tree) { const workspaceBuffer = tree.read('/angular.json') || tree.read('/workspace.json'); @@ -16,3 +33,20 @@ export function readWorkspaceSchema(tree: Tree) { return workspaceSchema; } + +export async function resolveProject( + tree: Tree, + name: string, +): Promise<{ name: string; definition: workspaces.ProjectDefinition }> { + const workspace = await getWorkspace(tree); + let definition = workspace.projects.get(name); + + if (!definition) { + name = readWorkspaceSchema(tree).defaultProject!; + definition = workspace.projects.get(name); + } + + if (!definition) throw new SchematicsException(Exception.NoProject); + + return { name, definition }; +}