@angular/cli
Advanced tools
Comparing version 18.1.0-next.3 to 18.1.0-rc.0
{ | ||
"name": "@angular/cli", | ||
"version": "18.1.0-next.3", | ||
"version": "18.1.0-rc.0", | ||
"description": "CLI tool for Angular", | ||
@@ -28,12 +28,12 @@ "main": "lib/cli/index.js", | ||
"dependencies": { | ||
"@angular-devkit/architect": "0.1801.0-next.3", | ||
"@angular-devkit/core": "18.1.0-next.3", | ||
"@angular-devkit/schematics": "18.1.0-next.3", | ||
"@angular-devkit/architect": "0.1801.0-rc.0", | ||
"@angular-devkit/core": "18.1.0-rc.0", | ||
"@angular-devkit/schematics": "18.1.0-rc.0", | ||
"@inquirer/prompts": "5.0.6", | ||
"@listr2/prompt-adapter-inquirer": "2.0.12", | ||
"@schematics/angular": "18.1.0-next.3", | ||
"@listr2/prompt-adapter-inquirer": "2.0.13", | ||
"@schematics/angular": "18.1.0-rc.0", | ||
"@yarnpkg/lockfile": "1.1.0", | ||
"ini": "4.1.3", | ||
"jsonc-parser": "3.2.1", | ||
"listr2": "8.2.2", | ||
"jsonc-parser": "3.3.1", | ||
"listr2": "8.2.3", | ||
"npm-package-arg": "11.0.2", | ||
@@ -50,10 +50,10 @@ "npm-pick-manifest": "9.0.1", | ||
"packageGroup": { | ||
"@angular/cli": "18.1.0-next.3", | ||
"@angular/build": "18.1.0-next.3", | ||
"@angular/ssr": "18.1.0-next.3", | ||
"@angular-devkit/architect": "0.1801.0-next.3", | ||
"@angular-devkit/build-angular": "18.1.0-next.3", | ||
"@angular-devkit/build-webpack": "0.1801.0-next.3", | ||
"@angular-devkit/core": "18.1.0-next.3", | ||
"@angular-devkit/schematics": "18.1.0-next.3" | ||
"@angular/cli": "18.1.0-rc.0", | ||
"@angular/build": "18.1.0-rc.0", | ||
"@angular/ssr": "18.1.0-rc.0", | ||
"@angular-devkit/architect": "0.1801.0-rc.0", | ||
"@angular-devkit/build-angular": "18.1.0-rc.0", | ||
"@angular-devkit/build-webpack": "0.1801.0-rc.0", | ||
"@angular-devkit/core": "18.1.0-rc.0", | ||
"@angular-devkit/schematics": "18.1.0-rc.0" | ||
} | ||
@@ -60,0 +60,0 @@ }, |
@@ -50,3 +50,3 @@ "use strict"; | ||
async runSingleTarget(target, options) { | ||
const architectHost = await this.getArchitectHost(); | ||
const architectHost = this.getArchitectHost(); | ||
let builderName; | ||
@@ -53,0 +53,0 @@ try { |
@@ -9,10 +9,35 @@ "use strict"; | ||
*/ | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { | ||
var useValue = arguments.length > 2; | ||
for (var i = 0; i < initializers.length; i++) { | ||
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); | ||
} | ||
return useValue ? value : void 0; | ||
}; | ||
var __metadata = (this && this.__metadata) || function (k, v) { | ||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { | ||
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } | ||
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; | ||
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; | ||
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); | ||
var _, done = false; | ||
for (var i = decorators.length - 1; i >= 0; i--) { | ||
var context = {}; | ||
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; | ||
for (var p in contextIn.access) context.access[p] = contextIn.access[p]; | ||
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; | ||
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); | ||
if (kind === "accessor") { | ||
if (result === void 0) continue; | ||
if (result === null || typeof result !== "object") throw new TypeError("Object expected"); | ||
if (_ = accept(result.get)) descriptor.get = _; | ||
if (_ = accept(result.set)) descriptor.set = _; | ||
if (_ = accept(result.init)) initializers.unshift(_); | ||
} | ||
else if (_ = accept(result)) { | ||
if (kind === "field") initializers.unshift(_); | ||
else descriptor[key] = _; | ||
} | ||
} | ||
if (target) Object.defineProperty(target, contextIn.name, descriptor); | ||
done = true; | ||
}; | ||
@@ -25,131 +50,140 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
const command_module_1 = require("./command-module"); | ||
class ArchitectCommandModule extends architect_base_command_module_1.ArchitectBaseCommandModule { | ||
async builder(argv) { | ||
const project = this.getArchitectProject(); | ||
const { jsonHelp, getYargsCompletions, help } = this.context.args.options; | ||
const localYargs = argv | ||
.positional('project', { | ||
describe: 'The name of the project to build. Can be an application or a library.', | ||
type: 'string', | ||
// Hide choices from JSON help so that we don't display them in AIO. | ||
choices: jsonHelp ? undefined : this.getProjectChoices(), | ||
}) | ||
.option('configuration', { | ||
describe: `One or more named builder configurations as a comma-separated ` + | ||
`list as specified in the "configurations" section in angular.json.\n` + | ||
`The builder uses the named configurations to run the given target.\n` + | ||
`For more information, see https://angular.dev/reference/configs/workspace-config#alternate-build-configurations.`, | ||
alias: 'c', | ||
type: 'string', | ||
// Show only in when using --help and auto completion because otherwise comma seperated configuration values will be invalid. | ||
// Also, hide choices from JSON help so that we don't display them in AIO. | ||
choices: (getYargsCompletions || help) && !jsonHelp && project | ||
? this.getConfigurationChoices(project) | ||
: undefined, | ||
}) | ||
.strict(); | ||
if (!project) { | ||
return localYargs; | ||
let ArchitectCommandModule = (() => { | ||
let _classSuper = architect_base_command_module_1.ArchitectBaseCommandModule; | ||
let _instanceExtraInitializers = []; | ||
let _getProjectNamesByTarget_decorators; | ||
return class ArchitectCommandModule extends _classSuper { | ||
static { | ||
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; | ||
_getProjectNamesByTarget_decorators = [memoize_1.memoize]; | ||
__esDecorate(this, null, _getProjectNamesByTarget_decorators, { kind: "method", name: "getProjectNamesByTarget", static: false, private: false, access: { has: obj => "getProjectNamesByTarget" in obj, get: obj => obj.getProjectNamesByTarget }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); | ||
} | ||
const target = this.getArchitectTarget(); | ||
const schemaOptions = await this.getArchitectTargetOptions({ | ||
project, | ||
target, | ||
}); | ||
return this.addSchemaOptionsToCommand(localYargs, schemaOptions); | ||
} | ||
async run(options) { | ||
const target = this.getArchitectTarget(); | ||
const { configuration = '', project, ...architectOptions } = options; | ||
if (!project) { | ||
// This runs each target sequentially. | ||
// Running them in parallel would jumble the log messages. | ||
let result = 0; | ||
const projectNames = this.getProjectNamesByTarget(target); | ||
if (!projectNames) { | ||
return this.onMissingTarget('Cannot determine project or target for command.'); | ||
async builder(argv) { | ||
const project = this.getArchitectProject(); | ||
const { jsonHelp, getYargsCompletions, help } = this.context.args.options; | ||
const localYargs = argv | ||
.positional('project', { | ||
describe: 'The name of the project to build. Can be an application or a library.', | ||
type: 'string', | ||
// Hide choices from JSON help so that we don't display them in AIO. | ||
choices: jsonHelp ? undefined : this.getProjectChoices(), | ||
}) | ||
.option('configuration', { | ||
describe: `One or more named builder configurations as a comma-separated ` + | ||
`list as specified in the "configurations" section in angular.json.\n` + | ||
`The builder uses the named configurations to run the given target.\n` + | ||
`For more information, see https://angular.dev/reference/configs/workspace-config#alternate-build-configurations.`, | ||
alias: 'c', | ||
type: 'string', | ||
// Show only in when using --help and auto completion because otherwise comma seperated configuration values will be invalid. | ||
// Also, hide choices from JSON help so that we don't display them in AIO. | ||
choices: (getYargsCompletions || help) && !jsonHelp && project | ||
? this.getConfigurationChoices(project) | ||
: undefined, | ||
}) | ||
.strict(); | ||
if (!project) { | ||
return localYargs; | ||
} | ||
for (const project of projectNames) { | ||
result |= await this.runSingleTarget({ configuration, target, project }, architectOptions); | ||
const target = this.getArchitectTarget(); | ||
const schemaOptions = await this.getArchitectTargetOptions({ | ||
project, | ||
target, | ||
}); | ||
return this.addSchemaOptionsToCommand(localYargs, schemaOptions); | ||
} | ||
async run(options) { | ||
const target = this.getArchitectTarget(); | ||
const { configuration = '', project, ...architectOptions } = options; | ||
if (!project) { | ||
// This runs each target sequentially. | ||
// Running them in parallel would jumble the log messages. | ||
let result = 0; | ||
const projectNames = this.getProjectNamesByTarget(target); | ||
if (!projectNames) { | ||
return this.onMissingTarget('Cannot determine project or target for command.'); | ||
} | ||
for (const project of projectNames) { | ||
result |= await this.runSingleTarget({ configuration, target, project }, architectOptions); | ||
} | ||
return result; | ||
} | ||
return result; | ||
else { | ||
return await this.runSingleTarget({ configuration, target, project }, architectOptions); | ||
} | ||
} | ||
else { | ||
return await this.runSingleTarget({ configuration, target, project }, architectOptions); | ||
getArchitectProject() { | ||
const { options, positional } = this.context.args; | ||
const [, projectName] = positional; | ||
if (projectName) { | ||
return projectName; | ||
} | ||
// Yargs allows positional args to be used as flags. | ||
if (typeof options['project'] === 'string') { | ||
return options['project']; | ||
} | ||
const target = this.getArchitectTarget(); | ||
const projectFromTarget = this.getProjectNamesByTarget(target); | ||
return projectFromTarget?.length ? projectFromTarget[0] : undefined; | ||
} | ||
} | ||
getArchitectProject() { | ||
const { options, positional } = this.context.args; | ||
const [, projectName] = positional; | ||
if (projectName) { | ||
return projectName; | ||
} | ||
// Yargs allows positional args to be used as flags. | ||
if (typeof options['project'] === 'string') { | ||
return options['project']; | ||
} | ||
const target = this.getArchitectTarget(); | ||
const projectFromTarget = this.getProjectNamesByTarget(target); | ||
return projectFromTarget?.length ? projectFromTarget[0] : undefined; | ||
} | ||
getProjectNamesByTarget(target) { | ||
const workspace = this.getWorkspaceOrThrow(); | ||
const allProjectsForTargetName = []; | ||
for (const [name, project] of workspace.projects) { | ||
if (project.targets.has(target)) { | ||
allProjectsForTargetName.push(name); | ||
getProjectNamesByTarget(target) { | ||
const workspace = this.getWorkspaceOrThrow(); | ||
const allProjectsForTargetName = []; | ||
for (const [name, project] of workspace.projects) { | ||
if (project.targets.has(target)) { | ||
allProjectsForTargetName.push(name); | ||
} | ||
} | ||
} | ||
if (allProjectsForTargetName.length === 0) { | ||
if (allProjectsForTargetName.length === 0) { | ||
return undefined; | ||
} | ||
if (this.multiTarget) { | ||
// For multi target commands, we always list all projects that have the target. | ||
return allProjectsForTargetName; | ||
} | ||
else { | ||
if (allProjectsForTargetName.length === 1) { | ||
return allProjectsForTargetName; | ||
} | ||
const maybeProject = (0, config_1.getProjectByCwd)(workspace); | ||
if (maybeProject) { | ||
return allProjectsForTargetName.includes(maybeProject) ? [maybeProject] : undefined; | ||
} | ||
const { getYargsCompletions, help } = this.context.args.options; | ||
if (!getYargsCompletions && !help) { | ||
// Only issue the below error when not in help / completion mode. | ||
throw new command_module_1.CommandModuleError('Cannot determine project for command.\n' + | ||
'This is a multi-project workspace and more than one project supports this command. ' + | ||
`Run "ng ${this.command}" to execute the command for a specific project or change the current ` + | ||
'working directory to a project directory.\n\n' + | ||
`Available projects are:\n${allProjectsForTargetName | ||
.sort() | ||
.map((p) => `- ${p}`) | ||
.join('\n')}`); | ||
} | ||
} | ||
return undefined; | ||
} | ||
if (this.multiTarget) { | ||
// For multi target commands, we always list all projects that have the target. | ||
return allProjectsForTargetName; | ||
/** @returns a sorted list of project names to be used for auto completion. */ | ||
getProjectChoices() { | ||
const { workspace } = this.context; | ||
return workspace ? [...workspace.projects.keys()].sort() : undefined; | ||
} | ||
else { | ||
if (allProjectsForTargetName.length === 1) { | ||
return allProjectsForTargetName; | ||
/** @returns a sorted list of configuration names to be used for auto completion. */ | ||
getConfigurationChoices(project) { | ||
const projectDefinition = this.context.workspace?.projects.get(project); | ||
if (!projectDefinition) { | ||
return undefined; | ||
} | ||
const maybeProject = (0, config_1.getProjectByCwd)(workspace); | ||
if (maybeProject) { | ||
return allProjectsForTargetName.includes(maybeProject) ? [maybeProject] : undefined; | ||
} | ||
const { getYargsCompletions, help } = this.context.args.options; | ||
if (!getYargsCompletions && !help) { | ||
// Only issue the below error when not in help / completion mode. | ||
throw new command_module_1.CommandModuleError('Cannot determine project for command.\n' + | ||
'This is a multi-project workspace and more than one project supports this command. ' + | ||
`Run "ng ${this.command}" to execute the command for a specific project or change the current ` + | ||
'working directory to a project directory.\n\n' + | ||
`Available projects are:\n${allProjectsForTargetName | ||
.sort() | ||
.map((p) => `- ${p}`) | ||
.join('\n')}`); | ||
} | ||
const target = this.getArchitectTarget(); | ||
const configurations = projectDefinition.targets.get(target)?.configurations; | ||
return configurations ? Object.keys(configurations).sort() : undefined; | ||
} | ||
return undefined; | ||
} | ||
/** @returns a sorted list of project names to be used for auto completion. */ | ||
getProjectChoices() { | ||
const { workspace } = this.context; | ||
return workspace ? [...workspace.projects.keys()].sort() : undefined; | ||
} | ||
/** @returns a sorted list of configuration names to be used for auto completion. */ | ||
getConfigurationChoices(project) { | ||
const projectDefinition = this.context.workspace?.projects.get(project); | ||
if (!projectDefinition) { | ||
return undefined; | ||
constructor() { | ||
super(...arguments); | ||
__runInitializers(this, _instanceExtraInitializers); | ||
} | ||
const target = this.getArchitectTarget(); | ||
const configurations = projectDefinition.targets.get(target)?.configurations; | ||
return configurations ? Object.keys(configurations).sort() : undefined; | ||
} | ||
} | ||
}; | ||
})(); | ||
exports.ArchitectCommandModule = ArchitectCommandModule; | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", [String]), | ||
__metadata("design:returntype", Object) | ||
], ArchitectCommandModule.prototype, "getProjectNamesByTarget", null); |
@@ -25,8 +25,36 @@ "use strict"; | ||
}); | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { | ||
var useValue = arguments.length > 2; | ||
for (var i = 0; i < initializers.length; i++) { | ||
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); | ||
} | ||
return useValue ? value : void 0; | ||
}; | ||
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { | ||
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } | ||
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; | ||
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; | ||
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); | ||
var _, done = false; | ||
for (var i = decorators.length - 1; i >= 0; i--) { | ||
var context = {}; | ||
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; | ||
for (var p in contextIn.access) context.access[p] = contextIn.access[p]; | ||
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; | ||
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); | ||
if (kind === "accessor") { | ||
if (result === void 0) continue; | ||
if (result === null || typeof result !== "object") throw new TypeError("Object expected"); | ||
if (_ = accept(result.get)) descriptor.get = _; | ||
if (_ = accept(result.set)) descriptor.set = _; | ||
if (_ = accept(result.init)) initializers.unshift(_); | ||
} | ||
else if (_ = accept(result)) { | ||
if (kind === "field") initializers.unshift(_); | ||
else descriptor[key] = _; | ||
} | ||
} | ||
if (target) Object.defineProperty(target, contextIn.name, descriptor); | ||
done = true; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
@@ -39,5 +67,2 @@ if (mod && mod.__esModule) return mod; | ||
}; | ||
var __metadata = (this && this.__metadata) || function (k, v) { | ||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -67,209 +92,213 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
})(CommandScope || (exports.CommandScope = CommandScope = {})); | ||
class CommandModule { | ||
context; | ||
shouldReportAnalytics = true; | ||
scope = CommandScope.Both; | ||
optionsWithAnalytics = new Map(); | ||
constructor(context) { | ||
this.context = context; | ||
} | ||
/** | ||
* Description object which contains the long command descroption. | ||
* This is used to generate JSON help wich is used in AIO. | ||
* | ||
* `false` will result in a hidden command. | ||
*/ | ||
get fullDescribe() { | ||
return this.describe === false | ||
? false | ||
: { | ||
describe: this.describe, | ||
...(this.longDescriptionPath | ||
? { | ||
longDescriptionRelativePath: path | ||
.relative(path.join(__dirname, '../../../../'), this.longDescriptionPath) | ||
.replace(/\\/g, path.posix.sep), | ||
longDescription: (0, fs_1.readFileSync)(this.longDescriptionPath, 'utf8').replace(/\r\n/g, '\n'), | ||
} | ||
: {}), | ||
}; | ||
} | ||
get commandName() { | ||
return this.command.split(' ', 1)[0]; | ||
} | ||
async handler(args) { | ||
const { _, $0, ...options } = args; | ||
// Camelize options as yargs will return the object in kebab-case when camel casing is disabled. | ||
const camelCasedOptions = {}; | ||
for (const [key, value] of Object.entries(options)) { | ||
camelCasedOptions[helpers_1.Parser.camelCase(key)] = value; | ||
let CommandModule = (() => { | ||
let _instanceExtraInitializers = []; | ||
let _getAnalytics_decorators; | ||
return class CommandModule { | ||
static { | ||
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; | ||
_getAnalytics_decorators = [memoize_1.memoize]; | ||
__esDecorate(this, null, _getAnalytics_decorators, { kind: "method", name: "getAnalytics", static: false, private: false, access: { has: obj => "getAnalytics" in obj, get: obj => obj.getAnalytics }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); | ||
} | ||
// Set up autocompletion if appropriate. | ||
const autocompletionExitCode = await (0, completion_1.considerSettingUpAutocompletion)(this.commandName, this.context.logger); | ||
if (autocompletionExitCode !== undefined) { | ||
process.exitCode = autocompletionExitCode; | ||
return; | ||
context = __runInitializers(this, _instanceExtraInitializers); | ||
shouldReportAnalytics = true; | ||
scope = CommandScope.Both; | ||
optionsWithAnalytics = new Map(); | ||
constructor(context) { | ||
this.context = context; | ||
} | ||
// Gather and report analytics. | ||
const analytics = await this.getAnalytics(); | ||
const stopPeriodicFlushes = analytics && analytics.periodFlush(); | ||
let exitCode; | ||
try { | ||
if (analytics) { | ||
this.reportCommandRunAnalytics(analytics); | ||
this.reportWorkspaceInfoAnalytics(analytics); | ||
} | ||
exitCode = await this.run(camelCasedOptions); | ||
/** | ||
* Description object which contains the long command descroption. | ||
* This is used to generate JSON help wich is used in AIO. | ||
* | ||
* `false` will result in a hidden command. | ||
*/ | ||
get fullDescribe() { | ||
return this.describe === false | ||
? false | ||
: { | ||
describe: this.describe, | ||
...(this.longDescriptionPath | ||
? { | ||
longDescriptionRelativePath: path | ||
.relative(path.join(__dirname, '../../../../'), this.longDescriptionPath) | ||
.replace(/\\/g, path.posix.sep), | ||
longDescription: (0, fs_1.readFileSync)(this.longDescriptionPath, 'utf8').replace(/\r\n/g, '\n'), | ||
} | ||
: {}), | ||
}; | ||
} | ||
catch (e) { | ||
if (e instanceof core_1.schema.SchemaValidationException) { | ||
this.context.logger.fatal(`Error: ${e.message}`); | ||
exitCode = 1; | ||
get commandName() { | ||
return this.command.split(' ', 1)[0]; | ||
} | ||
async handler(args) { | ||
const { _, $0, ...options } = args; | ||
// Camelize options as yargs will return the object in kebab-case when camel casing is disabled. | ||
const camelCasedOptions = {}; | ||
for (const [key, value] of Object.entries(options)) { | ||
camelCasedOptions[helpers_1.Parser.camelCase(key)] = value; | ||
} | ||
else { | ||
throw e; | ||
// Set up autocompletion if appropriate. | ||
const autocompletionExitCode = await (0, completion_1.considerSettingUpAutocompletion)(this.commandName, this.context.logger); | ||
if (autocompletionExitCode !== undefined) { | ||
process.exitCode = autocompletionExitCode; | ||
return; | ||
} | ||
// Gather and report analytics. | ||
const analytics = await this.getAnalytics(); | ||
const stopPeriodicFlushes = analytics && analytics.periodFlush(); | ||
let exitCode; | ||
try { | ||
if (analytics) { | ||
this.reportCommandRunAnalytics(analytics); | ||
this.reportWorkspaceInfoAnalytics(analytics); | ||
} | ||
exitCode = await this.run(camelCasedOptions); | ||
} | ||
catch (e) { | ||
if (e instanceof core_1.schema.SchemaValidationException) { | ||
this.context.logger.fatal(`Error: ${e.message}`); | ||
exitCode = 1; | ||
} | ||
else { | ||
throw e; | ||
} | ||
} | ||
finally { | ||
await stopPeriodicFlushes?.(); | ||
if (typeof exitCode === 'number' && exitCode > 0) { | ||
process.exitCode = exitCode; | ||
} | ||
} | ||
} | ||
finally { | ||
await stopPeriodicFlushes?.(); | ||
if (typeof exitCode === 'number' && exitCode > 0) { | ||
process.exitCode = exitCode; | ||
async getAnalytics() { | ||
if (!this.shouldReportAnalytics) { | ||
return undefined; | ||
} | ||
const userId = await (0, analytics_1.getAnalyticsUserId)(this.context, | ||
// Don't prompt on `ng update`, 'ng version' or `ng analytics`. | ||
['version', 'update', 'analytics'].includes(this.commandName)); | ||
return userId ? new analytics_collector_1.AnalyticsCollector(this.context, userId) : undefined; | ||
} | ||
} | ||
async getAnalytics() { | ||
if (!this.shouldReportAnalytics) { | ||
return undefined; | ||
} | ||
const userId = await (0, analytics_1.getAnalyticsUserId)(this.context, | ||
// Don't prompt on `ng update`, 'ng version' or `ng analytics`. | ||
['version', 'update', 'analytics'].includes(this.commandName)); | ||
return userId ? new analytics_collector_1.AnalyticsCollector(this.context, userId) : undefined; | ||
} | ||
/** | ||
* Adds schema options to a command also this keeps track of options that are required for analytics. | ||
* **Note:** This method should be called from the command bundler method. | ||
*/ | ||
addSchemaOptionsToCommand(localYargs, options) { | ||
const booleanOptionsWithNoPrefix = new Set(); | ||
for (const option of options) { | ||
const { default: defaultVal, positional, deprecated, description, alias, userAnalytics, type, hidden, name, choices, } = option; | ||
const sharedOptions = { | ||
alias, | ||
hidden, | ||
description, | ||
deprecated, | ||
choices, | ||
// This should only be done when `--help` is used otherwise default will override options set in angular.json. | ||
...(this.context.args.options.help ? { default: defaultVal } : {}), | ||
}; | ||
let dashedName = core_1.strings.dasherize(name); | ||
/** | ||
* Adds schema options to a command also this keeps track of options that are required for analytics. | ||
* **Note:** This method should be called from the command bundler method. | ||
*/ | ||
addSchemaOptionsToCommand(localYargs, options) { | ||
const booleanOptionsWithNoPrefix = new Set(); | ||
for (const option of options) { | ||
const { default: defaultVal, positional, deprecated, description, alias, userAnalytics, type, hidden, name, choices, } = option; | ||
const sharedOptions = { | ||
alias, | ||
hidden, | ||
description, | ||
deprecated, | ||
choices, | ||
// This should only be done when `--help` is used otherwise default will override options set in angular.json. | ||
...(this.context.args.options.help ? { default: defaultVal } : {}), | ||
}; | ||
let dashedName = core_1.strings.dasherize(name); | ||
// Handle options which have been defined in the schema with `no` prefix. | ||
if (type === 'boolean' && dashedName.startsWith('no-')) { | ||
dashedName = dashedName.slice(3); | ||
booleanOptionsWithNoPrefix.add(dashedName); | ||
} | ||
if (positional === undefined) { | ||
localYargs = localYargs.option(dashedName, { | ||
type, | ||
...sharedOptions, | ||
}); | ||
} | ||
else { | ||
localYargs = localYargs.positional(dashedName, { | ||
type: type === 'array' || type === 'count' ? 'string' : type, | ||
...sharedOptions, | ||
}); | ||
} | ||
// Record option of analytics. | ||
if (userAnalytics !== undefined) { | ||
this.optionsWithAnalytics.set(name, userAnalytics); | ||
} | ||
} | ||
// Handle options which have been defined in the schema with `no` prefix. | ||
if (type === 'boolean' && dashedName.startsWith('no-')) { | ||
dashedName = dashedName.slice(3); | ||
booleanOptionsWithNoPrefix.add(dashedName); | ||
if (booleanOptionsWithNoPrefix.size) { | ||
localYargs.middleware((options) => { | ||
for (const key of booleanOptionsWithNoPrefix) { | ||
if (key in options) { | ||
options[`no-${key}`] = !options[key]; | ||
delete options[key]; | ||
} | ||
} | ||
}, false); | ||
} | ||
if (positional === undefined) { | ||
localYargs = localYargs.option(dashedName, { | ||
type, | ||
...sharedOptions, | ||
}); | ||
return localYargs; | ||
} | ||
getWorkspaceOrThrow() { | ||
const { workspace } = this.context; | ||
if (!workspace) { | ||
throw new CommandModuleError('A workspace is required for this command.'); | ||
} | ||
else { | ||
localYargs = localYargs.positional(dashedName, { | ||
type: type === 'array' || type === 'count' ? 'string' : type, | ||
...sharedOptions, | ||
}); | ||
} | ||
// Record option of analytics. | ||
if (userAnalytics !== undefined) { | ||
this.optionsWithAnalytics.set(name, userAnalytics); | ||
} | ||
return workspace; | ||
} | ||
// Handle options which have been defined in the schema with `no` prefix. | ||
if (booleanOptionsWithNoPrefix.size) { | ||
localYargs.middleware((options) => { | ||
for (const key of booleanOptionsWithNoPrefix) { | ||
if (key in options) { | ||
options[`no-${key}`] = !options[key]; | ||
delete options[key]; | ||
} | ||
/** | ||
* Flush on an interval (if the event loop is waiting). | ||
* | ||
* @returns a method that when called will terminate the periodic | ||
* flush and call flush one last time. | ||
*/ | ||
getAnalyticsParameters(options) { | ||
const parameters = {}; | ||
const validEventCustomDimensionAndMetrics = new Set([ | ||
...Object.values(analytics_parameters_1.EventCustomDimension), | ||
...Object.values(analytics_parameters_1.EventCustomMetric), | ||
]); | ||
for (const [name, ua] of this.optionsWithAnalytics) { | ||
const value = options[name]; | ||
if ((typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') && | ||
validEventCustomDimensionAndMetrics.has(ua)) { | ||
parameters[ua] = value; | ||
} | ||
}, false); | ||
} | ||
return localYargs; | ||
} | ||
getWorkspaceOrThrow() { | ||
const { workspace } = this.context; | ||
if (!workspace) { | ||
throw new CommandModuleError('A workspace is required for this command.'); | ||
} | ||
return workspace; | ||
} | ||
/** | ||
* Flush on an interval (if the event loop is waiting). | ||
* | ||
* @returns a method that when called will terminate the periodic | ||
* flush and call flush one last time. | ||
*/ | ||
getAnalyticsParameters(options) { | ||
const parameters = {}; | ||
const validEventCustomDimensionAndMetrics = new Set([ | ||
...Object.values(analytics_parameters_1.EventCustomDimension), | ||
...Object.values(analytics_parameters_1.EventCustomMetric), | ||
]); | ||
for (const [name, ua] of this.optionsWithAnalytics) { | ||
const value = options[name]; | ||
if ((typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') && | ||
validEventCustomDimensionAndMetrics.has(ua)) { | ||
parameters[ua] = value; | ||
} | ||
return parameters; | ||
} | ||
return parameters; | ||
} | ||
reportCommandRunAnalytics(analytics) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const internalMethods = yargs_1.default.getInternalMethods(); | ||
// $0 generate component [name] -> generate_component | ||
// $0 add <collection> -> add | ||
const fullCommand = internalMethods.getUsageInstance().getUsage()[0][0] | ||
.split(' ') | ||
.filter((x) => { | ||
const code = x.charCodeAt(0); | ||
return code >= 97 && code <= 122; | ||
}) | ||
.join('_'); | ||
analytics.reportCommandRunEvent(fullCommand); | ||
} | ||
reportWorkspaceInfoAnalytics(analytics) { | ||
const { workspace } = this.context; | ||
if (!workspace) { | ||
return; | ||
reportCommandRunAnalytics(analytics) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const internalMethods = yargs_1.default.getInternalMethods(); | ||
// $0 generate component [name] -> generate_component | ||
// $0 add <collection> -> add | ||
const fullCommand = internalMethods.getUsageInstance().getUsage()[0][0] | ||
.split(' ') | ||
.filter((x) => { | ||
const code = x.charCodeAt(0); | ||
return code >= 97 && code <= 122; | ||
}) | ||
.join('_'); | ||
analytics.reportCommandRunEvent(fullCommand); | ||
} | ||
let applicationProjectsCount = 0; | ||
let librariesProjectsCount = 0; | ||
for (const project of workspace.projects.values()) { | ||
switch (project.extensions['projectType']) { | ||
case 'application': | ||
applicationProjectsCount++; | ||
break; | ||
case 'library': | ||
librariesProjectsCount++; | ||
break; | ||
reportWorkspaceInfoAnalytics(analytics) { | ||
const { workspace } = this.context; | ||
if (!workspace) { | ||
return; | ||
} | ||
let applicationProjectsCount = 0; | ||
let librariesProjectsCount = 0; | ||
for (const project of workspace.projects.values()) { | ||
switch (project.extensions['projectType']) { | ||
case 'application': | ||
applicationProjectsCount++; | ||
break; | ||
case 'library': | ||
librariesProjectsCount++; | ||
break; | ||
} | ||
} | ||
analytics.reportWorkspaceInfoEvent({ | ||
[analytics_parameters_1.EventCustomMetric.AllProjectsCount]: librariesProjectsCount + applicationProjectsCount, | ||
[analytics_parameters_1.EventCustomMetric.ApplicationProjectsCount]: applicationProjectsCount, | ||
[analytics_parameters_1.EventCustomMetric.LibraryProjectsCount]: librariesProjectsCount, | ||
}); | ||
} | ||
analytics.reportWorkspaceInfoEvent({ | ||
[analytics_parameters_1.EventCustomMetric.AllProjectsCount]: librariesProjectsCount + applicationProjectsCount, | ||
[analytics_parameters_1.EventCustomMetric.ApplicationProjectsCount]: applicationProjectsCount, | ||
[analytics_parameters_1.EventCustomMetric.LibraryProjectsCount]: librariesProjectsCount, | ||
}); | ||
} | ||
} | ||
}; | ||
})(); | ||
exports.CommandModule = CommandModule; | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", []), | ||
__metadata("design:returntype", Promise) | ||
], CommandModule.prototype, "getAnalytics", null); | ||
/** | ||
@@ -276,0 +305,0 @@ * Creates an known command module error. |
@@ -25,8 +25,36 @@ "use strict"; | ||
}); | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { | ||
var useValue = arguments.length > 2; | ||
for (var i = 0; i < initializers.length; i++) { | ||
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); | ||
} | ||
return useValue ? value : void 0; | ||
}; | ||
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { | ||
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } | ||
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; | ||
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; | ||
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); | ||
var _, done = false; | ||
for (var i = decorators.length - 1; i >= 0; i--) { | ||
var context = {}; | ||
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; | ||
for (var p in contextIn.access) context.access[p] = contextIn.access[p]; | ||
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; | ||
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); | ||
if (kind === "accessor") { | ||
if (result === void 0) continue; | ||
if (result === null || typeof result !== "object") throw new TypeError("Object expected"); | ||
if (_ = accept(result.get)) descriptor.get = _; | ||
if (_ = accept(result.set)) descriptor.set = _; | ||
if (_ = accept(result.init)) initializers.unshift(_); | ||
} | ||
else if (_ = accept(result)) { | ||
if (kind === "field") initializers.unshift(_); | ||
else descriptor[key] = _; | ||
} | ||
} | ||
if (target) Object.defineProperty(target, contextIn.name, descriptor); | ||
done = true; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
@@ -39,5 +67,2 @@ if (mod && mod.__esModule) return mod; | ||
}; | ||
var __metadata = (this && this.__metadata) || function (k, v) { | ||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -60,298 +85,297 @@ exports.SchematicsCommandModule = exports.DEFAULT_SCHEMATICS_COLLECTION = void 0; | ||
exports.DEFAULT_SCHEMATICS_COLLECTION = '@schematics/angular'; | ||
class SchematicsCommandModule extends command_module_1.CommandModule { | ||
scope = command_module_1.CommandScope.In; | ||
allowPrivateSchematics = false; | ||
async builder(argv) { | ||
return argv | ||
.option('interactive', { | ||
describe: 'Enable interactive input prompts.', | ||
type: 'boolean', | ||
default: true, | ||
}) | ||
.option('dry-run', { | ||
describe: 'Run through and reports activity without writing out results.', | ||
type: 'boolean', | ||
alias: ['d'], | ||
default: false, | ||
}) | ||
.option('defaults', { | ||
describe: 'Disable interactive input prompts for options with a default.', | ||
type: 'boolean', | ||
default: false, | ||
}) | ||
.option('force', { | ||
describe: 'Force overwriting of existing files.', | ||
type: 'boolean', | ||
default: false, | ||
}) | ||
.strict(); | ||
} | ||
/** Get schematic schema options.*/ | ||
async getSchematicOptions(collection, schematicName, workflow) { | ||
const schematic = collection.createSchematic(schematicName, true); | ||
const { schemaJson } = schematic.description; | ||
if (!schemaJson) { | ||
return []; | ||
let SchematicsCommandModule = (() => { | ||
let _classSuper = command_module_1.CommandModule; | ||
let _instanceExtraInitializers = []; | ||
let _getOrCreateWorkflowForBuilder_decorators; | ||
let _getOrCreateWorkflowForExecution_decorators; | ||
let _getSchematicCollections_decorators; | ||
return class SchematicsCommandModule extends _classSuper { | ||
static { | ||
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; | ||
_getOrCreateWorkflowForBuilder_decorators = [memoize_1.memoize]; | ||
_getOrCreateWorkflowForExecution_decorators = [memoize_1.memoize]; | ||
_getSchematicCollections_decorators = [memoize_1.memoize]; | ||
__esDecorate(this, null, _getOrCreateWorkflowForBuilder_decorators, { kind: "method", name: "getOrCreateWorkflowForBuilder", static: false, private: false, access: { has: obj => "getOrCreateWorkflowForBuilder" in obj, get: obj => obj.getOrCreateWorkflowForBuilder }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
__esDecorate(this, null, _getOrCreateWorkflowForExecution_decorators, { kind: "method", name: "getOrCreateWorkflowForExecution", static: false, private: false, access: { has: obj => "getOrCreateWorkflowForExecution" in obj, get: obj => obj.getOrCreateWorkflowForExecution }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
__esDecorate(this, null, _getSchematicCollections_decorators, { kind: "method", name: "getSchematicCollections", static: false, private: false, access: { has: obj => "getSchematicCollections" in obj, get: obj => obj.getSchematicCollections }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); | ||
} | ||
return (0, json_schema_1.parseJsonSchemaToOptions)(workflow.registry, schemaJson); | ||
} | ||
getOrCreateWorkflowForBuilder(collectionName) { | ||
return new tools_1.NodeWorkflow(this.context.root, { | ||
resolvePaths: this.getResolvePaths(collectionName), | ||
engineHostCreator: (options) => new schematic_engine_host_1.SchematicEngineHost(options.resolvePaths), | ||
}); | ||
} | ||
async getOrCreateWorkflowForExecution(collectionName, options) { | ||
const { logger, root, packageManager } = this.context; | ||
const { force, dryRun, packageRegistry } = options; | ||
const workflow = new tools_1.NodeWorkflow(root, { | ||
force, | ||
dryRun, | ||
packageManager: packageManager.name, | ||
// A schema registry is required to allow customizing addUndefinedDefaults | ||
registry: new core_1.schema.CoreSchemaRegistry(schematics_1.formats.standardFormats), | ||
packageRegistry, | ||
resolvePaths: this.getResolvePaths(collectionName), | ||
schemaValidation: true, | ||
optionTransforms: [ | ||
// Add configuration file defaults | ||
async (schematic, current) => { | ||
const projectName = typeof current?.project === 'string' ? current.project : this.getProjectName(); | ||
return { | ||
...(await (0, config_1.getSchematicDefaults)(schematic.collection.name, schematic.name, projectName)), | ||
...current, | ||
}; | ||
}, | ||
], | ||
engineHostCreator: (options) => new schematic_engine_host_1.SchematicEngineHost(options.resolvePaths), | ||
}); | ||
workflow.registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults); | ||
workflow.registry.useXDeprecatedProvider((msg) => logger.warn(msg)); | ||
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName()); | ||
const workingDir = (0, core_1.normalize)((0, path_1.relative)(this.context.root, process.cwd())); | ||
workflow.registry.addSmartDefaultProvider('workingDirectory', () => workingDir === '' ? undefined : workingDir); | ||
let shouldReportAnalytics = true; | ||
workflow.engineHost.registerOptionsTransform(async (schematic, options) => { | ||
// Report analytics | ||
if (shouldReportAnalytics) { | ||
shouldReportAnalytics = false; | ||
const { collection: { name: collectionName }, name: schematicName, } = schematic; | ||
const analytics = (0, analytics_1.isPackageNameSafeForAnalytics)(collectionName) | ||
? await this.getAnalytics() | ||
: undefined; | ||
analytics?.reportSchematicRunEvent({ | ||
[analytics_parameters_1.EventCustomDimension.SchematicCollectionName]: collectionName, | ||
[analytics_parameters_1.EventCustomDimension.SchematicName]: schematicName, | ||
...this.getAnalyticsParameters(options), | ||
}); | ||
scope = (__runInitializers(this, _instanceExtraInitializers), command_module_1.CommandScope.In); | ||
allowPrivateSchematics = false; | ||
async builder(argv) { | ||
return argv | ||
.option('interactive', { | ||
describe: 'Enable interactive input prompts.', | ||
type: 'boolean', | ||
default: true, | ||
}) | ||
.option('dry-run', { | ||
describe: 'Run through and reports activity without writing out results.', | ||
type: 'boolean', | ||
alias: ['d'], | ||
default: false, | ||
}) | ||
.option('defaults', { | ||
describe: 'Disable interactive input prompts for options with a default.', | ||
type: 'boolean', | ||
default: false, | ||
}) | ||
.option('force', { | ||
describe: 'Force overwriting of existing files.', | ||
type: 'boolean', | ||
default: false, | ||
}) | ||
.strict(); | ||
} | ||
/** Get schematic schema options.*/ | ||
async getSchematicOptions(collection, schematicName, workflow) { | ||
const schematic = collection.createSchematic(schematicName, true); | ||
const { schemaJson } = schematic.description; | ||
if (!schemaJson) { | ||
return []; | ||
} | ||
return options; | ||
}); | ||
if (options.interactive !== false && (0, tty_1.isTTY)()) { | ||
workflow.registry.usePromptProvider(async (definitions) => { | ||
let prompts; | ||
const answers = {}; | ||
for (const definition of definitions) { | ||
if (options.defaults && definition.default !== undefined) { | ||
continue; | ||
} | ||
// Only load prompt package if needed | ||
prompts ??= await Promise.resolve().then(() => __importStar(require('@inquirer/prompts'))); | ||
switch (definition.type) { | ||
case 'confirmation': | ||
answers[definition.id] = await prompts.confirm({ | ||
message: definition.message, | ||
default: definition.default, | ||
}); | ||
break; | ||
case 'list': | ||
if (!definition.items?.length) { | ||
continue; | ||
} | ||
const choices = definition.items?.map((item) => { | ||
return typeof item == 'string' | ||
? { | ||
name: item, | ||
value: item, | ||
} | ||
: { | ||
name: item.label, | ||
value: item.value, | ||
}; | ||
}); | ||
answers[definition.id] = await (definition.multiselect ? prompts.checkbox : prompts.select)({ | ||
message: definition.message, | ||
default: definition.default, | ||
choices, | ||
}); | ||
break; | ||
case 'input': | ||
let finalValue; | ||
answers[definition.id] = await prompts.input({ | ||
message: definition.message, | ||
default: definition.default, | ||
async validate(value) { | ||
if (definition.validator === undefined) { | ||
return true; | ||
} | ||
let lastValidation = false; | ||
for (const type of definition.propertyTypes) { | ||
let potential; | ||
switch (type) { | ||
case 'string': | ||
potential = String(value); | ||
break; | ||
case 'integer': | ||
case 'number': | ||
potential = Number(value); | ||
break; | ||
default: | ||
potential = value; | ||
break; | ||
return (0, json_schema_1.parseJsonSchemaToOptions)(workflow.registry, schemaJson); | ||
} | ||
getOrCreateWorkflowForBuilder(collectionName) { | ||
return new tools_1.NodeWorkflow(this.context.root, { | ||
resolvePaths: this.getResolvePaths(collectionName), | ||
engineHostCreator: (options) => new schematic_engine_host_1.SchematicEngineHost(options.resolvePaths), | ||
}); | ||
} | ||
async getOrCreateWorkflowForExecution(collectionName, options) { | ||
const { logger, root, packageManager } = this.context; | ||
const { force, dryRun, packageRegistry } = options; | ||
const workflow = new tools_1.NodeWorkflow(root, { | ||
force, | ||
dryRun, | ||
packageManager: packageManager.name, | ||
// A schema registry is required to allow customizing addUndefinedDefaults | ||
registry: new core_1.schema.CoreSchemaRegistry(schematics_1.formats.standardFormats), | ||
packageRegistry, | ||
resolvePaths: this.getResolvePaths(collectionName), | ||
schemaValidation: true, | ||
optionTransforms: [ | ||
// Add configuration file defaults | ||
async (schematic, current) => { | ||
const projectName = typeof current?.project === 'string' ? current.project : this.getProjectName(); | ||
return { | ||
...(await (0, config_1.getSchematicDefaults)(schematic.collection.name, schematic.name, projectName)), | ||
...current, | ||
}; | ||
}, | ||
], | ||
engineHostCreator: (options) => new schematic_engine_host_1.SchematicEngineHost(options.resolvePaths), | ||
}); | ||
workflow.registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults); | ||
workflow.registry.useXDeprecatedProvider((msg) => logger.warn(msg)); | ||
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName()); | ||
const workingDir = (0, core_1.normalize)((0, path_1.relative)(this.context.root, process.cwd())); | ||
workflow.registry.addSmartDefaultProvider('workingDirectory', () => workingDir === '' ? undefined : workingDir); | ||
let shouldReportAnalytics = true; | ||
workflow.engineHost.registerOptionsTransform(async (schematic, options) => { | ||
// Report analytics | ||
if (shouldReportAnalytics) { | ||
shouldReportAnalytics = false; | ||
const { collection: { name: collectionName }, name: schematicName, } = schematic; | ||
const analytics = (0, analytics_1.isPackageNameSafeForAnalytics)(collectionName) | ||
? await this.getAnalytics() | ||
: undefined; | ||
analytics?.reportSchematicRunEvent({ | ||
[analytics_parameters_1.EventCustomDimension.SchematicCollectionName]: collectionName, | ||
[analytics_parameters_1.EventCustomDimension.SchematicName]: schematicName, | ||
...this.getAnalyticsParameters(options), | ||
}); | ||
} | ||
return options; | ||
}); | ||
if (options.interactive !== false && (0, tty_1.isTTY)()) { | ||
workflow.registry.usePromptProvider(async (definitions) => { | ||
let prompts; | ||
const answers = {}; | ||
for (const definition of definitions) { | ||
if (options.defaults && definition.default !== undefined) { | ||
continue; | ||
} | ||
// Only load prompt package if needed | ||
prompts ??= await Promise.resolve().then(() => __importStar(require('@inquirer/prompts'))); | ||
switch (definition.type) { | ||
case 'confirmation': | ||
answers[definition.id] = await prompts.confirm({ | ||
message: definition.message, | ||
default: definition.default, | ||
}); | ||
break; | ||
case 'list': | ||
if (!definition.items?.length) { | ||
continue; | ||
} | ||
const choices = definition.items?.map((item) => { | ||
return typeof item == 'string' | ||
? { | ||
name: item, | ||
value: item, | ||
} | ||
lastValidation = await definition.validator(potential); | ||
// Can be a string if validation fails | ||
if (lastValidation === true) { | ||
finalValue = potential; | ||
: { | ||
name: item.label, | ||
value: item.value, | ||
}; | ||
}); | ||
answers[definition.id] = await (definition.multiselect ? prompts.checkbox : prompts.select)({ | ||
message: definition.message, | ||
default: definition.default, | ||
choices, | ||
}); | ||
break; | ||
case 'input': | ||
let finalValue; | ||
answers[definition.id] = await prompts.input({ | ||
message: definition.message, | ||
default: definition.default, | ||
async validate(value) { | ||
if (definition.validator === undefined) { | ||
return true; | ||
} | ||
} | ||
return lastValidation; | ||
}, | ||
}); | ||
// Use validated value if present. | ||
// This ensures the correct type is inserted into the final schema options. | ||
if (finalValue !== undefined) { | ||
answers[definition.id] = finalValue; | ||
} | ||
break; | ||
let lastValidation = false; | ||
for (const type of definition.propertyTypes) { | ||
let potential; | ||
switch (type) { | ||
case 'string': | ||
potential = String(value); | ||
break; | ||
case 'integer': | ||
case 'number': | ||
potential = Number(value); | ||
break; | ||
default: | ||
potential = value; | ||
break; | ||
} | ||
lastValidation = await definition.validator(potential); | ||
// Can be a string if validation fails | ||
if (lastValidation === true) { | ||
finalValue = potential; | ||
return true; | ||
} | ||
} | ||
return lastValidation; | ||
}, | ||
}); | ||
// Use validated value if present. | ||
// This ensures the correct type is inserted into the final schema options. | ||
if (finalValue !== undefined) { | ||
answers[definition.id] = finalValue; | ||
} | ||
break; | ||
} | ||
} | ||
return answers; | ||
}); | ||
} | ||
return workflow; | ||
} | ||
async getSchematicCollections() { | ||
// Resolve relative collections from the location of `angular.json` | ||
const resolveRelativeCollection = (collectionName) => collectionName.charAt(0) === '.' | ||
? (0, path_1.resolve)(this.context.root, collectionName) | ||
: collectionName; | ||
const getSchematicCollections = (configSection) => { | ||
if (!configSection) { | ||
return undefined; | ||
} | ||
return answers; | ||
}); | ||
} | ||
return workflow; | ||
} | ||
async getSchematicCollections() { | ||
// Resolve relative collections from the location of `angular.json` | ||
const resolveRelativeCollection = (collectionName) => collectionName.charAt(0) === '.' | ||
? (0, path_1.resolve)(this.context.root, collectionName) | ||
: collectionName; | ||
const getSchematicCollections = (configSection) => { | ||
if (!configSection) { | ||
const { schematicCollections } = configSection; | ||
if (Array.isArray(schematicCollections)) { | ||
return new Set(schematicCollections.map((c) => resolveRelativeCollection(c))); | ||
} | ||
return undefined; | ||
}; | ||
const { workspace, globalConfiguration } = this.context; | ||
if (workspace) { | ||
const project = (0, config_1.getProjectByCwd)(workspace); | ||
if (project) { | ||
const value = getSchematicCollections(workspace.getProjectCli(project)); | ||
if (value) { | ||
return value; | ||
} | ||
} | ||
} | ||
const { schematicCollections } = configSection; | ||
if (Array.isArray(schematicCollections)) { | ||
return new Set(schematicCollections.map((c) => resolveRelativeCollection(c))); | ||
const value = getSchematicCollections(workspace?.getCli()) ?? | ||
getSchematicCollections(globalConfiguration.getCli()); | ||
if (value) { | ||
return value; | ||
} | ||
return undefined; | ||
}; | ||
const { workspace, globalConfiguration } = this.context; | ||
if (workspace) { | ||
const project = (0, config_1.getProjectByCwd)(workspace); | ||
if (project) { | ||
const value = getSchematicCollections(workspace.getProjectCli(project)); | ||
if (value) { | ||
return value; | ||
} | ||
return new Set([exports.DEFAULT_SCHEMATICS_COLLECTION]); | ||
} | ||
parseSchematicInfo(schematic) { | ||
if (schematic?.includes(':')) { | ||
const [collectionName, schematicName] = schematic.split(':', 2); | ||
return [collectionName, schematicName]; | ||
} | ||
return [undefined, schematic]; | ||
} | ||
const value = getSchematicCollections(workspace?.getCli()) ?? | ||
getSchematicCollections(globalConfiguration.getCli()); | ||
if (value) { | ||
return value; | ||
} | ||
return new Set([exports.DEFAULT_SCHEMATICS_COLLECTION]); | ||
} | ||
parseSchematicInfo(schematic) { | ||
if (schematic?.includes(':')) { | ||
const [collectionName, schematicName] = schematic.split(':', 2); | ||
return [collectionName, schematicName]; | ||
} | ||
return [undefined, schematic]; | ||
} | ||
async runSchematic(options) { | ||
const { logger } = this.context; | ||
const { schematicOptions, executionOptions, collectionName, schematicName } = options; | ||
const workflow = await this.getOrCreateWorkflowForExecution(collectionName, executionOptions); | ||
if (!schematicName) { | ||
throw new Error('schematicName cannot be undefined.'); | ||
} | ||
const { unsubscribe, files } = (0, schematic_workflow_1.subscribeToWorkflow)(workflow, logger); | ||
try { | ||
await workflow | ||
.execute({ | ||
collection: collectionName, | ||
schematic: schematicName, | ||
options: schematicOptions, | ||
logger, | ||
allowPrivate: this.allowPrivateSchematics, | ||
}) | ||
.toPromise(); | ||
if (!files.size) { | ||
logger.info('Nothing to be done.'); | ||
async runSchematic(options) { | ||
const { logger } = this.context; | ||
const { schematicOptions, executionOptions, collectionName, schematicName } = options; | ||
const workflow = await this.getOrCreateWorkflowForExecution(collectionName, executionOptions); | ||
if (!schematicName) { | ||
throw new Error('schematicName cannot be undefined.'); | ||
} | ||
if (executionOptions.dryRun) { | ||
logger.warn(`\nNOTE: The "--dry-run" option means no changes were made.`); | ||
const { unsubscribe, files } = (0, schematic_workflow_1.subscribeToWorkflow)(workflow, logger); | ||
try { | ||
await workflow | ||
.execute({ | ||
collection: collectionName, | ||
schematic: schematicName, | ||
options: schematicOptions, | ||
logger, | ||
allowPrivate: this.allowPrivateSchematics, | ||
}) | ||
.toPromise(); | ||
if (!files.size) { | ||
logger.info('Nothing to be done.'); | ||
} | ||
if (executionOptions.dryRun) { | ||
logger.warn(`\nNOTE: The "--dry-run" option means no changes were made.`); | ||
} | ||
} | ||
catch (err) { | ||
// In case the workflow was not successful, show an appropriate error message. | ||
if (err instanceof schematics_1.UnsuccessfulWorkflowExecution) { | ||
// "See above" because we already printed the error. | ||
logger.fatal('The Schematic workflow failed. See above.'); | ||
} | ||
else { | ||
(0, error_1.assertIsError)(err); | ||
logger.fatal(err.message); | ||
} | ||
return 1; | ||
} | ||
finally { | ||
unsubscribe(); | ||
} | ||
return 0; | ||
} | ||
catch (err) { | ||
// In case the workflow was not successful, show an appropriate error message. | ||
if (err instanceof schematics_1.UnsuccessfulWorkflowExecution) { | ||
// "See above" because we already printed the error. | ||
logger.fatal('The Schematic workflow failed. See above.'); | ||
getProjectName() { | ||
const { workspace, logger } = this.context; | ||
if (!workspace) { | ||
return undefined; | ||
} | ||
else { | ||
(0, error_1.assertIsError)(err); | ||
logger.fatal(err.message); | ||
const projectName = (0, config_1.getProjectByCwd)(workspace); | ||
if (projectName) { | ||
return projectName; | ||
} | ||
return 1; | ||
} | ||
finally { | ||
unsubscribe(); | ||
} | ||
return 0; | ||
} | ||
getProjectName() { | ||
const { workspace, logger } = this.context; | ||
if (!workspace) { | ||
return undefined; | ||
} | ||
const projectName = (0, config_1.getProjectByCwd)(workspace); | ||
if (projectName) { | ||
return projectName; | ||
getResolvePaths(collectionName) { | ||
const { workspace, root } = this.context; | ||
return workspace | ||
? // Workspace | ||
collectionName === exports.DEFAULT_SCHEMATICS_COLLECTION | ||
? // Favor __dirname for @schematics/angular to use the build-in version | ||
[__dirname, process.cwd(), root] | ||
: [process.cwd(), root, __dirname] | ||
: // Global | ||
[__dirname, process.cwd()]; | ||
} | ||
return undefined; | ||
} | ||
getResolvePaths(collectionName) { | ||
const { workspace, root } = this.context; | ||
return workspace | ||
? // Workspace | ||
collectionName === exports.DEFAULT_SCHEMATICS_COLLECTION | ||
? // Favor __dirname for @schematics/angular to use the build-in version | ||
[__dirname, process.cwd(), root] | ||
: [process.cwd(), root, __dirname] | ||
: // Global | ||
[__dirname, process.cwd()]; | ||
} | ||
} | ||
}; | ||
})(); | ||
exports.SchematicsCommandModule = SchematicsCommandModule; | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", [String]), | ||
__metadata("design:returntype", tools_1.NodeWorkflow) | ||
], SchematicsCommandModule.prototype, "getOrCreateWorkflowForBuilder", null); | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", [String, Object]), | ||
__metadata("design:returntype", Promise) | ||
], SchematicsCommandModule.prototype, "getOrCreateWorkflowForExecution", null); | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", []), | ||
__metadata("design:returntype", Promise) | ||
], SchematicsCommandModule.prototype, "getSchematicCollections", null); |
@@ -33,3 +33,3 @@ "use strict"; | ||
: await this.getCollectionFromConfig(); | ||
const workflow = await this.getOrCreateWorkflowForBuilder(collectionName); | ||
const workflow = this.getOrCreateWorkflowForBuilder(collectionName); | ||
const collection = workflow.engine.createCollection(collectionName); | ||
@@ -36,0 +36,0 @@ const options = await this.getSchematicOptions(collection, this.schematicName, workflow); |
@@ -9,2 +9,2 @@ /** | ||
export { color as colors, figures } from 'listr2'; | ||
export declare function supportColor(): boolean; | ||
export declare function supportColor(stream?: NodeJS.WritableStream): boolean; |
@@ -16,25 +16,13 @@ "use strict"; | ||
Object.defineProperty(exports, "figures", { enumerable: true, get: function () { return listr2_1.figures; } }); | ||
function supportColor() { | ||
if (process.env.FORCE_COLOR !== undefined) { | ||
// 2 colors: FORCE_COLOR = 0 (Disables colors), depth 1 | ||
// 16 colors: FORCE_COLOR = 1, depth 4 | ||
// 256 colors: FORCE_COLOR = 2, depth 8 | ||
// 16,777,216 colors: FORCE_COLOR = 3, depth 16 | ||
// See: https://nodejs.org/dist/latest-v12.x/docs/api/tty.html#tty_writestream_getcolordepth_env | ||
// and https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/tty.js#L106; | ||
switch (process.env.FORCE_COLOR) { | ||
case '': | ||
case 'true': | ||
case '1': | ||
case '2': | ||
case '3': | ||
return true; | ||
default: | ||
return false; | ||
} | ||
function supportColor(stream = process.stdout) { | ||
if (stream instanceof node_tty_1.WriteStream) { | ||
return stream.hasColors(); | ||
} | ||
if (process.stdout instanceof node_tty_1.WriteStream) { | ||
return process.stdout.getColorDepth() > 1; | ||
try { | ||
// The hasColors function does not rely on any instance state and should ideally be static | ||
return node_tty_1.WriteStream.prototype.hasColors(); | ||
} | ||
return false; | ||
catch { | ||
return process.env['FORCE_COLOR'] !== undefined && process.env['FORCE_COLOR'] !== '0'; | ||
} | ||
} |
@@ -15,2 +15,2 @@ /** | ||
*/ | ||
export declare function memoize<T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T>; | ||
export declare function memoize<This, Args extends unknown[], Return>(target: (this: This, ...args: Args) => Return, context: ClassMemberDecoratorContext): (this: This, ...args: Args) => Return; |
@@ -18,25 +18,20 @@ "use strict"; | ||
*/ | ||
function memoize(target, propertyKey, descriptor) { | ||
const descriptorPropertyName = descriptor.get ? 'get' : 'value'; | ||
const originalMethod = descriptor[descriptorPropertyName]; | ||
if (typeof originalMethod !== 'function') { | ||
function memoize(target, context) { | ||
if (context.kind !== 'method' && context.kind !== 'getter') { | ||
throw new Error('Memoize decorator can only be used on methods or get accessors.'); | ||
} | ||
const cache = new Map(); | ||
return { | ||
...descriptor, | ||
[descriptorPropertyName]: function (...args) { | ||
for (const arg of args) { | ||
if (!isJSONSerializable(arg)) { | ||
throw new Error(`Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JSON serializable.`); | ||
} | ||
return function (...args) { | ||
for (const arg of args) { | ||
if (!isJSONSerializable(arg)) { | ||
throw new Error(`Argument ${isNonPrimitive(arg) ? arg.toString() : arg} is JSON serializable.`); | ||
} | ||
const key = JSON.stringify(args); | ||
if (cache.has(key)) { | ||
return cache.get(key); | ||
} | ||
const result = originalMethod.apply(this, args); | ||
cache.set(key, result); | ||
return result; | ||
}, | ||
} | ||
const key = JSON.stringify(args); | ||
if (cache.has(key)) { | ||
return cache.get(key); | ||
} | ||
const result = target.apply(this, args); | ||
cache.set(key, result); | ||
return result; | ||
}; | ||
@@ -43,0 +38,0 @@ } |
@@ -9,10 +9,35 @@ "use strict"; | ||
*/ | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { | ||
var useValue = arguments.length > 2; | ||
for (var i = 0; i < initializers.length; i++) { | ||
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); | ||
} | ||
return useValue ? value : void 0; | ||
}; | ||
var __metadata = (this && this.__metadata) || function (k, v) { | ||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { | ||
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } | ||
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; | ||
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; | ||
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); | ||
var _, done = false; | ||
for (var i = decorators.length - 1; i >= 0; i--) { | ||
var context = {}; | ||
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; | ||
for (var p in contextIn.access) context.access[p] = contextIn.access[p]; | ||
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; | ||
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); | ||
if (kind === "accessor") { | ||
if (result === void 0) continue; | ||
if (result === null || typeof result !== "object") throw new TypeError("Object expected"); | ||
if (_ = accept(result.get)) descriptor.get = _; | ||
if (_ = accept(result.set)) descriptor.set = _; | ||
if (_ = accept(result.init)) initializers.unshift(_); | ||
} | ||
else if (_ = accept(result)) { | ||
if (kind === "field") initializers.unshift(_); | ||
else descriptor[key] = _; | ||
} | ||
} | ||
if (target) Object.defineProperty(target, contextIn.name, descriptor); | ||
done = true; | ||
}; | ||
@@ -29,255 +54,256 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
const memoize_1 = require("./memoize"); | ||
class PackageManagerUtils { | ||
context; | ||
constructor(context) { | ||
this.context = context; | ||
} | ||
/** Get the package manager name. */ | ||
get name() { | ||
return this.getName(); | ||
} | ||
/** Get the package manager version. */ | ||
get version() { | ||
return this.getVersion(this.name); | ||
} | ||
/** Install a single package. */ | ||
async install(packageName, save = true, extraArgs = [], cwd) { | ||
const packageManagerArgs = this.getArguments(); | ||
const installArgs = [packageManagerArgs.install, packageName]; | ||
if (save === 'devDependencies') { | ||
installArgs.push(packageManagerArgs.saveDev); | ||
let PackageManagerUtils = (() => { | ||
let _instanceExtraInitializers = []; | ||
let _getVersion_decorators; | ||
let _getName_decorators; | ||
return class PackageManagerUtils { | ||
static { | ||
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; | ||
_getVersion_decorators = [memoize_1.memoize]; | ||
_getName_decorators = [memoize_1.memoize]; | ||
__esDecorate(this, null, _getVersion_decorators, { kind: "method", name: "getVersion", static: false, private: false, access: { has: obj => "getVersion" in obj, get: obj => obj.getVersion }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
__esDecorate(this, null, _getName_decorators, { kind: "method", name: "getName", static: false, private: false, access: { has: obj => "getName" in obj, get: obj => obj.getName }, metadata: _metadata }, null, _instanceExtraInitializers); | ||
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); | ||
} | ||
return this.run([...installArgs, ...extraArgs], { cwd, silent: true }); | ||
} | ||
/** Install all packages. */ | ||
async installAll(extraArgs = [], cwd) { | ||
const packageManagerArgs = this.getArguments(); | ||
const installArgs = []; | ||
if (packageManagerArgs.installAll) { | ||
installArgs.push(packageManagerArgs.installAll); | ||
context = __runInitializers(this, _instanceExtraInitializers); | ||
constructor(context) { | ||
this.context = context; | ||
} | ||
return this.run([...installArgs, ...extraArgs], { cwd, silent: true }); | ||
} | ||
/** Install a single package temporary. */ | ||
async installTemp(packageName, extraArgs) { | ||
const tempPath = await fs_1.promises.mkdtemp((0, path_1.join)((0, fs_1.realpathSync)((0, os_1.tmpdir)()), 'angular-cli-packages-')); | ||
// clean up temp directory on process exit | ||
process.on('exit', () => { | ||
try { | ||
(0, fs_1.rmSync)(tempPath, { recursive: true, maxRetries: 3 }); | ||
/** Get the package manager name. */ | ||
get name() { | ||
return this.getName(); | ||
} | ||
/** Get the package manager version. */ | ||
get version() { | ||
return this.getVersion(this.name); | ||
} | ||
/** Install a single package. */ | ||
async install(packageName, save = true, extraArgs = [], cwd) { | ||
const packageManagerArgs = this.getArguments(); | ||
const installArgs = [packageManagerArgs.install, packageName]; | ||
if (save === 'devDependencies') { | ||
installArgs.push(packageManagerArgs.saveDev); | ||
} | ||
catch { } | ||
}); | ||
// NPM will warn when a `package.json` is not found in the install directory | ||
// Example: | ||
// npm WARN enoent ENOENT: no such file or directory, open '/tmp/.ng-temp-packages-84Qi7y/package.json' | ||
// npm WARN .ng-temp-packages-84Qi7y No description | ||
// npm WARN .ng-temp-packages-84Qi7y No repository field. | ||
// npm WARN .ng-temp-packages-84Qi7y No license field. | ||
// While we can use `npm init -y` we will end up needing to update the 'package.json' anyways | ||
// because of missing fields. | ||
await fs_1.promises.writeFile((0, path_1.join)(tempPath, 'package.json'), JSON.stringify({ | ||
name: 'temp-cli-install', | ||
description: 'temp-cli-install', | ||
repository: 'temp-cli-install', | ||
license: 'MIT', | ||
})); | ||
// setup prefix/global modules path | ||
const packageManagerArgs = this.getArguments(); | ||
const tempNodeModules = (0, path_1.join)(tempPath, 'node_modules'); | ||
// Yarn will not append 'node_modules' to the path | ||
const prefixPath = this.name === workspace_schema_1.PackageManager.Yarn ? tempNodeModules : tempPath; | ||
const installArgs = [ | ||
...(extraArgs ?? []), | ||
`${packageManagerArgs.prefix}="${prefixPath}"`, | ||
packageManagerArgs.noLockfile, | ||
]; | ||
return { | ||
success: await this.install(packageName, true, installArgs, tempPath), | ||
tempNodeModules, | ||
}; | ||
} | ||
getArguments() { | ||
switch (this.name) { | ||
case workspace_schema_1.PackageManager.Yarn: | ||
return { | ||
saveDev: '--dev', | ||
install: 'add', | ||
prefix: '--modules-folder', | ||
noLockfile: '--no-lockfile', | ||
}; | ||
case workspace_schema_1.PackageManager.Pnpm: | ||
return { | ||
saveDev: '--save-dev', | ||
install: 'add', | ||
installAll: 'install', | ||
prefix: '--prefix', | ||
noLockfile: '--no-lockfile', | ||
}; | ||
case workspace_schema_1.PackageManager.Bun: | ||
return { | ||
saveDev: '--development', | ||
install: 'add', | ||
installAll: 'install', | ||
prefix: '--cwd', | ||
noLockfile: '', | ||
}; | ||
default: | ||
return { | ||
saveDev: '--save-dev', | ||
install: 'install', | ||
installAll: 'install', | ||
prefix: '--prefix', | ||
noLockfile: '--no-package-lock', | ||
}; | ||
return this.run([...installArgs, ...extraArgs], { cwd, silent: true }); | ||
} | ||
} | ||
async run(args, options = {}) { | ||
const { cwd = process.cwd(), silent = false } = options; | ||
return new Promise((resolve) => { | ||
const bufferedOutput = []; | ||
const childProcess = (0, child_process_1.spawn)(this.name, args, { | ||
// Always pipe stderr to allow for failures to be reported | ||
stdio: silent ? ['ignore', 'ignore', 'pipe'] : 'pipe', | ||
shell: true, | ||
cwd, | ||
}).on('close', (code) => { | ||
if (code === 0) { | ||
resolve(true); | ||
/** Install all packages. */ | ||
async installAll(extraArgs = [], cwd) { | ||
const packageManagerArgs = this.getArguments(); | ||
const installArgs = []; | ||
if (packageManagerArgs.installAll) { | ||
installArgs.push(packageManagerArgs.installAll); | ||
} | ||
return this.run([...installArgs, ...extraArgs], { cwd, silent: true }); | ||
} | ||
/** Install a single package temporary. */ | ||
async installTemp(packageName, extraArgs) { | ||
const tempPath = await fs_1.promises.mkdtemp((0, path_1.join)((0, fs_1.realpathSync)((0, os_1.tmpdir)()), 'angular-cli-packages-')); | ||
// clean up temp directory on process exit | ||
process.on('exit', () => { | ||
try { | ||
(0, fs_1.rmSync)(tempPath, { recursive: true, maxRetries: 3 }); | ||
} | ||
else { | ||
bufferedOutput.forEach(({ stream, data }) => stream.write(data)); | ||
resolve(false); | ||
} | ||
catch { } | ||
}); | ||
childProcess.stdout?.on('data', (data) => bufferedOutput.push({ stream: process.stdout, data: data })); | ||
childProcess.stderr?.on('data', (data) => bufferedOutput.push({ stream: process.stderr, data: data })); | ||
}); | ||
} | ||
getVersion(name) { | ||
try { | ||
return (0, child_process_1.execSync)(`${name} --version`, { | ||
encoding: 'utf8', | ||
stdio: ['ignore', 'pipe', 'ignore'], | ||
env: { | ||
...process.env, | ||
// NPM updater notifier will prevents the child process from closing until it timeout after 3 minutes. | ||
NO_UPDATE_NOTIFIER: '1', | ||
NPM_CONFIG_UPDATE_NOTIFIER: 'false', | ||
}, | ||
}).trim(); | ||
// NPM will warn when a `package.json` is not found in the install directory | ||
// Example: | ||
// npm WARN enoent ENOENT: no such file or directory, open '/tmp/.ng-temp-packages-84Qi7y/package.json' | ||
// npm WARN .ng-temp-packages-84Qi7y No description | ||
// npm WARN .ng-temp-packages-84Qi7y No repository field. | ||
// npm WARN .ng-temp-packages-84Qi7y No license field. | ||
// While we can use `npm init -y` we will end up needing to update the 'package.json' anyways | ||
// because of missing fields. | ||
await fs_1.promises.writeFile((0, path_1.join)(tempPath, 'package.json'), JSON.stringify({ | ||
name: 'temp-cli-install', | ||
description: 'temp-cli-install', | ||
repository: 'temp-cli-install', | ||
license: 'MIT', | ||
})); | ||
// setup prefix/global modules path | ||
const packageManagerArgs = this.getArguments(); | ||
const tempNodeModules = (0, path_1.join)(tempPath, 'node_modules'); | ||
// Yarn will not append 'node_modules' to the path | ||
const prefixPath = this.name === workspace_schema_1.PackageManager.Yarn ? tempNodeModules : tempPath; | ||
const installArgs = [ | ||
...(extraArgs ?? []), | ||
`${packageManagerArgs.prefix}="${prefixPath}"`, | ||
packageManagerArgs.noLockfile, | ||
]; | ||
return { | ||
success: await this.install(packageName, true, installArgs, tempPath), | ||
tempNodeModules, | ||
}; | ||
} | ||
catch { | ||
return undefined; | ||
getArguments() { | ||
switch (this.name) { | ||
case workspace_schema_1.PackageManager.Yarn: | ||
return { | ||
saveDev: '--dev', | ||
install: 'add', | ||
prefix: '--modules-folder', | ||
noLockfile: '--no-lockfile', | ||
}; | ||
case workspace_schema_1.PackageManager.Pnpm: | ||
return { | ||
saveDev: '--save-dev', | ||
install: 'add', | ||
installAll: 'install', | ||
prefix: '--prefix', | ||
noLockfile: '--no-lockfile', | ||
}; | ||
case workspace_schema_1.PackageManager.Bun: | ||
return { | ||
saveDev: '--development', | ||
install: 'add', | ||
installAll: 'install', | ||
prefix: '--cwd', | ||
noLockfile: '', | ||
}; | ||
default: | ||
return { | ||
saveDev: '--save-dev', | ||
install: 'install', | ||
installAll: 'install', | ||
prefix: '--prefix', | ||
noLockfile: '--no-package-lock', | ||
}; | ||
} | ||
} | ||
} | ||
getName() { | ||
const packageManager = this.getConfiguredPackageManager(); | ||
if (packageManager) { | ||
return packageManager; | ||
async run(args, options = {}) { | ||
const { cwd = process.cwd(), silent = false } = options; | ||
return new Promise((resolve) => { | ||
const bufferedOutput = []; | ||
const childProcess = (0, child_process_1.spawn)(this.name, args, { | ||
// Always pipe stderr to allow for failures to be reported | ||
stdio: silent ? ['ignore', 'ignore', 'pipe'] : 'pipe', | ||
shell: true, | ||
cwd, | ||
}).on('close', (code) => { | ||
if (code === 0) { | ||
resolve(true); | ||
} | ||
else { | ||
bufferedOutput.forEach(({ stream, data }) => stream.write(data)); | ||
resolve(false); | ||
} | ||
}); | ||
childProcess.stdout?.on('data', (data) => bufferedOutput.push({ stream: process.stdout, data: data })); | ||
childProcess.stderr?.on('data', (data) => bufferedOutput.push({ stream: process.stderr, data: data })); | ||
}); | ||
} | ||
const hasNpmLock = this.hasLockfile(workspace_schema_1.PackageManager.Npm); | ||
const hasYarnLock = this.hasLockfile(workspace_schema_1.PackageManager.Yarn); | ||
const hasPnpmLock = this.hasLockfile(workspace_schema_1.PackageManager.Pnpm); | ||
const hasBunLock = this.hasLockfile(workspace_schema_1.PackageManager.Bun); | ||
// PERF NOTE: `this.getVersion` spawns the package a the child_process which can take around ~300ms at times. | ||
// Therefore, we should only call this method when needed. IE: don't call `this.getVersion(PackageManager.Pnpm)` unless truly needed. | ||
// The result of this method is not stored in a variable because it's memoized. | ||
if (hasNpmLock) { | ||
// Has NPM lock file. | ||
if (!hasYarnLock && !hasPnpmLock && !hasBunLock && this.getVersion(workspace_schema_1.PackageManager.Npm)) { | ||
// Only NPM lock file and NPM binary is available. | ||
return workspace_schema_1.PackageManager.Npm; | ||
getVersion(name) { | ||
try { | ||
return (0, child_process_1.execSync)(`${name} --version`, { | ||
encoding: 'utf8', | ||
stdio: ['ignore', 'pipe', 'ignore'], | ||
env: { | ||
...process.env, | ||
// NPM updater notifier will prevents the child process from closing until it timeout after 3 minutes. | ||
NO_UPDATE_NOTIFIER: '1', | ||
NPM_CONFIG_UPDATE_NOTIFIER: 'false', | ||
}, | ||
}).trim(); | ||
} | ||
catch { | ||
return undefined; | ||
} | ||
} | ||
else { | ||
// No NPM lock file. | ||
if (hasYarnLock && this.getVersion(workspace_schema_1.PackageManager.Yarn)) { | ||
// Yarn lock file and Yarn binary is available. | ||
return workspace_schema_1.PackageManager.Yarn; | ||
getName() { | ||
const packageManager = this.getConfiguredPackageManager(); | ||
if (packageManager) { | ||
return packageManager; | ||
} | ||
else if (hasPnpmLock && this.getVersion(workspace_schema_1.PackageManager.Pnpm)) { | ||
// PNPM lock file and PNPM binary is available. | ||
return workspace_schema_1.PackageManager.Pnpm; | ||
const hasNpmLock = this.hasLockfile(workspace_schema_1.PackageManager.Npm); | ||
const hasYarnLock = this.hasLockfile(workspace_schema_1.PackageManager.Yarn); | ||
const hasPnpmLock = this.hasLockfile(workspace_schema_1.PackageManager.Pnpm); | ||
const hasBunLock = this.hasLockfile(workspace_schema_1.PackageManager.Bun); | ||
// PERF NOTE: `this.getVersion` spawns the package a the child_process which can take around ~300ms at times. | ||
// Therefore, we should only call this method when needed. IE: don't call `this.getVersion(PackageManager.Pnpm)` unless truly needed. | ||
// The result of this method is not stored in a variable because it's memoized. | ||
if (hasNpmLock) { | ||
// Has NPM lock file. | ||
if (!hasYarnLock && !hasPnpmLock && !hasBunLock && this.getVersion(workspace_schema_1.PackageManager.Npm)) { | ||
// Only NPM lock file and NPM binary is available. | ||
return workspace_schema_1.PackageManager.Npm; | ||
} | ||
} | ||
else if (hasBunLock && this.getVersion(workspace_schema_1.PackageManager.Bun)) { | ||
// Bun lock file and Bun binary is available. | ||
return workspace_schema_1.PackageManager.Bun; | ||
else { | ||
// No NPM lock file. | ||
if (hasYarnLock && this.getVersion(workspace_schema_1.PackageManager.Yarn)) { | ||
// Yarn lock file and Yarn binary is available. | ||
return workspace_schema_1.PackageManager.Yarn; | ||
} | ||
else if (hasPnpmLock && this.getVersion(workspace_schema_1.PackageManager.Pnpm)) { | ||
// PNPM lock file and PNPM binary is available. | ||
return workspace_schema_1.PackageManager.Pnpm; | ||
} | ||
else if (hasBunLock && this.getVersion(workspace_schema_1.PackageManager.Bun)) { | ||
// Bun lock file and Bun binary is available. | ||
return workspace_schema_1.PackageManager.Bun; | ||
} | ||
} | ||
if (!this.getVersion(workspace_schema_1.PackageManager.Npm)) { | ||
// Doesn't have NPM installed. | ||
const hasYarn = !!this.getVersion(workspace_schema_1.PackageManager.Yarn); | ||
const hasPnpm = !!this.getVersion(workspace_schema_1.PackageManager.Pnpm); | ||
const hasBun = !!this.getVersion(workspace_schema_1.PackageManager.Bun); | ||
if (hasYarn && !hasPnpm && !hasBun) { | ||
return workspace_schema_1.PackageManager.Yarn; | ||
} | ||
else if (hasPnpm && !hasYarn && !hasBun) { | ||
return workspace_schema_1.PackageManager.Pnpm; | ||
} | ||
else if (hasBun && !hasYarn && !hasPnpm) { | ||
return workspace_schema_1.PackageManager.Bun; | ||
} | ||
} | ||
// TODO: This should eventually inform the user of ambiguous package manager usage. | ||
// Potentially with a prompt to choose and optionally set as the default. | ||
return workspace_schema_1.PackageManager.Npm; | ||
} | ||
if (!this.getVersion(workspace_schema_1.PackageManager.Npm)) { | ||
// Doesn't have NPM installed. | ||
const hasYarn = !!this.getVersion(workspace_schema_1.PackageManager.Yarn); | ||
const hasPnpm = !!this.getVersion(workspace_schema_1.PackageManager.Pnpm); | ||
const hasBun = !!this.getVersion(workspace_schema_1.PackageManager.Bun); | ||
if (hasYarn && !hasPnpm && !hasBun) { | ||
return workspace_schema_1.PackageManager.Yarn; | ||
hasLockfile(packageManager) { | ||
let lockfileName; | ||
switch (packageManager) { | ||
case workspace_schema_1.PackageManager.Yarn: | ||
lockfileName = 'yarn.lock'; | ||
break; | ||
case workspace_schema_1.PackageManager.Pnpm: | ||
lockfileName = 'pnpm-lock.yaml'; | ||
break; | ||
case workspace_schema_1.PackageManager.Bun: | ||
lockfileName = 'bun.lockb'; | ||
break; | ||
case workspace_schema_1.PackageManager.Npm: | ||
default: | ||
lockfileName = 'package-lock.json'; | ||
break; | ||
} | ||
else if (hasPnpm && !hasYarn && !hasBun) { | ||
return workspace_schema_1.PackageManager.Pnpm; | ||
} | ||
else if (hasBun && !hasYarn && !hasPnpm) { | ||
return workspace_schema_1.PackageManager.Bun; | ||
} | ||
return (0, fs_1.existsSync)((0, path_1.join)(this.context.root, lockfileName)); | ||
} | ||
// TODO: This should eventually inform the user of ambiguous package manager usage. | ||
// Potentially with a prompt to choose and optionally set as the default. | ||
return workspace_schema_1.PackageManager.Npm; | ||
} | ||
hasLockfile(packageManager) { | ||
let lockfileName; | ||
switch (packageManager) { | ||
case workspace_schema_1.PackageManager.Yarn: | ||
lockfileName = 'yarn.lock'; | ||
break; | ||
case workspace_schema_1.PackageManager.Pnpm: | ||
lockfileName = 'pnpm-lock.yaml'; | ||
break; | ||
case workspace_schema_1.PackageManager.Bun: | ||
lockfileName = 'bun.lockb'; | ||
break; | ||
case workspace_schema_1.PackageManager.Npm: | ||
default: | ||
lockfileName = 'package-lock.json'; | ||
break; | ||
} | ||
return (0, fs_1.existsSync)((0, path_1.join)(this.context.root, lockfileName)); | ||
} | ||
getConfiguredPackageManager() { | ||
const getPackageManager = (source) => { | ||
if (source && (0, core_1.isJsonObject)(source)) { | ||
const value = source['packageManager']; | ||
if (typeof value === 'string') { | ||
return value; | ||
getConfiguredPackageManager() { | ||
const getPackageManager = (source) => { | ||
if (source && (0, core_1.isJsonObject)(source)) { | ||
const value = source['packageManager']; | ||
if (typeof value === 'string') { | ||
return value; | ||
} | ||
} | ||
return undefined; | ||
}; | ||
let result; | ||
const { workspace: localWorkspace, globalConfiguration: globalWorkspace } = this.context; | ||
if (localWorkspace) { | ||
const project = (0, config_1.getProjectByCwd)(localWorkspace); | ||
if (project) { | ||
result = getPackageManager(localWorkspace.projects.get(project)?.extensions['cli']); | ||
} | ||
result ??= getPackageManager(localWorkspace.extensions['cli']); | ||
} | ||
return undefined; | ||
}; | ||
let result; | ||
const { workspace: localWorkspace, globalConfiguration: globalWorkspace } = this.context; | ||
if (localWorkspace) { | ||
const project = (0, config_1.getProjectByCwd)(localWorkspace); | ||
if (project) { | ||
result = getPackageManager(localWorkspace.projects.get(project)?.extensions['cli']); | ||
if (!result) { | ||
result = getPackageManager(globalWorkspace.extensions['cli']); | ||
} | ||
result ??= getPackageManager(localWorkspace.extensions['cli']); | ||
return result; | ||
} | ||
if (!result) { | ||
result = getPackageManager(globalWorkspace.extensions['cli']); | ||
} | ||
return result; | ||
} | ||
} | ||
}; | ||
})(); | ||
exports.PackageManagerUtils = PackageManagerUtils; | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", [String]), | ||
__metadata("design:returntype", Object) | ||
], PackageManagerUtils.prototype, "getVersion", null); | ||
__decorate([ | ||
memoize_1.memoize, | ||
__metadata("design:type", Function), | ||
__metadata("design:paramtypes", []), | ||
__metadata("design:returntype", String) | ||
], PackageManagerUtils.prototype, "getName", null); |
@@ -8,2 +8,2 @@ /** | ||
*/ | ||
export declare function isTTY(): boolean; | ||
export declare function isTTY(stream?: NodeJS.WriteStream): boolean; |
@@ -15,3 +15,3 @@ "use strict"; | ||
} | ||
function isTTY() { | ||
function isTTY(stream = process.stdout) { | ||
// If we force TTY, we always return true. | ||
@@ -22,3 +22,3 @@ const force = process.env['NG_FORCE_TTY']; | ||
} | ||
return !!process.stdout.isTTY && !_isTruthy(process.env['CI']); | ||
return !!stream.isTTY && !_isTruthy(process.env['CI']); | ||
} |
@@ -28,3 +28,3 @@ "use strict"; | ||
// TODO(bazel): Convert this to use build-time version stamping after flipping the build script to use bazel | ||
// export const VERSION = new Version('18.1.0-next.3'); | ||
// export const VERSION = new Version('18.1.0-rc.0'); | ||
exports.VERSION = new Version(JSON.parse((0, fs_1.readFileSync)((0, path_1.resolve)(__dirname, '../../package.json'), 'utf-8')).version); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
633144
15451
+ Added@angular-devkit/architect@0.1801.0-rc.0(transitive)
+ Added@angular-devkit/core@18.1.0-rc.0(transitive)
+ Added@angular-devkit/schematics@18.1.0-rc.0(transitive)
+ Added@listr2/prompt-adapter-inquirer@2.0.13(transitive)
+ Added@schematics/angular@18.1.0-rc.0(transitive)
+ Addedjsonc-parser@3.3.1(transitive)
+ Addedlistr2@8.2.3(transitive)
- Removed@angular-devkit/architect@0.1801.0-next.3(transitive)
- Removed@angular-devkit/core@18.1.0-next.3(transitive)
- Removed@angular-devkit/schematics@18.1.0-next.3(transitive)
- Removed@listr2/prompt-adapter-inquirer@2.0.12(transitive)
- Removed@schematics/angular@18.1.0-next.3(transitive)
- Removedjsonc-parser@3.2.1(transitive)
- Removedlistr2@8.2.2(transitive)
Updatedjsonc-parser@3.3.1
Updatedlistr2@8.2.3