@tgrv/void-cli 1.1.0 → 1.1.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/void.js +179 -37
- package/package.json +1 -1
- package/templates/cpp/CMakeLists.txt +27 -0
- package/templates/cpp/README.md +57 -0
- package/templates/cpp/package.json +14 -0
- package/templates/cpp/src/plugin.cpp +17 -0
- package/templates/cpp/types.d.ts +7 -0
- package/templates/cpp/void.json +15 -0
- package/templates/go/README.md +1 -1
- package/templates/rust/README.md +1 -1
package/bin/void.js
CHANGED
|
@@ -72,6 +72,14 @@ function ensureDir(dir) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function toJsFriendlyName(name) {
|
|
76
|
+
let clean = name.includes('/') ? name.split('/').pop() : name;
|
|
77
|
+
clean = clean.replace(/^[^a-zA-Z_$]+|[^a-zA-Z0-9_$]+$/g, '');
|
|
78
|
+
return clean.replace(/[-_]([a-z0-9])/gi, (match, group1) => {
|
|
79
|
+
return group1.toUpperCase();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
75
83
|
function copyFolderRecursive(src, dest, replacements = {}) {
|
|
76
84
|
ensureDir(dest);
|
|
77
85
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
@@ -100,44 +108,44 @@ function copyFolderRecursive(src, dest, replacements = {}) {
|
|
|
100
108
|
}
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
111
|
+
function matchGlob(filePath, pattern) {
|
|
112
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
113
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
107
114
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
if (normalizedPath === normalizedPattern) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
const prefix = normalizedPattern.endsWith('/') ? normalizedPattern : normalizedPattern + '/';
|
|
119
|
+
if (normalizedPath.startsWith(prefix)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
111
122
|
|
|
112
|
-
|
|
123
|
+
const globToRegex = (glob) => {
|
|
124
|
+
return '^' + glob
|
|
125
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
126
|
+
.replace(/\*\*/g, '___DOUBLE_STAR___')
|
|
127
|
+
.replace(/\*/g, '___SINGLE_STAR___')
|
|
128
|
+
.replace(/\?/g, '___QUESTION___')
|
|
129
|
+
.replace(/___DOUBLE_STAR___/g, '.*')
|
|
130
|
+
.replace(/___SINGLE_STAR___/g, '[^/]*')
|
|
131
|
+
.replace(/___QUESTION___/g, '.') + '$';
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const regex = new RegExp(globToRegex(normalizedPattern));
|
|
135
|
+
|
|
136
|
+
if (!normalizedPattern.includes('/')) {
|
|
137
|
+
const baseName = path.basename(normalizedPath);
|
|
138
|
+
if (regex.test(baseName)) {
|
|
113
139
|
return true;
|
|
114
140
|
}
|
|
115
|
-
|
|
116
|
-
if (normalizedPath.startsWith(prefix)) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const globToRegex = (glob) => {
|
|
121
|
-
return '^' + glob
|
|
122
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
123
|
-
.replace(/\*\*/g, '___DOUBLE_STAR___')
|
|
124
|
-
.replace(/\*/g, '___SINGLE_STAR___')
|
|
125
|
-
.replace(/\?/g, '___QUESTION___')
|
|
126
|
-
.replace(/___DOUBLE_STAR___/g, '.*')
|
|
127
|
-
.replace(/___SINGLE_STAR___/g, '[^/]*')
|
|
128
|
-
.replace(/___QUESTION___/g, '.') + '$';
|
|
129
|
-
};
|
|
141
|
+
}
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (!normalizedPattern.includes('/')) {
|
|
134
|
-
const baseName = path.basename(normalizedPath);
|
|
135
|
-
if (regex.test(baseName)) {
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
143
|
+
return regex.test(normalizedPath);
|
|
144
|
+
}
|
|
139
145
|
|
|
140
|
-
|
|
146
|
+
function copyNonSourceFiles(src, dest, buildOutputDir, filesConfig, wasmFilename) {
|
|
147
|
+
if (!filesConfig || !Array.isArray(filesConfig) || filesConfig.length === 0) {
|
|
148
|
+
return;
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
function traverse(currentDir) {
|
|
@@ -178,6 +186,62 @@ function copyNonSourceFiles(src, dest, buildOutputDir, filesConfig, wasmFilename
|
|
|
178
186
|
traverse(src);
|
|
179
187
|
}
|
|
180
188
|
|
|
189
|
+
function cleanupOutputDirectory(pluginDir, buildOutputDir, filesConfig, wasmFilename, typesFilename) {
|
|
190
|
+
if (!fs.existsSync(buildOutputDir)) return;
|
|
191
|
+
|
|
192
|
+
function traverse(currentDir) {
|
|
193
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
196
|
+
const relativePath = path.relative(buildOutputDir, fullPath);
|
|
197
|
+
|
|
198
|
+
if (entry.isDirectory()) {
|
|
199
|
+
traverse(fullPath);
|
|
200
|
+
// Clean up empty directories
|
|
201
|
+
if (fs.readdirSync(fullPath).length === 0) {
|
|
202
|
+
try {
|
|
203
|
+
fs.rmdirSync(fullPath);
|
|
204
|
+
} catch (e) {}
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
// Skip core files
|
|
208
|
+
if (entry.name === "index.js" ||
|
|
209
|
+
entry.name === "package.json" ||
|
|
210
|
+
entry.name === wasmFilename ||
|
|
211
|
+
(typesFilename && entry.name === typesFilename)) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Check if the file still exists in the source plugin root
|
|
216
|
+
const sourcePath = path.join(pluginDir, relativePath);
|
|
217
|
+
if (!fs.existsSync(sourcePath)) {
|
|
218
|
+
try {
|
|
219
|
+
fs.unlinkSync(fullPath);
|
|
220
|
+
} catch (e) {}
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check if the file still matches the files configuration
|
|
225
|
+
if (!filesConfig || !Array.isArray(filesConfig) || filesConfig.length === 0) {
|
|
226
|
+
try {
|
|
227
|
+
fs.unlinkSync(fullPath);
|
|
228
|
+
} catch (e) {}
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const matches = filesConfig.some(pattern => matchGlob(relativePath, pattern));
|
|
233
|
+
if (!matches) {
|
|
234
|
+
try {
|
|
235
|
+
fs.unlinkSync(fullPath);
|
|
236
|
+
} catch (e) {}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
traverse(buildOutputDir);
|
|
243
|
+
}
|
|
244
|
+
|
|
181
245
|
const args = process.argv.slice(2);
|
|
182
246
|
const command = args[0];
|
|
183
247
|
|
|
@@ -198,7 +262,7 @@ ${colors.bold}Usage:${colors.reset}
|
|
|
198
262
|
process.exit(0);
|
|
199
263
|
}
|
|
200
264
|
|
|
201
|
-
// Build core compilation wrapper
|
|
265
|
+
// Build core compilation wrapper
|
|
202
266
|
function runBuild(pluginPathArg) {
|
|
203
267
|
const absolutePluginDir = path.resolve(process.cwd(), pluginPathArg);
|
|
204
268
|
if (!fs.existsSync(absolutePluginDir)) {
|
|
@@ -238,7 +302,8 @@ function runBuild(pluginPathArg) {
|
|
|
238
302
|
const pluginType = manifest.type;
|
|
239
303
|
const buildDir = manifest.buildDir;
|
|
240
304
|
const buildOutputDir = path.join(absolutePluginDir, buildDir);
|
|
241
|
-
const
|
|
305
|
+
const rawExport = manifest.export || "plugin";
|
|
306
|
+
const exportName = toJsFriendlyName(rawExport);
|
|
242
307
|
const wasmFilename = `${exportName}.wasm`;
|
|
243
308
|
|
|
244
309
|
if (pluginType === "sdk") {
|
|
@@ -282,6 +347,45 @@ function runBuild(pluginPathArg) {
|
|
|
282
347
|
process.exit(1);
|
|
283
348
|
}
|
|
284
349
|
builtWasmPath = outputWasm;
|
|
350
|
+
}
|
|
351
|
+
// C++ plugin compilation
|
|
352
|
+
else if (pluginType === "cpp") {
|
|
353
|
+
console.log(`${info} Running: ${colors.blue}emcmake cmake -B build -DCMAKE_BUILD_TYPE=Release${colors.reset}`);
|
|
354
|
+
const configSuccess = runCommand("emcmake cmake -B build -DCMAKE_BUILD_TYPE=Release", { cwd: absolutePluginDir });
|
|
355
|
+
if (!configSuccess) {
|
|
356
|
+
console.error(`${cross} ${colors.red}Emscripten CMake configuration failed. Make sure emscripten SDK is active.${colors.reset}`);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
console.log(`${info} Running: ${colors.blue}cmake --build build --config Release${colors.reset}`);
|
|
361
|
+
const buildSuccess = runCommand("cmake --build build --config Release", { cwd: absolutePluginDir });
|
|
362
|
+
if (!buildSuccess) {
|
|
363
|
+
console.error(`${cross} ${colors.red}C++ compilation failed.${colors.reset}`);
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const buildPath = path.join(absolutePluginDir, "build");
|
|
368
|
+
function findWasm(dir) {
|
|
369
|
+
if (!fs.existsSync(dir)) return null;
|
|
370
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
371
|
+
for (const entry of entries) {
|
|
372
|
+
const fullPath = path.join(dir, entry.name);
|
|
373
|
+
if (entry.isDirectory()) {
|
|
374
|
+
const found = findWasm(fullPath);
|
|
375
|
+
if (found) return found;
|
|
376
|
+
} else if (entry.name.endsWith(".wasm")) {
|
|
377
|
+
return fullPath;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const wasmFile = findWasm(buildPath);
|
|
384
|
+
if (!wasmFile) {
|
|
385
|
+
console.error(`${cross} ${colors.red}Could not find compiled .wasm file in C++ build directory${colors.reset}`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
builtWasmPath = wasmFile;
|
|
285
389
|
} else {
|
|
286
390
|
console.error(`${cross} ${colors.red}Unsupported plugin type: '${pluginType}' in void.json${colors.reset}`);
|
|
287
391
|
process.exit(1);
|
|
@@ -290,6 +394,18 @@ function runBuild(pluginPathArg) {
|
|
|
290
394
|
console.log(`${info} Placing build output to local folder at ${colors.bold}${buildOutputDir}${colors.reset}...`);
|
|
291
395
|
ensureDir(buildOutputDir);
|
|
292
396
|
|
|
397
|
+
// Remove past builds' .wasm files from the build output directory
|
|
398
|
+
if (fs.existsSync(buildOutputDir)) {
|
|
399
|
+
const files = fs.readdirSync(buildOutputDir);
|
|
400
|
+
for (const file of files) {
|
|
401
|
+
if (file.endsWith(".wasm")) {
|
|
402
|
+
try {
|
|
403
|
+
fs.unlinkSync(path.join(buildOutputDir, file));
|
|
404
|
+
} catch (e) {}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
293
409
|
// Copy WASM
|
|
294
410
|
fs.copyFileSync(builtWasmPath, path.join(buildOutputDir, wasmFilename));
|
|
295
411
|
|
|
@@ -312,6 +428,7 @@ function runBuild(pluginPathArg) {
|
|
|
312
428
|
main: "index.js",
|
|
313
429
|
dependencies: {
|
|
314
430
|
"@tgrv/void-runtime": "^1.0.0",
|
|
431
|
+
...(manifest.dependencies || {})
|
|
315
432
|
},
|
|
316
433
|
publishConfig: {
|
|
317
434
|
access: "public"
|
|
@@ -334,6 +451,13 @@ function runBuild(pluginPathArg) {
|
|
|
334
451
|
existingPkg.types = manifest.types;
|
|
335
452
|
changed = true;
|
|
336
453
|
}
|
|
454
|
+
if (manifest.dependencies) {
|
|
455
|
+
existingPkg.dependencies = {
|
|
456
|
+
...existingPkg.dependencies,
|
|
457
|
+
...manifest.dependencies
|
|
458
|
+
};
|
|
459
|
+
changed = true;
|
|
460
|
+
}
|
|
337
461
|
if (changed) {
|
|
338
462
|
fs.writeFileSync(packageJsonPath, JSON.stringify(existingPkg, null, 2));
|
|
339
463
|
}
|
|
@@ -366,6 +490,7 @@ export default ${exportName};
|
|
|
366
490
|
`;
|
|
367
491
|
fs.writeFileSync(path.join(buildOutputDir, "index.js"), indexJsContent);
|
|
368
492
|
copyNonSourceFiles(absolutePluginDir, buildOutputDir, buildOutputDir, manifest.files, wasmFilename);
|
|
493
|
+
cleanupOutputDirectory(absolutePluginDir, buildOutputDir, manifest.files, wasmFilename, manifest.types);
|
|
369
494
|
console.log(`${tick} ${colors.green}Successfully completed compilation & packaging!${colors.reset}`);
|
|
370
495
|
return buildOutputDir;
|
|
371
496
|
}
|
|
@@ -645,13 +770,13 @@ try {
|
|
|
645
770
|
// Prompt for language
|
|
646
771
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
647
772
|
const rawLanguage = await new Promise((resolve) => {
|
|
648
|
-
rl.question(`${info} Select plugin language (go/rust) [default: rust]: `, (ans) => {
|
|
773
|
+
rl.question(`${info} Select plugin language (go/rust/cpp) [default: rust]: `, (ans) => {
|
|
649
774
|
resolve(ans.trim().toLowerCase() || "rust");
|
|
650
775
|
});
|
|
651
776
|
});
|
|
652
777
|
rl.close();
|
|
653
778
|
|
|
654
|
-
if (rawLanguage !== "rust" && rawLanguage !== "go") {
|
|
779
|
+
if (rawLanguage !== "rust" && rawLanguage !== "go" && rawLanguage !== "cpp") {
|
|
655
780
|
console.error(`${cross} ${colors.red}Error: Unsupported language: ${rawLanguage}${colors.reset}`);
|
|
656
781
|
process.exit(1);
|
|
657
782
|
}
|
|
@@ -673,7 +798,7 @@ try {
|
|
|
673
798
|
"\\{\\{type\\}\\}": "rust",
|
|
674
799
|
"\\{\\{workspace_dir\\}\\}": workspaceDir.replace(/\\/g, "/"),
|
|
675
800
|
});
|
|
676
|
-
} else {
|
|
801
|
+
} else if (rawLanguage === "go") {
|
|
677
802
|
// Verify Go
|
|
678
803
|
const goCheck = runCommand("go version");
|
|
679
804
|
if (!goCheck) {
|
|
@@ -690,6 +815,23 @@ try {
|
|
|
690
815
|
"\\{\\{type\\}\\}": "go",
|
|
691
816
|
"\\{\\{workspace_dir\\}\\}": workspaceDir.replace(/\\/g, "/"),
|
|
692
817
|
});
|
|
818
|
+
} else {
|
|
819
|
+
// Verify CMake
|
|
820
|
+
const cmakeCheck = runCommand("cmake --version");
|
|
821
|
+
if (!cmakeCheck) {
|
|
822
|
+
console.error(`\n${cross} ${colors.red}Error: 'cmake' is not installed on your machine.${colors.reset}`);
|
|
823
|
+
console.error(`${colors.yellow}Please install CMake from https://cmake.org/ first.${colors.reset}\n`);
|
|
824
|
+
process.exit(1);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
console.log(`${info} Creating C++ plugin template at ${colors.bold}${targetDir}${colors.reset}...`);
|
|
828
|
+
ensureDir(targetDir);
|
|
829
|
+
const templateSrc = path.join(cliRoot, "templates", "cpp");
|
|
830
|
+
copyFolderRecursive(templateSrc, targetDir, {
|
|
831
|
+
"\\{\\{name\\}\\}": folderName,
|
|
832
|
+
"\\{\\{type\\}\\}": "cpp",
|
|
833
|
+
"\\{\\{workspace_dir\\}\\}": workspaceDir.replace(/\\/g, "/"),
|
|
834
|
+
});
|
|
693
835
|
}
|
|
694
836
|
|
|
695
837
|
console.log(`${tick} ${colors.green}Plugin created successfully under '${pluginPathArg}'!${colors.reset}`);
|
package/package.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.14)
|
|
2
|
+
project({{name}} LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
|
|
7
|
+
# Configure output as a WebAssembly module
|
|
8
|
+
set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
|
|
9
|
+
|
|
10
|
+
# Exclude entry point and export functions explicitly for Emscripten
|
|
11
|
+
if (EMSCRIPTEN)
|
|
12
|
+
set(EXPORT_FUNCTIONS "-sEXPORTED_FUNCTIONS=_void_malloc,_void_free,_void_free_string,_void_invoke,_void_init")
|
|
13
|
+
set(EXPORT_METHODS "-sEXPORTED_RUNTIME_METHODS=ccall,cwrap")
|
|
14
|
+
add_link_options(
|
|
15
|
+
"${EXPORT_FUNCTIONS}"
|
|
16
|
+
"${EXPORT_METHODS}"
|
|
17
|
+
"--no-entry"
|
|
18
|
+
"-sALLOW_MEMORY_GROWTH=1"
|
|
19
|
+
)
|
|
20
|
+
endif()
|
|
21
|
+
|
|
22
|
+
# Reference Void C++ SDK
|
|
23
|
+
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/@tgrv/void-sdk-cpp" void-sdk-cpp-build)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
add_executable({{name}} src/plugin.cpp)
|
|
27
|
+
target_link_libraries({{name}} PRIVATE void-sdk-cpp)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Void C++ Plugin Template
|
|
2
|
+
|
|
3
|
+
A template for building WebAssembly (WASM) plugins for the **Void** framework using C++.
|
|
4
|
+
|
|
5
|
+
## 🚀 Getting Started
|
|
6
|
+
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> Before building your plugin, run **`npm install`** (or `npm i`) in this root directory to download the C++ SDK dependency (`@tgrv/void-sdk-cpp`). The `package.json` file in this root folder is only used for local development setup and resolving CMake dependencies; it is **not** the package that gets published. The final publishable package (with its own generated `package.json`) will be built inside your output directory (configured in `void.json` as `buildDir`).
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### 1. Where to Start
|
|
12
|
+
Write your plugin logic inside [src/plugin.cpp](src/plugin.cpp). Define handlers matching the signature:
|
|
13
|
+
```cpp
|
|
14
|
+
nlohmann::json MyHandler(const void_sdk::ArgsMap& args)
|
|
15
|
+
```
|
|
16
|
+
And register them inside `init_handlers()`:
|
|
17
|
+
```cpp
|
|
18
|
+
void init_handlers() {
|
|
19
|
+
void_sdk::register_handler("hello", hello);
|
|
20
|
+
}
|
|
21
|
+
VOID_PLUGIN(init_handlers);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Build the Plugin
|
|
25
|
+
Compile your plugin by running the build command in this directory:
|
|
26
|
+
```bash
|
|
27
|
+
npx void build
|
|
28
|
+
```
|
|
29
|
+
This runs `emcmake` to configure CMake and compiles the C++ code to a WebAssembly binary.
|
|
30
|
+
|
|
31
|
+
### 3. Test/Install Locally
|
|
32
|
+
To test the built plugin in a local Void application:
|
|
33
|
+
1. Initialize your application project: `npx void init`
|
|
34
|
+
2. Add your compiled local plugin build output folder path:
|
|
35
|
+
```bash
|
|
36
|
+
npx void add ./path/to/plugin/@void/<plugin-name>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 4. Publish
|
|
40
|
+
To build and publish the plugin to the npm registry:
|
|
41
|
+
```bash
|
|
42
|
+
npx void publish
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ⚙️ Configuration (`void.json`)
|
|
48
|
+
|
|
49
|
+
Your plugin configuration is defined in `void.json`. Here are the available fields:
|
|
50
|
+
|
|
51
|
+
- **`name`**: The package name of your plugin (e.g. `my-plugin`).
|
|
52
|
+
- **`version`**: The current semantic version of the plugin.
|
|
53
|
+
- **`type`**: The compilation target language. Set to `"cpp"`.
|
|
54
|
+
- **`buildDir`**: The target directory where compilation and wrapping assets are generated (e.g. `@void/my-plugin`).
|
|
55
|
+
- **`types`**: Path to the TypeScript declaration file (e.g. `"types.d.ts"`).
|
|
56
|
+
- **`export`**: The name of the JavaScript variable used to load the WASM binary, which is also the default export name (e.g. `"myPlugin"`). **Note:** Ensure you use a JS-friendly name (e.g. alphanumeric/camelCase) to ensure the generated JS code does not contain syntax errors. The CLI will automatically sanitize special characters (like `-`, `_`, or `@scope/`) into camelCase/JS-friendly format for the variable and the generated WASM binary name.
|
|
57
|
+
- **`files`**: An array of glob patterns of non-source files (such as `*.md` or `*.d.ts`) to copy from the plugin root into the build output folder.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "void-cpp-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@tgrv/void-runtime": "^1.0.0",
|
|
8
|
+
"@tgrv/void-sdk-cpp": "^1.0.0"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"types": "types.d.ts"
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#include <void/void.hpp>
|
|
2
|
+
|
|
3
|
+
using json = nlohmann::json;
|
|
4
|
+
|
|
5
|
+
// Define a starter function handler
|
|
6
|
+
json hello(const void_sdk::ArgsMap& args) {
|
|
7
|
+
std::string name = void_sdk::get_string(args, "name");
|
|
8
|
+
return json{{"message", "Hello, " + name + " from C++!"}};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Register function handlers
|
|
12
|
+
void init_handlers() {
|
|
13
|
+
void_sdk::register_handler("hello", hello);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Bind initialization entrypoint
|
|
17
|
+
VOID_PLUGIN(init_handlers);
|
package/templates/go/README.md
CHANGED
|
@@ -48,5 +48,5 @@ Your plugin configuration is defined in `void.json`. Here are the available fiel
|
|
|
48
48
|
- **`type`**: The compilation target language. Set to `"go"`.
|
|
49
49
|
- **`buildDir`**: The target directory where compilation and wrapping assets are generated (e.g. `@void/my-plugin`).
|
|
50
50
|
- **`types`**: Path to the TypeScript declaration file (e.g. `"types.d.ts"`). During the build process, the CLI validates its existence, copies it to the build output, and automatically sets the `"types"` entry in `package.json` for autocomplete and editor support.
|
|
51
|
-
- **`export`**: The name of the JavaScript variable used to load the WASM binary, which is also the default export name (e.g. `"myPlugin"`).
|
|
51
|
+
- **`export`**: The name of the JavaScript variable used to load the WASM binary, which is also the default export name (e.g. `"myPlugin"`). **Note:** Ensure you use a JS-friendly name (e.g. alphanumeric/camelCase) to ensure the generated JS code does not contain syntax errors. The CLI will automatically sanitize special characters (like `-`, `_`, or `@scope/`) into camelCase/JS-friendly format for the variable and the generated WASM binary name.
|
|
52
52
|
- **`files`**: An array of glob patterns of non-source files (such as `*.md` or `*.d.ts`) to copy from the plugin root into the build output folder.
|
package/templates/rust/README.md
CHANGED
|
@@ -40,5 +40,5 @@ Your plugin configuration is defined in `void.json`. Here are the available fiel
|
|
|
40
40
|
- **`type`**: The compilation target language. Set to `"rust"`.
|
|
41
41
|
- **`buildDir`**: The target directory where compilation and wrapping assets are generated (e.g. `@void/my-plugin`).
|
|
42
42
|
- **`types`**: Path to the TypeScript declaration file (e.g. `"types.d.ts"`). During the build process, the CLI validates its existence, copies it to the build output, and automatically sets the `"types"` entry in `package.json` for autocomplete and editor support.
|
|
43
|
-
- **`export`**: The name of the JavaScript variable used to load the WASM binary, which is also the default export name (e.g. `"myPlugin"`).
|
|
43
|
+
- **`export`**: The name of the JavaScript variable used to load the WASM binary, which is also the default export name (e.g. `"myPlugin"`). **Note:** Ensure you use a JS-friendly name (e.g. alphanumeric/camelCase) to ensure the generated JS code does not contain syntax errors. The CLI will automatically sanitize special characters (like `-`, `_`, or `@scope/`) into camelCase/JS-friendly format for the variable and the generated WASM binary name.
|
|
44
44
|
- **`files`**: An array of glob patterns of non-source files (such as `*.md` or `*.d.ts`) to copy from the plugin root into the build output folder.
|