@pumpkin-plugins/build 0.1.0 → 0.1.2
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 +4 -0
- package/dist/cli.js +153 -115
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -10,6 +10,10 @@ This package is configured for public npm publication as `@pumpkin-plugins/build
|
|
|
10
10
|
publish its packed tarball; see [CI and releases](../../docs/ci-and-releases.md#releases) and the
|
|
11
11
|
[build guide](../../docs/building.md).
|
|
12
12
|
|
|
13
|
+
The builder and migration codemod share the dependency-free
|
|
14
|
+
[`@pumpkin-plugins/wasi-capabilities`](../wasi-capabilities/README.md) package for WASI names and
|
|
15
|
+
interface mapping.
|
|
16
|
+
|
|
13
17
|
<!-- docs:begin reference -->
|
|
14
18
|
<!-- Generated by pumpkin-plugins-docs from package, action, extension, and component docs metadata. Run `pnpm readme`. -->
|
|
15
19
|
|
package/dist/cli.js
CHANGED
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import * as fs9 from "node:fs";
|
|
5
|
-
import { createRequire as
|
|
5
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path9 from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { Command } from "@commander-js/extra-typings";
|
|
10
10
|
import { ensurePumpkinWit } from "@pumpkin-plugins/pumpkin-api/wit";
|
|
11
|
+
import { wasiInterfaces } from "@pumpkin-plugins/wasi-capabilities";
|
|
11
12
|
import { CommanderError } from "commander";
|
|
12
13
|
|
|
13
14
|
// src/bundle.ts
|
|
14
15
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
15
|
-
import * as
|
|
16
|
+
import * as fs4 from "node:fs";
|
|
16
17
|
import { createRequire as createRequire2 } from "node:module";
|
|
17
|
-
import * as
|
|
18
|
+
import * as path4 from "node:path";
|
|
18
19
|
import { buildStaticHermesComponent, staticHermesImportsPlugin } from "@pumpkin-plugins/static-hermes-runtime";
|
|
19
20
|
import * as esbuild from "esbuild";
|
|
20
21
|
|
|
@@ -40,22 +41,35 @@ function errorMessage(error) {
|
|
|
40
41
|
return error instanceof Error ? error.message : String(error);
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
// src/repo.ts
|
|
45
|
+
import * as fs from "node:fs";
|
|
46
|
+
import * as path from "node:path";
|
|
47
|
+
function findRepoRoot(from) {
|
|
48
|
+
for (let dir = path.resolve(from); ; dir = path.dirname(dir)) {
|
|
49
|
+
if (fs.existsSync(path.join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
50
|
+
if (path.dirname(dir) === dir) return path.resolve(from);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function cacheDir(from) {
|
|
54
|
+
return process.env.PUMPKIN_PLUGINS_CACHE_DIR || path.join(findRepoRoot(from), ".cache");
|
|
55
|
+
}
|
|
56
|
+
|
|
43
57
|
// src/types.ts
|
|
44
58
|
import { execFileSync } from "node:child_process";
|
|
45
|
-
import * as
|
|
59
|
+
import * as fs2 from "node:fs";
|
|
46
60
|
import { createRequire } from "node:module";
|
|
47
|
-
import * as
|
|
61
|
+
import * as path2 from "node:path";
|
|
48
62
|
var require2 = createRequire(import.meta.url);
|
|
49
63
|
function generateTypes(witDir, outDir) {
|
|
50
64
|
const jco = resolveJcoCli();
|
|
51
|
-
const output =
|
|
52
|
-
const parent =
|
|
53
|
-
|
|
54
|
-
const temporary =
|
|
55
|
-
const generated =
|
|
65
|
+
const output = path2.resolve(outDir);
|
|
66
|
+
const parent = path2.dirname(output);
|
|
67
|
+
fs2.mkdirSync(parent, { recursive: true });
|
|
68
|
+
const temporary = fs2.mkdtempSync(path2.join(parent, `.${path2.basename(output)}-`));
|
|
69
|
+
const generated = path2.join(temporary, "generated");
|
|
56
70
|
let preserveTemporary = false;
|
|
57
71
|
try {
|
|
58
|
-
|
|
72
|
+
fs2.mkdirSync(generated);
|
|
59
73
|
execFileSync(
|
|
60
74
|
process.execPath,
|
|
61
75
|
[jco, "guest-types", witDir, "-n", "plugin", "-o", generated, "--name", "index", "--quiet"],
|
|
@@ -67,7 +81,7 @@ function generateTypes(witDir, outDir) {
|
|
|
67
81
|
preserveTemporary = true;
|
|
68
82
|
});
|
|
69
83
|
} finally {
|
|
70
|
-
if (!preserveTemporary)
|
|
84
|
+
if (!preserveTemporary) fs2.rmSync(temporary, { recursive: true, force: true });
|
|
71
85
|
}
|
|
72
86
|
}
|
|
73
87
|
function resolveJcoCli() {
|
|
@@ -77,37 +91,37 @@ function resolveJcoCli() {
|
|
|
77
91
|
} catch {
|
|
78
92
|
throw new Error("@bytecodealliance/jco is missing from @pumpkin-plugins/build dependencies");
|
|
79
93
|
}
|
|
80
|
-
for (let directory =
|
|
81
|
-
const packagePath =
|
|
82
|
-
if (
|
|
83
|
-
const packageJson = JSON.parse(
|
|
94
|
+
for (let directory = path2.dirname(entry); ; directory = path2.dirname(directory)) {
|
|
95
|
+
const packagePath = path2.join(directory, "package.json");
|
|
96
|
+
if (fs2.existsSync(packagePath)) {
|
|
97
|
+
const packageJson = JSON.parse(fs2.readFileSync(packagePath, "utf8"));
|
|
84
98
|
if (packageJson.name === "@bytecodealliance/jco") {
|
|
85
99
|
const command = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.jco;
|
|
86
100
|
if (!command) throw new Error("@bytecodealliance/jco package metadata does not declare its jco binary");
|
|
87
|
-
const binaryPath =
|
|
88
|
-
if (!
|
|
101
|
+
const binaryPath = path2.resolve(directory, command);
|
|
102
|
+
if (!fs2.existsSync(binaryPath))
|
|
89
103
|
throw new Error(`jco binary is missing from its package: ${binaryPath}`);
|
|
90
104
|
return binaryPath;
|
|
91
105
|
}
|
|
92
106
|
}
|
|
93
|
-
const parent =
|
|
107
|
+
const parent = path2.dirname(directory);
|
|
94
108
|
if (parent === directory) break;
|
|
95
109
|
}
|
|
96
110
|
throw new Error(`could not locate @bytecodealliance/jco package metadata from ${entry}`);
|
|
97
111
|
}
|
|
98
112
|
function publishTypes(generated, output, temporary, preserveForRecovery) {
|
|
99
|
-
if (!
|
|
100
|
-
|
|
113
|
+
if (!fs2.existsSync(output)) {
|
|
114
|
+
fs2.renameSync(generated, output);
|
|
101
115
|
return;
|
|
102
116
|
}
|
|
103
|
-
if (!
|
|
104
|
-
const previous =
|
|
105
|
-
|
|
117
|
+
if (!fs2.statSync(output).isDirectory()) throw new Error(`type output is not a directory: ${output}`);
|
|
118
|
+
const previous = path2.join(temporary, "previous");
|
|
119
|
+
fs2.renameSync(output, previous);
|
|
106
120
|
try {
|
|
107
|
-
|
|
121
|
+
fs2.renameSync(generated, output);
|
|
108
122
|
} catch (publishError) {
|
|
109
123
|
try {
|
|
110
|
-
|
|
124
|
+
fs2.renameSync(previous, output);
|
|
111
125
|
} catch (restoreError) {
|
|
112
126
|
preserveForRecovery();
|
|
113
127
|
throw new AggregateError(
|
|
@@ -120,24 +134,38 @@ function publishTypes(generated, output, temporary, preserveForRecovery) {
|
|
|
120
134
|
}
|
|
121
135
|
|
|
122
136
|
// src/wit-method-usage.ts
|
|
123
|
-
import * as
|
|
124
|
-
import * as
|
|
137
|
+
import * as fs3 from "node:fs";
|
|
138
|
+
import * as path3 from "node:path";
|
|
125
139
|
import * as ts from "typescript";
|
|
126
140
|
function findUsedWitMethods(entry, additionalTypesDir) {
|
|
127
|
-
const absoluteEntry =
|
|
128
|
-
if (!
|
|
129
|
-
const configPath = ts.findConfigFile(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
const absoluteEntry = path3.resolve(entry);
|
|
142
|
+
if (!fs3.existsSync(absoluteEntry)) return void 0;
|
|
143
|
+
const configPath = ts.findConfigFile(path3.dirname(absoluteEntry), ts.sys.fileExists, "tsconfig.json");
|
|
144
|
+
let parsed;
|
|
145
|
+
if (configPath) {
|
|
146
|
+
const config = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
147
|
+
if (config.error) throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, "\n"));
|
|
148
|
+
parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, path3.dirname(configPath));
|
|
149
|
+
} else {
|
|
150
|
+
parsed = ts.parseJsonConfigFileContent({}, ts.sys, path3.dirname(absoluteEntry));
|
|
151
|
+
}
|
|
134
152
|
if (parsed.errors.length) {
|
|
135
153
|
throw new Error(
|
|
136
154
|
parsed.errors.map((error) => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n")
|
|
137
155
|
);
|
|
138
156
|
}
|
|
139
157
|
const additionalTypeFiles = additionalTypesDir ? ts.sys.readDirectory(additionalTypesDir, [".d.ts"], void 0, ["**/*.d.ts"]) : [];
|
|
140
|
-
const options = {
|
|
158
|
+
const options = {
|
|
159
|
+
...configPath ? {} : {
|
|
160
|
+
target: ts.ScriptTarget.ES2022,
|
|
161
|
+
module: ts.ModuleKind.ESNext,
|
|
162
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
163
|
+
strict: true
|
|
164
|
+
},
|
|
165
|
+
...parsed.options,
|
|
166
|
+
allowJs: true,
|
|
167
|
+
maxNodeModuleJsDepth: 100
|
|
168
|
+
};
|
|
141
169
|
const implementationFiles = /* @__PURE__ */ new Set();
|
|
142
170
|
const runtimeHost = {
|
|
143
171
|
...ts.sys,
|
|
@@ -577,22 +605,24 @@ function toWitName(name) {
|
|
|
577
605
|
|
|
578
606
|
// src/bundle.ts
|
|
579
607
|
var require3 = createRequire2(import.meta.url);
|
|
608
|
+
var buildPackageJsonPath = require3.resolve("../package.json");
|
|
609
|
+
var buildPackageRepositoryUrl = packageRepositoryUrl(require3(buildPackageJsonPath));
|
|
580
610
|
var MAX_PRODUCTION_COMPONENT_BYTES = 5 * 1024 * 1024;
|
|
581
611
|
var TEMPORARY_DIRECTORY_PREFIX = ".pumpkin-build-";
|
|
582
612
|
var LEGACY_TEMPORARY_DIRECTORY_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
583
613
|
var activeTemporaryDirectories = /* @__PURE__ */ new Set();
|
|
584
614
|
async function bundlePlugin(options) {
|
|
585
|
-
const output =
|
|
586
|
-
const outputDir =
|
|
587
|
-
|
|
615
|
+
const output = path4.resolve(options.output);
|
|
616
|
+
const outputDir = path4.dirname(output);
|
|
617
|
+
fs4.mkdirSync(outputDir, { recursive: true });
|
|
588
618
|
removeAbandonedTemporaryDirectories(outputDir);
|
|
589
|
-
const temporaryDir =
|
|
619
|
+
const temporaryDir = fs4.mkdtempSync(path4.join(outputDir, `${TEMPORARY_DIRECTORY_PREFIX}${process.pid}-`));
|
|
590
620
|
activeTemporaryDirectories.add(temporaryDir);
|
|
591
|
-
const bundle =
|
|
592
|
-
const component =
|
|
621
|
+
const bundle = path4.join(temporaryDir, "bundle.js");
|
|
622
|
+
const component = path4.join(temporaryDir, "plugin.wasm");
|
|
593
623
|
const engine = options.engine ?? "static-hermes";
|
|
594
624
|
const quietRuntimeOutput = options.quietRuntimeOutput ?? false;
|
|
595
|
-
const projectRoot =
|
|
625
|
+
const projectRoot = path4.resolve(options.projectRoot ?? process.cwd());
|
|
596
626
|
const resolvedWasiImports = /* @__PURE__ */ new Set();
|
|
597
627
|
let preserveTemporaryDir = false;
|
|
598
628
|
try {
|
|
@@ -606,7 +636,7 @@ async function bundlePlugin(options) {
|
|
|
606
636
|
globalName: "__pumpkinPlugin",
|
|
607
637
|
plugins: [
|
|
608
638
|
staticHermesImportsPlugin({
|
|
609
|
-
resolveDir:
|
|
639
|
+
resolveDir: path4.dirname(path4.resolve(options.entry)),
|
|
610
640
|
workspaceRoot: projectRoot,
|
|
611
641
|
witDir: options.witDir,
|
|
612
642
|
developmentMode: options.developmentMode ?? false,
|
|
@@ -625,7 +655,7 @@ async function bundlePlugin(options) {
|
|
|
625
655
|
}
|
|
626
656
|
});
|
|
627
657
|
if (engine === "static-hermes") {
|
|
628
|
-
const source =
|
|
658
|
+
const source = fs4.readFileSync(bundle, "utf8");
|
|
629
659
|
const unsupportedWasiImports = staticHermesWasiImports(buildResult.metafile).filter(
|
|
630
660
|
(specifier) => !resolvedWasiImports.has(specifier)
|
|
631
661
|
);
|
|
@@ -634,8 +664,8 @@ async function bundlePlugin(options) {
|
|
|
634
664
|
`Static Hermes JavaScript bundle imports WASI interface${unsupportedWasiImports.length === 1 ? "" : "s"} without a JSI adapter: ${unsupportedWasiImports.join(", ")}`
|
|
635
665
|
);
|
|
636
666
|
}
|
|
637
|
-
|
|
638
|
-
const generatedTypes =
|
|
667
|
+
fs4.writeFileSync(bundle, unwrapStaticHermesExports(source));
|
|
668
|
+
const generatedTypes = path4.join(temporaryDir, "wit-types");
|
|
639
669
|
generateTypes(options.witDir, generatedTypes);
|
|
640
670
|
const usedWitMethods = findUsedWitMethods(options.entry, generatedTypes);
|
|
641
671
|
options.onOutput?.({
|
|
@@ -678,13 +708,13 @@ async function bundlePlugin(options) {
|
|
|
678
708
|
throw runtimeBuildError("Static Hermes", error);
|
|
679
709
|
}
|
|
680
710
|
} else {
|
|
681
|
-
const componentizerPackage =
|
|
711
|
+
const componentizerPackage = path4.dirname(require3.resolve("@di-framework/componentize-qjs/package.json"));
|
|
682
712
|
options.onOutput?.({ type: "componentize", engine });
|
|
683
713
|
try {
|
|
684
714
|
execFileSync2(
|
|
685
715
|
process.execPath,
|
|
686
716
|
[
|
|
687
|
-
|
|
717
|
+
path4.join(componentizerPackage, "bin/componentize-qjs.cjs"),
|
|
688
718
|
"--world",
|
|
689
719
|
"plugin",
|
|
690
720
|
"--wit",
|
|
@@ -692,7 +722,7 @@ async function bundlePlugin(options) {
|
|
|
692
722
|
"--js",
|
|
693
723
|
bundle,
|
|
694
724
|
"--runtime",
|
|
695
|
-
|
|
725
|
+
path4.join(import.meta.dirname, "../runtime/quickjs-runtime-bigint.wasm"),
|
|
696
726
|
"--output",
|
|
697
727
|
component
|
|
698
728
|
],
|
|
@@ -706,11 +736,11 @@ async function bundlePlugin(options) {
|
|
|
706
736
|
throw runtimeBuildError("QuickJS", error);
|
|
707
737
|
}
|
|
708
738
|
}
|
|
709
|
-
const size =
|
|
739
|
+
const size = fs4.statSync(component).size;
|
|
710
740
|
if (!options.developmentMode && size > MAX_PRODUCTION_COMPONENT_BYTES) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
);
|
|
741
|
+
const message = `Production WebAssembly component is ${size} bytes; maximum is ${MAX_PRODUCTION_COMPONENT_BYTES} bytes (5 MiB)`;
|
|
742
|
+
if (isRepositoryProject(projectRoot)) throw new Error(message);
|
|
743
|
+
options.onOutput?.({ type: "warning", message });
|
|
714
744
|
}
|
|
715
745
|
publishComponent(component, output, temporaryDir, () => {
|
|
716
746
|
preserveTemporaryDir = true;
|
|
@@ -718,25 +748,47 @@ async function bundlePlugin(options) {
|
|
|
718
748
|
return size;
|
|
719
749
|
} finally {
|
|
720
750
|
activeTemporaryDirectories.delete(temporaryDir);
|
|
721
|
-
if (!preserveTemporaryDir)
|
|
751
|
+
if (!preserveTemporaryDir) fs4.rmSync(temporaryDir, { recursive: true, force: true });
|
|
722
752
|
}
|
|
723
753
|
}
|
|
754
|
+
function isRepositoryProject(projectRoot) {
|
|
755
|
+
if (buildPackageRepositoryUrl === void 0) return false;
|
|
756
|
+
let projectManifest;
|
|
757
|
+
try {
|
|
758
|
+
projectManifest = JSON.parse(fs4.readFileSync(path4.join(findRepoRoot(projectRoot), "package.json"), "utf8"));
|
|
759
|
+
} catch {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
const projectRepositoryUrl = packageRepositoryUrl(projectManifest);
|
|
763
|
+
return projectRepositoryUrl !== void 0 && normalizeRepositoryUrl(projectRepositoryUrl) === normalizeRepositoryUrl(buildPackageRepositoryUrl);
|
|
764
|
+
}
|
|
765
|
+
function packageRepositoryUrl(manifest) {
|
|
766
|
+
if (typeof manifest !== "object" || manifest === null || Array.isArray(manifest)) return void 0;
|
|
767
|
+
const repository = manifest.repository;
|
|
768
|
+
if (typeof repository === "string") return repository;
|
|
769
|
+
if (typeof repository !== "object" || repository === null || Array.isArray(repository)) return void 0;
|
|
770
|
+
const url = repository.url;
|
|
771
|
+
return typeof url === "string" ? url : void 0;
|
|
772
|
+
}
|
|
773
|
+
function normalizeRepositoryUrl(url) {
|
|
774
|
+
return url.replace(/^git\+/, "").replace(/\.git$/, "").replace(/\/$/, "");
|
|
775
|
+
}
|
|
724
776
|
function removeAbandonedTemporaryDirectories(outputDir) {
|
|
725
|
-
for (const entry of
|
|
777
|
+
for (const entry of fs4.readdirSync(outputDir, { withFileTypes: true })) {
|
|
726
778
|
if (!entry.isDirectory() || !entry.name.startsWith(TEMPORARY_DIRECTORY_PREFIX)) continue;
|
|
727
|
-
const temporaryDir =
|
|
728
|
-
if (activeTemporaryDirectories.has(temporaryDir) ||
|
|
779
|
+
const temporaryDir = path4.join(outputDir, entry.name);
|
|
780
|
+
if (activeTemporaryDirectories.has(temporaryDir) || fs4.existsSync(path4.join(temporaryDir, "previous.wasm"))) {
|
|
729
781
|
continue;
|
|
730
782
|
}
|
|
731
783
|
const owner = /^\.pumpkin-build-(\d+)-/.exec(entry.name);
|
|
732
784
|
if (owner) {
|
|
733
785
|
const pid = Number(owner[1]);
|
|
734
786
|
if (pid !== process.pid && isProcessRunning(pid)) continue;
|
|
735
|
-
|
|
787
|
+
fs4.rmSync(temporaryDir, { recursive: true, force: true });
|
|
736
788
|
continue;
|
|
737
789
|
}
|
|
738
|
-
if (Date.now() -
|
|
739
|
-
|
|
790
|
+
if (Date.now() - fs4.statSync(temporaryDir).mtimeMs >= LEGACY_TEMPORARY_DIRECTORY_MAX_AGE_MS) {
|
|
791
|
+
fs4.rmSync(temporaryDir, { recursive: true, force: true });
|
|
740
792
|
}
|
|
741
793
|
}
|
|
742
794
|
}
|
|
@@ -779,18 +831,18 @@ function isTrailingLicenseComment(source) {
|
|
|
779
831
|
}
|
|
780
832
|
function publishComponent(component, output, temporaryDir, preserveForRecovery) {
|
|
781
833
|
try {
|
|
782
|
-
|
|
834
|
+
fs4.renameSync(component, output);
|
|
783
835
|
} catch (error) {
|
|
784
|
-
if (!isReplaceError(error) || !
|
|
785
|
-
const existing =
|
|
836
|
+
if (!isReplaceError(error) || !fs4.existsSync(output)) throw error;
|
|
837
|
+
const existing = fs4.lstatSync(output);
|
|
786
838
|
if (!existing.isFile() && !existing.isSymbolicLink()) throw error;
|
|
787
|
-
const previous =
|
|
788
|
-
|
|
839
|
+
const previous = path4.join(temporaryDir, "previous.wasm");
|
|
840
|
+
fs4.renameSync(output, previous);
|
|
789
841
|
try {
|
|
790
|
-
|
|
842
|
+
fs4.renameSync(component, output);
|
|
791
843
|
} catch (publishError) {
|
|
792
844
|
try {
|
|
793
|
-
|
|
845
|
+
fs4.renameSync(previous, output);
|
|
794
846
|
} catch (restoreError) {
|
|
795
847
|
preserveForRecovery();
|
|
796
848
|
throw new AggregateError(
|
|
@@ -806,23 +858,6 @@ function isReplaceError(error) {
|
|
|
806
858
|
return typeof error === "object" && error !== null && "code" in error && (error.code === "EEXIST" || error.code === "EPERM" || error.code === "EACCES");
|
|
807
859
|
}
|
|
808
860
|
|
|
809
|
-
// src/capabilities.ts
|
|
810
|
-
var WASI_VERSION = "0.2.3";
|
|
811
|
-
var CAPABILITIES = {
|
|
812
|
-
http: ["http/types", "http/outgoing-handler"],
|
|
813
|
-
filesystem: ["filesystem/types", "filesystem/preopens"],
|
|
814
|
-
sockets: ["sockets/network", "sockets/instance-network", "sockets/tcp", "sockets/tcp-create-socket"],
|
|
815
|
-
udp: ["sockets/network", "sockets/instance-network", "sockets/udp", "sockets/udp-create-socket"]
|
|
816
|
-
};
|
|
817
|
-
var SUPPORT_IMPORTS = ["io/poll", "io/streams", "clocks/monotonic-clock"];
|
|
818
|
-
function isCapability(name) {
|
|
819
|
-
return Object.hasOwn(CAPABILITIES, name);
|
|
820
|
-
}
|
|
821
|
-
function wasiInterfaces(capabilities) {
|
|
822
|
-
if (capabilities.length === 0) return [];
|
|
823
|
-
return [.../* @__PURE__ */ new Set([...capabilities.flatMap((c) => CAPABILITIES[c]), ...SUPPORT_IMPORTS])];
|
|
824
|
-
}
|
|
825
|
-
|
|
826
861
|
// ../minecraft-colors/src/index.ts
|
|
827
862
|
var COLORS = {
|
|
828
863
|
black: "0",
|
|
@@ -955,10 +990,11 @@ addNamedFormatters(ansi, "ansi");
|
|
|
955
990
|
|
|
956
991
|
// src/output.ts
|
|
957
992
|
function formatBuildOutput(message) {
|
|
958
|
-
if (message.type === "error") {
|
|
993
|
+
if (message.type === "error" || message.type === "warning") {
|
|
994
|
+
const formatLine = message.type === "error" ? ansi.named.error : ansi.named.value;
|
|
959
995
|
return message.message.split(/\r?\n/).map((line, index) => {
|
|
960
|
-
const prefix = index === 0 ? "Error: " : " ";
|
|
961
|
-
return `[build] ${prefix}${
|
|
996
|
+
const prefix = index === 0 ? `${message.type === "error" ? "Error" : "Warning"}: ` : " ";
|
|
997
|
+
return `[build] ${prefix}${formatLine(line)}`;
|
|
962
998
|
}).join("\n");
|
|
963
999
|
}
|
|
964
1000
|
if (message.type === "built") {
|
|
@@ -982,6 +1018,7 @@ function formatBuildOutput(message) {
|
|
|
982
1018
|
function printBuildOutput(message) {
|
|
983
1019
|
const formatted = formatBuildOutput(message);
|
|
984
1020
|
if (message.type === "error") console.error(formatted);
|
|
1021
|
+
else if (message.type === "warning") console.warn(formatted);
|
|
985
1022
|
else console.log(formatted);
|
|
986
1023
|
}
|
|
987
1024
|
function runtimeLabel(engine, runtimeVariant, gcVariant, parseTypeScript) {
|
|
@@ -997,12 +1034,13 @@ function formatSelectionOption(option, selection, omittedValue) {
|
|
|
997
1034
|
}
|
|
998
1035
|
|
|
999
1036
|
// src/plugin-config.ts
|
|
1000
|
-
import * as
|
|
1001
|
-
import * as
|
|
1037
|
+
import * as fs5 from "node:fs";
|
|
1038
|
+
import * as path5 from "node:path";
|
|
1039
|
+
import { CAPABILITIES, isCapability } from "@pumpkin-plugins/wasi-capabilities";
|
|
1002
1040
|
function readPluginConfig(pluginDir) {
|
|
1003
1041
|
let pkg;
|
|
1004
1042
|
try {
|
|
1005
|
-
pkg = JSON.parse(
|
|
1043
|
+
pkg = JSON.parse(fs5.readFileSync(path5.join(pluginDir, "package.json"), "utf8"));
|
|
1006
1044
|
} catch (error) {
|
|
1007
1045
|
if (error instanceof SyntaxError) throw new BuildError(`package.json is not valid JSON (${error.message})`);
|
|
1008
1046
|
if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
@@ -1077,11 +1115,11 @@ function optionalRelativePath(value, name) {
|
|
|
1077
1115
|
}
|
|
1078
1116
|
function requiredRelativePath(value, name) {
|
|
1079
1117
|
if (typeof value !== "string") throw new BuildError(`"pumpkinPlugin.${name}" must be a relative path`);
|
|
1080
|
-
const normalized =
|
|
1081
|
-
if (value.length === 0 || value.includes("\0") ||
|
|
1118
|
+
const normalized = path5.posix.normalize(value.replaceAll("\\", "/"));
|
|
1119
|
+
if (value.length === 0 || value.includes("\0") || path5.isAbsolute(value) || path5.win32.isAbsolute(value) || path5.win32.parse(value).root !== "" || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
1082
1120
|
throw new BuildError(`"pumpkinPlugin.${name}" must be a path inside the package`);
|
|
1083
1121
|
}
|
|
1084
|
-
if (name === "output" &&
|
|
1122
|
+
if (name === "output" && path5.posix.extname(normalized).toLowerCase() !== ".wasm") {
|
|
1085
1123
|
throw new BuildError('"pumpkinPlugin.output" must name a .wasm file');
|
|
1086
1124
|
}
|
|
1087
1125
|
return normalized;
|
|
@@ -1090,22 +1128,13 @@ function isRecord(value) {
|
|
|
1090
1128
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1091
1129
|
}
|
|
1092
1130
|
|
|
1093
|
-
// src/repo.ts
|
|
1094
|
-
import * as fs5 from "node:fs";
|
|
1095
|
-
import * as path5 from "node:path";
|
|
1096
|
-
function findRepoRoot(from) {
|
|
1097
|
-
for (let dir = path5.resolve(from); ; dir = path5.dirname(dir)) {
|
|
1098
|
-
if (fs5.existsSync(path5.join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
1099
|
-
if (path5.dirname(dir) === dir) return path5.resolve(from);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
function cacheDir(from) {
|
|
1103
|
-
return process.env.PUMPKIN_PLUGINS_CACHE_DIR || path5.join(findRepoRoot(from), ".cache");
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
1131
|
// src/update-check.ts
|
|
1132
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
1107
1133
|
import { latestVersion, ONE_DAY } from "@badisi/latest-version";
|
|
1108
|
-
var
|
|
1134
|
+
var packageMetadata = createRequire3(import.meta.url)("../package.json");
|
|
1135
|
+
var packageName = packageMetadata.name;
|
|
1136
|
+
var repositoryUrl = packageMetadata.repository.url.replace(/^git\+/, "").replace(/\.git$/, "");
|
|
1137
|
+
var releaseComponent = packageName.split("/").at(-1) ?? packageName;
|
|
1109
1138
|
var requestTimeout = 5e3;
|
|
1110
1139
|
function isBuildUpdateCheckAllowed(args, environment, isTTY) {
|
|
1111
1140
|
return isTTY && !environment.CI && environment.PUMPKIN_DEV_MODE !== "1" && environment.PUMPKIN_PLUGINS_NO_UPDATE_NOTIFIER !== "1" && !args.some((argument) => ["--help", "-h", "--version", "-V", "--no-update-notifier"].includes(argument));
|
|
@@ -1130,14 +1159,22 @@ async function startBuildUpdateCheck(args, options) {
|
|
|
1130
1159
|
}
|
|
1131
1160
|
function formatBuildUpdateNotice(currentVersion, latestVersion2) {
|
|
1132
1161
|
const content = [
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1162
|
+
"",
|
|
1163
|
+
`Update available v${currentVersion} \u226B v${latestVersion2}`,
|
|
1164
|
+
`Changelog: ${new URL(`releases/tag/${releaseComponent}-v${latestVersion2}`, `${repositoryUrl}/`).href}`,
|
|
1165
|
+
'Run "pnpm dlx @pumpkin-plugins/codemod update-build ." to update',
|
|
1166
|
+
"",
|
|
1167
|
+
"Follow Filiph Sandstr\xF6m for updates: https://x.com/filiphsandstrom",
|
|
1168
|
+
""
|
|
1136
1169
|
];
|
|
1137
1170
|
const contentWidth = Math.max(...content.map((line) => line.length));
|
|
1138
1171
|
const border = "\u2500".repeat(contentWidth + 2);
|
|
1139
|
-
const body = content.map((line) =>
|
|
1140
|
-
|
|
1172
|
+
const body = content.map((line) => {
|
|
1173
|
+
const leftPadding = Math.floor((contentWidth - line.length) / 2);
|
|
1174
|
+
const centeredLine = `${" ".repeat(leftPadding)}${line}${" ".repeat(contentWidth - line.length - leftPadding)}`;
|
|
1175
|
+
return `\u2502 ${centeredLine} \u2502`;
|
|
1176
|
+
});
|
|
1177
|
+
return [`\u256D${border}\u256E`, ...body, `\u2570${border}\u256F`, ""].join("\n");
|
|
1141
1178
|
}
|
|
1142
1179
|
|
|
1143
1180
|
// src/wasi-wit.ts
|
|
@@ -1457,6 +1494,7 @@ async function writeAtomically(file, bytes, expectedHash, stagingDirectory) {
|
|
|
1457
1494
|
// src/wit.ts
|
|
1458
1495
|
import * as fs8 from "node:fs";
|
|
1459
1496
|
import * as path8 from "node:path";
|
|
1497
|
+
import { WASI_VERSION } from "@pumpkin-plugins/wasi-capabilities";
|
|
1460
1498
|
function injectWasiImports(pluginWit, interfaces) {
|
|
1461
1499
|
const firstExport = /^[ \t]*export /m.exec(pluginWit);
|
|
1462
1500
|
if (!firstExport) throw new BuildError("could not find the exports in plugin.wit; the API layout changed");
|
|
@@ -1561,7 +1599,7 @@ function isInputOutputError(error) {
|
|
|
1561
1599
|
|
|
1562
1600
|
// src/cli.ts
|
|
1563
1601
|
async function run(args, pluginDir) {
|
|
1564
|
-
const command = new Command().name("pumpkin-plugins-build").description("Build the Pumpkin plugin in the current directory.").version(
|
|
1602
|
+
const command = new Command().name("pumpkin-plugins-build").description("Build the Pumpkin plugin in the current directory.").version(createRequire4(import.meta.url)("../package.json").version).option("--types-only", "Generate guest declarations without building a component").option("--parse-ts", "Use Hermes TypeScript parsing for the component bundle").option("--no-update-notifier", "Skip the npm update check").configureOutput({ outputError: () => {
|
|
1565
1603
|
} }).exitOverride();
|
|
1566
1604
|
try {
|
|
1567
1605
|
command.parse(args, { from: "user" });
|
|
@@ -1657,7 +1695,7 @@ async function executeCli(args, pluginDir, options = {}) {
|
|
|
1657
1695
|
}
|
|
1658
1696
|
await main(args, pluginDir);
|
|
1659
1697
|
}
|
|
1660
|
-
function resolveApiWit(pluginDir, resolvePackageJson = (root, packageSpecifier) =>
|
|
1698
|
+
function resolveApiWit(pluginDir, resolvePackageJson = (root, packageSpecifier) => createRequire4(path9.join(root, "package.json")).resolve(packageSpecifier)) {
|
|
1661
1699
|
let packageJson;
|
|
1662
1700
|
try {
|
|
1663
1701
|
const canonicalSpecifier = "@pumpkin-plugins/pumpkin-api/package.json";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pumpkin-plugins/build",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Shared build tool for the plugins",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"minecraft",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"contributors": [
|
|
36
36
|
"Filiph Sandström <filfat@hotmail.se> (https://github.com/filiphsps)"
|
|
37
37
|
],
|
|
38
|
+
"sideEffects": false,
|
|
38
39
|
"type": "module",
|
|
39
40
|
"bin": {
|
|
40
41
|
"pumpkin-plugins-build": "dist/cli.js"
|
|
@@ -51,13 +52,14 @@
|
|
|
51
52
|
"@di-framework/componentize-qjs": "0.4.4-di.3",
|
|
52
53
|
"@pumpkin-plugins/minecraft-colors": "0.1.0",
|
|
53
54
|
"@pumpkin-plugins/pumpkin-api": "0.1.0",
|
|
54
|
-
"@pumpkin-plugins/static-hermes-runtime": "0.1.
|
|
55
|
+
"@pumpkin-plugins/static-hermes-runtime": "0.1.1",
|
|
56
|
+
"@pumpkin-plugins/wasi-capabilities": "0.1.0",
|
|
55
57
|
"commander": "15.0.0",
|
|
56
58
|
"esbuild": "0.28.2",
|
|
57
59
|
"typescript": "6.0.3"
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
60
|
-
"@pumpkin-plugins/docs": "0.1.
|
|
62
|
+
"@pumpkin-plugins/docs": "0.1.2",
|
|
61
63
|
"@types/node": "24.19.1",
|
|
62
64
|
"@vitest/coverage-v8": "5.0.4",
|
|
63
65
|
"vitest": "5.0.4"
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"access": "public"
|
|
70
72
|
},
|
|
71
73
|
"scripts": {
|
|
72
|
-
"build": "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node24 --packages=external --alias:@pumpkin-plugins/minecraft-colors=../minecraft-colors/src/index.ts --
|
|
74
|
+
"build": "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node24 --packages=external --alias:@pumpkin-plugins/minecraft-colors=../minecraft-colors/src/index.ts --outdir=dist",
|
|
73
75
|
"readme": "pumpkin-plugins-docs generate docs.ts",
|
|
74
76
|
"readme:check": "pumpkin-plugins-docs generate docs.ts --check",
|
|
75
77
|
"test": "vitest run",
|