@savvy-web/tsdown-plugins 2.3.0 → 2.4.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/README.md CHANGED
@@ -46,7 +46,7 @@ export default defineConfig({
46
46
  - **Multi-target resolution** — `resolveTargets` turns a `publishConfig.targets` map into the distinct byte-variant groups to build and the registry bindings for each; `writeTargetsBinding` persists that resolution as `dist/prod/targets.json` for the release step.
47
47
  - **JSX resolution** — `resolveJsxConfig` and `readTsconfigJsx` derive the effective JSX transform from a package's tsconfig, with an explicit override winning. The tsconfig is read through a loader that honors JSONC syntax and `extends` chains, so a `jsx` setting inherited from a base config resolves.
48
48
  - **Executable binaries** — `normalizeExeOptions` fills the SEA defaults and infers targets from the package's `os`/`cpu`; `runExeBuild` drives `@tsdown/exe` to compile the binaries.
49
- - **Config validation** — the `ConfigValidator` Effect service (with `ConfigValidatorLive`) fast-fails on a bad `publishConfig.targets`, `exe` or `meta` config, raising the typed `ConfigValidationError`.
49
+ - **Config validation** — the `ConfigValidator` Effect service (with `ConfigValidator.layer`) fast-fails on a bad `publishConfig.targets`, `exe` or `meta` config, raising the typed `ConfigValidationError`.
50
50
  - **dts tsconfig port** — `buildResolvedTsconfig` and `writeResolvedTsconfig` write a temp tsconfig with absolute paths so type declarations emit cleanly under pnpm symlinks.
51
51
  - **Per-target build loop** — `deriveTargetGroupOptions` and `buildTargetGroups` map a target to its `tsdown` options and run the build once per target, exposed as a helper so the escape hatch gets multi-target builds too. A `format` of `["esm", "cjs"]` (the `BuildFormat` type) derives a dual-format build — a require-able CJS output with default-export interop and `.d.cts` declarations alongside the ESM one. The `bundleNodeModules`, `bundledPackages` and `dtsExternals` options thread the dependency-bundling posture into both the JS and declaration passes. A per-entry override partition can also set `platform` (the JS-pass target, `"browser"` for a client bundle), `css` (forwarded to tsdown's `css` option for `@tsdown/css`) and `outSubdir` (build the partition into an isolated `<group>/pkg/<subdir>/` sub-package). The `define` option forwards compile-time global replacements to both passes, merged with an auto-injected `process.env.__PACKAGE_VERSION__` constant.
52
52
  - **Loose files** — `normalizeLooseFiles` resolves a `LooseFiles` map of literal output filenames to `NormalizedLooseFile` descriptors, inferring the module format from each `.mjs`/`.cjs` key and raising `ConfigValidationError` on a path separator, an unsupported extension or an ambiguous `.js`. `buildTargetGroups` takes the normalized form as its `looseFiles` option and emits one extra single-entry, bundled, declaration-free and manifest-free pass per file per target group, inheriting the group's bundling posture so each file is self-contained.
@@ -1,12 +1,68 @@
1
- import { Context } from "effect";
1
+ import { ConfigValidationError } from "../errors.js";
2
+ import { normalizeLooseFiles } from "../build/loose-files.js";
3
+ import { normalizeExeOptions } from "../exe/config.js";
4
+ import { resolveTargets } from "../targets/resolve-targets.js";
5
+ import { existsSync, statSync } from "node:fs";
6
+ import { Context, Effect, Layer } from "effect";
2
7
 
3
8
  //#region src/config-validation/ConfigValidator.ts
9
+ const VALID_SYNTAX_KINDS = /* @__PURE__ */ new Set([
10
+ "block",
11
+ "inline",
12
+ "modifier"
13
+ ]);
14
+ /** Synchronous rule set; throws ConfigValidationError on the first violation. */
15
+ function check(input) {
16
+ if (input.targets !== void 0 && Object.keys(input.targets).length > 0) resolveTargets({
17
+ targets: input.targets,
18
+ baseName: input.baseName
19
+ });
20
+ if (input.exe !== void 0) {
21
+ const specs = normalizeExeOptions(input.exe, input.osCpu ?? {
22
+ os: [],
23
+ cpu: []
24
+ });
25
+ for (const spec of specs) {
26
+ if (spec.fileName.trim() === "") throw new ConfigValidationError({
27
+ path: "exe.fileName",
28
+ reason: "an exe binary needs a non-empty fileName"
29
+ });
30
+ if (spec.targets.length === 0) throw new ConfigValidationError({
31
+ path: `exe.${spec.fileName}.targets`,
32
+ reason: "no targets: the package declares no os/cpu and the exe config states none"
33
+ });
34
+ }
35
+ }
36
+ if (input.meta !== void 0) {
37
+ if (!input.hasExports) throw new ConfigValidationError({
38
+ path: "meta",
39
+ reason: "meta requires an exports map to extract an api-model from"
40
+ });
41
+ for (const tag of input.meta.tsdoc?.tagDefinitions ?? []) if (!VALID_SYNTAX_KINDS.has(tag.syntaxKind)) throw new ConfigValidationError({
42
+ path: "meta.tsdoc.tagDefinitions",
43
+ reason: `tag "${tag.tagName}" has an invalid syntaxKind "${tag.syntaxKind}"`
44
+ });
45
+ for (const p of input.meta.localPaths ?? []) if (existsSync(p) && !statSync(p).isDirectory()) throw new ConfigValidationError({
46
+ path: "meta.localPaths",
47
+ reason: `"${p}" exists but is not a directory`
48
+ });
49
+ }
50
+ if (input.looseFiles !== void 0) normalizeLooseFiles(input.looseFiles);
51
+ }
4
52
  /**
5
53
  * Fast-fail config validator; runs first in the bundler over the resolved config.
6
54
  *
7
55
  * @public
8
56
  */
9
- var ConfigValidator = class extends Context.Service()("@savvy-web/tsdown-plugins/ConfigValidator") {};
57
+ var ConfigValidator = class extends Context.Service()("@savvy-web/tsdown-plugins/ConfigValidator") {
58
+ static layer = Layer.succeed(this, { validate: (input) => Effect.try({
59
+ try: () => check(input),
60
+ catch: (e) => e instanceof ConfigValidationError ? e : new ConfigValidationError({
61
+ path: "config",
62
+ reason: String(e)
63
+ })
64
+ }) });
65
+ };
10
66
 
11
67
  //#endregion
12
68
  export { ConfigValidator };
@@ -9,7 +9,8 @@ import { resolve } from "node:path";
9
9
  * @public
10
10
  */
11
11
  function packageJsonEntries(options = {}) {
12
- return extractEntries(options.pkg ?? JSON.parse(readFileSync(resolve(options.cwd ?? process.cwd(), "package.json"), "utf-8")), {
12
+ const pkg = options.pkg ?? JSON.parse(readFileSync(resolve(options.cwd ?? process.cwd(), "package.json"), "utf-8"));
13
+ return extractEntries(pkg, {
13
14
  exportsAsIndexes: options.exportsAsIndexes,
14
15
  excludeSources: options.excludeSources
15
16
  }).entries;
package/index.d.ts CHANGED
@@ -1208,15 +1208,9 @@ declare const ConfigValidator_base: Context.ServiceClass<ConfigValidator, "@savv
1208
1208
  *
1209
1209
  * @public
1210
1210
  */
1211
- declare class ConfigValidator extends ConfigValidator_base {}
1212
- //#endregion
1213
- //#region src/config-validation/ConfigValidatorLive.d.ts
1214
- /**
1215
- * Live ConfigValidator: wraps the synchronous rule set, surfacing ConfigValidationError as a typed Effect failure.
1216
- *
1217
- * @public
1218
- */
1219
- declare const ConfigValidatorLive: Layer.Layer<ConfigValidator, never, never>;
1211
+ declare class ConfigValidator extends ConfigValidator_base {
1212
+ static readonly layer: Layer.Layer<ConfigValidator>;
1213
+ }
1220
1214
  //#endregion
1221
1215
  //#region src/dts/reexport-stub.d.ts
1222
1216
  /**
@@ -1737,6 +1731,17 @@ declare function writeIssuesArtifact(opts: {
1737
1731
  } | undefined;
1738
1732
  }): string;
1739
1733
  //#endregion
1734
+ //#region src/report/metrics-plugin.d.ts
1735
+ /**
1736
+ * Rolldown plugin that records emitted-file metrics into the BuildCollector via writeBundle (which
1737
+ * fires for the JS pass AND the emitDtsOnly dts pass — verified against tsdown 0.22.3), plus a
1738
+ * defensive onLog for rolldown-level diagnostics that bypass tsdown's logger. Append it to each
1739
+ * build pass's `plugins` array. `bytes` is taken from the in-memory chunk/asset content (no fs);
1740
+ * `gzip` is computed only when `verbose`.
1741
+ * @public
1742
+ */
1743
+ declare function buildMetricsPlugin(collector: BuildCollector, groupId: string, pass: PassKind, verbose: boolean): Plugin;
1744
+ //#endregion
1740
1745
  //#region src/report/services/EnvironmentDetector.d.ts
1741
1746
  /** @public */
1742
1747
  type Environment = "agent-shell" | "terminal" | "ci-github" | "ci-generic";
@@ -1744,11 +1749,9 @@ declare const EnvironmentDetector_base: Context.ServiceClass<EnvironmentDetector
1744
1749
  readonly detect: () => Effect.Effect<Environment>;
1745
1750
  }>;
1746
1751
  /** @public */
1747
- declare class EnvironmentDetector extends EnvironmentDetector_base {}
1748
- //#endregion
1749
- //#region src/report/layers/EnvironmentDetectorLive.d.ts
1750
- /** @public */
1751
- declare const EnvironmentDetectorLive: Layer.Layer<EnvironmentDetector, never, never>;
1752
+ declare class EnvironmentDetector extends EnvironmentDetector_base {
1753
+ static readonly layer: Layer.Layer<EnvironmentDetector>;
1754
+ }
1752
1755
  //#endregion
1753
1756
  //#region src/report/services/ExecutorResolver.d.ts
1754
1757
  /** @public */
@@ -1757,11 +1760,9 @@ declare const ExecutorResolver_base: Context.ServiceClass<ExecutorResolver, "@sa
1757
1760
  readonly resolve: (env: Environment) => Effect.Effect<Executor>;
1758
1761
  }>;
1759
1762
  /** @public */
1760
- declare class ExecutorResolver extends ExecutorResolver_base {}
1761
- //#endregion
1762
- //#region src/report/layers/ExecutorResolverLive.d.ts
1763
- /** @public */
1764
- declare const ExecutorResolverLive: Layer.Layer<ExecutorResolver, never, never>;
1763
+ declare class ExecutorResolver extends ExecutorResolver_base {
1764
+ static readonly layer: Layer.Layer<ExecutorResolver>;
1765
+ }
1765
1766
  //#endregion
1766
1767
  //#region src/report/services/FormatSelector.d.ts
1767
1768
  /** @public */
@@ -1770,37 +1771,22 @@ declare const FormatSelector_base: Context.ServiceClass<FormatSelector, "@savvy-
1770
1771
  readonly select: (executor: Executor, explicit?: OutputFormat, env?: Environment) => Effect.Effect<OutputFormat>;
1771
1772
  }>;
1772
1773
  /** @public */
1773
- declare class FormatSelector extends FormatSelector_base {}
1774
- //#endregion
1775
- //#region src/report/layers/FormatSelectorLive.d.ts
1776
- /** @public */
1777
- declare const FormatSelectorLive: Layer.Layer<FormatSelector, never, never>;
1774
+ declare class FormatSelector extends FormatSelector_base {
1775
+ static readonly layer: Layer.Layer<FormatSelector>;
1776
+ }
1778
1777
  //#endregion
1779
1778
  //#region src/report/services/OutputRenderer.d.ts
1780
1779
  declare const OutputRenderer_base: Context.ServiceClass<OutputRenderer, "@savvy-web/tsdown-plugins/OutputRenderer", {
1781
1780
  readonly render: (reports: ReadonlyArray<BuildReport>, format: OutputFormat, ctx: FormatterContext) => Effect.Effect<ReadonlyArray<RenderedOutput>>;
1782
1781
  }>;
1783
1782
  /** @public */
1784
- declare class OutputRenderer extends OutputRenderer_base {}
1785
- //#endregion
1786
- //#region src/report/layers/OutputRendererLive.d.ts
1787
- /** @public */
1788
- declare const OutputRendererLive: Layer.Layer<OutputRenderer, never, never>;
1789
- //#endregion
1790
- //#region src/report/metrics-plugin.d.ts
1791
- /**
1792
- * Rolldown plugin that records emitted-file metrics into the BuildCollector via writeBundle (which
1793
- * fires for the JS pass AND the emitDtsOnly dts pass — verified against tsdown 0.22.3), plus a
1794
- * defensive onLog for rolldown-level diagnostics that bypass tsdown's logger. Append it to each
1795
- * build pass's `plugins` array. `bytes` is taken from the in-memory chunk/asset content (no fs);
1796
- * `gzip` is computed only when `verbose`.
1797
- * @public
1798
- */
1799
- declare function buildMetricsPlugin(collector: BuildCollector, groupId: string, pass: PassKind, verbose: boolean): Plugin;
1783
+ declare class OutputRenderer extends OutputRenderer_base {
1784
+ static readonly layer: Layer.Layer<OutputRenderer>;
1785
+ }
1800
1786
  //#endregion
1801
1787
  //#region src/report/pipeline.d.ts
1802
1788
  /** @public */
1803
- declare const ReportPipelineLive: Layer.Layer<EnvironmentDetector | ExecutorResolver | FormatSelector | OutputRenderer, never, never>;
1789
+ declare const ReportPipeline: Layer.Layer<EnvironmentDetector | ExecutorResolver | FormatSelector | OutputRenderer, never, never>;
1804
1790
  /** @public */
1805
1791
  interface RenderReportOptions {
1806
1792
  readonly explicitFormat?: OutputFormat;
@@ -1870,5 +1856,5 @@ declare function resolveTargets(options: {
1870
1856
  baseName: string;
1871
1857
  }): TargetResolution;
1872
1858
  //#endregion
1873
- export { type AmbientDtsEntry, BuildCollector, BuildCollectorTag, type BuildEmittedManifestOptions, type BuildFormat, type BuildGroupSpec, type BuildIssues, type BuildPlatform, type BuildReport, BuildReport as BuildReportSchema, type BuildTargetGroupsOptions, CatalogAssemblyError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, type CopyAmbientDtsOptions, type CssOptions, DEFAULT_EXE_NODE_VERSION, DependencyResolutionError, type DeriveOptions, type DerivedTsdownOptions, type DiagnosticEntry, type DiagnosticInput, type DtsExportClass, type DualExports, type EmitManifestOptions, type EmittedFile, type EntryOverride, type Environment, EnvironmentDetector, EnvironmentDetectorLive, type ExeBuild, type ExeConfig, type ExeRewrite, type ExeSeaConfig, type ExeTarget, type ExeTargetInput, type Executor, ExecutorResolver, ExecutorResolverLive, type ExtractAmbientOptions, type ExtractOptions, type ExtractResult, FormatSelector, FormatSelectorLive, type Formatter, type FormatterContext, type GenerateMetaOptions, type Json, JsonFormatter, type JsxConfig, type LooseFileSpec, type LooseFiles, ManifestDecodeError, type ManifestLike, MarkdownFormatter, MetaGenerationError, type MetaOptions, type MetaResult, type ModuleExportNames, type NextVersions, type NormalizedExe, type NormalizedLooseFile, type NormalizedMeta, type OutputFormat, OutputRenderer, OutputRendererLive, type PackageJsonEntriesOptions, type PackageJsonLike, type PassKind, type PassReport, type PkgOsCpu, type PlainDiagnostic, type PortableTsconfig, type PublishTargetObject, type PublishTargetValue, type PublishTargets, type ReexportBarrelAnalysis, type RenderReportOptions, type RenderedOutput, ReportPipelineLive, ReportTimings, type ResolvedCompilerOptions, type ResolvedGroup, type ResolvedTarget, type ResolvedTsconfig, type ResolvedTsconfigOptions, type RunExeBuildOptions, type RunMetaPassOptions, SilentFormatter, type TargetGroupId, type TargetGroupRef, type TargetGroupReport, TargetGroupReport as TargetGroupReportSchema, type TargetResolution, TerminalFormatter, type Timer, type TransformManifestOptions, type TsconfigJsx, type TsdocOptions, type TsdocTagDefinition, type TsdownBuild, type TsdownLogger, UnresolvedDependencyError, type ValidationInput, type WarningSuppressionRule, ambientOutName, analyzeReexportBarrel, applySubdirMetaEntries, assertNoEntryCollisions, buildEmittedManifest, buildMetricsPlugin, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, classifyDtsExport, collectExportNames, computeExeFileName, copyAmbientDts, copyPublicDir, createEntryName, createTimer, createTsdownLogger, declarationExt, defaultManifestTransform, deriveExportPaths, deriveTargetGroupOptions, emitManifest, extractAmbientDts, extractEntries, findRelativeSpecifiers, flattenIssues, formatTime, generateMeta, isTargetObject, mixedDtsExportError, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReexportStub, renderReport, resolveJsxConfig, resolveManifest, resolveNextVersions, resolvePortableTsconfig, resolveTargets, rewriteMetaVersions, runExeBuild, runMetaPass, serializeIssues, transformBin, transformExports, transformManifest, writeDtsEmitTsconfig, writeIssuesArtifact, writeResolvedTsconfig, writeTargetsBinding };
1859
+ export { type AmbientDtsEntry, BuildCollector, BuildCollectorTag, type BuildEmittedManifestOptions, type BuildFormat, type BuildGroupSpec, type BuildIssues, type BuildPlatform, type BuildReport, BuildReport as BuildReportSchema, type BuildTargetGroupsOptions, CatalogAssemblyError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, type CopyAmbientDtsOptions, type CssOptions, DEFAULT_EXE_NODE_VERSION, DependencyResolutionError, type DeriveOptions, type DerivedTsdownOptions, type DiagnosticEntry, type DiagnosticInput, type DtsExportClass, type DualExports, type EmitManifestOptions, type EmittedFile, type EntryOverride, type Environment, EnvironmentDetector, type ExeBuild, type ExeConfig, type ExeRewrite, type ExeSeaConfig, type ExeTarget, type ExeTargetInput, type Executor, ExecutorResolver, type ExtractAmbientOptions, type ExtractOptions, type ExtractResult, FormatSelector, type Formatter, type FormatterContext, type GenerateMetaOptions, type Json, JsonFormatter, type JsxConfig, type LooseFileSpec, type LooseFiles, ManifestDecodeError, type ManifestLike, MarkdownFormatter, MetaGenerationError, type MetaOptions, type MetaResult, type ModuleExportNames, type NextVersions, type NormalizedExe, type NormalizedLooseFile, type NormalizedMeta, type OutputFormat, OutputRenderer, type PackageJsonEntriesOptions, type PackageJsonLike, type PassKind, type PassReport, type PkgOsCpu, type PlainDiagnostic, type PortableTsconfig, type PublishTargetObject, type PublishTargetValue, type PublishTargets, type ReexportBarrelAnalysis, type RenderReportOptions, type RenderedOutput, ReportPipeline, ReportTimings, type ResolvedCompilerOptions, type ResolvedGroup, type ResolvedTarget, type ResolvedTsconfig, type ResolvedTsconfigOptions, type RunExeBuildOptions, type RunMetaPassOptions, SilentFormatter, type TargetGroupId, type TargetGroupRef, type TargetGroupReport, TargetGroupReport as TargetGroupReportSchema, type TargetResolution, TerminalFormatter, type Timer, type TransformManifestOptions, type TsconfigJsx, type TsdocOptions, type TsdocTagDefinition, type TsdownBuild, type TsdownLogger, UnresolvedDependencyError, type ValidationInput, type WarningSuppressionRule, ambientOutName, analyzeReexportBarrel, applySubdirMetaEntries, assertNoEntryCollisions, buildEmittedManifest, buildMetricsPlugin, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, classifyDtsExport, collectExportNames, computeExeFileName, copyAmbientDts, copyPublicDir, createEntryName, createTimer, createTsdownLogger, declarationExt, defaultManifestTransform, deriveExportPaths, deriveTargetGroupOptions, emitManifest, extractAmbientDts, extractEntries, findRelativeSpecifiers, flattenIssues, formatTime, generateMeta, isTargetObject, mixedDtsExportError, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReexportStub, renderReport, resolveJsxConfig, resolveManifest, resolveNextVersions, resolvePortableTsconfig, resolveTargets, rewriteMetaVersions, runExeBuild, runMetaPass, serializeIssues, transformBin, transformExports, transformManifest, writeDtsEmitTsconfig, writeIssuesArtifact, writeResolvedTsconfig, writeTargetsBinding };
1874
1860
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -18,11 +18,10 @@ import { buildTargetGroups } from "./build/build-target-groups.js";
18
18
  import { normalizeLooseFiles } from "./build/loose-files.js";
19
19
  import { removeDeclarationMaps } from "./build/strip-maps.js";
20
20
  import { resolveNextVersions } from "./changesets/next-versions.js";
21
- import { ConfigValidator } from "./config-validation/ConfigValidator.js";
22
21
  import { DEFAULT_EXE_NODE_VERSION, normalizeExeOptions } from "./exe/config.js";
23
22
  import { isTargetObject } from "./targets/config.js";
24
23
  import { resolveTargets } from "./targets/resolve-targets.js";
25
- import { ConfigValidatorLive } from "./config-validation/ConfigValidatorLive.js";
24
+ import { ConfigValidator } from "./config-validation/ConfigValidator.js";
26
25
  import { packageJsonEntries } from "./entry/package-json-entries.js";
27
26
  import { runExeBuild } from "./exe/build.js";
28
27
  import { computeExeFileName } from "./exe/filename.js";
@@ -41,15 +40,11 @@ import { SilentFormatter } from "./report/formatters/silent.js";
41
40
  import { TerminalFormatter } from "./report/formatters/terminal.js";
42
41
  import { flattenIssues, serializeIssues, writeIssuesArtifact } from "./report/issues-artifact.js";
43
42
  import { EnvironmentDetector } from "./report/services/EnvironmentDetector.js";
44
- import { EnvironmentDetectorLive } from "./report/layers/EnvironmentDetectorLive.js";
45
43
  import { ExecutorResolver } from "./report/services/ExecutorResolver.js";
46
- import { ExecutorResolverLive } from "./report/layers/ExecutorResolverLive.js";
47
44
  import { FormatSelector } from "./report/services/FormatSelector.js";
48
- import { FormatSelectorLive } from "./report/layers/FormatSelectorLive.js";
49
45
  import { OutputRenderer } from "./report/services/OutputRenderer.js";
50
- import { OutputRendererLive } from "./report/layers/OutputRendererLive.js";
51
- import { ReportPipelineLive, renderReport } from "./report/pipeline.js";
46
+ import { ReportPipeline, renderReport } from "./report/pipeline.js";
52
47
  import { writeTargetsBinding } from "./targets/binding.js";
53
48
  import { CatalogAssemblyError, DependencyResolutionError, ManifestDecodeError, UnresolvedDependencyError } from "@effected/npm";
54
49
 
55
- export { BuildCollector, BuildCollectorTag, BuildReport as BuildReportSchema, CatalogAssemblyError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, DEFAULT_EXE_NODE_VERSION, DependencyResolutionError, EnvironmentDetector, EnvironmentDetectorLive, ExecutorResolver, ExecutorResolverLive, FormatSelector, FormatSelectorLive, JsonFormatter, ManifestDecodeError, MarkdownFormatter, MetaGenerationError, OutputRenderer, OutputRendererLive, ReportPipelineLive, ReportTimings, SilentFormatter, TargetGroupReport as TargetGroupReportSchema, TerminalFormatter, UnresolvedDependencyError, ambientOutName, analyzeReexportBarrel, applySubdirMetaEntries, assertNoEntryCollisions, buildEmittedManifest, buildMetricsPlugin, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, classifyDtsExport, collectExportNames, computeExeFileName, copyAmbientDts, copyPublicDir, createEntryName, createTimer, createTsdownLogger, declarationExt, defaultManifestTransform, deriveExportPaths, deriveTargetGroupOptions, emitManifest, extractAmbientDts, extractEntries, findRelativeSpecifiers, flattenIssues, formatTime, generateMeta, isTargetObject, mixedDtsExportError, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReexportStub, renderReport, resolveJsxConfig, resolveManifest, resolveNextVersions, resolvePortableTsconfig, resolveTargets, rewriteMetaVersions, runExeBuild, runMetaPass, serializeIssues, transformBin, transformExports, transformManifest, writeDtsEmitTsconfig, writeIssuesArtifact, writeResolvedTsconfig, writeTargetsBinding };
50
+ export { BuildCollector, BuildCollectorTag, BuildReport as BuildReportSchema, CatalogAssemblyError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, DEFAULT_EXE_NODE_VERSION, DependencyResolutionError, EnvironmentDetector, ExecutorResolver, FormatSelector, JsonFormatter, ManifestDecodeError, MarkdownFormatter, MetaGenerationError, OutputRenderer, ReportPipeline, ReportTimings, SilentFormatter, TargetGroupReport as TargetGroupReportSchema, TerminalFormatter, UnresolvedDependencyError, ambientOutName, analyzeReexportBarrel, applySubdirMetaEntries, assertNoEntryCollisions, buildEmittedManifest, buildMetricsPlugin, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, classifyDtsExport, collectExportNames, computeExeFileName, copyAmbientDts, copyPublicDir, createEntryName, createTimer, createTsdownLogger, declarationExt, defaultManifestTransform, deriveExportPaths, deriveTargetGroupOptions, emitManifest, extractAmbientDts, extractEntries, findRelativeSpecifiers, flattenIssues, formatTime, generateMeta, isTargetObject, mixedDtsExportError, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReexportStub, renderReport, resolveJsxConfig, resolveManifest, resolveNextVersions, resolvePortableTsconfig, resolveTargets, rewriteMetaVersions, runExeBuild, runMetaPass, serializeIssues, transformBin, transformExports, transformManifest, writeDtsEmitTsconfig, writeIssuesArtifact, writeResolvedTsconfig, writeTargetsBinding };
package/meta/generate.js CHANGED
@@ -41,7 +41,8 @@ async function generateMeta(options) {
41
41
  });
42
42
  for (const entryName of entryNames) {
43
43
  const modelEntryDts = join(dtsDir, `${entries[entryName]}.d.ts`);
44
- const perEntryApiJson = join(outMetaDir, `${entryName.replace(/[\\/]/g, "__")}.entry.api.json`);
44
+ const safeEntry = entryName.replace(/[\\/]/g, "__");
45
+ const perEntryApiJson = join(outMetaDir, `${safeEntry}.entry.api.json`);
45
46
  intermediateApiJsons.push(perEntryApiJson);
46
47
  const isMain = (exportPaths[entryName] ?? (entryName === "index" ? "." : `./${entryName}`)) === ".";
47
48
  const captureRollupOnlyFatal = splitDiagnostics && onMessage !== void 0 && ci !== true;
@@ -37,7 +37,8 @@ function writeTsdocConfig(cwd, tsdoc) {
37
37
  tagDefinitions: tsdoc.tagDefinitions ?? []
38
38
  });
39
39
  if (existsSync(path)) try {
40
- if (isDeepStrictEqual(JSON.parse(readFileSync(path, "utf-8")), config)) return path;
40
+ const existing = JSON.parse(readFileSync(path, "utf-8"));
41
+ if (isDeepStrictEqual(existing, config)) return path;
41
42
  } catch {}
42
43
  writeFileSync(path, `${JSON.stringify(config, null, " ")}\n`, "utf-8");
43
44
  return path;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/tsdown-plugins",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "private": false,
5
5
  "description": "Interface-only tsdown/rolldown plugin pack powering @savvy-web/bundler",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/tsdown-plugins",
@@ -31,10 +31,10 @@
31
31
  "dependencies": {
32
32
  "@changesets/get-release-plan": "^5.0.0-next.7",
33
33
  "@effect/platform-node": "4.0.0-beta.101",
34
- "@effected/npm": "^0.6.0",
35
- "@effected/package-json": "^0.6.1",
34
+ "@effected/npm": "^0.8.0",
35
+ "@effected/package-json": "^0.7.1",
36
36
  "@effected/tsconfig-json": "^0.4.0",
37
- "@effected/workspaces": "^0.9.1",
37
+ "@effected/workspaces": "^0.9.3",
38
38
  "@microsoft/api-extractor": "^7.58.12",
39
39
  "@microsoft/tsdoc": "^0.16.0",
40
40
  "@microsoft/tsdoc-config": "^0.18.1",
@@ -40,7 +40,7 @@ function dedupe(entries) {
40
40
  const MAX_FAILURE_MESSAGE = 2e3;
41
41
  /** Normalize a caller-supplied failure into the stamped shape (message truncated, empty name dropped). */
42
42
  function toFailure(failure) {
43
- const message = failure.message.length > MAX_FAILURE_MESSAGE ? `${failure.message.slice(0, MAX_FAILURE_MESSAGE - 1)}…` : failure.message;
43
+ const message = failure.message.length > MAX_FAILURE_MESSAGE ? `${failure.message.slice(0, 1999)}…` : failure.message;
44
44
  return failure.name !== void 0 && failure.name !== "" ? {
45
45
  name: failure.name,
46
46
  message
@@ -1,16 +1,12 @@
1
1
  import { EnvironmentDetector } from "./services/EnvironmentDetector.js";
2
- import { EnvironmentDetectorLive } from "./layers/EnvironmentDetectorLive.js";
3
2
  import { ExecutorResolver } from "./services/ExecutorResolver.js";
4
- import { ExecutorResolverLive } from "./layers/ExecutorResolverLive.js";
5
3
  import { FormatSelector } from "./services/FormatSelector.js";
6
- import { FormatSelectorLive } from "./layers/FormatSelectorLive.js";
7
4
  import { OutputRenderer } from "./services/OutputRenderer.js";
8
- import { OutputRendererLive } from "./layers/OutputRendererLive.js";
9
5
  import { Effect, Layer } from "effect";
10
6
 
11
7
  //#region src/report/pipeline.ts
12
8
  /** @public */
13
- const ReportPipelineLive = Layer.mergeAll(EnvironmentDetectorLive, ExecutorResolverLive, FormatSelectorLive, OutputRendererLive);
9
+ const ReportPipeline = Layer.mergeAll(EnvironmentDetector.layer, ExecutorResolver.layer, FormatSelector.layer, OutputRenderer.layer);
14
10
  /** @public */
15
11
  const renderReport = (reports, options) => Effect.gen(function* () {
16
12
  const detector = yield* EnvironmentDetector;
@@ -27,4 +23,4 @@ const renderReport = (reports, options) => Effect.gen(function* () {
27
23
  });
28
24
 
29
25
  //#endregion
30
- export { ReportPipelineLive, renderReport };
26
+ export { ReportPipeline, renderReport };
@@ -1,8 +1,17 @@
1
- import { Context } from "effect";
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { isAgent, isCI } from "std-env";
2
3
 
3
4
  //#region src/report/services/EnvironmentDetector.ts
5
+ const isGitHub = () => process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1";
4
6
  /** @public */
5
- var EnvironmentDetector = class extends Context.Service()("@savvy-web/tsdown-plugins/EnvironmentDetector") {};
7
+ var EnvironmentDetector = class extends Context.Service()("@savvy-web/tsdown-plugins/EnvironmentDetector") {
8
+ static layer = Layer.succeed(this, { detect: () => Effect.sync(() => {
9
+ if (isAgent) return "agent-shell";
10
+ if (isGitHub()) return "ci-github";
11
+ if (isCI) return "ci-generic";
12
+ return "terminal";
13
+ }) });
14
+ };
6
15
 
7
16
  //#endregion
8
17
  export { EnvironmentDetector };
@@ -1,8 +1,10 @@
1
- import { Context } from "effect";
1
+ import { Context, Effect, Layer } from "effect";
2
2
 
3
3
  //#region src/report/services/ExecutorResolver.ts
4
4
  /** @public */
5
- var ExecutorResolver = class extends Context.Service()("@savvy-web/tsdown-plugins/ExecutorResolver") {};
5
+ var ExecutorResolver = class extends Context.Service()("@savvy-web/tsdown-plugins/ExecutorResolver") {
6
+ static layer = Layer.succeed(this, { resolve: (env) => Effect.succeed(env === "agent-shell" ? "agent" : env === "terminal" ? "human" : "ci") });
7
+ };
6
8
 
7
9
  //#endregion
8
10
  export { ExecutorResolver };
@@ -1,8 +1,10 @@
1
- import { Context } from "effect";
1
+ import { Context, Effect, Layer } from "effect";
2
2
 
3
3
  //#region src/report/services/FormatSelector.ts
4
4
  /** @public */
5
- var FormatSelector = class extends Context.Service()("@savvy-web/tsdown-plugins/FormatSelector") {};
5
+ var FormatSelector = class extends Context.Service()("@savvy-web/tsdown-plugins/FormatSelector") {
6
+ static layer = Layer.succeed(this, { select: (executor, explicit, env) => Effect.succeed(explicit ?? (env === "ci-github" && executor === "ci" ? "ci-annotations" : executor === "agent" ? "markdown" : executor === "ci" ? "json" : "terminal")) });
7
+ };
6
8
 
7
9
  //#endregion
8
10
  export { FormatSelector };
@@ -1,8 +1,25 @@
1
- import { Context } from "effect";
1
+ import { CiAnnotationsFormatter } from "../formatters/ci-annotations.js";
2
+ import { JsonFormatter } from "../formatters/json.js";
3
+ import { MarkdownFormatter } from "../formatters/markdown.js";
4
+ import { SilentFormatter } from "../formatters/silent.js";
5
+ import { TerminalFormatter } from "../formatters/terminal.js";
6
+ import { Context, Effect, Layer } from "effect";
2
7
 
3
8
  //#region src/report/services/OutputRenderer.ts
9
+ const formatters = /* @__PURE__ */ new Map([
10
+ ["terminal", TerminalFormatter],
11
+ ["json", JsonFormatter],
12
+ ["markdown", MarkdownFormatter],
13
+ ["ci-annotations", CiAnnotationsFormatter],
14
+ ["silent", SilentFormatter]
15
+ ]);
4
16
  /** @public */
5
- var OutputRenderer = class extends Context.Service()("@savvy-web/tsdown-plugins/OutputRenderer") {};
17
+ var OutputRenderer = class extends Context.Service()("@savvy-web/tsdown-plugins/OutputRenderer") {
18
+ static layer = Layer.succeed(this, { render: (reports, format, ctx) => Effect.sync(() => {
19
+ const f = formatters.get(format);
20
+ return f ? f.render(reports, ctx) : [];
21
+ }) });
22
+ };
6
23
 
7
24
  //#endregion
8
25
  export { OutputRenderer };
@@ -1,67 +0,0 @@
1
- import { ConfigValidationError } from "../errors.js";
2
- import { normalizeLooseFiles } from "../build/loose-files.js";
3
- import { ConfigValidator } from "./ConfigValidator.js";
4
- import { normalizeExeOptions } from "../exe/config.js";
5
- import { resolveTargets } from "../targets/resolve-targets.js";
6
- import { existsSync, statSync } from "node:fs";
7
- import { Effect, Layer } from "effect";
8
-
9
- //#region src/config-validation/ConfigValidatorLive.ts
10
- const VALID_SYNTAX_KINDS = /* @__PURE__ */ new Set([
11
- "block",
12
- "inline",
13
- "modifier"
14
- ]);
15
- /** Synchronous rule set; throws ConfigValidationError on the first violation. */
16
- function check(input) {
17
- if (input.targets !== void 0 && Object.keys(input.targets).length > 0) resolveTargets({
18
- targets: input.targets,
19
- baseName: input.baseName
20
- });
21
- if (input.exe !== void 0) {
22
- const specs = normalizeExeOptions(input.exe, input.osCpu ?? {
23
- os: [],
24
- cpu: []
25
- });
26
- for (const spec of specs) {
27
- if (spec.fileName.trim() === "") throw new ConfigValidationError({
28
- path: "exe.fileName",
29
- reason: "an exe binary needs a non-empty fileName"
30
- });
31
- if (spec.targets.length === 0) throw new ConfigValidationError({
32
- path: `exe.${spec.fileName}.targets`,
33
- reason: "no targets: the package declares no os/cpu and the exe config states none"
34
- });
35
- }
36
- }
37
- if (input.meta !== void 0) {
38
- if (!input.hasExports) throw new ConfigValidationError({
39
- path: "meta",
40
- reason: "meta requires an exports map to extract an api-model from"
41
- });
42
- for (const tag of input.meta.tsdoc?.tagDefinitions ?? []) if (!VALID_SYNTAX_KINDS.has(tag.syntaxKind)) throw new ConfigValidationError({
43
- path: "meta.tsdoc.tagDefinitions",
44
- reason: `tag "${tag.tagName}" has an invalid syntaxKind "${tag.syntaxKind}"`
45
- });
46
- for (const p of input.meta.localPaths ?? []) if (existsSync(p) && !statSync(p).isDirectory()) throw new ConfigValidationError({
47
- path: "meta.localPaths",
48
- reason: `"${p}" exists but is not a directory`
49
- });
50
- }
51
- if (input.looseFiles !== void 0) normalizeLooseFiles(input.looseFiles);
52
- }
53
- /**
54
- * Live ConfigValidator: wraps the synchronous rule set, surfacing ConfigValidationError as a typed Effect failure.
55
- *
56
- * @public
57
- */
58
- const ConfigValidatorLive = Layer.succeed(ConfigValidator, { validate: (input) => Effect.try({
59
- try: () => check(input),
60
- catch: (e) => e instanceof ConfigValidationError ? e : new ConfigValidationError({
61
- path: "config",
62
- reason: String(e)
63
- })
64
- }) });
65
-
66
- //#endregion
67
- export { ConfigValidatorLive };
@@ -1,16 +0,0 @@
1
- import { EnvironmentDetector } from "../services/EnvironmentDetector.js";
2
- import { Effect, Layer } from "effect";
3
- import { isAgent, isCI } from "std-env";
4
-
5
- //#region src/report/layers/EnvironmentDetectorLive.ts
6
- const isGitHub = () => process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1";
7
- /** @public */
8
- const EnvironmentDetectorLive = Layer.succeed(EnvironmentDetector, { detect: () => Effect.sync(() => {
9
- if (isAgent) return "agent-shell";
10
- if (isGitHub()) return "ci-github";
11
- if (isCI) return "ci-generic";
12
- return "terminal";
13
- }) });
14
-
15
- //#endregion
16
- export { EnvironmentDetectorLive };
@@ -1,9 +0,0 @@
1
- import { ExecutorResolver } from "../services/ExecutorResolver.js";
2
- import { Effect, Layer } from "effect";
3
-
4
- //#region src/report/layers/ExecutorResolverLive.ts
5
- /** @public */
6
- const ExecutorResolverLive = Layer.succeed(ExecutorResolver, { resolve: (env) => Effect.succeed(env === "agent-shell" ? "agent" : env === "terminal" ? "human" : "ci") });
7
-
8
- //#endregion
9
- export { ExecutorResolverLive };
@@ -1,9 +0,0 @@
1
- import { FormatSelector } from "../services/FormatSelector.js";
2
- import { Effect, Layer } from "effect";
3
-
4
- //#region src/report/layers/FormatSelectorLive.ts
5
- /** @public */
6
- const FormatSelectorLive = Layer.succeed(FormatSelector, { select: (executor, explicit, env) => Effect.succeed(explicit ?? (env === "ci-github" && executor === "ci" ? "ci-annotations" : executor === "agent" ? "markdown" : executor === "ci" ? "json" : "terminal")) });
7
-
8
- //#endregion
9
- export { FormatSelectorLive };
@@ -1,24 +0,0 @@
1
- import { CiAnnotationsFormatter } from "../formatters/ci-annotations.js";
2
- import { JsonFormatter } from "../formatters/json.js";
3
- import { MarkdownFormatter } from "../formatters/markdown.js";
4
- import { SilentFormatter } from "../formatters/silent.js";
5
- import { TerminalFormatter } from "../formatters/terminal.js";
6
- import { OutputRenderer } from "../services/OutputRenderer.js";
7
- import { Effect, Layer } from "effect";
8
-
9
- //#region src/report/layers/OutputRendererLive.ts
10
- const formatters = /* @__PURE__ */ new Map([
11
- ["terminal", TerminalFormatter],
12
- ["json", JsonFormatter],
13
- ["markdown", MarkdownFormatter],
14
- ["ci-annotations", CiAnnotationsFormatter],
15
- ["silent", SilentFormatter]
16
- ]);
17
- /** @public */
18
- const OutputRendererLive = Layer.succeed(OutputRenderer, { render: (reports, format, ctx) => Effect.sync(() => {
19
- const f = formatters.get(format);
20
- return f ? f.render(reports, ctx) : [];
21
- }) });
22
-
23
- //#endregion
24
- export { OutputRendererLive };