rspress-plugin-api-extractor 0.1.2 → 0.2.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.
Files changed (109) hide show
  1. package/README.md +2 -2
  2. package/api-extracted-package.js +426 -0
  3. package/build-program.js +120 -0
  4. package/build-stages.js +664 -0
  5. package/category-resolver.js +50 -0
  6. package/code-post-processor.js +38 -0
  7. package/config-helpers.js +106 -0
  8. package/config-utils.js +258 -0
  9. package/content-hash.js +79 -0
  10. package/errors.js +29 -0
  11. package/formatter.js +69 -0
  12. package/hide-cut-transformer.js +96 -0
  13. package/index.d.ts +901 -831
  14. package/index.js +4 -6128
  15. package/layers/ConfigServiceLive.js +377 -0
  16. package/layers/ObservabilityLive.js +136 -0
  17. package/layers/PathDerivationServiceLive.js +16 -0
  18. package/layers/SnapshotServiceLive.js +94 -0
  19. package/layers/TypeRegistryServiceLive.js +46 -0
  20. package/llms-processing.js +270 -0
  21. package/llms-program.js +262 -0
  22. package/loader.js +186 -0
  23. package/markdown/cross-linker.js +156 -0
  24. package/markdown/helpers.js +364 -0
  25. package/markdown/index.js +11 -0
  26. package/markdown/page-generators/class-page.js +357 -0
  27. package/markdown/page-generators/enum-page.js +152 -0
  28. package/markdown/page-generators/function-page.js +127 -0
  29. package/markdown/page-generators/index-pages.js +27 -0
  30. package/markdown/page-generators/interface-page.js +307 -0
  31. package/markdown/page-generators/namespace-page.js +280 -0
  32. package/markdown/page-generators/type-alias-page.js +110 -0
  33. package/markdown/page-generators/variable-page.js +110 -0
  34. package/markdown/shiki-utils.js +48 -0
  35. package/migrations/001_create_snapshots.js +25 -0
  36. package/model-loader.js +95 -0
  37. package/multi-entry-resolver.js +70 -0
  38. package/og-resolver.js +271 -0
  39. package/package.json +63 -73
  40. package/path-derivation.js +48 -0
  41. package/plugin.js +218 -0
  42. package/prettier-formatter.js +73 -0
  43. package/public/tsconfig/rspress.json +44 -0
  44. package/remark-api-codeblocks.js +130 -0
  45. package/remark-with-api.js +172 -0
  46. package/route-collisions.js +52 -0
  47. package/runtime/components/ApiExample/index.js +29 -25
  48. package/runtime/components/ApiLlmsPackageActions/index.js +252 -323
  49. package/runtime/components/ApiLlmsViewOptions/index.js +269 -340
  50. package/runtime/components/ApiMember/index.js +49 -47
  51. package/runtime/components/ApiSignature/index.js +32 -28
  52. package/runtime/components/EnumMembersTable/{index_module.css → index.css} +18 -19
  53. package/runtime/components/EnumMembersTable/index.js +36 -67
  54. package/runtime/components/EnumMembersTable/index.module.js +9 -6
  55. package/runtime/components/ExampleBlock/{index_module.css → index.css} +2 -3
  56. package/runtime/components/ExampleBlock/index.js +23 -28
  57. package/runtime/components/ExampleBlock/index.module.js +8 -5
  58. package/runtime/components/MarkdownContent/index.js +26 -18
  59. package/runtime/components/MarkdownText/index.js +28 -22
  60. package/runtime/components/MemberSignature/{index_module.css → index.css} +5 -6
  61. package/runtime/components/MemberSignature/index.js +46 -46
  62. package/runtime/components/MemberSignature/index.module.js +9 -6
  63. package/runtime/components/ParametersTable/{index_module.css → index.css} +19 -20
  64. package/runtime/components/ParametersTable/index.js +36 -67
  65. package/runtime/components/ParametersTable/index.module.js +9 -6
  66. package/runtime/components/SignatureBlock/{index_module.css → index.css} +5 -6
  67. package/runtime/components/SignatureBlock/index.js +30 -29
  68. package/runtime/components/SignatureBlock/index.module.js +9 -6
  69. package/runtime/components/SignatureCode/{index_module.css → index.css} +9 -10
  70. package/runtime/components/SignatureCode/index.js +40 -32
  71. package/runtime/components/SignatureCode/index.module.js +9 -6
  72. package/runtime/components/SignatureToolbar/{index_module.css → index.css} +18 -20
  73. package/runtime/components/SignatureToolbar/index.js +48 -51
  74. package/runtime/components/SignatureToolbar/index.module.js +13 -10
  75. package/runtime/components/buttons/ButtonGroup.js +13 -6
  76. package/runtime/components/buttons/CopyCodeButton.js +40 -38
  77. package/runtime/components/buttons/WrapSignatureButton.js +20 -16
  78. package/runtime/components/buttons/{index_module.css → index.css} +5 -6
  79. package/runtime/components/buttons/index.module.js +8 -5
  80. package/runtime/components/icons/CheckIcon/index.js +20 -17
  81. package/runtime/components/icons/CopyIcon/index.js +20 -17
  82. package/runtime/components/icons/UnwrapIcon/index.js +22 -18
  83. package/runtime/components/icons/WrapIcon/index.js +20 -17
  84. package/runtime/components/shared/_twoslash.css +3 -10
  85. package/runtime/components/shared/variables.css +0 -3
  86. package/runtime/hooks/useWrapToggle.js +32 -9
  87. package/runtime/index.d.ts +513 -173
  88. package/runtime/index.js +11 -9
  89. package/runtime/utils/decode-hast.js +31 -16
  90. package/runtime/utils/hast-renderer.js +21 -7
  91. package/schemas/config.js +199 -0
  92. package/schemas/index.js +5 -0
  93. package/schemas/opengraph.js +26 -0
  94. package/schemas/performance.js +19 -0
  95. package/serve.js +133 -0
  96. package/services/ConfigService.js +7 -0
  97. package/services/PathDerivationService.js +7 -0
  98. package/services/SnapshotService.js +7 -0
  99. package/services/TypeRegistryService.js +7 -0
  100. package/shiki-transformer.js +758 -0
  101. package/tsconfig-parser.js +127 -0
  102. package/tsdoc-metadata.json +11 -11
  103. package/twoslash-patterns.js +87 -0
  104. package/twoslash-transformer.js +316 -0
  105. package/type-reference-extractor.js +201 -0
  106. package/typescript-config.js +168 -0
  107. package/vfs-registry.js +121 -0
  108. package/0~llms-program.js +0 -344
  109. package/runtime/components/ApiLlmsPackageActions/index.module.js +0 -2
@@ -0,0 +1,201 @@
1
+ import { ApiItemKind } from "@microsoft/api-extractor-model";
2
+
3
+ //#region src/type-reference-extractor.ts
4
+ /**
5
+ * Extracts type references from API Extractor models to generate import statements.
6
+ *
7
+ * This class analyzes API items and their excerpt tokens to identify external type
8
+ * references that need to be imported in the generated TypeScript declaration files.
9
+ *
10
+ * **How it works:**
11
+ * 1. Walks through all API items (classes, interfaces, functions, etc.)
12
+ * 2. Extracts type references from excerpt tokens
13
+ * 3. Filters out built-in types and internal references
14
+ * 4. Groups external references by package
15
+ * 5. Generates `import type` statements
16
+ *
17
+ * **Reference Types:**
18
+ * - **Built-in:** TypeScript types like `Promise`, `Record`, `NonNullable` (skipped)
19
+ * - **Internal:** References to types in the same package (skipped)
20
+ * - **External:** References to types from npm packages (imported)
21
+ *
22
+ * **Canonical Reference Format:**
23
+ * API Extractor uses canonical references like:
24
+ * - `"zod!ZodType:interface"` → External reference to `zod` package
25
+ * - `"mypackage!MyType:type"` → Internal reference (same package)
26
+ * - `"!Promise:interface"` → Built-in TypeScript type
27
+ * - `"!\"node:buffer\".__global.Buffer:interface"` → Node.js built-in (treated as built-in)
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const extractor = new TypeReferenceExtractor(apiPackage, "my-package");
32
+ * const imports = extractor.extractImports();
33
+ *
34
+ * for (const stmt of imports) {
35
+ * console.log(`import type { ${[...stmt.symbols].join(", ")} } from "${stmt.packageName}";`);
36
+ * }
37
+ * // Output:
38
+ * // import type { ZodType } from "zod";
39
+ * // import type { Effect } from "@effect/schema";
40
+ * ```
41
+ */
42
+ var TypeReferenceExtractor = class {
43
+ apiPackage;
44
+ currentPackageName;
45
+ /**
46
+ * All type references found in the API package
47
+ */
48
+ references = /* @__PURE__ */ new Map();
49
+ constructor(apiPackage, currentPackageName) {
50
+ this.apiPackage = apiPackage;
51
+ this.currentPackageName = currentPackageName;
52
+ }
53
+ /**
54
+ * Extract all type references from the API package and generate import statements.
55
+ * Returns an array of import statements grouped by package.
56
+ */
57
+ extractImports() {
58
+ this.walkApiPackage();
59
+ return this.generateImportStatements();
60
+ }
61
+ /**
62
+ * Extract type references for a specific entry point only.
63
+ * This enables per-entry-point import optimization for multi-entry packages.
64
+ *
65
+ * @param entryPoint - The specific entry point to extract imports for
66
+ * @returns Import statements containing only types used in this entry point
67
+ */
68
+ extractImportsForEntryPoint(entryPoint) {
69
+ this.references.clear();
70
+ for (const member of entryPoint.members) this.walkApiItem(member);
71
+ return this.generateImportStatements();
72
+ }
73
+ /**
74
+ * Extract type references for a single API item.
75
+ * This enables generating imports for individual signatures.
76
+ *
77
+ * @param apiItem - The specific API item to extract imports for
78
+ * @returns Import statements containing only types used in this item
79
+ */
80
+ extractImportsForApiItem(apiItem) {
81
+ this.references.clear();
82
+ this.walkApiItem(apiItem);
83
+ return this.generateImportStatements();
84
+ }
85
+ /**
86
+ * Generate import statements from collected references.
87
+ * Used by both extractImports() and extractImportsForEntryPoint().
88
+ */
89
+ generateImportStatements() {
90
+ const packageMap = /* @__PURE__ */ new Map();
91
+ for (const ref of this.references.values()) {
92
+ if (ref.isBuiltIn || ref.isInternal) continue;
93
+ if (!packageMap.has(ref.packageName)) packageMap.set(ref.packageName, /* @__PURE__ */ new Set());
94
+ packageMap.get(ref.packageName)?.add(ref.symbolName);
95
+ }
96
+ const imports = [];
97
+ for (const [packageName, symbols] of packageMap.entries()) imports.push({
98
+ packageName,
99
+ symbols,
100
+ typeOnly: true
101
+ });
102
+ imports.sort((a, b) => a.packageName.localeCompare(b.packageName));
103
+ return imports;
104
+ }
105
+ /**
106
+ * Generate import statement strings from ImportStatement objects.
107
+ * Returns an array of formatted import statements.
108
+ */
109
+ static formatImports(imports) {
110
+ const statements = [];
111
+ for (const stmt of imports) {
112
+ const sortedSymbols = Array.from(stmt.symbols).sort();
113
+ const statement = `${stmt.typeOnly ? "import type" : "import"} { ${sortedSymbols.join(", ")} } from "${stmt.packageName}";`;
114
+ statements.push(statement);
115
+ }
116
+ return statements;
117
+ }
118
+ /**
119
+ * Walk through the entire API package and extract all type references
120
+ */
121
+ walkApiPackage() {
122
+ for (const entryPoint of this.apiPackage.entryPoints) for (const member of entryPoint.members) this.walkApiItem(member);
123
+ }
124
+ /**
125
+ * Recursively walk through an API item and its children to extract type references
126
+ */
127
+ walkApiItem(apiItem) {
128
+ this.extractFromExcerpt(apiItem);
129
+ if ("members" in apiItem) {
130
+ const members = apiItem.members;
131
+ if (Array.isArray(members)) for (const member of members) this.walkApiItem(member);
132
+ }
133
+ }
134
+ /**
135
+ * Extract type references from an API item using its excerpt
136
+ */
137
+ extractFromExcerpt(apiItem) {
138
+ const excerpt = this.getExcerpt(apiItem);
139
+ if (!excerpt) return;
140
+ this.extractFromExcerptTokens(excerpt);
141
+ }
142
+ /**
143
+ * Get the appropriate excerpt from an API item based on its kind
144
+ */
145
+ getExcerpt(apiItem) {
146
+ const item = apiItem;
147
+ if (item.excerpt) return item.excerpt;
148
+ if (apiItem.kind === ApiItemKind.TypeAlias && item.typeExcerpt) return item.typeExcerpt;
149
+ if ((apiItem.kind === ApiItemKind.Property || apiItem.kind === ApiItemKind.PropertySignature) && item.propertyTypeExcerpt) return item.propertyTypeExcerpt;
150
+ if (item.returnTypeExcerpt) return item.returnTypeExcerpt;
151
+ return null;
152
+ }
153
+ /**
154
+ * Extract type references from excerpt tokens
155
+ */
156
+ extractFromExcerptTokens(excerpt) {
157
+ if (!excerpt.spannedTokens || excerpt.spannedTokens.length === 0) return;
158
+ for (const token of excerpt.spannedTokens) {
159
+ if (token.kind !== "Reference") continue;
160
+ const canonicalRef = token.canonicalReference?.toString();
161
+ if (!canonicalRef || typeof canonicalRef !== "string") continue;
162
+ const ref = this.parseCanonicalReference(canonicalRef, token.text);
163
+ if (ref) this.references.set(ref.canonicalReference, ref);
164
+ }
165
+ }
166
+ /**
167
+ * Parse a canonical reference string to extract type reference information.
168
+ *
169
+ * Canonical reference format: "packageName!symbolName:kind"
170
+ * Examples:
171
+ * - "zod!ZodType:interface" → External reference
172
+ * - "mypackage!MyType:type" → Internal reference
173
+ * - "!Promise:interface" → Built-in type
174
+ * - "!\"node:buffer\".__global.Buffer:interface" → Node.js built-in
175
+ */
176
+ parseCanonicalReference(canonicalRef, symbolText) {
177
+ const exclamationIndex = canonicalRef.indexOf("!");
178
+ if (exclamationIndex === -1) return null;
179
+ const packagePart = canonicalRef.substring(0, exclamationIndex);
180
+ const rest = canonicalRef.substring(exclamationIndex + 1);
181
+ const colonIndex = rest.indexOf(":");
182
+ const symbolFromCanonical = colonIndex !== -1 ? rest.substring(0, colonIndex) : rest;
183
+ const isBuiltIn = packagePart === "" || packagePart.startsWith("\"");
184
+ const isInternal = packagePart === this.currentPackageName;
185
+ let symbolName;
186
+ if (symbolText.includes(".")) {
187
+ const parts = symbolText.split(".");
188
+ symbolName = parts[parts.length - 1].trim();
189
+ } else symbolName = symbolFromCanonical.trim();
190
+ return {
191
+ symbolName,
192
+ packageName: packagePart,
193
+ canonicalReference: canonicalRef,
194
+ isBuiltIn,
195
+ isInternal
196
+ };
197
+ }
198
+ };
199
+
200
+ //#endregion
201
+ export { TypeReferenceExtractor };
@@ -0,0 +1,168 @@
1
+ import { TsConfigParseError, parseTsConfig } from "./tsconfig-parser.js";
2
+
3
+ //#region src/typescript-config.ts
4
+ /**
5
+ * Default TypeScript compiler options for Twoslash and type resolution.
6
+ *
7
+ * These defaults are optimized for documentation:
8
+ * - Modern ES targets (ESNext)
9
+ * - Bundler module resolution for broad compatibility
10
+ * - Lenient settings (non-strict) since docs often show simplified examples
11
+ * - Skip lib checks for faster processing
12
+ *
13
+ * @remarks
14
+ * Numeric values correspond to TypeScript enums:
15
+ * - target: 99 = ESNext
16
+ * - module: 99 = ESNext
17
+ * - moduleResolution: 100 = Bundler
18
+ */
19
+ const DEFAULT_COMPILER_OPTIONS = {
20
+ target: 99,
21
+ module: 99,
22
+ moduleResolution: 100,
23
+ lib: ["ESNext", "DOM"],
24
+ strict: false,
25
+ skipLibCheck: true,
26
+ esModuleInterop: true,
27
+ allowSyntheticDefaultImports: true
28
+ };
29
+ /**
30
+ * Merge two TypeResolutionCompilerOptions objects.
31
+ * Properties from `override` take precedence over `base`.
32
+ *
33
+ * @param base - Base compiler options
34
+ * @param override - Options to merge on top (takes precedence)
35
+ * @returns Merged options
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const base = { target: 99, lib: ["ESNext"] };
40
+ * const override = { lib: ["ESNext", "DOM"], strict: true };
41
+ * const merged = mergeCompilerOptions(base, override);
42
+ * // Result: { target: 99, lib: ["ESNext", "DOM"], strict: true }
43
+ * ```
44
+ */
45
+ function mergeCompilerOptions(base, override) {
46
+ if (!override) return { ...base };
47
+ const merged = { ...base };
48
+ if (override.target !== void 0) merged.target = override.target;
49
+ if (override.module !== void 0) merged.module = override.module;
50
+ if (override.moduleResolution !== void 0) merged.moduleResolution = override.moduleResolution;
51
+ if (override.lib !== void 0) merged.lib = override.lib;
52
+ if (override.strict !== void 0) merged.strict = override.strict;
53
+ if (override.skipLibCheck !== void 0) merged.skipLibCheck = override.skipLibCheck;
54
+ if (override.esModuleInterop !== void 0) merged.esModuleInterop = override.esModuleInterop;
55
+ if (override.allowSyntheticDefaultImports !== void 0) merged.allowSyntheticDefaultImports = override.allowSyntheticDefaultImports;
56
+ if (override.jsx !== void 0) merged.jsx = override.jsx;
57
+ if (override.types !== void 0) merged.types = override.types;
58
+ return merged;
59
+ }
60
+ /**
61
+ * Resolve a single TypeScriptConfig to compiler options (async version).
62
+ * Handles both path-based and function-based tsconfig.
63
+ *
64
+ * Follows the priority cascade:
65
+ * 1. Load tsconfig (from path or function)
66
+ * 2. Merge compilerOptions on top
67
+ *
68
+ * @param config - TypeScript config with optional tsconfig path/function and/or compilerOptions
69
+ * @param projectRoot - Project root for resolving relative tsconfig paths
70
+ * @returns Promise resolving to compiler options (not merged with defaults)
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * // Path-based tsconfig
75
+ * await resolveTypeScriptConfigSingleAsync({ tsconfig: "tsconfig.json" }, "/project");
76
+ *
77
+ * // Function-based tsconfig
78
+ * await resolveTypeScriptConfigSingleAsync({
79
+ * tsconfig: async () => ({ target: 99, lib: ["ESNext"] })
80
+ * }, "/project");
81
+ *
82
+ * // Both (compilerOptions override tsconfig)
83
+ * await resolveTypeScriptConfigSingleAsync({
84
+ * tsconfig: async () => ({ target: 99 }),
85
+ * compilerOptions: { strict: false }
86
+ * }, "/project");
87
+ * ```
88
+ */
89
+ async function resolveTypeScriptConfigSingleAsync(config, projectRoot) {
90
+ if (!config) return {};
91
+ let options = {};
92
+ if (config.tsconfig) if (typeof config.tsconfig === "function") options = await config.tsconfig();
93
+ else {
94
+ const tsconfigPath = String(config.tsconfig);
95
+ try {
96
+ options = parseTsConfig(tsconfigPath, projectRoot);
97
+ } catch (error) {
98
+ if (error instanceof TsConfigParseError) throw error;
99
+ throw new TsConfigParseError(tsconfigPath, error instanceof Error ? error.message : String(error), error);
100
+ }
101
+ }
102
+ if (config.compilerOptions) options = mergeCompilerOptions(options, config.compilerOptions);
103
+ return options;
104
+ }
105
+ /**
106
+ * Resolve TypeScript compiler options from a cascade of configurations (async).
107
+ *
108
+ * Resolution order (later levels override earlier):
109
+ * 1. DEFAULT_COMPILER_OPTIONS (sensible defaults)
110
+ * 2. Global plugin config
111
+ * 3. API-level config
112
+ * 4. Version-level config
113
+ * 5. Per-package override (for external packages)
114
+ *
115
+ * At each level, if a TypeScriptConfig has both `tsconfig` and `compilerOptions`,
116
+ * the tsconfig is loaded first, then compilerOptions are merged on top.
117
+ *
118
+ * @param projectRoot - Project root directory for resolving relative paths
119
+ * @param global - Global plugin TypeScript configuration
120
+ * @param api - API-level TypeScript configuration
121
+ * @param version - Version-level TypeScript configuration
122
+ * @param packageOverride - Per-package TypeScript configuration override
123
+ * @returns Promise resolving to fully resolved compiler options
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * // Simple global config
128
+ * const options = await resolveTypeScriptConfig("/project", {
129
+ * tsconfig: "tsconfig.json"
130
+ * });
131
+ *
132
+ * // With async tsconfig loader
133
+ * const options = await resolveTypeScriptConfig("/project", {
134
+ * tsconfig: async () => ({ target: 99, lib: ["ESNext"] })
135
+ * });
136
+ *
137
+ * // With API override
138
+ * const options = await resolveTypeScriptConfig(
139
+ * "/project",
140
+ * { tsconfig: "tsconfig.json" },
141
+ * { compilerOptions: { strict: false } }
142
+ * );
143
+ *
144
+ * // Full cascade
145
+ * const options = await resolveTypeScriptConfig(
146
+ * "/project",
147
+ * { tsconfig: "tsconfig.json" }, // global
148
+ * { compilerOptions: { strict: false } }, // API
149
+ * { compilerOptions: { target: 9 } }, // version
150
+ * { compilerOptions: { module: 1 } } // package override
151
+ * );
152
+ * ```
153
+ */
154
+ async function resolveTypeScriptConfig(projectRoot, global, api, version, packageOverride) {
155
+ let options = { ...DEFAULT_COMPILER_OPTIONS };
156
+ const globalOptions = await resolveTypeScriptConfigSingleAsync(global, projectRoot);
157
+ options = mergeCompilerOptions(options, globalOptions);
158
+ const apiOptions = await resolveTypeScriptConfigSingleAsync(api, projectRoot);
159
+ options = mergeCompilerOptions(options, apiOptions);
160
+ const versionOptions = await resolveTypeScriptConfigSingleAsync(version, projectRoot);
161
+ options = mergeCompilerOptions(options, versionOptions);
162
+ const packageOptions = await resolveTypeScriptConfigSingleAsync(packageOverride, projectRoot);
163
+ options = mergeCompilerOptions(options, packageOptions);
164
+ return options;
165
+ }
166
+
167
+ //#endregion
168
+ export { DEFAULT_COMPILER_OPTIONS, resolveTypeScriptConfig };
@@ -0,0 +1,121 @@
1
+ //#region src/vfs-registry.ts
2
+ /**
3
+ * Module-scoped registry for VFS configurations.
4
+ *
5
+ * This is a singleton registry that stores VFS data keyed by:
6
+ * - API scope (e.g., "claude-binary-plugin")
7
+ *
8
+ * The registry is designed to be:
9
+ * - Written to during `beforeBuild` (when VFS is generated)
10
+ * - Read from during MDX compilation (when remark plugin transforms code blocks)
11
+ * - Thread-safe for reads (VFS is immutable after registration)
12
+ */
13
+ var VfsRegistryImpl = class {
14
+ /**
15
+ * Map of API scope to VFS configuration
16
+ */
17
+ configs = /* @__PURE__ */ new Map();
18
+ /**
19
+ * Register a VFS configuration for an API scope.
20
+ *
21
+ * @param apiScope - The API scope identifier (e.g., "claude-binary-plugin")
22
+ * @param config - The VFS configuration to register
23
+ */
24
+ register(apiScope, config) {
25
+ this.configs.set(apiScope, config);
26
+ }
27
+ /**
28
+ * Get the VFS configuration for an API scope.
29
+ *
30
+ * @param apiScope - The API scope to look up
31
+ * @returns The VFS configuration, or undefined if not found
32
+ */
33
+ get(apiScope) {
34
+ return this.configs.get(apiScope);
35
+ }
36
+ /**
37
+ * Get the VFS configuration by matching a file path to an API scope.
38
+ *
39
+ * This method extracts the API scope from a file path and returns
40
+ * the corresponding VFS configuration.
41
+ *
42
+ * @param filePath - The absolute file path being processed
43
+ * @returns The VFS configuration, or undefined if not found
44
+ */
45
+ getByFilePath(filePath) {
46
+ const apiScope = this.extractApiScope(filePath);
47
+ if (!apiScope) return;
48
+ return this.get(apiScope);
49
+ }
50
+ /**
51
+ * Extract the API scope from a file path.
52
+ *
53
+ * Path patterns:
54
+ * - `docs/en/api-scope/rest.mdx`
55
+ * - `website/docs/en/api-scope/rest.mdx`
56
+ *
57
+ * @param filePath - The file path to extract from
58
+ * @returns The API scope, or undefined if not matched
59
+ */
60
+ extractApiScope(filePath) {
61
+ const match = filePath.replace(/\\/g, "/").match(/(?:^|\/)(docs\/en|website\/docs\/en)\/([^/]+)(?:\/|$)/);
62
+ if (!match) return;
63
+ return match[2];
64
+ }
65
+ /**
66
+ * Check if any VFS configurations are registered.
67
+ *
68
+ * @returns True if at least one configuration is registered
69
+ */
70
+ hasConfigs() {
71
+ return this.configs.size > 0;
72
+ }
73
+ /**
74
+ * Get all registered API scopes.
75
+ *
76
+ * @returns Array of registered API scope identifiers
77
+ */
78
+ getScopes() {
79
+ return Array.from(this.configs.keys());
80
+ }
81
+ /**
82
+ * Clear all registered configurations.
83
+ *
84
+ * This should be called between builds to avoid stale data.
85
+ */
86
+ clear() {
87
+ this.configs.clear();
88
+ }
89
+ };
90
+ /**
91
+ * Global VFS Registry singleton instance.
92
+ *
93
+ * Use this to register and retrieve VFS configurations:
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * // In beforeBuild hook:
98
+ * VfsRegistry.register("claude-binary-plugin", {
99
+ * vfs: combinedVfs,
100
+ * highlighter,
101
+ * twoslashTransformer,
102
+ * crossLinker: shikiCrossLinker,
103
+ * packageName: "claude-binary-plugin",
104
+ * apiScope: "claude-binary-plugin",
105
+ * });
106
+ *
107
+ * // In remark plugin:
108
+ * const config = VfsRegistry.getByFilePath(file.path);
109
+ * if (config) {
110
+ * // Generate HAST with Shiki, then post-process with cross-linker
111
+ * let hast = await generateShikiHast(code, config.highlighter, transformers);
112
+ * if (hast && config.crossLinker) {
113
+ * hast = config.crossLinker.transformHast(hast, config.apiScope);
114
+ * }
115
+ * }
116
+ * ```
117
+ */
118
+ const VfsRegistry = new VfsRegistryImpl();
119
+
120
+ //#endregion
121
+ export { VfsRegistry };