Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2300d85

Browse files
author
Angular Builds
committed
5eddced build: update github/codeql-action action to v3.30.2
1 parent fb2e7b4 commit 2300d85

File tree

7 files changed

+174
-26
lines changed

7 files changed

+174
-26
lines changed

lib/code-examples.db

0 Bytes
Binary file not shown.

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@angular/cli",
3-
"version": "21.0.0-next.2+sha-e6a3b55",
3+
"version": "21.0.0-next.2+sha-5eddced",
44
"description": "CLI tool for Angular",
55
"main": "lib/cli/index.js",
66
"bin": {
@@ -25,13 +25,13 @@
2525
},
2626
"homepage": "https://github.com/angular/angular-cli",
2727
"dependencies": {
28-
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#e6a3b55",
29-
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#e6a3b55",
30-
"@angular-devkit/schematics": "github:angular/angular-devkit-schematics-builds#e6a3b55",
28+
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#5eddced",
29+
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#5eddced",
30+
"@angular-devkit/schematics": "github:angular/angular-devkit-schematics-builds#5eddced",
3131
"@inquirer/prompts": "7.8.4",
3232
"@listr2/prompt-adapter-inquirer": "3.0.3",
3333
"@modelcontextprotocol/sdk": "1.17.5",
34-
"@schematics/angular": "github:angular/schematics-angular-builds#e6a3b55",
34+
"@schematics/angular": "github:angular/schematics-angular-builds#5eddced",
3535
"@yarnpkg/lockfile": "1.1.0",
3636
"algoliasearch": "5.37.0",
3737
"ini": "5.0.0",
@@ -47,14 +47,14 @@
4747
"ng-update": {
4848
"migrations": "@schematics/angular/migrations/migration-collection.json",
4949
"packageGroup": {
50-
"@angular/cli": "github:angular/cli-builds#e6a3b55",
51-
"@angular/build": "github:angular/angular-build-builds#e6a3b55",
52-
"@angular/ssr": "github:angular/angular-ssr-builds#e6a3b55",
53-
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#e6a3b55",
54-
"@angular-devkit/build-angular": "github:angular/angular-devkit-build-angular-builds#e6a3b55",
55-
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#e6a3b55",
56-
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#e6a3b55",
57-
"@angular-devkit/schematics": "github:angular/angular-devkit-schematics-builds#e6a3b55"
50+
"@angular/cli": "github:angular/cli-builds#5eddced",
51+
"@angular/build": "github:angular/angular-build-builds#5eddced",
52+
"@angular/ssr": "github:angular/angular-ssr-builds#5eddced",
53+
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#5eddced",
54+
"@angular-devkit/build-angular": "github:angular/angular-devkit-build-angular-builds#5eddced",
55+
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#5eddced",
56+
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#5eddced",
57+
"@angular-devkit/schematics": "github:angular/angular-devkit-schematics-builds#5eddced"
5858
}
5959
},
6060
"packageManager": "[email protected]",

src/commands/mcp/mcp-server.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ import { AnyMcpToolDeclaration } from './tools/tool-registry';
1414
*/
1515
export declare const EXPERIMENTAL_TOOLS: readonly [import("./tools/tool-registry").McpToolDeclaration<{
1616
query: import("zod").ZodString;
17+
keywords: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
18+
required_packages: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
19+
related_concepts: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
1720
}, {
1821
examples: import("zod").ZodArray<import("zod").ZodObject<{
1922
content: import("zod").ZodString;

src/commands/mcp/tools/examples.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import { z } from 'zod';
99
export declare const FIND_EXAMPLE_TOOL: import("./tool-registry").McpToolDeclaration<{
1010
query: z.ZodString;
11+
keywords: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
12+
required_packages: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
13+
related_concepts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1114
}, {
1215
examples: z.ZodArray<z.ZodObject<{
1316
content: z.ZodString;

src/commands/mcp/tools/examples.js

Lines changed: 153 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ Examples of queries:
7272
- Find signal inputs: 'signal input'
7373
- Find lazy loading a route: 'lazy load route'
7474
- Find forms with validation: 'form AND (validation OR validator)'`),
75+
keywords: zod_1.z.array(zod_1.z.string()).optional().describe('Filter examples by specific keywords.'),
76+
required_packages: zod_1.z
77+
.array(zod_1.z.string())
78+
.optional()
79+
.describe('Filter examples by required NPM packages (e.g., "@angular/forms").'),
80+
related_concepts: zod_1.z
81+
.array(zod_1.z.string())
82+
.optional()
83+
.describe('Filter examples by related high-level concepts.'),
7584
});
7685
exports.FIND_EXAMPLE_TOOL = (0, tool_registry_1.declareTool)({
7786
name: 'find_examples',
@@ -89,7 +98,9 @@ new or evolving features.
8998
* **Modern Implementation:** Finding the correct modern syntax for features
9099
(e.g., query: 'functional route guard' or 'http client with fetch').
91100
* **Refactoring to Modern Patterns:** Upgrading older code by finding examples of new syntax
92-
(e.g., query: 'built-in control flow' to replace "*ngIf').
101+
(e.g., query: 'built-in control flow' to replace "*ngIf").
102+
* **Advanced Filtering:** Combining a full-text search with filters to narrow results.
103+
(e.g., query: 'forms', required_packages: ['@angular/forms'], keywords: ['validation'])
93104
</Use Cases>
94105
<Operational Notes>
95106
* **Tool Selection:** This database primarily contains examples for new and recently updated Angular
@@ -98,6 +109,8 @@ new or evolving features.
98109
* The examples in this database are the single source of truth for modern Angular coding patterns.
99110
* The search query uses a powerful full-text search syntax (FTS5). Refer to the 'query'
100111
parameter description for detailed syntax rules and examples.
112+
* You can combine the main 'query' with optional filters like 'keywords', 'required_packages',
113+
and 'related_concepts' to create highly specific searches.
101114
</Operational Notes>`,
102115
inputSchema: findExampleInputSchema.shape,
103116
outputSchema: {
@@ -128,7 +141,7 @@ async function createFindExampleHandler({ exampleDatabasePath }) {
128141
db = await setupRuntimeExamples(process.env['NG_MCP_EXAMPLES_DIR']);
129142
}
130143
suppressSqliteWarning();
131-
return async ({ query }) => {
144+
return async (input) => {
132145
if (!db) {
133146
if (!exampleDatabasePath) {
134147
// This should be prevented by the registration logic in mcp-server.ts
@@ -137,14 +150,41 @@ async function createFindExampleHandler({ exampleDatabasePath }) {
137150
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
138151
db = new DatabaseSync(exampleDatabasePath, { readOnly: true });
139152
}
140-
if (!queryStatement) {
141-
queryStatement = db.prepare('SELECT * from examples WHERE examples MATCH ? ORDER BY rank;');
153+
const { query, keywords, required_packages, related_concepts } = input;
154+
// Build the query dynamically
155+
const params = [];
156+
let sql = 'SELECT content FROM examples_fts';
157+
const whereClauses = [];
158+
// FTS query
159+
if (query) {
160+
whereClauses.push('examples_fts MATCH ?');
161+
params.push(escapeSearchQuery(query));
142162
}
143-
const sanitizedQuery = escapeSearchQuery(query);
163+
// JSON array filters
164+
const addJsonFilter = (column, values) => {
165+
if (values?.length) {
166+
for (const value of values) {
167+
whereClauses.push(`${column} LIKE ?`);
168+
params.push(`%"${value}"%`);
169+
}
170+
}
171+
};
172+
addJsonFilter('keywords', keywords);
173+
addJsonFilter('required_packages', required_packages);
174+
addJsonFilter('related_concepts', related_concepts);
175+
if (whereClauses.length > 0) {
176+
sql += ` WHERE ${whereClauses.join(' AND ')}`;
177+
}
178+
// Order the results by relevance using the BM25 algorithm.
179+
// The weights assigned to each column boost the ranking of documents where the
180+
// search term appears in a more important field.
181+
// Column order: title, summary, keywords, required_packages, related_concepts, related_tools, content
182+
sql += ' ORDER BY bm25(examples_fts, 10.0, 5.0, 5.0, 1.0, 2.0, 1.0, 1.0);';
183+
const queryStatement = db.prepare(sql);
144184
// Query database and return results
145185
const examples = [];
146186
const textContent = [];
147-
for (const exampleRecord of queryStatement.all(sanitizedQuery)) {
187+
for (const exampleRecord of queryStatement.all(...params)) {
148188
const exampleContent = exampleRecord['content'];
149189
examples.push({ content: exampleContent });
150190
textContent.push({ type: 'text', text: exampleContent });
@@ -232,18 +272,120 @@ function suppressSqliteWarning() {
232272
return originalProcessEmit.apply(process, arguments);
233273
};
234274
}
275+
/**
276+
* A simple YAML front matter parser.
277+
*
278+
* This function extracts the YAML block enclosed by `---` at the beginning of a string
279+
* and parses it into a JavaScript object. It is not a full YAML parser and only
280+
* supports simple key-value pairs and string arrays.
281+
*
282+
* @param content The string content to parse.
283+
* @returns A record containing the parsed front matter data.
284+
*/
285+
function parseFrontmatter(content) {
286+
const match = content.match(/^---\r?\n(.*?)\r?\n---/s);
287+
if (!match) {
288+
return {};
289+
}
290+
const frontmatter = match[1];
291+
const data = {};
292+
const lines = frontmatter.split(/\r?\n/);
293+
let currentKey = '';
294+
let isArray = false;
295+
const arrayValues = [];
296+
for (const line of lines) {
297+
const keyValueMatch = line.match(/^([^:]+):\s*(.*)/);
298+
if (keyValueMatch) {
299+
if (currentKey && isArray) {
300+
data[currentKey] = arrayValues.slice();
301+
arrayValues.length = 0;
302+
}
303+
const [, key, value] = keyValueMatch;
304+
currentKey = key.trim();
305+
isArray = value.trim() === '';
306+
if (!isArray) {
307+
data[currentKey] = value.trim();
308+
}
309+
}
310+
else {
311+
const arrayItemMatch = line.match(/^\s*-\s*(.*)/);
312+
if (arrayItemMatch && currentKey && isArray) {
313+
arrayValues.push(arrayItemMatch[1].trim());
314+
}
315+
}
316+
}
317+
if (currentKey && isArray) {
318+
data[currentKey] = arrayValues;
319+
}
320+
return data;
321+
}
235322
async function setupRuntimeExamples(examplesPath) {
236323
const { DatabaseSync } = await Promise.resolve().then(() => __importStar(require('node:sqlite')));
237324
const db = new DatabaseSync(':memory:');
238-
db.exec(`CREATE VIRTUAL TABLE examples USING fts5(content, tokenize = 'porter ascii');`);
239-
const insertStatement = db.prepare('INSERT INTO examples(content) VALUES(?);');
325+
// Create a relational table to store the structured example data.
326+
db.exec(`
327+
CREATE TABLE examples (
328+
id INTEGER PRIMARY KEY,
329+
title TEXT NOT NULL,
330+
summary TEXT NOT NULL,
331+
keywords TEXT,
332+
required_packages TEXT,
333+
related_concepts TEXT,
334+
related_tools TEXT,
335+
content TEXT NOT NULL
336+
);
337+
`);
338+
// Create an FTS5 virtual table to provide full-text search capabilities.
339+
db.exec(`
340+
CREATE VIRTUAL TABLE examples_fts USING fts5(
341+
title,
342+
summary,
343+
keywords,
344+
required_packages,
345+
related_concepts,
346+
related_tools,
347+
content,
348+
content='examples',
349+
content_rowid='id',
350+
tokenize = 'porter ascii'
351+
);
352+
`);
353+
// Create triggers to keep the FTS table synchronized with the examples table.
354+
db.exec(`
355+
CREATE TRIGGER examples_after_insert AFTER INSERT ON examples BEGIN
356+
INSERT INTO examples_fts(rowid, title, summary, keywords, required_packages, related_concepts, related_tools, content)
357+
VALUES (
358+
new.id, new.title, new.summary, new.keywords, new.required_packages, new.related_concepts,
359+
new.related_tools, new.content
360+
);
361+
END;
362+
`);
363+
const insertStatement = db.prepare('INSERT INTO examples(' +
364+
'title, summary, keywords, required_packages, related_concepts, related_tools, content' +
365+
') VALUES(?, ?, ?, ?, ?, ?, ?);');
366+
const frontmatterSchema = zod_1.z.object({
367+
title: zod_1.z.string(),
368+
summary: zod_1.z.string(),
369+
keywords: zod_1.z.array(zod_1.z.string()).optional(),
370+
required_packages: zod_1.z.array(zod_1.z.string()).optional(),
371+
related_concepts: zod_1.z.array(zod_1.z.string()).optional(),
372+
related_tools: zod_1.z.array(zod_1.z.string()).optional(),
373+
});
240374
db.exec('BEGIN TRANSACTION');
241-
for await (const entry of (0, promises_1.glob)('*.md', { cwd: examplesPath, withFileTypes: true })) {
375+
for await (const entry of (0, promises_1.glob)('**/*.md', { cwd: examplesPath, withFileTypes: true })) {
242376
if (!entry.isFile()) {
243377
continue;
244378
}
245-
const example = await (0, promises_1.readFile)(node_path_1.default.join(entry.parentPath, entry.name), 'utf-8');
246-
insertStatement.run(example);
379+
const content = await (0, promises_1.readFile)(node_path_1.default.join(entry.parentPath, entry.name), 'utf-8');
380+
const frontmatter = parseFrontmatter(content);
381+
const validation = frontmatterSchema.safeParse(frontmatter);
382+
if (!validation.success) {
383+
// eslint-disable-next-line no-console
384+
console.warn(`Skipping invalid example file ${entry.name}:`, validation.error.issues);
385+
continue;
386+
}
387+
const { title, summary, keywords, required_packages, related_concepts, related_tools } = validation.data;
388+
insertStatement.run(title, summary, JSON.stringify(keywords ?? []), JSON.stringify(required_packages ?? []), JSON.stringify(related_concepts ?? []), JSON.stringify(related_tools ?? []), content);
247389
}
248390
db.exec('END TRANSACTION');
249391
return db;

src/utilities/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ class Version {
2222
this.patch = patch;
2323
}
2424
}
25-
exports.VERSION = new Version('21.0.0-next.2+sha-e6a3b55');
25+
exports.VERSION = new Version('21.0.0-next.2+sha-5eddced');

uniqueId

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Tue Sep 09 2025 05:36:42 GMT+0000 (Coordinated Universal Time)
1+
Tue Sep 09 2025 11:16:02 GMT+0000 (Coordinated Universal Time)

0 commit comments

Comments
 (0)