diff --git a/package.json b/package.json index 53dfe13439bd..7ac947bd43dd 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,6 @@ "unenv": "^1.10.0", "verdaccio": "6.2.3", "verdaccio-auth-memory": "^10.0.0", - "zod": "4.1.13", "zone.js": "^0.16.0" }, "dependenciesMeta": { diff --git a/packages/angular/cli/BUILD.bazel b/packages/angular/cli/BUILD.bazel index aeb1878b9d52..d53d8d7078da 100644 --- a/packages/angular/cli/BUILD.bazel +++ b/packages/angular/cli/BUILD.bazel @@ -4,8 +4,7 @@ # found in the LICENSE file at https://angular.dev/license load("@npm//:defs.bzl", "npm_link_all_packages") -load("//tools:defaults.bzl", "jasmine_test", "npm_package", "ts_project") -load("//tools:example_db_generator.bzl", "cli_example_db") +load("//tools:defaults.bzl", "jasmine_test", "ng_examples_db", "npm_package", "ts_project") load("//tools:ng_cli_schema_generator.bzl", "cli_json_schema") load("//tools:ts_json_schema.bzl", "ts_json_schema") @@ -90,7 +89,7 @@ ts_project( ], ) -cli_example_db( +ng_examples_db( name = "cli_example_database", srcs = glob( include = [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2644777b133d..3814382a0a1e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -301,9 +301,6 @@ importers: verdaccio-auth-memory: specifier: ^10.0.0 version: 10.3.1 - zod: - specifier: 4.1.13 - version: 4.1.13 zone.js: specifier: ^0.16.0 version: 0.16.0 @@ -7782,7 +7779,6 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. - (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qjobs@1.2.0: diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 59c817e3aa06..4804a9ee59a6 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -30,12 +30,3 @@ js_binary( ], entry_point = "quicktype_runner.js", ) - -js_binary( - name = "ng_example_db", - data = [ - "example_db_generator.js", - "//:node_modules/zod", - ], - entry_point = "example_db_generator.js", -) diff --git a/tools/defaults.bzl b/tools/defaults.bzl index dd4238243f16..d301591a32ba 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -2,6 +2,7 @@ load("@aspect_bazel_lib//lib:copy_to_bin.bzl", _copy_to_bin = "copy_to_bin") load("@aspect_rules_jasmine//jasmine:defs.bzl", _jasmine_test = "jasmine_test") load("@aspect_rules_js//js:defs.bzl", _js_binary = "js_binary") load("@devinfra//bazel/ts_project:index.bzl", "strict_deps_test") +load("@rules_angular//src/ng_examples_db:index.bzl", _ng_examples_db = "ng_examples_db") load("@rules_angular//src/ng_package:index.bzl", _ng_package = "ng_package") load("@rules_angular//src/ts_project:index.bzl", _ts_project = "ts_project") load("//tools:substitutions.bzl", "substitutions") @@ -77,3 +78,6 @@ def jasmine_test(data = [], args = [], **kwargs): data = data + ["//:node_modules/source-map-support"], **kwargs ) + +def ng_examples_db(**kwargs): + _ng_examples_db(**kwargs) diff --git a/tools/example_db_generator.bzl b/tools/example_db_generator.bzl deleted file mode 100644 index 7a899e3d8de4..000000000000 --- a/tools/example_db_generator.bzl +++ /dev/null @@ -1,12 +0,0 @@ -load("@aspect_rules_js//js:defs.bzl", "js_run_binary") - -def cli_example_db(name, srcs, path, out, data = []): - js_run_binary( - name = name, - outs = [out], - srcs = srcs + data, - tool = "//tools:ng_example_db", - progress_message = "Generating code example database from %s" % path, - mnemonic = "NgExampleSqliteDb", - args = [path, "$(rootpath %s)" % out], - ) diff --git a/tools/example_db_generator.js b/tools/example_db_generator.js deleted file mode 100644 index 052bb1afb53d..000000000000 --- a/tools/example_db_generator.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * @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 - */ - -const { globSync, readdirSync, readFileSync, mkdirSync, existsSync, rmSync } = require('node:fs'); -const { resolve, dirname, join } = require('node:path'); -const { DatabaseSync } = require('node:sqlite'); -const { z } = require('zod'); - -/** - * A simple YAML front matter parser. - * - * This function extracts the YAML block enclosed by `---` at the beginning of a string - * and parses it into a JavaScript object. It is not a full YAML parser and only - * supports simple key-value pairs and string arrays. - * - * @param content The string content to parse. - * @returns A record containing the parsed front matter data. - */ -function parseFrontmatter(content) { - const match = content.match(/^---\r?\n(.*?)\r?\n---/s); - if (!match) { - return {}; - } - - const frontmatter = match[1]; - const data = {}; - const lines = frontmatter.split(/\r?\n/); - - let currentKey = ''; - let isArray = false; - const arrayValues = []; - - for (const line of lines) { - const keyValueMatch = line.match(/^([^:]+):\s*(.*)/); - if (keyValueMatch) { - if (currentKey && isArray) { - data[currentKey] = arrayValues.slice(); - arrayValues.length = 0; - } - - const [, key, value] = keyValueMatch; - currentKey = key.trim(); - isArray = value.trim() === ''; - - if (!isArray) { - const trimmedValue = value.trim(); - if (trimmedValue === 'true') { - data[currentKey] = true; - } else if (trimmedValue === 'false') { - data[currentKey] = false; - } else { - data[currentKey] = trimmedValue; - } - } - } else { - const arrayItemMatch = line.match(/^\s*-\s*(.*)/); - if (arrayItemMatch && currentKey && isArray) { - let value = arrayItemMatch[1].trim(); - // Unquote if the value is quoted. - if ( - (value.startsWith("'") && value.endsWith("'")) || - (value.startsWith('"') && value.endsWith('"')) - ) { - value = value.slice(1, -1); - } - arrayValues.push(value); - } - } - } - - if (currentKey && isArray) { - data[currentKey] = arrayValues; - } - - return data; -} - -function generate(inPath, outPath) { - const dbPath = outPath; - mkdirSync(dirname(outPath), { recursive: true }); - - if (existsSync(dbPath)) { - rmSync(dbPath); - } - const db = new DatabaseSync(dbPath); - - // Create a table to store metadata. - db.exec(` - CREATE TABLE metadata ( - key TEXT PRIMARY KEY NOT NULL, - value TEXT NOT NULL - ); - `); - - db.exec(` - INSERT INTO metadata (key, value) VALUES - ('schema_version', '1'), - ('created_at', '${new Date().toISOString()}'); - `); - - // Create a relational table to store the structured example data. - db.exec(` - CREATE TABLE examples ( - id INTEGER PRIMARY KEY, - title TEXT NOT NULL, - summary TEXT NOT NULL, - keywords TEXT, - required_packages TEXT, - related_concepts TEXT, - related_tools TEXT, - experimental INTEGER NOT NULL DEFAULT 0, - content TEXT NOT NULL - ); - `); - - // Create an FTS5 virtual table to provide full-text search capabilities. - db.exec(` - CREATE VIRTUAL TABLE examples_fts USING fts5( - title, - summary, - keywords, - required_packages, - related_concepts, - related_tools, - content, - content='examples', - content_rowid='id', - tokenize = 'porter ascii' - ); - `); - - // Create triggers to keep the FTS table synchronized with the examples table. - db.exec(` - CREATE TRIGGER examples_after_insert AFTER INSERT ON examples BEGIN - INSERT INTO examples_fts( - rowid, title, summary, keywords, required_packages, related_concepts, related_tools, - content - ) - VALUES ( - new.id, new.title, new.summary, new.keywords, new.required_packages, - new.related_concepts, new.related_tools, new.content - ); - END; - `); - - const insertStatement = db.prepare( - 'INSERT INTO examples(' + - 'title, summary, keywords, required_packages, related_concepts, related_tools, experimental, content' + - ') VALUES(?, ?, ?, ?, ?, ?, ?, ?);', - ); - - const frontmatterSchema = z.object({ - title: z.string(), - summary: z.string(), - keywords: z.array(z.string()).optional(), - required_packages: z.array(z.string()).optional(), - related_concepts: z.array(z.string()).optional(), - related_tools: z.array(z.string()).optional(), - experimental: z.boolean().optional(), - }); - - db.exec('BEGIN TRANSACTION'); - const entries = globSync - ? globSync('**/*.md', { cwd: resolve(inPath), withFileTypes: true }) - : readdirSync(resolve(inPath), { withFileTypes: true }); - for (const entry of entries) { - if (!entry.isFile() || !entry.name.endsWith('.md')) { - continue; - } - - const content = readFileSync(join(entry.parentPath, entry.name), 'utf-8'); - const frontmatter = parseFrontmatter(content); - - const validation = frontmatterSchema.safeParse(frontmatter); - if (!validation.success) { - console.error(`Validation failed for example file: ${entry.name}`); - console.error('Issues:', validation.error.issues); - throw new Error(`Invalid front matter in ${entry.name}`); - } - - const { - title, - summary, - keywords, - required_packages, - related_concepts, - related_tools, - experimental, - } = validation.data; - insertStatement.run( - title, - summary, - JSON.stringify(keywords ?? []), - JSON.stringify(required_packages ?? []), - JSON.stringify(related_concepts ?? []), - JSON.stringify(related_tools ?? []), - experimental ? 1 : 0, - content, - ); - } - db.exec('END TRANSACTION'); - - db.close(); -} - -if (require.main === module) { - const argv = process.argv.slice(2); - if (argv.length !== 2) { - console.error('Must include 2 arguments.'); - process.exit(1); - } - - const [inPath, outPath] = argv; - - try { - generate(inPath, outPath); - } catch (error) { - console.error('An error happened:'); - console.error(error); - process.exit(127); - } -} - -exports.generate = generate;