diff --git a/deno.json b/deno.json index db7c0750b1..126f5fdf06 100644 --- a/deno.json +++ b/deno.json @@ -478,7 +478,7 @@ "storybook": "npm --prefix storybook run storybook", "build:storybook": "npm --prefix storybook run build-storybook", "storybook:check": "deno test --no-lock --config=scripts/test.deno.json --no-check --allow-read scripts/storybook/storybook-workbench.test.ts", - "lint": "DENO_NO_PACKAGE_JSON=1 deno lint src/ cli/ react/ && deno lint --config=scripts/test.deno.json scripts/test/ scripts/build/dnt-polyfill.ts scripts/build/dnt-polyfill.test.ts scripts/build/npm-package-metadata.test.ts scripts/build/prepare-framework-sources.test.ts && deno lint --config=scripts/codemods/deno.json scripts/codemods/", + "lint": "DENO_NO_PACKAGE_JSON=1 deno lint && deno lint --config=scripts/test.deno.json scripts/test/ scripts/build/dnt-polyfill.ts scripts/build/dnt-polyfill.test.ts scripts/build/npm-package-metadata.test.ts scripts/build/prepare-framework-sources.test.ts && deno lint --config=scripts/codemods/deno.json scripts/codemods/", "fmt": "deno fmt src/ cli/ react/ && deno fmt --config=scripts/test.deno.json scripts/test/ scripts/build/dnt-polyfill.ts scripts/build/dnt-polyfill.test.ts scripts/build/prepare-framework-sources.test.ts && deno fmt --config=scripts/codemods/deno.json scripts/codemods/", "fmt:check": "deno fmt --check src/ cli/ react/ && deno fmt --check --config=scripts/test.deno.json scripts/test/ scripts/build/dnt-polyfill.ts scripts/build/dnt-polyfill.test.ts scripts/build/prepare-framework-sources.test.ts && deno fmt --check --config=scripts/codemods/deno.json scripts/codemods/", "typecheck": "deno task generate:manifests:check && deno check src/index.ts cli/main.ts src/server/index.ts src/routing/api/index.ts src/rendering/index.ts src/platform/index.ts src/platform/adapters/index.ts src/build/index.ts src/build/production-build/index.ts src/transforms/index.ts src/config/index.ts src/utils/index.ts src/data/index.ts src/security/index.ts src/middleware/index.ts src/server/handlers/dev/index.ts src/server/handlers/request/api/index.ts src/rendering/cache/index.ts src/rendering/cache/stores/index.ts src/rendering/rsc/actions/index.ts src/html/index.ts src/html/hydration-script-builder/runtime/main.ts src/modules/index.ts src/proxy/main.ts src/react/components/ui/index.ts src/chat/index.ts src/markdown/index.ts src/mdx/index.ts src/fs/index.ts src/oauth/index.ts src/agent/index.ts src/agent/service/route-export.check.ts src/eval/index.ts src/tool/index.ts src/workflow/index.ts src/prompt/index.ts src/resource/index.ts src/runs/index.ts src/mcp/index.ts src/provider/index.ts", @@ -519,7 +519,7 @@ "lint:ban-test-only": "deno run --allow-read scripts/lint/ban-test-only.ts", "lint:sanitizer-baseline": "deno run --allow-read scripts/lint/check-sanitizer-baseline.ts", "lint:skipped-tests": "deno run --allow-read scripts/lint/check-skipped-tests-baseline.ts", - "test:scripts": "deno test --config=scripts/test.deno.json --no-check --allow-read --allow-write --allow-run scripts/ci/publish-npm-packages.test.ts scripts/build/dnt-polyfill.test.ts scripts/build/generate-sbom.test.ts scripts/build/npm-dependency-sources.test.ts scripts/build/npm-extension-package-metadata.test.ts scripts/build/npm-package-metadata.test.ts scripts/build/npm-react-shims.test.ts scripts/build/prepare-framework-sources.test.ts scripts/docs/docs-coverage.test.ts scripts/docs/generate-api-reference.test.ts scripts/docs/guide-validation.test.ts scripts/lint/audit-core-deps.test.ts scripts/lint/audit-dependency-boundaries.test.ts scripts/lint/audit-extension-capabilities.test.ts scripts/lint/audit-extension-contracts.test.ts scripts/lint/audit-deps.test.ts scripts/lint/check-module-boundaries.test.ts scripts/lint/ban-test-only.test.ts scripts/lint/check-sanitizer-baseline.test.ts scripts/lint/check-skipped-tests-baseline.test.ts scripts/lint/check-test-typecheck-baseline.test.ts scripts/lint/check-coverage.test.ts scripts/security/audit-npm.test.ts scripts/security/submit-dependency-snapshot.test.ts && deno task test:tool-search-live", + "test:scripts": "deno test --config=scripts/test.deno.json --no-check --allow-read --allow-write --allow-run scripts/ci/publish-npm-packages.test.ts scripts/build/dnt-polyfill.test.ts scripts/build/generate-sbom.test.ts scripts/build/npm-dependency-sources.test.ts scripts/build/npm-extension-package-metadata.test.ts scripts/build/npm-package-metadata.test.ts scripts/build/npm-react-shims.test.ts scripts/build/prepare-framework-sources.test.ts scripts/docs/docs-coverage.test.ts scripts/docs/generate-api-reference.test.ts scripts/docs/guide-validation.test.ts scripts/lint/audit-core-deps.test.ts scripts/lint/audit-dependency-boundaries.test.ts scripts/lint/audit-extension-capabilities.test.ts scripts/lint/audit-extension-contracts.test.ts scripts/lint/audit-deps.test.ts scripts/lint/check-module-boundaries.test.ts scripts/lint/lint-config.test.ts scripts/lint/ban-test-only.test.ts scripts/lint/check-sanitizer-baseline.test.ts scripts/lint/check-skipped-tests-baseline.test.ts scripts/lint/check-test-typecheck-baseline.test.ts scripts/lint/check-coverage.test.ts scripts/security/audit-npm.test.ts scripts/security/submit-dependency-snapshot.test.ts && deno task test:tool-search-live", "test:sentry-runtime-packages": "deno test --config=scripts/test.deno.json --no-check --no-lock --allow-read --allow-write --allow-run --allow-env=DENO_DIR,HOME,XDG_CACHE_HOME,LOCALAPPDATA,USERPROFILE scripts/build/sentry-runtime-packages.test.ts", "test:tool-search-live": "VF_DISABLE_LRU_INTERVAL=1 deno test --no-check -A tests/agent/verify-tool-search-live.test.ts", "test:cross-runtime": "deno run --allow-all src/platform/compat/cross-runtime.test.ts", @@ -546,8 +546,11 @@ "include": [ "src/**/*.ts", "src/**/*.tsx", + "src/**/*.js", "cli/**/*.ts", "cli/**/*.tsx", + "extensions/**/*.ts", + "extensions/**/*.tsx", "react/**/*.ts", "react/**/*.tsx" ], diff --git a/extensions/ext-llm-anthropic/src/anthropic-request-builder.ts b/extensions/ext-llm-anthropic/src/anthropic-request-builder.ts index 4d9d75f6f4..6158b89e21 100644 --- a/extensions/ext-llm-anthropic/src/anthropic-request-builder.ts +++ b/extensions/ext-llm-anthropic/src/anthropic-request-builder.ts @@ -2,7 +2,6 @@ import { jsonValuesEqual, readProviderOptions, readRecord, - stringifyJsonValue, stringifyToolResultValue, unwrapToolInputSchema, } from "veryfront/provider/shared"; diff --git a/extensions/ext-llm-openai/src/openai-responses-request-builder.ts b/extensions/ext-llm-openai/src/openai-responses-request-builder.ts index e4d358c5bb..093fa001f2 100644 --- a/extensions/ext-llm-openai/src/openai-responses-request-builder.ts +++ b/extensions/ext-llm-openai/src/openai-responses-request-builder.ts @@ -1,7 +1,6 @@ import { jsonValuesEqual, readProviderOptions, - stringifyJsonValue, stringifyToolArguments, stringifyToolResultValue, unwrapToolInputSchema, diff --git a/scripts/deno.lock b/scripts/deno.lock index 4111744f8d..7f18e98b97 100644 --- a/scripts/deno.lock +++ b/scripts/deno.lock @@ -18,6 +18,7 @@ "jsr:@ts-morph/common@0.27": "0.27.0", "npm:@babel/parser@7.29.2": "7.29.2", "npm:@mdx-js/mdx@3.1.1": "3.1.1", + "npm:es-module-lexer@2.3.1": "2.3.1", "npm:esbuild@0.28.1": "0.28.1" }, "jsr": { @@ -365,6 +366,9 @@ "dequal" ] }, + "es-module-lexer@2.3.1": { + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==" + }, "esast-util-from-estree@2.0.0": { "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", "dependencies": [ diff --git a/scripts/lint/lint-config.test.ts b/scripts/lint/lint-config.test.ts new file mode 100644 index 0000000000..e623a77f88 --- /dev/null +++ b/scripts/lint/lint-config.test.ts @@ -0,0 +1,92 @@ +import { assert, assertEquals } from "#std/assert"; +import { globToRegExp, join } from "#std/path"; +import { describe, it } from "#veryfront/testing/bdd.ts"; + +interface DenoConfig { + lint?: { + include?: string[]; + exclude?: string[]; + }; +} + +const EXTENSION_SOURCE_EXTENSIONS = [".ts", ".tsx"] as const; +const EXTENSION_LINT_PATTERNS = [ + "extensions/**/*.ts", + "extensions/**/*.tsx", +] as const; + +function isExtensionSource(path: string): boolean { + return EXTENSION_SOURCE_EXTENSIONS.some((extension) => + path.endsWith(extension) + ); +} + +function isCoveredByGlob(path: string, pattern: string): boolean { + return globToRegExp(pattern, { globstar: true }).test( + path.replaceAll("\\", "/"), + ); +} + +async function collectExtensionSources(root = "extensions"): Promise { + const files: string[] = []; + async function walk(directory: string): Promise { + for await (const entry of Deno.readDir(directory)) { + const path = join(directory, entry.name); + if (entry.isDirectory) { + await walk(path); + continue; + } + if (entry.isFile && isExtensionSource(path)) { + files.push(path); + } + } + } + await walk(root); + return files.sort(); +} + +async function readLintConfig(): Promise< + Required> +> { + const config = JSON.parse(await Deno.readTextFile("deno.json")) as DenoConfig; + return { + include: config.lint?.include ?? [], + exclude: config.lint?.exclude ?? [], + }; +} + +describe("root lint configuration", () => { + it("covers extension sources", async () => { + const { include, exclude } = await readLintConfig(); + const extensionSources = await collectExtensionSources(); + + assert(extensionSources.length > 0); + assertEquals( + EXTENSION_LINT_PATTERNS.every((pattern) => include.includes(pattern)), + true, + ); + assertEquals( + extensionSources.filter((source) => + !include.some((pattern) => isCoveredByGlob(source, pattern)) || + exclude.some((pattern) => isCoveredByGlob(source, pattern)) + ), + [], + ); + }); + + it("keeps production-build JavaScript templates inside the lint gate", async () => { + const { include, exclude } = await readLintConfig(); + const templates = [ + "src/build/production-build/templates/fallback-prefetch.js", + "src/build/production-build/templates/fallback-router.js", + ]; + + assertEquals( + templates.filter((template) => + !include.some((pattern) => isCoveredByGlob(template, pattern)) || + exclude.some((pattern) => isCoveredByGlob(template, pattern)) + ), + [], + ); + }); +});