@angular/cli 21.1.0-next.0 → 21.1.0-next.1
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.
- package/lib/code-examples.db +0 -0
- package/package.json +16 -16
- package/src/commands/mcp/host.d.ts +27 -0
- package/src/commands/mcp/host.js +8 -0
- package/src/commands/mcp/host.js.map +1 -1
- package/src/commands/mcp/mcp-server.d.ts +20 -9
- package/src/commands/mcp/mcp-server.js +4 -2
- package/src/commands/mcp/mcp-server.js.map +1 -1
- package/src/commands/mcp/resources/ai-tutor.md +199 -3
- package/src/commands/mcp/tools/ai-tutor.d.ts +5 -1
- package/src/commands/mcp/tools/best-practices.d.ts +3 -1
- package/src/commands/mcp/tools/build.d.ts +8 -19
- package/src/commands/mcp/tools/devserver/start-devserver.d.ts +2 -12
- package/src/commands/mcp/tools/devserver/stop-devserver.d.ts +3 -13
- package/src/commands/mcp/tools/devserver/wait-for-devserver-build.d.ts +10 -16
- package/src/commands/mcp/tools/doc-search.d.ts +1 -11
- package/src/commands/mcp/tools/examples/database-discovery.d.ts +34 -0
- package/src/commands/mcp/tools/examples/database-discovery.js +87 -0
- package/src/commands/mcp/tools/examples/database-discovery.js.map +1 -0
- package/src/commands/mcp/tools/examples/database.d.ts +35 -0
- package/src/commands/mcp/tools/examples/database.js +125 -0
- package/src/commands/mcp/tools/examples/database.js.map +1 -0
- package/src/commands/mcp/tools/examples/index.d.ts +26 -0
- package/src/commands/mcp/tools/examples/index.js +149 -0
- package/src/commands/mcp/tools/examples/index.js.map +1 -0
- package/src/commands/mcp/tools/examples/query-escaper.d.ts +20 -0
- package/src/commands/mcp/tools/examples/query-escaper.js +68 -0
- package/src/commands/mcp/tools/examples/query-escaper.js.map +1 -0
- package/src/commands/mcp/tools/examples/runtime-database.d.ts +10 -0
- package/src/commands/mcp/tools/examples/runtime-database.js +192 -0
- package/src/commands/mcp/tools/examples/runtime-database.js.map +1 -0
- package/src/commands/mcp/tools/examples/schemas.d.ts +29 -0
- package/src/commands/mcp/tools/examples/schemas.js +101 -0
- package/src/commands/mcp/tools/examples/schemas.js.map +1 -0
- package/src/commands/mcp/tools/examples/utils.d.ts +14 -0
- package/src/commands/mcp/tools/examples/utils.js +31 -0
- package/src/commands/mcp/tools/examples/utils.js.map +1 -0
- package/src/commands/mcp/tools/modernize.d.ts +8 -18
- package/src/commands/mcp/tools/onpush-zoneless-migration/zoneless-migration.d.ts +3 -1
- package/src/commands/mcp/tools/projects.d.ts +23 -64
- package/src/commands/mcp/tools/tool-registry.d.ts +4 -3
- package/src/commands/mcp/tools/tool-registry.js.map +1 -1
- package/src/package-managers/host.d.ts +6 -0
- package/src/package-managers/host.js +1 -0
- package/src/package-managers/host.js.map +1 -1
- package/src/package-managers/package-manager-descriptor.d.ts +6 -6
- package/src/package-managers/package-manager-descriptor.js +5 -5
- package/src/package-managers/package-manager-descriptor.js.map +1 -1
- package/src/package-managers/package-manager.d.ts +21 -3
- package/src/package-managers/package-manager.js +74 -5
- package/src/package-managers/package-manager.js.map +1 -1
- package/src/utilities/version.js +1 -1
- package/src/commands/mcp/tools/examples.d.ts +0 -58
- package/src/commands/mcp/tools/examples.js +0 -654
- package/src/commands/mcp/tools/examples.js.map +0 -1
package/lib/code-examples.db
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/cli",
|
|
3
|
-
"version": "21.1.0-next.
|
|
3
|
+
"version": "21.1.0-next.1",
|
|
4
4
|
"description": "CLI tool for Angular",
|
|
5
5
|
"main": "lib/cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/angular/angular-cli",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@angular-devkit/architect": "0.2101.0-next.
|
|
29
|
-
"@angular-devkit/core": "21.1.0-next.
|
|
30
|
-
"@angular-devkit/schematics": "21.1.0-next.
|
|
28
|
+
"@angular-devkit/architect": "0.2101.0-next.1",
|
|
29
|
+
"@angular-devkit/core": "21.1.0-next.1",
|
|
30
|
+
"@angular-devkit/schematics": "21.1.0-next.1",
|
|
31
31
|
"@inquirer/prompts": "7.10.1",
|
|
32
32
|
"@listr2/prompt-adapter-inquirer": "3.0.5",
|
|
33
|
-
"@modelcontextprotocol/sdk": "1.
|
|
34
|
-
"@schematics/angular": "21.1.0-next.
|
|
33
|
+
"@modelcontextprotocol/sdk": "1.24.0",
|
|
34
|
+
"@schematics/angular": "21.1.0-next.1",
|
|
35
35
|
"@yarnpkg/lockfile": "1.1.0",
|
|
36
36
|
"algoliasearch": "5.45.0",
|
|
37
37
|
"ini": "6.0.0",
|
|
@@ -43,22 +43,22 @@
|
|
|
43
43
|
"resolve": "1.22.11",
|
|
44
44
|
"semver": "7.7.3",
|
|
45
45
|
"yargs": "18.0.0",
|
|
46
|
-
"zod": "
|
|
46
|
+
"zod": "4.1.13"
|
|
47
47
|
},
|
|
48
48
|
"ng-update": {
|
|
49
49
|
"migrations": "@schematics/angular/migrations/migration-collection.json",
|
|
50
50
|
"packageGroup": {
|
|
51
|
-
"@angular/cli": "21.1.0-next.
|
|
52
|
-
"@angular/build": "21.1.0-next.
|
|
53
|
-
"@angular/ssr": "21.1.0-next.
|
|
54
|
-
"@angular-devkit/architect": "0.2101.0-next.
|
|
55
|
-
"@angular-devkit/build-angular": "21.1.0-next.
|
|
56
|
-
"@angular-devkit/build-webpack": "0.2101.0-next.
|
|
57
|
-
"@angular-devkit/core": "21.1.0-next.
|
|
58
|
-
"@angular-devkit/schematics": "21.1.0-next.
|
|
51
|
+
"@angular/cli": "21.1.0-next.1",
|
|
52
|
+
"@angular/build": "21.1.0-next.1",
|
|
53
|
+
"@angular/ssr": "21.1.0-next.1",
|
|
54
|
+
"@angular-devkit/architect": "0.2101.0-next.1",
|
|
55
|
+
"@angular-devkit/build-angular": "21.1.0-next.1",
|
|
56
|
+
"@angular-devkit/build-webpack": "0.2101.0-next.1",
|
|
57
|
+
"@angular-devkit/core": "21.1.0-next.1",
|
|
58
|
+
"@angular-devkit/schematics": "21.1.0-next.1"
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
|
-
"packageManager": "pnpm@10.
|
|
61
|
+
"packageManager": "pnpm@10.24.0",
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
|
64
64
|
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
|
@@ -31,6 +31,33 @@ export interface Host {
|
|
|
31
31
|
* @returns A boolean indicating whether the path exists.
|
|
32
32
|
*/
|
|
33
33
|
existsSync(path: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Reads a file and returns its content.
|
|
36
|
+
* @param path The path to the file.
|
|
37
|
+
* @param encoding The encoding to use.
|
|
38
|
+
* @returns A promise that resolves to the file content.
|
|
39
|
+
*/
|
|
40
|
+
readFile(path: string, encoding: 'utf-8'): Promise<string>;
|
|
41
|
+
/**
|
|
42
|
+
* Finds files matching a glob pattern.
|
|
43
|
+
* @param pattern The glob pattern.
|
|
44
|
+
* @param options Options for the glob search.
|
|
45
|
+
* @returns An async iterable of file entries.
|
|
46
|
+
*/
|
|
47
|
+
glob(pattern: string, options: {
|
|
48
|
+
cwd: string;
|
|
49
|
+
}): AsyncIterable<{
|
|
50
|
+
name: string;
|
|
51
|
+
parentPath: string;
|
|
52
|
+
isFile(): boolean;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Resolves a module request from a given path.
|
|
56
|
+
* @param request The module request to resolve.
|
|
57
|
+
* @param from The path from which to resolve the request.
|
|
58
|
+
* @returns The resolved module path.
|
|
59
|
+
*/
|
|
60
|
+
resolveModule(request: string, from: string): string;
|
|
34
61
|
/**
|
|
35
62
|
* Spawns a child process and returns a promise that resolves with the process's
|
|
36
63
|
* output or rejects with a structured error.
|
package/src/commands/mcp/host.js
CHANGED
|
@@ -17,6 +17,7 @@ exports.LocalWorkspaceHost = exports.CommandError = void 0;
|
|
|
17
17
|
const fs_1 = require("fs");
|
|
18
18
|
const node_child_process_1 = require("node:child_process");
|
|
19
19
|
const promises_1 = require("node:fs/promises");
|
|
20
|
+
const node_module_1 = require("node:module");
|
|
20
21
|
const node_net_1 = require("node:net");
|
|
21
22
|
/**
|
|
22
23
|
* An error thrown when a command fails to execute.
|
|
@@ -37,6 +38,13 @@ exports.CommandError = CommandError;
|
|
|
37
38
|
exports.LocalWorkspaceHost = {
|
|
38
39
|
stat: promises_1.stat,
|
|
39
40
|
existsSync: fs_1.existsSync,
|
|
41
|
+
readFile: promises_1.readFile,
|
|
42
|
+
glob: function (pattern, options) {
|
|
43
|
+
return (0, promises_1.glob)(pattern, { ...options, withFileTypes: true });
|
|
44
|
+
},
|
|
45
|
+
resolveModule(request, from) {
|
|
46
|
+
return (0, node_module_1.createRequire)(from).resolve(request);
|
|
47
|
+
},
|
|
40
48
|
runCommand: async (command, args, options = {}) => {
|
|
41
49
|
const signal = options.timeout ? AbortSignal.timeout(options.timeout) : undefined;
|
|
42
50
|
return new Promise((resolve, reject) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["host.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH;;;;;GAKG;AAEH,2BAAkD;AAClD,2DAAyD;AAEzD,+
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["host.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,15 +16,20 @@ export declare const EXPERIMENTAL_TOOLS: readonly [import("./tools/tool-registry
|
|
|
16
16
|
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
17
17
|
configuration: import("zod").ZodOptional<import("zod").ZodString>;
|
|
18
18
|
}, {
|
|
19
|
-
status: import("zod").ZodEnum<
|
|
20
|
-
|
|
19
|
+
status: import("zod").ZodEnum<{
|
|
20
|
+
success: "success";
|
|
21
|
+
failure: "failure";
|
|
22
|
+
}>;
|
|
23
|
+
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
21
24
|
path: import("zod").ZodOptional<import("zod").ZodString>;
|
|
22
25
|
}>, import("./tools/tool-registry").McpToolDeclaration<{
|
|
23
|
-
directories: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString
|
|
24
|
-
transformations: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodEnum<
|
|
26
|
+
directories: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
27
|
+
transformations: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodEnum<{
|
|
28
|
+
[x: string]: string;
|
|
29
|
+
}>>>;
|
|
25
30
|
}, {
|
|
26
|
-
instructions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString
|
|
27
|
-
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString
|
|
31
|
+
instructions: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
32
|
+
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
28
33
|
}>, ...(import("./tools/tool-registry").McpToolDeclaration<{
|
|
29
34
|
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
30
35
|
}, {
|
|
@@ -34,13 +39,19 @@ export declare const EXPERIMENTAL_TOOLS: readonly [import("./tools/tool-registry
|
|
|
34
39
|
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
35
40
|
}, {
|
|
36
41
|
message: import("zod").ZodString;
|
|
37
|
-
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString
|
|
42
|
+
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
38
43
|
}> | import("./tools/tool-registry").McpToolDeclaration<{
|
|
39
44
|
project: import("zod").ZodOptional<import("zod").ZodString>;
|
|
40
45
|
timeout: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
41
46
|
}, {
|
|
42
|
-
status: import("zod").ZodEnum<
|
|
43
|
-
|
|
47
|
+
status: import("zod").ZodEnum<{
|
|
48
|
+
success: "success";
|
|
49
|
+
timeout: "timeout";
|
|
50
|
+
failure: "failure";
|
|
51
|
+
unknown: "unknown";
|
|
52
|
+
no_devserver_found: "no_devserver_found";
|
|
53
|
+
}>;
|
|
54
|
+
logs: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
44
55
|
}>)[]];
|
|
45
56
|
export declare function createMcpServer(options: {
|
|
46
57
|
workspace?: AngularWorkspace;
|
|
@@ -13,6 +13,7 @@ exports.assembleToolDeclarations = assembleToolDeclarations;
|
|
|
13
13
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
14
14
|
const node_path_1 = require("node:path");
|
|
15
15
|
const version_1 = require("../../utilities/version");
|
|
16
|
+
const host_1 = require("./host");
|
|
16
17
|
const instructions_1 = require("./resources/instructions");
|
|
17
18
|
const ai_tutor_1 = require("./tools/ai-tutor");
|
|
18
19
|
const best_practices_1 = require("./tools/best-practices");
|
|
@@ -21,7 +22,7 @@ const start_devserver_1 = require("./tools/devserver/start-devserver");
|
|
|
21
22
|
const stop_devserver_1 = require("./tools/devserver/stop-devserver");
|
|
22
23
|
const wait_for_devserver_build_1 = require("./tools/devserver/wait-for-devserver-build");
|
|
23
24
|
const doc_search_1 = require("./tools/doc-search");
|
|
24
|
-
const
|
|
25
|
+
const index_1 = require("./tools/examples/index");
|
|
25
26
|
const modernize_1 = require("./tools/modernize");
|
|
26
27
|
const zoneless_migration_1 = require("./tools/onpush-zoneless-migration/zoneless-migration");
|
|
27
28
|
const projects_1 = require("./tools/projects");
|
|
@@ -38,7 +39,7 @@ const STABLE_TOOLS = [
|
|
|
38
39
|
ai_tutor_1.AI_TUTOR_TOOL,
|
|
39
40
|
best_practices_1.BEST_PRACTICES_TOOL,
|
|
40
41
|
doc_search_1.DOC_SEARCH_TOOL,
|
|
41
|
-
|
|
42
|
+
index_1.FIND_EXAMPLE_TOOL,
|
|
42
43
|
projects_1.LIST_PROJECTS_TOOL,
|
|
43
44
|
zoneless_migration_1.ZONELESS_MIGRATION_TOOL,
|
|
44
45
|
];
|
|
@@ -97,6 +98,7 @@ equivalent actions.
|
|
|
97
98
|
logger,
|
|
98
99
|
exampleDatabasePath: (0, node_path_1.join)(__dirname, '../../../lib/code-examples.db'),
|
|
99
100
|
devServers: new Map(),
|
|
101
|
+
host: host_1.LocalWorkspaceHost,
|
|
100
102
|
}, toolDeclarations);
|
|
101
103
|
return server;
|
|
102
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["mcp-server.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["mcp-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,6 +19,7 @@ This is your most important principle. You will teach **Modern Angular** as the
|
|
|
19
19
|
- ✅ **DO** teach the built-in **control flow** (`@if`, `@for`, `@switch`) in templates.
|
|
20
20
|
- ✅ **DO** teach the new v20 file naming conventions (e.g., `app.ts` for a component file).
|
|
21
21
|
- ❌ **DO NOT** teach outdated patterns like `NgModules`, `ngIf`/`ngFor`/`ngSwitch`, or `@Input()` decorators unless a user specifically asks for a comparison. Frame them as "the old way" and note that as of v20, the core structural directives are officially deprecated.
|
|
22
|
+
- **CRITICAL NOTE (Experimental Features)**: You **must prominently warn** the user whenever a module covers an **experimental or developer-preview feature** (currently Phase 5: Signal Forms). Emphasize that the API is subject to change.
|
|
22
23
|
|
|
23
24
|
### 2. The Concept-Example-Exercise-Support Cycle
|
|
24
25
|
|
|
@@ -26,7 +27,7 @@ Your primary teaching method involves guiding the user to solve problems themsel
|
|
|
26
27
|
|
|
27
28
|
1. **Explain Concept (The "Why" and "What")**: Clearly explain the Angular concept or feature, its purpose, and how it generally works. The depth of this explanation depends on the user's experience level.
|
|
28
29
|
|
|
29
|
-
2.
|
|
30
|
+
2. **Provide Generic Example (The "How" in Isolation)**: **(MANDATORY)** You **MUST** provide a clear, well-formatted, concise code snippet that illustrates the core concept. **This example MUST NOT be code directly from the user's tutorial project ("Smart Recipe Box").** It should be a generic, illustrative example designed to show the concept in action (e.g., using a simple `Counter` to demonstrate a signal, or a generic `Logger` to explain dependency injection). This generic code should still follow all rules in `## ⚙️ Specific Technical & Syntax Rules`.
|
|
30
31
|
|
|
31
32
|
3. **Define Project Exercise (The "Apply it to Your App")**:
|
|
32
33
|
**IMPORTANT:** Your primary directive for creating a project exercise is to **describe the destination, not the journey.** You must present a high-level challenge by defining the properties of the _finished product_, not the steps to get there.
|
|
@@ -201,6 +202,14 @@ This rule defines the logical process you **must** follow to determine the preci
|
|
|
201
202
|
_ **Import Path Accuracy**: All relative `import` paths (`../`, `./`) in TypeScript files must be correct based on the final, canonical file structure.
|
|
202
203
|
_ **Dependency Completeness**: If a component's template uses CSS classes, its decorator **must** include a `styleUrl` property pointing to an existing `.css` file. All standalone `imports` arrays must be complete and correct for the features used in the template. \* **Code Hygiene**: Remove any unused variables, methods, or imports that were created in an early module but made obsolete by a later module's refactoring.
|
|
203
204
|
|
|
205
|
+
### 17. Mandatory Build Verification
|
|
206
|
+
|
|
207
|
+
Whenever you apply automated edits to the user's project (e.g., during module skipping, auto-completion, or jumping), you **must** verify the application compiles **before** asking the user to check their preview.
|
|
208
|
+
|
|
209
|
+
- **Action**: Immediately after writing file changes, run `ng build`.
|
|
210
|
+
- **Handle Failure**: If the build fails, you **must** analyze the errors, apply fixes, and re-run the build. Do not return control to the user until the build passes.
|
|
211
|
+
- **Proceed**: Only after a successful build should you prompt the user to verify the outcome in the web preview.
|
|
212
|
+
|
|
204
213
|
---
|
|
205
214
|
|
|
206
215
|
## ⚙️ Specific Technical & Syntax Rules
|
|
@@ -289,6 +298,10 @@ ng generate service <service-name>
|
|
|
289
298
|
_ **`RouterModule`**: Instruct users that they **should NEVER** need to import `RouterModule` into their standalone components. Router directives are globally available via `provideRouter`.
|
|
290
299
|
- **`RouterLink` and `RouterOutlet` Import**: When a component template uses router directives like `routerLink`, `routerLinkActive`, or `<router-outlet>`, you **must** instruct the user to `import` the specific directive class (e.g., `RouterLink`, `RouterOutlet`) from `'@angular/router'` and add it to that component's `imports` array.
|
|
291
300
|
|
|
301
|
+
### **Application Configuration (app.config.ts)**
|
|
302
|
+
|
|
303
|
+
- **CRITICAL: Animation Provider Prohibition**: The `provideAnimationsAsync` function **MUST NOT** be used in `app.config.ts` or any other configuration file. This provider is deprecated and is not necessary for modern Angular applications, even when using Angular Material. **You must not generate code that imports or calls `provideAnimationsAsync()` under any circumstances.**
|
|
304
|
+
|
|
292
305
|
### Styling, Layout, and Accessibility
|
|
293
306
|
|
|
294
307
|
- **Layout Guidance (Flexbox vs. Grid)**: When providing generic examples or guiding exercises, recommend CSS Flexbox for one-dimensional alignment within components (e.g., aligning items in a header).
|
|
@@ -299,6 +312,99 @@ ng generate service <service-name>
|
|
|
299
312
|
- When an exercise involves Material, guide the user to import the specific `Mat...Module` needed for the UI components they are using.
|
|
300
313
|
- For conditional styling, **you must teach property binding to `class` and `style` as the preferred method** (e.g., `[class.is-active]="isActive()"` or `[style.color]="'red'"`). The `[ngClass]` and `[ngStyle]` directives should be framed as an older pattern for more complex, object-based scenarios.
|
|
301
314
|
|
|
315
|
+
### Signal Forms
|
|
316
|
+
|
|
317
|
+
When teaching or generating code for Phase 5 (Signal Forms), you **must** strictly adhere to these new syntax and import rules:
|
|
318
|
+
|
|
319
|
+
- **Imports**:
|
|
320
|
+
- `form`, `submit`, `Field`, and validator functions (like `required`, `email`) must be imported from `@angular/forms/signals`.
|
|
321
|
+
- **Critical**: You must import `Field` (capitalized) to use strict typing in your component imports, but the binding in the template uses the lowercase `[field]` directive.
|
|
322
|
+
- **Definition**:
|
|
323
|
+
- Use `protected readonly myForm = form(...)` to create the form group.
|
|
324
|
+
- The first argument is the initial model state (e.g., `this.initialData` or a signal).
|
|
325
|
+
- The second argument is the validation callback (optional).
|
|
326
|
+
- **Template Binding**:
|
|
327
|
+
- Use the `[field]` directive to bind a form control to an input.
|
|
328
|
+
- **Correct Syntax**: `<input [field]="myForm.username">` (Note: `field` is lowercase here).
|
|
329
|
+
- **Submission Logic**:
|
|
330
|
+
- Use the `submit()` utility function inside a standard click handler.
|
|
331
|
+
- **Syntax**: `submit(this.myForm, async () => { /* logic */ })`.
|
|
332
|
+
- **Resetting Logic**:
|
|
333
|
+
- To reset the form, you must perform two actions:
|
|
334
|
+
1. **Clear Interaction State**: Call `.reset()` on the form signal's value: `this.myForm().reset()`.
|
|
335
|
+
2. **Clear Values**: Update the underlying model signal: `this.myModel.set({ ... })`.
|
|
336
|
+
- **Validation Syntax**:
|
|
337
|
+
- Import validator functions (`required`, `email`, etc.) directly from `@angular/forms/signals`.
|
|
338
|
+
- Apply them inside the definition callback.
|
|
339
|
+
- **Field State & Error Display**:
|
|
340
|
+
- Access field state by calling the field property as a signal (e.g., `myForm.email()`).
|
|
341
|
+
- Check validity using the `.invalid()` signal.
|
|
342
|
+
- Retrieve errors using the `.errors()` signal, which returns an array of error objects.
|
|
343
|
+
- **Pattern**:
|
|
344
|
+
```html
|
|
345
|
+
@if (myForm.email().invalid()) {
|
|
346
|
+
<ul>
|
|
347
|
+
@for (error of myForm.email().errors(); track error) {
|
|
348
|
+
<li>{{ error.message }}</li>
|
|
349
|
+
}
|
|
350
|
+
</ul>
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
- **Code Example (Standard Pattern)**:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// src/app/example/example.ts
|
|
357
|
+
import { Component, signal, inject } from '@angular/core';
|
|
358
|
+
import { form, submit, Field, required, email } from '@angular/forms/signals';
|
|
359
|
+
import { AuthService } from './auth.service';
|
|
360
|
+
|
|
361
|
+
@Component({
|
|
362
|
+
selector: 'app-example',
|
|
363
|
+
standalone: true,
|
|
364
|
+
imports: [Field],
|
|
365
|
+
template: `
|
|
366
|
+
<form>
|
|
367
|
+
<label>
|
|
368
|
+
Email
|
|
369
|
+
<input [field]="loginForm.email" />
|
|
370
|
+
</label>
|
|
371
|
+
@if (loginForm.email().touched() && loginForm.email().invalid()) {
|
|
372
|
+
<p class="error">
|
|
373
|
+
@for (error of loginForm.email().errors(); track $index) {
|
|
374
|
+
<span>{{ error.message }}</span>
|
|
375
|
+
}
|
|
376
|
+
</p>
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
<label>Password <input type="password" [field]="loginForm.password" /></label>
|
|
380
|
+
|
|
381
|
+
<button (click)="save($event)" [disabled]="loginForm().invalid()">Log In</button>
|
|
382
|
+
</form>
|
|
383
|
+
`,
|
|
384
|
+
})
|
|
385
|
+
export class Example {
|
|
386
|
+
private readonly authService = inject(AuthService);
|
|
387
|
+
protected readonly loginModel = signal({ email: '', password: '' });
|
|
388
|
+
|
|
389
|
+
protected readonly loginForm = form(this.loginModel, (s) => {
|
|
390
|
+
required(s.email, { message: 'Required' });
|
|
391
|
+
email(s.email, { message: 'Invalid email' });
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
protected async save(event: Event): Promise<void> {
|
|
395
|
+
event.preventDefault();
|
|
396
|
+
await submit(this.loginForm, async () => {
|
|
397
|
+
await this.authService.login(this.loginForm().value());
|
|
398
|
+
this.loginForm().reset();
|
|
399
|
+
this.loginModel.set({ email: '', password: '' });
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
`````
|
|
406
|
+
|
|
407
|
+
|
|
302
408
|
---
|
|
303
409
|
|
|
304
410
|
## 🚀 Onboarding: Project Analysis & Confirmation
|
|
@@ -429,9 +535,30 @@ _(The LLM will need to interpret "project-specific" or "app-themed" below based
|
|
|
429
535
|
_ **16a**: A new component exists with a `ReactiveForm` (using `FormBuilder`, `FormGroup`, `FormControl`). `description`: "building a reactive form to add new items."
|
|
430
536
|
_ **16b**: The form's submit handler calls a method on an injected service to add the new data. `description`: "adding the new item to the service on form submission."
|
|
431
537
|
- **Module 17 (Intro to Angular Material)**
|
|
432
|
-
_ **17a**: `package.json` contains `@angular/material`. `description`: "installing Angular Material."
|
|
538
|
+
_ **17a**: `package.json` contains `@angular/material`. `description`: "installing Angular Material." When installing `@angular/material`, use the command `ng add @angular/material`. Do not install `@angular/animations`, which is no longer a dependency of `@angular/material`.
|
|
433
539
|
_ **17b**: A component imports a Material module and uses a Material component in its template. `description`: "using an Angular Material component."
|
|
434
540
|
|
|
541
|
+
### Phase 5: Modern Signal Forms
|
|
542
|
+
|
|
543
|
+
- **Module 18 (Introduction to Signal Forms)**
|
|
544
|
+
- **18a**: `models.ts` includes `authorEmail` in the `RecipeModel` interface. `description`: "updating the model for new form fields."
|
|
545
|
+
- **18b**: A component imports `form` and `Field` from `@angular/forms/signals`. `description`: "importing the Signal Forms API."
|
|
546
|
+
- **18c**: A `protected readonly` form signal is defined using `form()` and initialized with a signal model. `description`: "creating the form signal."
|
|
547
|
+
- **18d**: The template uses the `[field]` directive on inputs to bind to the form. `description`: "binding inputs to the signal form."
|
|
548
|
+
- **Module 19 (Submitting & Resetting)**
|
|
549
|
+
- **19a**: The component imports `submit` from `@angular/forms/signals`. `description`: "importing the submit utility."
|
|
550
|
+
- **19b**: A save method uses `submit(this.form, ...)` to wrap the submission logic. `description`: "using the submit utility function."
|
|
551
|
+
- **19c**: The save method calls the service to add data. `description`: "integrating the service call."
|
|
552
|
+
- **19d**: The save method resets the form state using `.reset()` and clears the model values using `.set()`. `description`: "implementing form reset logic."
|
|
553
|
+
- **Module 20 (Validation in Signal Forms)**
|
|
554
|
+
- **20a**: The component imports validator functions (e.g., `required`, `email`) from `@angular/forms/signals`. `description`: "importing functional validators."
|
|
555
|
+
- **20b**: The `form()` definition uses a validation callback. `description`: "defining the validation schema."
|
|
556
|
+
- **20c**: The button uses `[disabled]` bound to `myForm.invalid()`. `description`: "disabling the button for invalid forms."
|
|
557
|
+
- **Module 21 (Field State & Error Messages)**
|
|
558
|
+
- **21a**: The template uses an `@if` block checking `field().invalid()` (e.g., `myForm.name().invalid()`). `description`: "checking field invalidity."
|
|
559
|
+
- **21b**: Inside the check, an `@for` loop iterates over `field().errors()`. `description`: "iterating over validation errors."
|
|
560
|
+
- **21c**: The loop displays the `error.message`. `description`: "displaying specific error messages."
|
|
561
|
+
|
|
435
562
|
---
|
|
436
563
|
|
|
437
564
|
## 🗺️ The Phased Learning Journey
|
|
@@ -501,7 +628,7 @@ touch src/app/mock-recipes.ts
|
|
|
501
628
|
];
|
|
502
629
|
``` **Exercise**: Now that our data structure is ready, your exercise is to import the`RecipeModel`and mock data into`app.ts`, create a `recipe`signal initialized with one of the recipes, display its text data, and use the existing buttons from Module 3 to change the active recipe using`.set()`.
|
|
503
630
|
|
|
504
|
-
|
|
631
|
+
`````
|
|
505
632
|
|
|
506
633
|
- **Module 5**: **State Management with Writable Signals (Part 2: `update`)**: Concept: Modifying state based on the current value. Exercise: Create a new `servings` signal of type `number`. Add buttons to the template that call methods to increment and decrement the servings count using the `.update()` method.
|
|
507
634
|
- **Module 6**: **Computed Signals**: Concept: Deriving state with `computed()`. Exercise: Create an `adjustedIngredients` computed signal that recalculates ingredient quantities based on the `recipe` and `servings` signals. Display the list of ingredients for the active recipe, showing how their quantities change dynamically when you adjust the servings.
|
|
@@ -625,3 +752,72 @@ touch src/app/mock-recipes.ts
|
|
|
625
752
|
- **Module 15**: **Basic Routing**: Concept: Decoupling components and enabling navigation using `provideRouter`, dynamic routes (e.g., `path: 'recipes/:id'`), and the `routerLink` directive. **Exercise**: A major refactoring lesson. Your goal is to convert your single-view application into a multi-view application with navigation. You will define routes to show the `RecipeList` at a `/recipes` URL and the `RecipeDetail` at a `/recipes/:id` URL. In the `RecipeList`, you will replace the nested detail component with a list of links (using `routerLink`) that navigate to the specific detail page for each recipe. Finally, you will modify the `RecipeDetail` component to fetch its own data from your `RecipeService` using the ID from the route URL, removing its dependency on the parent component's `input()` binding.
|
|
626
753
|
- **Module 16**: **Introduction to Forms**: Concept: Handling user input with `ReactiveFormsModule`. Exercise: Create a new component with a reactive form to add a new recipe. Upon successful form submission, the new recipe should be added to the array of items held in your application's service.
|
|
627
754
|
- **Module 17**: **Intro to Angular Material**: Concept: Using professional UI libraries. Exercise: Replace a standard HTML element with an Angular Material equivalent (e.g., `MatButton`).
|
|
755
|
+
|
|
756
|
+
### Phase 5: Experimental Signal Forms (⚠️ WARNING: Subject to Change)
|
|
757
|
+
|
|
758
|
+
**CRITICAL NOTE FOR THIS PHASE:** Signal Forms are currently an **EXPERIMENTAL** feature. The API may change significantly in future Angular releases. Please proceed with the understanding that this section demonstrates a cutting-edge feature.
|
|
759
|
+
|
|
760
|
+
- **Module 18**: **Introduction to Signal Forms**: Concept: Using the new `form()` signal API for state-driven forms. **Setup**: **Prerequisite: Angular v21+**. Signal Forms are a feature available starting in Angular v21. Before proceeding, please check your `package.json` or run `ng version`. If you are on an older version, run `ng update @angular/cli @angular/core` to upgrade your project. We need to update our recipe model to include some new fields that we will use in our form. Please update `models.ts` and `mock-recipes.ts` with the code below.
|
|
761
|
+
**File: `src/app/models.ts`** (Updated)
|
|
762
|
+
|
|
763
|
+
```typescript
|
|
764
|
+
export interface Ingredient {
|
|
765
|
+
name: string;
|
|
766
|
+
quantity: number;
|
|
767
|
+
unit: string;
|
|
768
|
+
}
|
|
769
|
+
export interface RecipeModel {
|
|
770
|
+
id: number;
|
|
771
|
+
name: string;
|
|
772
|
+
description: string;
|
|
773
|
+
authorEmail: string; // Add this
|
|
774
|
+
imgUrl: string;
|
|
775
|
+
isFavorite: boolean;
|
|
776
|
+
ingredients: Ingredient[];
|
|
777
|
+
}
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
**File: `src/app/mock-recipes.ts`** (Updated)
|
|
781
|
+
|
|
782
|
+
```typescript
|
|
783
|
+
import { RecipeModel } from './models';
|
|
784
|
+
export const MOCK_RECIPES: RecipeModel[] = [
|
|
785
|
+
{
|
|
786
|
+
id: 1,
|
|
787
|
+
name: 'Spaghetti Carbonara',
|
|
788
|
+
description: 'A classic Italian pasta dish.',
|
|
789
|
+
authorEmail: 'mario@italy.com', // Add this
|
|
790
|
+
imgUrl:
|
|
791
|
+
'[https://via.placeholder.com/300x200.png?text=Spaghetti+Carbonara](https://via.placeholder.com/300x200.png?text=Spaghetti+Carbonara)',
|
|
792
|
+
isFavorite: true,
|
|
793
|
+
ingredients: [
|
|
794
|
+
{ name: 'Spaghetti', quantity: 200, unit: 'g' },
|
|
795
|
+
{ name: 'Guanciale', quantity: 100, unit: 'g' },
|
|
796
|
+
{ name: 'Egg Yolks', quantity: 4, unit: 'each' },
|
|
797
|
+
{ name: 'Pecorino Romano Cheese', quantity: 50, unit: 'g' },
|
|
798
|
+
{ name: 'Black Pepper', quantity: 1, unit: 'tsp' },
|
|
799
|
+
],
|
|
800
|
+
},
|
|
801
|
+
// ... (update other mock recipes similarly or leave optional fields undefined)
|
|
802
|
+
];
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
**Exercise**: Your goal is to create a new `AddRecipe` component that uses the modern `Signal Forms` API. Import `form` and `Field` from `@angular/forms/signals`. Create a form using the `form()` function that includes fields for `name`, `description`, and `authorEmail`. In your template, use the `[field]` binding to connect your inputs to these form controls.
|
|
806
|
+
|
|
807
|
+
- **Module 19**: **Submitting & Resetting**: Concept: Handling form submission and resetting state. **Exercise**: Inject the service into your `AddRecipe` component. Create a protected `save()` method triggered by a "Save Recipe" button's `(click)` event. Inside this method:
|
|
808
|
+
1. Use the `submit(this.myForm, ...)` utility.
|
|
809
|
+
2. Update the `RecipeService` to include an `addRecipe(newRecipe: RecipeModel)` method.
|
|
810
|
+
3. Construct a complete `RecipeModel` (merging form values with defaults) and pass it to the service.
|
|
811
|
+
4. **Reset the form**: Call `this.myForm().reset()` to clear interaction flags.
|
|
812
|
+
5. **Clear the values**: Call `this.myModel.set(...)` to reset the inputs.
|
|
813
|
+
|
|
814
|
+
- **Module 20**: **Validation in Signal Forms**: Concept: Applying functional validators. **Exercise**: Import `required` and `email` from `@angular/forms/signals`. Modify your `form()` definition to add a validation callback enforcing:
|
|
815
|
+
- `name`: Required (Message: 'Recipe name is required.').
|
|
816
|
+
- `description`: Required (Message: 'Description is required.').
|
|
817
|
+
- `authorEmail`: Required (Message: 'Author email is required.') AND Email format (Message: 'Please enter a valid email address.').
|
|
818
|
+
**Finally, bind the `[disabled]` property of your button to `myForm.invalid()` so users cannot submit invalid data.**
|
|
819
|
+
|
|
820
|
+
- **Module 21**: **Field State & Error Messages**: Concept: Providing user feedback by accessing field state signals. **Exercise**: Improve the UX of your `AddRecipe` component by showing specific error messages when data is missing or incorrect. In your template, for the `name`, `description`, and `authorEmail` inputs:
|
|
821
|
+
1. Create an `@if` block that checks if the field is `invalid()` (e.g., `myForm.name().invalid()`).
|
|
822
|
+
2. Inside the block, use `@for` to iterate over the field's `.errors()`.
|
|
823
|
+
3. Display the `error.message` in a red text color or helper text style so the user knows exactly what to fix.
|
|
@@ -5,4 +5,8 @@
|
|
|
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
|
-
export declare const AI_TUTOR_TOOL: import("./tool-registry").McpToolDeclaration<
|
|
8
|
+
export declare const AI_TUTOR_TOOL: import("./tool-registry").McpToolDeclaration<Readonly<{
|
|
9
|
+
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
10
|
+
}>, Readonly<{
|
|
11
|
+
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
12
|
+
}>>;
|
|
@@ -8,4 +8,6 @@
|
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
export declare const BEST_PRACTICES_TOOL: import("./tool-registry").McpToolDeclaration<{
|
|
10
10
|
workspacePath: z.ZodOptional<z.ZodString>;
|
|
11
|
-
},
|
|
11
|
+
}, Readonly<{
|
|
12
|
+
[k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
13
|
+
}>>;
|
|
@@ -11,27 +11,16 @@ import { type McpToolDeclaration } from './tool-registry';
|
|
|
11
11
|
declare const buildToolInputSchema: z.ZodObject<{
|
|
12
12
|
project: z.ZodOptional<z.ZodString>;
|
|
13
13
|
configuration: z.ZodOptional<z.ZodString>;
|
|
14
|
-
},
|
|
15
|
-
project?: string | undefined;
|
|
16
|
-
configuration?: string | undefined;
|
|
17
|
-
}, {
|
|
18
|
-
project?: string | undefined;
|
|
19
|
-
configuration?: string | undefined;
|
|
20
|
-
}>;
|
|
14
|
+
}, z.core.$strip>;
|
|
21
15
|
export type BuildToolInput = z.infer<typeof buildToolInputSchema>;
|
|
22
16
|
declare const buildToolOutputSchema: z.ZodObject<{
|
|
23
|
-
status: z.ZodEnum<
|
|
24
|
-
|
|
17
|
+
status: z.ZodEnum<{
|
|
18
|
+
success: "success";
|
|
19
|
+
failure: "failure";
|
|
20
|
+
}>;
|
|
21
|
+
logs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
22
|
path: z.ZodOptional<z.ZodString>;
|
|
26
|
-
},
|
|
27
|
-
status: "success" | "failure";
|
|
28
|
-
path?: string | undefined;
|
|
29
|
-
logs?: string[] | undefined;
|
|
30
|
-
}, {
|
|
31
|
-
status: "success" | "failure";
|
|
32
|
-
path?: string | undefined;
|
|
33
|
-
logs?: string[] | undefined;
|
|
34
|
-
}>;
|
|
23
|
+
}, z.core.$strip>;
|
|
35
24
|
export type BuildToolOutput = z.infer<typeof buildToolOutputSchema>;
|
|
36
25
|
export declare function runBuild(input: BuildToolInput, host: Host): Promise<{
|
|
37
26
|
content: {
|
|
@@ -40,8 +29,8 @@ export declare function runBuild(input: BuildToolInput, host: Host): Promise<{
|
|
|
40
29
|
}[];
|
|
41
30
|
structuredContent: {
|
|
42
31
|
status: "success" | "failure";
|
|
43
|
-
path?: string | undefined;
|
|
44
32
|
logs?: string[] | undefined;
|
|
33
|
+
path?: string | undefined;
|
|
45
34
|
};
|
|
46
35
|
}>;
|
|
47
36
|
export declare const BUILD_TOOL: McpToolDeclaration<typeof buildToolInputSchema.shape, typeof buildToolOutputSchema.shape>;
|
|
@@ -10,22 +10,12 @@ import { type Host } from '../../host';
|
|
|
10
10
|
import { type McpToolContext, type McpToolDeclaration } from '../tool-registry';
|
|
11
11
|
declare const startDevServerToolInputSchema: z.ZodObject<{
|
|
12
12
|
project: z.ZodOptional<z.ZodString>;
|
|
13
|
-
},
|
|
14
|
-
project?: string | undefined;
|
|
15
|
-
}, {
|
|
16
|
-
project?: string | undefined;
|
|
17
|
-
}>;
|
|
13
|
+
}, z.core.$strip>;
|
|
18
14
|
export type StartDevserverToolInput = z.infer<typeof startDevServerToolInputSchema>;
|
|
19
15
|
declare const startDevServerToolOutputSchema: z.ZodObject<{
|
|
20
16
|
message: z.ZodString;
|
|
21
17
|
address: z.ZodOptional<z.ZodString>;
|
|
22
|
-
},
|
|
23
|
-
message: string;
|
|
24
|
-
address?: string | undefined;
|
|
25
|
-
}, {
|
|
26
|
-
message: string;
|
|
27
|
-
address?: string | undefined;
|
|
28
|
-
}>;
|
|
18
|
+
}, z.core.$strip>;
|
|
29
19
|
export type StartDevserverToolOutput = z.infer<typeof startDevServerToolOutputSchema>;
|
|
30
20
|
export declare function startDevServer(input: StartDevserverToolInput, context: McpToolContext, host: Host): Promise<{
|
|
31
21
|
content: {
|
|
@@ -9,22 +9,12 @@ import { z } from 'zod';
|
|
|
9
9
|
import { type McpToolContext, type McpToolDeclaration } from '../tool-registry';
|
|
10
10
|
declare const stopDevserverToolInputSchema: z.ZodObject<{
|
|
11
11
|
project: z.ZodOptional<z.ZodString>;
|
|
12
|
-
},
|
|
13
|
-
project?: string | undefined;
|
|
14
|
-
}, {
|
|
15
|
-
project?: string | undefined;
|
|
16
|
-
}>;
|
|
12
|
+
}, z.core.$strip>;
|
|
17
13
|
export type StopDevserverToolInput = z.infer<typeof stopDevserverToolInputSchema>;
|
|
18
14
|
declare const stopDevserverToolOutputSchema: z.ZodObject<{
|
|
19
15
|
message: z.ZodString;
|
|
20
|
-
logs: z.ZodOptional<z.ZodArray<z.ZodString
|
|
21
|
-
},
|
|
22
|
-
message: string;
|
|
23
|
-
logs?: string[] | undefined;
|
|
24
|
-
}, {
|
|
25
|
-
message: string;
|
|
26
|
-
logs?: string[] | undefined;
|
|
27
|
-
}>;
|
|
16
|
+
logs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
|
+
}, z.core.$strip>;
|
|
28
18
|
export type StopDevserverToolOutput = z.infer<typeof stopDevserverToolOutputSchema>;
|
|
29
19
|
export declare function stopDevserver(input: StopDevserverToolInput, context: McpToolContext): {
|
|
30
20
|
content: {
|