rspress-plugin-api-extractor 0.11.0 → 0.12.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/BuildEnv.js +3 -3
- package/build-program.js +2 -3
- package/build-stages.js +3 -5
- package/config-helpers.js +7 -7
- package/errors.js +1 -5
- package/index.d.ts +84 -86
- package/layers/AppLayer.js +67 -0
- package/layers/api-results.js +83 -0
- package/layers/build-metrics.js +1 -1
- package/layers/{ConfigServiceLive.js → config-resolution.js} +76 -175
- package/layers/external-types.js +74 -0
- package/layers/{ObservabilityLive.js → observability.js} +3 -3
- package/layers/type-environment.js +109 -0
- package/layers/xdg.js +1 -1
- package/markdown/shiki-utils.js +1 -1
- package/model-loader.js +3 -3
- package/observability/EventBus.js +2 -2
- package/observability/heartbeat.js +1 -1
- package/observability/sinks/metrics-sink.js +1 -1
- package/observability/sinks/trace-sink.js +4 -4
- package/og-resolver.js +32 -1
- package/package.json +2 -2
- package/plugin.js +30 -33
- package/prettier-formatter.js +1 -1
- package/remark-api-codeblocks.js +1 -1
- package/remark-with-api.js +1 -1
- package/schemas/config.js +0 -2
- package/services/ConfigService.js +37 -2
- package/services/HighlighterService.js +48 -3
- package/services/OgService.js +169 -2
- package/services/PluginConfig.js +1 -1
- package/services/TwoslashCacheService.js +128 -2
- package/services/TwoslashEnvironments.js +30 -2
- package/services/TypeRegistryService.js +178 -2
- package/shiki-transformer.js +1 -1
- package/sync-node-fs.js +6 -6
- package/tsconfig-parser.js +77 -95
- package/twoslash-access.js +1 -1
- package/twoslash-transformer.js +1 -1
- package/layers/HighlighterServiceLive.js +0 -52
- package/layers/OgServiceLive.js +0 -134
- package/layers/TwoslashCacheServiceLive.js +0 -108
- package/layers/TwoslashEnvironmentsLive.js +0 -33
- package/layers/TypeRegistryServiceLive.js +0 -162
- package/markdown/index.js +0 -11
- package/schemas/index.js +0 -6
package/BuildEnv.js
CHANGED
|
@@ -7,12 +7,12 @@ import { Context } from "effect";
|
|
|
7
7
|
*
|
|
8
8
|
* @remarks
|
|
9
9
|
* Each of these used to travel by hand. `thresholds` made a four-hop journey —
|
|
10
|
-
* `plugin.ts` → `
|
|
10
|
+
* `plugin.ts` → `ConfigService.layer`'s fourth constructor argument →
|
|
11
11
|
* a `ResolvedBuildContext` field → destructured in `build-program.ts` → every
|
|
12
12
|
* `withPhase` call — while `obs.thresholds` already held the same value one
|
|
13
13
|
* scope away. `buildId` was worse: 24 event emit sites wrote
|
|
14
14
|
* `ctx: { buildId: "" }` because the value was not reachable from where they
|
|
15
|
-
* stood, and in `
|
|
15
|
+
* stood, and in `TypeRegistryService.layer` it genuinely was not — that layer is
|
|
16
16
|
* module-level and has no build to name. A Reference is the fix precisely
|
|
17
17
|
* because it reaches module-level code that no parameter can.
|
|
18
18
|
*
|
|
@@ -46,7 +46,7 @@ const Thresholds = Context.Reference("rspress-plugin-api-extractor/Thresholds",
|
|
|
46
46
|
* How many pages the build pipeline generates concurrently.
|
|
47
47
|
*
|
|
48
48
|
* @remarks
|
|
49
|
-
* Defaults to the CPU count, which is what `
|
|
49
|
+
* Defaults to the CPU count, which is what `ConfigService.layer` computed
|
|
50
50
|
* inline. Kept a Reference rather than a constant so a consumer with a
|
|
51
51
|
* constrained CI runner can lower it without a code change.
|
|
52
52
|
*/
|
package/build-program.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { BuildId, PageConcurrency, SuppressExampleErrors } from "./BuildEnv.js";
|
|
2
2
|
import { setProseLinker } from "./markdown/prose-linker.js";
|
|
3
|
-
import "./markdown/index.js";
|
|
4
3
|
import { buildPipelineForApi, cleanupAndCommit, prepareWorkItems, writeMetadata } from "./build-stages.js";
|
|
5
4
|
import { HideCutLinesTransformer, MemberFormatTransformer } from "./hide-cut-transformer.js";
|
|
6
5
|
import { withPhase } from "./observability/spans.js";
|
|
7
6
|
import { HighlighterService } from "./services/HighlighterService.js";
|
|
7
|
+
import { addTypeRoutes } from "./twoslash-transformer.js";
|
|
8
8
|
import { TwoslashEnvironments } from "./services/TwoslashEnvironments.js";
|
|
9
9
|
import { ShikiCrossLinker } from "./shiki-transformer.js";
|
|
10
|
-
import { addTypeRoutes } from "./twoslash-transformer.js";
|
|
11
10
|
import { VfsRegistry } from "./vfs-registry.js";
|
|
12
11
|
import path from "node:path";
|
|
13
|
-
import { SnapshotService } from "@tsdoctor/snapshot";
|
|
14
12
|
import { Effect, FileSystem } from "effect";
|
|
13
|
+
import { SnapshotService } from "@tsdoctor/snapshot";
|
|
15
14
|
|
|
16
15
|
//#region src/build-program.ts
|
|
17
16
|
/**
|
package/build-stages.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { parseFrontmatter, stringifyFrontmatter } from "./frontmatter.js";
|
|
2
|
+
import { BuildMetrics } from "./layers/build-metrics.js";
|
|
2
3
|
import { PluginEvent } from "./observability/events.js";
|
|
3
4
|
import { emit } from "./observability/EventBus.js";
|
|
4
|
-
import { BuildMetrics } from "./layers/build-metrics.js";
|
|
5
|
-
import "./layers/ObservabilityLive.js";
|
|
6
5
|
import { emitSync, syncBuildId } from "./observability/sync-emitter.js";
|
|
7
6
|
import { generateFrontmatter } from "./markdown/helpers.js";
|
|
8
7
|
import { ClassPageGenerator } from "./markdown/page-generators/class-page.js";
|
|
@@ -13,12 +12,11 @@ import { InterfacePageGenerator } from "./markdown/page-generators/interface-pag
|
|
|
13
12
|
import { NamespacePageGenerator } from "./markdown/page-generators/namespace-page.js";
|
|
14
13
|
import { TypeAliasPageGenerator } from "./markdown/page-generators/type-alias-page.js";
|
|
15
14
|
import { VariablePageGenerator } from "./markdown/page-generators/variable-page.js";
|
|
16
|
-
import "./markdown/index.js";
|
|
17
15
|
import { createPageMetadata } from "./og-resolver.js";
|
|
18
16
|
import { OgService } from "./services/OgService.js";
|
|
19
17
|
import path from "node:path";
|
|
20
|
-
import { SnapshotService, hashContent, hashFrontmatter } from "@tsdoctor/snapshot";
|
|
21
18
|
import { Effect, FileSystem, Metric, Option, Stream } from "effect";
|
|
19
|
+
import { SnapshotService, hashContent, hashFrontmatter } from "@tsdoctor/snapshot";
|
|
22
20
|
import { ApiItemKind } from "@microsoft/api-extractor-model";
|
|
23
21
|
import { ApiItems, EntryPoints, Routes, SyntheticBases } from "@tsdoctor/model";
|
|
24
22
|
|
|
@@ -427,7 +425,7 @@ function writeSingleFile(result, ctx) {
|
|
|
427
425
|
};
|
|
428
426
|
}
|
|
429
427
|
let finalContent = stringifyFrontmatter(bodyContent, frontmatter);
|
|
430
|
-
if (siteUrl && packageName) {
|
|
428
|
+
if (siteUrl != null && packageName) {
|
|
431
429
|
const ogSvc = yield* OgService;
|
|
432
430
|
const ogImageResult = yield* Effect.result(ogSvc.resolveImage({
|
|
433
431
|
config: ogImage,
|
package/config-helpers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeBaseRoute } from "./path-derivation.js";
|
|
2
2
|
import { SyncDiscoveryLayer } from "./sync-node-fs.js";
|
|
3
|
-
import
|
|
3
|
+
import fsSync from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { Effect, Result } from "effect";
|
|
6
6
|
import { discoverBundle } from "@tsdoctor/bundle";
|
|
@@ -18,14 +18,14 @@ const PREFIX = "[rspress-plugin-api-extractor]";
|
|
|
18
18
|
function requirePackageJson(dir) {
|
|
19
19
|
let stat;
|
|
20
20
|
try {
|
|
21
|
-
stat =
|
|
21
|
+
stat = fsSync.statSync(dir);
|
|
22
22
|
} catch {
|
|
23
23
|
throw new Error(`${PREFIX} api.fromDir: directory not found: ${dir}`);
|
|
24
24
|
}
|
|
25
25
|
if (!stat.isDirectory()) throw new Error(`${PREFIX} api.fromDir: not a directory: ${dir}`);
|
|
26
26
|
let pkg;
|
|
27
27
|
try {
|
|
28
|
-
pkg = JSON.parse(
|
|
28
|
+
pkg = JSON.parse(fsSync.readFileSync(path.join(dir, "package.json"), "utf8"));
|
|
29
29
|
} catch {
|
|
30
30
|
throw new Error(`${PREFIX} api.fromDir: missing or unreadable package.json in ${dir}`);
|
|
31
31
|
}
|
|
@@ -103,9 +103,9 @@ function fromDir(dir, overrides = {}) {
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
function isModelFolder(dir) {
|
|
106
|
-
if (!
|
|
106
|
+
if (!fsSync.existsSync(path.join(dir, "package.json"))) return false;
|
|
107
107
|
try {
|
|
108
|
-
return
|
|
108
|
+
return fsSync.readdirSync(dir).some((f) => f.endsWith(".api.json"));
|
|
109
109
|
} catch {
|
|
110
110
|
return false;
|
|
111
111
|
}
|
|
@@ -124,12 +124,12 @@ function fromParentDir(parentDir, options = {}) {
|
|
|
124
124
|
const absParent = path.resolve(cwd ?? process.cwd(), parentDir);
|
|
125
125
|
let stat;
|
|
126
126
|
try {
|
|
127
|
-
stat =
|
|
127
|
+
stat = fsSync.statSync(absParent);
|
|
128
128
|
} catch {
|
|
129
129
|
throw new Error(`${PREFIX} apis.fromDir: directory not found: ${absParent}`);
|
|
130
130
|
}
|
|
131
131
|
if (!stat.isDirectory()) throw new Error(`${PREFIX} apis.fromDir: not a directory: ${absParent}`);
|
|
132
|
-
const subdirs =
|
|
132
|
+
const subdirs = fsSync.readdirSync(absParent, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
133
133
|
const configs = [];
|
|
134
134
|
for (const name of subdirs) {
|
|
135
135
|
const subdir = path.join(absParent, name);
|
package/errors.js
CHANGED
|
@@ -7,16 +7,12 @@ var ConfigValidationError = class extends ConfigValidationErrorBase {
|
|
|
7
7
|
return `Config validation failed for '${this.field}': ${this.reason}`;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
-
const ApiModelLoadErrorBase = Data.TaggedError("ApiModelLoadError");
|
|
11
10
|
const TypeRegistryErrorBase = Data.TaggedError("TypeRegistryError");
|
|
12
11
|
var TypeRegistryError = class extends TypeRegistryErrorBase {
|
|
13
12
|
get message() {
|
|
14
13
|
return `Type registry error for '${this.packageName}@${this.version}': ${this.reason}`;
|
|
15
14
|
}
|
|
16
15
|
};
|
|
17
|
-
const PageGenerationErrorBase = Data.TaggedError("PageGenerationError");
|
|
18
|
-
const TwoslashProcessingErrorBase = Data.TaggedError("TwoslashProcessingError");
|
|
19
|
-
const PrettierFormatErrorBase = Data.TaggedError("PrettierFormatError");
|
|
20
16
|
|
|
21
17
|
//#endregion
|
|
22
|
-
export { ConfigValidationError,
|
|
18
|
+
export { ConfigValidationError, TypeRegistryError };
|
package/index.d.ts
CHANGED
|
@@ -669,8 +669,6 @@ declare const PluginOptions: Schema.Struct<{
|
|
|
669
669
|
*/
|
|
670
670
|
readonly compilerOptions: Schema.optional<Schema.Unknown>;
|
|
671
671
|
}>>>>>;
|
|
672
|
-
/** Canonical site URL used for Open Graph absolute URLs. */
|
|
673
|
-
readonly siteUrl: Schema.optional<Schema.String>;
|
|
674
672
|
/** Global Open Graph image configuration (overridden per-API). */
|
|
675
673
|
readonly ogImage: Schema.optional<Schema.Union<readonly [Schema.String, Schema.Struct<{
|
|
676
674
|
readonly url: Schema.String;
|
|
@@ -746,90 +744,6 @@ declare const PluginOptions: Schema.Struct<{
|
|
|
746
744
|
/** @public */
|
|
747
745
|
type PluginOptions = typeof PluginOptions.Encoded;
|
|
748
746
|
//#endregion
|
|
749
|
-
//#region src/schemas/opengraph.d.ts
|
|
750
|
-
/**
|
|
751
|
-
* Structured Open Graph image metadata (alternative to a plain URL string).
|
|
752
|
-
*
|
|
753
|
-
* @public
|
|
754
|
-
*/
|
|
755
|
-
declare const OpenGraphImageMetadata: Schema.Struct<{
|
|
756
|
-
/** Absolute URL of the image. */
|
|
757
|
-
readonly url: Schema.String;
|
|
758
|
-
/** HTTPS URL of the image (for secure contexts). */
|
|
759
|
-
readonly secureUrl: Schema.optional<Schema.String>;
|
|
760
|
-
/** MIME type of the image (e.g. `"image/png"`). */
|
|
761
|
-
readonly type: Schema.optional<Schema.String>;
|
|
762
|
-
/** Image width in pixels. */
|
|
763
|
-
readonly width: Schema.optional<Schema.Number>;
|
|
764
|
-
/** Image height in pixels. */
|
|
765
|
-
readonly height: Schema.optional<Schema.Number>;
|
|
766
|
-
/** Alt text for the image. */
|
|
767
|
-
readonly alt: Schema.optional<Schema.String>;
|
|
768
|
-
}>;
|
|
769
|
-
/** @public */
|
|
770
|
-
type OpenGraphImageMetadata = typeof OpenGraphImageMetadata.Type;
|
|
771
|
-
/**
|
|
772
|
-
* Open Graph image: either a plain URL string or structured `OpenGraphImageMetadata`.
|
|
773
|
-
*
|
|
774
|
-
* @public
|
|
775
|
-
*/
|
|
776
|
-
declare const OpenGraphImageConfig: Schema.Union<readonly [Schema.String, Schema.Struct<{
|
|
777
|
-
/** Absolute URL of the image. */
|
|
778
|
-
readonly url: Schema.String;
|
|
779
|
-
/** HTTPS URL of the image (for secure contexts). */
|
|
780
|
-
readonly secureUrl: Schema.optional<Schema.String>;
|
|
781
|
-
/** MIME type of the image (e.g. `"image/png"`). */
|
|
782
|
-
readonly type: Schema.optional<Schema.String>;
|
|
783
|
-
/** Image width in pixels. */
|
|
784
|
-
readonly width: Schema.optional<Schema.Number>;
|
|
785
|
-
/** Image height in pixels. */
|
|
786
|
-
readonly height: Schema.optional<Schema.Number>;
|
|
787
|
-
/** Alt text for the image. */
|
|
788
|
-
readonly alt: Schema.optional<Schema.String>;
|
|
789
|
-
}>]>;
|
|
790
|
-
/** @public */
|
|
791
|
-
type OpenGraphImageConfig = typeof OpenGraphImageConfig.Type;
|
|
792
|
-
/**
|
|
793
|
-
* Resolved Open Graph metadata emitted into each generated page's frontmatter.
|
|
794
|
-
*
|
|
795
|
-
* @public
|
|
796
|
-
*/
|
|
797
|
-
declare const OpenGraphMetadata: Schema.Struct<{
|
|
798
|
-
/** Canonical site base URL. */
|
|
799
|
-
readonly siteUrl: Schema.String;
|
|
800
|
-
/** Page route path (e.g. `/api/classes/myclass`). */
|
|
801
|
-
readonly pageRoute: Schema.String;
|
|
802
|
-
/** Page description for the `og:description` tag. */
|
|
803
|
-
readonly description: Schema.String;
|
|
804
|
-
/** ISO 8601 date string for `article:published_time`. */
|
|
805
|
-
readonly publishedTime: Schema.String;
|
|
806
|
-
/** ISO 8601 date string for `article:modified_time`. */
|
|
807
|
-
readonly modifiedTime: Schema.String;
|
|
808
|
-
/** Article section label (e.g. `"API"`). */
|
|
809
|
-
readonly section: Schema.String;
|
|
810
|
-
/** Article tag keywords. */
|
|
811
|
-
readonly tags: Schema.mutable<Schema.$Array<Schema.String>>;
|
|
812
|
-
/** Optional structured image metadata. */
|
|
813
|
-
readonly ogImage: Schema.optional<Schema.Struct<{
|
|
814
|
-
/** Absolute URL of the image. */
|
|
815
|
-
readonly url: Schema.String;
|
|
816
|
-
/** HTTPS URL of the image (for secure contexts). */
|
|
817
|
-
readonly secureUrl: Schema.optional<Schema.String>;
|
|
818
|
-
/** MIME type of the image (e.g. `"image/png"`). */
|
|
819
|
-
readonly type: Schema.optional<Schema.String>;
|
|
820
|
-
/** Image width in pixels. */
|
|
821
|
-
readonly width: Schema.optional<Schema.Number>;
|
|
822
|
-
/** Image height in pixels. */
|
|
823
|
-
readonly height: Schema.optional<Schema.Number>;
|
|
824
|
-
/** Alt text for the image. */
|
|
825
|
-
readonly alt: Schema.optional<Schema.String>;
|
|
826
|
-
}>>;
|
|
827
|
-
/** Open Graph object type (e.g. `"article"`). */
|
|
828
|
-
readonly ogType: Schema.String;
|
|
829
|
-
}>;
|
|
830
|
-
/** @public */
|
|
831
|
-
type OpenGraphMetadata = typeof OpenGraphMetadata.Type;
|
|
832
|
-
//#endregion
|
|
833
747
|
//#region src/config-helpers.d.ts
|
|
834
748
|
/**
|
|
835
749
|
* Metadata discovered from a single rslib-builder localPaths package folder.
|
|
@@ -940,6 +854,90 @@ declare const ApiExtractorPlugin: typeof ApiExtractorPluginImpl & {
|
|
|
940
854
|
};
|
|
941
855
|
};
|
|
942
856
|
//#endregion
|
|
857
|
+
//#region src/schemas/opengraph.d.ts
|
|
858
|
+
/**
|
|
859
|
+
* Structured Open Graph image metadata (alternative to a plain URL string).
|
|
860
|
+
*
|
|
861
|
+
* @public
|
|
862
|
+
*/
|
|
863
|
+
declare const OpenGraphImageMetadata: Schema.Struct<{
|
|
864
|
+
/** Absolute URL of the image. */
|
|
865
|
+
readonly url: Schema.String;
|
|
866
|
+
/** HTTPS URL of the image (for secure contexts). */
|
|
867
|
+
readonly secureUrl: Schema.optional<Schema.String>;
|
|
868
|
+
/** MIME type of the image (e.g. `"image/png"`). */
|
|
869
|
+
readonly type: Schema.optional<Schema.String>;
|
|
870
|
+
/** Image width in pixels. */
|
|
871
|
+
readonly width: Schema.optional<Schema.Number>;
|
|
872
|
+
/** Image height in pixels. */
|
|
873
|
+
readonly height: Schema.optional<Schema.Number>;
|
|
874
|
+
/** Alt text for the image. */
|
|
875
|
+
readonly alt: Schema.optional<Schema.String>;
|
|
876
|
+
}>;
|
|
877
|
+
/** @public */
|
|
878
|
+
type OpenGraphImageMetadata = typeof OpenGraphImageMetadata.Type;
|
|
879
|
+
/**
|
|
880
|
+
* Open Graph image: either a plain URL string or structured `OpenGraphImageMetadata`.
|
|
881
|
+
*
|
|
882
|
+
* @public
|
|
883
|
+
*/
|
|
884
|
+
declare const OpenGraphImageConfig: Schema.Union<readonly [Schema.String, Schema.Struct<{
|
|
885
|
+
/** Absolute URL of the image. */
|
|
886
|
+
readonly url: Schema.String;
|
|
887
|
+
/** HTTPS URL of the image (for secure contexts). */
|
|
888
|
+
readonly secureUrl: Schema.optional<Schema.String>;
|
|
889
|
+
/** MIME type of the image (e.g. `"image/png"`). */
|
|
890
|
+
readonly type: Schema.optional<Schema.String>;
|
|
891
|
+
/** Image width in pixels. */
|
|
892
|
+
readonly width: Schema.optional<Schema.Number>;
|
|
893
|
+
/** Image height in pixels. */
|
|
894
|
+
readonly height: Schema.optional<Schema.Number>;
|
|
895
|
+
/** Alt text for the image. */
|
|
896
|
+
readonly alt: Schema.optional<Schema.String>;
|
|
897
|
+
}>]>;
|
|
898
|
+
/** @public */
|
|
899
|
+
type OpenGraphImageConfig = typeof OpenGraphImageConfig.Type;
|
|
900
|
+
/**
|
|
901
|
+
* Resolved Open Graph metadata emitted into each generated page's frontmatter.
|
|
902
|
+
*
|
|
903
|
+
* @public
|
|
904
|
+
*/
|
|
905
|
+
declare const OpenGraphMetadata: Schema.Struct<{
|
|
906
|
+
/** Canonical site base URL. */
|
|
907
|
+
readonly siteUrl: Schema.String;
|
|
908
|
+
/** Page route path (e.g. `/api/classes/myclass`). */
|
|
909
|
+
readonly pageRoute: Schema.String;
|
|
910
|
+
/** Page description for the `og:description` tag. */
|
|
911
|
+
readonly description: Schema.String;
|
|
912
|
+
/** ISO 8601 date string for `article:published_time`. */
|
|
913
|
+
readonly publishedTime: Schema.String;
|
|
914
|
+
/** ISO 8601 date string for `article:modified_time`. */
|
|
915
|
+
readonly modifiedTime: Schema.String;
|
|
916
|
+
/** Article section label (e.g. `"API"`). */
|
|
917
|
+
readonly section: Schema.String;
|
|
918
|
+
/** Article tag keywords. */
|
|
919
|
+
readonly tags: Schema.mutable<Schema.$Array<Schema.String>>;
|
|
920
|
+
/** Optional structured image metadata. */
|
|
921
|
+
readonly ogImage: Schema.optional<Schema.Struct<{
|
|
922
|
+
/** Absolute URL of the image. */
|
|
923
|
+
readonly url: Schema.String;
|
|
924
|
+
/** HTTPS URL of the image (for secure contexts). */
|
|
925
|
+
readonly secureUrl: Schema.optional<Schema.String>;
|
|
926
|
+
/** MIME type of the image (e.g. `"image/png"`). */
|
|
927
|
+
readonly type: Schema.optional<Schema.String>;
|
|
928
|
+
/** Image width in pixels. */
|
|
929
|
+
readonly width: Schema.optional<Schema.Number>;
|
|
930
|
+
/** Image height in pixels. */
|
|
931
|
+
readonly height: Schema.optional<Schema.Number>;
|
|
932
|
+
/** Alt text for the image. */
|
|
933
|
+
readonly alt: Schema.optional<Schema.String>;
|
|
934
|
+
}>>;
|
|
935
|
+
/** Open Graph object type (e.g. `"article"`). */
|
|
936
|
+
readonly ogType: Schema.String;
|
|
937
|
+
}>;
|
|
938
|
+
/** @public */
|
|
939
|
+
type OpenGraphMetadata = typeof OpenGraphMetadata.Type;
|
|
940
|
+
//#endregion
|
|
943
941
|
//#region src/serve.d.ts
|
|
944
942
|
/**
|
|
945
943
|
* Which RSPress server {@link serve} runs.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { BuildId, PageConcurrency, SuppressExampleErrors, Thresholds } from "../BuildEnv.js";
|
|
2
|
+
import { OgService } from "../services/OgService.js";
|
|
3
|
+
import { collectShikiThemes } from "../markdown/shiki-utils.js";
|
|
4
|
+
import { HighlighterService } from "../services/HighlighterService.js";
|
|
5
|
+
import { TwoslashEnvironments } from "../services/TwoslashEnvironments.js";
|
|
6
|
+
import { PluginConfig } from "../services/PluginConfig.js";
|
|
7
|
+
import { PlatformLive } from "./xdg.js";
|
|
8
|
+
import { TypeRegistryService } from "../services/TypeRegistryService.js";
|
|
9
|
+
import { TwoslashCacheService } from "../services/TwoslashCacheService.js";
|
|
10
|
+
import { ConfigService } from "../services/ConfigService.js";
|
|
11
|
+
import { makeSummaryLoggerLayer } from "./observability.js";
|
|
12
|
+
import { Layer } from "effect";
|
|
13
|
+
import { SnapshotService } from "@tsdoctor/snapshot";
|
|
14
|
+
import { NodeFileSystem } from "@effect/platform-node";
|
|
15
|
+
|
|
16
|
+
//#region src/layers/AppLayer.ts
|
|
17
|
+
/**
|
|
18
|
+
* The build's layer stack, tiered.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* `plugin.ts` used to merge eleven layers side by side in one `Layer.mergeAll`
|
|
22
|
+
* — `NodeFileSystem.layer` (platform) next to `TypeRegistryService.layer`
|
|
23
|
+
* (domain) next to `makeSummaryLoggerLayer` (observability) — with one of them
|
|
24
|
+
* carrying a local `Layer.provide` because a flat merge could not feed it its
|
|
25
|
+
* dependencies. Reading that told you what the build contains but not what
|
|
26
|
+
* depends on what.
|
|
27
|
+
*
|
|
28
|
+
* The tiers below are ordered by what they may reach: platform knows nothing
|
|
29
|
+
* about this plugin, core services know the platform, and build-scoped services
|
|
30
|
+
* know both.
|
|
31
|
+
*
|
|
32
|
+
* @packageDocumentation
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Build both stacks for one build.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* **A layer factory: call it once and bind the result to a `const`.** Layers
|
|
39
|
+
* memoize by reference, so a second call mints a second stack — a second Shiki
|
|
40
|
+
* highlighter, a second snapshot database, a second metric registry.
|
|
41
|
+
*/
|
|
42
|
+
function makeAppLayers(input) {
|
|
43
|
+
/**
|
|
44
|
+
* Per-build configuration, provided to BOTH stacks. Sharing these values is
|
|
45
|
+
* what lets a sync island and an Effect program agree on the build id and
|
|
46
|
+
* the slow-block threshold without either being handed them.
|
|
47
|
+
*/
|
|
48
|
+
const BuildEnvLayer = Layer.mergeAll(Layer.succeed(BuildId, input.buildId), Layer.succeed(Thresholds, input.obs.thresholds), Layer.succeed(PageConcurrency, input.pageConcurrency), Layer.succeed(SuppressExampleErrors, input.options.errors?.example !== "show"));
|
|
49
|
+
/**
|
|
50
|
+
* Sinks, metrics and the logger gate. Synchronously buildable, which is what
|
|
51
|
+
* lets the emitter stack below reuse it wholesale.
|
|
52
|
+
*/
|
|
53
|
+
const ObservabilityLayer = Layer.mergeAll(input.eventBus, input.metrics.layer, makeSummaryLoggerLayer(input.obs.logLevel));
|
|
54
|
+
/** Services that own a resource and need only the platform to build. */
|
|
55
|
+
const CoreLayer = Layer.mergeAll(TypeRegistryService.layer, TwoslashCacheService.layer, SnapshotService.layer(input.dbPath), Layer.provide(OgService.layer, PlatformLive));
|
|
56
|
+
/** Bound to a `const`: this is a factory, and a second call acquires a second highlighter. */
|
|
57
|
+
const HighlighterLive = HighlighterService.layer(collectShikiThemes(input.options.api ? [input.options.api] : input.options.apis ?? []));
|
|
58
|
+
/** Services scoped to this build's configuration. */
|
|
59
|
+
const BuildLayer = Layer.mergeAll(Layer.succeed(PluginConfig, input.options), HighlighterLive, TwoslashEnvironments.layer, BuildEnvLayer);
|
|
60
|
+
return {
|
|
61
|
+
app: Layer.provideMerge(ConfigService.layer, Layer.mergeAll(BuildLayer, CoreLayer, ObservabilityLayer, NodeFileSystem.layer)),
|
|
62
|
+
emitter: Layer.mergeAll(ObservabilityLayer, BuildEnvLayer)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
export { makeAppLayers };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { PluginEvent } from "../observability/events.js";
|
|
2
|
+
import { emit } from "../observability/EventBus.js";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/layers/api-results.ts
|
|
6
|
+
/**
|
|
7
|
+
* Accumulating one API's resolution result into the build-wide totals.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* `ConfigService.layer` resolves APIs down three paths — versioned, single
|
|
11
|
+
* non-versioned, and multi-API — and each one ended with a near-identical
|
|
12
|
+
* ~35-line block that merged the same three accumulators and then emitted the
|
|
13
|
+
* same two events per VFS entry. Three copies of one algorithm is three places
|
|
14
|
+
* for it to drift, and the third copy had ALREADY drifted: it emits its events
|
|
15
|
+
* inside the per-API effect and merges afterwards, rather than doing both in
|
|
16
|
+
* one pass.
|
|
17
|
+
*
|
|
18
|
+
* Splitting the block in two is what makes all three paths expressible. The
|
|
19
|
+
* merge is pure and the emission is effectful, and the multi-API path needs
|
|
20
|
+
* them at different moments; a single combined helper would have fitted two
|
|
21
|
+
* paths and forced the third to keep its own copy.
|
|
22
|
+
*
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Merge one result into the build-wide accumulators.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* Mutates `acc` rather than returning a new one. The accumulators are three
|
|
30
|
+
* `const` collections in a long generator that appends to them from several
|
|
31
|
+
* branches, and threading a replacement through every branch would be a larger
|
|
32
|
+
* change than this task is buying.
|
|
33
|
+
*
|
|
34
|
+
* **The VFS is a single flat namespace shared by every documented API.** A
|
|
35
|
+
* later entry silently overwrites an earlier one at the same path, which is
|
|
36
|
+
* load-bearing rather than accidental: cross-package type references resolve
|
|
37
|
+
* only because every package's declarations live in one environment (see
|
|
38
|
+
* `type-loading-vfs.md`).
|
|
39
|
+
*/
|
|
40
|
+
function mergeApiResult(acc, result) {
|
|
41
|
+
for (const [filepath, content] of result.vfs.entries()) acc.combinedVfs.set(filepath, content);
|
|
42
|
+
if (result.externalPackages.length > 0) acc.allExternalPackages.push(...result.externalPackages);
|
|
43
|
+
if (result.config) acc.apiConfigs.push(result.config);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Emit the per-entry VFS events for one API's payloads.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* `ImportsPrepended` fires only when imports were actually prepended, so an
|
|
50
|
+
* entry that needed none produces one event rather than two.
|
|
51
|
+
*
|
|
52
|
+
* `wantTrace` gates the two heavy fields — the full declaration text and the
|
|
53
|
+
* resolved import refs. Both are only ever read by the JSONL trace sink, and
|
|
54
|
+
* carrying them unconditionally would put every generated declaration file
|
|
55
|
+
* through the event bus on every build.
|
|
56
|
+
*/
|
|
57
|
+
function emitVfsPayloadEvents(packageName, payloads, wantTrace) {
|
|
58
|
+
return Effect.gen(function* () {
|
|
59
|
+
for (const payload of payloads) {
|
|
60
|
+
const ctx = {
|
|
61
|
+
packageName,
|
|
62
|
+
...payload.entryPoint ? { entryPoint: payload.entryPoint } : {}
|
|
63
|
+
};
|
|
64
|
+
yield* emit(PluginEvent.VfsGenerated({
|
|
65
|
+
ctx,
|
|
66
|
+
level: "debug",
|
|
67
|
+
file: payload.file,
|
|
68
|
+
declCount: payload.declCount,
|
|
69
|
+
contentHash: payload.contentHash,
|
|
70
|
+
...wantTrace && payload.content ? { content: payload.content } : {}
|
|
71
|
+
}));
|
|
72
|
+
if (payload.hasImports) yield* emit(PluginEvent.ImportsPrepended({
|
|
73
|
+
ctx,
|
|
74
|
+
level: "debug",
|
|
75
|
+
file: payload.file,
|
|
76
|
+
imports: wantTrace ? payload.importRefs : []
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
export { emitVfsPayloadEvents, mergeApiResult };
|
package/layers/build-metrics.js
CHANGED
|
@@ -18,7 +18,7 @@ function makeMetricStore() {
|
|
|
18
18
|
* build still gets its own counters — see {@link MetricRegistryLive}.
|
|
19
19
|
*
|
|
20
20
|
* Extracted into its own module so that `metrics-sink.ts` can import it
|
|
21
|
-
* without creating a circular dependency through `
|
|
21
|
+
* without creating a circular dependency through `observability.ts`
|
|
22
22
|
* (which itself imports `metrics-sink.ts`).
|
|
23
23
|
*/
|
|
24
24
|
const BuildMetrics = {
|