@contractkit/plugin-typescript 0.17.5 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
3
3
 
4
4
  // src/index.ts
5
5
  import { resolve as resolve2, join as join2, relative as relative6, dirname as dirname6, basename as basename3 } from "path";
6
+ import { existsSync, readFileSync, rmSync, readdirSync, rmdirSync } from "fs";
6
7
 
7
8
  // src/codegen-contract.ts
8
9
  import { relative, dirname } from "path";
@@ -1734,6 +1735,9 @@ function deriveTypeImportPath(file, template) {
1734
1735
  }
1735
1736
  __name(deriveTypeImportPath, "deriveTypeImportPath");
1736
1737
 
1738
+ // src/index.ts
1739
+ import { runIncrementalCodegen, parseIncrementalManifest, emptyIncrementalManifest, hashFingerprint, collectTransitiveModelRefs } from "@contractkit/core";
1740
+
1737
1741
  // src/codegen-sdk.ts
1738
1742
  import { resolveModifiers as resolveModifiers2, isJsonMime, classifyContentType as classifyContentType2 } from "@contractkit/core";
1739
1743
  import { basename as basename2, dirname as dirname3, relative as relative3 } from "path";
@@ -1798,7 +1802,7 @@ function generateSdk(root, options = {}) {
1798
1802
  const lines = [];
1799
1803
  const includeInternal = options.includeInternal ?? false;
1800
1804
  const types = collectTypes2(root, options.modelsWithInput, options.modelsWithOutput, includeInternal);
1801
- const clientClassName = deriveClientClassName(root.file);
1805
+ const clientClassName = options.clientClassName ?? deriveClientClassName(root.file);
1802
1806
  if (types.length > 0) {
1803
1807
  lines.push(...generateTypeImports2(types, root.file, options));
1804
1808
  }
@@ -1899,6 +1903,26 @@ function generateSdk(root, options = {}) {
1899
1903
  return lines.join("\n");
1900
1904
  }
1901
1905
  __name(generateSdk, "generateSdk");
1906
+ function generateClientMethods(root, options) {
1907
+ const lines = [];
1908
+ const methodNames = [];
1909
+ const includeInternal = options.includeInternal ?? false;
1910
+ for (const route of root.routes) {
1911
+ for (const op of route.operations) {
1912
+ const mods = resolveModifiers2(route, op);
1913
+ if (!includeInternal && mods.includes("internal")) continue;
1914
+ lines.push("");
1915
+ if (mods.includes("deprecated")) lines.push(" /** @deprecated */");
1916
+ lines.push(...generateMethod(route, op, root.file, options));
1917
+ methodNames.push(deriveMethodName(op, route));
1918
+ }
1919
+ }
1920
+ return {
1921
+ lines,
1922
+ methodNames
1923
+ };
1924
+ }
1925
+ __name(generateClientMethods, "generateClientMethods");
1902
1926
  function generateMethod(route, op, file, options) {
1903
1927
  const lines = [];
1904
1928
  const methodName = deriveMethodName(op, route);
@@ -2202,6 +2226,38 @@ function deriveClientPropertyName(file) {
2202
2226
  return base.charAt(0).toLowerCase() + base.slice(1);
2203
2227
  }
2204
2228
  __name(deriveClientPropertyName, "deriveClientPropertyName");
2229
+ function getAreaSubarea(root) {
2230
+ return {
2231
+ area: root.meta?.area,
2232
+ subarea: root.meta?.subarea
2233
+ };
2234
+ }
2235
+ __name(getAreaSubarea, "getAreaSubarea");
2236
+ function pascal(value) {
2237
+ return value.split(/[-_\s]+/).filter(Boolean).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
2238
+ }
2239
+ __name(pascal, "pascal");
2240
+ function camel(value) {
2241
+ const p = pascal(value);
2242
+ return p.charAt(0).toLowerCase() + p.slice(1);
2243
+ }
2244
+ __name(camel, "camel");
2245
+ function deriveAreaClientClassName(area) {
2246
+ return `${pascal(area)}Client`;
2247
+ }
2248
+ __name(deriveAreaClientClassName, "deriveAreaClientClassName");
2249
+ function deriveAreaPropertyName(area) {
2250
+ return camel(area);
2251
+ }
2252
+ __name(deriveAreaPropertyName, "deriveAreaPropertyName");
2253
+ function deriveSubareaClientClassName(area, subarea) {
2254
+ return `${pascal(area)}${pascal(subarea)}Client`;
2255
+ }
2256
+ __name(deriveSubareaClientClassName, "deriveSubareaClientClassName");
2257
+ function deriveSubareaPropertyName(subarea) {
2258
+ return camel(subarea);
2259
+ }
2260
+ __name(deriveSubareaPropertyName, "deriveSubareaPropertyName");
2205
2261
  function collectTypes2(root, modelsWithInput, modelsWithOutput, includeInternal = false) {
2206
2262
  const types = /* @__PURE__ */ new Set();
2207
2263
  for (const route of root.routes) {
@@ -2516,22 +2572,128 @@ function generateSdkOptions() {
2516
2572
  ].join("\n");
2517
2573
  }
2518
2574
  __name(generateSdkOptions, "generateSdkOptions");
2519
- function generateSdkAggregator(clients, sdkOptionsImportPath = "./sdk-options.js", sdkClassName = "Sdk") {
2575
+ function generateSdkAggregator(input) {
2576
+ const sdkOptionsImportPath = input.sdkOptionsImportPath ?? "./sdk-options.js";
2577
+ const sdkClassName = input.sdkClassName ?? "Sdk";
2578
+ const inlinedByArea = /* @__PURE__ */ new Map();
2579
+ const typesByImportPath = /* @__PURE__ */ new Map();
2580
+ const unresolvedTypes = /* @__PURE__ */ new Set();
2581
+ let needsJson = false;
2582
+ let needsBigIntReplacer = false;
2583
+ let needsBigIntReviver = false;
2584
+ let needsQueryString = false;
2585
+ for (const area of input.areas) {
2586
+ const collected = [];
2587
+ const seenMethods = /* @__PURE__ */ new Set();
2588
+ for (const inline of area.inlineFiles) {
2589
+ const includeInternal = inline.codegenOptions.includeInternal ?? false;
2590
+ const { lines: methodLines, methodNames } = generateClientMethods(inline.root, inline.codegenOptions);
2591
+ for (const name of methodNames) {
2592
+ if (seenMethods.has(name)) {
2593
+ throw new Error(`[sdk] duplicate method '${name}' in area '${area.area}': two area-level files contribute the same method. Disambiguate via 'sdk:' or move one into a subarea.`);
2594
+ }
2595
+ seenMethods.add(name);
2596
+ }
2597
+ collected.push(...methodLines);
2598
+ if (sdkNeedsJson(inline.root, includeInternal)) needsJson = true;
2599
+ if (sdkNeedsBigIntReplacer(inline.root, includeInternal)) needsBigIntReplacer = true;
2600
+ if (sdkNeedsBigIntReviver(inline.root, includeInternal)) needsBigIntReviver = true;
2601
+ if (sdkNeedsQueryString(inline.root, includeInternal)) needsQueryString = true;
2602
+ const typesForFile = collectTypes2(inline.root, inline.codegenOptions.modelsWithInput, inline.codegenOptions.modelsWithOutput, includeInternal);
2603
+ const { modelOutPaths, outPath } = inline.codegenOptions;
2604
+ if (modelOutPaths && outPath) {
2605
+ const fromDir = dirname3(outPath);
2606
+ for (const t of typesForFile) {
2607
+ const typeOutPath = modelOutPaths.get(t);
2608
+ if (typeOutPath) {
2609
+ let rel = relative3(fromDir, typeOutPath).replace(/\.ts$/, ".js");
2610
+ if (!rel.startsWith(".")) rel = "./" + rel;
2611
+ const set = typesByImportPath.get(rel) ?? /* @__PURE__ */ new Set();
2612
+ set.add(t);
2613
+ typesByImportPath.set(rel, set);
2614
+ } else {
2615
+ unresolvedTypes.add(t);
2616
+ }
2617
+ }
2618
+ }
2619
+ }
2620
+ inlinedByArea.set(area.area, {
2621
+ lines: collected,
2622
+ methodNames: seenMethods
2623
+ });
2624
+ }
2520
2625
  const lines = [];
2626
+ const jsonImport = needsJson ? ", JsonValue" : "";
2627
+ lines.push(`import type { SdkFetch${jsonImport} } from '${sdkOptionsImportPath}';`);
2628
+ const valueImports = [];
2629
+ if (needsBigIntReplacer) valueImports.push("bigIntReplacer");
2630
+ if (needsBigIntReviver) valueImports.push("parseJson");
2631
+ if (needsQueryString) valueImports.push("buildQueryString");
2632
+ if (valueImports.length > 0) {
2633
+ lines.push(`import { ${valueImports.join(", ")} } from '${sdkOptionsImportPath}';`);
2634
+ }
2521
2635
  lines.push(`import type { SdkOptions } from '${sdkOptionsImportPath}';`);
2522
2636
  lines.push(`import { createSdkFetch } from '${sdkOptionsImportPath}';`);
2523
- for (const c of clients) {
2637
+ const typeImportPaths = [
2638
+ ...typesByImportPath.keys()
2639
+ ].sort();
2640
+ for (const path of typeImportPaths) {
2641
+ const names = [
2642
+ ...typesByImportPath.get(path)
2643
+ ].sort();
2644
+ lines.push(`import type { ${names.join(", ")} } from '${path}';`);
2645
+ }
2646
+ for (const t of [
2647
+ ...unresolvedTypes
2648
+ ].sort()) {
2649
+ lines.push(`import type { ${t} } from './${pascalToDotCase(t)}.js';`);
2650
+ }
2651
+ const importedClients = /* @__PURE__ */ new Set();
2652
+ const pushClientImport = /* @__PURE__ */ __name((c) => {
2653
+ const key = `${c.className}|${c.importPath}`;
2654
+ if (importedClients.has(key)) return;
2655
+ importedClients.add(key);
2524
2656
  lines.push(`import { ${c.className} } from '${c.importPath}';`);
2657
+ }, "pushClientImport");
2658
+ for (const c of input.topLevelClients) pushClientImport(c);
2659
+ for (const area of input.areas) {
2660
+ for (const sc of area.subareaClients) pushClientImport(sc.client);
2525
2661
  }
2526
2662
  lines.push("");
2663
+ for (const area of input.areas) {
2664
+ const areaClassName = deriveAreaClientClassName(area.area);
2665
+ const inlined = inlinedByArea.get(area.area);
2666
+ lines.push(`class ${areaClassName} {`);
2667
+ for (const sc of area.subareaClients) {
2668
+ lines.push(` readonly ${sc.propertyName}: ${sc.client.className};`);
2669
+ }
2670
+ if (area.subareaClients.length > 0) lines.push("");
2671
+ if (inlined.lines.length > 0 || area.subareaClients.length > 0) {
2672
+ const fetchModifier = inlined.lines.length > 0 ? "private " : "";
2673
+ lines.push(` constructor(${fetchModifier}fetch: SdkFetch) {`);
2674
+ for (const sc of area.subareaClients) {
2675
+ lines.push(` this.${sc.propertyName} = new ${sc.client.className}(fetch);`);
2676
+ }
2677
+ lines.push(" }");
2678
+ }
2679
+ for (const ln of inlined.lines) lines.push(ln);
2680
+ lines.push("}");
2681
+ lines.push("");
2682
+ }
2527
2683
  lines.push(`export class ${sdkClassName} {`);
2528
- for (const c of clients) {
2684
+ for (const area of input.areas) {
2685
+ lines.push(` readonly ${deriveAreaPropertyName(area.area)}: ${deriveAreaClientClassName(area.area)};`);
2686
+ }
2687
+ for (const c of input.topLevelClients) {
2529
2688
  lines.push(` readonly ${c.propertyName}: ${c.className};`);
2530
2689
  }
2531
2690
  lines.push("");
2532
2691
  lines.push(" constructor(options: SdkOptions) {");
2533
2692
  lines.push(" const sdkFetch = options.fetch ?? createSdkFetch(options);");
2534
- for (const c of clients) {
2693
+ for (const area of input.areas) {
2694
+ lines.push(` this.${deriveAreaPropertyName(area.area)} = new ${deriveAreaClientClassName(area.area)}(sdkFetch);`);
2695
+ }
2696
+ for (const c of input.topLevelClients) {
2535
2697
  lines.push(` this.${c.propertyName} = new ${c.className}(sdkFetch);`);
2536
2698
  }
2537
2699
  lines.push(" }");
@@ -2945,19 +3107,149 @@ function computePubliclyReachableTypes(opAsts, contractAsts, modelsWithInput, mo
2945
3107
  __name(computePubliclyReachableTypes, "computePubliclyReachableTypes");
2946
3108
 
2947
3109
  // src/index.ts
2948
- function runServerGeneration(config, rootDir, inputs, emitFile) {
3110
+ var TYPESCRIPT_CODEGEN_VERSION = "1";
3111
+ var MANIFEST_FILENAME = ".contractkit-typescript-manifest.json";
3112
+ var plugin = {
3113
+ name: "typescript",
3114
+ async generateTargets(inputs, ctx) {
3115
+ const config = ctx.options;
3116
+ await runTypescriptCodegen(inputs, ctx, config, ctx.rootDir);
3117
+ }
3118
+ };
3119
+ var index_default = plugin;
3120
+ function createTypescriptPlugin(config, rootDir) {
3121
+ return {
3122
+ name: "typescript",
3123
+ async generateTargets(inputs, ctx) {
3124
+ await runTypescriptCodegen(inputs, ctx, config, rootDir);
3125
+ }
3126
+ };
3127
+ }
3128
+ __name(createTypescriptPlugin, "createTypescriptPlugin");
3129
+ async function runTypescriptCodegen(inputs, ctx, config, rootDir) {
3130
+ const manifestPath = resolve2(rootDir, MANIFEST_FILENAME);
3131
+ const prevManifest = ctx.cacheEnabled ? readManifest(manifestPath) : emptyIncrementalManifest(TYPESCRIPT_CODEGEN_VERSION);
3132
+ const units = [];
3133
+ const globalFiles = [];
3134
+ if (config.server) collectServerOutput(config.server, rootDir, inputs, units);
3135
+ if (config.sdk) collectSdkOutput(config.sdk, rootDir, inputs, units, globalFiles);
3136
+ if (config.zod) collectZodOutput(config.zod, rootDir, inputs, units);
3137
+ if (config.types) collectTypesOutput(config.types, rootDir, inputs, units);
3138
+ const result = runIncrementalCodegen({
3139
+ codegenVersion: TYPESCRIPT_CODEGEN_VERSION,
3140
+ manifestFilename: manifestPath,
3141
+ prevManifest,
3142
+ globalFiles,
3143
+ units,
3144
+ // Paths are absolute, so existsSync works directly.
3145
+ fileExists: existsSync
3146
+ });
3147
+ deleteStalePaths(result.deletedPaths);
3148
+ for (const { relativePath, content } of result.filesToWrite) {
3149
+ ctx.emitFile(relativePath, content);
3150
+ }
3151
+ }
3152
+ __name(runTypescriptCodegen, "runTypescriptCodegen");
3153
+ function buildModelMap(contractRoots) {
3154
+ const map = /* @__PURE__ */ new Map();
3155
+ for (const root of contractRoots) {
3156
+ for (const model of root.models) map.set(model.name, model);
3157
+ }
3158
+ return map;
3159
+ }
3160
+ __name(buildModelMap, "buildModelMap");
3161
+ function collectContractRootRefs(root, modelMap) {
3162
+ const seeds = [];
3163
+ for (const m of root.models) {
3164
+ if (m.type) seeds.push(m.type);
3165
+ for (const f of m.fields) seeds.push(f.type);
3166
+ if (m.bases) {
3167
+ for (const b of m.bases) seeds.push({
3168
+ kind: "ref",
3169
+ name: b
3170
+ });
3171
+ }
3172
+ }
3173
+ return collectTransitiveModelRefs(seeds, modelMap);
3174
+ }
3175
+ __name(collectContractRootRefs, "collectContractRootRefs");
3176
+ function collectOpRootRefs(root, modelMap) {
3177
+ const seeds = [];
3178
+ for (const route of root.routes) {
3179
+ if (route.params) seeds.push(...paramSourceTypes(route.params));
3180
+ for (const op of route.operations) {
3181
+ if (op.query) seeds.push(...paramSourceTypes(op.query));
3182
+ if (op.headers) seeds.push(...paramSourceTypes(op.headers));
3183
+ if (op.request) {
3184
+ for (const body of op.request.bodies) seeds.push(body.bodyType);
3185
+ }
3186
+ for (const resp of op.responses) {
3187
+ if (resp.bodyType) seeds.push(resp.bodyType);
3188
+ if (resp.headers) {
3189
+ for (const h of resp.headers) seeds.push(h.type);
3190
+ }
3191
+ }
3192
+ }
3193
+ }
3194
+ return collectTransitiveModelRefs(seeds, modelMap);
3195
+ }
3196
+ __name(collectOpRootRefs, "collectOpRootRefs");
3197
+ function paramSourceTypes(src) {
3198
+ const out = [];
3199
+ if (src.kind === "params") {
3200
+ for (const n of src.nodes) out.push(n.type);
3201
+ } else if (src.kind === "ref") {
3202
+ out.push({
3203
+ kind: "ref",
3204
+ name: src.name
3205
+ });
3206
+ } else if (src.kind === "type") {
3207
+ out.push(src.node);
3208
+ }
3209
+ return out;
3210
+ }
3211
+ __name(paramSourceTypes, "paramSourceTypes");
3212
+ function sliceOutPathMap(refs, modelOutPaths, modelsWithInput, modelsWithOutput) {
3213
+ const slice = {};
3214
+ for (const ref of [
3215
+ ...refs
3216
+ ].sort()) {
3217
+ const p = modelOutPaths.get(ref);
3218
+ if (p) slice[ref] = p;
3219
+ if (modelsWithInput.has(ref)) {
3220
+ const ip = modelOutPaths.get(`${ref}Input`);
3221
+ if (ip) slice[`${ref}Input`] = ip;
3222
+ }
3223
+ if (modelsWithOutput.has(ref)) {
3224
+ const op = modelOutPaths.get(`${ref}Output`);
3225
+ if (op) slice[`${ref}Output`] = op;
3226
+ }
3227
+ }
3228
+ return slice;
3229
+ }
3230
+ __name(sliceOutPathMap, "sliceOutPathMap");
3231
+ function sliceModelSet(refs, ownNames, set) {
3232
+ const result = [];
3233
+ for (const name of set) {
3234
+ if (refs.has(name) || ownNames.has(name)) result.push(name);
3235
+ }
3236
+ return result.sort();
3237
+ }
3238
+ __name(sliceModelSet, "sliceModelSet");
3239
+ function collectServerOutput(config, rootDir, inputs, units) {
2949
3240
  const serverBase = resolve2(rootDir, config.baseDir ?? ".");
2950
3241
  const modelsWithInput = inputs.modelsWithInput;
2951
3242
  const modelsWithOutput = inputs.modelsWithOutput;
3243
+ const modelMap = buildModelMap(inputs.contractRoots);
2952
3244
  const allFiles = [
2953
3245
  ...inputs.contractRoots.map((r) => r.file),
2954
3246
  ...inputs.opRoots.map((r) => r.file)
2955
3247
  ];
2956
3248
  const commonRoot = commonDir(allFiles, rootDir);
2957
- let serverModelOutPaths = /* @__PURE__ */ new Map();
3249
+ const subConfigKey = stableSubConfig(config);
3250
+ const serverModelOutPaths = /* @__PURE__ */ new Map();
3251
+ const typeEntries = [];
2958
3252
  if (config.output?.types) {
2959
- serverModelOutPaths = /* @__PURE__ */ new Map();
2960
- const typeEntries = [];
2961
3253
  for (const ast of inputs.contractRoots) {
2962
3254
  const typeOutPath = computeContractOutPath(ast.file, serverBase, config.output.types, ".ts", commonRoot, ast.meta);
2963
3255
  typeEntries.push({
@@ -2966,40 +3258,81 @@ function runServerGeneration(config, rootDir, inputs, emitFile) {
2966
3258
  });
2967
3259
  for (const model of ast.models) {
2968
3260
  serverModelOutPaths.set(model.name, typeOutPath);
2969
- if (modelsWithInput.has(model.name)) {
2970
- serverModelOutPaths.set(`${model.name}Input`, typeOutPath);
2971
- }
2972
- if (modelsWithOutput.has(model.name)) {
2973
- serverModelOutPaths.set(`${model.name}Output`, typeOutPath);
2974
- }
3261
+ if (modelsWithInput.has(model.name)) serverModelOutPaths.set(`${model.name}Input`, typeOutPath);
3262
+ if (modelsWithOutput.has(model.name)) serverModelOutPaths.set(`${model.name}Output`, typeOutPath);
2975
3263
  }
2976
3264
  }
2977
- for (const { ast, typeOutPath } of typeEntries) {
2978
- const ctx = {
2979
- modelOutPaths: serverModelOutPaths,
2980
- currentOutPath: typeOutPath,
2981
- modelsWithInput,
2982
- modelsWithOutput
2983
- };
2984
- const content = config.zod ? generateContract(ast, ctx) : generatePlainTypes(ast, ctx);
2985
- emitFile(typeOutPath, content);
2986
- }
3265
+ }
3266
+ for (const { ast, typeOutPath } of typeEntries) {
3267
+ const refs = collectContractRootRefs(ast, modelMap);
3268
+ const ownNames = new Set(ast.models.map((m) => m.name));
3269
+ const fingerprint = hashFingerprint({
3270
+ kind: "server-types",
3271
+ v: TYPESCRIPT_CODEGEN_VERSION,
3272
+ outPath: typeOutPath,
3273
+ root: ast,
3274
+ outPathSlice: sliceOutPathMap(refs, serverModelOutPaths, modelsWithInput, modelsWithOutput),
3275
+ modelsWithInput: sliceModelSet(refs, ownNames, modelsWithInput),
3276
+ modelsWithOutput: sliceModelSet(refs, ownNames, modelsWithOutput),
3277
+ sub: subConfigKey
3278
+ });
3279
+ units.push({
3280
+ key: `server-types::${typeOutPath}`,
3281
+ fingerprint,
3282
+ render: /* @__PURE__ */ __name(() => {
3283
+ const renderCtx = {
3284
+ modelOutPaths: serverModelOutPaths,
3285
+ currentOutPath: typeOutPath,
3286
+ modelsWithInput,
3287
+ modelsWithOutput
3288
+ };
3289
+ const content = config.zod ? generateContract(ast, renderCtx) : generatePlainTypes(ast, renderCtx);
3290
+ return [
3291
+ {
3292
+ relativePath: typeOutPath,
3293
+ content
3294
+ }
3295
+ ];
3296
+ }, "render")
3297
+ });
2987
3298
  }
2988
3299
  for (const ast of inputs.opRoots) {
2989
3300
  const outPath = computeOpOutPath(ast.file, serverBase, config.output?.routes, ".router.ts", commonRoot, ast.meta);
2990
- const content = generateOp(ast, {
2991
- servicePathTemplate: config.servicePathTemplate,
3301
+ const refs = collectOpRootRefs(ast, modelMap);
3302
+ const fingerprint = hashFingerprint({
3303
+ kind: "server-router",
3304
+ v: TYPESCRIPT_CODEGEN_VERSION,
2992
3305
  outPath,
2993
- modelOutPaths: serverModelOutPaths,
2994
- modelsWithInput,
2995
- modelsWithOutput,
2996
- includeInternal: config.includeInternal
3306
+ root: ast,
3307
+ // The router imports types from each contract root's type file; the slice covers exactly that.
3308
+ outPathSlice: sliceOutPathMap(refs, serverModelOutPaths, modelsWithInput, modelsWithOutput),
3309
+ modelsWithInput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithInput),
3310
+ modelsWithOutput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithOutput),
3311
+ servicePathTemplate: config.servicePathTemplate ?? null,
3312
+ includeInternal: config.includeInternal ?? true,
3313
+ sub: subConfigKey
3314
+ });
3315
+ units.push({
3316
+ key: `server-router::${outPath}`,
3317
+ fingerprint,
3318
+ render: /* @__PURE__ */ __name(() => [
3319
+ {
3320
+ relativePath: outPath,
3321
+ content: generateOp(ast, {
3322
+ servicePathTemplate: config.servicePathTemplate,
3323
+ outPath,
3324
+ modelOutPaths: serverModelOutPaths,
3325
+ modelsWithInput,
3326
+ modelsWithOutput,
3327
+ includeInternal: config.includeInternal
3328
+ })
3329
+ }
3330
+ ], "render")
2997
3331
  });
2998
- emitFile(outPath, content);
2999
3332
  }
3000
3333
  }
3001
- __name(runServerGeneration, "runServerGeneration");
3002
- function runSdkGeneration(config, rootDir, inputs, emitFile) {
3334
+ __name(collectServerOutput, "collectServerOutput");
3335
+ function collectSdkOutput(config, rootDir, inputs, units, globalFiles) {
3003
3336
  const sdkBase = config.baseDir ? resolve2(rootDir, config.baseDir) : rootDir;
3004
3337
  const sdkName = config.name;
3005
3338
  const sdkOutput = config.output?.sdk;
@@ -3007,20 +3340,21 @@ function runSdkGeneration(config, rootDir, inputs, emitFile) {
3007
3340
  name: sdkName ?? "sdk"
3008
3341
  }) : sdkOutput) : join2(sdkBase, "sdk.ts");
3009
3342
  const sdkOptionsPath = join2(dirname6(sdkEntryPath), "sdk-options.ts");
3343
+ const subConfigKey = stableSubConfig(config);
3010
3344
  const modelsWithInput = inputs.modelsWithInput;
3011
3345
  const modelsWithOutput = inputs.modelsWithOutput;
3346
+ const modelMap = buildModelMap(inputs.contractRoots);
3012
3347
  const allFiles = [
3013
3348
  ...inputs.contractRoots.map((r) => r.file),
3014
3349
  ...inputs.opRoots.map((r) => r.file)
3015
3350
  ];
3016
3351
  const ckCommonRoot = commonDir(allFiles, rootDir);
3017
- let sdkModelOutPaths = /* @__PURE__ */ new Map();
3352
+ const sdkModelOutPaths = /* @__PURE__ */ new Map();
3018
3353
  const sdkTypePaths = [];
3019
3354
  const sdkClientInfos = [];
3355
+ const sdkContractEntries = [];
3020
3356
  if (config.output?.types) {
3021
- sdkModelOutPaths = /* @__PURE__ */ new Map();
3022
3357
  const publicTypes = computePubliclyReachableTypes(inputs.opRoots, inputs.contractRoots, modelsWithInput, modelsWithOutput);
3023
- const sdkContractEntries = [];
3024
3358
  for (const ast of inputs.contractRoots) {
3025
3359
  const typeOutPath = computeSdkTypeOutPath(ast.file, sdkBase, config.output.types, ckCommonRoot, ast.meta);
3026
3360
  if (!typeOutPath) continue;
@@ -3036,74 +3370,240 @@ function runSdkGeneration(config, rootDir, inputs, emitFile) {
3036
3370
  if (modelsWithOutput.has(model.name)) sdkModelOutPaths.set(`${model.name}Output`, typeOutPath);
3037
3371
  }
3038
3372
  }
3039
- for (const { ast, typeOutPath } of sdkContractEntries) {
3040
- let content;
3041
- if (config.zod) {
3042
- content = generateContract(ast, {
3043
- modelOutPaths: sdkModelOutPaths,
3044
- currentOutPath: typeOutPath,
3045
- modelsWithInput,
3046
- modelsWithOutput
3047
- });
3048
- } else {
3049
- let rel = relative6(dirname6(typeOutPath), sdkOptionsPath).replace(/\.ts$/, ".js");
3050
- if (!rel.startsWith(".")) rel = "./" + rel;
3051
- content = generatePlainTypes(ast, {
3052
- modelOutPaths: sdkModelOutPaths,
3053
- currentOutPath: typeOutPath,
3054
- modelsWithInput,
3055
- modelsWithOutput,
3056
- jsonValueImportPath: rel
3057
- });
3058
- }
3059
- emitFile(typeOutPath, content);
3060
- }
3061
3373
  }
3374
+ for (const { ast, typeOutPath } of sdkContractEntries) {
3375
+ const refs = collectContractRootRefs(ast, modelMap);
3376
+ const ownNames = new Set(ast.models.map((m) => m.name));
3377
+ const fingerprint = hashFingerprint({
3378
+ kind: "sdk-types",
3379
+ v: TYPESCRIPT_CODEGEN_VERSION,
3380
+ outPath: typeOutPath,
3381
+ root: ast,
3382
+ outPathSlice: sliceOutPathMap(refs, sdkModelOutPaths, modelsWithInput, modelsWithOutput),
3383
+ modelsWithInput: sliceModelSet(refs, ownNames, modelsWithInput),
3384
+ modelsWithOutput: sliceModelSet(refs, ownNames, modelsWithOutput),
3385
+ sdkOptionsPath,
3386
+ sub: subConfigKey
3387
+ });
3388
+ units.push({
3389
+ key: `sdk-types::${typeOutPath}`,
3390
+ fingerprint,
3391
+ render: /* @__PURE__ */ __name(() => {
3392
+ let content;
3393
+ if (config.zod) {
3394
+ content = generateContract(ast, {
3395
+ modelOutPaths: sdkModelOutPaths,
3396
+ currentOutPath: typeOutPath,
3397
+ modelsWithInput,
3398
+ modelsWithOutput
3399
+ });
3400
+ } else {
3401
+ let rel = relative6(dirname6(typeOutPath), sdkOptionsPath).replace(/\.ts$/, ".js");
3402
+ if (!rel.startsWith(".")) rel = "./" + rel;
3403
+ content = generatePlainTypes(ast, {
3404
+ modelOutPaths: sdkModelOutPaths,
3405
+ currentOutPath: typeOutPath,
3406
+ modelsWithInput,
3407
+ modelsWithOutput,
3408
+ jsonValueImportPath: rel
3409
+ });
3410
+ }
3411
+ return [
3412
+ {
3413
+ relativePath: typeOutPath,
3414
+ content
3415
+ }
3416
+ ];
3417
+ }, "render")
3418
+ });
3419
+ }
3420
+ const areaBuckets = /* @__PURE__ */ new Map();
3421
+ const topLevelEntries = [];
3062
3422
  if (config.output?.clients) {
3063
3423
  for (const ast of inputs.opRoots) {
3064
3424
  const sdkOutPath = computeSdkOutPath(ast.file, sdkBase, config.output.clients, ckCommonRoot, ast.meta);
3065
3425
  if (!sdkOutPath || !hasPublicOperations(ast, config.includeInternal)) continue;
3426
+ const { area, subarea } = getAreaSubarea(ast);
3427
+ if (area && subarea) {
3428
+ const bucket = areaBuckets.get(area) ?? {
3429
+ leaves: [],
3430
+ inlineRoots: []
3431
+ };
3432
+ bucket.leaves.push({
3433
+ ast,
3434
+ outPath: sdkOutPath,
3435
+ subarea
3436
+ });
3437
+ areaBuckets.set(area, bucket);
3438
+ } else if (area) {
3439
+ const bucket = areaBuckets.get(area) ?? {
3440
+ leaves: [],
3441
+ inlineRoots: []
3442
+ };
3443
+ bucket.inlineRoots.push(ast);
3444
+ areaBuckets.set(area, bucket);
3445
+ } else {
3446
+ topLevelEntries.push({
3447
+ ast,
3448
+ outPath: sdkOutPath
3449
+ });
3450
+ }
3451
+ }
3452
+ for (const [area, bucket] of areaBuckets.entries()) {
3453
+ for (const leaf of bucket.leaves) {
3454
+ const className = deriveSubareaClientClassName(area, leaf.subarea);
3455
+ sdkClientInfos.push({
3456
+ outPath: leaf.outPath,
3457
+ className,
3458
+ propertyName: deriveSubareaPropertyName(leaf.subarea)
3459
+ });
3460
+ const refs = collectOpRootRefs(leaf.ast, modelMap);
3461
+ const fingerprint = hashFingerprint({
3462
+ kind: "sdk-leaf-client",
3463
+ v: TYPESCRIPT_CODEGEN_VERSION,
3464
+ outPath: leaf.outPath,
3465
+ root: leaf.ast,
3466
+ outPathSlice: sliceOutPathMap(refs, sdkModelOutPaths, modelsWithInput, modelsWithOutput),
3467
+ modelsWithInput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithInput),
3468
+ modelsWithOutput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithOutput),
3469
+ sdkOptionsPath,
3470
+ className,
3471
+ includeInternal: config.includeInternal ?? false,
3472
+ sub: subConfigKey
3473
+ });
3474
+ units.push({
3475
+ key: `sdk-leaf-client::${leaf.outPath}`,
3476
+ fingerprint,
3477
+ render: /* @__PURE__ */ __name(() => [
3478
+ {
3479
+ relativePath: leaf.outPath,
3480
+ content: generateSdk(leaf.ast, {
3481
+ typeImportPathTemplate: void 0,
3482
+ outPath: leaf.outPath,
3483
+ modelOutPaths: sdkModelOutPaths,
3484
+ sdkOptionsPath,
3485
+ modelsWithInput,
3486
+ modelsWithOutput,
3487
+ includeInternal: config.includeInternal,
3488
+ clientClassName: className
3489
+ })
3490
+ }
3491
+ ], "render")
3492
+ });
3493
+ }
3494
+ }
3495
+ for (const { ast, outPath } of topLevelEntries) {
3496
+ const className = deriveClientClassName(ast.file);
3066
3497
  sdkClientInfos.push({
3067
- outPath: sdkOutPath,
3068
- className: deriveClientClassName(ast.file),
3498
+ outPath,
3499
+ className,
3069
3500
  propertyName: deriveClientPropertyName(ast.file)
3070
3501
  });
3071
- emitFile(sdkOutPath, generateSdk(ast, {
3072
- typeImportPathTemplate: void 0,
3073
- outPath: sdkOutPath,
3074
- modelOutPaths: sdkModelOutPaths,
3502
+ const refs = collectOpRootRefs(ast, modelMap);
3503
+ const fingerprint = hashFingerprint({
3504
+ kind: "sdk-top-client",
3505
+ v: TYPESCRIPT_CODEGEN_VERSION,
3506
+ outPath,
3507
+ root: ast,
3508
+ outPathSlice: sliceOutPathMap(refs, sdkModelOutPaths, modelsWithInput, modelsWithOutput),
3509
+ modelsWithInput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithInput),
3510
+ modelsWithOutput: sliceModelSet(refs, /* @__PURE__ */ new Set(), modelsWithOutput),
3075
3511
  sdkOptionsPath,
3076
- modelsWithInput,
3077
- modelsWithOutput,
3078
- includeInternal: config.includeInternal
3079
- }));
3512
+ includeInternal: config.includeInternal ?? false,
3513
+ sub: subConfigKey
3514
+ });
3515
+ units.push({
3516
+ key: `sdk-top-client::${outPath}`,
3517
+ fingerprint,
3518
+ render: /* @__PURE__ */ __name(() => [
3519
+ {
3520
+ relativePath: outPath,
3521
+ content: generateSdk(ast, {
3522
+ typeImportPathTemplate: void 0,
3523
+ outPath,
3524
+ modelOutPaths: sdkModelOutPaths,
3525
+ sdkOptionsPath,
3526
+ modelsWithInput,
3527
+ modelsWithOutput,
3528
+ includeInternal: config.includeInternal
3529
+ })
3530
+ }
3531
+ ], "render")
3532
+ });
3080
3533
  }
3081
3534
  }
3082
- emitFile(sdkOptionsPath, generateSdkOptions());
3083
- if (sdkClientInfos.length > 0) {
3535
+ globalFiles.push({
3536
+ relativePath: sdkOptionsPath,
3537
+ content: generateSdkOptions()
3538
+ });
3539
+ const hasAnything = sdkClientInfos.length > 0 || areaBuckets.size > 0;
3540
+ if (hasAnything) {
3084
3541
  const sdkEntryDir = dirname6(sdkEntryPath);
3085
- const clients = sdkClientInfos.map((c) => {
3086
- let rel = relative6(sdkEntryDir, c.outPath).replace(/\.ts$/, ".js");
3542
+ const sdkOptionsRel = relative6(sdkEntryDir, sdkOptionsPath).replace(/\.ts$/, ".js");
3543
+ const sdkOptionsImportPath = sdkOptionsRel.startsWith(".") ? sdkOptionsRel : "./" + sdkOptionsRel;
3544
+ const sdkClassName = sdkName ? sdkName.split(/[-._\s]+/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") + "Sdk" : "Sdk";
3545
+ const toClientImport = /* @__PURE__ */ __name((info) => {
3546
+ let rel = relative6(sdkEntryDir, info.outPath).replace(/\.ts$/, ".js");
3087
3547
  if (!rel.startsWith(".")) rel = "./" + rel;
3088
3548
  return {
3089
- className: c.className,
3090
- propertyName: c.propertyName,
3549
+ className: info.className,
3550
+ propertyName: info.propertyName,
3091
3551
  importPath: rel
3092
3552
  };
3553
+ }, "toClientImport");
3554
+ const topLevelClients = topLevelEntries.map((e) => ({
3555
+ className: deriveClientClassName(e.ast.file),
3556
+ propertyName: deriveClientPropertyName(e.ast.file),
3557
+ importPath: (() => {
3558
+ const rel = relative6(sdkEntryDir, e.outPath).replace(/\.ts$/, ".js");
3559
+ return rel.startsWith(".") ? rel : "./" + rel;
3560
+ })()
3561
+ }));
3562
+ const areas = [
3563
+ ...areaBuckets.entries()
3564
+ ].sort(([a], [b]) => a.localeCompare(b)).map(([area, bucket]) => ({
3565
+ area,
3566
+ inlineFiles: bucket.inlineRoots.map((root) => ({
3567
+ root,
3568
+ codegenOptions: {
3569
+ typeImportPathTemplate: void 0,
3570
+ outPath: sdkEntryPath,
3571
+ modelOutPaths: sdkModelOutPaths,
3572
+ sdkOptionsPath,
3573
+ modelsWithInput,
3574
+ modelsWithOutput,
3575
+ includeInternal: config.includeInternal
3576
+ }
3577
+ })),
3578
+ subareaClients: bucket.leaves.sort((a, b) => a.subarea.localeCompare(b.subarea)).map((l) => ({
3579
+ propertyName: deriveSubareaPropertyName(l.subarea),
3580
+ client: toClientImport({
3581
+ outPath: l.outPath,
3582
+ className: deriveSubareaClientClassName(area, l.subarea),
3583
+ propertyName: deriveSubareaPropertyName(l.subarea)
3584
+ })
3585
+ }))
3586
+ }));
3587
+ globalFiles.push({
3588
+ relativePath: sdkEntryPath,
3589
+ content: generateSdkAggregator({
3590
+ topLevelClients,
3591
+ areas,
3592
+ sdkOptionsImportPath,
3593
+ sdkClassName
3594
+ })
3093
3595
  });
3094
- const sdkOptionsRel = relative6(sdkEntryDir, sdkOptionsPath).replace(/\.ts$/, ".js");
3095
- const sdkClassName = sdkName ? sdkName.split(/[-._\s]+/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("") + "Sdk" : "Sdk";
3096
- emitFile(sdkEntryPath, generateSdkAggregator(clients, sdkOptionsRel.startsWith(".") ? sdkOptionsRel : "./" + sdkOptionsRel, sdkClassName));
3097
3596
  }
3098
3597
  const sdkSrcDir = dirname6(sdkEntryPath);
3099
3598
  const sdkTypeBarrels = generateBarrelFiles(sdkTypePaths);
3100
- for (const barrel of sdkTypeBarrels) emitFile(barrel.outPath, barrel.content);
3599
+ for (const barrel of sdkTypeBarrels) globalFiles.push({
3600
+ relativePath: barrel.outPath,
3601
+ content: barrel.content
3602
+ });
3101
3603
  const rootExports = [
3102
3604
  `export * from './${basename3(sdkOptionsPath).replace(/\.ts$/, ".js")}';`
3103
3605
  ];
3104
- if (sdkClientInfos.length > 0) {
3105
- rootExports.push(`export * from './${basename3(sdkEntryPath).replace(/\.ts$/, ".js")}';`);
3106
- }
3606
+ if (hasAnything) rootExports.push(`export * from './${basename3(sdkEntryPath).replace(/\.ts$/, ".js")}';`);
3107
3607
  for (const c of sdkClientInfos) {
3108
3608
  let rel = relative6(sdkSrcDir, c.outPath).replace(/\.ts$/, ".js");
3109
3609
  if (!rel.startsWith(".")) rel = "./" + rel;
@@ -3114,12 +3614,15 @@ function runSdkGeneration(config, rootDir, inputs, emitFile) {
3114
3614
  if (!rel.startsWith(".")) rel = "./" + rel;
3115
3615
  rootExports.push(`export * from '${rel}';`);
3116
3616
  }
3117
- emitFile(join2(sdkSrcDir, "index.ts"), `// Auto-generated barrel file
3617
+ globalFiles.push({
3618
+ relativePath: join2(sdkSrcDir, "index.ts"),
3619
+ content: `// Auto-generated barrel file
3118
3620
  ${rootExports.sort().join("\n")}
3119
- `);
3621
+ `
3622
+ });
3120
3623
  }
3121
- __name(runSdkGeneration, "runSdkGeneration");
3122
- function runZodGeneration(config, rootDir, inputs, emitFile) {
3624
+ __name(collectSdkOutput, "collectSdkOutput");
3625
+ function collectZodOutput(config, rootDir, inputs, units) {
3123
3626
  const zodBase = resolve2(rootDir, config.baseDir ?? ".");
3124
3627
  const allFiles = [
3125
3628
  ...inputs.contractRoots.map((r) => r.file),
@@ -3128,6 +3631,8 @@ function runZodGeneration(config, rootDir, inputs, emitFile) {
3128
3631
  const commonRoot = commonDir(allFiles, rootDir);
3129
3632
  const modelsWithInput = inputs.modelsWithInput;
3130
3633
  const modelsWithOutput = inputs.modelsWithOutput;
3634
+ const modelMap = buildModelMap(inputs.contractRoots);
3635
+ const subConfigKey = stableSubConfig(config);
3131
3636
  const modelOutPaths = /* @__PURE__ */ new Map();
3132
3637
  const entries = [];
3133
3638
  for (const ast of inputs.contractRoots) {
@@ -3143,17 +3648,37 @@ function runZodGeneration(config, rootDir, inputs, emitFile) {
3143
3648
  }
3144
3649
  }
3145
3650
  for (const { ast, outPath } of entries) {
3146
- const content = generateContract(ast, {
3147
- modelOutPaths,
3148
- currentOutPath: outPath,
3149
- modelsWithInput,
3150
- modelsWithOutput
3651
+ const refs = collectContractRootRefs(ast, modelMap);
3652
+ const ownNames = new Set(ast.models.map((m) => m.name));
3653
+ const fingerprint = hashFingerprint({
3654
+ kind: "zod",
3655
+ v: TYPESCRIPT_CODEGEN_VERSION,
3656
+ outPath,
3657
+ root: ast,
3658
+ outPathSlice: sliceOutPathMap(refs, modelOutPaths, modelsWithInput, modelsWithOutput),
3659
+ modelsWithInput: sliceModelSet(refs, ownNames, modelsWithInput),
3660
+ modelsWithOutput: sliceModelSet(refs, ownNames, modelsWithOutput),
3661
+ sub: subConfigKey
3662
+ });
3663
+ units.push({
3664
+ key: `zod::${outPath}`,
3665
+ fingerprint,
3666
+ render: /* @__PURE__ */ __name(() => [
3667
+ {
3668
+ relativePath: outPath,
3669
+ content: generateContract(ast, {
3670
+ modelOutPaths,
3671
+ currentOutPath: outPath,
3672
+ modelsWithInput,
3673
+ modelsWithOutput
3674
+ })
3675
+ }
3676
+ ], "render")
3151
3677
  });
3152
- emitFile(outPath, content);
3153
3678
  }
3154
3679
  }
3155
- __name(runZodGeneration, "runZodGeneration");
3156
- function runTypesGeneration(config, rootDir, inputs, emitFile) {
3680
+ __name(collectZodOutput, "collectZodOutput");
3681
+ function collectTypesOutput(config, rootDir, inputs, units) {
3157
3682
  const typesBase = resolve2(rootDir, config.baseDir ?? ".");
3158
3683
  const allFiles = [
3159
3684
  ...inputs.contractRoots.map((r) => r.file),
@@ -3162,6 +3687,8 @@ function runTypesGeneration(config, rootDir, inputs, emitFile) {
3162
3687
  const commonRoot = commonDir(allFiles, rootDir);
3163
3688
  const modelsWithInput = inputs.modelsWithInput;
3164
3689
  const modelsWithOutput = inputs.modelsWithOutput;
3690
+ const modelMap = buildModelMap(inputs.contractRoots);
3691
+ const subConfigKey = stableSubConfig(config);
3165
3692
  const modelOutPaths = /* @__PURE__ */ new Map();
3166
3693
  const entries = [];
3167
3694
  for (const ast of inputs.contractRoots) {
@@ -3177,58 +3704,79 @@ function runTypesGeneration(config, rootDir, inputs, emitFile) {
3177
3704
  }
3178
3705
  }
3179
3706
  for (const { ast, outPath } of entries) {
3180
- const content = generatePlainTypes(ast, {
3181
- modelOutPaths,
3182
- currentOutPath: outPath,
3183
- modelsWithInput,
3184
- modelsWithOutput
3707
+ const refs = collectContractRootRefs(ast, modelMap);
3708
+ const ownNames = new Set(ast.models.map((m) => m.name));
3709
+ const fingerprint = hashFingerprint({
3710
+ kind: "plain-types",
3711
+ v: TYPESCRIPT_CODEGEN_VERSION,
3712
+ outPath,
3713
+ root: ast,
3714
+ outPathSlice: sliceOutPathMap(refs, modelOutPaths, modelsWithInput, modelsWithOutput),
3715
+ modelsWithInput: sliceModelSet(refs, ownNames, modelsWithInput),
3716
+ modelsWithOutput: sliceModelSet(refs, ownNames, modelsWithOutput),
3717
+ sub: subConfigKey
3718
+ });
3719
+ units.push({
3720
+ key: `plain-types::${outPath}`,
3721
+ fingerprint,
3722
+ render: /* @__PURE__ */ __name(() => [
3723
+ {
3724
+ relativePath: outPath,
3725
+ content: generatePlainTypes(ast, {
3726
+ modelOutPaths,
3727
+ currentOutPath: outPath,
3728
+ modelsWithInput,
3729
+ modelsWithOutput
3730
+ })
3731
+ }
3732
+ ], "render")
3185
3733
  });
3186
- emitFile(outPath, content);
3187
3734
  }
3188
3735
  }
3189
- __name(runTypesGeneration, "runTypesGeneration");
3190
- var plugin = {
3191
- name: "typescript",
3192
- cacheKey: "typescript",
3193
- async generateTargets(inputs, ctx) {
3194
- const config = ctx.options;
3195
- if (config.server) {
3196
- runServerGeneration(config.server, ctx.rootDir, inputs, ctx.emitFile.bind(ctx));
3197
- }
3198
- if (config.sdk) {
3199
- runSdkGeneration(config.sdk, ctx.rootDir, inputs, ctx.emitFile.bind(ctx));
3200
- }
3201
- if (config.zod) {
3202
- runZodGeneration(config.zod, ctx.rootDir, inputs, ctx.emitFile.bind(ctx));
3203
- }
3204
- if (config.types) {
3205
- runTypesGeneration(config.types, ctx.rootDir, inputs, ctx.emitFile.bind(ctx));
3736
+ __name(collectTypesOutput, "collectTypesOutput");
3737
+ function readManifest(manifestPath) {
3738
+ if (!existsSync(manifestPath)) return emptyIncrementalManifest(TYPESCRIPT_CODEGEN_VERSION);
3739
+ try {
3740
+ return parseIncrementalManifest(readFileSync(manifestPath, "utf-8"));
3741
+ } catch {
3742
+ return emptyIncrementalManifest(TYPESCRIPT_CODEGEN_VERSION);
3743
+ }
3744
+ }
3745
+ __name(readManifest, "readManifest");
3746
+ function deleteStalePaths(absPaths) {
3747
+ if (absPaths.length === 0) return;
3748
+ const removedDirs = /* @__PURE__ */ new Set();
3749
+ for (const abs of absPaths) {
3750
+ if (existsSync(abs)) {
3751
+ rmSync(abs, {
3752
+ force: true
3753
+ });
3754
+ removedDirs.add(dirname6(abs));
3206
3755
  }
3207
3756
  }
3208
- };
3209
- var index_default = plugin;
3210
- function createTypescriptPlugin(config, rootDir) {
3211
- return {
3212
- name: "typescript",
3213
- cacheKey: `typescript:${JSON.stringify(config)}`,
3214
- async generateTargets(inputs, ctx) {
3215
- if (config.server) {
3216
- runServerGeneration(config.server, rootDir, inputs, ctx.emitFile.bind(ctx));
3217
- }
3218
- if (config.sdk) {
3219
- runSdkGeneration(config.sdk, rootDir, inputs, ctx.emitFile.bind(ctx));
3220
- }
3221
- if (config.zod) {
3222
- runZodGeneration(config.zod, rootDir, inputs, ctx.emitFile.bind(ctx));
3223
- }
3224
- if (config.types) {
3225
- runTypesGeneration(config.types, rootDir, inputs, ctx.emitFile.bind(ctx));
3757
+ for (const dir of removedDirs) {
3758
+ let current = dir;
3759
+ while (current.length > 1) {
3760
+ try {
3761
+ if (readdirSync(current).length === 0) {
3762
+ rmdirSync(current);
3763
+ current = dirname6(current);
3764
+ } else {
3765
+ break;
3766
+ }
3767
+ } catch {
3768
+ break;
3226
3769
  }
3227
3770
  }
3228
- };
3771
+ }
3229
3772
  }
3230
- __name(createTypescriptPlugin, "createTypescriptPlugin");
3773
+ __name(deleteStalePaths, "deleteStalePaths");
3774
+ function stableSubConfig(config) {
3775
+ return JSON.stringify(config ?? null);
3776
+ }
3777
+ __name(stableSubConfig, "stableSubConfig");
3231
3778
  export {
3779
+ TYPESCRIPT_CODEGEN_VERSION,
3232
3780
  createTypescriptPlugin,
3233
3781
  index_default as default
3234
3782
  };