@crafter8/sdk 0.1.0-next.1
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/LICENSE +21 -0
- package/README.md +175 -0
- package/build.js +553 -0
- package/index.d.ts +473 -0
- package/index.js +1831 -0
- package/mock.d.ts +128 -0
- package/mock.js +471 -0
- package/package.json +61 -0
- package/react.d.ts +30 -0
- package/react.js +124 -0
package/build.js
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
ARTIFACT_SPEC_V2,
|
|
11
|
+
HOST_API_V1,
|
|
12
|
+
generateArtifactManifest,
|
|
13
|
+
isArtifactDefinition,
|
|
14
|
+
} from "./index.js";
|
|
15
|
+
|
|
16
|
+
function printUsage() {
|
|
17
|
+
console.log(`crafter8-build
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
crafter8-build --entry <file> [--runtime-entry <file>] [--out-dir <dir>] [--version <version>] [--spec-version <n>] [--host-api <n>] [--legacy-uses] [--emit-community-datapack] [--publication-dir <dir>] [--stdout]
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
crafter8-build --entry ./src/index.js --out-dir ./dist
|
|
24
|
+
crafter8-build --entry ./src/crafter8.js --out-dir ./dist
|
|
25
|
+
crafter8-build --entry ./src/crafter8.js --runtime-entry ./src/index.js --out-dir ./dist
|
|
26
|
+
crafter8-build --entry ./crafter8.mjs --emit-community-datapack --publication-dir .
|
|
27
|
+
crafter8-build --entry ./src/crafter8.js --legacy-uses --out-dir ./dist
|
|
28
|
+
crafter8-build --entry ./src/crafter8.js --version 1.2.0 --stdout
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function parseArgs(argv) {
|
|
33
|
+
const options = {
|
|
34
|
+
outDir: "dist",
|
|
35
|
+
specVersion: ARTIFACT_SPEC_V2,
|
|
36
|
+
hostApi: HOST_API_V1,
|
|
37
|
+
stdout: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
41
|
+
const arg = argv[index];
|
|
42
|
+
|
|
43
|
+
if (arg === "--help" || arg === "-h") {
|
|
44
|
+
options.help = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (arg === "--stdout") {
|
|
49
|
+
options.stdout = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (arg === "--legacy-uses") {
|
|
54
|
+
options.legacyUses = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (arg === "--emit-community-datapack") {
|
|
59
|
+
options.emitCommunityDatapack = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const next = argv[index + 1];
|
|
64
|
+
|
|
65
|
+
if (arg === "--entry") {
|
|
66
|
+
options.entry = next;
|
|
67
|
+
index += 1;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (arg === "--out-dir") {
|
|
72
|
+
options.outDir = next;
|
|
73
|
+
index += 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (arg === "--runtime-entry") {
|
|
78
|
+
options.runtimeEntry = next;
|
|
79
|
+
index += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (arg === "--version") {
|
|
84
|
+
options.version = next;
|
|
85
|
+
index += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (arg === "--publication-dir") {
|
|
90
|
+
options.publicationDir = next;
|
|
91
|
+
index += 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (arg === "--spec-version") {
|
|
96
|
+
options.specVersion = Number(next);
|
|
97
|
+
index += 1;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (arg === "--host-api") {
|
|
102
|
+
options.hostApi = Number(next);
|
|
103
|
+
index += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return options;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function ensureFile(filePath, label) {
|
|
114
|
+
if (!filePath) {
|
|
115
|
+
throw new Error(`${label} is required.`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const absolutePath = path.resolve(filePath);
|
|
119
|
+
if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) {
|
|
120
|
+
throw new Error(`${label} does not exist: ${absolutePath}`);
|
|
121
|
+
}
|
|
122
|
+
return absolutePath;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function findNearestPackageJson(startDir) {
|
|
126
|
+
let currentDir = startDir;
|
|
127
|
+
|
|
128
|
+
while (true) {
|
|
129
|
+
const candidate = path.join(currentDir, "package.json");
|
|
130
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
131
|
+
return candidate;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const parentDir = path.dirname(currentDir);
|
|
135
|
+
if (parentDir === currentDir) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
currentDir = parentDir;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function findNearestGitRoot(startDir) {
|
|
143
|
+
let currentDir = startDir;
|
|
144
|
+
|
|
145
|
+
while (true) {
|
|
146
|
+
const candidate = path.join(currentDir, ".git");
|
|
147
|
+
if (fs.existsSync(candidate)) {
|
|
148
|
+
return currentDir;
|
|
149
|
+
}
|
|
150
|
+
const parentDir = path.dirname(currentDir);
|
|
151
|
+
if (parentDir === currentDir) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
currentDir = parentDir;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function relativePosix(from, to) {
|
|
159
|
+
return path.relative(from, to).split(path.sep).join("/");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function resolveVersion(entryPath, explicitVersion) {
|
|
163
|
+
if (explicitVersion) {
|
|
164
|
+
return explicitVersion;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const packageJsonPath = findNearestPackageJson(path.dirname(entryPath));
|
|
168
|
+
if (!packageJsonPath) {
|
|
169
|
+
throw new Error("Could not find package.json for declaration entry. Pass --version explicitly.");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
173
|
+
if (typeof packageJson.version !== "string" || packageJson.version.trim() === "") {
|
|
174
|
+
throw new Error(`package.json is missing a valid version: ${packageJsonPath}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return packageJson.version.trim();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function loadDefinition(entryPath) {
|
|
181
|
+
const moduleUrl = pathToFileURL(entryPath).href;
|
|
182
|
+
const loaded = await import(moduleUrl);
|
|
183
|
+
const definition = loaded.default ?? loaded.artifact ?? loaded.definition;
|
|
184
|
+
|
|
185
|
+
if (!isArtifactDefinition(definition)) {
|
|
186
|
+
throw new Error(`Declaration module did not export a Crafter8 definition as default, artifact, or definition: ${entryPath}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return definition;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function packageNameFromSpecifier(specifier) {
|
|
193
|
+
if (!specifier || specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("node:")) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
if (/^[A-Za-z]:[\\/]/.test(specifier)) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
if (specifier.startsWith("@")) {
|
|
200
|
+
const parts = specifier.split("/");
|
|
201
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
|
|
202
|
+
}
|
|
203
|
+
return specifier.split("/")[0] || null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function resolveLocalImport(importerPath, specifier) {
|
|
207
|
+
const basePath = path.resolve(path.dirname(importerPath), specifier);
|
|
208
|
+
const candidates = [
|
|
209
|
+
basePath,
|
|
210
|
+
`${basePath}.js`,
|
|
211
|
+
`${basePath}.mjs`,
|
|
212
|
+
`${basePath}.cjs`,
|
|
213
|
+
`${basePath}.ts`,
|
|
214
|
+
`${basePath}.tsx`,
|
|
215
|
+
`${basePath}.jsx`,
|
|
216
|
+
path.join(basePath, "index.js"),
|
|
217
|
+
path.join(basePath, "index.mjs"),
|
|
218
|
+
path.join(basePath, "index.ts"),
|
|
219
|
+
path.join(basePath, "index.tsx"),
|
|
220
|
+
path.join(basePath, "index.jsx"),
|
|
221
|
+
];
|
|
222
|
+
return candidates.find((candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isFile()) || null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function collectImportSpecifiers(filePath, visited = new Set(), packageNames = new Set()) {
|
|
226
|
+
const absolutePath = path.resolve(filePath);
|
|
227
|
+
if (visited.has(absolutePath)) {
|
|
228
|
+
return packageNames;
|
|
229
|
+
}
|
|
230
|
+
visited.add(absolutePath);
|
|
231
|
+
|
|
232
|
+
const source = fs.readFileSync(absolutePath, "utf8");
|
|
233
|
+
const patterns = [
|
|
234
|
+
/(?:import|export)\s+(?:[^"'`]*?\s+from\s+)?["']([^"'`]+)["']/g,
|
|
235
|
+
/import\s*\(\s*["']([^"'`]+)["']\s*\)/g,
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
for (const pattern of patterns) {
|
|
239
|
+
let match;
|
|
240
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
241
|
+
const specifier = String(match[1] || "").trim();
|
|
242
|
+
if (!specifier) continue;
|
|
243
|
+
if (specifier.startsWith(".")) {
|
|
244
|
+
const resolved = resolveLocalImport(absolutePath, specifier);
|
|
245
|
+
if (resolved) {
|
|
246
|
+
collectImportSpecifiers(resolved, visited, packageNames);
|
|
247
|
+
}
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const packageName = packageNameFromSpecifier(specifier);
|
|
251
|
+
if (packageName) {
|
|
252
|
+
packageNames.add(packageName);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return packageNames;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function readCrafter8DependencyDefinition(packageName, runtimeEntryPath) {
|
|
261
|
+
if (!packageName || packageName === "@crafter8/sdk") {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const requireFromEntry = createRequire(runtimeEntryPath);
|
|
266
|
+
let crafter8EntryPath;
|
|
267
|
+
try {
|
|
268
|
+
crafter8EntryPath = requireFromEntry.resolve(`${packageName}/crafter8`);
|
|
269
|
+
} catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const source = fs.readFileSync(crafter8EntryPath, "utf8");
|
|
275
|
+
const kind =
|
|
276
|
+
source.includes("defineDatapack(")
|
|
277
|
+
? "datapack"
|
|
278
|
+
: source.includes("defineModule(")
|
|
279
|
+
? "module"
|
|
280
|
+
: source.includes("defineApp(")
|
|
281
|
+
? "app"
|
|
282
|
+
: null;
|
|
283
|
+
const idMatch = source.match(/\bid\s*:\s*["']([^"'`]+)["']/);
|
|
284
|
+
if (kind && (kind === "datapack" || kind === "module")) {
|
|
285
|
+
return {
|
|
286
|
+
kind,
|
|
287
|
+
id: idMatch?.[1]?.trim() || packageName,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
} catch {
|
|
291
|
+
// Fall through to dynamic import.
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const loaded = await import(pathToFileURL(crafter8EntryPath).href);
|
|
295
|
+
const definition = loaded.default ?? loaded.artifact ?? loaded.definition;
|
|
296
|
+
return isArtifactDefinition(definition) ? definition : null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export async function extractCrafter8Dependencies(options) {
|
|
300
|
+
if (!options?.runtimeEntry) {
|
|
301
|
+
return { modules: [], datapacks: [] };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const runtimeEntryPath = ensureFile(options.runtimeEntry, "runtime entry");
|
|
305
|
+
const packageNames = Array.from(collectImportSpecifiers(runtimeEntryPath));
|
|
306
|
+
const dependencies = {
|
|
307
|
+
modules: [],
|
|
308
|
+
datapacks: [],
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
for (const packageName of packageNames) {
|
|
312
|
+
const definition = await readCrafter8DependencyDefinition(packageName, runtimeEntryPath);
|
|
313
|
+
if (!definition) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (definition.kind === "module") {
|
|
317
|
+
dependencies.modules.push(definition.id);
|
|
318
|
+
}
|
|
319
|
+
if (definition.kind === "datapack") {
|
|
320
|
+
dependencies.datapacks.push(definition.id);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
modules: Array.from(new Set(dependencies.modules)).sort(),
|
|
326
|
+
datapacks: Array.from(new Set(dependencies.datapacks)).sort(),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function writeManifest(outDir, manifest) {
|
|
331
|
+
const crafter8Dir = path.join(outDir, ".crafter8");
|
|
332
|
+
fs.mkdirSync(crafter8Dir, { recursive: true });
|
|
333
|
+
const manifestPath = path.join(crafter8Dir, "artifact.json");
|
|
334
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
335
|
+
return manifestPath;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function inferDatapackContentType(filePath) {
|
|
339
|
+
const ext = path.extname(String(filePath || "")).toLowerCase();
|
|
340
|
+
if (ext === ".json") return "application/json";
|
|
341
|
+
if (ext === ".txt" || ext === ".md") return "text/plain";
|
|
342
|
+
if (ext === ".csv") return "text/csv";
|
|
343
|
+
if (ext === ".html") return "text/html";
|
|
344
|
+
if (ext === ".css") return "text/css";
|
|
345
|
+
if (ext === ".js" || ext === ".mjs") return "application/javascript";
|
|
346
|
+
return "application/octet-stream";
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function collectDatapackPublishEntries(rootDir) {
|
|
350
|
+
const rows = [];
|
|
351
|
+
|
|
352
|
+
function walk(currentDir) {
|
|
353
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
354
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
355
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
356
|
+
if (entry.isDirectory()) {
|
|
357
|
+
walk(absolutePath);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const relativePath = relativePosix(rootDir, absolutePath);
|
|
361
|
+
const key = relativePath.replace(/\.[^.]+$/u, "");
|
|
362
|
+
rows.push({
|
|
363
|
+
key,
|
|
364
|
+
label: key,
|
|
365
|
+
kind: "file",
|
|
366
|
+
path: relativePath,
|
|
367
|
+
contentType: inferDatapackContentType(relativePath),
|
|
368
|
+
role: key === "manifest" ? "dataset-manifest" : "content",
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
walk(rootDir);
|
|
374
|
+
return rows;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function buildCommunityDatapackManifestFromDefinition(definition, options) {
|
|
378
|
+
if (definition.kind !== "datapack") {
|
|
379
|
+
throw new Error("Community datapack publication can only be generated for datapack definitions.");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const entryPath = ensureFile(options.entry, "entry");
|
|
383
|
+
const packageJsonPath = findNearestPackageJson(path.dirname(entryPath));
|
|
384
|
+
if (!packageJsonPath) {
|
|
385
|
+
throw new Error("Could not find package.json for datapack declaration entry.");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const packageDir = path.dirname(packageJsonPath);
|
|
389
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
390
|
+
if (typeof packageJson.name !== "string" || packageJson.name.trim() === "") {
|
|
391
|
+
throw new Error(`package.json is missing a valid name: ${packageJsonPath}`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const repoRoot = options.repoRoot ? path.resolve(options.repoRoot) : findNearestGitRoot(packageDir) ?? packageDir;
|
|
395
|
+
const version = resolveVersion(entryPath, options.version);
|
|
396
|
+
const packageName = packageJson.name.trim();
|
|
397
|
+
const slug = packageName.split("/").pop();
|
|
398
|
+
const contentsRoot = path.resolve(path.dirname(entryPath), definition.contents?.root || ".");
|
|
399
|
+
if (!fs.existsSync(contentsRoot) || !fs.statSync(contentsRoot).isDirectory()) {
|
|
400
|
+
throw new Error(`Datapack contents root does not exist: ${contentsRoot}`);
|
|
401
|
+
}
|
|
402
|
+
const payloadRoot = relativePosix(packageDir, contentsRoot);
|
|
403
|
+
const publishEntries = collectDatapackPublishEntries(contentsRoot);
|
|
404
|
+
const manifestEntryRelative =
|
|
405
|
+
typeof definition.contents?.manifest === "string" && definition.contents.manifest.trim() !== ""
|
|
406
|
+
? relativePosix(contentsRoot, path.resolve(path.dirname(entryPath), definition.contents.manifest.trim()))
|
|
407
|
+
: null;
|
|
408
|
+
|
|
409
|
+
const contents = publishEntries.map((entry) =>
|
|
410
|
+
manifestEntryRelative && entry.path === manifestEntryRelative
|
|
411
|
+
? {
|
|
412
|
+
...entry,
|
|
413
|
+
key: "manifest",
|
|
414
|
+
label: "manifest",
|
|
415
|
+
role: "dataset-manifest",
|
|
416
|
+
}
|
|
417
|
+
: entry,
|
|
418
|
+
);
|
|
419
|
+
contents.sort((a, b) => {
|
|
420
|
+
if (a.key === "manifest" && b.key !== "manifest") return -1;
|
|
421
|
+
if (b.key === "manifest" && a.key !== "manifest") return 1;
|
|
422
|
+
return String(a.key).localeCompare(String(b.key));
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
const manifest = {
|
|
426
|
+
kind: "datapack",
|
|
427
|
+
manifestVersion: 1,
|
|
428
|
+
packageName,
|
|
429
|
+
id: definition.id,
|
|
430
|
+
slug,
|
|
431
|
+
name: definition.name,
|
|
432
|
+
description: definition.summary || definition.name,
|
|
433
|
+
version,
|
|
434
|
+
package: relativePosix(repoRoot, packageDir),
|
|
435
|
+
capability: "datapacks.read",
|
|
436
|
+
payloadRoot,
|
|
437
|
+
provides: definition.provides || {},
|
|
438
|
+
publish: {
|
|
439
|
+
sourceRoot: payloadRoot,
|
|
440
|
+
entries: contents.map((entry) => ({
|
|
441
|
+
from: entry.path,
|
|
442
|
+
to: entry.path,
|
|
443
|
+
})),
|
|
444
|
+
},
|
|
445
|
+
contents,
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
const registry = [
|
|
449
|
+
{
|
|
450
|
+
kind: "datapack",
|
|
451
|
+
packageName,
|
|
452
|
+
id: definition.id,
|
|
453
|
+
slug,
|
|
454
|
+
name: definition.name,
|
|
455
|
+
description: definition.summary || definition.name,
|
|
456
|
+
version,
|
|
457
|
+
capability: "datapacks.read",
|
|
458
|
+
package: relativePosix(repoRoot, packageDir),
|
|
459
|
+
manifestVersion: 1,
|
|
460
|
+
manifestPath: `${relativePosix(repoRoot, packageDir)}/community-datapack.manifest.json`,
|
|
461
|
+
payloadRoot: `${relativePosix(repoRoot, packageDir)}/${payloadRoot}`,
|
|
462
|
+
generatedAt: new Date().toISOString(),
|
|
463
|
+
contentKeys: contents.map((entry) => entry.key),
|
|
464
|
+
...(definition.provides?.profile ? { profile: definition.provides.profile } : {}),
|
|
465
|
+
},
|
|
466
|
+
];
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
manifest,
|
|
470
|
+
registry,
|
|
471
|
+
packageDir,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function writeCommunityDatapackPublication(targetDir, publication) {
|
|
476
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
477
|
+
const manifestPath = path.join(targetDir, "community-datapack.manifest.json");
|
|
478
|
+
const registryPath = path.join(targetDir, "community-datapacks.json");
|
|
479
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(publication.manifest, null, 2)}\n`);
|
|
480
|
+
fs.writeFileSync(registryPath, `${JSON.stringify(publication.registry, null, 2)}\n`);
|
|
481
|
+
return {
|
|
482
|
+
manifestPath,
|
|
483
|
+
registryPath,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export async function buildArtifact(options) {
|
|
488
|
+
const entryPath = ensureFile(options.entry, "entry");
|
|
489
|
+
const version = resolveVersion(entryPath, options.version);
|
|
490
|
+
const definition = await loadDefinition(entryPath);
|
|
491
|
+
const dependencies = await extractCrafter8Dependencies({
|
|
492
|
+
runtimeEntry: options.runtimeEntry || entryPath,
|
|
493
|
+
});
|
|
494
|
+
const manifest = generateArtifactManifest(definition, {
|
|
495
|
+
version,
|
|
496
|
+
specVersion: options.specVersion,
|
|
497
|
+
hostApi: options.hostApi,
|
|
498
|
+
dependencies,
|
|
499
|
+
legacyUses: options.legacyUses === true,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
if (options.stdout) {
|
|
503
|
+
return { definition, dependencies, manifest, manifestPath: null, publication: null };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const outDir = path.resolve(options.outDir);
|
|
507
|
+
const manifestPath = writeManifest(outDir, manifest);
|
|
508
|
+
let publication = null;
|
|
509
|
+
if (options.emitCommunityDatapack) {
|
|
510
|
+
const builtPublication = buildCommunityDatapackManifestFromDefinition(definition, {
|
|
511
|
+
...options,
|
|
512
|
+
entry: entryPath,
|
|
513
|
+
version,
|
|
514
|
+
});
|
|
515
|
+
const publicationDir = path.resolve(options.publicationDir || builtPublication.packageDir);
|
|
516
|
+
publication = {
|
|
517
|
+
...builtPublication,
|
|
518
|
+
paths: writeCommunityDatapackPublication(publicationDir, builtPublication),
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
return { definition, dependencies, manifest, manifestPath, publication };
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async function main() {
|
|
525
|
+
const options = parseArgs(process.argv.slice(2));
|
|
526
|
+
if (options.help) {
|
|
527
|
+
printUsage();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const { manifest, manifestPath, publication } = await buildArtifact(options);
|
|
532
|
+
|
|
533
|
+
if (options.stdout) {
|
|
534
|
+
process.stdout.write(`${JSON.stringify(manifest, null, 2)}\n`);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
console.log(`[crafter8-build] wrote ${manifestPath}`);
|
|
539
|
+
if (publication?.paths?.manifestPath) {
|
|
540
|
+
console.log(`[crafter8-build] wrote ${publication.paths.manifestPath}`);
|
|
541
|
+
}
|
|
542
|
+
if (publication?.paths?.registryPath) {
|
|
543
|
+
console.log(`[crafter8-build] wrote ${publication.paths.registryPath}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const isEntrypoint = import.meta.url === pathToFileURL(process.argv[1] || "").href;
|
|
548
|
+
if (isEntrypoint) {
|
|
549
|
+
main().catch((error) => {
|
|
550
|
+
console.error(`[crafter8-build] Failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
551
|
+
process.exit(1);
|
|
552
|
+
});
|
|
553
|
+
}
|