diff --git a/@binkylabs/muzzle/package.json b/@binkylabs/muzzle/package.json index ca60fbb..d8b0f07 100644 --- a/@binkylabs/muzzle/package.json +++ b/@binkylabs/muzzle/package.json @@ -45,7 +45,7 @@ "vitest": "^4.0.16" }, "dependencies": { - "@typespec/compiler": "^1.7.1" + "@typespec/compiler": "^1.8.0-dev.6" }, "engines": { "node": ">=20.0.0" diff --git a/@binkylabs/muzzle/src/index.test.ts b/@binkylabs/muzzle/src/index.test.ts index bb3cd5f..27fa726 100644 --- a/@binkylabs/muzzle/src/index.test.ts +++ b/@binkylabs/muzzle/src/index.test.ts @@ -94,24 +94,28 @@ model Foo { it("should add suppress directives before model keyword when using 'is' keyword", async () => { const inputTypeSpec = `namespace OpenAI; +/** A Foo model */ model Foo { } +/** A Bar model */ model Bar { } -model FooBarArray is (Foo | Bar)[]; +/** A model that is a union of Foo and Bar in an array */ +model FooBarArray + is (Foo | Bar)[]; `; const expectedOutput = `namespace OpenAI; -#suppress "@azure-tools/typespec-azure-core/documentation-required" "Auto-suppressed warnings non-applicable rules during import." +/** A Foo model */ model Foo {} -#suppress "@azure-tools/typespec-azure-core/documentation-required" "Auto-suppressed warnings non-applicable rules during import." +/** A Bar model */ model Bar {} -#suppress "@azure-tools/typespec-azure-core/documentation-required" "Auto-suppressed warnings non-applicable rules during import." +/** A model that is a union of Foo and Bar in an array */ #suppress "@azure-tools/typespec-azure-core/no-unnamed-union" "Auto-suppressed warnings non-applicable rules during import." model FooBarArray is (Foo | Bar)[]; `; diff --git a/@binkylabs/muzzle/src/index.ts b/@binkylabs/muzzle/src/index.ts index ca2eb5a..9f8f284 100644 --- a/@binkylabs/muzzle/src/index.ts +++ b/@binkylabs/muzzle/src/index.ts @@ -1,10 +1,8 @@ import { existsSync } from "node:fs"; import { compile as typespecCompile, - createSuppressCodeFix, - DiagnosticTarget, + createSuppressCodeFixes, NodeHost, - NoTarget, Program, resolveCompilerOptions, applyCodeFixes, @@ -12,8 +10,6 @@ import { CompilerOptions, } from "@typespec/compiler"; -import { findSuppressTarget } from "./typespec-imports.js"; - /** * Adds suppress directives for all warnings in the TypeSpec program. * @param p The TypeSpec program @@ -24,33 +20,9 @@ export async function suppressEverything( p: Program, options: Partial> = {}, ) { - const codeFixes = Array.from( - Map.groupBy( - p.diagnostics - .filter( - (diag) => diag.severity === "warning" && diag.target !== NoTarget, - ) - .map((diag) => { - const suppressTarget = findSuppressTarget( - diag.target as DiagnosticTarget, - ); - const groupingKey = suppressTarget - ? `${diag.code}-${suppressTarget.file.path}-${suppressTarget.pos}-${suppressTarget.end}` - : `no-target-${diag.code}`; - return { - groupingKey: groupingKey, - fix: createSuppressCodeFix( - diag.target as DiagnosticTarget, - diag.code, - options.message || - "Warnings auto-suppressed by @binkylabs/muzzle.", - ), - }; - }), - (fix) => fix.groupingKey, - ) - .entries() - .map((group) => group[1][0].fix), + const codeFixes = createSuppressCodeFixes( + p.diagnostics, + options.message || "Warnings auto-suppressed by @binkylabs/muzzle.", ); await applyCodeFixes(p.host, codeFixes); } diff --git a/@binkylabs/muzzle/src/typespec-imports.ts b/@binkylabs/muzzle/src/typespec-imports.ts deleted file mode 100644 index 53639b2..0000000 --- a/@binkylabs/muzzle/src/typespec-imports.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - DiagnosticTarget, - getSourceLocation, - SourceLocation, -} from "@typespec/compiler"; - -import { getNodeForTarget, Node, SyntaxKind } from "@typespec/compiler/ast"; - -export function findSuppressTarget( - target: DiagnosticTarget, -): SourceLocation | undefined { - if ("file" in target) { - return target; - } - - const nodeTarget = getNodeForTarget(target); - if (!nodeTarget) return undefined; - - const node = findSuppressNode(nodeTarget); - return getSourceLocation(node); -} - -/** Find the node where the suppression should be applied */ -function findSuppressNode(node: Node): Node { - switch (node.kind) { - case SyntaxKind.Identifier: - case SyntaxKind.TypeReference: - case SyntaxKind.UnionExpression: - case SyntaxKind.ModelExpression: - return findSuppressNode(node.parent!); - default: - // Check if this node is the 'is' or 'extends' expression of a ModelStatement - // If so, move up to the parent statement to place suppression before 'model' keyword - if (node.parent && node.parent.kind === SyntaxKind.ModelStatement) { - const modelParent = node.parent; - if (modelParent.is === node || modelParent.extends === node) { - return node.parent; - } - } - return node; - } -} diff --git a/@binkylabs/muzzle/tsconfig.json b/@binkylabs/muzzle/tsconfig.json index 9539c01..f2b4c1f 100644 --- a/@binkylabs/muzzle/tsconfig.json +++ b/@binkylabs/muzzle/tsconfig.json @@ -14,5 +14,6 @@ /* Linting */ "strict": true }, - "include": ["src", "test", "vitest.d.ts"] + "include": ["src", "vitest.d.ts"], + "exclude": ["**/*.test.ts", "test-fixtures"] } diff --git a/@binkylabs/muzzle/vitest.config.ts b/@binkylabs/muzzle/vitest.config.ts index 1140eda..b9c85dc 100644 --- a/@binkylabs/muzzle/vitest.config.ts +++ b/@binkylabs/muzzle/vitest.config.ts @@ -4,6 +4,8 @@ export default defineConfig({ test: { globals: true, environment: "node", - testTimeout: 30000, // 30 seconds for slow TypeSpec compilation + testTimeout: 30000, // 30 seconds for slow TypeSpec compilation, + include: ["**/*.test.ts", "**/*.spec.ts"], + exclude: ["**/node_modules/**", "**/dist/**"], }, }); diff --git a/package-lock.json b/package-lock.json index 2bb36bf..ef3b9f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "version": "1.1.1", "license": "MIT", "dependencies": { - "@typespec/compiler": "^1.7.1" + "@typespec/compiler": "^1.8.0-dev.6" }, "bin": { "muzzle": "dist/src/cli.js" @@ -36,6 +36,38 @@ "node": ">=20.0.0" } }, + "@binkylabs/muzzle/node_modules/@typespec/compiler": { + "version": "1.8.0-dev.6", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.8.0-dev.6.tgz", + "integrity": "sha512-kNKrlZWPH79ymfoeXKHP121tfxr59b5jcskK7NMWpYzjcrC8YII4nTpjaT8TP9IYm8k1tyyUvPhDPpNps5NXxA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "~7.27.1", + "@inquirer/prompts": "^8.0.1", + "ajv": "~8.17.1", + "change-case": "~5.4.4", + "env-paths": "^3.0.0", + "globby": "~16.0.0", + "is-unicode-supported": "^2.1.0", + "mustache": "~4.2.0", + "picocolors": "~1.1.1", + "prettier": "~3.7.4", + "semver": "^7.7.1", + "tar": "^7.5.2", + "temporal-polyfill": "^0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.12", + "yaml": "~2.8.2", + "yargs": "~18.0.0" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@azure-tools/typespec-autorest": { "version": "0.63.1", "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.63.1.tgz", @@ -1845,7 +1877,9 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.7.1.tgz", "integrity": "sha512-sb3MEsKjFlAx8ZG484exs5Ec+JwmYf2anJqLjMusrV3rRMUhv3fbEulk9MD+l4eOkBS46VMNGqRu0wTn8suVVA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "~7.27.1", "@inquirer/prompts": "^8.0.1", @@ -1877,7 +1911,9 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -3411,7 +3447,6 @@ "version": "3.7.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", - "dev": true, "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -4243,16 +4278,18 @@ } }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 9853bcf..7c16949 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "main": "index.js", "scripts": { "test": "npm --workspace @binkylabs/muzzle run test", + "test:watch": "npm --workspace @binkylabs/muzzle run test:watch", "build": "npm --workspace @binkylabs/muzzle run build", "lint": "npm --workspace @binkylabs/muzzle run lint", "format": "npm --workspace @binkylabs/muzzle run format",