From eeee93e5d38f39ed76ab7d49ec0a5b3e9d7966f8 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 11 Oct 2024 14:13:24 -0700 Subject: [PATCH] TSPD exports support (#4700) --- ...tspd-exports-support-2024-9-11-17-14-36.md | 20 +++++++ packages/compiler/package.json | 1 + packages/events/package.json | 5 +- packages/http/package.json | 1 + packages/json-schema/package.json | 1 + packages/library-linter/package.json | 1 + packages/openapi/package.json | 1 + packages/openapi3/package.json | 1 + packages/protobuf/package.json | 6 ++- packages/rest/package.json | 1 + packages/spec-lib/package.json | 5 +- packages/sse/package.json | 5 +- packages/streams/package.json | 1 + .../gen-extern-signatures.ts | 52 +++++++++++++++++-- packages/tspd/src/ref-doc/lib.ts | 9 +++- packages/versioning/package.json | 1 + packages/xml/package.json | 5 +- 17 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 .chronus/changes/tspd-exports-support-2024-9-11-17-14-36.md diff --git a/.chronus/changes/tspd-exports-support-2024-9-11-17-14-36.md b/.chronus/changes/tspd-exports-support-2024-9-11-17-14-36.md new file mode 100644 index 0000000000..c20071ff0a --- /dev/null +++ b/.chronus/changes/tspd-exports-support-2024-9-11-17-14-36.md @@ -0,0 +1,20 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/compiler" + - "@typespec/events" + - "@typespec/http" + - "@typespec/json-schema" + - "@typespec/library-linter" + - "@typespec/openapi" + - "@typespec/openapi3" + - "@typespec/protobuf" + - "@typespec/rest" + - "@typespec/sse" + - "@typespec/streams" + - "@typespec/versioning" + - "@typespec/xml" +--- + +TSPD exports support diff --git a/packages/compiler/package.json b/packages/compiler/package.json index cd33e5d045..6acad5eb33 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -22,6 +22,7 @@ "tspMain": "lib/std/main.tsp", "exports": { ".": { + "typespec": "./lib/std/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/events/package.json b/packages/events/package.json index 4809f6ed4a..f345e04b93 100644 --- a/packages/events/package.json +++ b/packages/events/package.json @@ -20,7 +20,10 @@ "main": "dist/src/index.js", "tspMain": "lib/main.tsp", "exports": { - ".": "./dist/src/index.js", + ".": { + "typespec": "./lib/main.tsp", + "default": "./dist/src/index.js" + }, "./testing": "./dist/src/testing/index.js", "./experimental": { "types": "./dist/src/experimental/index.d.ts", diff --git a/packages/http/package.json b/packages/http/package.json index f93f4c73e4..8cf48f2a16 100644 --- a/packages/http/package.json +++ b/packages/http/package.json @@ -22,6 +22,7 @@ "tspMain": "lib/http.tsp", "exports": { ".": { + "typespec": "./lib/http.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/json-schema/package.json b/packages/json-schema/package.json index 7a16a21995..4d5eaeb5f6 100644 --- a/packages/json-schema/package.json +++ b/packages/json-schema/package.json @@ -21,6 +21,7 @@ "main": "dist/src/index.js", "exports": { ".": { + "typespec": "./lib/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/library-linter/package.json b/packages/library-linter/package.json index 87933fe21a..d48a30d252 100644 --- a/packages/library-linter/package.json +++ b/packages/library-linter/package.json @@ -20,6 +20,7 @@ "main": "dist/src/index.js", "exports": { ".": { + "typespec": "./dist/src/index.js", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/openapi/package.json b/packages/openapi/package.json index 677ad041d2..08f66fcaf3 100644 --- a/packages/openapi/package.json +++ b/packages/openapi/package.json @@ -21,6 +21,7 @@ "tspMain": "lib/main.tsp", "exports": { ".": { + "typespec": "./lib/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/openapi3/package.json b/packages/openapi3/package.json index f1cb0aabd8..d05a9ba6bd 100644 --- a/packages/openapi3/package.json +++ b/packages/openapi3/package.json @@ -24,6 +24,7 @@ "tspMain": "lib/main.tsp", "exports": { ".": { + "typespec": "./lib/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/protobuf/package.json b/packages/protobuf/package.json index 7948be3fdc..c3c5addcf4 100644 --- a/packages/protobuf/package.json +++ b/packages/protobuf/package.json @@ -20,7 +20,11 @@ ], "main": "dist/src/index.js", "exports": { - ".": "./dist/src/index.js", + ".": { + "typespec": "./lib/proto.tsp", + "types": "./dist/src/index.d.ts", + "default": "./dist/src/index.js" + }, "./testing": "./dist/src/testing/index.js" }, "type": "module", diff --git a/packages/rest/package.json b/packages/rest/package.json index 01f3099aaf..3127664e9a 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -21,6 +21,7 @@ "tspMain": "lib/rest.tsp", "exports": { ".": { + "typespec": "./lib/rest.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/spec-lib/package.json b/packages/spec-lib/package.json index e9466a9216..c0da8a477a 100644 --- a/packages/spec-lib/package.json +++ b/packages/spec-lib/package.json @@ -17,7 +17,10 @@ "main": "dist/index.js", "tspMain": "lib/lib.tsp", "exports": { - ".": "./dist/src/index.js" + ".": { + "typespec": "./lib/lib.tsp", + "default": "./dist/src/index.js" + } }, "engines": { "node": ">=16.0.0" diff --git a/packages/sse/package.json b/packages/sse/package.json index 02758fc372..a8384c404d 100644 --- a/packages/sse/package.json +++ b/packages/sse/package.json @@ -20,7 +20,10 @@ "main": "dist/src/index.js", "tspMain": "lib/main.tsp", "exports": { - ".": "./dist/src/index.js", + ".": { + "typespec": "./lib/main.tsp", + "default": "./dist/src/index.js" + }, "./testing": "./dist/src/testing/index.js" }, "engines": { diff --git a/packages/streams/package.json b/packages/streams/package.json index 0b705e35f9..a9e0a2b828 100644 --- a/packages/streams/package.json +++ b/packages/streams/package.json @@ -21,6 +21,7 @@ "tspMain": "lib/main.tsp", "exports": { ".": { + "typespec": "./lib/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/tspd/src/gen-extern-signatures/gen-extern-signatures.ts b/packages/tspd/src/gen-extern-signatures/gen-extern-signatures.ts index f2c74ad677..6ae44525cb 100644 --- a/packages/tspd/src/gen-extern-signatures/gen-extern-signatures.ts +++ b/packages/tspd/src/gen-extern-signatures/gen-extern-signatures.ts @@ -2,32 +2,74 @@ import { CompilerHost, Decorator, Diagnostic, + type PackageJson, Program, + type SourceLocation, compile, createDiagnosticCollector, + createSourceFile, getLocationContext, getTypeName, joinPaths, navigateProgram, resolvePath, - type PackageJson, } from "@typespec/compiler"; import prettier from "prettier"; +import { createDiagnostic } from "../ref-doc/lib.js"; import { generateSignatureTests, generateSignatures } from "./decorators-signatures.js"; import { DecoratorSignature } from "./types.js"; +function createSourceLocation(path: string): SourceLocation { + return { file: createSourceFile("", path), pos: 0, end: 0 }; +} export async function generateExternSignatures( host: CompilerHost, libraryPath: string, ): Promise { const diagnostics = createDiagnosticCollector(); const pkgJson = await readPackageJson(host, libraryPath); - if (!pkgJson.tspMain) { - throw new Error("Must have a tspMain with decorator declaration."); + if (!pkgJson.exports) { + return [ + createDiagnostic({ + code: "exports-missing", + target: createSourceLocation(resolvePath(libraryPath, "package.json")), + }), + ]; + } + + const exportsMap: Record = {}; + for (const [key, value] of Object.entries(pkgJson.exports)) { + if (typeof value === "object" && "typespec" in value && typeof value.typespec === "string") { + exportsMap[key] = resolvePath(libraryPath, value.typespec); + } + } + + const exports = Object.values(exportsMap); + if (exports.length > 0) { + diagnostics.pipe(await generateExternSignatureForExports(host, libraryPath, pkgJson, exports)); + } else { + diagnostics.add( + createDiagnostic({ + code: "exports-missing", + messageId: "missingCondition", + target: createSourceLocation(resolvePath(libraryPath, "package.json")), + }), + ); } - const main = resolvePath(libraryPath, pkgJson.tspMain); + return diagnostics.diagnostics; +} + +export async function generateExternSignatureForExports( + host: CompilerHost, + libraryPath: string, + pkgJson: PackageJson, + exports: string[], +): Promise<[undefined, readonly Diagnostic[]]> { + const [main, ...additionalImports] = exports; + const diagnostics = createDiagnosticCollector(); const program = await compile(host, main, { + additionalImports, parseOptions: { comments: true, docs: true }, }); const prettierConfig = await prettier.resolveConfig(libraryPath); @@ -42,7 +84,7 @@ export async function generateExternSignatures( for (const [name, content] of Object.entries(files)) { await host.writeFile(resolvePath(outDir, name), content); } - return diagnostics.diagnostics; + return [undefined, diagnostics.diagnostics]; } async function readPackageJson(host: CompilerHost, libraryPath: string): Promise { diff --git a/packages/tspd/src/ref-doc/lib.ts b/packages/tspd/src/ref-doc/lib.ts index 9874a0d281..482e4ce199 100644 --- a/packages/tspd/src/ref-doc/lib.ts +++ b/packages/tspd/src/ref-doc/lib.ts @@ -3,6 +3,13 @@ import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler"; export const libDef = { name: "@typespec/tspd", diagnostics: { + "exports-missing": { + severity: "error", + messages: { + default: `exports field is missing in package.json`, + missingCondition: `exports field is missing one export with the typespec condition`, + }, + }, "documentation-missing": { severity: "warning", messages: { @@ -22,6 +29,6 @@ export const libDef = { } as const; export const $lib = createTypeSpecLibrary(libDef); -export const { reportDiagnostic, createStateSymbol } = $lib; +export const { reportDiagnostic, createStateSymbol, createDiagnostic } = $lib; export type RefDocLibrary = typeof $lib; diff --git a/packages/versioning/package.json b/packages/versioning/package.json index 1a40afdcb3..5a8e3ad093 100644 --- a/packages/versioning/package.json +++ b/packages/versioning/package.json @@ -21,6 +21,7 @@ "tspMain": "lib/main.tsp", "exports": { ".": { + "typespec": "./lib/main.tsp", "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, diff --git a/packages/xml/package.json b/packages/xml/package.json index 271b7cb4ee..3068d17ed6 100644 --- a/packages/xml/package.json +++ b/packages/xml/package.json @@ -20,7 +20,10 @@ "main": "dist/src/index.js", "tspMain": "lib/main.tsp", "exports": { - ".": "./dist/src/index.js", + ".": { + "typespec": "./lib/main.tsp", + "default": "./dist/src/index.js" + }, "./testing": "./dist/src/testing/index.js" }, "engines": {