Updated the files.

This commit is contained in:
Batuhan Berk Başoğlu 2024-02-08 19:38:41 -05:00
parent 1553e6b971
commit 753967d4f5
23418 changed files with 3784666 additions and 0 deletions

25
my-app/node_modules/@angular-devkit/core/src/exception.d.ts generated vendored Executable file
View file

@ -0,0 +1,25 @@
/**
* @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
*/
export declare class BaseException extends Error {
constructor(message?: string);
}
export declare class UnknownException extends BaseException {
constructor(message: string);
}
export declare class FileDoesNotExistException extends BaseException {
constructor(path: string);
}
export declare class FileAlreadyExistException extends BaseException {
constructor(path: string);
}
export declare class PathIsDirectoryException extends BaseException {
constructor(path: string);
}
export declare class PathIsFileException extends BaseException {
constructor(path: string);
}

47
my-app/node_modules/@angular-devkit/core/src/exception.js generated vendored Executable file
View file

@ -0,0 +1,47 @@
"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 });
exports.PathIsFileException = exports.PathIsDirectoryException = exports.FileAlreadyExistException = exports.FileDoesNotExistException = exports.UnknownException = exports.BaseException = void 0;
class BaseException extends Error {
constructor(message = '') {
super(message);
}
}
exports.BaseException = BaseException;
class UnknownException extends BaseException {
constructor(message) {
super(message);
}
}
exports.UnknownException = UnknownException;
// Exceptions
class FileDoesNotExistException extends BaseException {
constructor(path) {
super(`Path "${path}" does not exist.`);
}
}
exports.FileDoesNotExistException = FileDoesNotExistException;
class FileAlreadyExistException extends BaseException {
constructor(path) {
super(`Path "${path}" already exist.`);
}
}
exports.FileAlreadyExistException = FileAlreadyExistException;
class PathIsDirectoryException extends BaseException {
constructor(path) {
super(`Path "${path}" is a directory.`);
}
}
exports.PathIsDirectoryException = PathIsDirectoryException;
class PathIsFileException extends BaseException {
constructor(path) {
super(`Path "${path}" is a file.`);
}
}
exports.PathIsFileException = PathIsFileException;

15
my-app/node_modules/@angular-devkit/core/src/index.d.ts generated vendored Executable file
View file

@ -0,0 +1,15 @@
/**
* @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 * as json from './json/index';
import * as logging from './logger/index';
import * as workspaces from './workspace';
export * from './exception';
export * from './json/index';
export * from './utils/index';
export * from './virtual-fs/index';
export { json, logging, workspaces };

46
my-app/node_modules/@angular-devkit/core/src/index.js generated vendored Executable file
View file

@ -0,0 +1,46 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.workspaces = exports.logging = exports.json = void 0;
const json = __importStar(require("./json/index"));
exports.json = json;
const logging = __importStar(require("./logger/index"));
exports.logging = logging;
const workspaces = __importStar(require("./workspace"));
exports.workspaces = workspaces;
__exportStar(require("./exception"), exports);
__exportStar(require("./json/index"), exports);
__exportStar(require("./utils/index"), exports);
__exportStar(require("./virtual-fs/index"), exports);

10
my-app/node_modules/@angular-devkit/core/src/json/index.d.ts generated vendored Executable file
View file

@ -0,0 +1,10 @@
/**
* @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 * as schema from './schema/index';
export * from './utils';
export { schema };

39
my-app/node_modules/@angular-devkit/core/src/json/index.js generated vendored Executable file
View file

@ -0,0 +1,39 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.schema = void 0;
const schema = __importStar(require("./schema/index"));
exports.schema = schema;
__exportStar(require("./utils"), exports);

View file

@ -0,0 +1,15 @@
/**
* @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 * as transforms from './transforms';
export * from './interface';
export * from './pointer';
export * from './registry';
export * from './schema';
export * from './visitor';
export * from './utility';
export { transforms };

View file

@ -0,0 +1,44 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transforms = void 0;
const transforms = __importStar(require("./transforms"));
exports.transforms = transforms;
__exportStar(require("./interface"), exports);
__exportStar(require("./pointer"), exports);
__exportStar(require("./registry"), exports);
__exportStar(require("./schema"), exports);
__exportStar(require("./visitor"), exports);
__exportStar(require("./utility"), exports);

View file

@ -0,0 +1,84 @@
/**
* @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 { ErrorObject, Format } from 'ajv';
import { Observable, ObservableInput } from 'rxjs';
import { JsonArray, JsonObject, JsonValue } from '../utils';
export type JsonPointer = string & {
__PRIVATE_DEVKIT_JSON_POINTER: void;
};
export interface SchemaValidatorResult {
data: JsonValue;
success: boolean;
errors?: SchemaValidatorError[];
}
export type SchemaValidatorError = Partial<ErrorObject>;
export interface SchemaValidatorOptions {
applyPreTransforms?: boolean;
applyPostTransforms?: boolean;
withPrompts?: boolean;
}
export interface SchemaValidator {
(data: JsonValue, options?: SchemaValidatorOptions): Promise<SchemaValidatorResult>;
}
export type SchemaFormatter = Format;
export interface SchemaFormat {
name: string;
formatter: SchemaFormatter;
}
export interface SmartDefaultProvider<T> {
(schema: JsonObject): T | Observable<T>;
}
export interface SchemaKeywordValidator {
(data: JsonValue, schema: JsonValue, parent: JsonObject | JsonArray | undefined, parentProperty: string | number | undefined, pointer: JsonPointer, rootData: JsonValue): boolean | Observable<boolean>;
}
export interface PromptDefinition {
id: string;
type: string;
message: string;
default?: string | string[] | number | boolean | null;
validator?: (value: JsonValue) => boolean | string | Promise<boolean | string>;
items?: Array<string | {
value: JsonValue;
label: string;
}>;
raw?: string | JsonObject;
multiselect?: boolean;
propertyTypes: Set<string>;
}
export type PromptProvider = (definitions: Array<PromptDefinition>) => ObservableInput<{
[id: string]: JsonValue;
}>;
export interface SchemaRegistry {
compile(schema: Object): Promise<SchemaValidator>;
/** @private */
ɵflatten(schema: JsonObject | string): Promise<JsonObject>;
addFormat(format: SchemaFormat): void;
addSmartDefaultProvider<T>(source: string, provider: SmartDefaultProvider<T>): void;
usePromptProvider(provider: PromptProvider): void;
useXDeprecatedProvider(onUsage: (message: string) => void): void;
/**
* Add a transformation step before the validation of any Json.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void;
/**
* Add a transformation step after the validation of any Json. The JSON will not be validated
* after the POST, so if transformations are not compatible with the Schema it will not result
* in an error.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void;
}
export interface JsonSchemaVisitor {
(current: JsonObject | JsonArray, pointer: JsonPointer, parentSchema?: JsonObject | JsonArray, index?: string): void;
}
export interface JsonVisitor {
(value: JsonValue, pointer: JsonPointer, schema?: JsonObject, root?: JsonObject | JsonArray): Observable<JsonValue> | JsonValue;
}

View file

@ -0,0 +1,9 @@
"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 });

View file

@ -0,0 +1,11 @@
/**
* @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 { JsonPointer } from './interface';
export declare function buildJsonPointer(fragments: string[]): JsonPointer;
export declare function joinJsonPointer(root: JsonPointer, ...others: string[]): JsonPointer;
export declare function parseJsonPointer(pointer: JsonPointer): string[];

View file

@ -0,0 +1,39 @@
"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 });
exports.parseJsonPointer = exports.joinJsonPointer = exports.buildJsonPointer = void 0;
function buildJsonPointer(fragments) {
return ('/' +
fragments
.map((f) => {
return f.replace(/~/g, '~0').replace(/\//g, '~1');
})
.join('/'));
}
exports.buildJsonPointer = buildJsonPointer;
function joinJsonPointer(root, ...others) {
if (root == '/') {
return buildJsonPointer(others);
}
return (root + buildJsonPointer(others));
}
exports.joinJsonPointer = joinJsonPointer;
function parseJsonPointer(pointer) {
if (pointer === '') {
return [];
}
if (pointer.charAt(0) !== '/') {
throw new Error('Relative pointer: ' + pointer);
}
return pointer
.substring(1)
.split(/\//)
.map((str) => str.replace(/~1/g, '/').replace(/~0/g, '~'));
}
exports.parseJsonPointer = parseJsonPointer;

View file

@ -0,0 +1,79 @@
/**
* @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 { ValidateFunction } from 'ajv';
import { Observable } from 'rxjs';
import { BaseException } from '../../exception';
import { JsonObject } from '../utils';
import { JsonVisitor, PromptProvider, SchemaFormat, SchemaRegistry, SchemaValidator, SchemaValidatorError, SmartDefaultProvider } from './interface';
import { JsonSchema } from './schema';
export type UriHandler = (uri: string) => Observable<JsonObject> | Promise<JsonObject> | null | undefined;
export declare class SchemaValidationException extends BaseException {
readonly errors: SchemaValidatorError[];
constructor(errors?: SchemaValidatorError[], baseMessage?: string);
static createMessages(errors?: SchemaValidatorError[]): string[];
}
export declare class CoreSchemaRegistry implements SchemaRegistry {
private _ajv;
private _uriCache;
private _uriHandlers;
private _pre;
private _post;
private _currentCompilationSchemaInfo?;
private _smartDefaultKeyword;
private _promptProvider?;
private _sourceMap;
constructor(formats?: SchemaFormat[]);
private _fetch;
/**
* Add a transformation step before the validation of any Json.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPreTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void;
/**
* Add a transformation step after the validation of any Json. The JSON will not be validated
* after the POST, so if transformations are not compatible with the Schema it will not result
* in an error.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPostTransform(visitor: JsonVisitor, deps?: JsonVisitor[]): void;
protected _resolver(ref: string, validate?: ValidateFunction): {
context?: ValidateFunction;
schema?: JsonObject;
};
/**
* Flatten the Schema, resolving and replacing all the refs. Makes it into a synchronous schema
* that is also easier to traverse. Does not cache the result.
*
* Producing a flatten schema document does not in all cases produce a schema with identical behavior to the original.
* See: https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.appendix.B.2
*
* @param schema The schema or URI to flatten.
* @returns An Observable of the flattened schema object.
* @private since 11.2 without replacement.
*/
ɵflatten(schema: JsonObject): Promise<JsonObject>;
/**
* Compile and return a validation function for the Schema.
*
* @param schema The schema to validate. If a string, will fetch the schema before compiling it
* (using schema as a URI).
*/
compile(schema: JsonSchema): Promise<SchemaValidator>;
private _compile;
addFormat(format: SchemaFormat): void;
addSmartDefaultProvider<T>(source: string, provider: SmartDefaultProvider<T>): void;
registerUriHandler(handler: UriHandler): void;
usePromptProvider(provider: PromptProvider): void;
private _applyPrompts;
private static _set;
private _applySmartDefaults;
useXDeprecatedProvider(onUsage: (message: string) => void): void;
private normalizeDataPathArr;
}

View file

@ -0,0 +1,553 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CoreSchemaRegistry = exports.SchemaValidationException = void 0;
const ajv_1 = __importDefault(require("ajv"));
const ajv_formats_1 = __importDefault(require("ajv-formats"));
const http = __importStar(require("http"));
const https = __importStar(require("https"));
const rxjs_1 = require("rxjs");
const Url = __importStar(require("url"));
const exception_1 = require("../../exception");
const utils_1 = require("../../utils");
const utils_2 = require("../utils");
const utility_1 = require("./utility");
const visitor_1 = require("./visitor");
class SchemaValidationException extends exception_1.BaseException {
errors;
constructor(errors, baseMessage = 'Schema validation failed with the following errors:') {
if (!errors || errors.length === 0) {
super('Schema validation failed.');
this.errors = [];
return;
}
const messages = SchemaValidationException.createMessages(errors);
super(`${baseMessage}\n ${messages.join('\n ')}`);
this.errors = errors;
}
static createMessages(errors) {
if (!errors || errors.length === 0) {
return [];
}
const messages = errors.map((err) => {
let message = `Data path ${JSON.stringify(err.instancePath)} ${err.message}`;
if (err.params) {
switch (err.keyword) {
case 'additionalProperties':
message += `(${err.params.additionalProperty})`;
break;
case 'enum':
message += `. Allowed values are: ${err.params.allowedValues
?.map((v) => `"${v}"`)
.join(', ')}`;
break;
}
}
return message + '.';
});
return messages;
}
}
exports.SchemaValidationException = SchemaValidationException;
class CoreSchemaRegistry {
_ajv;
_uriCache = new Map();
_uriHandlers = new Set();
_pre = new utils_1.PartiallyOrderedSet();
_post = new utils_1.PartiallyOrderedSet();
_currentCompilationSchemaInfo;
_smartDefaultKeyword = false;
_promptProvider;
_sourceMap = new Map();
constructor(formats = []) {
this._ajv = new ajv_1.default({
strict: false,
loadSchema: (uri) => this._fetch(uri),
passContext: true,
});
(0, ajv_formats_1.default)(this._ajv);
for (const format of formats) {
this.addFormat(format);
}
}
async _fetch(uri) {
const maybeSchema = this._uriCache.get(uri);
if (maybeSchema) {
return maybeSchema;
}
// Try all handlers, one after the other.
for (const handler of this._uriHandlers) {
let handlerResult = handler(uri);
if (handlerResult === null || handlerResult === undefined) {
continue;
}
if ((0, rxjs_1.isObservable)(handlerResult)) {
handlerResult = (0, rxjs_1.lastValueFrom)(handlerResult);
}
const value = await handlerResult;
this._uriCache.set(uri, value);
return value;
}
// If none are found, handle using http client.
return new Promise((resolve, reject) => {
const url = new Url.URL(uri);
const client = url.protocol === 'https:' ? https : http;
client.get(url, (res) => {
if (!res.statusCode || res.statusCode >= 300) {
// Consume the rest of the data to free memory.
res.resume();
reject(new Error(`Request failed. Status Code: ${res.statusCode}`));
}
else {
res.setEncoding('utf8');
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const json = JSON.parse(data);
this._uriCache.set(uri, json);
resolve(json);
}
catch (err) {
reject(err);
}
});
}
});
});
}
/**
* Add a transformation step before the validation of any Json.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPreTransform(visitor, deps) {
this._pre.add(visitor, deps);
}
/**
* Add a transformation step after the validation of any Json. The JSON will not be validated
* after the POST, so if transformations are not compatible with the Schema it will not result
* in an error.
* @param {JsonVisitor} visitor The visitor to transform every value.
* @param {JsonVisitor[]} deps A list of other visitors to run before.
*/
addPostTransform(visitor, deps) {
this._post.add(visitor, deps);
}
_resolver(ref, validate) {
if (!validate || !ref) {
return {};
}
const schema = validate.schemaEnv.root.schema;
const id = typeof schema === 'object' ? schema.$id : null;
let fullReference = ref;
if (typeof id === 'string') {
fullReference = Url.resolve(id, ref);
if (ref.startsWith('#')) {
fullReference = id + fullReference;
}
}
const resolvedSchema = this._ajv.getSchema(fullReference);
return {
context: resolvedSchema?.schemaEnv.validate,
schema: resolvedSchema?.schema,
};
}
/**
* Flatten the Schema, resolving and replacing all the refs. Makes it into a synchronous schema
* that is also easier to traverse. Does not cache the result.
*
* Producing a flatten schema document does not in all cases produce a schema with identical behavior to the original.
* See: https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.appendix.B.2
*
* @param schema The schema or URI to flatten.
* @returns An Observable of the flattened schema object.
* @private since 11.2 without replacement.
*/
async ɵflatten(schema) {
this._ajv.removeSchema(schema);
this._currentCompilationSchemaInfo = undefined;
const validate = await this._ajv.compileAsync(schema);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
function visitor(current, pointer, parentSchema, index) {
if (current &&
parentSchema &&
index &&
(0, utils_2.isJsonObject)(current) &&
Object.prototype.hasOwnProperty.call(current, '$ref') &&
typeof current['$ref'] == 'string') {
const resolved = self._resolver(current['$ref'], validate);
if (resolved.schema) {
parentSchema[index] = resolved.schema;
}
}
}
const schemaCopy = (0, utils_1.deepCopy)(validate.schema);
(0, visitor_1.visitJsonSchema)(schemaCopy, visitor);
return schemaCopy;
}
/**
* Compile and return a validation function for the Schema.
*
* @param schema The schema to validate. If a string, will fetch the schema before compiling it
* (using schema as a URI).
*/
async compile(schema) {
const validate = await this._compile(schema);
return (value, options) => validate(value, options);
}
async _compile(schema) {
if (typeof schema === 'boolean') {
return async (data) => ({ success: schema, data });
}
const schemaInfo = {
smartDefaultRecord: new Map(),
promptDefinitions: [],
};
this._ajv.removeSchema(schema);
let validator;
try {
this._currentCompilationSchemaInfo = schemaInfo;
validator = this._ajv.compile(schema);
}
catch (e) {
// This should eventually be refactored so that we we handle race condition where the same schema is validated at the same time.
if (!(e instanceof ajv_1.default.MissingRefError)) {
throw e;
}
validator = await this._ajv.compileAsync(schema);
}
finally {
this._currentCompilationSchemaInfo = undefined;
}
return async (data, options) => {
const validationOptions = {
withPrompts: true,
applyPostTransforms: true,
applyPreTransforms: true,
...options,
};
const validationContext = {
promptFieldsWithValue: new Set(),
};
// Apply pre-validation transforms
if (validationOptions.applyPreTransforms) {
for (const visitor of this._pre.values()) {
data = await (0, rxjs_1.lastValueFrom)((0, visitor_1.visitJson)(data, visitor, schema, this._resolver.bind(this), validator));
}
}
// Apply smart defaults
await this._applySmartDefaults(data, schemaInfo.smartDefaultRecord);
// Apply prompts
if (validationOptions.withPrompts) {
const visitor = (value, pointer) => {
if (value !== undefined) {
validationContext.promptFieldsWithValue.add(pointer);
}
return value;
};
if (typeof schema === 'object') {
await (0, rxjs_1.lastValueFrom)((0, visitor_1.visitJson)(data, visitor, schema, this._resolver.bind(this), validator));
}
const definitions = schemaInfo.promptDefinitions.filter((def) => !validationContext.promptFieldsWithValue.has(def.id));
if (definitions.length > 0) {
await this._applyPrompts(data, definitions);
}
}
// Validate using ajv
try {
const success = await validator.call(validationContext, data);
if (!success) {
return { data, success, errors: validator.errors ?? [] };
}
}
catch (error) {
if (error instanceof ajv_1.default.ValidationError) {
return { data, success: false, errors: error.errors };
}
throw error;
}
// Apply post-validation transforms
if (validationOptions.applyPostTransforms) {
for (const visitor of this._post.values()) {
data = await (0, rxjs_1.lastValueFrom)((0, visitor_1.visitJson)(data, visitor, schema, this._resolver.bind(this), validator));
}
}
return { data, success: true };
};
}
addFormat(format) {
this._ajv.addFormat(format.name, format.formatter);
}
addSmartDefaultProvider(source, provider) {
if (this._sourceMap.has(source)) {
throw new Error(source);
}
this._sourceMap.set(source, provider);
if (!this._smartDefaultKeyword) {
this._smartDefaultKeyword = true;
this._ajv.addKeyword({
keyword: '$default',
errors: false,
valid: true,
compile: (schema, _parentSchema, it) => {
const compilationSchemInfo = this._currentCompilationSchemaInfo;
if (compilationSchemInfo === undefined) {
return () => true;
}
// We cheat, heavily.
const pathArray = this.normalizeDataPathArr(it);
compilationSchemInfo.smartDefaultRecord.set(JSON.stringify(pathArray), schema);
return () => true;
},
metaSchema: {
type: 'object',
properties: {
'$source': { type: 'string' },
},
additionalProperties: true,
required: ['$source'],
},
});
}
}
registerUriHandler(handler) {
this._uriHandlers.add(handler);
}
usePromptProvider(provider) {
const isSetup = !!this._promptProvider;
this._promptProvider = provider;
if (isSetup) {
return;
}
this._ajv.addKeyword({
keyword: 'x-prompt',
errors: false,
valid: true,
compile: (schema, parentSchema, it) => {
const compilationSchemInfo = this._currentCompilationSchemaInfo;
if (!compilationSchemInfo) {
return () => true;
}
const path = '/' + this.normalizeDataPathArr(it).join('/');
let type;
let items;
let message;
if (typeof schema == 'string') {
message = schema;
}
else {
message = schema.message;
type = schema.type;
items = schema.items;
}
const propertyTypes = (0, utility_1.getTypesOfSchema)(parentSchema);
if (!type) {
if (propertyTypes.size === 1 && propertyTypes.has('boolean')) {
type = 'confirmation';
}
else if (Array.isArray(parentSchema.enum)) {
type = 'list';
}
else if (propertyTypes.size === 1 &&
propertyTypes.has('array') &&
parentSchema.items &&
Array.isArray(parentSchema.items.enum)) {
type = 'list';
}
else {
type = 'input';
}
}
let multiselect;
if (type === 'list') {
multiselect =
schema.multiselect === undefined
? propertyTypes.size === 1 && propertyTypes.has('array')
: schema.multiselect;
const enumValues = multiselect
? parentSchema.items &&
parentSchema.items.enum
: parentSchema.enum;
if (!items && Array.isArray(enumValues)) {
items = [];
for (const value of enumValues) {
if (typeof value == 'string') {
items.push(value);
}
else if (typeof value == 'object') {
// Invalid
}
else {
items.push({ label: value.toString(), value });
}
}
}
}
const definition = {
id: path,
type,
message,
raw: schema,
items,
multiselect,
propertyTypes,
default: typeof parentSchema.default == 'object' &&
parentSchema.default !== null &&
!Array.isArray(parentSchema.default)
? undefined
: parentSchema.default,
async validator(data) {
try {
const result = await it.self.validate(parentSchema, data);
// If the schema is sync then false will be returned on validation failure
if (result) {
return result;
}
else if (it.self.errors?.length) {
// Validation errors will be present on the Ajv instance when sync
return it.self.errors[0].message;
}
}
catch (e) {
const validationError = e;
// If the schema is async then an error will be thrown on validation failure
if (Array.isArray(validationError.errors) && validationError.errors.length) {
return validationError.errors[0].message;
}
}
return false;
},
};
compilationSchemInfo.promptDefinitions.push(definition);
return function () {
// If 'this' is undefined in the call, then it defaults to the global
// 'this'.
if (this && this.promptFieldsWithValue) {
this.promptFieldsWithValue.add(path);
}
return true;
};
},
metaSchema: {
oneOf: [
{ type: 'string' },
{
type: 'object',
properties: {
'type': { type: 'string' },
'message': { type: 'string' },
},
additionalProperties: true,
required: ['message'],
},
],
},
});
}
async _applyPrompts(data, prompts) {
const provider = this._promptProvider;
if (!provider) {
return;
}
const answers = await (0, rxjs_1.lastValueFrom)((0, rxjs_1.from)(provider(prompts)));
for (const path in answers) {
const pathFragments = path.split('/').slice(1);
CoreSchemaRegistry._set(data, pathFragments, answers[path], null, undefined, true);
}
}
static _set(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data, fragments, value,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parent = null, parentProperty, force) {
for (let index = 0; index < fragments.length; index++) {
const fragment = fragments[index];
if (/^i\d+$/.test(fragment)) {
if (!Array.isArray(data)) {
return;
}
for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {
CoreSchemaRegistry._set(data[dataIndex], fragments.slice(index + 1), value, data, `${dataIndex}`);
}
return;
}
if (!data && parent !== null && parentProperty) {
data = parent[parentProperty] = {};
}
parent = data;
parentProperty = fragment;
data = data[fragment];
}
if (parent && parentProperty && (force || parent[parentProperty] === undefined)) {
parent[parentProperty] = value;
}
}
async _applySmartDefaults(data, smartDefaults) {
for (const [pointer, schema] of smartDefaults.entries()) {
const fragments = JSON.parse(pointer);
const source = this._sourceMap.get(schema.$source);
if (!source) {
continue;
}
let value = source(schema);
if ((0, rxjs_1.isObservable)(value)) {
value = (await (0, rxjs_1.lastValueFrom)(value));
}
CoreSchemaRegistry._set(data, fragments, value);
}
}
useXDeprecatedProvider(onUsage) {
this._ajv.addKeyword({
keyword: 'x-deprecated',
validate: (schema, _data, _parentSchema, dataCxt) => {
if (schema) {
onUsage(`Option "${dataCxt?.parentDataProperty}" is deprecated${typeof schema == 'string' ? ': ' + schema : '.'}`);
}
return true;
},
errors: false,
});
}
normalizeDataPathArr(it) {
return it.dataPathArr
.slice(1, it.dataLevel + 1)
.map((p) => (typeof p === 'number' ? p : p.str.replace(/"/g, '')));
}
}
exports.CoreSchemaRegistry = CoreSchemaRegistry;

View file

@ -0,0 +1,22 @@
/**
* @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 { JsonObject } from '../utils';
/**
* A specialized interface for JsonSchema (to come). JsonSchemas are also JsonObject.
*
* @public
*/
export type JsonSchema = JsonObject | boolean;
export declare function isJsonSchema(value: unknown): value is JsonSchema;
/**
* Return a schema that is the merge of all subschemas, ie. it should validate all the schemas
* that were passed in. It is possible to make an invalid schema this way, e.g. by using
* `mergeSchemas({ type: 'number' }, { type: 'string' })`, which will never validate.
* @param schemas All schemas to be merged.
*/
export declare function mergeSchemas(...schemas: (JsonSchema | undefined)[]): JsonSchema;

View file

@ -0,0 +1,52 @@
"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 });
exports.mergeSchemas = exports.isJsonSchema = void 0;
const utils_1 = require("../utils");
function isJsonSchema(value) {
return (0, utils_1.isJsonObject)(value) || value === false || value === true;
}
exports.isJsonSchema = isJsonSchema;
/**
* Return a schema that is the merge of all subschemas, ie. it should validate all the schemas
* that were passed in. It is possible to make an invalid schema this way, e.g. by using
* `mergeSchemas({ type: 'number' }, { type: 'string' })`, which will never validate.
* @param schemas All schemas to be merged.
*/
function mergeSchemas(...schemas) {
return schemas.reduce((prev, curr) => {
if (curr === undefined) {
return prev;
}
if (prev === false || curr === false) {
return false;
}
else if (prev === true) {
return curr;
}
else if (curr === true) {
return prev;
}
else if (Array.isArray(prev.allOf)) {
if (Array.isArray(curr.allOf)) {
return { ...prev, allOf: [...prev.allOf, ...curr.allOf] };
}
else {
return { ...prev, allOf: [...prev.allOf, curr] };
}
}
else if (Array.isArray(curr.allOf)) {
return { ...prev, allOf: [prev, ...curr.allOf] };
}
else {
return { ...prev, allOf: [prev, curr] };
}
}, true);
}
exports.mergeSchemas = mergeSchemas;

View file

@ -0,0 +1,11 @@
/**
* @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 { JsonValue } from '../utils';
import { JsonPointer } from './interface';
import { JsonSchema } from './schema';
export declare function addUndefinedDefaults(value: JsonValue, _pointer: JsonPointer, schema?: JsonSchema): JsonValue;

View file

@ -0,0 +1,94 @@
"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 });
exports.addUndefinedDefaults = void 0;
const utils_1 = require("../utils");
const utility_1 = require("./utility");
function addUndefinedDefaults(value, _pointer, schema) {
if (typeof schema === 'boolean' || schema === undefined) {
return value;
}
value ??= schema.default;
const types = (0, utility_1.getTypesOfSchema)(schema);
if (types.size === 0) {
return value;
}
let type;
if (types.size === 1) {
// only one potential type
type = Array.from(types)[0];
}
else if (types.size === 2 && types.has('array') && types.has('object')) {
// need to create one of them and array is simpler
type = 'array';
}
else if (schema.properties && types.has('object')) {
// assume object
type = 'object';
}
else if (schema.items && types.has('array')) {
// assume array
type = 'array';
}
else {
// anything else needs to be checked by the consumer anyway
return value;
}
if (type === 'array') {
return value == undefined ? [] : value;
}
if (type === 'object') {
let newValue;
if (value == undefined) {
newValue = {};
}
else if ((0, utils_1.isJsonObject)(value)) {
newValue = value;
}
else {
return value;
}
if (!(0, utils_1.isJsonObject)(schema.properties)) {
return newValue;
}
for (const [propName, schemaObject] of Object.entries(schema.properties)) {
if (propName === '$schema' || !(0, utils_1.isJsonObject)(schemaObject)) {
continue;
}
const value = newValue[propName];
if (value === undefined) {
newValue[propName] = schemaObject.default;
}
else if ((0, utils_1.isJsonObject)(value)) {
// Basic support for oneOf and anyOf.
const propertySchemas = schemaObject.oneOf || schemaObject.anyOf;
const allProperties = Object.keys(value);
// Locate a schema which declares all the properties that the object contains.
const adjustedSchema = (0, utils_1.isJsonArray)(propertySchemas) &&
propertySchemas.find((s) => {
if (!(0, utils_1.isJsonObject)(s)) {
return false;
}
const schemaType = (0, utility_1.getTypesOfSchema)(s);
if (schemaType.size === 1 && schemaType.has('object') && (0, utils_1.isJsonObject)(s.properties)) {
const properties = Object.keys(s.properties);
return allProperties.every((key) => properties.includes(key));
}
return false;
});
if (adjustedSchema && (0, utils_1.isJsonObject)(adjustedSchema)) {
newValue[propName] = addUndefinedDefaults(value, _pointer, adjustedSchema);
}
}
}
return newValue;
}
return value;
}
exports.addUndefinedDefaults = addUndefinedDefaults;

View file

@ -0,0 +1,9 @@
/**
* @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 { JsonSchema } from './schema';
export declare function getTypesOfSchema(schema: JsonSchema): Set<string>;

View file

@ -0,0 +1,88 @@
"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 });
exports.getTypesOfSchema = void 0;
const utils_1 = require("../utils");
const allTypes = ['string', 'integer', 'number', 'object', 'array', 'boolean', 'null'];
function getTypesOfSchema(schema) {
if (!schema) {
return new Set();
}
if (schema === true) {
return new Set(allTypes);
}
let potentials;
if (typeof schema.type === 'string') {
potentials = new Set([schema.type]);
}
else if (Array.isArray(schema.type)) {
potentials = new Set(schema.type);
}
else if ((0, utils_1.isJsonArray)(schema.enum)) {
potentials = new Set();
// Gather the type of each enum values, and use that as a starter for potential types.
for (const v of schema.enum) {
switch (typeof v) {
case 'string':
case 'number':
case 'boolean':
potentials.add(typeof v);
break;
case 'object':
if (Array.isArray(v)) {
potentials.add('array');
}
else if (v === null) {
potentials.add('null');
}
else {
potentials.add('object');
}
break;
}
}
}
else {
potentials = new Set(allTypes);
}
if ((0, utils_1.isJsonObject)(schema.not)) {
const notTypes = getTypesOfSchema(schema.not);
potentials = new Set([...potentials].filter((p) => !notTypes.has(p)));
}
if (Array.isArray(schema.allOf)) {
for (const sub of schema.allOf) {
const types = getTypesOfSchema(sub);
potentials = new Set([...types].filter((t) => potentials.has(t)));
}
}
if (Array.isArray(schema.oneOf)) {
let options = new Set();
for (const sub of schema.oneOf) {
const types = getTypesOfSchema(sub);
options = new Set([...options, ...types]);
}
potentials = new Set([...options].filter((o) => potentials.has(o)));
}
if (Array.isArray(schema.anyOf)) {
let options = new Set();
for (const sub of schema.anyOf) {
const types = getTypesOfSchema(sub);
options = new Set([...options, ...types]);
}
potentials = new Set([...options].filter((o) => potentials.has(o)));
}
if (schema.properties) {
potentials.add('object');
}
else if (schema.items) {
potentials.add('array');
}
return potentials;
}
exports.getTypesOfSchema = getTypesOfSchema;

View file

@ -0,0 +1,34 @@
/**
* @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 { Observable } from 'rxjs';
import { JsonObject, JsonValue } from '../utils';
import { JsonSchemaVisitor, JsonVisitor } from './interface';
import { JsonSchema } from './schema';
export interface ReferenceResolver<ContextT> {
(ref: string, context?: ContextT): {
context?: ContextT;
schema?: JsonObject;
};
}
/**
* Visit all the properties in a JSON object, allowing to transform them. It supports calling
* properties synchronously or asynchronously (through Observables).
* The original object can be mutated or replaced entirely. In case where it's replaced, the new
* value is returned. When it's mutated though the original object will be changed.
*
* Please note it is possible to have an infinite loop here (which will result in a stack overflow)
* if you return 2 objects that references each others (or the same object all the time).
*
* @param {JsonValue} json The Json value to visit.
* @param {JsonVisitor} visitor A function that will be called on every items.
* @param {JsonObject} schema A JSON schema to pass through to the visitor (where possible).
* @param refResolver a function to resolve references in the schema.
* @returns {Observable< | undefined>} The observable of the new root, if the root changed.
*/
export declare function visitJson<ContextT>(json: JsonValue, visitor: JsonVisitor, schema?: JsonSchema, refResolver?: ReferenceResolver<ContextT>, context?: ContextT): Observable<JsonValue>;
export declare function visitJsonSchema(schema: JsonSchema, visitor: JsonSchemaVisitor): void;

View file

@ -0,0 +1,147 @@
"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 });
exports.visitJsonSchema = exports.visitJson = void 0;
const rxjs_1 = require("rxjs");
const pointer_1 = require("./pointer");
function _getObjectSubSchema(schema, key) {
if (typeof schema !== 'object' || schema === null) {
return undefined;
}
// Is it an object schema?
if (typeof schema.properties == 'object' || schema.type == 'object') {
if (typeof schema.properties == 'object' &&
typeof schema.properties[key] == 'object') {
return schema.properties[key];
}
if (typeof schema.additionalProperties == 'object') {
return schema.additionalProperties;
}
return undefined;
}
// Is it an array schema?
if (typeof schema.items == 'object' || schema.type == 'array') {
return typeof schema.items == 'object' ? schema.items : undefined;
}
return undefined;
}
function _visitJsonRecursive(json, visitor, ptr, schema, refResolver, context, root) {
if (schema === true || schema === false) {
// There's no schema definition, so just visit the JSON recursively.
schema = undefined;
}
// eslint-disable-next-line no-prototype-builtins
if (schema && schema.hasOwnProperty('$ref') && typeof schema['$ref'] == 'string') {
if (refResolver) {
const resolved = refResolver(schema['$ref'], context);
schema = resolved.schema;
context = resolved.context;
}
}
const value = visitor(json, ptr, schema, root);
return ((0, rxjs_1.isObservable)(value) ? value : (0, rxjs_1.of)(value)).pipe((0, rxjs_1.concatMap)((value) => {
if (Array.isArray(value)) {
return (0, rxjs_1.concat)((0, rxjs_1.from)(value).pipe((0, rxjs_1.mergeMap)((item, i) => {
return _visitJsonRecursive(item, visitor, (0, pointer_1.joinJsonPointer)(ptr, '' + i), _getObjectSubSchema(schema, '' + i), refResolver, context, root || value).pipe((0, rxjs_1.tap)((x) => (value[i] = x)));
}), (0, rxjs_1.ignoreElements)()), (0, rxjs_1.of)(value));
}
else if (typeof value == 'object' && value !== null) {
return (0, rxjs_1.concat)((0, rxjs_1.from)(Object.getOwnPropertyNames(value)).pipe((0, rxjs_1.mergeMap)((key) => {
return _visitJsonRecursive(value[key], visitor, (0, pointer_1.joinJsonPointer)(ptr, key), _getObjectSubSchema(schema, key), refResolver, context, root || value).pipe((0, rxjs_1.tap)((x) => {
const descriptor = Object.getOwnPropertyDescriptor(value, key);
if (descriptor && descriptor.writable && value[key] !== x) {
value[key] = x;
}
}));
}), (0, rxjs_1.ignoreElements)()), (0, rxjs_1.of)(value));
}
else {
return (0, rxjs_1.of)(value);
}
}));
}
/**
* Visit all the properties in a JSON object, allowing to transform them. It supports calling
* properties synchronously or asynchronously (through Observables).
* The original object can be mutated or replaced entirely. In case where it's replaced, the new
* value is returned. When it's mutated though the original object will be changed.
*
* Please note it is possible to have an infinite loop here (which will result in a stack overflow)
* if you return 2 objects that references each others (or the same object all the time).
*
* @param {JsonValue} json The Json value to visit.
* @param {JsonVisitor} visitor A function that will be called on every items.
* @param {JsonObject} schema A JSON schema to pass through to the visitor (where possible).
* @param refResolver a function to resolve references in the schema.
* @returns {Observable< | undefined>} The observable of the new root, if the root changed.
*/
function visitJson(json, visitor, schema, refResolver, context) {
return _visitJsonRecursive(json, visitor, (0, pointer_1.buildJsonPointer)([]), schema, refResolver, context);
}
exports.visitJson = visitJson;
function visitJsonSchema(schema, visitor) {
if (schema === false || schema === true) {
// Nothing to visit.
return;
}
const keywords = {
additionalItems: true,
items: true,
contains: true,
additionalProperties: true,
propertyNames: true,
not: true,
};
const arrayKeywords = {
items: true,
allOf: true,
anyOf: true,
oneOf: true,
};
const propsKeywords = {
definitions: true,
properties: true,
patternProperties: true,
additionalProperties: true,
dependencies: true,
items: true,
};
function _traverse(schema, jsonPtr, rootSchema, parentSchema, keyIndex) {
if (schema && typeof schema == 'object' && !Array.isArray(schema)) {
visitor(schema, jsonPtr, parentSchema, keyIndex);
for (const key of Object.keys(schema)) {
const sch = schema[key];
if (key in propsKeywords) {
if (sch && typeof sch == 'object') {
for (const prop of Object.keys(sch)) {
_traverse(sch[prop], (0, pointer_1.joinJsonPointer)(jsonPtr, key, prop), rootSchema, schema, prop);
}
}
}
else if (key in keywords) {
_traverse(sch, (0, pointer_1.joinJsonPointer)(jsonPtr, key), rootSchema, schema, key);
}
else if (key in arrayKeywords) {
if (Array.isArray(sch)) {
for (let i = 0; i < sch.length; i++) {
_traverse(sch[i], (0, pointer_1.joinJsonPointer)(jsonPtr, key, '' + i), rootSchema, sch, '' + i);
}
}
}
else if (Array.isArray(sch)) {
for (let i = 0; i < sch.length; i++) {
_traverse(sch[i], (0, pointer_1.joinJsonPointer)(jsonPtr, key, '' + i), rootSchema, sch, '' + i);
}
}
}
}
}
_traverse(schema, (0, pointer_1.buildJsonPointer)([]), schema);
}
exports.visitJsonSchema = visitJsonSchema;

15
my-app/node_modules/@angular-devkit/core/src/json/utils.d.ts generated vendored Executable file
View file

@ -0,0 +1,15 @@
/**
* @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
*/
export interface JsonArray extends Array<JsonValue> {
}
export interface JsonObject {
[prop: string]: JsonValue;
}
export type JsonValue = boolean | string | number | JsonArray | JsonObject | null;
export declare function isJsonObject(value: JsonValue): value is JsonObject;
export declare function isJsonArray(value: JsonValue): value is JsonArray;

18
my-app/node_modules/@angular-devkit/core/src/json/utils.js generated vendored Executable file
View file

@ -0,0 +1,18 @@
"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 });
exports.isJsonArray = exports.isJsonObject = void 0;
function isJsonObject(value) {
return value != null && typeof value === 'object' && !Array.isArray(value);
}
exports.isJsonObject = isJsonObject;
function isJsonArray(value) {
return Array.isArray(value);
}
exports.isJsonArray = isJsonArray;

View file

@ -0,0 +1,11 @@
/**
* @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 { Logger } from './logger';
export declare class IndentLogger extends Logger {
constructor(name: string, parent?: Logger | null, indentation?: string);
}

View file

@ -0,0 +1,40 @@
"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 });
exports.IndentLogger = void 0;
const rxjs_1 = require("rxjs");
const logger_1 = require("./logger");
/**
* Keep an map of indentation => array of indentations based on the level.
* This is to optimize calculating the prefix based on the indentation itself. Since most logs
* come from similar levels, and with similar indentation strings, this will be shared by all
* loggers. Also, string concatenation is expensive so performing concats for every log entries
* is expensive; this alleviates it.
*/
const indentationMap = {};
class IndentLogger extends logger_1.Logger {
constructor(name, parent = null, indentation = ' ') {
super(name, parent);
indentationMap[indentation] = indentationMap[indentation] || [''];
const indentMap = indentationMap[indentation];
this._observable = this._observable.pipe((0, rxjs_1.map)((entry) => {
const l = entry.path.filter((x) => !!x).length;
if (l >= indentMap.length) {
let current = indentMap[indentMap.length - 1];
while (l >= indentMap.length) {
current += indentation;
indentMap.push(current);
}
}
entry.message = indentMap[l] + entry.message.split(/\n/).join('\n' + indentMap[l]);
return entry;
}));
}
}
exports.IndentLogger = IndentLogger;

View file

@ -0,0 +1,12 @@
/**
* @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
*/
export * from './indent';
export * from './level';
export * from './logger';
export * from './null-logger';
export * from './transform-logger';

28
my-app/node_modules/@angular-devkit/core/src/logger/index.js generated vendored Executable file
View file

@ -0,0 +1,28 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./indent"), exports);
__exportStar(require("./level"), exports);
__exportStar(require("./logger"), exports);
__exportStar(require("./null-logger"), exports);
__exportStar(require("./transform-logger"), exports);

View file

@ -0,0 +1,28 @@
/**
* @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 { JsonObject } from '../json/utils';
import { LogLevel, Logger } from './logger';
export declare class LevelTransformLogger extends Logger {
readonly name: string;
readonly parent: Logger | null;
readonly levelTransform: (level: LogLevel) => LogLevel;
constructor(name: string, parent: Logger | null, levelTransform: (level: LogLevel) => LogLevel);
log(level: LogLevel, message: string, metadata?: JsonObject): void;
createChild(name: string): Logger;
}
export declare class LevelCapLogger extends LevelTransformLogger {
readonly name: string;
readonly parent: Logger | null;
readonly levelCap: LogLevel;
static levelMap: {
[cap: string]: {
[level: string]: string;
};
};
constructor(name: string, parent: Logger | null, levelCap: LogLevel);
}

50
my-app/node_modules/@angular-devkit/core/src/logger/level.js generated vendored Executable file
View file

@ -0,0 +1,50 @@
"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 });
exports.LevelCapLogger = exports.LevelTransformLogger = void 0;
const logger_1 = require("./logger");
class LevelTransformLogger extends logger_1.Logger {
name;
parent;
levelTransform;
constructor(name, parent = null, levelTransform) {
super(name, parent);
this.name = name;
this.parent = parent;
this.levelTransform = levelTransform;
}
log(level, message, metadata = {}) {
return super.log(this.levelTransform(level), message, metadata);
}
createChild(name) {
return new LevelTransformLogger(name, this, this.levelTransform);
}
}
exports.LevelTransformLogger = LevelTransformLogger;
class LevelCapLogger extends LevelTransformLogger {
name;
parent;
levelCap;
static levelMap = {
debug: { debug: 'debug', info: 'debug', warn: 'debug', error: 'debug', fatal: 'debug' },
info: { debug: 'debug', info: 'info', warn: 'info', error: 'info', fatal: 'info' },
warn: { debug: 'debug', info: 'info', warn: 'warn', error: 'warn', fatal: 'warn' },
error: { debug: 'debug', info: 'info', warn: 'warn', error: 'error', fatal: 'error' },
fatal: { debug: 'debug', info: 'info', warn: 'warn', error: 'error', fatal: 'fatal' },
};
constructor(name, parent = null, levelCap) {
super(name, parent, (level) => {
return (LevelCapLogger.levelMap[levelCap][level] || level);
});
this.name = name;
this.parent = parent;
this.levelCap = levelCap;
}
}
exports.LevelCapLogger = LevelCapLogger;

View file

@ -0,0 +1,55 @@
/**
* @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 { Observable, Operator, PartialObserver, Subject, Subscription } from 'rxjs';
import { JsonObject } from '../json/utils';
export interface LoggerMetadata extends JsonObject {
name: string;
path: string[];
}
export interface LogEntry extends LoggerMetadata {
level: LogLevel;
message: string;
timestamp: number;
}
export interface LoggerApi {
createChild(name: string): Logger;
log(level: LogLevel, message: string, metadata?: JsonObject): void;
debug(message: string, metadata?: JsonObject): void;
info(message: string, metadata?: JsonObject): void;
warn(message: string, metadata?: JsonObject): void;
error(message: string, metadata?: JsonObject): void;
fatal(message: string, metadata?: JsonObject): void;
}
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
export declare class Logger extends Observable<LogEntry> implements LoggerApi {
readonly name: string;
readonly parent: Logger | null;
protected readonly _subject: Subject<LogEntry>;
protected _metadata: LoggerMetadata;
private _obs;
private _subscription;
protected get _observable(): Observable<LogEntry>;
protected set _observable(v: Observable<LogEntry>);
constructor(name: string, parent?: Logger | null);
asApi(): LoggerApi;
createChild(name: string): Logger;
complete(): void;
log(level: LogLevel, message: string, metadata?: JsonObject): void;
next(entry: LogEntry): void;
debug(message: string, metadata?: JsonObject): void;
info(message: string, metadata?: JsonObject): void;
warn(message: string, metadata?: JsonObject): void;
error(message: string, metadata?: JsonObject): void;
fatal(message: string, metadata?: JsonObject): void;
toString(): string;
lift<R>(operator: Operator<LogEntry, R>): Observable<R>;
subscribe(): Subscription;
subscribe(observer: PartialObserver<LogEntry>): Subscription;
subscribe(next?: (value: LogEntry) => void, error?: (error: Error) => void, complete?: () => void): Subscription;
forEach(next: (value: LogEntry) => void, promiseCtor?: PromiseConstructorLike): Promise<void>;
}

122
my-app/node_modules/@angular-devkit/core/src/logger/logger.js generated vendored Executable file
View file

@ -0,0 +1,122 @@
"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 });
exports.Logger = void 0;
const rxjs_1 = require("rxjs");
class Logger extends rxjs_1.Observable {
name;
parent;
_subject = new rxjs_1.Subject();
_metadata;
_obs = rxjs_1.EMPTY;
_subscription = null;
get _observable() {
return this._obs;
}
set _observable(v) {
if (this._subscription) {
this._subscription.unsubscribe();
}
this._obs = v;
if (this.parent) {
this._subscription = this.subscribe((value) => {
if (this.parent) {
this.parent._subject.next(value);
}
}, (error) => {
if (this.parent) {
this.parent._subject.error(error);
}
}, () => {
if (this._subscription) {
this._subscription.unsubscribe();
}
this._subscription = null;
});
}
}
constructor(name, parent = null) {
super();
this.name = name;
this.parent = parent;
const path = [];
let p = parent;
while (p) {
path.push(p.name);
p = p.parent;
}
this._metadata = { name, path };
this._observable = this._subject.asObservable();
if (this.parent && this.parent._subject) {
// When the parent completes, complete us as well.
this.parent._subject.subscribe(undefined, undefined, () => this.complete());
}
}
asApi() {
return {
createChild: (name) => this.createChild(name),
log: (level, message, metadata) => {
return this.log(level, message, metadata);
},
debug: (message, metadata) => this.debug(message, metadata),
info: (message, metadata) => this.info(message, metadata),
warn: (message, metadata) => this.warn(message, metadata),
error: (message, metadata) => this.error(message, metadata),
fatal: (message, metadata) => this.fatal(message, metadata),
};
}
createChild(name) {
return new this.constructor(name, this);
}
complete() {
this._subject.complete();
}
log(level, message, metadata = {}) {
const entry = Object.assign({}, metadata, this._metadata, {
level,
message,
timestamp: +Date.now(),
});
this._subject.next(entry);
}
next(entry) {
this._subject.next(entry);
}
debug(message, metadata = {}) {
return this.log('debug', message, metadata);
}
info(message, metadata = {}) {
return this.log('info', message, metadata);
}
warn(message, metadata = {}) {
return this.log('warn', message, metadata);
}
error(message, metadata = {}) {
return this.log('error', message, metadata);
}
fatal(message, metadata = {}) {
return this.log('fatal', message, metadata);
}
toString() {
return `<Logger(${this.name})>`;
}
lift(operator) {
return this._observable.lift(operator);
}
subscribe(_observerOrNext, _error, _complete) {
// eslint-disable-next-line prefer-spread
return this._observable.subscribe.apply(this._observable,
// eslint-disable-next-line prefer-rest-params
arguments);
}
forEach(next, promiseCtor = Promise) {
return this._observable.forEach(next, promiseCtor);
}
}
exports.Logger = Logger;

View file

@ -0,0 +1,12 @@
/**
* @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 { Logger, LoggerApi } from './logger';
export declare class NullLogger extends Logger {
constructor(parent?: Logger | null);
asApi(): LoggerApi;
}

View file

@ -0,0 +1,30 @@
"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 });
exports.NullLogger = void 0;
const rxjs_1 = require("rxjs");
const logger_1 = require("./logger");
class NullLogger extends logger_1.Logger {
constructor(parent = null) {
super('', parent);
this._observable = rxjs_1.EMPTY;
}
asApi() {
return {
createChild: () => new NullLogger(this),
log() { },
debug() { },
info() { },
warn() { },
error() { },
fatal() { },
};
}
}
exports.NullLogger = NullLogger;

View file

@ -0,0 +1,12 @@
/**
* @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 { Observable } from 'rxjs';
import { LogEntry, Logger } from './logger';
export declare class TransformLogger extends Logger {
constructor(name: string, transform: (stream: Observable<LogEntry>) => Observable<LogEntry>, parent?: Logger | null);
}

View file

@ -0,0 +1,18 @@
"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 });
exports.TransformLogger = void 0;
const logger_1 = require("./logger");
class TransformLogger extends logger_1.Logger {
constructor(name, transform, parent = null) {
super(name, parent);
this._observable = transform(this._observable);
}
}
exports.TransformLogger = TransformLogger;

View file

@ -0,0 +1,15 @@
/**
* @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 * as tags from './literals';
import * as strings from './strings';
export * from './object';
export * from './template';
export * from './partially-ordered-set';
export * from './priority-queue';
export * from './lang';
export { tags, strings };

45
my-app/node_modules/@angular-devkit/core/src/utils/index.js generated vendored Executable file
View file

@ -0,0 +1,45 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.strings = exports.tags = void 0;
const tags = __importStar(require("./literals"));
exports.tags = tags;
const strings = __importStar(require("./strings"));
exports.strings = strings;
__exportStar(require("./object"), exports);
__exportStar(require("./template"), exports);
__exportStar(require("./partially-ordered-set"), exports);
__exportStar(require("./priority-queue"), exports);
__exportStar(require("./lang"), exports);

11
my-app/node_modules/@angular-devkit/core/src/utils/lang.d.ts generated vendored Executable file
View file

@ -0,0 +1,11 @@
/**
* @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
*/
/**
* Determine if the argument is shaped like a Promise
*/
export declare function isPromise(obj: any): obj is Promise<any>;

21
my-app/node_modules/@angular-devkit/core/src/utils/lang.js generated vendored Executable file
View file

@ -0,0 +1,21 @@
"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 });
exports.isPromise = void 0;
// Borrowed from @angular/core
/**
* Determine if the argument is shaped like a Promise
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isPromise(obj) {
// allow any Promise/A+ compliant thenable.
// It's up to the caller to ensure that obj.then conforms to the spec
return !!obj && typeof obj.then === 'function';
}
exports.isPromise = isPromise;

View file

@ -0,0 +1,15 @@
/**
* @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
*/
export interface TemplateTag<R = string> {
(template: TemplateStringsArray, ...substitutions: any[]): R;
}
export declare function oneLine(strings: TemplateStringsArray, ...values: any[]): string;
export declare function indentBy(indentations: number): TemplateTag;
export declare function stripIndent(strings: TemplateStringsArray, ...values: any[]): string;
export declare function stripIndents(strings: TemplateStringsArray, ...values: any[]): string;
export declare function trimNewlines(strings: TemplateStringsArray, ...values: any[]): string;

View file

@ -0,0 +1,59 @@
"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 });
exports.trimNewlines = exports.stripIndents = exports.stripIndent = exports.indentBy = exports.oneLine = void 0;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function oneLine(strings, ...values) {
const endResult = String.raw(strings, ...values);
return endResult.replace(/(?:\r?\n(?:\s*))+/gm, ' ').trim();
}
exports.oneLine = oneLine;
function indentBy(indentations) {
let i = '';
while (indentations--) {
i += ' ';
}
return (strings, ...values) => {
return i + stripIndent(strings, ...values).replace(/\n/g, '\n' + i);
};
}
exports.indentBy = indentBy;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function stripIndent(strings, ...values) {
const endResult = String.raw(strings, ...values);
// remove the shortest leading indentation from each line
const match = endResult.match(/^[ \t]*(?=\S)/gm);
// return early if there's nothing to strip
if (match === null) {
return endResult;
}
const indent = Math.min(...match.map((el) => el.length));
const regexp = new RegExp('^[ \\t]{' + indent + '}', 'gm');
return (indent > 0 ? endResult.replace(regexp, '') : endResult).trim();
}
exports.stripIndent = stripIndent;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function stripIndents(strings, ...values) {
return String.raw(strings, ...values)
.split('\n')
.map((line) => line.trim())
.join('\n')
.trim();
}
exports.stripIndents = stripIndents;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function trimNewlines(strings, ...values) {
const endResult = String.raw(strings, ...values);
return (endResult
// Remove the newline at the start.
.replace(/^(?:\r?\n)+/, '')
// Remove the newline at the end and following whitespace.
.replace(/(?:\r?\n(?:\s*))$/, ''));
}
exports.trimNewlines = trimNewlines;

View file

@ -0,0 +1,8 @@
/**
* @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
*/
export declare function deepCopy<T>(value: T): T;

37
my-app/node_modules/@angular-devkit/core/src/utils/object.js generated vendored Executable file
View file

@ -0,0 +1,37 @@
"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 });
exports.deepCopy = void 0;
const copySymbol = Symbol();
function deepCopy(value) {
if (Array.isArray(value)) {
return value.map((o) => deepCopy(o));
}
else if (value && typeof value === 'object') {
const valueCasted = value;
if (valueCasted[copySymbol]) {
// This is a circular dependency. Just return the cloned value.
return valueCasted[copySymbol];
}
if (valueCasted['toJSON']) {
return JSON.parse(valueCasted['toJSON']());
}
const copy = Object.create(Object.getPrototypeOf(valueCasted));
valueCasted[copySymbol] = copy;
for (const key of Object.getOwnPropertyNames(valueCasted)) {
copy[key] = deepCopy(valueCasted[key]);
}
delete valueCasted[copySymbol];
return copy;
}
else {
return value;
}
}
exports.deepCopy = deepCopy;

View file

@ -0,0 +1,38 @@
/**
* @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 { BaseException } from '../exception';
export declare class DependencyNotFoundException extends BaseException {
constructor();
}
export declare class CircularDependencyFoundException extends BaseException {
constructor();
}
export declare class PartiallyOrderedSet<T> implements Set<T> {
private _items;
protected _checkCircularDependencies(item: T, deps: Set<T>): void;
clear(): void;
has(item: T): boolean;
get size(): number;
forEach(callbackfn: (value: T, value2: T, set: PartiallyOrderedSet<T>) => void, thisArg?: any): void;
/**
* Returns an iterable of [v,v] pairs for every value `v` in the set.
*/
entries(): IterableIterator<[T, T]>;
/**
* Despite its name, returns an iterable of the values in the set,
*/
keys(): IterableIterator<T>;
/**
* Returns an iterable of values in the set.
*/
values(): IterableIterator<T>;
add(item: T, deps?: Set<T> | T[]): this;
delete(item: T): boolean;
[Symbol.iterator](): Generator<T, void, unknown>;
get [Symbol.toStringTag](): 'Set';
}

View file

@ -0,0 +1,143 @@
"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 });
exports.PartiallyOrderedSet = exports.CircularDependencyFoundException = exports.DependencyNotFoundException = void 0;
const exception_1 = require("../exception");
class DependencyNotFoundException extends exception_1.BaseException {
constructor() {
super('One of the dependencies is not part of the set.');
}
}
exports.DependencyNotFoundException = DependencyNotFoundException;
class CircularDependencyFoundException extends exception_1.BaseException {
constructor() {
super('Circular dependencies found.');
}
}
exports.CircularDependencyFoundException = CircularDependencyFoundException;
class PartiallyOrderedSet {
_items = new Map();
_checkCircularDependencies(item, deps) {
if (deps.has(item)) {
throw new CircularDependencyFoundException();
}
deps.forEach((dep) => this._checkCircularDependencies(item, this._items.get(dep) || new Set()));
}
clear() {
this._items.clear();
}
has(item) {
return this._items.has(item);
}
get size() {
return this._items.size;
}
forEach(callbackfn, thisArg) {
for (const x of this) {
callbackfn.call(thisArg, x, x, this);
}
}
/**
* Returns an iterable of [v,v] pairs for every value `v` in the set.
*/
*entries() {
for (const item of this) {
yield [item, item];
}
}
/**
* Despite its name, returns an iterable of the values in the set,
*/
keys() {
return this.values();
}
/**
* Returns an iterable of values in the set.
*/
values() {
return this[Symbol.iterator]();
}
add(item, deps = new Set()) {
if (Array.isArray(deps)) {
deps = new Set(deps);
}
// Verify item is not already in the set.
if (this._items.has(item)) {
const itemDeps = this._items.get(item) || new Set();
// If the dependency list is equal, just return, otherwise remove and keep going.
let equal = true;
for (const dep of deps) {
if (!itemDeps.has(dep)) {
equal = false;
break;
}
}
if (equal) {
for (const dep of itemDeps) {
if (!deps.has(dep)) {
equal = false;
break;
}
}
}
if (equal) {
return this;
}
else {
this._items.delete(item);
}
}
// Verify all dependencies are part of the Set.
for (const dep of deps) {
if (!this._items.has(dep)) {
throw new DependencyNotFoundException();
}
}
// Verify there's no dependency cycle.
this._checkCircularDependencies(item, deps);
this._items.set(item, new Set(deps));
return this;
}
delete(item) {
if (!this._items.has(item)) {
return false;
}
// Remove it from all dependencies if force == true.
this._items.forEach((value) => value.delete(item));
return this._items.delete(item);
}
*[Symbol.iterator]() {
const copy = new Map(this._items);
for (const [key, value] of copy.entries()) {
copy.set(key, new Set(value));
}
while (copy.size > 0) {
const run = [];
// Take the first item without dependencies.
for (const [item, deps] of copy.entries()) {
if (deps.size == 0) {
run.push(item);
}
}
for (const item of run) {
copy.forEach((s) => s.delete(item));
copy.delete(item);
yield item;
}
if (run.length == 0) {
// uh oh...
throw new CircularDependencyFoundException();
}
}
}
get [Symbol.toStringTag]() {
return 'Set';
}
}
exports.PartiallyOrderedSet = PartiallyOrderedSet;

View file

@ -0,0 +1,19 @@
/**
* @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
*/
/** Naive priority queue; not intended for large datasets */
export declare class PriorityQueue<T> {
private _comparator;
private _items;
constructor(_comparator: (x: T, y: T) => number);
clear(): void;
push(item: T): void;
pop(): T | undefined;
peek(): T | undefined;
get size(): number;
toArray(): Array<T>;
}

View file

@ -0,0 +1,49 @@
"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 });
exports.PriorityQueue = void 0;
/** Naive priority queue; not intended for large datasets */
class PriorityQueue {
_comparator;
_items = new Array();
constructor(_comparator) {
this._comparator = _comparator;
}
clear() {
this._items = new Array();
}
push(item) {
const index = this._items.findIndex((existing) => this._comparator(item, existing) <= 0);
if (index === -1) {
this._items.push(item);
}
else {
this._items.splice(index, 0, item);
}
}
pop() {
if (this._items.length === 0) {
return undefined;
}
return this._items.splice(0, 1)[0];
}
peek() {
if (this._items.length === 0) {
return undefined;
}
return this._items[0];
}
get size() {
return this._items.length;
}
toArray() {
return this._items.slice();
}
}
exports.PriorityQueue = PriorityQueue;

View file

@ -0,0 +1,112 @@
/**
* @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
*/
/**
* Converts a camelized string into all lower case separated by underscores.
*
```javascript
decamelize('innerHTML'); // 'inner_html'
decamelize('action_name'); // 'action_name'
decamelize('css-class-name'); // 'css-class-name'
decamelize('my favorite items'); // 'my favorite items'
```
@method decamelize
@param {String} str The string to decamelize.
@return {String} the decamelized string.
*/
export declare function decamelize(str: string): string;
/**
Replaces underscores, spaces, or camelCase with dashes.
```javascript
dasherize('innerHTML'); // 'inner-html'
dasherize('action_name'); // 'action-name'
dasherize('css-class-name'); // 'css-class-name'
dasherize('my favorite items'); // 'my-favorite-items'
```
@method dasherize
@param {String} str The string to dasherize.
@return {String} the dasherized string.
*/
export declare function dasherize(str: string): string;
/**
Returns the lowerCamelCase form of a string.
```javascript
camelize('innerHTML'); // 'innerHTML'
camelize('action_name'); // 'actionName'
camelize('css-class-name'); // 'cssClassName'
camelize('my favorite items'); // 'myFavoriteItems'
camelize('My Favorite Items'); // 'myFavoriteItems'
```
@method camelize
@param {String} str The string to camelize.
@return {String} the camelized string.
*/
export declare function camelize(str: string): string;
/**
Returns the UpperCamelCase form of a string.
@example
```javascript
'innerHTML'.classify(); // 'InnerHTML'
'action_name'.classify(); // 'ActionName'
'css-class-name'.classify(); // 'CssClassName'
'my favorite items'.classify(); // 'MyFavoriteItems'
'app.component'.classify(); // 'AppComponent'
```
@method classify
@param {String} str the string to classify
@return {String} the classified string
*/
export declare function classify(str: string): string;
/**
More general than decamelize. Returns the lower_case_and_underscored
form of a string.
```javascript
'innerHTML'.underscore(); // 'inner_html'
'action_name'.underscore(); // 'action_name'
'css-class-name'.underscore(); // 'css_class_name'
'my favorite items'.underscore(); // 'my_favorite_items'
```
@method underscore
@param {String} str The string to underscore.
@return {String} the underscored string.
*/
export declare function underscore(str: string): string;
/**
Returns the Capitalized form of a string
```javascript
'innerHTML'.capitalize() // 'InnerHTML'
'action_name'.capitalize() // 'Action_name'
'css-class-name'.capitalize() // 'Css-class-name'
'my favorite items'.capitalize() // 'My favorite items'
```
@method capitalize
@param {String} str The string to capitalize.
@return {String} The capitalized string.
*/
export declare function capitalize(str: string): string;
/**
* Calculate the levenshtein distance of two strings.
* See https://en.wikipedia.org/wiki/Levenshtein_distance.
* Based off https://gist.github.com/andrei-m/982927 (for using the faster dynamic programming
* version).
*
* @param a String a.
* @param b String b.
* @returns A number that represents the distance between the two strings. The greater the number
* the more distant the strings are from each others.
*/
export declare function levenshtein(a: string, b: string): number;

179
my-app/node_modules/@angular-devkit/core/src/utils/strings.js generated vendored Executable file
View file

@ -0,0 +1,179 @@
"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 });
exports.levenshtein = exports.capitalize = exports.underscore = exports.classify = exports.camelize = exports.dasherize = exports.decamelize = void 0;
const STRING_DASHERIZE_REGEXP = /[ _]/g;
const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g;
const STRING_CAMELIZE_REGEXP = /(-|_|\.|\s)+(.)?/g;
const STRING_UNDERSCORE_REGEXP_1 = /([a-z\d])([A-Z]+)/g;
const STRING_UNDERSCORE_REGEXP_2 = /-|\s+/g;
/**
* Converts a camelized string into all lower case separated by underscores.
*
```javascript
decamelize('innerHTML'); // 'inner_html'
decamelize('action_name'); // 'action_name'
decamelize('css-class-name'); // 'css-class-name'
decamelize('my favorite items'); // 'my favorite items'
```
@method decamelize
@param {String} str The string to decamelize.
@return {String} the decamelized string.
*/
function decamelize(str) {
return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase();
}
exports.decamelize = decamelize;
/**
Replaces underscores, spaces, or camelCase with dashes.
```javascript
dasherize('innerHTML'); // 'inner-html'
dasherize('action_name'); // 'action-name'
dasherize('css-class-name'); // 'css-class-name'
dasherize('my favorite items'); // 'my-favorite-items'
```
@method dasherize
@param {String} str The string to dasherize.
@return {String} the dasherized string.
*/
function dasherize(str) {
return decamelize(str).replace(STRING_DASHERIZE_REGEXP, '-');
}
exports.dasherize = dasherize;
/**
Returns the lowerCamelCase form of a string.
```javascript
camelize('innerHTML'); // 'innerHTML'
camelize('action_name'); // 'actionName'
camelize('css-class-name'); // 'cssClassName'
camelize('my favorite items'); // 'myFavoriteItems'
camelize('My Favorite Items'); // 'myFavoriteItems'
```
@method camelize
@param {String} str The string to camelize.
@return {String} the camelized string.
*/
function camelize(str) {
return str
.replace(STRING_CAMELIZE_REGEXP, (_match, _separator, chr) => {
return chr ? chr.toUpperCase() : '';
})
.replace(/^([A-Z])/, (match) => match.toLowerCase());
}
exports.camelize = camelize;
/**
Returns the UpperCamelCase form of a string.
@example
```javascript
'innerHTML'.classify(); // 'InnerHTML'
'action_name'.classify(); // 'ActionName'
'css-class-name'.classify(); // 'CssClassName'
'my favorite items'.classify(); // 'MyFavoriteItems'
'app.component'.classify(); // 'AppComponent'
```
@method classify
@param {String} str the string to classify
@return {String} the classified string
*/
function classify(str) {
return str
.split('.')
.map((part) => capitalize(camelize(part)))
.join('');
}
exports.classify = classify;
/**
More general than decamelize. Returns the lower_case_and_underscored
form of a string.
```javascript
'innerHTML'.underscore(); // 'inner_html'
'action_name'.underscore(); // 'action_name'
'css-class-name'.underscore(); // 'css_class_name'
'my favorite items'.underscore(); // 'my_favorite_items'
```
@method underscore
@param {String} str The string to underscore.
@return {String} the underscored string.
*/
function underscore(str) {
return str
.replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2')
.replace(STRING_UNDERSCORE_REGEXP_2, '_')
.toLowerCase();
}
exports.underscore = underscore;
/**
Returns the Capitalized form of a string
```javascript
'innerHTML'.capitalize() // 'InnerHTML'
'action_name'.capitalize() // 'Action_name'
'css-class-name'.capitalize() // 'Css-class-name'
'my favorite items'.capitalize() // 'My favorite items'
```
@method capitalize
@param {String} str The string to capitalize.
@return {String} The capitalized string.
*/
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
exports.capitalize = capitalize;
/**
* Calculate the levenshtein distance of two strings.
* See https://en.wikipedia.org/wiki/Levenshtein_distance.
* Based off https://gist.github.com/andrei-m/982927 (for using the faster dynamic programming
* version).
*
* @param a String a.
* @param b String b.
* @returns A number that represents the distance between the two strings. The greater the number
* the more distant the strings are from each others.
*/
function levenshtein(a, b) {
if (a.length == 0) {
return b.length;
}
if (b.length == 0) {
return a.length;
}
const matrix = [];
// increment along the first column of each row
for (let i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
// increment each column in the first row
for (let j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for (let i = 1; i <= b.length; i++) {
for (let j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) == a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
}
else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j] + 1);
}
}
}
return matrix[b.length][a.length];
}
exports.levenshtein = levenshtein;

View file

@ -0,0 +1,89 @@
/**
* @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 { Position } from 'source-map';
export interface TemplateOptions {
sourceURL?: string;
sourceMap?: boolean;
module?: boolean | {
exports: {};
};
sourceRoot?: string;
fileName?: string;
}
/**
* A simple AST for templates. There's only one level of AST nodes, but it's still useful
* to have the information you're looking for.
*/
export interface TemplateAst {
fileName: string;
content: string;
children: TemplateAstNode[];
}
/**
* The base, which contains positions.
*/
export interface TemplateAstBase {
start: Position;
end: Position;
}
/**
* A static content node.
*/
export interface TemplateAstContent extends TemplateAstBase {
kind: 'content';
content: string;
}
/**
* A comment node.
*/
export interface TemplateAstComment extends TemplateAstBase {
kind: 'comment';
text: string;
}
/**
* An evaluate node, which is the code between `<% ... %>`.
*/
export interface TemplateAstEvaluate extends TemplateAstBase {
kind: 'evaluate';
expression: string;
}
/**
* An escape node, which is the code between `<%- ... %>`.
*/
export interface TemplateAstEscape extends TemplateAstBase {
kind: 'escape';
expression: string;
}
/**
* An interpolation node, which is the code between `<%= ... %>`.
*/
export interface TemplateAstInterpolate extends TemplateAstBase {
kind: 'interpolate';
expression: string;
}
export type TemplateAstNode = TemplateAstContent | TemplateAstEvaluate | TemplateAstComment | TemplateAstEscape | TemplateAstInterpolate;
/**
* Given a source text (and a fileName), returns a TemplateAst.
*/
export declare function templateParser(sourceText: string, fileName: string): TemplateAst;
/**
* An equivalent of EJS templates, which is based on John Resig's `tmpl` implementation
* (http://ejohn.org/blog/javascript-micro-templating/) and Laura Doktorova's doT.js
* (https://github.com/olado/doT).
*
* This version differs from lodash by removing support from ES6 quasi-literals, and making the
* code slightly simpler to follow. It also does not depend on any third party, which is nice.
*
* Finally, it supports SourceMap, if you ever need to debug, which is super nice.
*
* @param content The template content.
* @param options Optional Options. See TemplateOptions for more description.
* @return {(input: T) => string} A function that accept an input object and returns the content
* of the template with the input applied.
*/
export declare function template<T>(content: string, options?: TemplateOptions): (input: T) => string;

View file

@ -0,0 +1,262 @@
"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 });
exports.template = exports.templateParser = void 0;
const source_map_1 = require("source-map");
// Matches <%= expr %>. This does not support structural JavaScript (for/if/...).
const kInterpolateRe = /<%=([\s\S]+?)%>/g;
// Matches <%# text %>. It's a comment and will be entirely ignored.
const kCommentRe = /<%#([\s\S]+?)%>/g;
// Used to match template delimiters.
// <%- expr %>: HTML escape the value.
// <% ... %>: Structural template code.
const kEscapeRe = /<%-([\s\S]+?)%>/g;
const kEvaluateRe = /<%([\s\S]+?)%>/g;
/** Used to map characters to HTML entities. */
const kHtmlEscapes = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'`': '&#96;',
};
// Used to match HTML entities and HTML characters.
const reUnescapedHtml = new RegExp(`[${Object.keys(kHtmlEscapes).join('')}]`, 'g');
function _positionFor(content, offset) {
let line = 1;
let column = 0;
for (let i = 0; i < offset - 1; i++) {
if (content[i] == '\n') {
line++;
column = 0;
}
else {
column++;
}
}
return {
line,
column,
};
}
/**
* Given a source text (and a fileName), returns a TemplateAst.
*/
function templateParser(sourceText, fileName) {
const children = [];
// Compile the regexp to match each delimiter.
const reExpressions = [kEscapeRe, kCommentRe, kInterpolateRe, kEvaluateRe];
const reDelimiters = RegExp(reExpressions.map((x) => x.source).join('|') + '|$', 'g');
const parsed = sourceText.split(reDelimiters);
let offset = 0;
// Optimization that uses the fact that the end of a node is always the beginning of the next
// node, so we keep the positioning of the nodes in memory.
let start = _positionFor(sourceText, offset);
let end;
const increment = reExpressions.length + 1;
for (let i = 0; i < parsed.length; i += increment) {
const [content, escape, comment, interpolate, evaluate] = parsed.slice(i, i + increment);
if (content) {
end = _positionFor(sourceText, offset + content.length);
offset += content.length;
children.push({ kind: 'content', content, start, end });
start = end;
}
if (escape) {
end = _positionFor(sourceText, offset + escape.length + 5);
offset += escape.length + 5;
children.push({ kind: 'escape', expression: escape, start, end });
start = end;
}
if (comment) {
end = _positionFor(sourceText, offset + comment.length + 5);
offset += comment.length + 5;
children.push({ kind: 'comment', text: comment, start, end });
start = end;
}
if (interpolate) {
end = _positionFor(sourceText, offset + interpolate.length + 5);
offset += interpolate.length + 5;
children.push({
kind: 'interpolate',
expression: interpolate,
start,
end,
});
start = end;
}
if (evaluate) {
end = _positionFor(sourceText, offset + evaluate.length + 5);
offset += evaluate.length + 5;
children.push({ kind: 'evaluate', expression: evaluate, start, end });
start = end;
}
}
return {
fileName,
content: sourceText,
children,
};
}
exports.templateParser = templateParser;
/**
* Fastest implementation of the templating algorithm. It only add strings and does not bother
* with source maps.
*/
function templateFast(ast, options) {
const module = options && options.module ? 'module.exports.default =' : '';
const reHtmlEscape = reUnescapedHtml.source.replace(/[']/g, "\\\\\\'");
return `
return ${module} function(obj) {
obj || (obj = {});
let __t;
let __p = '';
const __escapes = ${JSON.stringify(kHtmlEscapes)};
const __escapesre = new RegExp('${reHtmlEscape}', 'g');
const __e = function(s) {
return s ? s.replace(__escapesre, function(key) { return __escapes[key]; }) : '';
};
with (obj) {
${ast.children
.map((node) => {
switch (node.kind) {
case 'content':
return `__p += ${JSON.stringify(node.content)};`;
case 'interpolate':
return `__p += ((__t = (${node.expression})) == null) ? '' : __t;`;
case 'escape':
return `__p += __e(${node.expression});`;
case 'evaluate':
return node.expression;
}
})
.join('\n')}
}
return __p;
};
`;
}
/**
* Templating algorithm with source map support. The map is outputted as //# sourceMapUrl=...
*/
function templateWithSourceMap(ast, options) {
const sourceUrl = ast.fileName;
const module = options && options.module ? 'module.exports.default =' : '';
const reHtmlEscape = reUnescapedHtml.source.replace(/[']/g, "\\\\\\'");
const preamble = new source_map_1.SourceNode(1, 0, sourceUrl, '').add(new source_map_1.SourceNode(1, 0, sourceUrl, [
`return ${module} function(obj) {\n`,
' obj || (obj = {});\n',
' let __t;\n',
' let __p = "";\n',
` const __escapes = ${JSON.stringify(kHtmlEscapes)};\n`,
` const __escapesre = new RegExp('${reHtmlEscape}', 'g');\n`,
`\n`,
` const __e = function(s) { `,
` return s ? s.replace(__escapesre, function(key) { return __escapes[key]; }) : '';`,
` };\n`,
` with (obj) {\n`,
]));
const end = ast.children.length
? ast.children[ast.children.length - 1].end
: { line: 0, column: 0 };
const nodes = ast.children
.reduce((chunk, node) => {
let code = '';
switch (node.kind) {
case 'content':
code = [
new source_map_1.SourceNode(node.start.line, node.start.column, sourceUrl, '__p = __p'),
...node.content.split('\n').map((line, i, arr) => {
return new source_map_1.SourceNode(node.start.line + i, i == 0 ? node.start.column : 0, sourceUrl, '\n + ' + JSON.stringify(line + (i == arr.length - 1 ? '' : '\n')));
}),
new source_map_1.SourceNode(node.end.line, node.end.column, sourceUrl, ';\n'),
];
break;
case 'interpolate':
code = [
new source_map_1.SourceNode(node.start.line, node.start.column, sourceUrl, '__p += ((__t = '),
...node.expression.split('\n').map((line, i, arr) => {
return new source_map_1.SourceNode(node.start.line + i, i == 0 ? node.start.column : 0, sourceUrl, line + (i == arr.length - 1 ? '' : '\n'));
}),
new source_map_1.SourceNode(node.end.line, node.end.column, sourceUrl, ') == null ? "" : __t);\n'),
];
break;
case 'escape':
code = [
new source_map_1.SourceNode(node.start.line, node.start.column, sourceUrl, '__p += __e('),
...node.expression.split('\n').map((line, i, arr) => {
return new source_map_1.SourceNode(node.start.line + i, i == 0 ? node.start.column : 0, sourceUrl, line + (i == arr.length - 1 ? '' : '\n'));
}),
new source_map_1.SourceNode(node.end.line, node.end.column, sourceUrl, ');\n'),
];
break;
case 'evaluate':
code = [
...node.expression.split('\n').map((line, i, arr) => {
return new source_map_1.SourceNode(node.start.line + i, i == 0 ? node.start.column : 0, sourceUrl, line + (i == arr.length - 1 ? '' : '\n'));
}),
new source_map_1.SourceNode(node.end.line, node.end.column, sourceUrl, '\n'),
];
break;
}
return chunk.add(new source_map_1.SourceNode(node.start.line, node.start.column, sourceUrl, code));
}, preamble)
.add(new source_map_1.SourceNode(end.line, end.column, sourceUrl, [' };\n', '\n', ' return __p;\n', '}\n']));
const code = nodes.toStringWithSourceMap({
file: sourceUrl,
sourceRoot: (options && options.sourceRoot) || '.',
});
// Set the source content in the source map, otherwise the sourceUrl is not enough
// to find the content.
code.map.setSourceContent(sourceUrl, ast.content);
return (code.code +
'\n//# sourceMappingURL=data:application/json;base64,' +
Buffer.from(code.map.toString()).toString('base64'));
}
/**
* An equivalent of EJS templates, which is based on John Resig's `tmpl` implementation
* (http://ejohn.org/blog/javascript-micro-templating/) and Laura Doktorova's doT.js
* (https://github.com/olado/doT).
*
* This version differs from lodash by removing support from ES6 quasi-literals, and making the
* code slightly simpler to follow. It also does not depend on any third party, which is nice.
*
* Finally, it supports SourceMap, if you ever need to debug, which is super nice.
*
* @param content The template content.
* @param options Optional Options. See TemplateOptions for more description.
* @return {(input: T) => string} A function that accept an input object and returns the content
* of the template with the input applied.
*/
function template(content, options) {
const sourceUrl = (options && options.sourceURL) || 'ejs';
const ast = templateParser(content, sourceUrl);
let source;
// If there's no need for source map support, we revert back to the fast implementation.
if (options && options.sourceMap) {
source = templateWithSourceMap(ast, options);
}
else {
source = templateFast(ast, options);
}
// We pass a dummy module in case the module option is passed. If `module: true` is passed, we
// need to only use the source, not the function itself. Otherwise expect a module object to be
// passed, and we use that one.
const fn = Function('module', source);
const module = options && options.module ? (options.module === true ? { exports: {} } : options.module) : null;
const result = fn(module);
// Provide the compiled function's source by its `toString` method or
// the `source` property as a convenience for inlining compiled templates.
result.source = source;
return result;
}
exports.template = template;

View file

@ -0,0 +1,60 @@
/**
* @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 { Path } from '../path';
import { ResolverHost } from './resolver';
/**
* A Virtual Host that allow to alias some paths to other paths.
*
* This does not verify, when setting an alias, that the target or source exist. Neither does it
* check whether it's a file or a directory. Please not that directories are also renamed/replaced.
*
* No recursion is done on the resolution, which means the following is perfectly valid then:
*
* ```
* host.aliases.set(normalize('/file/a'), normalize('/file/b'));
* host.aliases.set(normalize('/file/b'), normalize('/file/a'));
* ```
*
* This will result in a proper swap of two files for each others.
*
* @example
* const host = new SimpleMemoryHost();
* host.write(normalize('/some/file'), content).subscribe();
*
* const aHost = new AliasHost(host);
* aHost.read(normalize('/some/file'))
* .subscribe(x => expect(x).toBe(content));
* aHost.aliases.set(normalize('/some/file'), normalize('/other/path');
*
* // This file will not exist because /other/path does not exist.
* aHost.read(normalize('/some/file'))
* .subscribe(undefined, err => expect(err.message).toMatch(/does not exist/));
*
* @example
* const host = new SimpleMemoryHost();
* host.write(normalize('/some/folder/file'), content).subscribe();
*
* const aHost = new AliasHost(host);
* aHost.read(normalize('/some/folder/file'))
* .subscribe(x => expect(x).toBe(content));
* aHost.aliases.set(normalize('/some'), normalize('/other');
*
* // This file will not exist because /other/path does not exist.
* aHost.read(normalize('/some/folder/file'))
* .subscribe(undefined, err => expect(err.message).toMatch(/does not exist/));
*
* // Create the file with new content and verify that this has the new content.
* aHost.write(normalize('/other/folder/file'), content2).subscribe();
* aHost.read(normalize('/some/folder/file'))
* .subscribe(x => expect(x).toBe(content2));
*/
export declare class AliasHost<StatsT extends object = {}> extends ResolverHost<StatsT> {
protected _aliases: Map<Path, Path>;
protected _resolve(path: Path): Path;
get aliases(): Map<Path, Path>;
}

View file

@ -0,0 +1,83 @@
"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 });
exports.AliasHost = void 0;
const path_1 = require("../path");
const resolver_1 = require("./resolver");
/**
* A Virtual Host that allow to alias some paths to other paths.
*
* This does not verify, when setting an alias, that the target or source exist. Neither does it
* check whether it's a file or a directory. Please not that directories are also renamed/replaced.
*
* No recursion is done on the resolution, which means the following is perfectly valid then:
*
* ```
* host.aliases.set(normalize('/file/a'), normalize('/file/b'));
* host.aliases.set(normalize('/file/b'), normalize('/file/a'));
* ```
*
* This will result in a proper swap of two files for each others.
*
* @example
* const host = new SimpleMemoryHost();
* host.write(normalize('/some/file'), content).subscribe();
*
* const aHost = new AliasHost(host);
* aHost.read(normalize('/some/file'))
* .subscribe(x => expect(x).toBe(content));
* aHost.aliases.set(normalize('/some/file'), normalize('/other/path');
*
* // This file will not exist because /other/path does not exist.
* aHost.read(normalize('/some/file'))
* .subscribe(undefined, err => expect(err.message).toMatch(/does not exist/));
*
* @example
* const host = new SimpleMemoryHost();
* host.write(normalize('/some/folder/file'), content).subscribe();
*
* const aHost = new AliasHost(host);
* aHost.read(normalize('/some/folder/file'))
* .subscribe(x => expect(x).toBe(content));
* aHost.aliases.set(normalize('/some'), normalize('/other');
*
* // This file will not exist because /other/path does not exist.
* aHost.read(normalize('/some/folder/file'))
* .subscribe(undefined, err => expect(err.message).toMatch(/does not exist/));
*
* // Create the file with new content and verify that this has the new content.
* aHost.write(normalize('/other/folder/file'), content2).subscribe();
* aHost.read(normalize('/some/folder/file'))
* .subscribe(x => expect(x).toBe(content2));
*/
class AliasHost extends resolver_1.ResolverHost {
_aliases = new Map();
_resolve(path) {
let maybeAlias = this._aliases.get(path);
const sp = (0, path_1.split)(path);
const remaining = [];
// Also resolve all parents of the requested files, only picking the first one that matches.
// This can have surprising behaviour when aliases are inside another alias. It will always
// use the closest one to the file.
while (!maybeAlias && sp.length > 0) {
const p = (0, path_1.join)(path_1.NormalizedRoot, ...sp);
maybeAlias = this._aliases.get(p);
if (maybeAlias) {
maybeAlias = (0, path_1.join)(maybeAlias, ...remaining);
}
// Allow non-null-operator because we know sp.length > 0 (condition on while).
remaining.unshift(sp.pop()); // eslint-disable-line @typescript-eslint/no-non-null-assertion
}
return maybeAlias || path;
}
get aliases() {
return this._aliases;
}
}
exports.AliasHost = AliasHost;

View file

@ -0,0 +1,13 @@
/**
* @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 { TemplateTag } from '../../utils/literals';
import { FileBuffer } from './interface';
export declare function stringToFileBuffer(str: string): FileBuffer;
export declare function fileBufferToString(fileBuffer: FileBuffer): string;
/** @deprecated use `stringToFileBuffer` instead. */
export declare const fileBuffer: TemplateTag<FileBuffer>;

View file

@ -0,0 +1,27 @@
"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 });
exports.fileBuffer = exports.fileBufferToString = exports.stringToFileBuffer = void 0;
const node_util_1 = require("node:util");
function stringToFileBuffer(str) {
return new node_util_1.TextEncoder().encode(str).buffer;
}
exports.stringToFileBuffer = stringToFileBuffer;
function fileBufferToString(fileBuffer) {
if (fileBuffer.toString.length === 1) {
return fileBuffer.toString('utf-8');
}
return new node_util_1.TextDecoder('utf-8').decode(new Uint8Array(fileBuffer));
}
exports.fileBufferToString = fileBufferToString;
/** @deprecated use `stringToFileBuffer` instead. */
const fileBuffer = (strings, ...values) => {
return stringToFileBuffer(String.raw(strings, ...values));
};
exports.fileBuffer = fileBuffer;

View file

@ -0,0 +1,21 @@
/**
* @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 { Path, PathFragment } from '../path';
import { FileBuffer, FileBufferLike, Host, Stats } from './interface';
export interface SyncHostHandler<StatsT extends object = {}> {
read(path: Path): FileBuffer;
list(path: Path): PathFragment[];
exists(path: Path): boolean;
isDirectory(path: Path): boolean;
isFile(path: Path): boolean;
stat(path: Path): Stats<StatsT> | null;
write(path: Path, content: FileBufferLike): void;
delete(path: Path): void;
rename(from: Path, to: Path): void;
}
export declare function createSyncHost<StatsT extends object = {}>(handler: SyncHostHandler<StatsT>): Host<StatsT>;

View file

@ -0,0 +1,55 @@
"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 });
exports.createSyncHost = void 0;
const rxjs_1 = require("rxjs");
function wrapAction(action) {
return new rxjs_1.Observable((subscriber) => {
subscriber.next(action());
subscriber.complete();
});
}
function createSyncHost(handler) {
return new (class {
get capabilities() {
return { synchronous: true };
}
read(path) {
return wrapAction(() => handler.read(path));
}
list(path) {
return wrapAction(() => handler.list(path));
}
exists(path) {
return wrapAction(() => handler.exists(path));
}
isDirectory(path) {
return wrapAction(() => handler.isDirectory(path));
}
isFile(path) {
return wrapAction(() => handler.isFile(path));
}
stat(path) {
return wrapAction(() => handler.stat(path));
}
write(path, content) {
return wrapAction(() => handler.write(path, content));
}
delete(path) {
return wrapAction(() => handler.delete(path));
}
rename(from, to) {
return wrapAction(() => handler.rename(from, to));
}
watch() {
return null;
}
})();
}
exports.createSyncHost = createSyncHost;

View file

@ -0,0 +1,19 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, HostCapabilities, ReadonlyHost, Stats } from './interface';
export declare class Empty implements ReadonlyHost {
readonly capabilities: HostCapabilities;
read(path: Path): Observable<FileBuffer>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats<{}> | null>;
}

View file

@ -0,0 +1,37 @@
"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 });
exports.Empty = void 0;
const rxjs_1 = require("rxjs");
const exception_1 = require("../../exception");
class Empty {
capabilities = {
synchronous: true,
};
read(path) {
return (0, rxjs_1.throwError)(new exception_1.FileDoesNotExistException(path));
}
list(path) {
return (0, rxjs_1.of)([]);
}
exists(path) {
return (0, rxjs_1.of)(false);
}
isDirectory(path) {
return (0, rxjs_1.of)(false);
}
isFile(path) {
return (0, rxjs_1.of)(false);
}
stat(path) {
// We support stat() but have no file.
return (0, rxjs_1.of)(null);
}
}
exports.Empty = Empty;

View file

@ -0,0 +1,20 @@
/**
* @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
*/
export * from './alias';
export * from './buffer';
export * from './create';
export * from './empty';
export * from './interface';
export * from './memory';
export * from './pattern';
export * from './record';
export * from './safe';
export * from './scoped';
export * from './sync';
export * from './resolver';
export * from './test';

View file

@ -0,0 +1,36 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./alias"), exports);
__exportStar(require("./buffer"), exports);
__exportStar(require("./create"), exports);
__exportStar(require("./empty"), exports);
__exportStar(require("./interface"), exports);
__exportStar(require("./memory"), exports);
__exportStar(require("./pattern"), exports);
__exportStar(require("./record"), exports);
__exportStar(require("./safe"), exports);
__exportStar(require("./scoped"), exports);
__exportStar(require("./sync"), exports);
__exportStar(require("./resolver"), exports);
__exportStar(require("./test"), exports);

View file

@ -0,0 +1,53 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
export type FileBuffer = ArrayBuffer;
export type FileBufferLike = ArrayBufferLike;
export interface HostWatchOptions {
readonly persistent?: boolean;
readonly recursive?: boolean;
}
export declare const enum HostWatchEventType {
Changed = 0,
Created = 1,
Deleted = 2,
Renamed = 3
}
export type Stats<T extends object = {}> = T & {
isFile(): boolean;
isDirectory(): boolean;
readonly size: number;
readonly atime: Date;
readonly mtime: Date;
readonly ctime: Date;
readonly birthtime: Date;
};
export interface HostWatchEvent {
readonly time: Date;
readonly type: HostWatchEventType;
readonly path: Path;
}
export interface HostCapabilities {
synchronous: boolean;
}
export interface ReadonlyHost<StatsT extends object = {}> {
readonly capabilities: HostCapabilities;
read(path: Path): Observable<FileBuffer>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats<StatsT> | null> | null;
}
export interface Host<StatsT extends object = {}> extends ReadonlyHost<StatsT> {
write(path: Path, content: FileBufferLike): Observable<void>;
delete(path: Path): Observable<void>;
rename(from: Path, to: Path): Observable<void>;
watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent> | null;
}

View file

@ -0,0 +1,9 @@
"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 });

View file

@ -0,0 +1,68 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, Host, HostCapabilities, HostWatchEvent, HostWatchEventType, HostWatchOptions, Stats } from './interface';
export interface SimpleMemoryHostStats {
readonly content: FileBuffer | null;
}
export declare class SimpleMemoryHost implements Host<{}> {
protected _cache: Map<Path, Stats<SimpleMemoryHostStats>>;
private _watchers;
protected _newDirStats(): {
inspect(): string;
isFile(): boolean;
isDirectory(): boolean;
size: number;
atime: Date;
ctime: Date;
mtime: Date;
birthtime: Date;
content: null;
};
protected _newFileStats(content: FileBuffer, oldStats?: Stats<SimpleMemoryHostStats>): {
inspect(): string;
isFile(): boolean;
isDirectory(): boolean;
size: number;
atime: Date;
ctime: Date;
mtime: Date;
birthtime: Date;
content: ArrayBuffer;
};
constructor();
protected _toAbsolute(path: Path): Path;
protected _updateWatchers(path: Path, type: HostWatchEventType): void;
get capabilities(): HostCapabilities;
/**
* List of protected methods that give direct access outside the observables to the cache
* and internal states.
*/
protected _write(path: Path, content: FileBuffer): void;
protected _read(path: Path): FileBuffer;
protected _delete(path: Path): void;
protected _rename(from: Path, to: Path): void;
protected _list(path: Path): PathFragment[];
protected _exists(path: Path): boolean;
protected _isDirectory(path: Path): boolean;
protected _isFile(path: Path): boolean;
protected _stat(path: Path): Stats<SimpleMemoryHostStats> | null;
protected _watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent>;
write(path: Path, content: FileBuffer): Observable<void>;
read(path: Path): Observable<FileBuffer>;
delete(path: Path): Observable<void>;
rename(from: Path, to: Path): Observable<void>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats<{}> | null> | null;
watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent> | null;
reset(): void;
}

View file

@ -0,0 +1,330 @@
"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 });
exports.SimpleMemoryHost = void 0;
const rxjs_1 = require("rxjs");
const exception_1 = require("../../exception");
const path_1 = require("../path");
class SimpleMemoryHost {
_cache = new Map();
_watchers = new Map();
_newDirStats() {
return {
inspect() {
return '<Directory>';
},
isFile() {
return false;
},
isDirectory() {
return true;
},
size: 0,
atime: new Date(),
ctime: new Date(),
mtime: new Date(),
birthtime: new Date(),
content: null,
};
}
_newFileStats(content, oldStats) {
return {
inspect() {
return `<File size(${content.byteLength})>`;
},
isFile() {
return true;
},
isDirectory() {
return false;
},
size: content.byteLength,
atime: oldStats ? oldStats.atime : new Date(),
ctime: new Date(),
mtime: new Date(),
birthtime: oldStats ? oldStats.birthtime : new Date(),
content,
};
}
constructor() {
this._cache.set((0, path_1.normalize)('/'), this._newDirStats());
}
_toAbsolute(path) {
return (0, path_1.isAbsolute)(path) ? path : (0, path_1.normalize)('/' + path);
}
_updateWatchers(path, type) {
const time = new Date();
let currentPath = path;
let parent = null;
if (this._watchers.size == 0) {
// Nothing to do if there's no watchers.
return;
}
const maybeWatcher = this._watchers.get(currentPath);
if (maybeWatcher) {
maybeWatcher.forEach((watcher) => {
const [options, subject] = watcher;
subject.next({ path, time, type });
if (!options.persistent && type == 2 /* HostWatchEventType.Deleted */) {
subject.complete();
this._watchers.delete(currentPath);
}
});
}
do {
currentPath = parent !== null ? parent : currentPath;
parent = (0, path_1.dirname)(currentPath);
const maybeWatcher = this._watchers.get(currentPath);
if (maybeWatcher) {
maybeWatcher.forEach((watcher) => {
const [options, subject] = watcher;
if (!options.recursive) {
return;
}
subject.next({ path, time, type });
if (!options.persistent && type == 2 /* HostWatchEventType.Deleted */) {
subject.complete();
this._watchers.delete(currentPath);
}
});
}
} while (parent != currentPath);
}
get capabilities() {
return { synchronous: true };
}
/**
* List of protected methods that give direct access outside the observables to the cache
* and internal states.
*/
_write(path, content) {
path = this._toAbsolute(path);
const old = this._cache.get(path);
if (old && old.isDirectory()) {
throw new exception_1.PathIsDirectoryException(path);
}
// Update all directories. If we find a file we know it's an invalid write.
const fragments = (0, path_1.split)(path);
let curr = (0, path_1.normalize)('/');
for (const fr of fragments) {
curr = (0, path_1.join)(curr, fr);
const maybeStats = this._cache.get(fr);
if (maybeStats) {
if (maybeStats.isFile()) {
throw new exception_1.PathIsFileException(curr);
}
}
else {
this._cache.set(curr, this._newDirStats());
}
}
// Create the stats.
const stats = this._newFileStats(content, old);
this._cache.set(path, stats);
this._updateWatchers(path, old ? 0 /* HostWatchEventType.Changed */ : 1 /* HostWatchEventType.Created */);
}
_read(path) {
path = this._toAbsolute(path);
const maybeStats = this._cache.get(path);
if (!maybeStats) {
throw new exception_1.FileDoesNotExistException(path);
}
else if (maybeStats.isDirectory()) {
throw new exception_1.PathIsDirectoryException(path);
}
else if (!maybeStats.content) {
throw new exception_1.PathIsDirectoryException(path);
}
else {
return maybeStats.content;
}
}
_delete(path) {
path = this._toAbsolute(path);
if (this._isDirectory(path)) {
for (const [cachePath] of this._cache.entries()) {
if (cachePath.startsWith(path + path_1.NormalizedSep) || cachePath === path) {
this._cache.delete(cachePath);
}
}
}
else {
this._cache.delete(path);
}
this._updateWatchers(path, 2 /* HostWatchEventType.Deleted */);
}
_rename(from, to) {
from = this._toAbsolute(from);
to = this._toAbsolute(to);
if (!this._cache.has(from)) {
throw new exception_1.FileDoesNotExistException(from);
}
else if (this._cache.has(to)) {
throw new exception_1.FileAlreadyExistException(to);
}
if (this._isDirectory(from)) {
for (const path of this._cache.keys()) {
if (path.startsWith(from + path_1.NormalizedSep)) {
const content = this._cache.get(path);
if (content) {
// We don't need to clone or extract the content, since we're moving files.
this._cache.set((0, path_1.join)(to, path_1.NormalizedSep, path.slice(from.length)), content);
}
}
}
}
else {
const content = this._cache.get(from);
if (content) {
const fragments = (0, path_1.split)(to);
const newDirectories = [];
let curr = (0, path_1.normalize)('/');
for (const fr of fragments) {
curr = (0, path_1.join)(curr, fr);
const maybeStats = this._cache.get(fr);
if (maybeStats) {
if (maybeStats.isFile()) {
throw new exception_1.PathIsFileException(curr);
}
}
else {
newDirectories.push(curr);
}
}
for (const newDirectory of newDirectories) {
this._cache.set(newDirectory, this._newDirStats());
}
this._cache.delete(from);
this._cache.set(to, content);
}
}
this._updateWatchers(from, 3 /* HostWatchEventType.Renamed */);
}
_list(path) {
path = this._toAbsolute(path);
if (this._isFile(path)) {
throw new exception_1.PathIsFileException(path);
}
const fragments = (0, path_1.split)(path);
const result = new Set();
if (path !== path_1.NormalizedRoot) {
for (const p of this._cache.keys()) {
if (p.startsWith(path + path_1.NormalizedSep)) {
result.add((0, path_1.split)(p)[fragments.length]);
}
}
}
else {
for (const p of this._cache.keys()) {
if (p.startsWith(path_1.NormalizedSep) && p !== path_1.NormalizedRoot) {
result.add((0, path_1.split)(p)[1]);
}
}
}
return [...result];
}
_exists(path) {
return !!this._cache.get(this._toAbsolute(path));
}
_isDirectory(path) {
const maybeStats = this._cache.get(this._toAbsolute(path));
return maybeStats ? maybeStats.isDirectory() : false;
}
_isFile(path) {
const maybeStats = this._cache.get(this._toAbsolute(path));
return maybeStats ? maybeStats.isFile() : false;
}
_stat(path) {
const maybeStats = this._cache.get(this._toAbsolute(path));
if (!maybeStats) {
return null;
}
else {
return maybeStats;
}
}
_watch(path, options) {
path = this._toAbsolute(path);
const subject = new rxjs_1.Subject();
let maybeWatcherArray = this._watchers.get(path);
if (!maybeWatcherArray) {
maybeWatcherArray = [];
this._watchers.set(path, maybeWatcherArray);
}
maybeWatcherArray.push([options || {}, subject]);
return subject.asObservable();
}
write(path, content) {
return new rxjs_1.Observable((obs) => {
this._write(path, content);
obs.next();
obs.complete();
});
}
read(path) {
return new rxjs_1.Observable((obs) => {
const content = this._read(path);
obs.next(content);
obs.complete();
});
}
delete(path) {
return new rxjs_1.Observable((obs) => {
this._delete(path);
obs.next();
obs.complete();
});
}
rename(from, to) {
return new rxjs_1.Observable((obs) => {
this._rename(from, to);
obs.next();
obs.complete();
});
}
list(path) {
return new rxjs_1.Observable((obs) => {
obs.next(this._list(path));
obs.complete();
});
}
exists(path) {
return new rxjs_1.Observable((obs) => {
obs.next(this._exists(path));
obs.complete();
});
}
isDirectory(path) {
return new rxjs_1.Observable((obs) => {
obs.next(this._isDirectory(path));
obs.complete();
});
}
isFile(path) {
return new rxjs_1.Observable((obs) => {
obs.next(this._isFile(path));
obs.complete();
});
}
// Some hosts may not support stat.
stat(path) {
return new rxjs_1.Observable((obs) => {
obs.next(this._stat(path));
obs.complete();
});
}
watch(path, options) {
return this._watch(path, options);
}
reset() {
this._cache.clear();
this._watchers.clear();
}
}
exports.SimpleMemoryHost = SimpleMemoryHost;

View file

@ -0,0 +1,17 @@
/**
* @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 { Path } from '../path';
import { ResolverHost } from './resolver';
export type ReplacementFunction = (path: Path) => Path;
/**
*/
export declare class PatternMatchingHost<StatsT extends object = {}> extends ResolverHost<StatsT> {
protected _patterns: Map<RegExp, ReplacementFunction>;
addPattern(pattern: string | string[], replacementFn: ReplacementFunction): void;
protected _resolve(path: Path): Path;
}

View file

@ -0,0 +1,34 @@
"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 });
exports.PatternMatchingHost = void 0;
const picomatch_1 = require("picomatch");
const resolver_1 = require("./resolver");
/**
*/
class PatternMatchingHost extends resolver_1.ResolverHost {
_patterns = new Map();
addPattern(pattern, replacementFn) {
const patterns = Array.isArray(pattern) ? pattern : [pattern];
for (const glob of patterns) {
const { output } = (0, picomatch_1.parse)(glob);
this._patterns.set(new RegExp(`^${output}$`), replacementFn);
}
}
_resolve(path) {
let newPath = path;
this._patterns.forEach((fn, re) => {
if (re.test(path)) {
newPath = fn(newPath);
}
});
return newPath;
}
}
exports.PatternMatchingHost = PatternMatchingHost;

View file

@ -0,0 +1,92 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, Host, HostCapabilities, HostWatchOptions, ReadonlyHost, Stats } from './interface';
import { SimpleMemoryHost } from './memory';
export interface CordHostCreate {
kind: 'create';
path: Path;
content: FileBuffer;
}
export interface CordHostOverwrite {
kind: 'overwrite';
path: Path;
content: FileBuffer;
}
export interface CordHostRename {
kind: 'rename';
from: Path;
to: Path;
}
export interface CordHostDelete {
kind: 'delete';
path: Path;
}
export type CordHostRecord = CordHostCreate | CordHostOverwrite | CordHostRename | CordHostDelete;
/**
* A Host that records changes to the underlying Host, while keeping a record of Create, Overwrite,
* Rename and Delete of files.
*
* This is fully compatible with Host, but will keep a staging of every changes asked. That staging
* follows the principle of the Tree (e.g. can create a file that already exists).
*
* Using `create()` and `overwrite()` will force those operations, but using `write` will add
* the create/overwrite records IIF the files does/doesn't already exist.
*/
export declare class CordHost extends SimpleMemoryHost {
protected _back: ReadonlyHost;
protected _filesToCreate: Set<Path>;
protected _filesToRename: Map<Path, Path>;
protected _filesToRenameRevert: Map<Path, Path>;
protected _filesToDelete: Set<Path>;
protected _filesToOverwrite: Set<Path>;
constructor(_back: ReadonlyHost);
get backend(): ReadonlyHost;
get capabilities(): HostCapabilities;
/**
* Create a copy of this host, including all actions made.
* @returns {CordHost} The carbon copy.
*/
clone(): CordHost;
/**
* Commit the changes recorded to a Host. It is assumed that the host does have the same structure
* as the host that was used for backend (could be the same host).
* @param host The host to create/delete/rename/overwrite files to.
* @param force Whether to skip existence checks when creating/overwriting. This is
* faster but might lead to incorrect states. Because Hosts natively don't support creation
* versus overwriting (it's only writing), we check for existence before completing a request.
* @returns An observable that completes when done, or error if an error occured.
*/
commit(host: Host, force?: boolean): Observable<void>;
records(): CordHostRecord[];
/**
* Specialized version of {@link CordHost#write} which forces the creation of a file whether it
* exists or not.
* @param {} path
* @param {FileBuffer} content
* @returns {Observable<void>}
*/
create(path: Path, content: FileBuffer): Observable<void>;
overwrite(path: Path, content: FileBuffer): Observable<void>;
write(path: Path, content: FileBuffer): Observable<void>;
read(path: Path): Observable<FileBuffer>;
delete(path: Path): Observable<void>;
rename(from: Path, to: Path): Observable<void>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats | null> | null;
watch(path: Path, options?: HostWatchOptions): null;
willCreate(path: Path): boolean;
willOverwrite(path: Path): boolean;
willDelete(path: Path): boolean;
willRename(path: Path): boolean;
willRenameTo(path: Path, to: Path): boolean;
}

View file

@ -0,0 +1,314 @@
"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 });
exports.CordHost = void 0;
const rxjs_1 = require("rxjs");
const exception_1 = require("../../exception");
const memory_1 = require("./memory");
/**
* A Host that records changes to the underlying Host, while keeping a record of Create, Overwrite,
* Rename and Delete of files.
*
* This is fully compatible with Host, but will keep a staging of every changes asked. That staging
* follows the principle of the Tree (e.g. can create a file that already exists).
*
* Using `create()` and `overwrite()` will force those operations, but using `write` will add
* the create/overwrite records IIF the files does/doesn't already exist.
*/
class CordHost extends memory_1.SimpleMemoryHost {
_back;
_filesToCreate = new Set();
_filesToRename = new Map();
_filesToRenameRevert = new Map();
_filesToDelete = new Set();
_filesToOverwrite = new Set();
constructor(_back) {
super();
this._back = _back;
}
get backend() {
return this._back;
}
get capabilities() {
// Our own host is always Synchronous, but the backend might not be.
return {
synchronous: this._back.capabilities.synchronous,
};
}
/**
* Create a copy of this host, including all actions made.
* @returns {CordHost} The carbon copy.
*/
clone() {
const dolly = new CordHost(this._back);
dolly._cache = new Map(this._cache);
dolly._filesToCreate = new Set(this._filesToCreate);
dolly._filesToRename = new Map(this._filesToRename);
dolly._filesToRenameRevert = new Map(this._filesToRenameRevert);
dolly._filesToDelete = new Set(this._filesToDelete);
dolly._filesToOverwrite = new Set(this._filesToOverwrite);
return dolly;
}
/**
* Commit the changes recorded to a Host. It is assumed that the host does have the same structure
* as the host that was used for backend (could be the same host).
* @param host The host to create/delete/rename/overwrite files to.
* @param force Whether to skip existence checks when creating/overwriting. This is
* faster but might lead to incorrect states. Because Hosts natively don't support creation
* versus overwriting (it's only writing), we check for existence before completing a request.
* @returns An observable that completes when done, or error if an error occured.
*/
commit(host, force = false) {
// Really commit everything to the actual host.
return (0, rxjs_1.from)(this.records()).pipe((0, rxjs_1.concatMap)((record) => {
switch (record.kind) {
case 'delete':
return host.delete(record.path);
case 'rename':
return host.rename(record.from, record.to);
case 'create':
return host.exists(record.path).pipe((0, rxjs_1.switchMap)((exists) => {
if (exists && !force) {
return (0, rxjs_1.throwError)(new exception_1.FileAlreadyExistException(record.path));
}
else {
return host.write(record.path, record.content);
}
}));
case 'overwrite':
return host.exists(record.path).pipe((0, rxjs_1.switchMap)((exists) => {
if (!exists && !force) {
return (0, rxjs_1.throwError)(new exception_1.FileDoesNotExistException(record.path));
}
else {
return host.write(record.path, record.content);
}
}));
}
}), (0, rxjs_1.reduce)(() => { }));
}
records() {
return [
...[...this._filesToDelete.values()].map((path) => ({
kind: 'delete',
path,
})),
...[...this._filesToRename.entries()].map(([from, to]) => ({
kind: 'rename',
from,
to,
})),
...[...this._filesToCreate.values()].map((path) => ({
kind: 'create',
path,
content: this._read(path),
})),
...[...this._filesToOverwrite.values()].map((path) => ({
kind: 'overwrite',
path,
content: this._read(path),
})),
];
}
/**
* Specialized version of {@link CordHost#write} which forces the creation of a file whether it
* exists or not.
* @param {} path
* @param {FileBuffer} content
* @returns {Observable<void>}
*/
create(path, content) {
if (super._exists(path)) {
throw new exception_1.FileAlreadyExistException(path);
}
if (this._filesToDelete.has(path)) {
this._filesToDelete.delete(path);
this._filesToOverwrite.add(path);
}
else {
this._filesToCreate.add(path);
}
return super.write(path, content);
}
overwrite(path, content) {
return this.isDirectory(path).pipe((0, rxjs_1.switchMap)((isDir) => {
if (isDir) {
return (0, rxjs_1.throwError)(new exception_1.PathIsDirectoryException(path));
}
return this.exists(path);
}), (0, rxjs_1.switchMap)((exists) => {
if (!exists) {
return (0, rxjs_1.throwError)(new exception_1.FileDoesNotExistException(path));
}
if (!this._filesToCreate.has(path)) {
this._filesToOverwrite.add(path);
}
return super.write(path, content);
}));
}
write(path, content) {
return this.exists(path).pipe((0, rxjs_1.switchMap)((exists) => {
if (exists) {
// It exists, but might be being renamed or deleted. In that case we want to create it.
if (this.willRename(path) || this.willDelete(path)) {
return this.create(path, content);
}
else {
return this.overwrite(path, content);
}
}
else {
return this.create(path, content);
}
}));
}
read(path) {
if (this._exists(path)) {
return super.read(path);
}
return this._back.read(path);
}
delete(path) {
if (this._exists(path)) {
if (this._filesToCreate.has(path)) {
this._filesToCreate.delete(path);
}
else if (this._filesToOverwrite.has(path)) {
this._filesToOverwrite.delete(path);
this._filesToDelete.add(path);
}
else {
const maybeOrigin = this._filesToRenameRevert.get(path);
if (maybeOrigin) {
this._filesToRenameRevert.delete(path);
this._filesToRename.delete(maybeOrigin);
this._filesToDelete.add(maybeOrigin);
}
else {
return (0, rxjs_1.throwError)(new exception_1.UnknownException(`This should never happen. Path: ${JSON.stringify(path)}.`));
}
}
return super.delete(path);
}
else {
return this._back.exists(path).pipe((0, rxjs_1.switchMap)((exists) => {
if (exists) {
this._filesToDelete.add(path);
return (0, rxjs_1.of)();
}
else {
return (0, rxjs_1.throwError)(new exception_1.FileDoesNotExistException(path));
}
}));
}
}
rename(from, to) {
return (0, rxjs_1.concat)(this.exists(to), this.exists(from)).pipe((0, rxjs_1.toArray)(), (0, rxjs_1.switchMap)(([existTo, existFrom]) => {
if (!existFrom) {
return (0, rxjs_1.throwError)(new exception_1.FileDoesNotExistException(from));
}
if (from === to) {
return rxjs_1.EMPTY;
}
if (existTo) {
return (0, rxjs_1.throwError)(new exception_1.FileAlreadyExistException(to));
}
// If we're renaming a file that's been created, shortcircuit to creating the `to` path.
if (this._filesToCreate.has(from)) {
this._filesToCreate.delete(from);
this._filesToCreate.add(to);
return super.rename(from, to);
}
if (this._filesToOverwrite.has(from)) {
this._filesToOverwrite.delete(from);
// Recursively call this function. This is so we don't repeat the bottom logic. This
// if will be by-passed because we just deleted the `from` path from files to overwrite.
return (0, rxjs_1.concat)(this.rename(from, to), new rxjs_1.Observable((x) => {
this._filesToOverwrite.add(to);
x.complete();
}));
}
if (this._filesToDelete.has(to)) {
this._filesToDelete.delete(to);
this._filesToDelete.add(from);
this._filesToOverwrite.add(to);
// We need to delete the original and write the new one.
return this.read(from).pipe((0, rxjs_1.map)((content) => this._write(to, content)));
}
const maybeTo1 = this._filesToRenameRevert.get(from);
if (maybeTo1) {
// We already renamed to this file (A => from), let's rename the former to the new
// path (A => to).
this._filesToRename.delete(maybeTo1);
this._filesToRenameRevert.delete(from);
from = maybeTo1;
}
this._filesToRename.set(from, to);
this._filesToRenameRevert.set(to, from);
// If the file is part of our data, just rename it internally.
if (this._exists(from)) {
return super.rename(from, to);
}
else {
// Create a file with the same content.
return this._back.read(from).pipe((0, rxjs_1.switchMap)((content) => super.write(to, content)));
}
}));
}
list(path) {
return (0, rxjs_1.concat)(super.list(path), this._back.list(path)).pipe((0, rxjs_1.reduce)((list, curr) => {
curr.forEach((elem) => list.add(elem));
return list;
}, new Set()), (0, rxjs_1.map)((set) => [...set]));
}
exists(path) {
return this._exists(path)
? (0, rxjs_1.of)(true)
: this.willDelete(path) || this.willRename(path)
? (0, rxjs_1.of)(false)
: this._back.exists(path);
}
isDirectory(path) {
return this._exists(path) ? super.isDirectory(path) : this._back.isDirectory(path);
}
isFile(path) {
return this._exists(path)
? super.isFile(path)
: this.willDelete(path) || this.willRename(path)
? (0, rxjs_1.of)(false)
: this._back.isFile(path);
}
stat(path) {
return this._exists(path)
? super.stat(path)
: this.willDelete(path) || this.willRename(path)
? (0, rxjs_1.of)(null)
: this._back.stat(path);
}
watch(path, options) {
// Watching not supported.
return null;
}
willCreate(path) {
return this._filesToCreate.has(path);
}
willOverwrite(path) {
return this._filesToOverwrite.has(path);
}
willDelete(path) {
return this._filesToDelete.has(path);
}
willRename(path) {
return this._filesToRename.has(path);
}
willRenameTo(path, to) {
return this._filesToRename.get(path) === to;
}
}
exports.CordHost = CordHost;

View file

@ -0,0 +1,30 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, Host, HostCapabilities, HostWatchEvent, HostWatchOptions, Stats } from './interface';
/**
* A Host that runs a method before calling its delegate. This is an abstract class and its actual
* behaviour is entirely dependant of the subclass.
*/
export declare abstract class ResolverHost<T extends object> implements Host<T> {
protected _delegate: Host<T>;
protected abstract _resolve(path: Path): Path;
constructor(_delegate: Host<T>);
get capabilities(): HostCapabilities;
write(path: Path, content: FileBuffer): Observable<void>;
read(path: Path): Observable<FileBuffer>;
delete(path: Path): Observable<void>;
rename(from: Path, to: Path): Observable<void>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats<T> | null> | null;
watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent> | null;
}

View file

@ -0,0 +1,56 @@
"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 });
exports.ResolverHost = void 0;
/**
* A Host that runs a method before calling its delegate. This is an abstract class and its actual
* behaviour is entirely dependant of the subclass.
*/
class ResolverHost {
_delegate;
constructor(_delegate) {
this._delegate = _delegate;
}
get capabilities() {
return this._delegate.capabilities;
}
write(path, content) {
return this._delegate.write(this._resolve(path), content);
}
read(path) {
return this._delegate.read(this._resolve(path));
}
delete(path) {
return this._delegate.delete(this._resolve(path));
}
rename(from, to) {
return this._delegate.rename(this._resolve(from), this._resolve(to));
}
list(path) {
return this._delegate.list(this._resolve(path));
}
exists(path) {
return this._delegate.exists(this._resolve(path));
}
isDirectory(path) {
return this._delegate.isDirectory(this._resolve(path));
}
isFile(path) {
return this._delegate.isFile(this._resolve(path));
}
// Some hosts may not support stat.
stat(path) {
return this._delegate.stat(this._resolve(path));
}
// Some hosts may not support watching.
watch(path, options) {
return this._delegate.watch(this._resolve(path), options);
}
}
exports.ResolverHost = ResolverHost;

View file

@ -0,0 +1,25 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, HostCapabilities, ReadonlyHost, Stats } from './interface';
/**
* A Host that filters out errors. The only exception is `read()` which will still error out if
* the delegate returned an error (e.g. NodeJS will error out if the file doesn't exist).
*/
export declare class SafeReadonlyHost<StatsT extends object = {}> implements ReadonlyHost<StatsT> {
private _delegate;
constructor(_delegate: ReadonlyHost<StatsT>);
get capabilities(): HostCapabilities;
read(path: Path): Observable<FileBuffer>;
list(path: Path): Observable<PathFragment[]>;
exists(path: Path): Observable<boolean>;
isDirectory(path: Path): Observable<boolean>;
isFile(path: Path): Observable<boolean>;
stat(path: Path): Observable<Stats<StatsT> | null> | null;
}

View file

@ -0,0 +1,45 @@
"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 });
exports.SafeReadonlyHost = void 0;
const rxjs_1 = require("rxjs");
/**
* A Host that filters out errors. The only exception is `read()` which will still error out if
* the delegate returned an error (e.g. NodeJS will error out if the file doesn't exist).
*/
class SafeReadonlyHost {
_delegate;
constructor(_delegate) {
this._delegate = _delegate;
}
get capabilities() {
return this._delegate.capabilities;
}
read(path) {
return this._delegate.read(path);
}
list(path) {
return this._delegate.list(path).pipe((0, rxjs_1.catchError)(() => (0, rxjs_1.of)([])));
}
exists(path) {
return this._delegate.exists(path);
}
isDirectory(path) {
return this._delegate.isDirectory(path).pipe((0, rxjs_1.catchError)(() => (0, rxjs_1.of)(false)));
}
isFile(path) {
return this._delegate.isFile(path).pipe((0, rxjs_1.catchError)(() => (0, rxjs_1.of)(false)));
}
// Some hosts may not support stats.
stat(path) {
const maybeStat = this._delegate.stat(path);
return maybeStat && maybeStat.pipe((0, rxjs_1.catchError)(() => (0, rxjs_1.of)(null)));
}
}
exports.SafeReadonlyHost = SafeReadonlyHost;

View file

@ -0,0 +1,15 @@
/**
* @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 { Path } from '../path';
import { Host } from './interface';
import { ResolverHost } from './resolver';
export declare class ScopedHost<T extends object> extends ResolverHost<T> {
protected _root: Path;
constructor(delegate: Host<T>, _root?: Path);
protected _resolve(path: Path): Path;
}

View file

@ -0,0 +1,23 @@
"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 });
exports.ScopedHost = void 0;
const path_1 = require("../path");
const resolver_1 = require("./resolver");
class ScopedHost extends resolver_1.ResolverHost {
_root;
constructor(delegate, _root = path_1.NormalizedRoot) {
super(delegate);
this._root = _root;
}
_resolve(path) {
return (0, path_1.join)(this._root, path);
}
}
exports.ScopedHost = ScopedHost;

View file

@ -0,0 +1,34 @@
/**
* @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 { Observable } from 'rxjs';
import { BaseException } from '../../exception';
import { Path, PathFragment } from '../path';
import { FileBuffer, FileBufferLike, Host, HostCapabilities, HostWatchEvent, HostWatchOptions, Stats } from './interface';
export declare class SynchronousDelegateExpectedException extends BaseException {
constructor();
}
/**
* Implement a synchronous-only host interface (remove the Observable parts).
*/
export declare class SyncDelegateHost<T extends object = {}> {
protected _delegate: Host<T>;
constructor(_delegate: Host<T>);
protected _doSyncCall<ResultT>(observable: Observable<ResultT>): ResultT;
get capabilities(): HostCapabilities;
get delegate(): Host<T>;
write(path: Path, content: FileBufferLike): void;
read(path: Path): FileBuffer;
delete(path: Path): void;
rename(from: Path, to: Path): void;
list(path: Path): PathFragment[];
exists(path: Path): boolean;
isDirectory(path: Path): boolean;
isFile(path: Path): boolean;
stat(path: Path): Stats<T> | null;
watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent> | null;
}

View file

@ -0,0 +1,92 @@
"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 });
exports.SyncDelegateHost = exports.SynchronousDelegateExpectedException = void 0;
const exception_1 = require("../../exception");
class SynchronousDelegateExpectedException extends exception_1.BaseException {
constructor() {
super(`Expected a synchronous delegate but got an asynchronous one.`);
}
}
exports.SynchronousDelegateExpectedException = SynchronousDelegateExpectedException;
/**
* Implement a synchronous-only host interface (remove the Observable parts).
*/
class SyncDelegateHost {
_delegate;
constructor(_delegate) {
this._delegate = _delegate;
if (!_delegate.capabilities.synchronous) {
throw new SynchronousDelegateExpectedException();
}
}
_doSyncCall(observable) {
let completed = false;
let result = undefined;
let errorResult = undefined;
// Perf note: this is not using an observer object to avoid a performance penalty in RxJS.
// See https://github.com/ReactiveX/rxjs/pull/5646 for details.
observable.subscribe((x) => (result = x), (err) => (errorResult = err), () => (completed = true));
if (errorResult !== undefined) {
throw errorResult;
}
if (!completed) {
throw new SynchronousDelegateExpectedException();
}
// The non-null operation is to work around `void` type. We don't allow to return undefined
// but ResultT could be void, which is undefined in JavaScript, so this doesn't change the
// behaviour.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return result;
}
get capabilities() {
return this._delegate.capabilities;
}
get delegate() {
return this._delegate;
}
write(path, content) {
return this._doSyncCall(this._delegate.write(path, content));
}
read(path) {
return this._doSyncCall(this._delegate.read(path));
}
delete(path) {
return this._doSyncCall(this._delegate.delete(path));
}
rename(from, to) {
return this._doSyncCall(this._delegate.rename(from, to));
}
list(path) {
return this._doSyncCall(this._delegate.list(path));
}
exists(path) {
return this._doSyncCall(this._delegate.exists(path));
}
isDirectory(path) {
return this._doSyncCall(this._delegate.isDirectory(path));
}
isFile(path) {
return this._doSyncCall(this._delegate.isFile(path));
}
// Some hosts may not support stat.
stat(path) {
const result = this._delegate.stat(path);
if (result) {
return this._doSyncCall(result);
}
else {
return null;
}
}
watch(path, options) {
return this._delegate.watch(path, options);
}
}
exports.SyncDelegateHost = SyncDelegateHost;

View file

@ -0,0 +1,50 @@
/**
* @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 { Observable } from 'rxjs';
import { Path, PathFragment } from '../path';
import { FileBuffer, HostWatchEvent, HostWatchOptions, Stats } from './interface';
import { SimpleMemoryHost, SimpleMemoryHostStats } from './memory';
import { SyncDelegateHost } from './sync';
export declare namespace test {
type TestLogRecord = {
kind: 'write' | 'read' | 'delete' | 'list' | 'exists' | 'isDirectory' | 'isFile' | 'stat' | 'watch';
path: Path;
} | {
kind: 'rename';
from: Path;
to: Path;
};
class TestHost extends SimpleMemoryHost {
protected _records: TestLogRecord[];
protected _sync: SyncDelegateHost<{}> | null;
constructor(map?: {
[path: string]: string;
});
get records(): TestLogRecord[];
clearRecords(): void;
get files(): Path[];
get sync(): SyncDelegateHost<{}>;
clone(): TestHost;
protected _write(path: Path, content: FileBuffer): void;
protected _read(path: Path): ArrayBuffer;
protected _delete(path: Path): void;
protected _rename(from: Path, to: Path): void;
protected _list(path: Path): PathFragment[];
protected _exists(path: Path): boolean;
protected _isDirectory(path: Path): boolean;
protected _isFile(path: Path): boolean;
protected _stat(path: Path): Stats<SimpleMemoryHostStats> | null;
protected _watch(path: Path, options?: HostWatchOptions): Observable<HostWatchEvent>;
$write(path: string, content: string): void;
$read(path: string): string;
$list(path: string): PathFragment[];
$exists(path: string): boolean;
$isDirectory(path: string): boolean;
$isFile(path: string): boolean;
}
}

View file

@ -0,0 +1,122 @@
"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 });
exports.test = void 0;
const path_1 = require("../path");
const buffer_1 = require("./buffer");
const memory_1 = require("./memory");
const sync_1 = require("./sync");
// eslint-disable-next-line @typescript-eslint/no-namespace
var test;
(function (test) {
class TestHost extends memory_1.SimpleMemoryHost {
_records = [];
_sync = null;
constructor(map = {}) {
super();
for (const filePath of Object.getOwnPropertyNames(map)) {
this._write((0, path_1.normalize)(filePath), (0, buffer_1.stringToFileBuffer)(map[filePath]));
}
}
get records() {
return [...this._records];
}
clearRecords() {
this._records = [];
}
get files() {
const sync = this.sync;
function _visit(p) {
return sync
.list(p)
.map((fragment) => (0, path_1.join)(p, fragment))
.reduce((files, path) => {
if (sync.isDirectory(path)) {
return files.concat(_visit(path));
}
else {
return files.concat(path);
}
}, []);
}
return _visit((0, path_1.normalize)('/'));
}
get sync() {
if (!this._sync) {
this._sync = new sync_1.SyncDelegateHost(this);
}
return this._sync;
}
clone() {
const newHost = new TestHost();
newHost._cache = new Map(this._cache);
return newHost;
}
// Override parents functions to keep a record of all operators that were done.
_write(path, content) {
this._records.push({ kind: 'write', path });
return super._write(path, content);
}
_read(path) {
this._records.push({ kind: 'read', path });
return super._read(path);
}
_delete(path) {
this._records.push({ kind: 'delete', path });
return super._delete(path);
}
_rename(from, to) {
this._records.push({ kind: 'rename', from, to });
return super._rename(from, to);
}
_list(path) {
this._records.push({ kind: 'list', path });
return super._list(path);
}
_exists(path) {
this._records.push({ kind: 'exists', path });
return super._exists(path);
}
_isDirectory(path) {
this._records.push({ kind: 'isDirectory', path });
return super._isDirectory(path);
}
_isFile(path) {
this._records.push({ kind: 'isFile', path });
return super._isFile(path);
}
_stat(path) {
this._records.push({ kind: 'stat', path });
return super._stat(path);
}
_watch(path, options) {
this._records.push({ kind: 'watch', path });
return super._watch(path, options);
}
$write(path, content) {
return super._write((0, path_1.normalize)(path), (0, buffer_1.stringToFileBuffer)(content));
}
$read(path) {
return (0, buffer_1.fileBufferToString)(super._read((0, path_1.normalize)(path)));
}
$list(path) {
return super._list((0, path_1.normalize)(path));
}
$exists(path) {
return super._exists((0, path_1.normalize)(path));
}
$isDirectory(path) {
return super._isDirectory((0, path_1.normalize)(path));
}
$isFile(path) {
return super._isFile((0, path_1.normalize)(path));
}
}
test.TestHost = TestHost;
})(test || (exports.test = test = {}));

View file

@ -0,0 +1,10 @@
/**
* @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 * as virtualFs from './host/index';
export * from './path';
export { virtualFs };

View file

@ -0,0 +1,39 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.virtualFs = void 0;
const virtualFs = __importStar(require("./host/index"));
exports.virtualFs = virtualFs;
__exportStar(require("./path"), exports);

View file

@ -0,0 +1,113 @@
/**
* @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 { BaseException } from '../exception';
import { TemplateTag } from '../utils/literals';
export declare class InvalidPathException extends BaseException {
constructor(path: string);
}
export declare class PathMustBeAbsoluteException extends BaseException {
constructor(path: string);
}
export declare class PathCannotBeFragmentException extends BaseException {
constructor(path: string);
}
/**
* A Path recognized by most methods in the DevKit.
*/
export type Path = string & {
__PRIVATE_DEVKIT_PATH: void;
};
/**
* A Path fragment (file or directory name) recognized by most methods in the DevKit.
*/
export type PathFragment = Path & {
__PRIVATE_DEVKIT_PATH_FRAGMENT: void;
};
/**
* The Separator for normalized path.
* @type {Path}
*/
export declare const NormalizedSep: Path;
/**
* The root of a normalized path.
* @type {Path}
*/
export declare const NormalizedRoot: Path;
/**
* Split a path into multiple path fragments. Each fragments except the last one will end with
* a path separator.
* @param {Path} path The path to split.
* @returns {Path[]} An array of path fragments.
*/
export declare function split(path: Path): PathFragment[];
/**
*
*/
export declare function extname(path: Path): string;
/**
* Return the basename of the path, as a Path. See path.basename
*/
export declare function basename(path: Path): PathFragment;
/**
* Return the dirname of the path, as a Path. See path.dirname
*/
export declare function dirname(path: Path): Path;
/**
* Join multiple paths together, and normalize the result. Accepts strings that will be
* normalized as well (but the original must be a path).
*/
export declare function join(p1: Path, ...others: string[]): Path;
/**
* Returns true if a path is absolute.
*/
export declare function isAbsolute(p: Path): boolean;
/**
* Returns a path such that `join(from, relative(from, to)) == to`.
* Both paths must be absolute, otherwise it does not make much sense.
*/
export declare function relative(from: Path, to: Path): Path;
/**
* Returns a Path that is the resolution of p2, from p1. If p2 is absolute, it will return p2,
* otherwise will join both p1 and p2.
*/
export declare function resolve(p1: Path, p2: Path): Path;
export declare function fragment(path: string): PathFragment;
/**
* Reset the cache. This is only useful for testing.
* @private
*/
export declare function resetNormalizeCache(): void;
/**
* Normalize a string into a Path. This is the only mean to get a Path type from a string that
* represents a system path. This method cache the results as real world paths tend to be
* duplicated often.
* Normalization includes:
* - Windows backslashes `\\` are replaced with `/`.
* - Windows drivers are replaced with `/X/`, where X is the drive letter.
* - Absolute paths starts with `/`.
* - Multiple `/` are replaced by a single one.
* - Path segments `.` are removed.
* - Path segments `..` are resolved.
* - If a path is absolute, having a `..` at the start is invalid (and will throw).
* @param path The path to be normalized.
*/
export declare function normalize(path: string): Path;
/**
* The no cache version of the normalize() function. Used for benchmarking and testing.
*/
export declare function noCacheNormalize(path: string): Path;
export declare const path: TemplateTag<Path>;
export type WindowsPath = string & {
__PRIVATE_DEVKIT_WINDOWS_PATH: void;
};
export type PosixPath = string & {
__PRIVATE_DEVKIT_POSIX_PATH: void;
};
export declare function asWindowsPath(path: Path): WindowsPath;
export declare function asPosixPath(path: Path): PosixPath;
export declare function getSystemPath(path: Path): string;

View file

@ -0,0 +1,287 @@
"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 });
exports.getSystemPath = exports.asPosixPath = exports.asWindowsPath = exports.path = exports.noCacheNormalize = exports.normalize = exports.resetNormalizeCache = exports.fragment = exports.resolve = exports.relative = exports.isAbsolute = exports.join = exports.dirname = exports.basename = exports.extname = exports.split = exports.NormalizedRoot = exports.NormalizedSep = exports.PathCannotBeFragmentException = exports.PathMustBeAbsoluteException = exports.InvalidPathException = void 0;
const exception_1 = require("../exception");
class InvalidPathException extends exception_1.BaseException {
constructor(path) {
super(`Path ${JSON.stringify(path)} is invalid.`);
}
}
exports.InvalidPathException = InvalidPathException;
class PathMustBeAbsoluteException extends exception_1.BaseException {
constructor(path) {
super(`Path ${JSON.stringify(path)} must be absolute.`);
}
}
exports.PathMustBeAbsoluteException = PathMustBeAbsoluteException;
class PathCannotBeFragmentException extends exception_1.BaseException {
constructor(path) {
super(`Path ${JSON.stringify(path)} cannot be made a fragment.`);
}
}
exports.PathCannotBeFragmentException = PathCannotBeFragmentException;
/**
* The Separator for normalized path.
* @type {Path}
*/
exports.NormalizedSep = '/';
/**
* The root of a normalized path.
* @type {Path}
*/
exports.NormalizedRoot = exports.NormalizedSep;
/**
* Split a path into multiple path fragments. Each fragments except the last one will end with
* a path separator.
* @param {Path} path The path to split.
* @returns {Path[]} An array of path fragments.
*/
function split(path) {
const fragments = path.split(exports.NormalizedSep).map((x) => fragment(x));
if (fragments[fragments.length - 1].length === 0) {
fragments.pop();
}
return fragments;
}
exports.split = split;
/**
*
*/
function extname(path) {
const base = basename(path);
const i = base.lastIndexOf('.');
if (i < 1) {
return '';
}
else {
return base.slice(i);
}
}
exports.extname = extname;
/**
* Return the basename of the path, as a Path. See path.basename
*/
function basename(path) {
const i = path.lastIndexOf(exports.NormalizedSep);
if (i == -1) {
return fragment(path);
}
else {
return fragment(path.slice(path.lastIndexOf(exports.NormalizedSep) + 1));
}
}
exports.basename = basename;
/**
* Return the dirname of the path, as a Path. See path.dirname
*/
function dirname(path) {
const index = path.lastIndexOf(exports.NormalizedSep);
if (index === -1) {
return '';
}
const endIndex = index === 0 ? 1 : index; // case of file under root: '/file'
return normalize(path.slice(0, endIndex));
}
exports.dirname = dirname;
/**
* Join multiple paths together, and normalize the result. Accepts strings that will be
* normalized as well (but the original must be a path).
*/
function join(p1, ...others) {
if (others.length > 0) {
return normalize((p1 ? p1 + exports.NormalizedSep : '') + others.join(exports.NormalizedSep));
}
else {
return p1;
}
}
exports.join = join;
/**
* Returns true if a path is absolute.
*/
function isAbsolute(p) {
return p.startsWith(exports.NormalizedSep);
}
exports.isAbsolute = isAbsolute;
/**
* Returns a path such that `join(from, relative(from, to)) == to`.
* Both paths must be absolute, otherwise it does not make much sense.
*/
function relative(from, to) {
if (!isAbsolute(from)) {
throw new PathMustBeAbsoluteException(from);
}
if (!isAbsolute(to)) {
throw new PathMustBeAbsoluteException(to);
}
let p;
if (from == to) {
p = '';
}
else {
const splitFrom = split(from);
const splitTo = split(to);
while (splitFrom.length > 0 && splitTo.length > 0 && splitFrom[0] == splitTo[0]) {
splitFrom.shift();
splitTo.shift();
}
if (splitFrom.length == 0) {
p = splitTo.join(exports.NormalizedSep);
}
else {
p = splitFrom
.map(() => '..')
.concat(splitTo)
.join(exports.NormalizedSep);
}
}
return normalize(p);
}
exports.relative = relative;
/**
* Returns a Path that is the resolution of p2, from p1. If p2 is absolute, it will return p2,
* otherwise will join both p1 and p2.
*/
function resolve(p1, p2) {
if (isAbsolute(p2)) {
return p2;
}
else {
return join(p1, p2);
}
}
exports.resolve = resolve;
function fragment(path) {
if (path.indexOf(exports.NormalizedSep) != -1) {
throw new PathCannotBeFragmentException(path);
}
return path;
}
exports.fragment = fragment;
/**
* normalize() cache to reduce computation. For now this grows and we never flush it, but in the
* future we might want to add a few cache flush to prevent this from growing too large.
*/
let normalizedCache = new Map();
/**
* Reset the cache. This is only useful for testing.
* @private
*/
function resetNormalizeCache() {
normalizedCache = new Map();
}
exports.resetNormalizeCache = resetNormalizeCache;
/**
* Normalize a string into a Path. This is the only mean to get a Path type from a string that
* represents a system path. This method cache the results as real world paths tend to be
* duplicated often.
* Normalization includes:
* - Windows backslashes `\\` are replaced with `/`.
* - Windows drivers are replaced with `/X/`, where X is the drive letter.
* - Absolute paths starts with `/`.
* - Multiple `/` are replaced by a single one.
* - Path segments `.` are removed.
* - Path segments `..` are resolved.
* - If a path is absolute, having a `..` at the start is invalid (and will throw).
* @param path The path to be normalized.
*/
function normalize(path) {
let maybePath = normalizedCache.get(path);
if (!maybePath) {
maybePath = noCacheNormalize(path);
normalizedCache.set(path, maybePath);
}
return maybePath;
}
exports.normalize = normalize;
/**
* The no cache version of the normalize() function. Used for benchmarking and testing.
*/
function noCacheNormalize(path) {
if (path == '' || path == '.') {
return '';
}
else if (path == exports.NormalizedRoot) {
return exports.NormalizedRoot;
}
// Match absolute windows path.
const original = path;
if (path.match(/^[A-Z]:[/\\]/i)) {
path = '\\' + path[0] + '\\' + path.slice(3);
}
// We convert Windows paths as well here.
const p = path.split(/[/\\]/g);
let relative = false;
let i = 1;
// Special case the first one.
if (p[0] != '') {
p.unshift('.');
relative = true;
}
while (i < p.length) {
if (p[i] == '.') {
p.splice(i, 1);
}
else if (p[i] == '..') {
if (i < 2 && !relative) {
throw new InvalidPathException(original);
}
else if (i >= 2 && p[i - 1] != '..') {
p.splice(i - 1, 2);
i--;
}
else {
i++;
}
}
else if (p[i] == '') {
p.splice(i, 1);
}
else {
i++;
}
}
if (p.length == 1) {
return p[0] == '' ? exports.NormalizedSep : '';
}
else {
if (p[0] == '.') {
p.shift();
}
return p.join(exports.NormalizedSep);
}
}
exports.noCacheNormalize = noCacheNormalize;
const path = (strings, ...values) => {
return normalize(String.raw(strings, ...values));
};
exports.path = path;
function asWindowsPath(path) {
const drive = path.match(/^\/(\w)(?:\/(.*))?$/);
if (drive) {
const subPath = drive[2] ? drive[2].replace(/\//g, '\\') : '';
return `${drive[1]}:\\${subPath}`;
}
return path.replace(/\//g, '\\');
}
exports.asWindowsPath = asWindowsPath;
function asPosixPath(path) {
return path;
}
exports.asPosixPath = asPosixPath;
function getSystemPath(path) {
if (process.platform.startsWith('win32')) {
return asWindowsPath(path);
}
else {
return asPosixPath(path);
}
}
exports.getSystemPath = getSystemPath;

View file

@ -0,0 +1,61 @@
/**
* @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 { WorkspaceDefinition } from './definitions';
import { WorkspaceHost } from './host';
/**
* Supported workspace formats
*/
export declare enum WorkspaceFormat {
JSON = 0
}
/**
* @private
*/
export declare function _test_addWorkspaceFile(name: string, format: WorkspaceFormat): void;
/**
* @private
*/
export declare function _test_removeWorkspaceFile(name: string): void;
/**
* Reads and constructs a `WorkspaceDefinition`. If the function is provided with a path to a
* directory instead of a file, a search of the directory's files will commence to attempt to
* locate a known workspace file. Currently the following are considered known workspace files:
* - `angular.json`
* - `.angular.json`
*
* @param path The path to either a workspace file or a directory containing a workspace file.
* @param host The `WorkspaceHost` to use to access the file and directory data.
* @param format An optional `WorkspaceFormat` value. Used if the path specifies a non-standard
* file name that would prevent automatically discovering the format.
*
*
* @return An `Promise` of the read result object with the `WorkspaceDefinition` contained within
* the `workspace` property.
*/
export declare function readWorkspace(path: string, host: WorkspaceHost, format?: WorkspaceFormat): Promise<{
workspace: WorkspaceDefinition;
}>;
/**
* Writes a `WorkspaceDefinition` to the underlying storage via the provided `WorkspaceHost`.
* If the `WorkspaceDefinition` was created via the `readWorkspace` function, metadata will be
* used to determine the path and format of the Workspace. In all other cases, the `path` and
* `format` options must be specified as they would be otherwise unknown.
*
* @param workspace The `WorkspaceDefinition` that will be written.
* @param host The `WorkspaceHost` to use to access/write the file and directory data.
* @param path The path to a file location for the output. Required if `readWorkspace` was not
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
* `WorkspaceDefinition` metadata if provided.
* @param format The `WorkspaceFormat` to use for output. Required if `readWorkspace` was not
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
* `WorkspaceDefinition` metadata if provided.
*
*
* @return An `Promise` of type `void`.
*/
export declare function writeWorkspace(workspace: WorkspaceDefinition, host: WorkspaceHost, path?: string, format?: WorkspaceFormat): Promise<void>;

View file

@ -0,0 +1,132 @@
"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 });
exports.writeWorkspace = exports.readWorkspace = exports._test_removeWorkspaceFile = exports._test_addWorkspaceFile = exports.WorkspaceFormat = void 0;
const virtual_fs_1 = require("../virtual-fs");
const reader_1 = require("./json/reader");
const writer_1 = require("./json/writer");
const formatLookup = new WeakMap();
/**
* Supported workspace formats
*/
var WorkspaceFormat;
(function (WorkspaceFormat) {
WorkspaceFormat[WorkspaceFormat["JSON"] = 0] = "JSON";
})(WorkspaceFormat || (exports.WorkspaceFormat = WorkspaceFormat = {}));
/**
* @private
*/
function _test_addWorkspaceFile(name, format) {
workspaceFiles[name] = format;
}
exports._test_addWorkspaceFile = _test_addWorkspaceFile;
/**
* @private
*/
function _test_removeWorkspaceFile(name) {
delete workspaceFiles[name];
}
exports._test_removeWorkspaceFile = _test_removeWorkspaceFile;
// NOTE: future additions could also perform content analysis to determine format/version
const workspaceFiles = {
'angular.json': WorkspaceFormat.JSON,
'.angular.json': WorkspaceFormat.JSON,
};
/**
* Reads and constructs a `WorkspaceDefinition`. If the function is provided with a path to a
* directory instead of a file, a search of the directory's files will commence to attempt to
* locate a known workspace file. Currently the following are considered known workspace files:
* - `angular.json`
* - `.angular.json`
*
* @param path The path to either a workspace file or a directory containing a workspace file.
* @param host The `WorkspaceHost` to use to access the file and directory data.
* @param format An optional `WorkspaceFormat` value. Used if the path specifies a non-standard
* file name that would prevent automatically discovering the format.
*
*
* @return An `Promise` of the read result object with the `WorkspaceDefinition` contained within
* the `workspace` property.
*/
async function readWorkspace(path, host, format) {
if (await host.isDirectory(path)) {
// TODO: Warn if multiple found (requires diagnostics support)
const directory = (0, virtual_fs_1.normalize)(path);
let found = false;
for (const [name, nameFormat] of Object.entries(workspaceFiles)) {
if (format !== undefined && format !== nameFormat) {
continue;
}
const potential = (0, virtual_fs_1.getSystemPath)((0, virtual_fs_1.join)(directory, name));
if (await host.isFile(potential)) {
path = potential;
format = nameFormat;
found = true;
break;
}
}
if (!found) {
throw new Error('Unable to locate a workspace file for workspace path. Are you missing an `angular.json`' +
' or `.angular.json` file?');
}
}
else if (format === undefined) {
const filename = (0, virtual_fs_1.basename)((0, virtual_fs_1.normalize)(path));
if (filename in workspaceFiles) {
format = workspaceFiles[filename];
}
}
if (format === undefined) {
throw new Error('Unable to determine format for workspace path.');
}
let workspace;
switch (format) {
case WorkspaceFormat.JSON:
workspace = await (0, reader_1.readJsonWorkspace)(path, host);
break;
default:
throw new Error('Unsupported workspace format.');
}
formatLookup.set(workspace, WorkspaceFormat.JSON);
return { workspace };
}
exports.readWorkspace = readWorkspace;
/**
* Writes a `WorkspaceDefinition` to the underlying storage via the provided `WorkspaceHost`.
* If the `WorkspaceDefinition` was created via the `readWorkspace` function, metadata will be
* used to determine the path and format of the Workspace. In all other cases, the `path` and
* `format` options must be specified as they would be otherwise unknown.
*
* @param workspace The `WorkspaceDefinition` that will be written.
* @param host The `WorkspaceHost` to use to access/write the file and directory data.
* @param path The path to a file location for the output. Required if `readWorkspace` was not
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
* `WorkspaceDefinition` metadata if provided.
* @param format The `WorkspaceFormat` to use for output. Required if `readWorkspace` was not
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
* `WorkspaceDefinition` metadata if provided.
*
*
* @return An `Promise` of type `void`.
*/
async function writeWorkspace(workspace, host, path, format) {
if (format === undefined) {
format = formatLookup.get(workspace);
if (format === undefined) {
throw new Error('A format is required for custom workspace objects.');
}
}
switch (format) {
case WorkspaceFormat.JSON:
return (0, writer_1.writeJsonWorkspace)(workspace, host, path);
default:
throw new Error('Unsupported workspace format.');
}
}
exports.writeWorkspace = writeWorkspace;

View file

@ -0,0 +1,63 @@
/**
* @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 { JsonValue } from '../json';
export interface WorkspaceDefinition {
readonly extensions: Record<string, JsonValue | undefined>;
readonly projects: ProjectDefinitionCollection;
}
export interface ProjectDefinition {
readonly extensions: Record<string, JsonValue | undefined>;
readonly targets: TargetDefinitionCollection;
root: string;
prefix?: string;
sourceRoot?: string;
}
export interface TargetDefinition {
options?: Record<string, JsonValue | undefined>;
configurations?: Record<string, Record<string, JsonValue | undefined> | undefined>;
defaultConfiguration?: string;
builder: string;
}
export type DefinitionCollectionListener<V extends object> = (name: string, newValue: V | undefined, collection: DefinitionCollection<V>) => void;
declare class DefinitionCollection<V extends object> implements ReadonlyMap<string, V> {
private _listener?;
private _map;
constructor(initial?: Record<string, V>, _listener?: DefinitionCollectionListener<V> | undefined);
delete(key: string): boolean;
set(key: string, value: V): this;
forEach<T>(callbackfn: (value: V, key: string, map: DefinitionCollection<V>) => void, thisArg?: T): void;
get(key: string): V | undefined;
has(key: string): boolean;
get size(): number;
[Symbol.iterator](): IterableIterator<[string, V]>;
entries(): IterableIterator<[string, V]>;
keys(): IterableIterator<string>;
values(): IterableIterator<V>;
}
export declare class ProjectDefinitionCollection extends DefinitionCollection<ProjectDefinition> {
constructor(initial?: Record<string, ProjectDefinition>, listener?: DefinitionCollectionListener<ProjectDefinition>);
add(definition: {
name: string;
root: string;
sourceRoot?: string;
prefix?: string;
targets?: Record<string, TargetDefinition | undefined>;
[key: string]: unknown;
}): ProjectDefinition;
set(name: string, value: ProjectDefinition): this;
private _validateName;
}
export declare class TargetDefinitionCollection extends DefinitionCollection<TargetDefinition> {
constructor(initial?: Record<string, TargetDefinition>, listener?: DefinitionCollectionListener<TargetDefinition>);
add(definition: {
name: string;
} & TargetDefinition): TargetDefinition;
set(name: string, value: TargetDefinition): this;
private _validateName;
}
export {};

View file

@ -0,0 +1,168 @@
"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 });
exports.TargetDefinitionCollection = exports.ProjectDefinitionCollection = void 0;
class DefinitionCollection {
_listener;
_map;
constructor(initial, _listener) {
this._listener = _listener;
this._map = new Map(initial && Object.entries(initial));
}
delete(key) {
const result = this._map.delete(key);
if (result) {
this._listener?.(key, undefined, this);
}
return result;
}
set(key, value) {
const updatedValue = value !== this.get(key);
if (updatedValue) {
this._map.set(key, value);
this._listener?.(key, value, this);
}
return this;
}
forEach(callbackfn, thisArg) {
this._map.forEach((value, key) => callbackfn(value, key, this), thisArg);
}
get(key) {
return this._map.get(key);
}
has(key) {
return this._map.has(key);
}
get size() {
return this._map.size;
}
[Symbol.iterator]() {
return this._map[Symbol.iterator]();
}
entries() {
return this._map.entries();
}
keys() {
return this._map.keys();
}
values() {
return this._map.values();
}
}
function isJsonValue(value) {
const visited = new Set();
switch (typeof value) {
case 'boolean':
case 'number':
case 'string':
return true;
case 'object':
if (value === null) {
return true;
}
visited.add(value);
for (const property of Object.values(value)) {
if (typeof value === 'object' && visited.has(property)) {
continue;
}
if (!isJsonValue(property)) {
return false;
}
}
return true;
default:
return false;
}
}
class ProjectDefinitionCollection extends DefinitionCollection {
constructor(initial, listener) {
super(initial, listener);
}
add(definition) {
if (this.has(definition.name)) {
throw new Error('Project name already exists.');
}
this._validateName(definition.name);
const project = {
root: definition.root,
prefix: definition.prefix,
sourceRoot: definition.sourceRoot,
targets: new TargetDefinitionCollection(),
extensions: {},
};
if (definition.targets) {
for (const [name, target] of Object.entries(definition.targets)) {
if (target) {
project.targets.set(name, target);
}
}
}
for (const [name, value] of Object.entries(definition)) {
switch (name) {
case 'name':
case 'root':
case 'sourceRoot':
case 'prefix':
case 'targets':
break;
default:
if (isJsonValue(value)) {
project.extensions[name] = value;
}
else {
throw new TypeError(`"${name}" must be a JSON value.`);
}
break;
}
}
super.set(definition.name, project);
return project;
}
set(name, value) {
this._validateName(name);
super.set(name, value);
return this;
}
_validateName(name) {
if (typeof name !== 'string' || !/^(?:@\w[\w.-]*\/)?\w[\w.-]*$/.test(name)) {
throw new Error('Project name must be a valid npm package name.');
}
}
}
exports.ProjectDefinitionCollection = ProjectDefinitionCollection;
class TargetDefinitionCollection extends DefinitionCollection {
constructor(initial, listener) {
super(initial, listener);
}
add(definition) {
if (this.has(definition.name)) {
throw new Error('Target name already exists.');
}
this._validateName(definition.name);
const target = {
builder: definition.builder,
options: definition.options,
configurations: definition.configurations,
defaultConfiguration: definition.defaultConfiguration,
};
super.set(definition.name, target);
return target;
}
set(name, value) {
this._validateName(name);
super.set(name, value);
return this;
}
_validateName(name) {
if (typeof name !== 'string') {
throw new TypeError('Target name must be a string.');
}
}
}
exports.TargetDefinitionCollection = TargetDefinitionCollection;

View file

@ -0,0 +1,15 @@
/**
* @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 { virtualFs } from '../virtual-fs';
export interface WorkspaceHost {
readFile(path: string): Promise<string>;
writeFile(path: string, data: string): Promise<void>;
isDirectory(path: string): Promise<boolean>;
isFile(path: string): Promise<boolean>;
}
export declare function createWorkspaceHost(host: virtualFs.Host): WorkspaceHost;

View file

@ -0,0 +1,43 @@
"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 });
exports.createWorkspaceHost = void 0;
const rxjs_1 = require("rxjs");
const virtual_fs_1 = require("../virtual-fs");
function createWorkspaceHost(host) {
const workspaceHost = {
async readFile(path) {
const data = await (0, rxjs_1.lastValueFrom)(host.read((0, virtual_fs_1.normalize)(path)));
return virtual_fs_1.virtualFs.fileBufferToString(data);
},
async writeFile(path, data) {
return (0, rxjs_1.lastValueFrom)(host.write((0, virtual_fs_1.normalize)(path), virtual_fs_1.virtualFs.stringToFileBuffer(data)));
},
async isDirectory(path) {
try {
return await (0, rxjs_1.lastValueFrom)(host.isDirectory((0, virtual_fs_1.normalize)(path)));
}
catch {
// some hosts throw if path does not exist
return false;
}
},
async isFile(path) {
try {
return await (0, rxjs_1.lastValueFrom)(host.isFile((0, virtual_fs_1.normalize)(path)));
}
catch {
// some hosts throw if path does not exist
return false;
}
},
};
return workspaceHost;
}
exports.createWorkspaceHost = createWorkspaceHost;

View file

@ -0,0 +1,10 @@
/**
* @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
*/
export * from './definitions';
export { WorkspaceHost, createWorkspaceHost } from './host';
export { WorkspaceFormat, readWorkspace, writeWorkspace } from './core';

View file

@ -0,0 +1,31 @@
"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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeWorkspace = exports.readWorkspace = exports.WorkspaceFormat = exports.createWorkspaceHost = void 0;
__exportStar(require("./definitions"), exports);
var host_1 = require("./host");
Object.defineProperty(exports, "createWorkspaceHost", { enumerable: true, get: function () { return host_1.createWorkspaceHost; } });
var core_1 = require("./core");
Object.defineProperty(exports, "WorkspaceFormat", { enumerable: true, get: function () { return core_1.WorkspaceFormat; } });
Object.defineProperty(exports, "readWorkspace", { enumerable: true, get: function () { return core_1.readWorkspace; } });
Object.defineProperty(exports, "writeWorkspace", { enumerable: true, get: function () { return core_1.writeWorkspace; } });

View file

@ -0,0 +1,40 @@
/**
* @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 { JSONPath, Node } from 'jsonc-parser';
import { JsonValue } from '../../json';
import { ProjectDefinition, TargetDefinition, WorkspaceDefinition } from '../definitions';
export declare const JsonWorkspaceSymbol: unique symbol;
export interface JsonWorkspaceDefinition extends WorkspaceDefinition {
[JsonWorkspaceSymbol]: JsonWorkspaceMetadata;
}
interface ChangeValues {
json: JsonValue;
project: ProjectDefinition;
target: TargetDefinition;
projectcollection: Iterable<[string, ProjectDefinition]>;
targetcollection: Iterable<[string, TargetDefinition]>;
}
export interface JsonChange {
value?: unknown;
type?: keyof ChangeValues;
jsonPath: string[];
}
export declare class JsonWorkspaceMetadata {
readonly filePath: string;
private readonly ast;
readonly raw: string;
readonly changes: Map<string, JsonChange>;
hasLegacyTargetsName: boolean;
constructor(filePath: string, ast: Node, raw: string);
get hasChanges(): boolean;
get changeCount(): number;
getNodeValueFromAst(path: JSONPath): unknown;
findChangesForPath(path: string): JsonChange | undefined;
addChange<T extends keyof ChangeValues = keyof ChangeValues>(jsonPath: string[], value: ChangeValues[T] | undefined, type?: T): void;
}
export {};

View file

@ -0,0 +1,59 @@
"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 });
exports.JsonWorkspaceMetadata = exports.JsonWorkspaceSymbol = void 0;
const jsonc_parser_1 = require("jsonc-parser");
exports.JsonWorkspaceSymbol = Symbol.for('@angular/core:workspace-json');
function escapeKey(key) {
return key.replace('~', '~0').replace('/', '~1');
}
class JsonWorkspaceMetadata {
filePath;
ast;
raw;
changes = new Map();
hasLegacyTargetsName = true;
constructor(filePath, ast, raw) {
this.filePath = filePath;
this.ast = ast;
this.raw = raw;
}
get hasChanges() {
return this.changes.size > 0;
}
get changeCount() {
return this.changes.size;
}
getNodeValueFromAst(path) {
const node = (0, jsonc_parser_1.findNodeAtLocation)(this.ast, path);
return node && (0, jsonc_parser_1.getNodeValue)(node);
}
findChangesForPath(path) {
return this.changes.get(path);
}
addChange(jsonPath, value, type) {
let currentPath = '';
for (let index = 0; index < jsonPath.length - 1; index++) {
currentPath = currentPath + '/' + escapeKey(jsonPath[index]);
if (this.changes.has(currentPath)) {
// Ignore changes on children as parent is updated.
return;
}
}
const pathKey = '/' + jsonPath.map((k) => escapeKey(k)).join('/');
for (const key of this.changes.keys()) {
if (key.startsWith(pathKey + '/')) {
// changes on the same or child paths are redundant.
this.changes.delete(key);
}
}
this.changes.set(pathKey, { jsonPath, type, value });
}
}
exports.JsonWorkspaceMetadata = JsonWorkspaceMetadata;

View file

@ -0,0 +1,14 @@
/**
* @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 { WorkspaceDefinition } from '../definitions';
import { WorkspaceHost } from '../host';
export interface JsonWorkspaceOptions {
allowedProjectExtensions?: string[];
allowedWorkspaceExtensions?: string[];
}
export declare function readJsonWorkspace(path: string, host: WorkspaceHost, options?: JsonWorkspaceOptions): Promise<WorkspaceDefinition>;

View file

@ -0,0 +1,230 @@
"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 });
exports.readJsonWorkspace = void 0;
const jsonc_parser_1 = require("jsonc-parser");
const utils_1 = require("../../json/utils");
const definitions_1 = require("../definitions");
const metadata_1 = require("./metadata");
const utilities_1 = require("./utilities");
const ANGULAR_WORKSPACE_EXTENSIONS = Object.freeze(['cli', 'newProjectRoot', 'schematics']);
const ANGULAR_PROJECT_EXTENSIONS = Object.freeze(['cli', 'schematics', 'projectType', 'i18n']);
async function readJsonWorkspace(path, host, options = {}) {
const raw = await host.readFile(path);
if (raw === undefined) {
throw new Error('Unable to read workspace file.');
}
const ast = (0, jsonc_parser_1.parseTree)(raw, undefined, { allowTrailingComma: true, disallowComments: false });
if (ast?.type !== 'object' || !ast.children) {
throw new Error('Invalid workspace file - expected JSON object.');
}
// Version check
const versionNode = (0, jsonc_parser_1.findNodeAtLocation)(ast, ['version']);
if (!versionNode) {
throw new Error('Unknown format - version specifier not found.');
}
const version = versionNode.value;
if (version !== 1) {
throw new Error(`Invalid format version detected - Expected:[ 1 ] Found: [ ${version} ]`);
}
const context = {
host,
metadata: new metadata_1.JsonWorkspaceMetadata(path, ast, raw),
trackChanges: true,
unprefixedWorkspaceExtensions: new Set([
...ANGULAR_WORKSPACE_EXTENSIONS,
...(options.allowedWorkspaceExtensions ?? []),
]),
unprefixedProjectExtensions: new Set([
...ANGULAR_PROJECT_EXTENSIONS,
...(options.allowedProjectExtensions ?? []),
]),
error(message, _node) {
// TODO: Diagnostic reporting support
throw new Error(message);
},
warn(message, _node) {
// TODO: Diagnostic reporting support
// eslint-disable-next-line no-console
console.warn(message);
},
};
const workspace = parseWorkspace(ast, context);
return workspace;
}
exports.readJsonWorkspace = readJsonWorkspace;
function parseWorkspace(workspaceNode, context) {
const jsonMetadata = context.metadata;
let projects;
let extensions;
if (!context.trackChanges) {
extensions = Object.create(null);
}
// TODO: `getNodeValue` - looks potentially expensive since it walks the whole tree and instantiates the full object structure each time.
// Might be something to look at moving forward to optimize.
const workspaceNodeValue = (0, jsonc_parser_1.getNodeValue)(workspaceNode);
for (const [name, value] of Object.entries(workspaceNodeValue)) {
if (name === '$schema' || name === 'version') {
// skip
}
else if (name === 'projects') {
const nodes = (0, jsonc_parser_1.findNodeAtLocation)(workspaceNode, ['projects']);
if (!(0, utils_1.isJsonObject)(value) || !nodes) {
context.error('Invalid "projects" field found; expected an object.', value);
continue;
}
projects = parseProjectsObject(nodes, context);
}
else {
if (!context.unprefixedWorkspaceExtensions.has(name) && !/^[a-z]{1,3}-.*/.test(name)) {
context.warn(`Workspace extension with invalid name (${name}) found.`, name);
}
if (extensions) {
extensions[name] = value;
}
}
}
let collectionListener;
if (context.trackChanges) {
collectionListener = (name, newValue) => {
jsonMetadata.addChange(['projects', name], newValue, 'project');
};
}
const projectCollection = new definitions_1.ProjectDefinitionCollection(projects, collectionListener);
return {
[metadata_1.JsonWorkspaceSymbol]: jsonMetadata,
projects: projectCollection,
// If not tracking changes the `extensions` variable will contain the parsed
// values. Otherwise the extensions are tracked via a virtual AST object.
extensions: extensions ??
(0, utilities_1.createVirtualAstObject)(workspaceNodeValue, {
exclude: ['$schema', 'version', 'projects'],
listener(path, value) {
jsonMetadata.addChange(path, value);
},
}),
};
}
function parseProjectsObject(projectsNode, context) {
const projects = Object.create(null);
for (const [name, value] of Object.entries((0, jsonc_parser_1.getNodeValue)(projectsNode))) {
const nodes = (0, jsonc_parser_1.findNodeAtLocation)(projectsNode, [name]);
if (!(0, utils_1.isJsonObject)(value) || !nodes) {
context.warn('Skipping invalid project value; expected an object.', value);
continue;
}
projects[name] = parseProject(name, nodes, context);
}
return projects;
}
function parseProject(projectName, projectNode, context) {
const jsonMetadata = context.metadata;
let targets;
let hasTargets = false;
let extensions;
let properties;
if (!context.trackChanges) {
// If not tracking changes, the parser will store the values directly in standard objects
extensions = Object.create(null);
properties = Object.create(null);
}
const projectNodeValue = (0, jsonc_parser_1.getNodeValue)(projectNode);
if (!('root' in projectNodeValue)) {
throw new Error(`Project "${projectName}" is missing a required property "root".`);
}
for (const [name, value] of Object.entries(projectNodeValue)) {
switch (name) {
case 'targets':
case 'architect':
const nodes = (0, jsonc_parser_1.findNodeAtLocation)(projectNode, [name]);
if (!(0, utils_1.isJsonObject)(value) || !nodes) {
context.error(`Invalid "${name}" field found; expected an object.`, value);
break;
}
hasTargets = true;
targets = parseTargetsObject(projectName, nodes, context);
jsonMetadata.hasLegacyTargetsName = name === 'architect';
break;
case 'prefix':
case 'root':
case 'sourceRoot':
if (typeof value !== 'string') {
context.warn(`Project property "${name}" should be a string.`, value);
}
if (properties) {
properties[name] = value;
}
break;
default:
if (!context.unprefixedProjectExtensions.has(name) && !/^[a-z]{1,3}-.*/.test(name)) {
context.warn(`Project '${projectName}' contains extension with invalid name (${name}).`, name);
}
if (extensions) {
extensions[name] = value;
}
break;
}
}
let collectionListener;
if (context.trackChanges) {
collectionListener = (name, newValue, collection) => {
if (hasTargets) {
jsonMetadata.addChange(['projects', projectName, 'targets', name], newValue, 'target');
}
else {
jsonMetadata.addChange(['projects', projectName, 'targets'], collection, 'targetcollection');
}
};
}
const base = {
targets: new definitions_1.TargetDefinitionCollection(targets, collectionListener),
// If not tracking changes the `extensions` variable will contain the parsed
// values. Otherwise the extensions are tracked via a virtual AST object.
extensions: extensions ??
(0, utilities_1.createVirtualAstObject)(projectNodeValue, {
exclude: ['architect', 'prefix', 'root', 'sourceRoot', 'targets'],
listener(path, value) {
jsonMetadata.addChange(['projects', projectName, ...path], value);
},
}),
};
const baseKeys = new Set(Object.keys(base));
const project = properties ??
(0, utilities_1.createVirtualAstObject)(projectNodeValue, {
include: ['prefix', 'root', 'sourceRoot', ...baseKeys],
listener(path, value) {
if (!baseKeys.has(path[0])) {
jsonMetadata.addChange(['projects', projectName, ...path], value);
}
},
});
return Object.assign(project, base);
}
function parseTargetsObject(projectName, targetsNode, context) {
const jsonMetadata = context.metadata;
const targets = Object.create(null);
for (const [name, value] of Object.entries((0, jsonc_parser_1.getNodeValue)(targetsNode))) {
if (!(0, utils_1.isJsonObject)(value)) {
context.warn('Skipping invalid target value; expected an object.', value);
continue;
}
if (context.trackChanges) {
targets[name] = (0, utilities_1.createVirtualAstObject)(value, {
include: ['builder', 'options', 'configurations', 'defaultConfiguration'],
listener(path, value) {
jsonMetadata.addChange(['projects', projectName, 'targets', name, ...path], value);
},
});
}
else {
targets[name] = value;
}
}
return targets;
}

View file

@ -0,0 +1,14 @@
/**
* @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 { JsonArray, JsonObject, JsonValue } from '../../json';
export type ChangeListener = (path: string[], newValue: JsonValue | undefined) => void;
export declare function createVirtualAstObject<T extends object = JsonObject>(root: JsonObject | JsonArray, options?: {
exclude?: string[];
include?: string[];
listener?: ChangeListener;
}): T;

View file

@ -0,0 +1,113 @@
"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 });
exports.createVirtualAstObject = void 0;
const json_1 = require("../../json");
function createVirtualAstObject(root, options = {}) {
const reporter = (path, target, oldValue, newValue) => {
if (!options.listener) {
return;
}
if (oldValue === newValue || JSON.stringify(oldValue) === JSON.stringify(newValue)) {
// same value
return;
}
if (Array.isArray(target)) {
// For arrays we remove the index and update the entire value as keeping
// track of changes by indices can be rather complex.
options.listener(path.slice(0, -1), target);
}
else {
options.listener(path, newValue);
}
};
return create(Array.isArray(root) ? [...root] : { ...root }, [], reporter, new Set(options.exclude), options.include?.length ? new Set(options.include) : undefined);
}
exports.createVirtualAstObject = createVirtualAstObject;
function create(obj, path, reporter, excluded = new Set(), included) {
return new Proxy(obj, {
getOwnPropertyDescriptor(target, p) {
if (excluded.has(p) || (included && !included.has(p))) {
return undefined;
}
return Reflect.getOwnPropertyDescriptor(target, p);
},
has(target, p) {
if (typeof p === 'symbol' || excluded.has(p)) {
return false;
}
return Reflect.has(target, p);
},
get(target, p) {
if (excluded.has(p) || (included && !included.has(p))) {
return undefined;
}
const value = Reflect.get(target, p);
if (typeof p === 'symbol') {
return value;
}
if (((0, json_1.isJsonObject)(value) && !(value instanceof Map)) || Array.isArray(value)) {
return create(value, [...path, p], reporter);
}
else {
return value;
}
},
set(target, p, value) {
if (excluded.has(p) || (included && !included.has(p))) {
return false;
}
if (value === undefined) {
// setting to undefined is equivalent to a delete.
return this.deleteProperty?.(target, p) ?? false;
}
if (typeof p === 'symbol') {
return Reflect.set(target, p, value);
}
const existingValue = getCurrentValue(target, p);
if (Reflect.set(target, p, value)) {
reporter([...path, p], target, existingValue, value);
return true;
}
return false;
},
deleteProperty(target, p) {
if (excluded.has(p)) {
return false;
}
if (typeof p === 'symbol') {
return Reflect.deleteProperty(target, p);
}
const existingValue = getCurrentValue(target, p);
if (Reflect.deleteProperty(target, p)) {
reporter([...path, p], target, existingValue, undefined);
return true;
}
return true;
},
defineProperty(target, p, attributes) {
if (typeof p === 'symbol') {
return Reflect.defineProperty(target, p, attributes);
}
return false;
},
ownKeys(target) {
return Reflect.ownKeys(target).filter((p) => !excluded.has(p) && (!included || included.has(p)));
},
});
}
function getCurrentValue(target, property) {
if (Array.isArray(target) && isFinite(+property)) {
return target[+property];
}
if (target && property in target) {
return target[property];
}
return undefined;
}

View file

@ -0,0 +1,12 @@
/**
* @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 { WorkspaceDefinition } from '../definitions';
import { WorkspaceHost } from '../host';
export declare function writeJsonWorkspace(workspace: WorkspaceDefinition, host: WorkspaceHost, path?: string, options?: {
schema?: string;
}): Promise<void>;

View file

@ -0,0 +1,143 @@
"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 });
exports.writeJsonWorkspace = void 0;
const jsonc_parser_1 = require("jsonc-parser");
const node_os_1 = require("node:os");
const metadata_1 = require("./metadata");
async function writeJsonWorkspace(workspace, host, path, options = {}) {
const metadata = workspace[metadata_1.JsonWorkspaceSymbol];
if (metadata) {
if (!metadata.hasChanges) {
return;
}
// update existing JSON workspace
const data = updateJsonWorkspace(metadata);
return host.writeFile(path ?? metadata.filePath, data);
}
else {
// serialize directly
if (!path) {
throw new Error('path option is required');
}
const obj = convertJsonWorkspace(workspace, options.schema);
const data = JSON.stringify(obj, null, 2);
return host.writeFile(path, data);
}
}
exports.writeJsonWorkspace = writeJsonWorkspace;
function convertJsonWorkspace(workspace, schema) {
const obj = {
$schema: schema || './node_modules/@angular/cli/lib/config/schema.json',
version: 1,
...workspace.extensions,
...(isEmpty(workspace.projects)
? {}
: { projects: convertJsonProjectCollection(workspace.projects) }),
};
return obj;
}
function convertJsonProjectCollection(collection) {
const projects = Object.create(null);
for (const [projectName, project] of collection) {
projects[projectName] = convertJsonProject(project);
}
return projects;
}
function convertJsonProject(project) {
let targets;
if (project.targets.size > 0) {
targets = Object.create(null);
for (const [targetName, target] of project.targets) {
targets[targetName] = convertJsonTarget(target);
}
}
const obj = {
...project.extensions,
root: project.root,
...(project.sourceRoot === undefined ? {} : { sourceRoot: project.sourceRoot }),
...(project.prefix === undefined ? {} : { prefix: project.prefix }),
...(targets === undefined ? {} : { architect: targets }),
};
return obj;
}
function isEmpty(obj) {
return obj === undefined || Object.keys(obj).length === 0;
}
function convertJsonTarget(target) {
return {
builder: target.builder,
...(isEmpty(target.options) ? {} : { options: target.options }),
...(isEmpty(target.configurations)
? {}
: { configurations: target.configurations }),
...(target.defaultConfiguration === undefined
? {}
: { defaultConfiguration: target.defaultConfiguration }),
};
}
function convertJsonTargetCollection(collection) {
const targets = Object.create(null);
for (const [projectName, target] of collection) {
targets[projectName] = convertJsonTarget(target);
}
return targets;
}
function normalizeValue(value, type) {
if (value === undefined) {
return undefined;
}
switch (type) {
case 'project':
return convertJsonProject(value);
case 'projectcollection':
const projects = convertJsonProjectCollection(value);
return isEmpty(projects) ? undefined : projects;
case 'target':
return convertJsonTarget(value);
case 'targetcollection':
const targets = convertJsonTargetCollection(value);
return isEmpty(targets) ? undefined : targets;
default:
return value;
}
}
function updateJsonWorkspace(metadata) {
let { raw: content } = metadata;
const { changes, hasLegacyTargetsName } = metadata;
for (const { jsonPath, value, type } of changes.values()) {
// Determine which key to use if (architect or targets)
if (hasLegacyTargetsName && jsonPath[2] === 'targets') {
jsonPath[2] = 'architect';
}
// TODO: `modify` re-parses the content every time.
// See: https://github.com/microsoft/node-jsonc-parser/blob/35d94cd71bd48f9784453b2439262c938e21d49b/src/impl/edit.ts#L18
// Ideally this should accept a string or an AST to avoid the potentially expensive repeat parsing operation.
const edits = (0, jsonc_parser_1.modify)(content, jsonPath, normalizeValue(value, type), {
formattingOptions: {
insertSpaces: true,
tabSize: 2,
eol: getEOL(content),
},
});
content = (0, jsonc_parser_1.applyEdits)(content, edits);
}
return content;
}
function getEOL(content) {
const CRLF = '\r\n';
const LF = '\n';
const newlines = content.match(/(?:\r?\n)/g);
if (newlines?.length) {
const crlf = newlines.filter((l) => l === CRLF).length;
const lf = newlines.length - crlf;
return crlf > lf ? CRLF : LF;
}
return node_os_1.EOL;
}