@tsdoctor/vfs 0.4.7 → 0.5.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/TsEnvironment.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isTypeDefinition } from "./Vfs.js";
2
2
  import { Effect, Schema } from "effect";
3
3
 
4
- //#region src/TsEnvironment.ts
4
+ // src/TsEnvironment.ts
5
5
  /**
6
6
  * Raised when building a virtual TypeScript environment fails — including
7
7
  * when the optional `typescript` / `@typescript/vfs` /
@@ -91,5 +91,4 @@ var TsEnvironment = class {
91
91
  }
92
92
  };
93
93
 
94
- //#endregion
95
94
  export { TsEnvironment, TsEnvironmentError };
package/TsconfigParser.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { decodeCompilerOptions } from "./TypeResolutionOptions.js";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import path from "node:path";
4
+ import { ErrorText } from "@effected/engine";
4
5
  import { TsconfigLoaderSync } from "@effected/tsconfig-json";
5
6
  import { Result } from "effect";
6
7
 
7
- //#region src/TsconfigParser.ts
8
+ // src/TsconfigParser.ts
8
9
  /**
9
10
  * Reading a `tsconfig.json` into the compiler options the plugin consumes.
10
11
  *
@@ -87,12 +88,11 @@ function parseTsConfig(configPath, projectRoot) {
87
88
  try {
88
89
  options = TsconfigLoaderSync.compilerOptions(absolutePath, syncHost);
89
90
  } catch (error) {
90
- throw new TsConfigParseError(absolutePath, error instanceof Error ? error.message : String(error), error);
91
+ throw new TsConfigParseError(absolutePath, ErrorText.describe(error), error);
91
92
  }
92
93
  const decoded = decodeCompilerOptions(options);
93
94
  if (Result.isFailure(decoded)) throw new TsConfigParseError(absolutePath, decoded.failure.message, decoded.failure);
94
95
  return decoded.success;
95
96
  }
96
97
 
97
- //#endregion
98
98
  export { TsConfigParseError, parseTsConfig };
package/TwoslashCache.js CHANGED
@@ -1,7 +1,9 @@
1
+ import { Result } from "effect";
1
2
  import { createHash } from "node:crypto";
2
3
  import { gunzipSync, gzipSync } from "node:zlib";
4
+ import { JsoncCanonicalizeOptions, JsoncFingerprint } from "@effected/jsonc";
3
5
 
4
- //#region src/TwoslashCache.ts
6
+ // src/TwoslashCache.ts
5
7
  /**
6
8
  * Persisted Twoslash result cache.
7
9
  *
@@ -62,10 +64,16 @@ import { gunzipSync, gzipSync } from "node:zlib";
62
64
  *
63
65
  * @public
64
66
  */
65
- const TWOSLASH_CACHE_FORMAT = 1;
66
- function sha256(input) {
67
- return createHash("sha256").update(input).digest("hex");
68
- }
67
+ const TWOSLASH_CACHE_FORMAT = 2;
68
+ const digest = (bytes) => createHash("sha256").update(bytes).digest();
69
+ /**
70
+ * Compiler options are TypeScript's own plain JSON shape, but a member may be
71
+ * present and `undefined`; those are omitted, as `JSON.stringify` would.
72
+ */
73
+ const COMPILER_OPTIONS_CANONICALIZATION = JsoncCanonicalizeOptions.make({
74
+ undefined: "omit",
75
+ nonFinite: "null"
76
+ });
69
77
  /**
70
78
  * Fingerprint the type environment a generation is checked against.
71
79
  *
@@ -88,28 +96,31 @@ function sha256(input) {
88
96
  */
89
97
  function twoslashEnvHash(vfs, toolchain) {
90
98
  const hash = createHash("sha256");
91
- hash.update(`format:${1}\0toolchain:${toolchain}\0`);
99
+ hash.update(`format:${2}\0toolchain:${toolchain}\0`);
92
100
  for (const key of [...vfs.keys()].sort()) hash.update(`${key}\0${vfs.get(key) ?? ""}\0`);
93
101
  return hash.digest("hex");
94
102
  }
95
- /** JSON with object keys sorted, so equivalent options hash identically. */
96
- function stableStringify(value) {
97
- if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
98
- if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
99
- return `{${Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
100
- }
101
103
  /**
102
104
  * Per-entry key: the code, its language, and the compiler configuration it is
103
105
  * checked under.
104
106
  *
105
107
  * The configuration matters because two APIs on one site may be documented
106
108
  * under different `tsconfig`s — the same source checked under different options
107
- * can produce different types, so it must not share a cache entry.
109
+ * can produce different types, so it must not share a cache entry. The options
110
+ * are folded in through their RFC 8785 canonical form, so key order does not
111
+ * matter.
112
+ *
113
+ * Returns `undefined` when the options cannot be canonicalized (a function or a
114
+ * non-plain object among them): such a block is not cached, rather than keyed
115
+ * on a spelling that could collide with different options.
108
116
  *
109
117
  * @public
110
118
  */
111
119
  function twoslashEntryKey(code, lang, compilerOptions) {
112
- return sha256(`${lang ?? "ts"}\0${stableStringify(compilerOptions ?? {})}\0${code}`);
120
+ const options = JsoncFingerprint.canonicalizeResult(compilerOptions ?? {}, COMPILER_OPTIONS_CANONICALIZATION);
121
+ if (Result.isFailure(options)) return void 0;
122
+ const key = JsoncFingerprint.hashTextResult(`${lang ?? "ts"}\0${options.success}\0${code}`, digest);
123
+ return Result.isSuccess(key) ? key.success : void 0;
113
124
  }
114
125
  /**
115
126
  * The cache key a whole generation is stored under. One blob per environment,
@@ -118,7 +129,7 @@ function twoslashEntryKey(code, lang, compilerOptions) {
118
129
  * @public
119
130
  */
120
131
  function twoslashBlobKey(envHash) {
121
- return `twoslash/v${1}/${envHash}`;
132
+ return `twoslash/v${2}/${envHash}`;
122
133
  }
123
134
  /**
124
135
  * Build a synchronous Twoslash cache over an in-memory map, optionally seeded
@@ -133,7 +144,8 @@ function makeTwoslashCache(initial) {
133
144
  let dirty = false;
134
145
  return {
135
146
  read: (code, lang, options) => {
136
- const found = map.get(twoslashEntryKey(code, lang, options?.compilerOptions));
147
+ const key = twoslashEntryKey(code, lang, options?.compilerOptions);
148
+ const found = key === void 0 ? void 0 : map.get(key);
137
149
  if (found === void 0) {
138
150
  misses += 1;
139
151
  return null;
@@ -142,12 +154,14 @@ function makeTwoslashCache(initial) {
142
154
  return found;
143
155
  },
144
156
  write: (code, data, lang, options) => {
157
+ const key = twoslashEntryKey(code, lang, options?.compilerOptions);
158
+ if (key === void 0) return;
145
159
  const value = {
146
160
  nodes: data.nodes,
147
161
  code: data.code,
148
162
  ...data.meta?.extension != null ? { meta: { extension: data.meta.extension } } : {}
149
163
  };
150
- map.set(twoslashEntryKey(code, lang, options?.compilerOptions), value);
164
+ map.set(key, value);
151
165
  dirty = true;
152
166
  },
153
167
  stats: () => ({
@@ -184,5 +198,4 @@ function decodeTwoslashCache(blob) {
184
198
  }
185
199
  }
186
200
 
187
- //#endregion
188
201
  export { TWOSLASH_CACHE_FORMAT, decodeTwoslashCache, encodeTwoslashCache, makeTwoslashCache, twoslashBlobKey, twoslashEntryKey, twoslashEnvHash };
@@ -1,7 +1,7 @@
1
1
  import { CompilerOptions, CompilerOptionsFromProgrammatic, TsEnumCodec } from "@effected/tsconfig-json";
2
2
  import { Result, Schema } from "effect";
3
3
 
4
- //#region src/TypeResolutionOptions.ts
4
+ // src/TypeResolutionOptions.ts
5
5
  const fields = CompilerOptions.schema.fields;
6
6
  /**
7
7
  * The compiler options that may influence how a documentation example
@@ -94,5 +94,4 @@ const decodeCompilerOptions = (input) => Result.map(Schema.decodeUnknownResult(C
94
94
  */
95
95
  const toProgrammaticCompilerOptions = (options) => TsEnumCodec.encodeCompilerOptions(options);
96
96
 
97
- //#endregion
98
97
  export { TypeResolutionCompilerOptions, decodeCompilerOptions, toProgrammaticCompilerOptions };
@@ -1,8 +1,9 @@
1
1
  import { decodeCompilerOptions } from "./TypeResolutionOptions.js";
2
2
  import { TsConfigParseError, parseTsConfig } from "./TsconfigParser.js";
3
+ import { ErrorText } from "@effected/engine";
3
4
  import { Result } from "effect";
4
5
 
5
- //#region src/TypeScriptConfig.ts
6
+ // src/TypeScriptConfig.ts
6
7
  /**
7
8
  * Default TypeScript compiler options for Twoslash and type resolution.
8
9
  *
@@ -120,7 +121,7 @@ function resolveTypeScriptConfigSingle(config, projectRoot) {
120
121
  options = parseTsConfig(tsconfigPath, projectRoot);
121
122
  } catch (error) {
122
123
  if (error instanceof TsConfigParseError) throw error;
123
- throw new TsConfigParseError(tsconfigPath, error instanceof Error ? error.message : String(error), error);
124
+ throw new TsConfigParseError(tsconfigPath, ErrorText.describe(error), error);
124
125
  }
125
126
  }
126
127
  if (config.compilerOptions) options = mergeCompilerOptions(options, decodeInput(config.compilerOptions, "compilerOptions"));
@@ -168,7 +169,7 @@ async function resolveTypeScriptConfigSingleAsync(config, projectRoot) {
168
169
  options = parseTsConfig(tsconfigPath, projectRoot);
169
170
  } catch (error) {
170
171
  if (error instanceof TsConfigParseError) throw error;
171
- throw new TsConfigParseError(tsconfigPath, error instanceof Error ? error.message : String(error), error);
172
+ throw new TsConfigParseError(tsconfigPath, ErrorText.describe(error), error);
172
173
  }
173
174
  }
174
175
  }
@@ -222,5 +223,4 @@ async function resolveTypeScriptConfig(projectRoot, global, api) {
222
223
  return options;
223
224
  }
224
225
 
225
- //#endregion
226
226
  export { DEFAULT_COMPILER_OPTIONS, mergeCompilerOptions, resolveTypeScriptConfig, resolveTypeScriptConfigSingle, resolveTypeScriptConfigSingleAsync };
package/Vfs.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/Vfs.ts
1
+ // src/Vfs.ts
2
2
  /**
3
3
  * Merge VFS maps left to right into a new map; later entries win on path
4
4
  * collisions.
@@ -43,5 +43,4 @@ const prefixVfs = (name, entries) => {
43
43
  */
44
44
  const isTypeDefinition = (filePath) => filePath.endsWith(".d.ts") || filePath.endsWith(".d.mts") || filePath.endsWith(".d.cts");
45
45
 
46
- //#endregion
47
46
  export { isTypeDefinition, mergeVfs, prefixVfs };
package/VirtualPackage.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Effect, FileSystem, Schema } from "effect";
2
2
 
3
- //#region src/VirtualPackage.ts
3
+ // src/VirtualPackage.ts
4
4
  /**
5
5
  * A synthetic npm package built from locally supplied TypeScript declaration
6
6
  * content, for inclusion in a {@link Vfs} without fetching from the CDN.
@@ -122,5 +122,4 @@ var VirtualPackage = class VirtualPackage extends Schema.Class("VirtualPackage")
122
122
  }
123
123
  };
124
124
 
125
- //#endregion
126
125
  export { VirtualPackage };
package/index.d.ts CHANGED
@@ -3,7 +3,6 @@ import { Effect, FileSystem, PlatformError, Result, Schema } from "effect";
3
3
  import { VirtualTypeScriptEnvironment } from "@typescript/vfs";
4
4
  import { TwoslashTypesCache } from "@shikijs/twoslash";
5
5
  import { PathLike } from "node:fs";
6
- //#region src/TypeResolutionOptions.d.ts
7
6
  /**
8
7
  * The compiler options that may influence how a documentation example
9
8
  * type-checks.
@@ -79,8 +78,6 @@ export declare const decodeCompilerOptions: (input: unknown) => Result.Result<Ty
79
78
  * @public
80
79
  */
81
80
  export declare const toProgrammaticCompilerOptions: (options: TypeResolutionCompilerOptions) => ProgrammaticCompilerOptions;
82
- //#endregion
83
- //#region src/TsconfigParser.d.ts
84
81
  /**
85
82
  * Error thrown when tsconfig.json parsing fails.
86
83
  *
@@ -97,8 +94,8 @@ export declare const toProgrammaticCompilerOptions: (options: TypeResolutionComp
97
94
  */
98
95
  export declare class TsConfigParseError extends Error {
99
96
  readonly configPath: string;
100
- readonly cause?: unknown | undefined;
101
- constructor(configPath: string, message: string, cause?: unknown | undefined);
97
+ readonly cause?: unknown;
98
+ constructor(configPath: string, message: string, cause?: unknown);
102
99
  }
103
100
  /**
104
101
  * Parse a `tsconfig.json` and extract the compiler options used for type
@@ -118,8 +115,6 @@ export declare class TsConfigParseError extends Error {
118
115
  * @public
119
116
  */
120
117
  export declare function parseTsConfig(configPath: string, projectRoot: string): TypeResolutionCompilerOptions;
121
- //#endregion
122
- //#region src/Vfs.d.ts
123
118
  /**
124
119
  * The package's currency type: a virtual file system mapping
125
120
  * `node_modules/`-prefixed paths to file contents.
@@ -171,8 +166,6 @@ export declare const prefixVfs: (name: string, entries: ReadonlyMap<string, stri
171
166
  * @public
172
167
  */
173
168
  export declare const isTypeDefinition: (filePath: string) => boolean;
174
- //#endregion
175
- //#region src/TsEnvironment.d.ts
176
169
  declare const TsEnvironmentError_base: Schema.Class<TsEnvironmentError, Schema.TaggedStruct<"TsEnvironmentError", {
177
170
  /** The underlying failure, preserved structurally. */
178
171
  readonly cause: Schema.Defect;
@@ -252,8 +245,6 @@ export declare class TsEnvironment {
252
245
  /** Build a `VirtualTypeScriptEnvironment` over a {@link Vfs}. */
253
246
  static make(options: TsEnvironmentOptions): Effect.Effect<VirtualTypeScriptEnvironment, TsEnvironmentError>;
254
247
  }
255
- //#endregion
256
- //#region src/TwoslashCache.d.ts
257
248
  /**
258
249
  * Persisted Twoslash result cache.
259
250
  *
@@ -314,7 +305,7 @@ export declare class TsEnvironment {
314
305
  *
315
306
  * @public
316
307
  */
317
- export declare const TWOSLASH_CACHE_FORMAT = 1;
308
+ export declare const TWOSLASH_CACHE_FORMAT = 2;
318
309
  /**
319
310
  * The subset of a Twoslash run that Shiki consumes, and all this cache stores.
320
311
  *
@@ -376,11 +367,17 @@ export declare function twoslashEnvHash(vfs: ReadonlyMap<string, string>, toolch
376
367
  *
377
368
  * The configuration matters because two APIs on one site may be documented
378
369
  * under different `tsconfig`s — the same source checked under different options
379
- * can produce different types, so it must not share a cache entry.
370
+ * can produce different types, so it must not share a cache entry. The options
371
+ * are folded in through their RFC 8785 canonical form, so key order does not
372
+ * matter.
373
+ *
374
+ * Returns `undefined` when the options cannot be canonicalized (a function or a
375
+ * non-plain object among them): such a block is not cached, rather than keyed
376
+ * on a spelling that could collide with different options.
380
377
  *
381
378
  * @public
382
379
  */
383
- export declare function twoslashEntryKey(code: string, lang: string | undefined, compilerOptions?: unknown): string;
380
+ export declare function twoslashEntryKey(code: string, lang: string | undefined, compilerOptions?: unknown): string | undefined;
384
381
  /**
385
382
  * The cache key a whole generation is stored under. One blob per environment,
386
383
  * so a changed environment reads as a miss rather than serving stale results.
@@ -409,8 +406,6 @@ export declare function encodeTwoslashCache(entries: ReadonlyMap<string, Twoslas
409
406
  * @public
410
407
  */
411
408
  export declare function decodeTwoslashCache(blob: Uint8Array): Map<string, TwoslashCacheValue>;
412
- //#endregion
413
- //#region src/TypeScriptConfig.d.ts
414
409
  /**
415
410
  * How a caller points at TypeScript configuration: a `tsconfig.json`, inline
416
411
  * compiler options, or both.
@@ -584,8 +579,6 @@ export declare function resolveTypeScriptConfigSingleAsync(config: TypeScriptCon
584
579
  * @public
585
580
  */
586
581
  export declare function resolveTypeScriptConfig(projectRoot: string, global?: TypeScriptConfig, api?: TypeScriptConfig): Promise<TypeResolutionCompilerOptions>;
587
- //#endregion
588
- //#region src/VirtualPackage.d.ts
589
582
  declare const VirtualPackage_base: Schema.Class<VirtualPackage, Schema.Struct<{
590
583
  /** The package name (e.g. `"@my-org/api-types"`). */
591
584
  readonly name: Schema.String;
@@ -658,6 +651,5 @@ export declare class VirtualPackage extends VirtualPackage_base {
658
651
  toVfs(): Vfs;
659
652
  private toPackageJson;
660
653
  }
661
- //#endregion
662
654
  export type { CompilerOptionsInput, TsEnvironmentOptions, TwoslashCacheStats, TwoslashCacheValue, TwoslashResultCache, TypeScriptConfig, Vfs };
663
655
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsdoctor/vfs",
3
- "version": "0.4.7",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "Virtual TypeScript projects for documentation tooling: the Vfs currency type, declaration-backed virtual packages, @typescript/vfs environments, and the compiler-option resolution that configures them.",
6
6
  "keywords": [
@@ -36,11 +36,15 @@
36
36
  },
37
37
  "./package.json": "./package.json"
38
38
  },
39
+ "dependencies": {
40
+ "@effected/engine": "^0.10.0",
41
+ "@effected/jsonc": "^0.21.0"
42
+ },
39
43
  "peerDependencies": {
40
- "@effected/tsconfig-json": "^0.16.0",
44
+ "@effected/tsconfig-json": "^0.18.0",
41
45
  "@shikijs/twoslash": "^4.4.3",
42
46
  "@typescript/vfs": "^1.6.5",
43
- "effect": "^4.0.5",
47
+ "effect": "^4.0.7",
44
48
  "typescript": "^6.0.3"
45
49
  },
46
50
  "peerDependenciesMeta": {
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.59.1"
8
+ "packageVersion": "7.60.0"
9
9
  }
10
10
  ]
11
11
  }