@savvy-web/tsdown-plugins 0.1.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 +61 -0
- package/build/build-target-groups.js +133 -0
- package/build/cjs-default-interop.js +98 -0
- package/build/node-builtin-default-interop.js +74 -0
- package/build/strip-maps.js +40 -0
- package/build/sync-public.js +67 -0
- package/build/target-groups.js +52 -0
- package/catalog/resolve-catalogs.js +24 -0
- package/config-validation/ConfigValidator.js +8 -0
- package/config-validation/ConfigValidatorLive.js +61 -0
- package/dts/resolved-tsconfig.js +44 -0
- package/entry/extract.js +68 -0
- package/entry/package-json-entries.js +12 -0
- package/errors.js +36 -0
- package/exe/build.js +23 -0
- package/exe/config.js +50 -0
- package/index.d.ts +1457 -0
- package/index.js +44 -0
- package/jsx/config.js +40 -0
- package/manifest/emit-manifest.js +56 -0
- package/manifest/transform.js +123 -0
- package/meta/api-extractor.js +59 -0
- package/meta/config.js +14 -0
- package/meta/generate.js +76 -0
- package/meta/merge-models.js +44 -0
- package/meta/message-suppressor.js +37 -0
- package/meta/tsconfig-resolver.js +260 -0
- package/meta/tsdoc-config.js +47 -0
- package/package.json +45 -0
- package/report/formatters/ci-annotations.js +20 -0
- package/report/formatters/json.js +12 -0
- package/report/formatters/markdown.js +25 -0
- package/report/formatters/silent.js +8 -0
- package/report/formatters/terminal.js +29 -0
- package/report/layers/EnvironmentDetectorLive.js +15 -0
- package/report/layers/ExecutorResolverLive.js +8 -0
- package/report/layers/FormatSelectorLive.js +8 -0
- package/report/layers/OutputRendererLive.js +23 -0
- package/report/pipeline.js +25 -0
- package/report/schema-export.js +18 -0
- package/report/schema.js +19 -0
- package/report/services/EnvironmentDetector.js +7 -0
- package/report/services/ExecutorResolver.js +7 -0
- package/report/services/FormatSelector.js +7 -0
- package/report/services/OutputRenderer.js +7 -0
- package/report/timer.js +15 -0
- package/targets/binding.js +15 -0
- package/targets/config.js +8 -0
- package/targets/resolve-targets.js +126 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
|
|
5
|
+
//#region src/dts/resolved-tsconfig.ts
|
|
6
|
+
/** Build the portable absolute-path tsconfig object (ported from rslib writeBundleTempConfig). */
|
|
7
|
+
function buildResolvedTsconfig(options) {
|
|
8
|
+
const cwd = options.cwd;
|
|
9
|
+
return {
|
|
10
|
+
compilerOptions: {
|
|
11
|
+
declaration: true,
|
|
12
|
+
emitDeclarationOnly: false,
|
|
13
|
+
declarationMap: true,
|
|
14
|
+
rootDir: cwd,
|
|
15
|
+
outDir: join(cwd, "dist"),
|
|
16
|
+
declarationDir: join(cwd, "dist"),
|
|
17
|
+
typeRoots: [join(cwd, "node_modules/@types"), join(cwd, "types")],
|
|
18
|
+
types: options.types ? [...options.types] : ["node"],
|
|
19
|
+
composite: false,
|
|
20
|
+
incremental: false,
|
|
21
|
+
tsBuildInfoFile: void 0,
|
|
22
|
+
...options.jsx !== void 0 ? { jsx: options.jsx } : {},
|
|
23
|
+
...options.jsxImportSource !== void 0 ? { jsxImportSource: options.jsxImportSource } : {}
|
|
24
|
+
},
|
|
25
|
+
include: [
|
|
26
|
+
join(cwd, "src/**/*.ts"),
|
|
27
|
+
join(cwd, "src/**/*.mts"),
|
|
28
|
+
join(cwd, "src/**/*.tsx"),
|
|
29
|
+
join(cwd, "types/*.ts"),
|
|
30
|
+
join(cwd, "package.json")
|
|
31
|
+
],
|
|
32
|
+
exclude: [join(cwd, "node_modules"), join(cwd, "dist/**/*")]
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Write the resolved tsconfig to a temp file and return its absolute path. */
|
|
36
|
+
function writeResolvedTsconfig(options) {
|
|
37
|
+
const cfg = buildResolvedTsconfig(options);
|
|
38
|
+
const path = join(tmpdir(), `tsconfig-bundle-${process.pid}-${options.cwd.replace(/[^\w]/g, "_")}.json`);
|
|
39
|
+
writeFileSync(path, `${JSON.stringify(cfg, null, " ")}\n`, "utf-8");
|
|
40
|
+
return path;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { buildResolvedTsconfig, writeResolvedTsconfig };
|
package/entry/extract.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
//#region src/entry/extract.ts
|
|
2
|
+
const isTypeScriptFile = (p) => p.endsWith(".ts") || p.endsWith(".tsx");
|
|
3
|
+
/** /dist/*.js to /src/*.ts; otherwise unchanged. */
|
|
4
|
+
const resolveToTypeScript = (p) => p.endsWith(".js") && p.includes("/dist/") ? p.replace("/dist/", "/src/").replace(/\.js$/, ".ts") : p;
|
|
5
|
+
/** Resolve an export value to a source path: import || default || types (NOT require). */
|
|
6
|
+
const resolveSourcePath = (value) => {
|
|
7
|
+
if (typeof value === "string") return value;
|
|
8
|
+
if (value && typeof value === "object") {
|
|
9
|
+
const o = value;
|
|
10
|
+
return o.import || o.default || o.types || void 0;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Map an export key to the tsdown entry name (the emitted output basename).
|
|
15
|
+
*
|
|
16
|
+
* `.` becomes `index`; otherwise the leading `./` is stripped and, unless
|
|
17
|
+
* `exportsAsIndexes` is set, nested slashes are flattened to dashes
|
|
18
|
+
* (e.g. `./changesets/markdownlint` to `changesets-markdownlint`). The manifest
|
|
19
|
+
* transform reuses this so the declared output path always matches the emitted file.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
const createEntryName = (exportKey, exportsAsIndexes) => {
|
|
24
|
+
if (exportKey === ".") return "index";
|
|
25
|
+
const withoutPrefix = exportKey.replace(/^\.\//, "");
|
|
26
|
+
return exportsAsIndexes ? `${withoutPrefix}/index` : withoutPrefix.replace(/\//g, "-");
|
|
27
|
+
};
|
|
28
|
+
function extractEntries(pkg, options = {}) {
|
|
29
|
+
const entries = {};
|
|
30
|
+
const exportPaths = {};
|
|
31
|
+
const exportsAsIndexes = options.exportsAsIndexes ?? false;
|
|
32
|
+
const exports = pkg.exports;
|
|
33
|
+
if (typeof exports === "string") {
|
|
34
|
+
if (isTypeScriptFile(exports)) {
|
|
35
|
+
entries.index = exports;
|
|
36
|
+
exportPaths.index = ".";
|
|
37
|
+
}
|
|
38
|
+
} else if (exports && typeof exports === "object") for (const [key, value] of Object.entries(exports)) {
|
|
39
|
+
if (key === "./package.json" || key.endsWith(".json")) continue;
|
|
40
|
+
const sourcePath = resolveSourcePath(value);
|
|
41
|
+
if (!sourcePath) continue;
|
|
42
|
+
const resolved = resolveToTypeScript(sourcePath);
|
|
43
|
+
if (!isTypeScriptFile(resolved)) continue;
|
|
44
|
+
const name = createEntryName(key, exportsAsIndexes);
|
|
45
|
+
if (name in entries) {
|
|
46
|
+
const previousKey = exportPaths[name];
|
|
47
|
+
throw new Error(`Export key "${key}" flattens to entry name "${name}", which collides with export key "${previousKey}". Rename one of the conflicting exports so each produces a distinct entry name.`);
|
|
48
|
+
}
|
|
49
|
+
entries[name] = resolved;
|
|
50
|
+
exportPaths[name] = key;
|
|
51
|
+
}
|
|
52
|
+
const bin = pkg.bin;
|
|
53
|
+
if (typeof bin === "string") {
|
|
54
|
+
const resolved = resolveToTypeScript(bin);
|
|
55
|
+
if (isTypeScriptFile(resolved)) entries["bin/cli"] = resolved;
|
|
56
|
+
} else if (bin && typeof bin === "object") for (const [command, p] of Object.entries(bin)) {
|
|
57
|
+
if (typeof p !== "string") continue;
|
|
58
|
+
const resolved = resolveToTypeScript(p);
|
|
59
|
+
if (isTypeScriptFile(resolved)) entries[`bin/${command}`] = resolved;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
entries,
|
|
63
|
+
exportPaths
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { createEntryName, extractEntries };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { extractEntries } from "./extract.js";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
|
|
5
|
+
//#region src/entry/package-json-entries.ts
|
|
6
|
+
/** Derive a tsdown `entry` record (name to source path) from a package.json. */
|
|
7
|
+
function packageJsonEntries(options = {}) {
|
|
8
|
+
return extractEntries(options.pkg ?? JSON.parse(readFileSync(resolve(options.cwd ?? process.cwd(), "package.json"), "utf-8")), { exportsAsIndexes: options.exportsAsIndexes }).entries;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { packageJsonEntries };
|
package/errors.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Data } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/errors.ts
|
|
4
|
+
/** Entry derivation from package.json failed. */
|
|
5
|
+
var EntryDetectionError = class extends Data.TaggedError("EntryDetectionError") {
|
|
6
|
+
get message() {
|
|
7
|
+
return `Entry detection failed: ${this.reason}`;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
/** Emitting the transformed manifest failed. */
|
|
11
|
+
var ManifestEmitError = class extends Data.TaggedError("ManifestEmitError") {
|
|
12
|
+
get message() {
|
|
13
|
+
return `Manifest emit failed: ${this.reason}`;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/** The tsdown build for a TargetGroup failed. */
|
|
17
|
+
var BuildFailed = class extends Data.TaggedError("BuildFailed") {
|
|
18
|
+
get message() {
|
|
19
|
+
return `Build failed for TargetGroup "${this.targetGroup}": ${this.reason}`;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
/** API Extractor meta generation failed for an entry. */
|
|
23
|
+
var MetaGenerationError = class extends Data.TaggedError("MetaGenerationError") {
|
|
24
|
+
get message() {
|
|
25
|
+
return `Meta generation failed for entry "${this.entry}": ${this.reason}`;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/** A savvy.build.ts or publishConfig.targets config is structurally invalid; raised before any build work. */
|
|
29
|
+
var ConfigValidationError = class extends Data.TaggedError("ConfigValidationError") {
|
|
30
|
+
get message() {
|
|
31
|
+
return `Config validation failed at "${this.path}": ${this.reason}`;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ConfigValidationError, MetaGenerationError };
|
package/exe/build.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/exe/build.ts
|
|
2
|
+
/** Compile each SEA binary via tsdown's exe mode. One tsdown build per spec. */
|
|
3
|
+
async function runExeBuild(options) {
|
|
4
|
+
const build = options.build ?? (await import("tsdown")).build;
|
|
5
|
+
for (const spec of options.specs) await build({
|
|
6
|
+
cwd: options.cwd,
|
|
7
|
+
config: false,
|
|
8
|
+
entry: [spec.entry],
|
|
9
|
+
format: "esm",
|
|
10
|
+
platform: "node",
|
|
11
|
+
clean: false,
|
|
12
|
+
deps: { alwaysBundle: (id) => !id.startsWith("node:") },
|
|
13
|
+
exe: {
|
|
14
|
+
fileName: spec.fileName,
|
|
15
|
+
outDir: options.outDir,
|
|
16
|
+
seaConfig: spec.seaConfig,
|
|
17
|
+
targets: spec.targets
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { runExeBuild };
|
package/exe/config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/exe/config.ts
|
|
2
|
+
/** Default Node runtime embedded in the SEA (parity with the vitest-agent reference). */
|
|
3
|
+
const DEFAULT_EXE_NODE_VERSION = "25.9.0";
|
|
4
|
+
/** Map a package.json os value to the tsdown exe platform token. */
|
|
5
|
+
function platformToken(os) {
|
|
6
|
+
if (os === "darwin") return "darwin";
|
|
7
|
+
if (os === "linux") return "linux";
|
|
8
|
+
if (os === "win32") return "win";
|
|
9
|
+
}
|
|
10
|
+
/** Infer the default targets from the package's os/cpu (the zero-config, one-platform-per-package case). */
|
|
11
|
+
function inferTargets(pkg) {
|
|
12
|
+
const os = pkg.os[0];
|
|
13
|
+
const cpu = pkg.cpu[0];
|
|
14
|
+
if (os === void 0 || cpu === void 0) return [];
|
|
15
|
+
const platform = platformToken(os);
|
|
16
|
+
if (platform === void 0 || cpu !== "arm64" && cpu !== "x64") return [];
|
|
17
|
+
return [{
|
|
18
|
+
platform,
|
|
19
|
+
arch: cpu
|
|
20
|
+
}];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalize `exe` (object or array) into one fully-resolved spec per binary.
|
|
24
|
+
*
|
|
25
|
+
* Pure function; structural validation (missing fileName, empty targets) lives in the
|
|
26
|
+
* config-validation layer.
|
|
27
|
+
*/
|
|
28
|
+
function normalizeExeOptions(exe, pkg) {
|
|
29
|
+
return (Array.isArray(exe) ? exe : [exe]).map((c) => {
|
|
30
|
+
const nodeVersion = c.nodeVersion ?? "25.9.0";
|
|
31
|
+
const targetInputs = c.targets ?? inferTargets(pkg);
|
|
32
|
+
return {
|
|
33
|
+
fileName: c.fileName,
|
|
34
|
+
entry: c.entry ?? "./src/bin.ts",
|
|
35
|
+
targets: targetInputs.map((t) => ({
|
|
36
|
+
platform: t.platform,
|
|
37
|
+
arch: t.arch,
|
|
38
|
+
nodeVersion
|
|
39
|
+
})),
|
|
40
|
+
seaConfig: {
|
|
41
|
+
disableExperimentalSEAWarning: c.seaConfig?.disableExperimentalSEAWarning ?? true,
|
|
42
|
+
useCodeCache: c.seaConfig?.useCodeCache ?? false,
|
|
43
|
+
useSnapshot: c.seaConfig?.useSnapshot ?? false
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { DEFAULT_EXE_NODE_VERSION, normalizeExeOptions };
|