"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@angular-devkit/core"); const schematics_1 = require("@angular-devkit/schematics"); const tasks_1 = require("@angular-devkit/schematics/tasks"); const dependencies_1 = require("../utility/dependencies"); const latest_versions_1 = require("../utility/latest-versions"); const paths_1 = require("../utility/paths"); const workspace_1 = require("../utility/workspace"); const workspace_models_1 = require("../utility/workspace-models"); const schema_1 = require("./schema"); function default_1(options) { return async (host, context) => { const { appDir, appRootSelector, componentOptions, folderName, sourceDir } = await getAppOptions(host, options); return (0, schematics_1.chain)([ addAppToWorkspaceFile(options, appDir, folderName), options.standalone ? (0, schematics_1.noop)() : (0, schematics_1.schematic)('module', { name: 'app', commonModule: false, flat: true, routing: options.routing, routingScope: 'Root', path: sourceDir, project: options.name, }), (0, schematics_1.schematic)('component', { name: 'app', selector: appRootSelector, flat: true, path: sourceDir, skipImport: true, project: options.name, ...componentOptions, }), (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(options.standalone ? './files/standalone-files' : './files/module-files'), [ options.routing ? (0, schematics_1.noop)() : (0, schematics_1.filter)((path) => !path.endsWith('app.routes.ts.template')), componentOptions.skipTests ? (0, schematics_1.filter)((path) => !path.endsWith('.spec.ts.template')) : (0, schematics_1.noop)(), (0, schematics_1.applyTemplates)({ utils: schematics_1.strings, ...options, ...componentOptions, selector: appRootSelector, relativePathToWorkspaceRoot: (0, paths_1.relativePathToWorkspaceRoot)(appDir), appName: options.name, folderName, }), (0, schematics_1.move)(appDir), ]), schematics_1.MergeStrategy.Overwrite), (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files/common-files'), [ options.minimal ? (0, schematics_1.filter)((path) => !path.endsWith('tsconfig.spec.json.template')) : (0, schematics_1.noop)(), componentOptions.inlineTemplate ? (0, schematics_1.filter)((path) => !path.endsWith('component.html.template')) : (0, schematics_1.noop)(), (0, schematics_1.applyTemplates)({ utils: schematics_1.strings, ...options, selector: appRootSelector, relativePathToWorkspaceRoot: (0, paths_1.relativePathToWorkspaceRoot)(appDir), appName: options.name, folderName, }), (0, schematics_1.move)(appDir), ]), schematics_1.MergeStrategy.Overwrite), options.ssr ? (0, schematics_1.schematic)('ssr', { project: options.name, skipInstall: true, }) : (0, schematics_1.noop)(), options.skipPackageJson ? (0, schematics_1.noop)() : addDependenciesToPackageJson(options), ]); }; } exports.default = default_1; function addDependenciesToPackageJson(options) { return (host, context) => { [ { type: dependencies_1.NodeDependencyType.Dev, name: '@angular/compiler-cli', version: latest_versions_1.latestVersions.Angular, }, { type: dependencies_1.NodeDependencyType.Dev, name: '@angular-devkit/build-angular', version: latest_versions_1.latestVersions.DevkitBuildAngular, }, { type: dependencies_1.NodeDependencyType.Dev, name: 'typescript', version: latest_versions_1.latestVersions['typescript'], }, ].forEach((dependency) => (0, dependencies_1.addPackageJsonDependency)(host, dependency)); if (!options.skipInstall) { context.addTask(new tasks_1.NodePackageInstallTask()); } return host; }; } function addAppToWorkspaceFile(options, appDir, folderName) { let projectRoot = appDir; if (projectRoot) { projectRoot += '/'; } const schematics = {}; if (options.inlineTemplate || options.inlineStyle || options.minimal || options.style !== schema_1.Style.Css) { const componentSchematicsOptions = {}; if (options.inlineTemplate ?? options.minimal) { componentSchematicsOptions.inlineTemplate = true; } if (options.inlineStyle ?? options.minimal) { componentSchematicsOptions.inlineStyle = true; } if (options.style && options.style !== schema_1.Style.Css) { componentSchematicsOptions.style = options.style; } schematics['@schematics/angular:component'] = componentSchematicsOptions; } if (options.skipTests || options.minimal) { const schematicsWithTests = [ 'class', 'component', 'directive', 'guard', 'interceptor', 'pipe', 'resolver', 'service', ]; schematicsWithTests.forEach((type) => { (schematics[`@schematics/angular:${type}`] ??= {}).skipTests = true; }); } if (!options.standalone) { const schematicsWithStandalone = ['component', 'directive', 'pipe']; schematicsWithStandalone.forEach((type) => { (schematics[`@schematics/angular:${type}`] ??= {}).standalone = false; }); } const sourceRoot = (0, core_1.join)((0, core_1.normalize)(projectRoot), 'src'); let budgets = []; if (options.strict) { budgets = [ { type: 'initial', maximumWarning: '500kb', maximumError: '1mb', }, { type: 'anyComponentStyle', maximumWarning: '2kb', maximumError: '4kb', }, ]; } else { budgets = [ { type: 'initial', maximumWarning: '2mb', maximumError: '5mb', }, { type: 'anyComponentStyle', maximumWarning: '6kb', maximumError: '10kb', }, ]; } const inlineStyleLanguage = options?.style !== schema_1.Style.Css ? options.style : undefined; const project = { root: (0, core_1.normalize)(projectRoot), sourceRoot, projectType: workspace_models_1.ProjectType.Application, prefix: options.prefix || 'app', schematics, targets: { build: { builder: workspace_models_1.Builders.Application, defaultConfiguration: 'production', options: { outputPath: `dist/${folderName}`, index: `${sourceRoot}/index.html`, browser: `${sourceRoot}/main.ts`, polyfills: ['zone.js'], tsConfig: `${projectRoot}tsconfig.app.json`, inlineStyleLanguage, assets: [`${sourceRoot}/favicon.ico`, `${sourceRoot}/assets`], styles: [`${sourceRoot}/styles.${options.style}`], scripts: [], }, configurations: { production: { budgets, outputHashing: 'all', }, development: { optimization: false, extractLicenses: false, sourceMap: true, }, }, }, serve: { builder: workspace_models_1.Builders.DevServer, defaultConfiguration: 'development', options: {}, configurations: { production: { buildTarget: `${options.name}:build:production`, }, development: { buildTarget: `${options.name}:build:development`, }, }, }, 'extract-i18n': { builder: workspace_models_1.Builders.ExtractI18n, options: { buildTarget: `${options.name}:build`, }, }, test: options.minimal ? undefined : { builder: workspace_models_1.Builders.Karma, options: { polyfills: ['zone.js', 'zone.js/testing'], tsConfig: `${projectRoot}tsconfig.spec.json`, inlineStyleLanguage, assets: [`${sourceRoot}/favicon.ico`, `${sourceRoot}/assets`], styles: [`${sourceRoot}/styles.${options.style}`], scripts: [], }, }, }, }; return (0, workspace_1.updateWorkspace)((workspace) => { workspace.projects.add({ name: options.name, ...project, }); }); } async function getAppOptions(host, options) { const appRootSelector = `${options.prefix}-root`; const componentOptions = getComponentOptions(options); const workspace = await (0, workspace_1.getWorkspace)(host); const newProjectRoot = workspace.extensions.newProjectRoot || ''; // If scoped project (i.e. "@foo/bar"), convert dir to "foo/bar". let folderName = options.name.startsWith('@') ? options.name.slice(1) : options.name; if (/[A-Z]/.test(folderName)) { folderName = schematics_1.strings.dasherize(folderName); } const appDir = options.projectRoot === undefined ? (0, core_1.join)((0, core_1.normalize)(newProjectRoot), folderName) : (0, core_1.normalize)(options.projectRoot); const sourceDir = `${appDir}/src/app`; return { appDir, appRootSelector, componentOptions, folderName, sourceDir, }; } function getComponentOptions(options) { const componentOptions = !options.minimal ? { inlineStyle: options.inlineStyle, inlineTemplate: options.inlineTemplate, skipTests: options.skipTests, style: options.style, viewEncapsulation: options.viewEncapsulation, } : { inlineStyle: options.inlineStyle ?? true, inlineTemplate: options.inlineTemplate ?? true, skipTests: true, style: options.style, viewEncapsulation: options.viewEncapsulation, }; return componentOptions; }