@ptkl/toolkit 0.7.2 → 0.8.8
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/dist/bin/toolkit.js +3 -2
- package/dist/builder/register.js +6 -6
- package/dist/builder/sdk6/lit.js +52 -0
- package/dist/builder/sdk6/react.js +56 -0
- package/dist/builder/sdk6/vue3.js +52 -0
- package/dist/builder/sdk6/webcomponents.js +41 -0
- package/dist/commands/apiUsers.js +1 -1
- package/dist/commands/apps.js +26 -2
- package/dist/commands/component.js +302 -19
- package/dist/commands/forge.js +284 -38
- package/dist/commands/functions.js +1 -1
- package/dist/commands/generate-types.js +38 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/profile.js +1 -1
- package/dist/commands/role.js +1 -1
- package/dist/commands/users.js +1 -1
- package/dist/commands/validate-idl.js +115 -0
- package/dist/lib/idlToDts.js +242 -0
- package/dist/lib/util.js +2 -2
- package/package.json +11 -2
package/dist/bin/toolkit.js
CHANGED
|
@@ -14,12 +14,13 @@ program.hook('preAction', (thisCommand, actionCommand) => {
|
|
|
14
14
|
});
|
|
15
15
|
commands.forEach(c => program.addCommand(c));
|
|
16
16
|
program.parseAsync(process.argv).catch((err) => {
|
|
17
|
+
console.log("An error occurred while executing the command.", err);
|
|
17
18
|
const { response } = err;
|
|
18
19
|
if (response && response.data) {
|
|
19
|
-
console.error(response.data.message);
|
|
20
|
+
console.error(response.data.message || "An error occurred with the API request.");
|
|
20
21
|
}
|
|
21
22
|
else {
|
|
22
|
-
console.error(err.message || err);
|
|
23
|
+
console.error(err.message || err || "An unknown error occurred.");
|
|
23
24
|
}
|
|
24
25
|
process.exit(1);
|
|
25
26
|
});
|
package/dist/builder/register.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import CompilerSDK4 from "./sdk4/vue2.js";
|
|
2
2
|
import CompilerSDK5 from "./sdk5/vue2.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
const latestVersion =
|
|
6
|
-
const defaultEngine = '
|
|
3
|
+
import CompilerSDK6WebComponents from "./sdk6/webcomponents.js";
|
|
4
|
+
import CompilerSDK6Lit from "./sdk6/lit.js";
|
|
5
|
+
const latestVersion = 6;
|
|
6
|
+
const defaultEngine = 'webcomponents';
|
|
7
7
|
const compilers = {
|
|
8
8
|
'sdk4::vue2': new CompilerSDK4,
|
|
9
9
|
'sdk5::vue2': new CompilerSDK5,
|
|
10
|
-
'
|
|
11
|
-
'
|
|
10
|
+
'sdk6::webcomponents': new CompilerSDK6WebComponents,
|
|
11
|
+
'sdk6::lit': new CompilerSDK6Lit,
|
|
12
12
|
};
|
|
13
13
|
export default {
|
|
14
14
|
getCompiler(sdkVersion, engine) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as Babel from '@babel/standalone';
|
|
2
|
+
import * as sass from 'sass';
|
|
3
|
+
export default class Compiler {
|
|
4
|
+
async compileBabel(expression) {
|
|
5
|
+
let code = Babel.transform(expression, {
|
|
6
|
+
sourceType: "module",
|
|
7
|
+
presets: [
|
|
8
|
+
"env",
|
|
9
|
+
["typescript", {
|
|
10
|
+
onlyRemoveTypeImports: true,
|
|
11
|
+
allowDeclareFields: true
|
|
12
|
+
}]
|
|
13
|
+
],
|
|
14
|
+
plugins: [
|
|
15
|
+
["proposal-decorators", { version: "2023-05" }],
|
|
16
|
+
"proposal-class-properties"
|
|
17
|
+
]
|
|
18
|
+
});
|
|
19
|
+
return code.code;
|
|
20
|
+
}
|
|
21
|
+
async compileCSS(scope, lang, expression) {
|
|
22
|
+
switch (lang) {
|
|
23
|
+
case 'scss':
|
|
24
|
+
case 'sass':
|
|
25
|
+
if (scope) {
|
|
26
|
+
const result = sass.compileString(`.${scope} { ${expression} }`);
|
|
27
|
+
return result.css;
|
|
28
|
+
}
|
|
29
|
+
const result = sass.compileString(expression);
|
|
30
|
+
return result.css;
|
|
31
|
+
default:
|
|
32
|
+
return expression;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async compile(ext, content) {
|
|
36
|
+
switch (ext) {
|
|
37
|
+
case 'js':
|
|
38
|
+
case 'ts':
|
|
39
|
+
return await this.compileBabel(content);
|
|
40
|
+
case 'css':
|
|
41
|
+
return await this.compileCSS(null, "css", content);
|
|
42
|
+
case 'scss':
|
|
43
|
+
case 'sass':
|
|
44
|
+
return await this.compileCSS(null, ext, content);
|
|
45
|
+
default:
|
|
46
|
+
return await Promise.resolve(content);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getSupportedExt() {
|
|
50
|
+
return ["js", "ts", "css", "scss", "sass", "json", "svg", "html"];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as Babel from '@babel/standalone';
|
|
2
|
+
import * as sass from 'sass';
|
|
3
|
+
export default class Compiler {
|
|
4
|
+
async compileBabel(expression) {
|
|
5
|
+
let code = Babel.transform(expression, {
|
|
6
|
+
sourceType: "module",
|
|
7
|
+
presets: [
|
|
8
|
+
"env",
|
|
9
|
+
["react", { runtime: "automatic" }],
|
|
10
|
+
["typescript", {
|
|
11
|
+
onlyRemoveTypeImports: true,
|
|
12
|
+
isTSX: true,
|
|
13
|
+
allExtensions: true
|
|
14
|
+
}]
|
|
15
|
+
],
|
|
16
|
+
plugins: [
|
|
17
|
+
'@babel/plugin-proposal-class-properties',
|
|
18
|
+
'@babel/plugin-transform-class-static-block'
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
return code.code;
|
|
22
|
+
}
|
|
23
|
+
async compileCSS(scope, lang, expression) {
|
|
24
|
+
switch (lang) {
|
|
25
|
+
case 'scss':
|
|
26
|
+
case 'sass':
|
|
27
|
+
if (scope) {
|
|
28
|
+
const result = sass.compileString(`.${scope} { ${expression} }`);
|
|
29
|
+
return result.css;
|
|
30
|
+
}
|
|
31
|
+
const result = sass.compileString(expression);
|
|
32
|
+
return result.css;
|
|
33
|
+
default:
|
|
34
|
+
return expression;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async compile(ext, content) {
|
|
38
|
+
switch (ext) {
|
|
39
|
+
case 'js':
|
|
40
|
+
case 'jsx':
|
|
41
|
+
case 'ts':
|
|
42
|
+
case 'tsx':
|
|
43
|
+
return await this.compileBabel(content);
|
|
44
|
+
case 'css':
|
|
45
|
+
return await this.compileCSS(null, "css", content);
|
|
46
|
+
case 'scss':
|
|
47
|
+
case 'sass':
|
|
48
|
+
return await this.compileCSS(null, ext, content);
|
|
49
|
+
default:
|
|
50
|
+
return await Promise.resolve(content);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
getSupportedExt() {
|
|
54
|
+
return ["js", "jsx", "ts", "tsx", "css", "scss", "sass", "json", "svg", "html"];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as Babel from '@babel/standalone';
|
|
2
|
+
import * as sass from 'sass';
|
|
3
|
+
export default class Compiler {
|
|
4
|
+
async compileBabel(expression) {
|
|
5
|
+
let code = Babel.transform(expression, {
|
|
6
|
+
sourceType: "module",
|
|
7
|
+
presets: [
|
|
8
|
+
"env",
|
|
9
|
+
["typescript", {
|
|
10
|
+
onlyRemoveTypeImports: true,
|
|
11
|
+
allExtensions: true
|
|
12
|
+
}]
|
|
13
|
+
],
|
|
14
|
+
plugins: [
|
|
15
|
+
'@babel/plugin-proposal-class-properties',
|
|
16
|
+
'@babel/plugin-transform-class-static-block'
|
|
17
|
+
]
|
|
18
|
+
});
|
|
19
|
+
return code.code;
|
|
20
|
+
}
|
|
21
|
+
async compileCSS(scope, lang, expression) {
|
|
22
|
+
switch (lang) {
|
|
23
|
+
case 'scss':
|
|
24
|
+
case 'sass':
|
|
25
|
+
if (scope) {
|
|
26
|
+
const result = sass.compileString(`.${scope} { ${expression} }`);
|
|
27
|
+
return result.css;
|
|
28
|
+
}
|
|
29
|
+
const result = sass.compileString(expression);
|
|
30
|
+
return result.css;
|
|
31
|
+
default:
|
|
32
|
+
return expression;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async compile(ext, content) {
|
|
36
|
+
switch (ext) {
|
|
37
|
+
case 'js':
|
|
38
|
+
case 'ts':
|
|
39
|
+
return await this.compileBabel(content);
|
|
40
|
+
case 'css':
|
|
41
|
+
return await this.compileCSS(null, "css", content);
|
|
42
|
+
case 'scss':
|
|
43
|
+
case 'sass':
|
|
44
|
+
return await this.compileCSS(null, ext, content);
|
|
45
|
+
default:
|
|
46
|
+
return await Promise.resolve(content);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getSupportedExt() {
|
|
50
|
+
return ["js", "ts", "css", "scss", "sass", "json", "svg", "html", "vue"];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as Babel from '@babel/standalone';
|
|
2
|
+
import * as sass from 'sass';
|
|
3
|
+
export default class Compiler {
|
|
4
|
+
async compileBabel(expression) {
|
|
5
|
+
let code = Babel.transform(expression, {
|
|
6
|
+
sourceType: "module",
|
|
7
|
+
presets: ["env"]
|
|
8
|
+
});
|
|
9
|
+
return code.code;
|
|
10
|
+
}
|
|
11
|
+
async compileCSS(scope, lang, expression) {
|
|
12
|
+
switch (lang) {
|
|
13
|
+
case 'scss':
|
|
14
|
+
case 'sass':
|
|
15
|
+
if (scope) {
|
|
16
|
+
const result = sass.compileString(`.${scope} { ${expression} }`);
|
|
17
|
+
return result.css;
|
|
18
|
+
}
|
|
19
|
+
const result = sass.compileString(expression);
|
|
20
|
+
return result.css;
|
|
21
|
+
default:
|
|
22
|
+
return expression;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async compile(ext, content) {
|
|
26
|
+
switch (ext) {
|
|
27
|
+
case 'js':
|
|
28
|
+
return await this.compileBabel(content);
|
|
29
|
+
case 'css':
|
|
30
|
+
return await this.compileCSS(null, "css", content);
|
|
31
|
+
case 'scss':
|
|
32
|
+
case 'sass':
|
|
33
|
+
return await this.compileCSS(null, ext, content);
|
|
34
|
+
default:
|
|
35
|
+
return await Promise.resolve(content);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
getSupportedExt() {
|
|
39
|
+
return ["js", "css", "scss", "sass", "json", "svg", "html"];
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/commands/apps.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Option } from "commander";
|
|
2
2
|
import util from "../lib/util.js";
|
|
3
|
-
import Api from "@ptkl/sdk";
|
|
3
|
+
import { Platform as Api } from "@ptkl/sdk";
|
|
4
4
|
import { build, createServer } from 'vite';
|
|
5
5
|
import { c } from 'tar';
|
|
6
6
|
import { Writable } from "stream";
|
|
@@ -129,7 +129,7 @@ class AppsCommand {
|
|
|
129
129
|
async bundle(options) {
|
|
130
130
|
const { path, upload } = options;
|
|
131
131
|
const module = await import(`${path}/ptkl.config.js`);
|
|
132
|
-
const { views, name, version, distPath, icon, label, permissions, } = module.default ?? {};
|
|
132
|
+
const { views, name, version, distPath, icon, label, permissions, install_permissions, runtime_permissions, requires, scripts, } = module.default ?? {};
|
|
133
133
|
// build manifest file
|
|
134
134
|
const manifest = {
|
|
135
135
|
name,
|
|
@@ -138,6 +138,10 @@ class AppsCommand {
|
|
|
138
138
|
label,
|
|
139
139
|
icon,
|
|
140
140
|
permissions,
|
|
141
|
+
install_permissions: install_permissions ?? [],
|
|
142
|
+
runtime_permissions: runtime_permissions ?? [],
|
|
143
|
+
requires: requires ?? null,
|
|
144
|
+
scripts,
|
|
141
145
|
};
|
|
142
146
|
const profile = Util.getCurrentProfile();
|
|
143
147
|
const client = Util.getClientForProfile();
|
|
@@ -161,9 +165,29 @@ class AppsCommand {
|
|
|
161
165
|
}
|
|
162
166
|
});
|
|
163
167
|
});
|
|
168
|
+
console.log("manifest", manifest);
|
|
169
|
+
const buildScripts = Object.keys(scripts).map((script) => {
|
|
170
|
+
manifest.scripts[script] = `${script}.script.js`;
|
|
171
|
+
return build({
|
|
172
|
+
root: path,
|
|
173
|
+
base,
|
|
174
|
+
build: {
|
|
175
|
+
rollupOptions: {
|
|
176
|
+
input: scripts[script],
|
|
177
|
+
output: {
|
|
178
|
+
format: 'iife',
|
|
179
|
+
entryFileNames: `${script}.script.js`,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
164
185
|
await Promise.allSettled(buildViews).catch(err => {
|
|
165
186
|
console.error('Error building:', err);
|
|
166
187
|
});
|
|
188
|
+
await Promise.allSettled(buildScripts).catch(err => {
|
|
189
|
+
console.error('Error building:', err);
|
|
190
|
+
});
|
|
167
191
|
console.log("Packaging app...");
|
|
168
192
|
// // write manifest file
|
|
169
193
|
const manifestPath = `${distPath}/manifest.json`;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import Builder from "../builder/index.js";
|
|
3
3
|
import { WebSocketServer } from "ws";
|
|
4
|
-
import { resolve } from "path";
|
|
4
|
+
import { resolve, join, dirname } from "path";
|
|
5
5
|
import { rollup } from "rollup";
|
|
6
6
|
import util from "../lib/util.js";
|
|
7
|
-
import Api from "@ptkl/sdk";
|
|
7
|
+
import { Platform as Api } from "@ptkl/sdk";
|
|
8
|
+
import { mkdirSync, writeFileSync, rmSync, readdirSync, existsSync, readFileSync } from "fs";
|
|
9
|
+
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import commonjsPlugin from '@rollup/plugin-commonjs';
|
|
12
|
+
import { babel as babelPlugin } from '@rollup/plugin-babel';
|
|
13
|
+
import { execSync } from 'child_process';
|
|
8
14
|
class ComponentCommand {
|
|
9
15
|
register() {
|
|
10
16
|
return new Command("component")
|
|
@@ -13,37 +19,314 @@ class ComponentCommand {
|
|
|
13
19
|
.addCommand(new Command("builder")
|
|
14
20
|
.description("Run builder for component templates")
|
|
15
21
|
.requiredOption("-v, --version <version>", "SDK version to be used for build", "6")
|
|
16
|
-
.requiredOption("-e, --engine <engine>", "SDK engine to be used for build", "
|
|
17
|
-
.
|
|
22
|
+
.requiredOption("-e, --engine <engine>", "SDK engine to be used for build", "webcomponents")
|
|
23
|
+
.option("-p, --port <port>", "WSS port", "11403")
|
|
24
|
+
.action(this.builder.bind(this)))
|
|
18
25
|
.addCommand(new Command("build")
|
|
19
26
|
.description("Build templates for component")
|
|
20
27
|
.requiredOption("-p, --path <path>", "Path to the source files", "./")
|
|
21
28
|
.action(this.build));
|
|
22
29
|
}
|
|
30
|
+
nodesToActualFiles(nodes, basePath) {
|
|
31
|
+
nodes.forEach((node) => {
|
|
32
|
+
const currentPath = join(basePath, node.name);
|
|
33
|
+
if (node.isLeaf) {
|
|
34
|
+
// Create directory for the file if it doesn't exist
|
|
35
|
+
const dir = dirname(currentPath);
|
|
36
|
+
mkdirSync(dir, { recursive: true });
|
|
37
|
+
// Write the file content
|
|
38
|
+
writeFileSync(currentPath, node.content || '');
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Create directory
|
|
42
|
+
mkdirSync(currentPath, { recursive: true });
|
|
43
|
+
// Process children recursively
|
|
44
|
+
if (node.children && node.children.length > 0) {
|
|
45
|
+
this.nodesToActualFiles(node.children, basePath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
23
50
|
async builder(options) {
|
|
24
|
-
const { version, engine } = options;
|
|
25
|
-
console.log(`Running builder for SDK version ${version} with engine ${engine}`);
|
|
26
|
-
const ws = new WebSocketServer({ port:
|
|
51
|
+
const { version, engine, port } = options;
|
|
52
|
+
console.log(`Running builder for SDK version ${version} with engine ${engine} on port ${port}`);
|
|
53
|
+
const ws = new WebSocketServer({ port: port ?? 11403 });
|
|
27
54
|
ws.on('connection', (socket) => {
|
|
28
55
|
socket.on('message', async (message) => {
|
|
29
|
-
console.log("Building component
|
|
56
|
+
console.log("\n🔨 Building component...");
|
|
30
57
|
const nodes = JSON.parse(message.toString());
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const compiledFiles = await builder.buildFromNodes(nodes);
|
|
35
|
-
dist = Object.assign({}, compiledFiles);
|
|
36
|
-
socket.send(JSON.stringify({ dist }));
|
|
37
|
-
console.log('Component templates built successfully');
|
|
38
|
-
// Do something with the parsed JSON
|
|
58
|
+
// SDK 6 uses new build system with Rollup and multi-view bundling
|
|
59
|
+
if (parseInt(version) >= 6) {
|
|
60
|
+
await this.buildSDK6(nodes, version, engine, socket);
|
|
39
61
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
else {
|
|
63
|
+
// SDK 5 and below use the legacy build system
|
|
64
|
+
await this.buildLegacy(nodes, version, engine, socket);
|
|
43
65
|
}
|
|
44
66
|
});
|
|
45
67
|
});
|
|
46
68
|
}
|
|
69
|
+
async buildSDK6(nodes, version, engine, socket) {
|
|
70
|
+
// Create temporary directory with constant name
|
|
71
|
+
const tempDir = '/tmp/.ptkl/components';
|
|
72
|
+
try {
|
|
73
|
+
// Parse engine to extract framework and version (e.g., "lit@3" -> { framework: "lit", version: "3" })
|
|
74
|
+
const engineMatch = engine.match(/^([^@]+)(?:@(.+))?$/);
|
|
75
|
+
const framework = engineMatch ? engineMatch[1] : engine;
|
|
76
|
+
const frameworkVersion = engineMatch ? engineMatch[2] : null;
|
|
77
|
+
// Create temp directory
|
|
78
|
+
mkdirSync(tempDir, { recursive: true });
|
|
79
|
+
// Clear all files except node_modules
|
|
80
|
+
const entries = readdirSync(tempDir);
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry !== 'node_modules') {
|
|
83
|
+
const fullPath = join(tempDir, entry);
|
|
84
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Convert nodes to actual files
|
|
88
|
+
this.nodesToActualFiles(nodes, tempDir);
|
|
89
|
+
// Look for component.js file that defines views
|
|
90
|
+
const componentsConfigPath = join(tempDir, 'component.js');
|
|
91
|
+
let viewsConfig = {};
|
|
92
|
+
if (!existsSync(componentsConfigPath)) {
|
|
93
|
+
throw new Error('component.js not found. Please create a component.js file that exports { views: { viewName: "./path/to/view.js" } }');
|
|
94
|
+
}
|
|
95
|
+
let componentConfig;
|
|
96
|
+
try {
|
|
97
|
+
// Read the component.js file as text
|
|
98
|
+
const componentContent = readFileSync(componentsConfigPath, 'utf-8');
|
|
99
|
+
// Parse the ES module manually
|
|
100
|
+
// Remove 'export default' and evaluate the object
|
|
101
|
+
const contentWithoutExport = componentContent
|
|
102
|
+
.replace(/export\s+default\s+/, '')
|
|
103
|
+
.trim();
|
|
104
|
+
// Use Function constructor to safely evaluate the object
|
|
105
|
+
componentConfig = new Function(`return ${contentWithoutExport}`)();
|
|
106
|
+
if (!componentConfig || !componentConfig.views) {
|
|
107
|
+
throw new Error('component.js must export default object with "views" property');
|
|
108
|
+
}
|
|
109
|
+
viewsConfig = componentConfig.views;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
throw new Error(`Failed to load component.js: ${error.message}. Please ensure component.js exports { views: { viewName: './path/to/view.js' } }`);
|
|
113
|
+
}
|
|
114
|
+
// Merge user packages with internal dependencies
|
|
115
|
+
const userPackages = componentConfig.packages || {};
|
|
116
|
+
const dependencies = {
|
|
117
|
+
'@ptkl/sdk': '^1.0.0',
|
|
118
|
+
// Lit is bundled into the component, not provided by platform
|
|
119
|
+
...(framework === 'lit' ? {
|
|
120
|
+
'lit': frameworkVersion ? `^${frameworkVersion}` : '^3.0.0'
|
|
121
|
+
} : {}),
|
|
122
|
+
...userPackages
|
|
123
|
+
};
|
|
124
|
+
// Create package.json with merged dependencies
|
|
125
|
+
const packageJson = {
|
|
126
|
+
name: 'component-build',
|
|
127
|
+
version: '1.0.0',
|
|
128
|
+
type: 'module',
|
|
129
|
+
dependencies
|
|
130
|
+
};
|
|
131
|
+
const packageJsonPath = join(tempDir, 'package.json');
|
|
132
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
133
|
+
// Run npm install
|
|
134
|
+
try {
|
|
135
|
+
execSync('npm install', {
|
|
136
|
+
cwd: tempDir,
|
|
137
|
+
stdio: 'pipe',
|
|
138
|
+
env: { ...process.env, NODE_ENV: 'production' }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
throw new Error(`npm install failed: ${error.message}`);
|
|
143
|
+
}
|
|
144
|
+
// Build each view separately with Rollup
|
|
145
|
+
const dist = {};
|
|
146
|
+
const warnings = [];
|
|
147
|
+
const viewCount = Object.keys(viewsConfig).length;
|
|
148
|
+
console.log(`📦 Bundling ${viewCount} view${viewCount !== 1 ? 's' : ''}...`);
|
|
149
|
+
for (const [viewName, viewPath] of Object.entries(viewsConfig)) {
|
|
150
|
+
const fullPath = join(tempDir, viewPath);
|
|
151
|
+
// Check and strip @customElement decorator for Lit components
|
|
152
|
+
if (framework === 'lit') {
|
|
153
|
+
const sourceContent = readFileSync(fullPath, 'utf-8');
|
|
154
|
+
const customElementDecoratorRegex = /@customElement\s*\(\s*['"`][^'"`]*['"`]\s*\)/g;
|
|
155
|
+
if (customElementDecoratorRegex.test(sourceContent)) {
|
|
156
|
+
const warning = `${viewName}: Found @customElement decorator which has been automatically removed. The platform handles element registration dynamically.`;
|
|
157
|
+
warnings.push(warning);
|
|
158
|
+
console.warn(`⚠️ ${warning}`);
|
|
159
|
+
// Strip the decorator from source
|
|
160
|
+
const strippedContent = sourceContent.replace(/@customElement\s*\(\s*['"`][^'"`]*['"`]\s*\)/g, '');
|
|
161
|
+
writeFileSync(fullPath, strippedContent, 'utf-8');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Configure Babel based on framework
|
|
165
|
+
let babelConfig = null;
|
|
166
|
+
if (framework === 'lit') {
|
|
167
|
+
babelConfig = {
|
|
168
|
+
babelHelpers: 'bundled',
|
|
169
|
+
extensions: ['.js', '.ts'],
|
|
170
|
+
presets: [
|
|
171
|
+
['@babel/preset-typescript', {
|
|
172
|
+
onlyRemoveTypeImports: true,
|
|
173
|
+
allowDeclareFields: true
|
|
174
|
+
}]
|
|
175
|
+
],
|
|
176
|
+
plugins: [
|
|
177
|
+
['@babel/plugin-proposal-decorators', { legacy: true }],
|
|
178
|
+
'@babel/plugin-proposal-class-properties',
|
|
179
|
+
'@babel/plugin-transform-class-static-block'
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
else if (framework === 'webcomponents') {
|
|
184
|
+
babelConfig = {
|
|
185
|
+
babelHelpers: 'bundled',
|
|
186
|
+
extensions: ['.js', '.ts'],
|
|
187
|
+
presets: [
|
|
188
|
+
['@babel/preset-typescript', {
|
|
189
|
+
onlyRemoveTypeImports: true,
|
|
190
|
+
allowDeclareFields: true
|
|
191
|
+
}]
|
|
192
|
+
],
|
|
193
|
+
plugins: [
|
|
194
|
+
'@babel/plugin-proposal-class-properties',
|
|
195
|
+
'@babel/plugin-transform-class-static-block'
|
|
196
|
+
]
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// Define external dependencies based on framework
|
|
200
|
+
const getExternalDependencies = (framework) => {
|
|
201
|
+
const externalDeps = [];
|
|
202
|
+
// Lit is bundled into the component, not externalized
|
|
203
|
+
// webcomponents framework has no external dependencies
|
|
204
|
+
return externalDeps;
|
|
205
|
+
};
|
|
206
|
+
const bundle = await rollup({
|
|
207
|
+
input: fullPath,
|
|
208
|
+
plugins: [
|
|
209
|
+
nodeResolve({
|
|
210
|
+
browser: true,
|
|
211
|
+
preferBuiltins: false,
|
|
212
|
+
extensions: ['.js', '.ts', '.jsx', '.tsx', '.vue']
|
|
213
|
+
}),
|
|
214
|
+
// Add Babel plugin if configured
|
|
215
|
+
...(babelConfig ? [babelPlugin(babelConfig)] : []),
|
|
216
|
+
// @ts-ignore
|
|
217
|
+
commonjsPlugin(),
|
|
218
|
+
],
|
|
219
|
+
// Externalize framework dependencies - platform provides them
|
|
220
|
+
external: (id) => {
|
|
221
|
+
const externalDeps = getExternalDependencies(framework);
|
|
222
|
+
return externalDeps.some(dep => {
|
|
223
|
+
if (typeof dep === 'string') {
|
|
224
|
+
return id === dep;
|
|
225
|
+
}
|
|
226
|
+
return dep.test(id);
|
|
227
|
+
});
|
|
228
|
+
},
|
|
229
|
+
onwarn: (warning, warn) => {
|
|
230
|
+
if (warning.code === 'UNRESOLVED_IMPORT') {
|
|
231
|
+
console.warn(`⚠️ Unresolved import in ${viewName}`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
warn(warning);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
const { output } = await bundle.generate({
|
|
238
|
+
format: 'esm',
|
|
239
|
+
sourcemap: false,
|
|
240
|
+
inlineDynamicImports: true,
|
|
241
|
+
});
|
|
242
|
+
// Add to dist with view name
|
|
243
|
+
output.forEach((chunk) => {
|
|
244
|
+
if (chunk.type === 'chunk') {
|
|
245
|
+
let code = chunk.code;
|
|
246
|
+
// Check for common issues and add warnings
|
|
247
|
+
// 1. Check if code contains customElements.define and remove it
|
|
248
|
+
// Handle various formats including multiline
|
|
249
|
+
const customElementsDefineRegex = /customElements\.define\s*\([^)]*\([\s\S]*?\)\s*\)\s*;?|customElements\.define\s*\([^)]*\)\s*;?/g;
|
|
250
|
+
const hasCustomElementsDefine = customElementsDefineRegex.test(code);
|
|
251
|
+
if (hasCustomElementsDefine) {
|
|
252
|
+
const warning = `${viewName}: Found customElements.define() which has been automatically removed. The platform handles element registration dynamically based on component context.`;
|
|
253
|
+
warnings.push(warning);
|
|
254
|
+
console.warn(`⚠️ ${warning}`);
|
|
255
|
+
// Remove customElements.define calls (reset regex after test)
|
|
256
|
+
code = code.replace(/customElements\.define\s*\([^)]*\([\s\S]*?\)\s*\)\s*;?/g, '');
|
|
257
|
+
code = code.replace(/customElements\.define\s*\([^)]*\)\s*;?/g, '');
|
|
258
|
+
}
|
|
259
|
+
// 2. Check if code has a default export
|
|
260
|
+
const hasDefaultExport = /export\s+default/.test(code) || /export\s*\{[^}]*default[^}]*\}/.test(code);
|
|
261
|
+
if (!hasDefaultExport) {
|
|
262
|
+
const warning = `${viewName}: Missing default export. The view must export a default component/class for the platform to use.`;
|
|
263
|
+
warnings.push(warning);
|
|
264
|
+
console.warn(`⚠️ ${warning}`);
|
|
265
|
+
}
|
|
266
|
+
// 3. Check if code is suspiciously small (might indicate build issue)
|
|
267
|
+
if (code.length < 50) {
|
|
268
|
+
const warning = `${viewName}: Bundle size is very small (${code.length} bytes). This might indicate a build issue.`;
|
|
269
|
+
warnings.push(warning);
|
|
270
|
+
console.warn(`⚠️ ${warning}`);
|
|
271
|
+
}
|
|
272
|
+
// 4. Check for missing imports that might cause runtime errors
|
|
273
|
+
if (framework === 'lit' && !code.includes('lit')) {
|
|
274
|
+
const warning = `${viewName}: Lit framework not detected in bundle. Make sure you're importing from 'lit'.`;
|
|
275
|
+
warnings.push(warning);
|
|
276
|
+
console.warn(`⚠️ ${warning}`);
|
|
277
|
+
}
|
|
278
|
+
dist[`${viewName}.js`] = code;
|
|
279
|
+
}
|
|
280
|
+
else if (chunk.type === 'asset') {
|
|
281
|
+
dist[`${viewName}-${chunk.fileName}`] = chunk.source.toString();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
const totalSize = Object.values(dist).reduce((sum, code) => sum + code.length, 0);
|
|
286
|
+
const formattedSize = totalSize > 1024 ? `${(totalSize / 1024).toFixed(2)} KB` : `${totalSize} bytes`;
|
|
287
|
+
console.log(`✅ Build complete: ${Object.keys(dist).length} file${Object.keys(dist).length !== 1 ? 's' : ''} (${formattedSize})`);
|
|
288
|
+
Object.entries(dist).forEach(([name, code]) => {
|
|
289
|
+
const size = code.length > 1024 ? `${(code.length / 1024).toFixed(2)} KB` : `${code.length} bytes`;
|
|
290
|
+
console.log(` • ${name} - ${size}`);
|
|
291
|
+
});
|
|
292
|
+
socket.send(JSON.stringify({
|
|
293
|
+
dist,
|
|
294
|
+
views: Object.keys(viewsConfig),
|
|
295
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
296
|
+
sdk_version: version,
|
|
297
|
+
sdk_engine: engine
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
console.error(`❌ Build failed: ${error.message}`);
|
|
302
|
+
socket.send(JSON.stringify({ error: error.message }));
|
|
303
|
+
}
|
|
304
|
+
finally {
|
|
305
|
+
try {
|
|
306
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
307
|
+
console.log(`Cleaned up temporary directory: ${tempDir}`);
|
|
308
|
+
}
|
|
309
|
+
catch (cleanupError) {
|
|
310
|
+
console.error(`Failed to clean up temporary directory: ${cleanupError}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async buildLegacy(nodes, version, engine, socket) {
|
|
315
|
+
try {
|
|
316
|
+
const builder = new Builder(parseInt(version), engine);
|
|
317
|
+
const dist = await builder.buildFromNodes(nodes);
|
|
318
|
+
socket.send(JSON.stringify({
|
|
319
|
+
dist,
|
|
320
|
+
sdk_version: version,
|
|
321
|
+
sdk_engine: engine
|
|
322
|
+
}));
|
|
323
|
+
console.log(`✅ Build complete (SDK ${version})`);
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
console.error(`❌ Build failed: ${error.message}`);
|
|
327
|
+
socket.send(JSON.stringify({ error: error.message }));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
47
330
|
async build(options) {
|
|
48
331
|
try {
|
|
49
332
|
const { path } = options;
|