@savvy-web/tsdown-plugins 0.7.0 → 0.9.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 +2 -1
- package/build/build-target-groups.js +42 -9
- package/build/cjs-default-interop.js +1 -0
- package/build/loose-files.js +1 -0
- package/build/node-builtin-default-interop.js +15 -9
- package/build/strip-maps.js +1 -0
- package/build/sync-public.js +1 -0
- package/build/target-groups.js +7 -2
- package/catalog/resolve-catalogs.js +1 -0
- package/changesets/next-versions.js +1 -0
- package/config-validation/ConfigValidator.js +5 -1
- package/config-validation/ConfigValidatorLive.js +6 -2
- package/dts/resolved-tsconfig.js +10 -2
- package/entry/extract.js +1 -0
- package/entry/package-json-entries.js +5 -1
- package/errors.js +10 -2
- package/exe/build.js +20 -2
- package/exe/config.js +6 -1
- package/exe/filename.js +1 -0
- package/index.d.ts +679 -593
- package/index.js +8 -4
- package/jsx/config.js +2 -0
- package/manifest/emit-manifest.js +10 -2
- package/manifest/transform.js +18 -4
- package/meta/api-extractor.js +41 -1
- package/meta/config.js +5 -1
- package/meta/generate.js +6 -2
- package/meta/optimistic.js +1 -0
- package/meta/run-pass.js +75 -0
- package/meta/tsconfig-resolver.js +12 -12
- package/package.json +1 -1
- package/report/collector.js +141 -0
- package/report/formatters/ci-annotations.js +9 -2
- package/report/formatters/diagnostics.js +23 -0
- package/report/formatters/json.js +1 -0
- package/report/formatters/markdown.js +19 -9
- package/report/formatters/silent.js +1 -0
- package/report/formatters/terminal.js +32 -3
- package/report/issues-artifact.js +88 -0
- package/report/layers/EnvironmentDetectorLive.js +1 -0
- package/report/layers/ExecutorResolverLive.js +1 -0
- package/report/layers/FormatSelectorLive.js +1 -0
- package/report/layers/OutputRendererLive.js +2 -1
- package/report/metrics-plugin.js +63 -0
- package/report/pipeline.js +6 -1
- package/report/schema.js +52 -10
- package/report/services/EnvironmentDetector.js +1 -0
- package/report/services/ExecutorResolver.js +1 -0
- package/report/services/FormatSelector.js +1 -0
- package/report/services/OutputRenderer.js +1 -0
- package/report/timer.js +6 -1
- package/report/tsdown-logger.js +42 -0
- package/targets/binding.js +5 -1
- package/targets/config.js +5 -1
- package/targets/resolve-targets.js +5 -1
- package/tsdoc-metadata.json +11 -0
- package/report/schema-export.js +0 -18
|
@@ -1,17 +1,27 @@
|
|
|
1
|
+
import { ciFatalCallout, ciFatalCountForPackage, suppressedSummary } from "./diagnostics.js";
|
|
2
|
+
|
|
1
3
|
//#region src/report/formatters/markdown.ts
|
|
4
|
+
/** @public */
|
|
2
5
|
const MarkdownFormatter = {
|
|
3
6
|
format: "markdown",
|
|
4
|
-
render: (reports) => {
|
|
7
|
+
render: (reports, ctx) => {
|
|
5
8
|
const lines = [];
|
|
6
9
|
for (const r of reports) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const hasErrors = r.targetGroups.some((g) => g.errors.length > 0);
|
|
11
|
+
const hasWarnings = r.targetGroups.some((g) => g.warnings.length > 0);
|
|
12
|
+
const hasSuppressed = r.targetGroups.some((g) => g.suppressed.length > 0);
|
|
13
|
+
const icon = hasErrors ? "❌" : hasWarnings || hasSuppressed ? "⚠️" : "✅";
|
|
14
|
+
lines.push(`## ${icon} ${r.package}`);
|
|
15
|
+
for (const g of r.targetGroups) {
|
|
16
|
+
if (g.errors.length === 0 && g.warnings.length === 0 && g.suppressed.length === 0) continue;
|
|
17
|
+
lines.push(`- **${g.id}**`);
|
|
18
|
+
for (const e of g.errors) lines.push(` - ❌ ${e.text}`);
|
|
19
|
+
for (const w of g.warnings) lines.push(` - ⚠️ ${w.text}${w.ciFatal === true ? " [fails CI]" : ""}`);
|
|
20
|
+
if (g.suppressed.length > 0) if (ctx.verbose) for (const s of g.suppressed) lines.push(` - 🔇 ${s.code ?? "?"}: ${s.text}`);
|
|
21
|
+
else lines.push(` - 🔇 suppressed ${g.suppressed.length}: ${suppressedSummary(g.suppressed)}`);
|
|
22
|
+
}
|
|
23
|
+
const fatal = ciFatalCountForPackage(r);
|
|
24
|
+
if (fatal > 0) lines.push(`> ${ciFatalCallout(fatal)}`);
|
|
15
25
|
}
|
|
16
26
|
return [{
|
|
17
27
|
target: "stdout",
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
import { formatTime } from "../timer.js";
|
|
2
|
+
import { ciFatalCallout, ciFatalCountForPackage, suppressedSummary } from "./diagnostics.js";
|
|
2
3
|
import pc from "picocolors";
|
|
3
4
|
|
|
4
5
|
//#region src/report/formatters/terminal.ts
|
|
6
|
+
const fmtBytes = (n) => n < 1024 ? `${n} B` : `${(n / 1024).toFixed(2)} kB`;
|
|
7
|
+
const fileCount = (g) => g.passes.reduce((sum, p) => sum + p.files.length, 0);
|
|
8
|
+
const diagLine = (d) => {
|
|
9
|
+
return `${d.file !== void 0 ? ` ${d.file}${d.line !== void 0 ? `:${d.line}` : ""}` : ""} ${d.text}`.trim();
|
|
10
|
+
};
|
|
11
|
+
/** @public */
|
|
5
12
|
const TerminalFormatter = {
|
|
6
13
|
format: "terminal",
|
|
7
14
|
render: (reports, ctx) => {
|
|
8
15
|
const color = (fn, s) => ctx.noColor ? s : fn(s);
|
|
9
16
|
const lines = [];
|
|
17
|
+
let totalMs = 0;
|
|
10
18
|
for (const r of reports) {
|
|
11
19
|
lines.push(color(pc.bold, r.package));
|
|
12
20
|
for (const g of r.targetGroups) {
|
|
13
21
|
const status = g.errors.length ? color(pc.red, "✗") : color(pc.green, "✓");
|
|
14
|
-
lines.push(` ${status} ${g.id}
|
|
15
|
-
|
|
16
|
-
for (const
|
|
22
|
+
lines.push(` ${status} ${g.id} ${fileCount(g)} files · ${formatTime(g.timings.totalMs)}`);
|
|
23
|
+
totalMs += g.timings.totalMs;
|
|
24
|
+
if (ctx.verbose) for (const p of g.passes) {
|
|
25
|
+
lines.push(` ${color(pc.dim, `${p.id} (${formatTime(p.ms)})`)}`);
|
|
26
|
+
for (const f of p.files) {
|
|
27
|
+
const gz = f.gzip !== void 0 ? ` │ gzip ${fmtBytes(f.gzip)}` : "";
|
|
28
|
+
lines.push(` ${f.path} ${fmtBytes(f.bytes)}${gz}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
for (const e of g.errors) lines.push(` ${color(pc.red, "error")} ${diagLine(e)}`);
|
|
32
|
+
for (const w of g.warnings) {
|
|
33
|
+
const tag = w.ciFatal === true ? color(pc.red, " [fails CI]") : "";
|
|
34
|
+
lines.push(` ${color(pc.yellow, "warn")} ${diagLine(w)}${tag}`);
|
|
35
|
+
}
|
|
36
|
+
if (g.suppressed.length > 0) if (ctx.verbose) for (const s of g.suppressed) lines.push(` ${color(pc.dim, `suppressed ${s.code ?? "?"}`)} ${diagLine(s)}`);
|
|
37
|
+
else lines.push(` ${color(pc.dim, `suppressed ${g.suppressed.length}: ${suppressedSummary(g.suppressed)}`)}`);
|
|
17
38
|
}
|
|
39
|
+
const fatal = ciFatalCountForPackage(r);
|
|
40
|
+
if (fatal > 0) lines.push(` ${color(pc.red, ciFatalCallout(fatal))}`);
|
|
41
|
+
}
|
|
42
|
+
const pkgs = reports.length;
|
|
43
|
+
if (pkgs > 0) {
|
|
44
|
+
const pkgLabel = `${pkgs} package${pkgs === 1 ? "" : "s"}`;
|
|
45
|
+
const hasErrors = reports.some((r) => r.targetGroups.some((g) => g.errors.length > 0));
|
|
46
|
+
lines.push(hasErrors ? `${color(pc.red, "✗")} build failed · ${pkgLabel} · ${formatTime(totalMs)}` : `${color(pc.green, "✔")} build complete · ${pkgLabel} · ${formatTime(totalMs)}`);
|
|
18
47
|
}
|
|
19
48
|
const content = lines.join("\n");
|
|
20
49
|
return content === "" ? [] : [{
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
//#region src/report/issues-artifact.ts
|
|
5
|
+
/** Copy a DiagnosticEntry to a plain object, omitting undefined optionals for stable output. */
|
|
6
|
+
function toPlain(d) {
|
|
7
|
+
const out = {
|
|
8
|
+
source: d.source,
|
|
9
|
+
level: d.level,
|
|
10
|
+
text: d.text
|
|
11
|
+
};
|
|
12
|
+
if (d.code !== void 0) out.code = d.code;
|
|
13
|
+
if (d.ciFatal !== void 0) out.ciFatal = d.ciFatal;
|
|
14
|
+
if (d.file !== void 0) out.file = d.file;
|
|
15
|
+
if (d.line !== void 0) out.line = d.line;
|
|
16
|
+
if (d.column !== void 0) out.column = d.column;
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
/** De-duplicate by the identity-bearing fields (registry target-groups carry identical diagnostics). */
|
|
20
|
+
function dedupe(entries) {
|
|
21
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const e of entries) {
|
|
24
|
+
const key = JSON.stringify([
|
|
25
|
+
e.source,
|
|
26
|
+
e.level,
|
|
27
|
+
e.code ?? "",
|
|
28
|
+
e.text,
|
|
29
|
+
e.file ?? "",
|
|
30
|
+
e.line ?? -1,
|
|
31
|
+
e.column ?? -1
|
|
32
|
+
]);
|
|
33
|
+
if (seen.has(key)) continue;
|
|
34
|
+
seen.add(key);
|
|
35
|
+
out.push(e);
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Flatten a build snapshot into the aggregated, de-duplicated issues artifact. Pure.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
function flattenIssues(reports, opts) {
|
|
45
|
+
const warnings = [];
|
|
46
|
+
const errors = [];
|
|
47
|
+
const suppressed = [];
|
|
48
|
+
for (const report of reports) for (const g of report.targetGroups) {
|
|
49
|
+
for (const w of g.warnings) warnings.push(toPlain(w));
|
|
50
|
+
for (const e of g.errors) errors.push(toPlain(e));
|
|
51
|
+
for (const s of g.suppressed) suppressed.push(toPlain(s));
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
generatedAt: opts.generatedAt,
|
|
55
|
+
package: reports[0]?.package ?? "unknown",
|
|
56
|
+
target: opts.target,
|
|
57
|
+
warnings: dedupe(warnings),
|
|
58
|
+
errors: dedupe(errors),
|
|
59
|
+
suppressed: dedupe(suppressed)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Serialize the issues artifact to pretty JSON with a trailing newline.
|
|
64
|
+
*
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
function serializeIssues(issues) {
|
|
68
|
+
return `${JSON.stringify(issues, null, 2)}\n`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Write the aggregated issues artifact to `<cwd>/dist/<target>/issues.json`. Returns the path written.
|
|
72
|
+
*
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
function writeIssuesArtifact(opts) {
|
|
76
|
+
const clock = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
77
|
+
const issues = flattenIssues(opts.reports, {
|
|
78
|
+
target: opts.target,
|
|
79
|
+
generatedAt: clock().toISOString()
|
|
80
|
+
});
|
|
81
|
+
const outPath = join(opts.cwd, "dist", opts.target, "issues.json");
|
|
82
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
83
|
+
writeFileSync(outPath, serializeIssues(issues), "utf8");
|
|
84
|
+
return outPath;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
export { flattenIssues, serializeIssues, writeIssuesArtifact };
|
|
@@ -4,6 +4,7 @@ import { isAgent, isCI } from "std-env";
|
|
|
4
4
|
|
|
5
5
|
//#region src/report/layers/EnvironmentDetectorLive.ts
|
|
6
6
|
const isGitHub = () => process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1";
|
|
7
|
+
/** @public */
|
|
7
8
|
const EnvironmentDetectorLive = Layer.succeed(EnvironmentDetector, { detect: () => Effect.sync(() => {
|
|
8
9
|
if (isAgent) return "agent-shell";
|
|
9
10
|
if (isGitHub()) return "ci-github";
|
|
@@ -2,6 +2,7 @@ import { ExecutorResolver } from "../services/ExecutorResolver.js";
|
|
|
2
2
|
import { Effect, Layer } from "effect";
|
|
3
3
|
|
|
4
4
|
//#region src/report/layers/ExecutorResolverLive.ts
|
|
5
|
+
/** @public */
|
|
5
6
|
const ExecutorResolverLive = Layer.succeed(ExecutorResolver, { resolve: (env) => Effect.succeed(env === "agent-shell" ? "agent" : env === "terminal" ? "human" : "ci") });
|
|
6
7
|
|
|
7
8
|
//#endregion
|
|
@@ -2,6 +2,7 @@ import { FormatSelector } from "../services/FormatSelector.js";
|
|
|
2
2
|
import { Effect, Layer } from "effect";
|
|
3
3
|
|
|
4
4
|
//#region src/report/layers/FormatSelectorLive.ts
|
|
5
|
+
/** @public */
|
|
5
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")) });
|
|
6
7
|
|
|
7
8
|
//#endregion
|
|
@@ -7,13 +7,14 @@ import { OutputRenderer } from "../services/OutputRenderer.js";
|
|
|
7
7
|
import { Effect, Layer } from "effect";
|
|
8
8
|
|
|
9
9
|
//#region src/report/layers/OutputRendererLive.ts
|
|
10
|
-
const formatters = new Map([
|
|
10
|
+
const formatters = /* @__PURE__ */ new Map([
|
|
11
11
|
["terminal", TerminalFormatter],
|
|
12
12
|
["json", JsonFormatter],
|
|
13
13
|
["markdown", MarkdownFormatter],
|
|
14
14
|
["ci-annotations", CiAnnotationsFormatter],
|
|
15
15
|
["silent", SilentFormatter]
|
|
16
16
|
]);
|
|
17
|
+
/** @public */
|
|
17
18
|
const OutputRendererLive = Layer.succeed(OutputRenderer, { render: (reports, format, ctx) => Effect.sync(() => {
|
|
18
19
|
const f = formatters.get(format);
|
|
19
20
|
return f ? f.render(reports, ctx) : [];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { gzipSync } from "node:zlib";
|
|
2
|
+
|
|
3
|
+
//#region src/report/metrics-plugin.ts
|
|
4
|
+
function contentOf(chunk) {
|
|
5
|
+
const c = chunk;
|
|
6
|
+
if (c.type === "chunk") return c.code;
|
|
7
|
+
if (c.type === "asset") return c.source;
|
|
8
|
+
return c.code ?? c.source;
|
|
9
|
+
}
|
|
10
|
+
function byteLength(content) {
|
|
11
|
+
return typeof content === "string" ? Buffer.byteLength(content) : content.byteLength;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Rolldown plugin that records emitted-file metrics into the BuildCollector via writeBundle (which
|
|
15
|
+
* fires for the JS pass AND the emitDtsOnly dts pass — verified against tsdown 0.22.3), plus a
|
|
16
|
+
* defensive onLog for rolldown-level diagnostics that bypass tsdown's logger. Append it to each
|
|
17
|
+
* build pass's `plugins` array. `bytes` is taken from the in-memory chunk/asset content (no fs);
|
|
18
|
+
* `gzip` is computed only when `verbose`.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
function buildMetricsPlugin(collector, groupId, pass, verbose) {
|
|
22
|
+
return {
|
|
23
|
+
name: "savvy:build-metrics",
|
|
24
|
+
writeBundle(_outputOptions, bundle) {
|
|
25
|
+
for (const [key, chunk] of Object.entries(bundle)) {
|
|
26
|
+
const content = contentOf(chunk);
|
|
27
|
+
if (content === void 0) continue;
|
|
28
|
+
const bytes = byteLength(content);
|
|
29
|
+
collector.recordEmitted(groupId, pass, {
|
|
30
|
+
path: key,
|
|
31
|
+
bytes,
|
|
32
|
+
...verbose ? { gzip: gzipSync(typeof content === "string" ? Buffer.from(content) : content).length } : {}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
onLog(level, log) {
|
|
37
|
+
const l = log;
|
|
38
|
+
const entry = {
|
|
39
|
+
text: l.message ?? String(log),
|
|
40
|
+
...l.id !== void 0 ? { file: l.id } : {},
|
|
41
|
+
...l.loc?.line !== void 0 ? { line: l.loc.line } : {},
|
|
42
|
+
...l.loc?.column !== void 0 ? { column: l.loc.column } : {}
|
|
43
|
+
};
|
|
44
|
+
if (level === "error") {
|
|
45
|
+
collector.recordError(groupId, {
|
|
46
|
+
source: "rolldown",
|
|
47
|
+
level: "error",
|
|
48
|
+
...entry
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (level === "warn") collector.recordWarning(groupId, {
|
|
53
|
+
source: "rolldown",
|
|
54
|
+
level: "warn",
|
|
55
|
+
...entry
|
|
56
|
+
});
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { buildMetricsPlugin };
|
package/report/pipeline.js
CHANGED
|
@@ -9,7 +9,9 @@ import { OutputRendererLive } from "./layers/OutputRendererLive.js";
|
|
|
9
9
|
import { Effect, Layer } from "effect";
|
|
10
10
|
|
|
11
11
|
//#region src/report/pipeline.ts
|
|
12
|
+
/** @public */
|
|
12
13
|
const ReportPipelineLive = Layer.mergeAll(EnvironmentDetectorLive, ExecutorResolverLive, FormatSelectorLive, OutputRendererLive);
|
|
14
|
+
/** @public */
|
|
13
15
|
const renderReport = (reports, options) => Effect.gen(function* () {
|
|
14
16
|
const detector = yield* EnvironmentDetector;
|
|
15
17
|
const executorResolver = yield* ExecutorResolver;
|
|
@@ -18,7 +20,10 @@ const renderReport = (reports, options) => Effect.gen(function* () {
|
|
|
18
20
|
const env = options.env ?? (yield* detector.detect());
|
|
19
21
|
const executor = yield* executorResolver.resolve(env);
|
|
20
22
|
const format = yield* formatSelector.select(executor, options.explicitFormat, env);
|
|
21
|
-
return yield* renderer.render(reports, format, {
|
|
23
|
+
return yield* renderer.render(reports, format, {
|
|
24
|
+
noColor: options.noColor,
|
|
25
|
+
verbose: options.verbose ?? false
|
|
26
|
+
});
|
|
22
27
|
});
|
|
23
28
|
|
|
24
29
|
//#endregion
|
package/report/schema.js
CHANGED
|
@@ -1,19 +1,61 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
|
|
3
3
|
//#region src/report/schema.ts
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/** @public */
|
|
5
|
+
var ReportTimings = class extends Schema.Class("ReportTimings")({ totalMs: Schema.Number }) {};
|
|
6
|
+
/**
|
|
7
|
+
* A captured warning or error, from tsdown's logger, rolldown's onLog, or API Extractor.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
var DiagnosticEntry = class extends Schema.Class("DiagnosticEntry")({
|
|
12
|
+
source: Schema.Literal("tsdown", "rolldown", "api-extractor"),
|
|
13
|
+
level: Schema.Literal("warn", "error"),
|
|
14
|
+
text: Schema.String,
|
|
15
|
+
/** API Extractor messageId (e.g. "ae-forgotten-export"); used to group suppressed messages by type. */
|
|
16
|
+
code: Schema.optional(Schema.String),
|
|
17
|
+
/** True when shown as `warn` locally but a hard error in CI (drives the "[fails CI]" nudge). */
|
|
18
|
+
ciFatal: Schema.optional(Schema.Boolean),
|
|
19
|
+
file: Schema.optional(Schema.String),
|
|
20
|
+
line: Schema.optional(Schema.Number),
|
|
21
|
+
column: Schema.optional(Schema.Number)
|
|
22
|
+
}) {};
|
|
23
|
+
/**
|
|
24
|
+
* One emitted output file with its in-memory byte size (gzip only when --verbose).
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
var EmittedFile = class extends Schema.Class("EmittedFile")({
|
|
29
|
+
path: Schema.String,
|
|
30
|
+
bytes: Schema.Number,
|
|
31
|
+
gzip: Schema.optional(Schema.Number)
|
|
32
|
+
}) {};
|
|
33
|
+
/**
|
|
34
|
+
* One build pass within a target group (js / dts / loose / exe / meta).
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
var PassReport = class extends Schema.Class("PassReport")({
|
|
39
|
+
id: Schema.Literal("js", "dts", "loose", "exe", "meta"),
|
|
40
|
+
files: Schema.Array(EmittedFile),
|
|
41
|
+
ms: Schema.Number
|
|
42
|
+
}) {};
|
|
43
|
+
/** @public */
|
|
44
|
+
var TargetGroupReport = class extends Schema.Class("TargetGroupReport")({
|
|
6
45
|
id: Schema.String,
|
|
7
46
|
entries: Schema.Array(Schema.String),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
47
|
+
passes: Schema.Array(PassReport),
|
|
48
|
+
warnings: Schema.Array(DiagnosticEntry),
|
|
49
|
+
errors: Schema.Array(DiagnosticEntry),
|
|
50
|
+
/** Messages matched by `suppressWarnings`, kept for accounting and `--verbose` expansion. */
|
|
51
|
+
suppressed: Schema.Array(DiagnosticEntry),
|
|
52
|
+
timings: ReportTimings
|
|
53
|
+
}) {};
|
|
54
|
+
/** @public */
|
|
55
|
+
var BuildReport = class extends Schema.Class("BuildReport")({
|
|
14
56
|
package: Schema.String,
|
|
15
57
|
targetGroups: Schema.Array(TargetGroupReport)
|
|
16
|
-
})
|
|
58
|
+
}) {};
|
|
17
59
|
|
|
18
60
|
//#endregion
|
|
19
|
-
export { BuildReport, ReportTimings, TargetGroupReport };
|
|
61
|
+
export { BuildReport, DiagnosticEntry, EmittedFile, PassReport, ReportTimings, TargetGroupReport };
|
package/report/timer.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
//#region src/report/timer.ts
|
|
2
|
+
/** @public */
|
|
2
3
|
function formatTime(ms) {
|
|
3
4
|
return ms < 1e3 ? `${Math.round(ms)}ms` : `${(ms / 1e3).toFixed(2)}s`;
|
|
4
5
|
}
|
|
5
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Create a wall-clock timer. (Date.now is fine in runtime build code.)
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
6
11
|
function createTimer(now = Date.now) {
|
|
7
12
|
const start = now();
|
|
8
13
|
return {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/report/tsdown-logger.ts
|
|
2
|
+
const ANSI = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
3
|
+
const join = (args) => args.map((a) => String(a)).join(" ").replace(ANSI, "").trim();
|
|
4
|
+
/**
|
|
5
|
+
* A tsdown `customLogger` that routes warnings/errors into the BuildCollector instead of the
|
|
6
|
+
* console. Paired with `logLevel: "silent"` in the same build config: silent suppresses tsdown's
|
|
7
|
+
* own console output while this logger still receives every message (verified against tsdown 0.22.3).
|
|
8
|
+
* info/success are dropped — file metrics come from the writeBundle plugin and timing from our timer.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
function createTsdownLogger(collector, groupId) {
|
|
12
|
+
const seenOnce = /* @__PURE__ */ new Set();
|
|
13
|
+
return {
|
|
14
|
+
level: "info",
|
|
15
|
+
info: () => {},
|
|
16
|
+
success: () => {},
|
|
17
|
+
clearScreen: () => {},
|
|
18
|
+
warn: (...args) => collector.recordWarning(groupId, {
|
|
19
|
+
source: "tsdown",
|
|
20
|
+
level: "warn",
|
|
21
|
+
text: join(args)
|
|
22
|
+
}),
|
|
23
|
+
warnOnce: (...args) => {
|
|
24
|
+
const text = join(args);
|
|
25
|
+
if (seenOnce.has(text)) return;
|
|
26
|
+
seenOnce.add(text);
|
|
27
|
+
collector.recordWarning(groupId, {
|
|
28
|
+
source: "tsdown",
|
|
29
|
+
level: "warn",
|
|
30
|
+
text
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
error: (...args) => collector.recordError(groupId, {
|
|
34
|
+
source: "tsdown",
|
|
35
|
+
level: "error",
|
|
36
|
+
text: join(args)
|
|
37
|
+
})
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { createTsdownLogger };
|
package/targets/binding.js
CHANGED
|
@@ -2,7 +2,11 @@ import { join } from "node:path";
|
|
|
2
2
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
|
|
4
4
|
//#region src/targets/binding.ts
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Write the target-to-group binding to dist/prod/targets.json for the release action to consume. Returns the path.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
6
10
|
function writeTargetsBinding(cwd, resolution) {
|
|
7
11
|
const dir = join(cwd, "dist", "prod");
|
|
8
12
|
mkdirSync(dir, { recursive: true });
|
package/targets/config.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
//#region src/targets/config.ts
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* True when a target value is the object form (carries registry/name/from).
|
|
4
|
+
*
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
3
7
|
function isTargetObject(value) {
|
|
4
8
|
return typeof value === "object" && value !== null;
|
|
5
9
|
}
|
|
@@ -7,7 +7,11 @@ const DEFAULT_REGISTRIES = {
|
|
|
7
7
|
npm: "https://registry.npmjs.org",
|
|
8
8
|
github: "https://npm.pkg.github.com"
|
|
9
9
|
};
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a `publishConfig.targets` map into the distinct groups to build and every target bound to one. Pure; throws ConfigValidationError on structurally-invalid config.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
11
15
|
function resolveTargets(options) {
|
|
12
16
|
const { targets, baseName } = options;
|
|
13
17
|
const ids = Object.keys(targets);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.58.9"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
package/report/schema-export.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { BuildReport } from "./schema.js";
|
|
2
|
-
import { Effect } from "effect";
|
|
3
|
-
import { JsonSchemaExporter } from "json-schema-effect";
|
|
4
|
-
|
|
5
|
-
//#region src/report/schema-export.ts
|
|
6
|
-
const SCHEMA_ID = "https://savvyweb.systems/schemas/build-report.schema.json";
|
|
7
|
-
/** Generate the SchemaStore-compatible JSON Schema document for BuildReport. */
|
|
8
|
-
const generateBuildReportSchema = () => Effect.gen(function* () {
|
|
9
|
-
return yield* (yield* JsonSchemaExporter).generate({
|
|
10
|
-
name: "build-report",
|
|
11
|
-
schema: BuildReport,
|
|
12
|
-
rootDefName: "BuildReport",
|
|
13
|
-
$id: SCHEMA_ID
|
|
14
|
-
});
|
|
15
|
-
}).pipe(Effect.provide(JsonSchemaExporter.Live));
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
export { generateBuildReportSchema };
|