diff --git a/packages/angular/cli/src/command-builder/command-module.ts b/packages/angular/cli/src/command-builder/command-module.ts index ae0eb82f0cb5..35e0d4f8201d 100644 --- a/packages/angular/cli/src/command-builder/command-module.ts +++ b/packages/angular/cli/src/command-builder/command-module.ts @@ -7,8 +7,6 @@ */ import { schema } from '@angular-devkit/core'; -import { readFileSync } from 'node:fs'; -import { join, posix, relative } from 'node:path'; import type { ArgumentsCamelCase, Argv, CommandModule as YargsCommandModule } from 'yargs'; import { Parser as yargsParser } from 'yargs/helpers'; import { getAnalyticsUserId } from '../analytics/analytics'; @@ -20,6 +18,7 @@ import { AngularWorkspace } from '../utilities/config'; import { memoize } from '../utilities/memoize'; import { CommandContext, CommandScope, Options, OtherOptions } from './definitions'; import { Option, addSchemaOptionsToCommand } from './utilities/json-schema'; +import '../utilities/markdown-loader'; export { CommandScope }; export type { CommandContext, Options, OtherOptions }; @@ -31,8 +30,11 @@ export interface CommandModuleImplementation extends Omit< /** Scope in which the command can be executed in. */ scope: CommandScope; - /** Path used to load the long description for the command in JSON help text. */ - longDescriptionPath?: string; + /** Long description for the command in JSON help text. */ + longDescription?: string; + + /** Relative path to the long description file for the command in JSON help text. */ + longDescriptionRelativePath?: string; /** Object declaring the options the command accepts, or a function accepting and returning a yargs instance. */ builder(argv: Argv): Promise> | Argv; @@ -50,7 +52,8 @@ export interface FullDescribe { export abstract class CommandModule implements CommandModuleImplementation { abstract readonly command: string; abstract readonly describe: string | false; - abstract readonly longDescriptionPath?: string; + readonly longDescription?: string; + readonly longDescriptionRelativePath?: string; protected readonly shouldReportAnalytics: boolean = true; readonly scope: CommandScope = CommandScope.Both; @@ -68,23 +71,22 @@ export abstract class CommandModule implements CommandModuleI * `false` will result in a hidden command. */ public get fullDescribe(): FullDescribe | false { - return this.describe === false - ? false - : { - describe: this.describe, - ...(this.longDescriptionPath - ? { - longDescriptionRelativePath: relative( - join(__dirname, '../../../../'), - this.longDescriptionPath, - ).replace(/\\/g, posix.sep), - longDescription: readFileSync(this.longDescriptionPath, 'utf8').replace( - /\r\n/g, - '\n', - ), - } - : {}), - }; + if (this.describe === false) { + return false; + } + + const description: FullDescribe = { + describe: this.describe, + }; + + if (this.longDescription) { + description.longDescription = this.longDescription.replace(/\r\n/g, '\n'); + description.longDescriptionRelativePath = + this.longDescriptionRelativePath ?? + `@angular/cli/src/commands/${this.commandName}/long-description.md`; + } + + return description; } protected get commandName(): string { diff --git a/packages/angular/cli/src/commands/add/cli.ts b/packages/angular/cli/src/commands/add/cli.ts index bc95f33ff8e7..fb352f70edfd 100644 --- a/packages/angular/cli/src/commands/add/cli.ts +++ b/packages/angular/cli/src/commands/add/cli.ts @@ -29,6 +29,9 @@ import { NgAddSaveDependency, PackageManifest, PackageMetadata } from '../../pac import { assertIsError } from '../../utilities/error'; import { isTTY } from '../../utilities/tty'; import { VERSION } from '../../utilities/version'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; class CommandError extends Error {} @@ -100,7 +103,7 @@ export default class AddCommandModule { command = 'add '; describe = 'Adds support for an external library to your project.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; protected override allowPrivateSchematics = true; private readonly schematicName = 'ng-add'; private rootRequire = createRequire(this.context.root + '/'); diff --git a/packages/angular/cli/src/commands/analytics/cli.ts b/packages/angular/cli/src/commands/analytics/cli.ts index da56a2a00460..9639cbab50e6 100644 --- a/packages/angular/cli/src/commands/analytics/cli.ts +++ b/packages/angular/cli/src/commands/analytics/cli.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { Argv } from 'yargs'; import { CommandModule, @@ -18,6 +17,9 @@ import { demandCommandFailureMessage, } from '../../command-builder/utilities/command'; import { AnalyticsInfoCommandModule } from './info/cli'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; import { AnalyticsDisableModule, AnalyticsEnableModule, @@ -30,7 +32,7 @@ export default class AnalyticsCommandModule { command = 'analytics'; describe = 'Configures the gathering of Angular CLI usage metrics.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; builder(localYargs: Argv): Argv { const subcommands = [ diff --git a/packages/angular/cli/src/commands/analytics/info/cli.ts b/packages/angular/cli/src/commands/analytics/info/cli.ts index e4434d35baee..93b34fd06716 100644 --- a/packages/angular/cli/src/commands/analytics/info/cli.ts +++ b/packages/angular/cli/src/commands/analytics/info/cli.ts @@ -20,7 +20,6 @@ export class AnalyticsInfoCommandModule { command = 'info'; describe = 'Prints analytics gathering and reporting configuration in the console.'; - longDescriptionPath?: string; builder(localYargs: Argv): Argv { return localYargs.strict(); diff --git a/packages/angular/cli/src/commands/analytics/settings/cli.ts b/packages/angular/cli/src/commands/analytics/settings/cli.ts index 16f07b353d1a..24105de2b060 100644 --- a/packages/angular/cli/src/commands/analytics/settings/cli.ts +++ b/packages/angular/cli/src/commands/analytics/settings/cli.ts @@ -26,8 +26,6 @@ abstract class AnalyticsSettingModule extends CommandModule implements CommandModuleImplementation { - longDescriptionPath?: string; - builder(localYargs: Argv): Argv { return localYargs .option('global', { diff --git a/packages/angular/cli/src/commands/build/cli.ts b/packages/angular/cli/src/commands/build/cli.ts index 365420ca3734..031e31b5140f 100644 --- a/packages/angular/cli/src/commands/build/cli.ts +++ b/packages/angular/cli/src/commands/build/cli.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; import { RootCommands } from '../command-config'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export default class BuildCommandModule extends ArchitectCommandModule @@ -20,5 +22,5 @@ export default class BuildCommandModule aliases = RootCommands['build'].aliases; describe = 'Compiles an Angular application or library into an output directory named dist/ at the given output path.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; } diff --git a/packages/angular/cli/src/commands/cache/clean/cli.ts b/packages/angular/cli/src/commands/cache/clean/cli.ts index a115b686b7e0..492699271b54 100644 --- a/packages/angular/cli/src/commands/cache/clean/cli.ts +++ b/packages/angular/cli/src/commands/cache/clean/cli.ts @@ -18,7 +18,6 @@ import { getCacheConfig } from '../utilities'; export class CacheCleanModule extends CommandModule implements CommandModuleImplementation { command = 'clean'; describe = 'Deletes persistent disk cache from disk.'; - longDescriptionPath: string | undefined; override scope = CommandScope.In; builder(localYargs: Argv): Argv { diff --git a/packages/angular/cli/src/commands/cache/cli.ts b/packages/angular/cli/src/commands/cache/cli.ts index dad144b034b3..25140041ae0e 100644 --- a/packages/angular/cli/src/commands/cache/cli.ts +++ b/packages/angular/cli/src/commands/cache/cli.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { Argv } from 'yargs'; import { CommandModule, @@ -20,6 +19,9 @@ import { } from '../../command-builder/utilities/command'; import { CacheCleanModule } from './clean/cli'; import { CacheInfoCommandModule } from './info/cli'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; import { CacheDisableModule, CacheEnableModule } from './settings/cli'; export default class CacheCommandModule @@ -28,7 +30,7 @@ export default class CacheCommandModule { command = 'cache'; describe = 'Configure persistent disk cache and retrieve cache statistics.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; override scope = CommandScope.In; builder(localYargs: Argv): Argv { diff --git a/packages/angular/cli/src/commands/cache/info/cli.ts b/packages/angular/cli/src/commands/cache/info/cli.ts index f4278d52db74..6fd2df0414c7 100644 --- a/packages/angular/cli/src/commands/cache/info/cli.ts +++ b/packages/angular/cli/src/commands/cache/info/cli.ts @@ -21,7 +21,6 @@ import { getCacheConfig } from '../utilities'; export class CacheInfoCommandModule extends CommandModule implements CommandModuleImplementation { command = 'info'; describe = 'Prints persistent disk cache configuration and statistics in the console.'; - longDescriptionPath?: string | undefined; override scope = CommandScope.In; builder(localYargs: Argv): Argv { diff --git a/packages/angular/cli/src/commands/cache/settings/cli.ts b/packages/angular/cli/src/commands/cache/settings/cli.ts index 9a4f654f7ac7..5de2d5496475 100644 --- a/packages/angular/cli/src/commands/cache/settings/cli.ts +++ b/packages/angular/cli/src/commands/cache/settings/cli.ts @@ -18,7 +18,6 @@ export class CacheDisableModule extends CommandModule implements CommandModuleIm command = 'disable'; aliases = 'off'; describe = 'Disables persistent disk cache for all projects in the workspace.'; - longDescriptionPath: string | undefined; override scope = CommandScope.In; builder(localYargs: Argv): Argv { @@ -34,7 +33,6 @@ export class CacheEnableModule extends CommandModule implements CommandModuleImp command = 'enable'; aliases = 'on'; describe = 'Enables disk cache for all projects in the workspace.'; - longDescriptionPath: string | undefined; override scope = CommandScope.In; builder(localYargs: Argv): Argv { diff --git a/packages/angular/cli/src/commands/completion/cli.ts b/packages/angular/cli/src/commands/completion/cli.ts index 3fc9dccdc703..ab81ce5636d8 100644 --- a/packages/angular/cli/src/commands/completion/cli.ts +++ b/packages/angular/cli/src/commands/completion/cli.ts @@ -6,13 +6,15 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { Argv } from 'yargs'; import { CommandModule, CommandModuleImplementation } from '../../command-builder/command-module'; import { addCommandModuleToYargs } from '../../command-builder/utilities/command'; import { colors } from '../../utilities/color'; import { hasGlobalCliInstall, initializeAutocomplete } from '../../utilities/completion'; import { assertIsError } from '../../utilities/error'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export default class CompletionCommandModule extends CommandModule @@ -20,7 +22,7 @@ export default class CompletionCommandModule { command = 'completion'; describe = 'Set up Angular CLI autocompletion for your terminal.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; builder(localYargs: Argv): Argv { addCommandModuleToYargs(CompletionScriptCommandModule, this.context); @@ -64,7 +66,6 @@ Appended \`source <(ng completion script)\` to \`${rcFile}\`. Restart your termi class CompletionScriptCommandModule extends CommandModule implements CommandModuleImplementation { command = 'script'; describe = 'Generate a bash and zsh real-time type-ahead autocompletion script.'; - longDescriptionPath = undefined; builder(localYargs: Argv): Argv { return localYargs; diff --git a/packages/angular/cli/src/commands/config/cli.ts b/packages/angular/cli/src/commands/config/cli.ts index 06b253b9a42d..f339fd9bb1ba 100644 --- a/packages/angular/cli/src/commands/config/cli.ts +++ b/packages/angular/cli/src/commands/config/cli.ts @@ -8,7 +8,6 @@ import { JsonValue } from '@angular-devkit/core'; import { randomUUID } from 'node:crypto'; -import { join } from 'node:path'; import { Argv } from 'yargs'; import { CommandModule, @@ -18,6 +17,9 @@ import { } from '../../command-builder/command-module'; import { getWorkspaceRaw, validateWorkspace } from '../../utilities/config'; import { JSONFile, parseJson } from '../../utilities/json-file'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; interface ConfigCommandArgs { 'json-path'?: string; @@ -32,7 +34,7 @@ export default class ConfigCommandModule command = 'config [json-path] [value]'; describe = 'Retrieves or sets Angular configuration values in the angular.json file for the workspace.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; builder(localYargs: Argv): Argv { return localYargs diff --git a/packages/angular/cli/src/commands/deploy/cli.ts b/packages/angular/cli/src/commands/deploy/cli.ts index 947dc90af2d4..28317cff1ee1 100644 --- a/packages/angular/cli/src/commands/deploy/cli.ts +++ b/packages/angular/cli/src/commands/deploy/cli.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { MissingTargetChoice } from '../../command-builder/architect-base-command-module'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export default class DeployCommandModule extends ArchitectCommandModule @@ -37,7 +39,7 @@ export default class DeployCommandModule multiTarget = false; command = 'deploy [project]'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; describe = 'Invokes the deploy builder for a specified project or for the default project in the workspace.'; } diff --git a/packages/angular/cli/src/commands/e2e/cli.ts b/packages/angular/cli/src/commands/e2e/cli.ts index 85d9aab173a0..9d63a8d96fb4 100644 --- a/packages/angular/cli/src/commands/e2e/cli.ts +++ b/packages/angular/cli/src/commands/e2e/cli.ts @@ -42,5 +42,4 @@ export default class E2eCommandModule command = 'e2e [project]'; aliases = RootCommands['e2e'].aliases; describe = 'Builds and serves an Angular application, then runs end-to-end tests.'; - longDescriptionPath?: string; } diff --git a/packages/angular/cli/src/commands/extract-i18n/cli.ts b/packages/angular/cli/src/commands/extract-i18n/cli.ts index 4f3dea2d8e7e..09b3df343403 100644 --- a/packages/angular/cli/src/commands/extract-i18n/cli.ts +++ b/packages/angular/cli/src/commands/extract-i18n/cli.ts @@ -19,7 +19,6 @@ export default class ExtractI18nCommandModule multiTarget = false; command = 'extract-i18n [project]'; describe = 'Extracts i18n messages from source code.'; - longDescriptionPath?: string | undefined; override async findDefaultBuilderName( project: workspaces.ProjectDefinition, diff --git a/packages/angular/cli/src/commands/generate/cli.ts b/packages/angular/cli/src/commands/generate/cli.ts index 4be29c3eaea0..8f605e03a18b 100644 --- a/packages/angular/cli/src/commands/generate/cli.ts +++ b/packages/angular/cli/src/commands/generate/cli.ts @@ -38,7 +38,6 @@ export default class GenerateCommandModule command = 'generate'; aliases = RootCommands['generate'].aliases; describe = 'Generates and/or modifies files based on a schematic.'; - longDescriptionPath?: string | undefined; override async builder(argv: Argv): Promise> { let localYargs = (await super.builder(argv)).command({ diff --git a/packages/angular/cli/src/commands/lint/cli.ts b/packages/angular/cli/src/commands/lint/cli.ts index 9510dd7afe53..3fdd38fc169c 100644 --- a/packages/angular/cli/src/commands/lint/cli.ts +++ b/packages/angular/cli/src/commands/lint/cli.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { MissingTargetChoice } from '../../command-builder/architect-base-command-module'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export default class LintCommandModule extends ArchitectCommandModule @@ -24,6 +26,6 @@ export default class LintCommandModule multiTarget = true; command = 'lint [project]'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; describe = 'Runs linting tools on Angular application code in a given project folder.'; } diff --git a/packages/angular/cli/src/commands/make-this-awesome/cli.ts b/packages/angular/cli/src/commands/make-this-awesome/cli.ts index 6a17c5614b94..8e36447f1f3a 100644 --- a/packages/angular/cli/src/commands/make-this-awesome/cli.ts +++ b/packages/angular/cli/src/commands/make-this-awesome/cli.ts @@ -17,7 +17,6 @@ export default class AwesomeCommandModule command = 'make-this-awesome'; describe = false as const; deprecated = false; - longDescriptionPath?: string | undefined; builder(localYargs: Argv): Argv { return localYargs; diff --git a/packages/angular/cli/src/commands/mcp/cli.ts b/packages/angular/cli/src/commands/mcp/cli.ts index a379022e8f5e..cbc94499a9ca 100644 --- a/packages/angular/cli/src/commands/mcp/cli.ts +++ b/packages/angular/cli/src/commands/mcp/cli.ts @@ -35,7 +35,6 @@ For more information and documentation, visit: https://angular.dev/ai/mcp export default class McpCommandModule extends CommandModule implements CommandModuleImplementation { command = 'mcp'; describe = false as const; - longDescriptionPath = undefined; builder(localYargs: Argv): Argv { return localYargs diff --git a/packages/angular/cli/src/commands/new/cli.ts b/packages/angular/cli/src/commands/new/cli.ts index 6e6545e66421..c47f3c63153b 100644 --- a/packages/angular/cli/src/commands/new/cli.ts +++ b/packages/angular/cli/src/commands/new/cli.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { Argv } from 'yargs'; import { CommandModuleImplementation, @@ -21,6 +20,9 @@ import { } from '../../command-builder/schematics-command-module'; import { VERSION } from '../../utilities/version'; import { RootCommands } from '../command-config'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; interface NewCommandArgs extends SchematicsCommandArgs { collection?: string; @@ -37,7 +39,7 @@ export default class NewCommandModule command = 'new [name]'; aliases = RootCommands['new'].aliases; describe = 'Creates a new Angular workspace.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; override async builder(argv: Argv): Promise> { const localYargs = (await super.builder(argv)).option('collection', { diff --git a/packages/angular/cli/src/commands/run/cli.ts b/packages/angular/cli/src/commands/run/cli.ts index aa12cd0158f7..774f811aa2a5 100644 --- a/packages/angular/cli/src/commands/run/cli.ts +++ b/packages/angular/cli/src/commands/run/cli.ts @@ -7,7 +7,6 @@ */ import { Target } from '@angular-devkit/architect'; -import { join } from 'node:path'; import { Argv } from 'yargs'; import { ArchitectBaseCommandModule } from '../../command-builder/architect-base-command-module'; import { @@ -17,6 +16,9 @@ import { Options, OtherOptions, } from '../../command-builder/command-module'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export interface RunCommandArgs { target: string; @@ -31,7 +33,7 @@ export default class RunCommandModule command = 'run '; describe = 'Runs an Architect target with an optional custom builder configuration defined in your project.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; async builder(argv: Argv): Promise> { const { jsonHelp, getYargsCompletions, help } = this.context.args.options; diff --git a/packages/angular/cli/src/commands/serve/cli.ts b/packages/angular/cli/src/commands/serve/cli.ts index 3b38fa122acd..6448c48b9484 100644 --- a/packages/angular/cli/src/commands/serve/cli.ts +++ b/packages/angular/cli/src/commands/serve/cli.ts @@ -18,5 +18,4 @@ export default class ServeCommandModule command = 'serve [project]'; aliases = RootCommands['serve'].aliases; describe = 'Builds and serves your application, rebuilding on file changes.'; - longDescriptionPath?: string | undefined; } diff --git a/packages/angular/cli/src/commands/test/cli.ts b/packages/angular/cli/src/commands/test/cli.ts index 600e9f41f517..f9dcaaf92c8c 100644 --- a/packages/angular/cli/src/commands/test/cli.ts +++ b/packages/angular/cli/src/commands/test/cli.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.dev/license */ -import { join } from 'node:path'; import { ArchitectCommandModule } from '../../command-builder/architect-command-module'; import { CommandModuleImplementation } from '../../command-builder/command-module'; import { RootCommands } from '../command-config'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; export default class TestCommandModule extends ArchitectCommandModule @@ -19,5 +21,5 @@ export default class TestCommandModule command = 'test [project]'; aliases = RootCommands['test'].aliases; describe = 'Runs unit tests in a project.'; - longDescriptionPath = join(__dirname, 'long-description.md'); + override longDescription = longDescription; } diff --git a/packages/angular/cli/src/commands/update/cli.ts b/packages/angular/cli/src/commands/update/cli.ts index 005df998b501..6418bfc13ce4 100644 --- a/packages/angular/cli/src/commands/update/cli.ts +++ b/packages/angular/cli/src/commands/update/cli.ts @@ -24,6 +24,9 @@ import type { InstalledPackage, PackageManager, PackageManifest } from '../../pa import { colors } from '../../utilities/color'; import { disableVersionCheck } from '../../utilities/environment-options'; import { assertIsError } from '../../utilities/error'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore strict-deps: Markdown files are asset dependencies bundled/loaded at runtime +import longDescription from './long-description.md'; import { UpdatePlan, applyUpdatePlan, @@ -63,7 +66,7 @@ export default class UpdateCommandModule extends CommandModule { return localYargs diff --git a/packages/angular/cli/src/commands/version/cli.ts b/packages/angular/cli/src/commands/version/cli.ts index 205f0bc7e55e..1a79b8b76eef 100644 --- a/packages/angular/cli/src/commands/version/cli.ts +++ b/packages/angular/cli/src/commands/version/cli.ts @@ -37,7 +37,6 @@ export default class VersionCommandModule command = 'version'; aliases = RootCommands['version'].aliases; describe = 'Outputs Angular CLI version.'; - longDescriptionPath?: string | undefined; /** * Builds the command-line options for the `ng version` command. diff --git a/packages/angular/cli/src/typings.d.ts b/packages/angular/cli/src/typings.d.ts new file mode 100644 index 000000000000..12e7de03c204 --- /dev/null +++ b/packages/angular/cli/src/typings.d.ts @@ -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.dev/license + */ + +declare module '*/long-description.md' { + const content: string; + export default content; +} diff --git a/packages/angular/cli/src/utilities/markdown-loader.ts b/packages/angular/cli/src/utilities/markdown-loader.ts new file mode 100644 index 000000000000..3a70a5eaae1c --- /dev/null +++ b/packages/angular/cli/src/utilities/markdown-loader.ts @@ -0,0 +1,35 @@ +/** + * @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.dev/license + */ + +import { readFileSync } from 'node:fs'; + +const LONG_DESCRIPTION_REGEXP = /[/\\]long-description\.md$/; + +function isCommandLongDescription(filePath: string | undefined): boolean { + return !!filePath && LONG_DESCRIPTION_REGEXP.test(filePath); +} + +// Register markdown extension hook for CommonJS execution +if (typeof require !== 'undefined' && require.extensions) { + const originalMdExtension = require.extensions['.md']; + require.extensions['.md'] = (module, filename) => { + if (isCommandLongDescription(filename)) { + module.exports = readFileSync(filename, 'utf8'); + + return; + } + + if (originalMdExtension) { + originalMdExtension(module, filename); + } else { + const err = new Error(`Cannot find module '${filename}'`); + (err as NodeJS.ErrnoException).code = 'MODULE_NOT_FOUND'; + throw err; + } + }; +}