@druid-ui/build 1.0.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/bin/gen-types.js +84 -0
- package/bin/index.js +172 -0
- package/dist/index.js +157 -0
- package/dist/types/cmd/gen-types.d.ts +3 -0
- package/dist/types/cmd/gen-types.d.ts.map +1 -0
- package/dist/types/cmd/index.d.ts +3 -0
- package/dist/types/cmd/index.d.ts.map +1 -0
- package/dist/types/esbuild-plugin.d.ts +3 -0
- package/dist/types/esbuild-plugin.d.ts.map +1 -0
- package/dist/types/gen-types.d.ts +2 -0
- package/dist/types/gen-types.d.ts.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/utils.d.ts +3 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/package.json +40 -0
- package/src/cmd/gen-types.ts +39 -0
- package/src/cmd/index.ts +47 -0
- package/src/esbuild-plugin.ts +52 -0
- package/src/gen-types.ts +31 -0
- package/src/index.ts +87 -0
- package/src/utils.ts +35 -0
- package/wit/druid-component.wit +16 -0
- package/wit/druid-ui.wit +37 -0
package/bin/gen-types.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/gen-types.ts
|
|
4
|
+
import { generateTypes } from "@bytecodealliance/jco/component";
|
|
5
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
6
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
7
|
+
|
|
8
|
+
// src/utils.ts
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import fsSync from "node:fs";
|
|
11
|
+
import fs from "node:fs/promises";
|
|
12
|
+
import { resolve, basename } from "node:path";
|
|
13
|
+
function getPackageJsonPath(startDir = import.meta.dirname) {
|
|
14
|
+
let dir = startDir;
|
|
15
|
+
while (dir !== path.parse(dir).root) {
|
|
16
|
+
const pkgJson = path.join(dir, "package.json");
|
|
17
|
+
if (fsSync.existsSync(pkgJson)) return dir;
|
|
18
|
+
dir = path.dirname(dir);
|
|
19
|
+
}
|
|
20
|
+
throw new Error("package.json not found");
|
|
21
|
+
}
|
|
22
|
+
async function getWitFolder(withFiles, witPath2 = "wit-out") {
|
|
23
|
+
await fs.mkdir(witPath2, { recursive: true });
|
|
24
|
+
const baseWitPath = getPackageJsonPath();
|
|
25
|
+
const witFiles = await fs.readdir(resolve(baseWitPath, "wit"));
|
|
26
|
+
for (const file of witFiles) {
|
|
27
|
+
await fs.copyFile(
|
|
28
|
+
resolve(baseWitPath, "wit", file),
|
|
29
|
+
resolve(witPath2, file)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
for (const file of withFiles || []) {
|
|
33
|
+
const filename = basename(file);
|
|
34
|
+
await fs.copyFile(file, resolve(witPath2, filename));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/gen-types.ts
|
|
39
|
+
async function genTypes(withFiles, worldName2 = "druid-ui", typePath = "types", witPath2 = "wit-out") {
|
|
40
|
+
await getWitFolder(withFiles, witPath2);
|
|
41
|
+
const t = await generateTypes(worldName2, {
|
|
42
|
+
wit: {
|
|
43
|
+
tag: "path",
|
|
44
|
+
val: resolve2(witPath2)
|
|
45
|
+
},
|
|
46
|
+
world: worldName2,
|
|
47
|
+
instantiation: {
|
|
48
|
+
tag: "async"
|
|
49
|
+
},
|
|
50
|
+
guest: true
|
|
51
|
+
});
|
|
52
|
+
for (const [filename, contents] of t) {
|
|
53
|
+
console.log("Writing generated type:", typePath + "/" + filename);
|
|
54
|
+
await mkdir(resolve2(typePath, dirname(filename)), { recursive: true });
|
|
55
|
+
await writeFile(resolve2(typePath, filename), contents);
|
|
56
|
+
}
|
|
57
|
+
await rm(witPath2, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/cmd/gen-types.ts
|
|
61
|
+
var args = process.argv.slice(2);
|
|
62
|
+
var witPath;
|
|
63
|
+
var outDir;
|
|
64
|
+
var additionalFiles = [];
|
|
65
|
+
args = args.filter((arg) => {
|
|
66
|
+
if (arg.startsWith("--temp-wit-path=")) {
|
|
67
|
+
witPath = arg.slice(16);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
if (arg.startsWith("--out-dir=")) {
|
|
71
|
+
outDir = arg.slice(10);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
});
|
|
76
|
+
if (args.length < 1) {
|
|
77
|
+
console.error(
|
|
78
|
+
"Usage: gen-types <world-name> [additional-wit-files...] [--wit-path=<path>] [--out-dir=<path>]"
|
|
79
|
+
);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
var worldName = args[0];
|
|
83
|
+
additionalFiles.push(...args.slice(1));
|
|
84
|
+
await genTypes(additionalFiles, worldName, outDir, witPath);
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { componentize } from "@bytecodealliance/componentize-js";
|
|
5
|
+
import { build } from "esbuild";
|
|
6
|
+
import fs3 from "node:fs/promises";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
9
|
+
import { basename as basename2 } from "node:path";
|
|
10
|
+
|
|
11
|
+
// src/utils.ts
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import fsSync from "node:fs";
|
|
14
|
+
import fs from "node:fs/promises";
|
|
15
|
+
import { resolve, basename } from "node:path";
|
|
16
|
+
function getPackageJsonPath(startDir = import.meta.dirname) {
|
|
17
|
+
let dir = startDir;
|
|
18
|
+
while (dir !== path.parse(dir).root) {
|
|
19
|
+
const pkgJson = path.join(dir, "package.json");
|
|
20
|
+
if (fsSync.existsSync(pkgJson)) return dir;
|
|
21
|
+
dir = path.dirname(dir);
|
|
22
|
+
}
|
|
23
|
+
throw new Error("package.json not found");
|
|
24
|
+
}
|
|
25
|
+
async function getWitFolder(withFiles, witPath = "wit-out") {
|
|
26
|
+
await fs.mkdir(witPath, { recursive: true });
|
|
27
|
+
const baseWitPath = getPackageJsonPath();
|
|
28
|
+
const witFiles2 = await fs.readdir(resolve(baseWitPath, "wit"));
|
|
29
|
+
for (const file of witFiles2) {
|
|
30
|
+
await fs.copyFile(
|
|
31
|
+
resolve(baseWitPath, "wit", file),
|
|
32
|
+
resolve(witPath, file)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
for (const file of withFiles || []) {
|
|
36
|
+
const filename = basename(file);
|
|
37
|
+
await fs.copyFile(file, resolve(witPath, filename));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/esbuild-plugin.ts
|
|
42
|
+
import fs2 from "fs/promises";
|
|
43
|
+
function druidExtensionPlugin() {
|
|
44
|
+
return {
|
|
45
|
+
name: "druid-extension",
|
|
46
|
+
setup(build2) {
|
|
47
|
+
build2.onLoad({ filter: /\.[jt]sx?$/ }, async (args2) => {
|
|
48
|
+
let code = await fs2.readFile(args2.path, "utf8");
|
|
49
|
+
if (!code.includes("druid:ui/")) return;
|
|
50
|
+
const transformNamed = (_, vars, name) => {
|
|
51
|
+
const mapped = vars.split(",").map((v) => {
|
|
52
|
+
const [left, right] = v.split(/\s+as\s+/).map((s) => s.trim());
|
|
53
|
+
return right ? `${left}: ${right}` : left;
|
|
54
|
+
}).join(", ");
|
|
55
|
+
return `const { ${mapped} } = window["druid-extension"]["${name}"];`;
|
|
56
|
+
};
|
|
57
|
+
code = code.replace(
|
|
58
|
+
/import\s*{\s*([^}]+)\s*}\s*from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
59
|
+
transformNamed
|
|
60
|
+
).replace(
|
|
61
|
+
/import\s+\*\s+as\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
62
|
+
(_, id, name) => `const ${id} = window["druid-extension"]["${name}"];`
|
|
63
|
+
).replace(
|
|
64
|
+
/import\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
65
|
+
(_, id, name) => `const ${id} = window["druid-extension"]["${name}"];`
|
|
66
|
+
);
|
|
67
|
+
let loader = "js";
|
|
68
|
+
if (args2.path.endsWith(".ts")) loader = "ts";
|
|
69
|
+
else if (args2.path.endsWith(".tsx")) loader = "tsx";
|
|
70
|
+
else if (args2.path.endsWith(".jsx")) loader = "jsx";
|
|
71
|
+
return { contents: code, loader };
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/gen-types.ts
|
|
78
|
+
import { generateTypes } from "@bytecodealliance/jco/component";
|
|
79
|
+
|
|
80
|
+
// src/index.ts
|
|
81
|
+
var require2 = createRequire(import.meta.url);
|
|
82
|
+
var getBundleFileName = (entryFile2) => {
|
|
83
|
+
const name = basename2(entryFile2, ".tsx");
|
|
84
|
+
const outfilename = name + ".bundled.js";
|
|
85
|
+
return outfilename;
|
|
86
|
+
};
|
|
87
|
+
async function buildWasm(entryFile2, outfolder2 = "./dist", witExtension) {
|
|
88
|
+
await fs3.mkdir(outfolder2, { recursive: true });
|
|
89
|
+
const outfilename = getBundleFileName(entryFile2);
|
|
90
|
+
const outfile = outfolder2 + "/" + outfilename;
|
|
91
|
+
console.log("Building", entryFile2, "to", outfile);
|
|
92
|
+
await build({
|
|
93
|
+
entryPoints: [entryFile2],
|
|
94
|
+
bundle: true,
|
|
95
|
+
write: true,
|
|
96
|
+
format: "esm",
|
|
97
|
+
outfile,
|
|
98
|
+
external: ["druid:ui/*"]
|
|
99
|
+
});
|
|
100
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
101
|
+
let witDist = outfolder2 + "/wit";
|
|
102
|
+
if (witExtension?.files?.length) {
|
|
103
|
+
await getWitFolder(witExtension.files, witDist);
|
|
104
|
+
} else {
|
|
105
|
+
witDist = getPackageJsonPath() + "/wit";
|
|
106
|
+
}
|
|
107
|
+
console.log("Generating WIT to", witDist);
|
|
108
|
+
const result = await componentize({
|
|
109
|
+
witPath: witDist,
|
|
110
|
+
worldName: witExtension?.worldName || "druid-ui",
|
|
111
|
+
sourcePath: outfile,
|
|
112
|
+
disableFeatures: ["clocks", "http", "random", "stdio", "fetch-event"]
|
|
113
|
+
});
|
|
114
|
+
const name = basename2(entryFile2, ".tsx");
|
|
115
|
+
await fs3.writeFile(outfolder2 + "/" + name + ".wasm", result.component);
|
|
116
|
+
}
|
|
117
|
+
async function buildRaw(entryFile2, outfolder2 = "./dist") {
|
|
118
|
+
const outfilename = getBundleFileName(entryFile2);
|
|
119
|
+
const outfile = outfolder2 + "/" + outfilename;
|
|
120
|
+
const rawPath = require2.resolve("@druid-ui/component/raw");
|
|
121
|
+
await build({
|
|
122
|
+
entryPoints: [entryFile2],
|
|
123
|
+
bundle: true,
|
|
124
|
+
write: true,
|
|
125
|
+
format: "esm",
|
|
126
|
+
outfile,
|
|
127
|
+
plugins: [druidExtensionPlugin()],
|
|
128
|
+
alias: {
|
|
129
|
+
"@druid-ui/component": rawPath
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/cmd/index.ts
|
|
135
|
+
console.log("Druid UI Build Tool");
|
|
136
|
+
var args = process.argv;
|
|
137
|
+
var duBuildRaw = false;
|
|
138
|
+
var worldName = "druid-ui";
|
|
139
|
+
var witFiles = [];
|
|
140
|
+
args = args.filter((arg) => {
|
|
141
|
+
if (arg === "--raw") {
|
|
142
|
+
duBuildRaw = true;
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if (arg.startsWith("--wit=")) {
|
|
146
|
+
witFiles.push(arg.slice(6));
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (arg.startsWith("--world-name=")) {
|
|
150
|
+
worldName = arg.slice(13);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
155
|
+
var entryFile = args[2];
|
|
156
|
+
if (!entryFile) {
|
|
157
|
+
console.error(
|
|
158
|
+
"Usage: ./cli <entry-file> [out-folder] [--world-name=<name>] [--wit=<file>] [--raw]"
|
|
159
|
+
);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
var outfolder = args[3] || "./dist";
|
|
163
|
+
console.log(`Building ${entryFile} to ${outfolder}...`);
|
|
164
|
+
if (duBuildRaw) {
|
|
165
|
+
await buildRaw(entryFile, outfolder);
|
|
166
|
+
} else {
|
|
167
|
+
await buildWasm(entryFile, outfolder, {
|
|
168
|
+
worldName,
|
|
169
|
+
files: witFiles
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
console.log("Build complete.");
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { componentize } from "@bytecodealliance/componentize-js";
|
|
3
|
+
import { build } from "esbuild";
|
|
4
|
+
import fs3 from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { basename as basename2 } from "node:path";
|
|
8
|
+
|
|
9
|
+
// src/utils.ts
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import fsSync from "node:fs";
|
|
12
|
+
import fs from "node:fs/promises";
|
|
13
|
+
import { resolve, basename } from "node:path";
|
|
14
|
+
function getPackageJsonPath(startDir = import.meta.dirname) {
|
|
15
|
+
let dir = startDir;
|
|
16
|
+
while (dir !== path.parse(dir).root) {
|
|
17
|
+
const pkgJson = path.join(dir, "package.json");
|
|
18
|
+
if (fsSync.existsSync(pkgJson)) return dir;
|
|
19
|
+
dir = path.dirname(dir);
|
|
20
|
+
}
|
|
21
|
+
throw new Error("package.json not found");
|
|
22
|
+
}
|
|
23
|
+
async function getWitFolder(withFiles, witPath = "wit-out") {
|
|
24
|
+
await fs.mkdir(witPath, { recursive: true });
|
|
25
|
+
const baseWitPath = getPackageJsonPath();
|
|
26
|
+
const witFiles = await fs.readdir(resolve(baseWitPath, "wit"));
|
|
27
|
+
for (const file of witFiles) {
|
|
28
|
+
await fs.copyFile(
|
|
29
|
+
resolve(baseWitPath, "wit", file),
|
|
30
|
+
resolve(witPath, file)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
for (const file of withFiles || []) {
|
|
34
|
+
const filename = basename(file);
|
|
35
|
+
await fs.copyFile(file, resolve(witPath, filename));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/esbuild-plugin.ts
|
|
40
|
+
import fs2 from "fs/promises";
|
|
41
|
+
function druidExtensionPlugin() {
|
|
42
|
+
return {
|
|
43
|
+
name: "druid-extension",
|
|
44
|
+
setup(build2) {
|
|
45
|
+
build2.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
|
|
46
|
+
let code = await fs2.readFile(args.path, "utf8");
|
|
47
|
+
if (!code.includes("druid:ui/")) return;
|
|
48
|
+
const transformNamed = (_, vars, name) => {
|
|
49
|
+
const mapped = vars.split(",").map((v) => {
|
|
50
|
+
const [left, right] = v.split(/\s+as\s+/).map((s) => s.trim());
|
|
51
|
+
return right ? `${left}: ${right}` : left;
|
|
52
|
+
}).join(", ");
|
|
53
|
+
return `const { ${mapped} } = window["druid-extension"]["${name}"];`;
|
|
54
|
+
};
|
|
55
|
+
code = code.replace(
|
|
56
|
+
/import\s*{\s*([^}]+)\s*}\s*from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
57
|
+
transformNamed
|
|
58
|
+
).replace(
|
|
59
|
+
/import\s+\*\s+as\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
60
|
+
(_, id, name) => `const ${id} = window["druid-extension"]["${name}"];`
|
|
61
|
+
).replace(
|
|
62
|
+
/import\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
63
|
+
(_, id, name) => `const ${id} = window["druid-extension"]["${name}"];`
|
|
64
|
+
);
|
|
65
|
+
let loader = "js";
|
|
66
|
+
if (args.path.endsWith(".ts")) loader = "ts";
|
|
67
|
+
else if (args.path.endsWith(".tsx")) loader = "tsx";
|
|
68
|
+
else if (args.path.endsWith(".jsx")) loader = "jsx";
|
|
69
|
+
return { contents: code, loader };
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/gen-types.ts
|
|
76
|
+
import { generateTypes } from "@bytecodealliance/jco/component";
|
|
77
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
78
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
79
|
+
async function genTypes(withFiles, worldName = "druid-ui", typePath = "types", witPath = "wit-out") {
|
|
80
|
+
await getWitFolder(withFiles, witPath);
|
|
81
|
+
const t = await generateTypes(worldName, {
|
|
82
|
+
wit: {
|
|
83
|
+
tag: "path",
|
|
84
|
+
val: resolve2(witPath)
|
|
85
|
+
},
|
|
86
|
+
world: worldName,
|
|
87
|
+
instantiation: {
|
|
88
|
+
tag: "async"
|
|
89
|
+
},
|
|
90
|
+
guest: true
|
|
91
|
+
});
|
|
92
|
+
for (const [filename, contents] of t) {
|
|
93
|
+
console.log("Writing generated type:", typePath + "/" + filename);
|
|
94
|
+
await mkdir(resolve2(typePath, dirname(filename)), { recursive: true });
|
|
95
|
+
await writeFile(resolve2(typePath, filename), contents);
|
|
96
|
+
}
|
|
97
|
+
await rm(witPath, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/index.ts
|
|
101
|
+
var require2 = createRequire(import.meta.url);
|
|
102
|
+
var getBundleFileName = (entryFile) => {
|
|
103
|
+
const name = basename2(entryFile, ".tsx");
|
|
104
|
+
const outfilename = name + ".bundled.js";
|
|
105
|
+
return outfilename;
|
|
106
|
+
};
|
|
107
|
+
async function buildWasm(entryFile, outfolder = "./dist", witExtension) {
|
|
108
|
+
await fs3.mkdir(outfolder, { recursive: true });
|
|
109
|
+
const outfilename = getBundleFileName(entryFile);
|
|
110
|
+
const outfile = outfolder + "/" + outfilename;
|
|
111
|
+
console.log("Building", entryFile, "to", outfile);
|
|
112
|
+
await build({
|
|
113
|
+
entryPoints: [entryFile],
|
|
114
|
+
bundle: true,
|
|
115
|
+
write: true,
|
|
116
|
+
format: "esm",
|
|
117
|
+
outfile,
|
|
118
|
+
external: ["druid:ui/*"]
|
|
119
|
+
});
|
|
120
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
121
|
+
let witDist = outfolder + "/wit";
|
|
122
|
+
if (witExtension?.files?.length) {
|
|
123
|
+
await getWitFolder(witExtension.files, witDist);
|
|
124
|
+
} else {
|
|
125
|
+
witDist = getPackageJsonPath() + "/wit";
|
|
126
|
+
}
|
|
127
|
+
console.log("Generating WIT to", witDist);
|
|
128
|
+
const result = await componentize({
|
|
129
|
+
witPath: witDist,
|
|
130
|
+
worldName: witExtension?.worldName || "druid-ui",
|
|
131
|
+
sourcePath: outfile,
|
|
132
|
+
disableFeatures: ["clocks", "http", "random", "stdio", "fetch-event"]
|
|
133
|
+
});
|
|
134
|
+
const name = basename2(entryFile, ".tsx");
|
|
135
|
+
await fs3.writeFile(outfolder + "/" + name + ".wasm", result.component);
|
|
136
|
+
}
|
|
137
|
+
async function buildRaw(entryFile, outfolder = "./dist") {
|
|
138
|
+
const outfilename = getBundleFileName(entryFile);
|
|
139
|
+
const outfile = outfolder + "/" + outfilename;
|
|
140
|
+
const rawPath = require2.resolve("@druid-ui/component/raw");
|
|
141
|
+
await build({
|
|
142
|
+
entryPoints: [entryFile],
|
|
143
|
+
bundle: true,
|
|
144
|
+
write: true,
|
|
145
|
+
format: "esm",
|
|
146
|
+
outfile,
|
|
147
|
+
plugins: [druidExtensionPlugin()],
|
|
148
|
+
alias: {
|
|
149
|
+
"@druid-ui/component": rawPath
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
buildRaw,
|
|
155
|
+
buildWasm,
|
|
156
|
+
genTypes
|
|
157
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gen-types.d.ts","sourceRoot":"","sources":["../../../src/cmd/gen-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmd/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"esbuild-plugin.d.ts","sourceRoot":"","sources":["../../src/esbuild-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGtC,wBAAgB,oBAAoB,IAAI,MAAM,CAgD7C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gen-types.d.ts","sourceRoot":"","sources":["../../src/gen-types.ts"],"names":[],"mappings":"AAKA,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,SAAa,EACtB,QAAQ,SAAU,EAClB,OAAO,SAAY,iBAqBpB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface WitExtension {
|
|
2
|
+
worldName: string;
|
|
3
|
+
files: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare function buildWasm(entryFile: any, outfolder?: string, witExtension?: WitExtension): Promise<void>;
|
|
6
|
+
export declare function buildRaw(entryFile: any, outfolder?: string): Promise<void>;
|
|
7
|
+
export * from "./gen-types";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AASD,wBAAsB,SAAS,CAC7B,SAAS,KAAA,EACT,SAAS,SAAW,EACpB,YAAY,CAAC,EAAE,YAAY,iBAsC5B;AAED,wBAAsB,QAAQ,CAAC,SAAS,KAAA,EAAE,SAAS,SAAW,iBAiB7D;AAED,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,MAA4B,GACrC,MAAM,CAQR;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,SAAY,iBAiB1E"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@druid-ui/build",
|
|
3
|
+
"version": "1.0.0-next.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/types/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"druid-ui-build": "./bin/index.js",
|
|
9
|
+
"druid-ui-gen-types": "./bin/gen-types.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"bin",
|
|
20
|
+
"wit",
|
|
21
|
+
"src"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "npm run build:lib && npm run build:cli && npm run build:cli-types && npm run build:types && npm rebuild --ignore-scripts @druid-ui/build",
|
|
25
|
+
"build:lib": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/index.js --external:@bytecodealliance/jco --external:esbuild --external:@bytecodealliance/componentize-js --external:@druid-ui/component",
|
|
26
|
+
"build:cli": "esbuild src/cmd/index.ts --bundle --platform=node --format=esm --target=node22 --outfile=bin/index.js --external:@bytecodealliance/jco --external:esbuild --external:@bytecodealliance/componentize-js --external:@druid-ui/component",
|
|
27
|
+
"build:cli-types": "esbuild src/cmd/gen-types.ts --bundle --platform=node --format=esm --target=node22 --outfile=bin/gen-types.js --external:@bytecodealliance/jco --external:esbuild --external:@bytecodealliance/componentize-js",
|
|
28
|
+
"build:types": "tsc --emitDeclarationOnly --outDir dist/types"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@bytecodealliance/componentize-js": "^0.19.3",
|
|
32
|
+
"@bytecodealliance/jco": "^1.15.3",
|
|
33
|
+
"@bytecodealliance/preview2-shim": "^0.17.5",
|
|
34
|
+
"esbuild": "^0.25.11"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"typescript": "~5.8.3"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { genTypes } from "../gen-types";
|
|
3
|
+
|
|
4
|
+
// Expected signature: genTypes(withFiles: string[], worldName: string, typePath: string, witPath: string)
|
|
5
|
+
// CLI usage: gen-types <world-name> [additional-wit-files...] [--wit-path=<path>] [--out-dir=<path>]
|
|
6
|
+
// <world-name>: WIT world name to generate types for
|
|
7
|
+
// [additional-wit-files...]: optional extra WIT files to include alongside built-ins
|
|
8
|
+
// [--wit-path=<path>]: directory to copy built-in WIT definitions into (default: "wit-out")
|
|
9
|
+
// [--out-dir=<path>]: output directory for generated TypeScript types (default: "types")
|
|
10
|
+
|
|
11
|
+
let args = process.argv.slice(2);
|
|
12
|
+
let witPath: string | undefined;
|
|
13
|
+
let outDir: string | undefined;
|
|
14
|
+
const additionalFiles: string[] = [];
|
|
15
|
+
|
|
16
|
+
args = args.filter((arg) => {
|
|
17
|
+
if (arg.startsWith("--temp-wit-path=")) {
|
|
18
|
+
witPath = arg.slice(16);
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (arg.startsWith("--out-dir=")) {
|
|
22
|
+
outDir = arg.slice(10);
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (args.length < 1) {
|
|
29
|
+
console.error(
|
|
30
|
+
"Usage: gen-types <world-name> [additional-wit-files...] [--wit-path=<path>] [--out-dir=<path>]",
|
|
31
|
+
);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Non-null assertion safe due to length check above
|
|
36
|
+
const worldName = args[0]!;
|
|
37
|
+
additionalFiles.push(...args.slice(1));
|
|
38
|
+
|
|
39
|
+
await genTypes(additionalFiles, worldName, outDir, witPath);
|
package/src/cmd/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { buildWasm, buildRaw } from "../";
|
|
4
|
+
console.log("Druid UI Build Tool");
|
|
5
|
+
let args = process.argv;
|
|
6
|
+
|
|
7
|
+
let duBuildRaw = false;
|
|
8
|
+
let worldName = "druid-ui";
|
|
9
|
+
const witFiles: string[] = [];
|
|
10
|
+
|
|
11
|
+
args = args.filter((arg) => {
|
|
12
|
+
if (arg === "--raw") {
|
|
13
|
+
duBuildRaw = true;
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (arg.startsWith("--wit=")) {
|
|
17
|
+
witFiles.push(arg.slice(6));
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (arg.startsWith("--world-name=")) {
|
|
21
|
+
worldName = arg.slice(13);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const entryFile = args[2];
|
|
28
|
+
|
|
29
|
+
if (!entryFile) {
|
|
30
|
+
console.error(
|
|
31
|
+
"Usage: ./cli <entry-file> [out-folder] [--world-name=<name>] [--wit=<file>] [--raw]",
|
|
32
|
+
);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const outfolder = args[3] || "./dist";
|
|
37
|
+
console.log(`Building ${entryFile} to ${outfolder}...`);
|
|
38
|
+
if (duBuildRaw) {
|
|
39
|
+
await buildRaw(entryFile, outfolder);
|
|
40
|
+
} else {
|
|
41
|
+
await buildWasm(entryFile, outfolder, {
|
|
42
|
+
worldName,
|
|
43
|
+
files: witFiles,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log("Build complete.");
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Plugin } from "esbuild";
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
|
|
4
|
+
export function druidExtensionPlugin(): Plugin {
|
|
5
|
+
return {
|
|
6
|
+
name: "druid-extension",
|
|
7
|
+
setup(build) {
|
|
8
|
+
build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
|
|
9
|
+
let code = await fs.readFile(args.path, "utf8");
|
|
10
|
+
if (!code.includes("druid:ui/")) return;
|
|
11
|
+
|
|
12
|
+
const transformNamed = (_: string, vars: string, name: string) => {
|
|
13
|
+
const mapped = vars
|
|
14
|
+
.split(",")
|
|
15
|
+
.map((v) => {
|
|
16
|
+
const [left, right] = v.split(/\s+as\s+/).map((s) => s.trim());
|
|
17
|
+
return right ? `${left}: ${right}` : left;
|
|
18
|
+
})
|
|
19
|
+
.join(", ");
|
|
20
|
+
return `const { ${mapped} } = window["druid-extension"]["${name}"];`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
code = code
|
|
24
|
+
// named imports
|
|
25
|
+
.replace(
|
|
26
|
+
/import\s*{\s*([^}]+)\s*}\s*from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
27
|
+
transformNamed
|
|
28
|
+
)
|
|
29
|
+
// namespace imports
|
|
30
|
+
.replace(
|
|
31
|
+
/import\s+\*\s+as\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
32
|
+
(_, id: string, name: string) =>
|
|
33
|
+
`const ${id} = window["druid-extension"]["${name}"];`
|
|
34
|
+
)
|
|
35
|
+
// default imports
|
|
36
|
+
.replace(
|
|
37
|
+
/import\s+([\w$]+)\s+from\s*["'](druid:ui\/[^"']+)["'];?/g,
|
|
38
|
+
(_, id: string, name: string) =>
|
|
39
|
+
`const ${id} = window["druid-extension"]["${name}"];`
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// choose loader based on file extension
|
|
43
|
+
let loader: "ts" | "tsx" | "js" | "jsx" = "js";
|
|
44
|
+
if (args.path.endsWith(".ts")) loader = "ts";
|
|
45
|
+
else if (args.path.endsWith(".tsx")) loader = "tsx";
|
|
46
|
+
else if (args.path.endsWith(".jsx")) loader = "jsx";
|
|
47
|
+
|
|
48
|
+
return { contents: code, loader };
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
package/src/gen-types.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { generateTypes } from "@bytecodealliance/jco/component";
|
|
2
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
3
|
+
import { dirname, resolve } from "path";
|
|
4
|
+
import { getWitFolder } from "./utils";
|
|
5
|
+
|
|
6
|
+
export async function genTypes(
|
|
7
|
+
withFiles: string[],
|
|
8
|
+
worldName = "druid-ui",
|
|
9
|
+
typePath = "types",
|
|
10
|
+
witPath = "wit-out"
|
|
11
|
+
) {
|
|
12
|
+
await getWitFolder(withFiles, witPath);
|
|
13
|
+
const t = await generateTypes(worldName, {
|
|
14
|
+
wit: {
|
|
15
|
+
tag: "path",
|
|
16
|
+
val: resolve(witPath),
|
|
17
|
+
},
|
|
18
|
+
world: worldName,
|
|
19
|
+
instantiation: {
|
|
20
|
+
tag: "async",
|
|
21
|
+
},
|
|
22
|
+
guest: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
for (const [filename, contents] of t) {
|
|
26
|
+
console.log("Writing generated type:", typePath + "/" + filename);
|
|
27
|
+
await mkdir(resolve(typePath, dirname(filename)), { recursive: true });
|
|
28
|
+
await writeFile(resolve(typePath, filename), contents);
|
|
29
|
+
}
|
|
30
|
+
await rm(witPath, { recursive: true });
|
|
31
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { componentize } from "@bytecodealliance/componentize-js";
|
|
3
|
+
import { build } from "esbuild";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { dirname, basename } from "node:path";
|
|
8
|
+
import { getPackageJsonPath, getWitFolder } from "./utils";
|
|
9
|
+
import { druidExtensionPlugin } from "./esbuild-plugin";
|
|
10
|
+
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
|
|
13
|
+
export interface WitExtension {
|
|
14
|
+
worldName: string;
|
|
15
|
+
files: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getBundleFileName = (entryFile) => {
|
|
19
|
+
const name = basename(entryFile, ".tsx");
|
|
20
|
+
|
|
21
|
+
const outfilename = name + ".bundled.js";
|
|
22
|
+
return outfilename;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export async function buildWasm(
|
|
26
|
+
entryFile,
|
|
27
|
+
outfolder = "./dist",
|
|
28
|
+
witExtension?: WitExtension
|
|
29
|
+
) {
|
|
30
|
+
await fs.mkdir(outfolder, { recursive: true });
|
|
31
|
+
|
|
32
|
+
const outfilename = getBundleFileName(entryFile);
|
|
33
|
+
|
|
34
|
+
const outfile = outfolder + "/" + outfilename;
|
|
35
|
+
console.log("Building", entryFile, "to", outfile);
|
|
36
|
+
await build({
|
|
37
|
+
entryPoints: [entryFile],
|
|
38
|
+
bundle: true,
|
|
39
|
+
write: true,
|
|
40
|
+
format: "esm",
|
|
41
|
+
outfile: outfile,
|
|
42
|
+
external: ["druid:ui/*"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
46
|
+
|
|
47
|
+
let witDist = outfolder + "/wit";
|
|
48
|
+
|
|
49
|
+
//if we want to extend, we need to copy the wit files into a unified folder
|
|
50
|
+
if (witExtension?.files?.length) {
|
|
51
|
+
await getWitFolder(witExtension.files, witDist);
|
|
52
|
+
} else {
|
|
53
|
+
witDist = getPackageJsonPath() + "/wit";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log("Generating WIT to", witDist);
|
|
57
|
+
const result = await componentize({
|
|
58
|
+
witPath: witDist,
|
|
59
|
+
worldName: witExtension?.worldName || "druid-ui",
|
|
60
|
+
sourcePath: outfile,
|
|
61
|
+
disableFeatures: ["clocks", "http", "random", "stdio", "fetch-event"],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const name = basename(entryFile, ".tsx");
|
|
65
|
+
await fs.writeFile(outfolder + "/" + name + ".wasm", result.component);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function buildRaw(entryFile, outfolder = "./dist") {
|
|
69
|
+
const outfilename = getBundleFileName(entryFile);
|
|
70
|
+
|
|
71
|
+
const outfile = outfolder + "/" + outfilename;
|
|
72
|
+
|
|
73
|
+
const rawPath = require.resolve("@druid-ui/component/raw");
|
|
74
|
+
await build({
|
|
75
|
+
entryPoints: [entryFile],
|
|
76
|
+
bundle: true,
|
|
77
|
+
write: true,
|
|
78
|
+
format: "esm",
|
|
79
|
+
outfile: outfile,
|
|
80
|
+
plugins: [druidExtensionPlugin()],
|
|
81
|
+
alias: {
|
|
82
|
+
"@druid-ui/component": rawPath,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export * from "./gen-types";
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fsSync from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { resolve, basename } from "node:path";
|
|
5
|
+
|
|
6
|
+
export function getPackageJsonPath(
|
|
7
|
+
startDir: string = import.meta.dirname
|
|
8
|
+
): string {
|
|
9
|
+
let dir = startDir;
|
|
10
|
+
while (dir !== path.parse(dir).root) {
|
|
11
|
+
const pkgJson = path.join(dir, "package.json");
|
|
12
|
+
if (fsSync.existsSync(pkgJson)) return dir;
|
|
13
|
+
dir = path.dirname(dir);
|
|
14
|
+
}
|
|
15
|
+
throw new Error("package.json not found");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function getWitFolder(withFiles: string[], witPath = "wit-out") {
|
|
19
|
+
//create outfolder/wit
|
|
20
|
+
await fs.mkdir(witPath, { recursive: true });
|
|
21
|
+
|
|
22
|
+
const baseWitPath = getPackageJsonPath();
|
|
23
|
+
|
|
24
|
+
const witFiles = await fs.readdir(resolve(baseWitPath, "wit"));
|
|
25
|
+
for (const file of witFiles) {
|
|
26
|
+
await fs.copyFile(
|
|
27
|
+
resolve(baseWitPath, "wit", file),
|
|
28
|
+
resolve(witPath, file)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
for (const file of withFiles || []) {
|
|
32
|
+
const filename = basename(file);
|
|
33
|
+
await fs.copyFile(file, resolve(witPath, filename));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package druid:ui;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
interface component {
|
|
5
|
+
use utils.{event, context};
|
|
6
|
+
|
|
7
|
+
init: func(ctx: context) -> string;
|
|
8
|
+
emit: func(nodeid: string, event: string, e: event);
|
|
9
|
+
async-complete: func(id: string, value: result<string>);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
world druid-ui {
|
|
14
|
+
import ui;
|
|
15
|
+
export component;
|
|
16
|
+
}
|
package/wit/druid-ui.wit
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package druid:ui;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
interface ui {
|
|
5
|
+
|
|
6
|
+
record prop { key: string, value: string, }
|
|
7
|
+
|
|
8
|
+
record props {
|
|
9
|
+
prop: list<prop>,
|
|
10
|
+
on: list<string>,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type async-id = string;
|
|
14
|
+
|
|
15
|
+
type children = option<list<string>>;
|
|
16
|
+
|
|
17
|
+
d: func(element: string, props: props, children: children) -> string;
|
|
18
|
+
log: func(msg: string);
|
|
19
|
+
set-hook: func(id: async-id, hook: string);
|
|
20
|
+
rerender: func();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface utils {
|
|
24
|
+
|
|
25
|
+
resource event {
|
|
26
|
+
constructor(value: string, checked: bool);
|
|
27
|
+
prevent-default: func();
|
|
28
|
+
stop-propagation: func();
|
|
29
|
+
value: func() -> string;
|
|
30
|
+
checked: func() -> bool;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
record context {
|
|
34
|
+
path: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
}
|