@angular/cli 20.2.0-next.3 → 20.2.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/lib/code-examples.db +0 -0
  2. package/lib/config/schema.json +18 -2
  3. package/lib/config/workspace-schema.d.ts +14 -0
  4. package/lib/config/workspace-schema.js +11 -1
  5. package/package.json +16 -16
  6. package/src/commands/mcp/cli.d.ts +5 -1
  7. package/src/commands/mcp/cli.js +24 -3
  8. package/src/commands/mcp/mcp-server.d.ts +13 -1
  9. package/src/commands/mcp/mcp-server.js +47 -26
  10. package/src/commands/mcp/{instructions → resources}/best-practices.md +0 -5
  11. package/src/commands/mcp/resources/instructions.d.ts +9 -0
  12. package/src/commands/mcp/resources/instructions.js +28 -0
  13. package/src/commands/mcp/tools/best-practices.d.ts +1 -2
  14. package/src/commands/mcp/tools/best-practices.js +29 -28
  15. package/src/commands/mcp/tools/doc-search.d.ts +5 -9
  16. package/src/commands/mcp/tools/doc-search.js +34 -37
  17. package/src/commands/mcp/tools/examples.d.ts +4 -11
  18. package/src/commands/mcp/tools/examples.js +44 -37
  19. package/src/commands/mcp/tools/modernize.d.ts +31 -0
  20. package/src/commands/mcp/tools/modernize.js +135 -0
  21. package/src/commands/mcp/tools/projects.d.ts +22 -5
  22. package/src/commands/mcp/tools/projects.js +37 -35
  23. package/src/commands/mcp/tools/tool-registry.d.ts +35 -0
  24. package/src/commands/mcp/tools/tool-registry.js +33 -0
  25. package/src/utilities/config.js +3 -0
  26. package/src/utilities/eol.d.ts +12 -0
  27. package/src/utilities/eol.js +12 -0
  28. package/src/utilities/error.d.ts +8 -0
  29. package/src/utilities/error.js +24 -4
  30. package/src/utilities/json-file.d.ts +15 -2
  31. package/src/utilities/json-file.js +100 -27
  32. package/src/utilities/version.js +1 -1
@@ -43,40 +43,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43
43
  return (mod && mod.__esModule) ? mod : { "default": mod };
44
44
  };
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
- exports.registerFindExampleTool = registerFindExampleTool;
46
+ exports.FIND_EXAMPLE_TOOL = void 0;
47
47
  exports.escapeSearchQuery = escapeSearchQuery;
48
48
  const promises_1 = require("node:fs/promises");
49
49
  const node_path_1 = __importDefault(require("node:path"));
50
50
  const zod_1 = require("zod");
51
- /**
52
- * Registers the `find_examples` tool with the MCP server.
53
- *
54
- * This tool allows users to search for best-practice Angular code examples
55
- * from a local SQLite database.
56
- *
57
- * @param server The MCP server instance.
58
- * @param exampleDatabasePath The path to the SQLite database file containing the examples.
59
- */
60
- async function registerFindExampleTool(server, exampleDatabasePath) {
61
- let db;
62
- let queryStatement;
63
- // Runtime directory of examples uses an in-memory database
64
- if (process.env['NG_MCP_EXAMPLES_DIR']) {
65
- db = await setupRuntimeExamples(process.env['NG_MCP_EXAMPLES_DIR']);
66
- }
67
- suppressSqliteWarning();
68
- server.registerTool('find_examples', {
69
- title: 'Find Angular Code Examples',
70
- description: 'Before writing or modifying any Angular code including templates, ' +
71
- '**ALWAYS** use this tool to find current best-practice examples. ' +
72
- 'This is critical for ensuring code quality and adherence to modern Angular standards. ' +
73
- 'This tool searches a curated database of approved Angular code examples and returns the most relevant results for your query. ' +
74
- 'Example Use Cases: ' +
75
- "1) Creating new components, directives, or services (e.g., query: 'standalone component' or 'signal input'). " +
76
- "2) Implementing core features (e.g., query: 'lazy load route', 'httpinterceptor', or 'route guard'). " +
77
- "3) Refactoring existing code to use modern patterns (e.g., query: 'ngfor trackby' or 'form validation').",
78
- inputSchema: {
79
- query: zod_1.z.string().describe(`Performs a full-text search using FTS5 syntax. The query should target relevant Angular concepts.
51
+ const tool_registry_1 = require("./tool-registry");
52
+ const findExampleInputSchema = zod_1.z.object({
53
+ query: zod_1.z.string().describe(`Performs a full-text search using FTS5 syntax. The query should target relevant Angular concepts.
80
54
 
81
55
  Key Syntax Features (see https://www.sqlite.org/fts5.html for full documentation):
82
56
  - AND (default): Space-separated terms are combined with AND.
@@ -98,13 +72,46 @@ Examples of queries:
98
72
  - Find signal inputs: 'signal input'
99
73
  - Find lazy loading a route: 'lazy load route'
100
74
  - Find forms with validation: 'form AND (validation OR validator)'`),
101
- },
102
- annotations: {
103
- readOnlyHint: true,
104
- openWorldHint: false,
105
- },
106
- }, async ({ query }) => {
75
+ });
76
+ exports.FIND_EXAMPLE_TOOL = (0, tool_registry_1.declareTool)({
77
+ name: 'find_examples',
78
+ title: 'Find Angular Code Examples',
79
+ description: 'Before writing or modifying any Angular code including templates, ' +
80
+ '**ALWAYS** use this tool to find current best-practice examples. ' +
81
+ 'This is critical for ensuring code quality and adherence to modern Angular standards. ' +
82
+ 'This tool searches a curated database of approved Angular code examples and returns the most relevant results for your query. ' +
83
+ 'Example Use Cases: ' +
84
+ "1) Creating new components, directives, or services (e.g., query: 'standalone component' or 'signal input'). " +
85
+ "2) Implementing core features (e.g., query: 'lazy load route', 'httpinterceptor', or 'route guard'). " +
86
+ "3) Refactoring existing code to use modern patterns (e.g., query: 'ngfor trackby' or 'form validation').",
87
+ inputSchema: findExampleInputSchema.shape,
88
+ isReadOnly: true,
89
+ isLocalOnly: true,
90
+ shouldRegister: ({ logger }) => {
91
+ // sqlite database support requires Node.js 22.16+
92
+ const [nodeMajor, nodeMinor] = process.versions.node.split('.', 2).map(Number);
93
+ if (nodeMajor < 22 || (nodeMajor === 22 && nodeMinor < 16)) {
94
+ logger.warn(`MCP tool 'find_examples' requires Node.js 22.16 (or higher). ` +
95
+ ' Registration of this tool has been skipped.');
96
+ return false;
97
+ }
98
+ return true;
99
+ },
100
+ factory: createFindExampleHandler,
101
+ });
102
+ async function createFindExampleHandler({ exampleDatabasePath }) {
103
+ let db;
104
+ let queryStatement;
105
+ if (process.env['NG_MCP_EXAMPLES_DIR']) {
106
+ db = await setupRuntimeExamples(process.env['NG_MCP_EXAMPLES_DIR']);
107
+ }
108
+ suppressSqliteWarning();
109
+ return async ({ query }) => {
107
110
  if (!db) {
111
+ if (!exampleDatabasePath) {
112
+ // This should be prevented by the registration logic in mcp-server.ts
113
+ throw new Error('Example database path is not available.');
114
+ }
108
115
  const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
109
116
  db = new DatabaseSync(exampleDatabasePath, { readOnly: true });
110
117
  }
@@ -120,7 +127,7 @@ Examples of queries:
120
127
  return {
121
128
  content,
122
129
  };
123
- });
130
+ };
124
131
  }
125
132
  /**
126
133
  * Escapes a search query for FTS5 by tokenizing and quoting terms.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import { z } from 'zod';
9
+ declare const modernizeInputSchema: z.ZodObject<{
10
+ transformations: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ transformations?: string[] | undefined;
13
+ }, {
14
+ transformations?: string[] | undefined;
15
+ }>;
16
+ export type ModernizeInput = z.infer<typeof modernizeInputSchema>;
17
+ export declare function runModernization(input: ModernizeInput): Promise<{
18
+ content: {
19
+ type: "text";
20
+ text: string;
21
+ }[];
22
+ structuredContent: {
23
+ instructions: string[];
24
+ };
25
+ }>;
26
+ export declare const MODERNIZE_TOOL: import("./tool-registry").McpToolDeclaration<{
27
+ transformations: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
28
+ }, {
29
+ instructions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
30
+ }>;
31
+ export {};
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.MODERNIZE_TOOL = void 0;
11
+ exports.runModernization = runModernization;
12
+ const zod_1 = require("zod");
13
+ const tool_registry_1 = require("./tool-registry");
14
+ const TRANSFORMATIONS = [
15
+ {
16
+ name: 'control-flow-migration',
17
+ description: 'Migrates from `*ngIf`, `*ngFor`, and `*ngSwitch` to the new `@if`, `@for`, and `@switch` block syntax in templates.',
18
+ documentationUrl: 'https://angular.dev/reference/migrations/control-flow',
19
+ },
20
+ {
21
+ name: 'self-closing-tags-migration',
22
+ description: 'Converts tags for elements with no content to be self-closing (e.g., `<app-foo></app-foo>` becomes `<app-foo />`).',
23
+ documentationUrl: 'https://angular.dev/reference/migrations/self-closing-tags',
24
+ },
25
+ {
26
+ name: 'test-bed-get',
27
+ description: 'Updates `TestBed.get` to the preferred and type-safe `TestBed.inject` in TypeScript test files.',
28
+ documentationUrl: 'https://angular.dev/guide/testing/dependency-injection',
29
+ },
30
+ {
31
+ name: 'inject',
32
+ description: 'Converts usages of constructor-based injection to the inject() function.',
33
+ documentationUrl: 'https://angular.dev/reference/migrations/inject-function',
34
+ },
35
+ {
36
+ name: 'output-migration',
37
+ description: 'Converts `@Output` declarations to the new functional `output()` syntax.',
38
+ documentationUrl: 'https://angular.dev/reference/migrations/outputs',
39
+ },
40
+ {
41
+ name: 'signal-input-migration',
42
+ description: 'Migrates `@Input` declarations to the new signal-based `input()` syntax.',
43
+ documentationUrl: 'https://angular.dev/reference/migrations/signal-inputs',
44
+ },
45
+ {
46
+ name: 'signal-queries-migration',
47
+ description: 'Migrates `@ViewChild` and `@ContentChild` queries to their signal-based `viewChild` and `contentChild` versions.',
48
+ documentationUrl: 'https://angular.dev/reference/migrations/signal-queries',
49
+ },
50
+ {
51
+ name: 'standalone',
52
+ description: 'Converts the application to use standalone components, directives, and pipes. This is a ' +
53
+ 'three-step process. After each step, you should verify that your application builds and ' +
54
+ 'runs correctly.',
55
+ instructions: 'This migration requires running a cli schematic multiple times. Run the commands in the ' +
56
+ 'order listed below, verifying that your code builds and runs between each step:\n\n' +
57
+ '1. Run `ng g @angular/core:standalone` and select "Convert all components, directives and pipes to standalone"\n' +
58
+ '2. Run `ng g @angular/core:standalone` and select "Remove unnecessary NgModule classes"\n' +
59
+ '3. Run `ng g @angular/core:standalone` and select "Bootstrap the project using standalone APIs"',
60
+ documentationUrl: 'https://angular.dev/reference/migrations/standalone',
61
+ },
62
+ {
63
+ name: 'zoneless',
64
+ description: 'Migrates the application to be zoneless.',
65
+ documentationUrl: 'https://angular.dev/guide/zoneless',
66
+ },
67
+ ];
68
+ const modernizeInputSchema = zod_1.z.object({
69
+ // Casting to [string, ...string[]] since the enum definition requires a nonempty array.
70
+ transformations: zod_1.z
71
+ .array(zod_1.z.enum(TRANSFORMATIONS.map((t) => t.name)))
72
+ .optional(),
73
+ });
74
+ function generateInstructions(transformationNames) {
75
+ if (transformationNames.length === 0) {
76
+ return [
77
+ 'See https://angular.dev/best-practices for Angular best practices. ' +
78
+ 'You can call this tool if you have specific transformation you want to run.',
79
+ ];
80
+ }
81
+ const instructions = [];
82
+ const transformationsToRun = TRANSFORMATIONS.filter((t) => transformationNames?.includes(t.name));
83
+ for (const transformation of transformationsToRun) {
84
+ let transformationInstructions = '';
85
+ if (transformation.instructions) {
86
+ transformationInstructions = transformation.instructions;
87
+ }
88
+ else {
89
+ // If no instructions are included, default to running a cli schematic with the transformation name.
90
+ const command = `ng generate @angular/core:${transformation.name}`;
91
+ transformationInstructions = `To run the ${transformation.name} migration, execute the following command: \`${command}\`.`;
92
+ }
93
+ if (transformation.documentationUrl) {
94
+ transformationInstructions += `\nFor more information, see ${transformation.documentationUrl}.`;
95
+ }
96
+ instructions.push(transformationInstructions);
97
+ }
98
+ return instructions;
99
+ }
100
+ async function runModernization(input) {
101
+ const structuredContent = { instructions: generateInstructions(input.transformations ?? []) };
102
+ return {
103
+ content: [{ type: 'text', text: JSON.stringify(structuredContent) }],
104
+ structuredContent,
105
+ };
106
+ }
107
+ exports.MODERNIZE_TOOL = (0, tool_registry_1.declareTool)({
108
+ name: 'modernize',
109
+ title: 'Modernize Angular Code',
110
+ description: '<Purpose>\n' +
111
+ 'This tool modernizes Angular code by applying the latest best practices and syntax improvements, ' +
112
+ 'ensuring it is idiomatic, readable, and maintainable.\n\n' +
113
+ '</Purpose>\n' +
114
+ '<Use Cases>\n' +
115
+ '* After generating new code: Run this tool immediately after creating new Angular components, directives, ' +
116
+ 'or services to ensure they adhere to modern standards.\n' +
117
+ '* On existing code: Apply to existing TypeScript files (.ts) and Angular templates (.html) to update ' +
118
+ 'them with the latest features, such as the new built-in control flow syntax.\n\n' +
119
+ '* When the user asks for a specific transformation: When the transformation list is populated, ' +
120
+ 'these specific ones will be ran on the inputs.\n' +
121
+ '</Use Cases>\n' +
122
+ '<Transformations>\n' +
123
+ TRANSFORMATIONS.map((t) => `* ${t.name}: ${t.description}`).join('\n') +
124
+ '\n</Transformations>\n',
125
+ inputSchema: modernizeInputSchema.shape,
126
+ outputSchema: {
127
+ instructions: zod_1.z
128
+ .array(zod_1.z.string())
129
+ .optional()
130
+ .describe('A list of instructions on how to run the migrations.'),
131
+ },
132
+ isLocalOnly: true,
133
+ isReadOnly: true,
134
+ factory: () => (input) => runModernization(input),
135
+ });
@@ -5,8 +5,25 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
9
- import type { AngularWorkspace } from '../../../utilities/config';
10
- export declare function registerListProjectsTool(server: McpServer, context: {
11
- workspace?: AngularWorkspace;
12
- }): void;
8
+ import z from 'zod';
9
+ export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclaration<z.ZodRawShape, {
10
+ projects: z.ZodArray<z.ZodObject<{
11
+ name: z.ZodString;
12
+ type: z.ZodOptional<z.ZodEnum<["application", "library"]>>;
13
+ root: z.ZodString;
14
+ sourceRoot: z.ZodString;
15
+ selectorPrefix: z.ZodOptional<z.ZodString>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ name: string;
18
+ root: string;
19
+ sourceRoot: string;
20
+ type?: "application" | "library" | undefined;
21
+ selectorPrefix?: string | undefined;
22
+ }, {
23
+ name: string;
24
+ root: string;
25
+ sourceRoot: string;
26
+ type?: "application" | "library" | undefined;
27
+ selectorPrefix?: string | undefined;
28
+ }>, "many">;
29
+ }>;
@@ -10,42 +10,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.registerListProjectsTool = registerListProjectsTool;
13
+ exports.LIST_PROJECTS_TOOL = void 0;
14
14
  const node_path_1 = __importDefault(require("node:path"));
15
15
  const zod_1 = __importDefault(require("zod"));
16
- function registerListProjectsTool(server, context) {
17
- server.registerTool('list_projects', {
18
- title: 'List Angular Projects',
19
- description: 'Lists the names of all applications and libraries defined within an Angular workspace. ' +
20
- 'It reads the `angular.json` configuration file to identify the projects. ',
21
- annotations: {
22
- readOnlyHint: true,
23
- openWorldHint: false,
24
- },
25
- outputSchema: {
26
- projects: zod_1.default.array(zod_1.default.object({
27
- name: zod_1.default
28
- .string()
29
- .describe('The name of the project, as defined in the `angular.json` file.'),
30
- type: zod_1.default
31
- .enum(['application', 'library'])
32
- .optional()
33
- .describe(`The type of the project, either 'application' or 'library'.`),
34
- root: zod_1.default
35
- .string()
36
- .describe('The root directory of the project, relative to the workspace root.'),
37
- sourceRoot: zod_1.default
38
- .string()
39
- .describe(`The root directory of the project's source files, relative to the workspace root.`),
40
- selectorPrefix: zod_1.default
41
- .string()
42
- .optional()
43
- .describe('The prefix to use for component selectors.' +
44
- ` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.`),
45
- })),
46
- },
47
- }, async () => {
48
- const { workspace } = context;
16
+ const tool_registry_1 = require("./tool-registry");
17
+ exports.LIST_PROJECTS_TOOL = (0, tool_registry_1.declareTool)({
18
+ name: 'list_projects',
19
+ title: 'List Angular Projects',
20
+ description: 'Lists the names of all applications and libraries defined within an Angular workspace. ' +
21
+ 'It reads the `angular.json` configuration file to identify the projects. ',
22
+ outputSchema: {
23
+ projects: zod_1.default.array(zod_1.default.object({
24
+ name: zod_1.default
25
+ .string()
26
+ .describe('The name of the project, as defined in the `angular.json` file.'),
27
+ type: zod_1.default
28
+ .enum(['application', 'library'])
29
+ .optional()
30
+ .describe(`The type of the project, either 'application' or 'library'.`),
31
+ root: zod_1.default
32
+ .string()
33
+ .describe('The root directory of the project, relative to the workspace root.'),
34
+ sourceRoot: zod_1.default
35
+ .string()
36
+ .describe(`The root directory of the project's source files, relative to the workspace root.`),
37
+ selectorPrefix: zod_1.default
38
+ .string()
39
+ .optional()
40
+ .describe('The prefix to use for component selectors.' +
41
+ ` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.`),
42
+ })),
43
+ },
44
+ isReadOnly: true,
45
+ isLocalOnly: true,
46
+ shouldRegister: (context) => !!context.workspace,
47
+ factory: createListProjectsHandler,
48
+ });
49
+ function createListProjectsHandler({ workspace }) {
50
+ return async () => {
49
51
  if (!workspace) {
50
52
  return {
51
53
  content: [
@@ -81,5 +83,5 @@ function registerListProjectsTool(server, context) {
81
83
  ],
82
84
  structuredContent: { projects },
83
85
  };
84
- });
86
+ };
85
87
  }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import type { McpServer, ToolCallback } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { ZodRawShape } from 'zod';
10
+ import type { AngularWorkspace } from '../../../utilities/config';
11
+ type ToolConfig = Parameters<McpServer['registerTool']>[1];
12
+ export interface McpToolContext {
13
+ workspace?: AngularWorkspace;
14
+ logger: {
15
+ warn(text: string): void;
16
+ };
17
+ exampleDatabasePath?: string;
18
+ }
19
+ export type McpToolFactory<TInput extends ZodRawShape> = (context: McpToolContext) => ToolCallback<TInput> | Promise<ToolCallback<TInput>>;
20
+ export interface McpToolDeclaration<TInput extends ZodRawShape, TOutput extends ZodRawShape> {
21
+ name: string;
22
+ title?: string;
23
+ description: string;
24
+ annotations?: ToolConfig['annotations'];
25
+ inputSchema?: TInput;
26
+ outputSchema?: TOutput;
27
+ factory: McpToolFactory<TInput>;
28
+ shouldRegister?: (context: McpToolContext) => boolean | Promise<boolean>;
29
+ isReadOnly?: boolean;
30
+ isLocalOnly?: boolean;
31
+ }
32
+ export type AnyMcpToolDeclaration = McpToolDeclaration<any, any>;
33
+ export declare function declareTool<TInput extends ZodRawShape, TOutput extends ZodRawShape>(declaration: McpToolDeclaration<TInput, TOutput>): McpToolDeclaration<TInput, TOutput>;
34
+ export declare function registerTools(server: McpServer, context: McpToolContext, declarations: AnyMcpToolDeclaration[]): Promise<void>;
35
+ export {};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.declareTool = declareTool;
11
+ exports.registerTools = registerTools;
12
+ function declareTool(declaration) {
13
+ return declaration;
14
+ }
15
+ async function registerTools(server, context, declarations) {
16
+ for (const declaration of declarations) {
17
+ if (declaration.shouldRegister && !(await declaration.shouldRegister(context))) {
18
+ continue;
19
+ }
20
+ const { name, factory, shouldRegister, isReadOnly, isLocalOnly, ...config } = declaration;
21
+ const handler = await factory(context);
22
+ // Add declarative characteristics to annotations
23
+ config.annotations ??= {};
24
+ if (isReadOnly !== undefined) {
25
+ config.annotations.readOnlyHint = isReadOnly;
26
+ }
27
+ if (isLocalOnly !== undefined) {
28
+ // openWorldHint: false means local only
29
+ config.annotations.openWorldHint = !isLocalOnly;
30
+ }
31
+ server.registerTool(name, config, handler);
32
+ }
33
+ }
@@ -220,6 +220,9 @@ async function getWorkspaceRaw(level = 'local') {
220
220
  }
221
221
  async function validateWorkspace(data, isGlobal) {
222
222
  const schema = (0, json_file_1.readAndParseJson)(exports.workspaceSchemaPath);
223
+ if (!isJsonObject(schema)) {
224
+ throw new Error('Workspace schema is not a JSON object.');
225
+ }
223
226
  // We should eventually have a dedicated global config schema and use that to validate.
224
227
  const schemaToValidate = isGlobal
225
228
  ? {
@@ -5,4 +5,16 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
+ /**
9
+ * Gets the end-of-line sequence from a string.
10
+ *
11
+ * This function analyzes the given string to determine the most frequent end-of-line (EOL)
12
+ * sequence. It counts the occurrences of carriage return line feed (`\r\n`) and
13
+ * line feed (`\n`).
14
+ *
15
+ * @param content The string to process.
16
+ * @returns The most frequent EOL sequence. If `\r\n` is more frequent, it returns `\r\n`.
17
+ * Otherwise (including ties), it returns `\n`. If no newlines are found, it falls back
18
+ * to the operating system's default EOL sequence.
19
+ */
8
20
  export declare function getEOL(content: string): string;
@@ -11,6 +11,18 @@ exports.getEOL = getEOL;
11
11
  const node_os_1 = require("node:os");
12
12
  const CRLF = '\r\n';
13
13
  const LF = '\n';
14
+ /**
15
+ * Gets the end-of-line sequence from a string.
16
+ *
17
+ * This function analyzes the given string to determine the most frequent end-of-line (EOL)
18
+ * sequence. It counts the occurrences of carriage return line feed (`\r\n`) and
19
+ * line feed (`\n`).
20
+ *
21
+ * @param content The string to process.
22
+ * @returns The most frequent EOL sequence. If `\r\n` is more frequent, it returns `\r\n`.
23
+ * Otherwise (including ties), it returns `\n`. If no newlines are found, it falls back
24
+ * to the operating system's default EOL sequence.
25
+ */
14
26
  function getEOL(content) {
15
27
  const newlines = content.match(/(?:\r?\n)/g);
16
28
  if (newlines?.length) {
@@ -5,6 +5,14 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
+ /**
9
+ * Asserts that a given value is an Error-like object.
10
+ *
11
+ * If the value is not an `Error` or an object with `name` and `message` properties,
12
+ * this function will throw an `AssertionError` with a descriptive message.
13
+ *
14
+ * @param value The value to check.
15
+ */
8
16
  export declare function assertIsError(value: unknown): asserts value is Error & {
9
17
  code?: string;
10
18
  };
@@ -12,9 +12,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.assertIsError = assertIsError;
14
14
  const node_assert_1 = __importDefault(require("node:assert"));
15
+ const node_util_1 = require("node:util");
16
+ /**
17
+ * Checks if a given value is an Error-like object.
18
+ *
19
+ * This type guard checks if the value is an instance of `Error` or if it's an object
20
+ * with `name` and `message` properties. This is useful for identifying error-like
21
+ * objects that may not be direct instances of `Error` (e.g., from RxJs).
22
+ *
23
+ * @param value The value to check.
24
+ * @returns `true` if the value is an Error-like object, `false` otherwise.
25
+ */
26
+ function isError(value) {
27
+ return (value instanceof Error ||
28
+ (typeof value === 'object' && value !== null && 'name' in value && 'message' in value));
29
+ }
30
+ /**
31
+ * Asserts that a given value is an Error-like object.
32
+ *
33
+ * If the value is not an `Error` or an object with `name` and `message` properties,
34
+ * this function will throw an `AssertionError` with a descriptive message.
35
+ *
36
+ * @param value The value to check.
37
+ */
15
38
  function assertIsError(value) {
16
- const isError = value instanceof Error ||
17
- // The following is needing to identify errors coming from RxJs.
18
- (typeof value === 'object' && value && 'name' in value && 'message' in value);
19
- (0, node_assert_1.default)(isError, 'catch clause variable is not an Error instance');
39
+ (0, node_assert_1.default)(isError(value), `Expected a value to be an Error-like object, but received: ${(0, node_util_1.inspect)(value)}`);
20
40
  }
@@ -5,7 +5,20 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.dev/license
7
7
  */
8
+ import { JsonValue } from '@angular-devkit/core';
9
+ /** A function that returns an index to insert a new property in a JSON object. */
8
10
  export type InsertionIndex = (properties: string[]) => number;
11
+ /** A JSON path. */
9
12
  export type JSONPath = (string | number)[];
10
- export declare function readAndParseJson(path: string): any;
11
- export declare function parseJson(content: string): any;
13
+ /**
14
+ * Reads and parses a JSON file, supporting comments and trailing commas.
15
+ * @param path The path to the JSON file.
16
+ * @returns The parsed JSON object.
17
+ */
18
+ export declare function readAndParseJson<T extends JsonValue>(path: string): T;
19
+ /**
20
+ * Parses a JSON string, supporting comments and trailing commas.
21
+ * @param content The JSON string to parse.
22
+ * @returns The parsed JSON object.
23
+ */
24
+ export declare function parseJson<T extends JsonValue>(content: string): T;