Fix angular 14 errors on packages/schematics

pull/13886/head
Mahmut Gundogdu 3 years ago
parent 3047e0b008
commit 0a8b53fcae

@ -41,14 +41,14 @@
"private": true,
"devDependencies": {
"@abp/utils": "~6.0.0-rc.4",
"@angular-devkit/build-angular": "14.2.2",
"@angular-devkit/build-angular": "14.2.1",
"@angular-devkit/build-ng-packagr": "^0.1002.0",
"@angular-devkit/schematics-cli": "~12.2.0",
"@angular-devkit/schematics-cli": "~14.2.1",
"@angular-eslint/eslint-plugin": "14.0.3",
"@angular-eslint/eslint-plugin-template": "14.0.3",
"@angular-eslint/template-parser": "14.0.3",
"@angular/animations": "14.2.1",
"@angular/cli": "~14.2.0",
"@angular/cli": "~14.2.1",
"@angular/common": "14.2.1",
"@angular/compiler": "14.2.1",
"@angular/compiler-cli": "14.2.1",

@ -10,6 +10,7 @@
"schematics": "./collection.json",
"dependencies": {
"@angular-devkit/core": "~14.2.1",
"@angular/cli": "~14.2.1",
"@angular-devkit/schematics": "~14.2.1",
"got": "^11.5.2",
"jsonc-parser": "^2.3.0",

@ -1,5 +1,5 @@
**DISCLAIMER**
This directory is a direct copy of https://github.com/angular/angular-cli/tree/d091bb0c7b76a73e1b7d4b5690c532c68452b1d6 and is used under terms and permissions by the MIT license granted by Google, Inc.
This directory is a direct copy of https://github.com/angular/angular-cli/tree/c5ef701639755d5b390e64287963ee35faab2cd4/packages/schematics/angular/utility and is used under terms and permissions by the MIT license granted by Google, LLC.
All credits go to Angular team for building these utilities.

@ -0,0 +1,173 @@
/**
* @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
*/
import { Rule, SchematicContext } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import * as path from 'path';
const installTasks = new WeakMap<SchematicContext, Set<string>>();
interface MinimalPackageManifest {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
}
/**
* An enum used to specify the type of a dependency found within a package manifest
* file (`package.json`).
*/
export enum DependencyType {
Default = 'dependencies',
Dev = 'devDependencies',
Peer = 'peerDependencies',
}
/**
* An enum used to specify the dependency installation behavior for the {@link addDependency}
* schematics rule. The installation behavior affects if and when {@link NodePackageInstallTask}
* will be scheduled when using the rule.
*/
export enum InstallBehavior {
/**
* No installation will occur as a result of the rule when specified.
*
* NOTE: This does not prevent other rules from scheduling a {@link NodePackageInstallTask}
* which may install the dependency.
*/
None,
/**
* Automatically determine the need to schedule a {@link NodePackageInstallTask} based on
* previous usage of the {@link addDependency} within the schematic.
*/
Auto,
/**
* Always schedule a {@link NodePackageInstallTask} when the rule is executed.
*/
Always,
}
/**
* An enum used to specify the existing dependency behavior for the {@link addDependency}
* schematics rule. The existing behavior affects whether the named dependency will be added
* to the `package.json` when the dependency is already present with a differing specifier.
*/
export enum ExistingBehavior {
/**
* The dependency will not be added or otherwise changed if it already exists.
*/
Skip,
/**
* The dependency's existing specifier will be replaced with the specifier provided in the
* {@link addDependency} call. A warning will also be shown during schematic execution to
* notify the user of the replacement.
*/
Replace,
}
/**
* Adds a package as a dependency to a `package.json`. By default the `package.json` located
* at the schematic's root will be used. The `manifestPath` option can be used to explicitly specify
* a `package.json` in different location. The type of the dependency can also be specified instead
* of the default of the `dependencies` section by using the `type` option for either `devDependencies`
* or `peerDependencies`.
*
* When using this rule, {@link NodePackageInstallTask} does not need to be included directly by
* a schematic. A package manager install task will be automatically scheduled as needed.
*
* @param name The name of the package to add.
* @param specifier The package specifier for the package to add. Typically a SemVer range.
* @param options An optional object that can contain the `type` of the dependency
* and/or a path (`packageJsonPath`) of a manifest file (`package.json`) to modify.
* @returns A Schematics {@link Rule}
*/
export function addDependency(
name: string,
specifier: string,
options: {
/**
* The type of the dependency determines the section of the `package.json` to which the
* dependency will be added. Defaults to {@link DependencyType.Default} (`dependencies`).
*/
type?: DependencyType;
/**
* The path of the package manifest file (`package.json`) that will be modified.
* Defaults to `/package.json`.
*/
packageJsonPath?: string;
/**
* The dependency installation behavior to use to determine whether a
* {@link NodePackageInstallTask} should be scheduled after adding the dependency.
* Defaults to {@link InstallBehavior.Auto}.
*/
install?: InstallBehavior;
/**
* The behavior to use when the dependency already exists within the `package.json`.
* Defaults to {@link ExistingBehavior.Replace}.
*/
existing?: ExistingBehavior;
} = {},
): Rule {
const {
type = DependencyType.Default,
packageJsonPath = '/package.json',
install = InstallBehavior.Auto,
existing = ExistingBehavior.Replace,
} = options;
return (tree, context) => {
const manifest = tree.readJson(packageJsonPath) as MinimalPackageManifest;
const dependencySection = manifest[type];
if (!dependencySection) {
// Section is not present. The dependency can be added to a new object literal for the section.
manifest[type] = { [name]: specifier };
} else {
const existingSpecifier = dependencySection[name];
if (existingSpecifier === specifier) {
// Already present with same specifier
return;
}
if (existingSpecifier) {
// Already present but different specifier
if (existing === ExistingBehavior.Skip) {
return;
}
// ExistingBehavior.Replace is the only other behavior currently
context.logger.warn(
`Package dependency "${name}" already exists with a different specifier. ` +
`"${existingSpecifier}" will be replaced with "${specifier}".`,
);
}
// Add new dependency in alphabetical order
const entries = Object.entries(dependencySection);
entries.push([name, specifier]);
entries.sort((a, b) => a[0].localeCompare(b[0]));
manifest[type] = Object.fromEntries(entries);
}
tree.overwrite(packageJsonPath, JSON.stringify(manifest, null, 2));
const installPaths = installTasks.get(context) ?? new Set<string>();
if (
install === InstallBehavior.Always ||
(install === InstallBehavior.Auto && !installPaths.has(packageJsonPath))
) {
context.addTask(
new NodePackageInstallTask({ workingDirectory: path.dirname(packageJsonPath) }),
);
installPaths.add(packageJsonPath);
installTasks.set(context, installPaths);
}
};
}

@ -17,6 +17,7 @@ export interface ModuleOptions {
skipImport?: boolean;
moduleExt?: string;
routingModuleExt?: string;
standalone?: boolean;
}
export const MODULE_EXT = '.module.ts';
@ -26,8 +27,7 @@ export const ROUTING_MODULE_EXT = '-routing.module.ts';
* Find the module referred by a set of options passed to the schematics.
*/
export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path | undefined {
// eslint-disable-next-line no-prototype-builtins
if (options.hasOwnProperty('skipImport') && options.skipImport) {
if (options.standalone || options.skipImport) {
return undefined;
}

@ -6,8 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import { strings } from '@angular-devkit/core';
import {
Rule,
Tree,
apply,
applyTemplates,
chain,
@ -15,11 +16,11 @@ import {
mergeWith,
move,
noop,
Rule,
Tree,
strings,
url,
} from '@angular-devkit/schematics';
import { parseName } from './parse-name';
import { validateClassName } from './validation';
import { createDefaultPath } from './workspace';
export interface GenerateFromFilesOptions {
@ -36,18 +37,18 @@ export function generateFromFiles(
extraTemplateValues: Record<string, string | ((v: string) => string)> = {},
): Rule {
return async (host: Tree) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
options.path ??= await createDefaultPath(host, options.project as string);
options.prefix ??= '';
options.flat ??= true;
const parsedPath = parseName(options.path!, options.name);
const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;
validateClassName(strings.classify(options.name));
const templateSource = apply(url('./files'), [
options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(),
options.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(),
applyTemplates({
...strings,
...options,

@ -27,12 +27,7 @@ export class JSONFile {
content: string;
constructor(private readonly host: Tree, private readonly path: string) {
const buffer = this.host.read(this.path);
if (buffer) {
this.content = buffer.toString();
} else {
throw new Error(`Could not read '${path}'.`);
}
this.content = this.host.readText(this.path);
}
private _jsonAst: Node | undefined;

@ -1,20 +1,23 @@
{
"description": "Package versions used by schematics in @schematics/angular.",
"comment": "This file is needed so that depedencies are synced by Renovate.",
"comment": "This file is needed so that dependencies are synced by Renovate.",
"private": true,
"dependencies": {
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
"@types/jasmine": "~4.0.0",
"@types/node": "^14.15.0",
"jasmine-core": "~4.3.0",
"jasmine-spec-reporter": "~7.0.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine-html-reporter": "~1.7.0",
"karma-jasmine": "~4.0.0",
"karma": "~6.3.0",
"ng-packagr": "^13.0.0",
"rxjs": "~6.6.7",
"karma-coverage": "~2.2.0",
"karma-jasmine-html-reporter": "~2.0.0",
"karma-jasmine": "~5.1.0",
"karma": "~6.4.0",
"ng-packagr": "^14.2.0",
"protractor": "~7.0.0",
"rxjs": "~7.5.0",
"tslib": "^2.3.0",
"typescript": "~4.6.2",
"ts-node": "~10.9.0",
"typescript": "~4.7.2",
"zone.js": "~0.11.4"
}
}

@ -13,11 +13,7 @@ import * as ts from 'typescript';
import { findNode, getSourceNodes } from './ast-utils';
export function findBootstrapModuleCall(host: Tree, mainPath: string): ts.CallExpression | null {
const mainBuffer = host.read(mainPath);
if (!mainBuffer) {
throw new SchematicsException(`Main file (${mainPath}) not found`);
}
const mainText = mainBuffer.toString('utf-8');
const mainText = host.readText(mainPath);
const source = ts.createSourceFile(mainPath, mainText, ts.ScriptTarget.Latest, true);
const allNodes = getSourceNodes(source);
@ -58,11 +54,7 @@ export function findBootstrapModulePath(host: Tree, mainPath: string): string {
const bootstrapModule = bootstrapCall.arguments[0];
const mainBuffer = host.read(mainPath);
if (!mainBuffer) {
throw new SchematicsException(`Client application main file (${mainPath}) not found`);
}
const mainText = mainBuffer.toString('utf-8');
const mainText = host.readText(mainPath);
const source = ts.createSourceFile(mainPath, mainText, ts.ScriptTarget.Latest, true);
const allNodes = getSourceNodes(source);
const bootstrapModuleRelativePath = allNodes

@ -6,16 +6,23 @@
* found in the LICENSE file at https://angular.io/license
*/
import { tags } from '@angular-devkit/core';
import { SchematicsException } from '@angular-devkit/schematics';
// Must start with a letter, and must contain only alphanumeric characters or dashes.
// When adding a dash the segment after the dash must also start with a letter.
export const htmlSelectorRe = /^[a-zA-Z][.0-9a-zA-Z]*(:?-[a-zA-Z][.0-9a-zA-Z]*)*$/;
// See: https://github.com/tc39/proposal-regexp-unicode-property-escapes/blob/fe6d07fad74cd0192d154966baa1e95e7cda78a1/README.md#other-examples
const ecmaIdentifierNameRegExp = /^(?:[$_\p{ID_Start}])(?:[$_\u200C\u200D\p{ID_Continue}])*$/u;
export function validateHtmlSelector(selector: string): void {
if (selector && !htmlSelectorRe.test(selector)) {
throw new SchematicsException(tags.oneLine`Selector (${selector})
is invalid.`);
throw new SchematicsException(`Selector "${selector}" is invalid.`);
}
}
export function validateClassName(className: string): void {
if (!ecmaIdentifierNameRegExp.test(className)) {
throw new SchematicsException(`Class name "${className}" is invalid.`);
}
}

@ -11,6 +11,12 @@ export enum ProjectType {
Library = 'library',
}
/**
* An enum of the official Angular builders.
* Each enum value provides the fully qualified name of the associated builder.
* This enum can be used when analyzing the `builder` fields of project configurations from the
* `angular.json` workspace file.
*/
export enum Builders {
AppShell = '@angular-devkit/build-angular:app-shell',
Server = '@angular-devkit/build-angular:server',
@ -129,10 +135,15 @@ export type ServeBuilderTarget = BuilderTarget<Builders.DevServer, ServeBuilderO
export type ExtractI18nBuilderTarget = BuilderTarget<Builders.ExtractI18n, ExtractI18nOptions>;
export type E2EBuilderTarget = BuilderTarget<Builders.Protractor, E2EOptions>;
interface WorkspaceCLISchema {
warnings?: Record<string, boolean>;
schematicCollections?: string[];
defaultCollection?: string;
}
export interface WorkspaceSchema {
version: 1;
defaultProject?: string;
cli?: { warnings?: Record<string, boolean> };
cli?: WorkspaceCLISchema;
projects: {
[key: string]: WorkspaceProject<ProjectType.Application | ProjectType.Library>;
};
@ -148,7 +159,7 @@ export interface WorkspaceProject<TProjectType extends ProjectType = ProjectType
sourceRoot: string;
prefix: string;
cli?: { warnings?: Record<string, boolean> };
cli?: WorkspaceCLISchema;
/**
* Tool options.

@ -6,69 +6,113 @@
* found in the LICENSE file at https://angular.io/license
*/
import { json, virtualFs, workspaces } from '@angular-devkit/core';
import { noop, Rule, Tree } from '@angular-devkit/schematics';
import { json, workspaces } from '@angular-devkit/core';
import { Rule, Tree, noop } from '@angular-devkit/schematics';
import { ProjectType } from './workspace-models';
function createHost(tree: Tree): workspaces.WorkspaceHost {
return {
async readFile(path: string): Promise<string> {
const data = tree.read(path);
if (!data) {
throw new Error('File not found.');
}
return virtualFs.fileBufferToString(data);
},
async writeFile(path: string, data: string): Promise<void> {
return tree.overwrite(path, data);
},
async isDirectory(path: string): Promise<boolean> {
// approximate a directory check
return !tree.exists(path) && tree.getDir(path).subfiles.length > 0;
},
async isFile(path: string): Promise<boolean> {
return tree.exists(path);
},
};
const DEFAULT_WORKSPACE_PATH = '/angular.json';
// re-export the workspace definition types for convenience
export type WorkspaceDefinition = workspaces.WorkspaceDefinition;
export type ProjectDefinition = workspaces.ProjectDefinition;
export type TargetDefinition = workspaces.TargetDefinition;
/**
* A {@link workspaces.WorkspaceHost} backed by a Schematics {@link Tree} instance.
*/
class TreeWorkspaceHost implements workspaces.WorkspaceHost {
constructor(private readonly tree: Tree) {}
async readFile(path: string): Promise<string> {
return this.tree.readText(path);
}
async writeFile(path: string, data: string): Promise<void> {
if (this.tree.exists(path)) {
this.tree.overwrite(path, data);
} else {
this.tree.create(path, data);
}
}
async isDirectory(path: string): Promise<boolean> {
// approximate a directory check
return !this.tree.exists(path) && this.tree.getDir(path).subfiles.length > 0;
}
async isFile(path: string): Promise<boolean> {
return this.tree.exists(path);
}
}
/**
* Updates the workspace file (`angular.json`) found within the root of the schematic's tree.
* The workspace object model can be directly modified within the provided updater function
* with changes being written to the workspace file after the updater function returns.
* The spacing and overall layout of the file (including comments) will be maintained where
* possible when updating the file.
*
* @param updater An update function that can be used to modify the object model for the
* workspace. A {@link WorkspaceDefinition} is provided as the first argument to the function.
*/
export function updateWorkspace(
updater: (workspace: workspaces.WorkspaceDefinition) => void | Rule | PromiseLike<void | Rule>,
): Rule;
export function updateWorkspace(workspace: workspaces.WorkspaceDefinition): Rule;
export function updateWorkspace(
updaterOrWorkspace:
| workspaces.WorkspaceDefinition
| ((workspace: workspaces.WorkspaceDefinition) => void | Rule | PromiseLike<void | Rule>),
updater: (workspace: WorkspaceDefinition) => void | Rule | PromiseLike<void | Rule>,
): Rule {
return async (tree: Tree) => {
const host = createHost(tree);
const host = new TreeWorkspaceHost(tree);
if (typeof updaterOrWorkspace === 'function') {
const { workspace } = await workspaces.readWorkspace('/', host);
const { workspace } = await workspaces.readWorkspace(DEFAULT_WORKSPACE_PATH, host);
const result = await updaterOrWorkspace(workspace);
const result = await updater(workspace);
await workspaces.writeWorkspace(workspace, host);
await workspaces.writeWorkspace(workspace, host);
return result || noop;
} else {
await workspaces.writeWorkspace(updaterOrWorkspace, host);
return noop;
}
return result || noop;
};
}
export async function getWorkspace(tree: Tree, path = '/') {
const host = createHost(tree);
// TODO: This should be renamed `readWorkspace` once deep imports are restricted (already exported from `utility` with that name)
/**
* Reads a workspace file (`angular.json`) from the provided {@link Tree} instance.
*
* @param tree A schematics {@link Tree} instance used to access the workspace file.
* @param path The path where a workspace file should be found. If a file is specified, the file
* path will be used. If a directory is specified, the file `angular.json` will be used from
* within the specified directory. Defaults to `/angular.json`.
* @returns A {@link WorkspaceDefinition} representing the workspace found at the specified path.
*/
export async function getWorkspace(
tree: Tree,
path = DEFAULT_WORKSPACE_PATH,
): Promise<WorkspaceDefinition> {
const host = new TreeWorkspaceHost(tree);
const { workspace } = await workspaces.readWorkspace(path, host);
return workspace;
}
/**
* Writes a workspace file (`angular.json`) to the provided {@link Tree} instance.
* The spacing and overall layout of an exisitng file (including comments) will be maintained where
* possible when writing the file.
*
* @param tree A schematics {@link Tree} instance used to access the workspace file.
* @param workspace The {@link WorkspaceDefinition} to write.
* @param path The path where a workspace file should be written. If a file is specified, the file
* path will be used. If not provided, the definition's underlying file path stored during reading
* will be used.
*/
export async function writeWorkspace(
tree: Tree,
workspace: WorkspaceDefinition,
path?: string,
): Promise<void> {
const host = new TreeWorkspaceHost(tree);
return workspaces.writeWorkspace(workspace, host, path);
}
/**
* Build a default project path for generating.
* @param project The project which will have its default path generated.

@ -7,7 +7,7 @@ import { buildDefaultPath, getWorkspace, ProjectType, WorkspaceSchema } from './
import { findEnvironmentExpression } from './ast';
import { readFileInTree } from './common';
import { NOT_FOUND_VALUE } from '../constants/symbols';
import { parseJson } from '@angular/cli/utilities/json-file';
import { parseJson } from '@angular/cli/src/utilities/json-file';
export function isLibrary(project: workspaces.ProjectDefinition): boolean {
return project.extensions['projectType'] === ProjectType.Library;

@ -1,7 +1,7 @@
{
"compilerOptions": {
"baseUrl": "tsconfig",
"lib": ["es2018", "dom"],
"lib": ["es2019", "dom"],
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save