@zeus-js/output-wc 0.1.1-beta.2 → 0.1.1-beta.20
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/capabilities.cjs +2 -2
- package/dist/capabilities.js +1 -1
- package/dist/capabilities.prod.cjs +2 -2
- package/dist/capabilities.prod.js +1 -1
- package/dist/output-wc.cjs +281 -112
- package/dist/output-wc.esm-bundler.js +331 -109
- package/dist/output-wc.prod.cjs +281 -112
- package/package.json +6 -6
package/dist/output-wc.prod.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* output-wc v0.1.1-beta.
|
|
2
|
+
* output-wc v0.1.1-beta.20
|
|
3
3
|
* (c) 2026 baicie
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
**/
|
|
@@ -31,11 +31,94 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
//#endregion
|
|
32
32
|
let node_path = require("node:path");
|
|
33
33
|
node_path = __toESM(node_path, 1);
|
|
34
|
+
let node_url = require("node:url");
|
|
34
35
|
let _zeus_js_bundler_plugin = require("@zeus-js/bundler-plugin");
|
|
35
36
|
let _zeus_js_component_dts = require("@zeus-js/component-dts");
|
|
37
|
+
//#region packages/web-c/output-wc/src/generateManifest.ts
|
|
38
|
+
function generateZeusComponentsManifest(manifest) {
|
|
39
|
+
validateComponentManifest(manifest);
|
|
40
|
+
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
41
|
+
}
|
|
42
|
+
function validateComponentManifest(manifest) {
|
|
43
|
+
if ((manifest === null || manifest === void 0 ? void 0 : manifest.schemaVersion) !== 1) throw new Error("[ZEUS_WC_ABI_VERSION] Component manifest schemaVersion must be 1.");
|
|
44
|
+
if (!Array.isArray(manifest.components)) throw new Error("[ZEUS_WC_INVALID_MANIFEST] Component manifest components must be an array.");
|
|
45
|
+
const tags = /* @__PURE__ */ new Set();
|
|
46
|
+
for (const [componentIndex, component] of manifest.components.entries()) {
|
|
47
|
+
if (!component || typeof component.tag !== "string") throw new Error(`[ZEUS_WC_INVALID_MANIFEST] components[${componentIndex}].tag must be a string.`);
|
|
48
|
+
if (tags.has(component.tag)) throw new Error(`[ZEUS_WC_DUPLICATE_TAG] Component tag "${component.tag}" is declared more than once.`);
|
|
49
|
+
tags.add(component.tag);
|
|
50
|
+
}
|
|
51
|
+
for (const [componentIndex, component] of manifest.components.entries()) {
|
|
52
|
+
var _component$props, _component$events, _component$props2;
|
|
53
|
+
const componentPath = `components[${componentIndex}]`;
|
|
54
|
+
if (!component || typeof component.tag !== "string" || typeof component.exportName !== "string") throw new Error(`[ZEUS_WC_INVALID_MANIFEST] ${componentPath} requires tag and exportName strings.`);
|
|
55
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
56
|
+
for (const [propName, prop] of Object.entries((_component$props = component.props) !== null && _component$props !== void 0 ? _component$props : {})) {
|
|
57
|
+
const attrName = prop.attr === false ? false : typeof prop.attr === "string" ? prop.attr : [
|
|
58
|
+
"string",
|
|
59
|
+
"number",
|
|
60
|
+
"boolean"
|
|
61
|
+
].includes(prop.type) ? propName.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`) : false;
|
|
62
|
+
if (attrName !== false) {
|
|
63
|
+
const previous = attributes.get(attrName);
|
|
64
|
+
if (previous && previous !== propName) throw new Error(`[ZEUS_WC_ATTR_COLLISION] ${componentPath}.props.${propName} and ${previous} both use attribute "${attrName}".`);
|
|
65
|
+
attributes.set(attrName, propName);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const [eventKey, event] of Object.entries((_component$events = component.events) !== null && _component$events !== void 0 ? _component$events : {})) {
|
|
69
|
+
if (event.name !== void 0 && typeof event.name !== "string" || event.reactName !== void 0 && typeof event.reactName !== "string" || event.bubbles !== void 0 && typeof event.bubbles !== "boolean" || event.composed !== void 0 && typeof event.composed !== "boolean" || event.cancelable !== void 0 && typeof event.cancelable !== "boolean") throw new Error(`[ZEUS_WC_EVENT_ABI] ${componentPath}.events.${eventKey} contains invalid names or bubbles/composed/cancelable flags.`);
|
|
70
|
+
const eventPath = `${componentPath}.events.${eventKey}`;
|
|
71
|
+
if (event.detail !== void 0) assertJsonSafe(event.detail, `${eventPath}.detail`);
|
|
72
|
+
if (event.detailOptional !== void 0) assertJsonSafe(event.detailOptional, `${eventPath}.detailOptional`);
|
|
73
|
+
if (event.detail !== void 0 && (event.detail === null || typeof event.detail !== "object" || Array.isArray(event.detail) || Object.values(event.detail).some((type) => typeof type !== "string"))) throw new Error(`[ZEUS_WC_EVENT_ABI] ${eventPath}.detail must map field names to type strings.`);
|
|
74
|
+
if (event.detailOptional !== void 0 && (!Array.isArray(event.detailOptional) || !event.detail || [...event.detailOptional].some((name) => typeof name !== "string" || !Object.prototype.hasOwnProperty.call(event.detail, name)) || new Set(event.detailOptional).size !== event.detailOptional.length)) throw new Error(`[ZEUS_WC_EVENT_ABI] ${eventPath}.detailOptional must contain unique names from detail.`);
|
|
75
|
+
}
|
|
76
|
+
for (const [propName, prop] of Object.entries((_component$props2 = component.props) !== null && _component$props2 !== void 0 ? _component$props2 : {})) {
|
|
77
|
+
if (prop.hasDefault !== void 0 && typeof prop.hasDefault !== "boolean") throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName}.hasDefault must be boolean.`);
|
|
78
|
+
if (prop.defaultStrategy !== void 0 && prop.defaultStrategy !== "static" && prop.defaultStrategy !== "factory") throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName}.defaultStrategy is invalid.`);
|
|
79
|
+
if (prop.defaultStrategy === "factory" && prop.default !== void 0) throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName} factory defaults cannot be serialized as values.`);
|
|
80
|
+
if (prop.defaultStrategy === "static" && !Object.prototype.hasOwnProperty.call(prop, "default")) throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName} static defaults require a value.`);
|
|
81
|
+
if (Object.prototype.hasOwnProperty.call(prop, "default")) {
|
|
82
|
+
if (prop.default === void 0) throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName}.default cannot be undefined.`);
|
|
83
|
+
assertJsonSafe(prop.default, `${componentPath}.props.${propName}.default`, /* @__PURE__ */ new Set(), "ZEUS_WC_INVALID_DEFAULT_META", true);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
assertJsonSafe(manifest, "manifest");
|
|
88
|
+
}
|
|
89
|
+
function assertJsonSafe(value, path, parents = /* @__PURE__ */ new Set(), code = "ZEUS_WC_INVALID_MANIFEST", rejectUndefined = false) {
|
|
90
|
+
if (value === void 0) {
|
|
91
|
+
if (rejectUndefined) throw invalidManifest(path, "undefined values are not supported", code);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (value === null) return;
|
|
95
|
+
if (typeof value === "string" || typeof value === "boolean") return;
|
|
96
|
+
if (typeof value === "number") {
|
|
97
|
+
if (!Number.isFinite(value) || Object.is(value, -0)) throw invalidManifest(path, "numbers must be finite and cannot be -0", code);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") throw invalidManifest(path, "functions, symbols, and bigint values are not supported", code);
|
|
101
|
+
if (typeof value !== "object") throw invalidManifest(path, "value is not JSON-safe", code);
|
|
102
|
+
if (parents.has(value)) throw invalidManifest(path, "cyclic values are not supported", code);
|
|
103
|
+
const prototype = Object.getPrototypeOf(value);
|
|
104
|
+
if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) throw invalidManifest(path, "only plain objects and arrays are supported", code);
|
|
105
|
+
if (Object.getOwnPropertySymbols(value).length > 0) throw invalidManifest(path, "symbol keys are not supported", code);
|
|
106
|
+
parents.add(value);
|
|
107
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
|
|
108
|
+
if ("get" in descriptor || "set" in descriptor) throw invalidManifest(`${path}.${key}`, "accessor properties are not supported", code);
|
|
109
|
+
if (descriptor.value === void 0 && !rejectUndefined) continue;
|
|
110
|
+
assertJsonSafe(descriptor.value, Array.isArray(value) ? `${path}[${key}]` : `${path}.${key}`, parents, code, rejectUndefined);
|
|
111
|
+
}
|
|
112
|
+
parents.delete(value);
|
|
113
|
+
}
|
|
114
|
+
function invalidManifest(path, reason, code) {
|
|
115
|
+
return /* @__PURE__ */ new Error(`[${code}] ${path}: ${reason}.`);
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
36
118
|
//#region packages/web-c/output-wc/src/generateCustomElementsJson.ts
|
|
37
119
|
function generateCustomElementsJson(options) {
|
|
38
120
|
const { manifest, getModulePath } = options;
|
|
121
|
+
validateComponentManifest(manifest);
|
|
39
122
|
const result = {
|
|
40
123
|
schemaVersion: "1.0.0",
|
|
41
124
|
modules: manifest.components.map((component) => {
|
|
@@ -97,21 +180,31 @@ function generateMembers(component) {
|
|
|
97
180
|
default: prop.default === void 0 ? void 0 : JSON.stringify(prop.default)
|
|
98
181
|
};
|
|
99
182
|
});
|
|
100
|
-
const methods = Object.
|
|
101
|
-
return {
|
|
102
|
-
kind: "method",
|
|
103
|
-
name
|
|
104
|
-
};
|
|
105
|
-
});
|
|
183
|
+
const methods = Object.entries((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {}).map(([name, method]) => generateMethodMember(name, method));
|
|
106
184
|
return [...fields, ...methods];
|
|
107
185
|
}
|
|
186
|
+
function generateMethodMember(name, method) {
|
|
187
|
+
var _method$returns, _method$returns2;
|
|
188
|
+
const member = {
|
|
189
|
+
kind: "method",
|
|
190
|
+
name,
|
|
191
|
+
return: { type: { text: method.async ? `Promise<${(_method$returns = method.returns) !== null && _method$returns !== void 0 ? _method$returns : "unknown"}>` : (_method$returns2 = method.returns) !== null && _method$returns2 !== void 0 ? _method$returns2 : "unknown" } }
|
|
192
|
+
};
|
|
193
|
+
if (method.parameters) member.parameters = method.parameters.map((parameter) => ({
|
|
194
|
+
name: parameter.name,
|
|
195
|
+
type: { text: parameter.type },
|
|
196
|
+
optional: parameter.optional,
|
|
197
|
+
rest: parameter.rest
|
|
198
|
+
}));
|
|
199
|
+
return member;
|
|
200
|
+
}
|
|
108
201
|
function generateEvents(component) {
|
|
109
202
|
return Object.entries(component.events).map(([key, event]) => {
|
|
110
203
|
var _event$name, _event$key;
|
|
111
204
|
return {
|
|
112
205
|
name: (_event$name = event.name) !== null && _event$name !== void 0 ? _event$name : toKebabCase$1((_event$key = event.key) !== null && _event$key !== void 0 ? _event$key : key),
|
|
113
206
|
description: event.description,
|
|
114
|
-
type: { text: event.detail ? `CustomEvent<${formatDetailType(event.detail)}>` : "CustomEvent" }
|
|
207
|
+
type: { text: event.detail ? `CustomEvent<${(0, _zeus_js_component_dts.formatDetailType)(event.detail, event.detailOptional)}>` : "CustomEvent" }
|
|
115
208
|
};
|
|
116
209
|
});
|
|
117
210
|
}
|
|
@@ -147,9 +240,6 @@ function formatPropType(prop) {
|
|
|
147
240
|
function isAttributeBackedType$1(type) {
|
|
148
241
|
return type === "string" || type === "number" || type === "boolean";
|
|
149
242
|
}
|
|
150
|
-
function formatDetailType(detail) {
|
|
151
|
-
return `{ ${Object.entries(detail).map(([name, type]) => `${name}: ${type}`).join("; ")} }`;
|
|
152
|
-
}
|
|
153
243
|
function normalizeModulePath(value) {
|
|
154
244
|
return value.replace(/\\/g, "/");
|
|
155
245
|
}
|
|
@@ -179,6 +269,15 @@ function generateWCEntry(options) {
|
|
|
179
269
|
`import { ${component.exportName} } from ${JSON.stringify(source)};`,
|
|
180
270
|
"",
|
|
181
271
|
`export { ${component.exportName} };`,
|
|
272
|
+
"",
|
|
273
|
+
`export function defineCustomElement(options = {}) {`,
|
|
274
|
+
` const registry = options.registry ?? (typeof customElements === 'undefined' ? undefined : customElements);`,
|
|
275
|
+
` if (!registry) return;`,
|
|
276
|
+
` const existing = registry.get(${JSON.stringify(component.tag)});`,
|
|
277
|
+
` if (existing === ${component.exportName}) return;`,
|
|
278
|
+
` if (existing) throw new Error(${JSON.stringify(`[ZEUS_WC_DUPLICATE_TAG] <${component.tag}> is already registered with a different definition.`)});`,
|
|
279
|
+
` registry.define(${JSON.stringify(component.tag)}, ${component.exportName});`,
|
|
280
|
+
`}`,
|
|
182
281
|
""
|
|
183
282
|
].join("\n");
|
|
184
283
|
}
|
|
@@ -204,16 +303,19 @@ function getVirtualIndexId() {
|
|
|
204
303
|
//#region packages/web-c/output-wc/src/generateLazyEntry.ts
|
|
205
304
|
function generateLazyEntry(options) {
|
|
206
305
|
const { component, outPath, sourceImport } = options;
|
|
207
|
-
const source = sourceImport !== null && sourceImport !== void 0 ? sourceImport : toRelativeImport(component.source, outPath)
|
|
306
|
+
const source = `${sourceImport !== null && sourceImport !== void 0 ? sourceImport : toRelativeImport(component.source, outPath)}?zeus-lazy-component=${component.exportName}`;
|
|
208
307
|
return [
|
|
209
|
-
`import { createCustomElementMountLifecycle, mountElementDefinition } from "@zeus-js/runtime-dom";`,
|
|
308
|
+
`import { createCustomElementMountLifecycle, getElementDefinition, mountElementDefinition } from "@zeus-js/runtime-dom";`,
|
|
309
|
+
`import { resolveHostProperties } from "@zeus-js/web-c-runtime";`,
|
|
210
310
|
`import { ${component.exportName} } from ${JSON.stringify(source)};`,
|
|
211
311
|
"",
|
|
212
312
|
`export function createComponent(hostRef) {`,
|
|
313
|
+
` resolveHostProperties(hostRef, getElementDefinition(${component.exportName}).propDefs);`,
|
|
213
314
|
` const mountState = {`,
|
|
214
315
|
` attributeProps: hostRef.attributeProps,`,
|
|
215
316
|
` internals: hostRef.internals,`,
|
|
216
317
|
` reflectingAttrs: hostRef.reflectingAttrs,`,
|
|
318
|
+
` exposedMethods: hostRef.exposedMethods,`,
|
|
217
319
|
` };`,
|
|
218
320
|
` const lifecycle = createCustomElementMountLifecycle(() =>`,
|
|
219
321
|
` mountElementDefinition(`,
|
|
@@ -233,8 +335,8 @@ function generateLazyEntry(options) {
|
|
|
233
335
|
` lifecycle.disconnect();`,
|
|
234
336
|
` },`,
|
|
235
337
|
"",
|
|
236
|
-
` propertyChanged(
|
|
237
|
-
` lifecycle.current()?.propertyChanged(
|
|
338
|
+
` propertyChanged(change) {`,
|
|
339
|
+
` lifecycle.current()?.propertyChanged(change);`,
|
|
238
340
|
` },`,
|
|
239
341
|
"",
|
|
240
342
|
` formAssociated(form) {`,
|
|
@@ -268,54 +370,6 @@ function toRelativeImport(source, outPath) {
|
|
|
268
370
|
return [...outParts.slice(common).map(() => ".."), ...sourceParts.slice(common)].join("/");
|
|
269
371
|
}
|
|
270
372
|
//#endregion
|
|
271
|
-
//#region packages/web-c/output-wc/src/generateLazyManifest.ts
|
|
272
|
-
function generateLazyManifest(options) {
|
|
273
|
-
const { components, getEntryFileName } = options;
|
|
274
|
-
return `export const components = [
|
|
275
|
-
${components.map((component) => {
|
|
276
|
-
var _component$runtimePro, _component$methods, _component$meta$shado, _component$meta, _component$meta$formA, _component$meta2;
|
|
277
|
-
const entryFile = getEntryFileName(component.tag).replace(/\\/g, "/");
|
|
278
|
-
const props = generatePropsArray((_component$runtimePro = component.runtimeProps) !== null && _component$runtimePro !== void 0 ? _component$runtimePro : component.props);
|
|
279
|
-
const methods = Object.keys((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {});
|
|
280
|
-
const importPath = entryFile.startsWith(".") ? JSON.stringify(entryFile) : JSON.stringify(`./${entryFile}`);
|
|
281
|
-
const methodLine = methods.length ? ` methods: ${JSON.stringify(methods)},\n` : "";
|
|
282
|
-
return ` {
|
|
283
|
-
tagName: ${JSON.stringify(component.tag)},
|
|
284
|
-
shadow: ${(_component$meta$shado = (_component$meta = component.meta) === null || _component$meta === void 0 ? void 0 : _component$meta.shadow) !== null && _component$meta$shado !== void 0 ? _component$meta$shado : false},
|
|
285
|
-
formAssociated: ${(_component$meta$formA = (_component$meta2 = component.meta) === null || _component$meta2 === void 0 ? void 0 : _component$meta2.formAssociated) !== null && _component$meta$formA !== void 0 ? _component$meta$formA : false},
|
|
286
|
-
load: () => import(${importPath}),
|
|
287
|
-
props: ${props},
|
|
288
|
-
${methodLine}
|
|
289
|
-
}`;
|
|
290
|
-
}).join(",\n")}
|
|
291
|
-
];
|
|
292
|
-
`;
|
|
293
|
-
}
|
|
294
|
-
function generatePropsArray(props) {
|
|
295
|
-
const entries = Object.entries(props);
|
|
296
|
-
if (entries.length === 0) return "[]";
|
|
297
|
-
return `[\n${entries.map(([name, prop]) => {
|
|
298
|
-
const parts = [`name: ${JSON.stringify(name)}`];
|
|
299
|
-
if (!isAttributeBackedType(prop.type) && !prop.deserialize || prop.attr === false) parts.push("attrName: false");
|
|
300
|
-
else {
|
|
301
|
-
var _prop$attr;
|
|
302
|
-
const attrName = (_prop$attr = prop.attr) !== null && _prop$attr !== void 0 ? _prop$attr : toKebabCase(name);
|
|
303
|
-
if (attrName !== toKebabCase(name)) parts.push(`attrName: ${JSON.stringify(attrName)}`);
|
|
304
|
-
}
|
|
305
|
-
parts.push(`type: ${JSON.stringify(prop.type)}`);
|
|
306
|
-
if (prop.reflect && (isAttributeBackedType(prop.type) || Boolean(prop.serialize))) parts.push("reflect: true");
|
|
307
|
-
if (prop.serialize) parts.push("serialize: true");
|
|
308
|
-
if (prop.deserialize) parts.push("deserialize: true");
|
|
309
|
-
return ` { ${parts.join(", ")} }`;
|
|
310
|
-
}).join(",\n")}\n ]`;
|
|
311
|
-
}
|
|
312
|
-
function isAttributeBackedType(type) {
|
|
313
|
-
return type === "string" || type === "number" || type === "boolean";
|
|
314
|
-
}
|
|
315
|
-
function toKebabCase(value) {
|
|
316
|
-
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
317
|
-
}
|
|
318
|
-
//#endregion
|
|
319
373
|
//#region packages/web-c/output-wc/src/generateLoader.ts
|
|
320
374
|
function generateLoader() {
|
|
321
375
|
return `import { bootstrapLazy } from "@zeus-js/web-c-runtime";
|
|
@@ -325,24 +379,11 @@ const componentsByTagName = new Map(
|
|
|
325
379
|
components.map(component => [component.tagName, component]),
|
|
326
380
|
);
|
|
327
381
|
|
|
328
|
-
const definedTagsByRegistry = new WeakMap();
|
|
329
|
-
|
|
330
382
|
function resolveRegistry(options) {
|
|
331
383
|
return options.registry ??
|
|
332
384
|
(typeof customElements === "undefined" ? undefined : customElements);
|
|
333
385
|
}
|
|
334
386
|
|
|
335
|
-
function getDefinedTags(registry) {
|
|
336
|
-
let definedTags = definedTagsByRegistry.get(registry);
|
|
337
|
-
|
|
338
|
-
if (!definedTags) {
|
|
339
|
-
definedTags = new Set();
|
|
340
|
-
definedTagsByRegistry.set(registry, definedTags);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return definedTags;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
387
|
export function defineCustomElement(tagName, options = {}) {
|
|
347
388
|
const registry = resolveRegistry(options);
|
|
348
389
|
|
|
@@ -356,16 +397,7 @@ export function defineCustomElement(tagName, options = {}) {
|
|
|
356
397
|
throw new Error(\`[zeus:web-c] Unknown custom element: <\${tagName}>.\`);
|
|
357
398
|
}
|
|
358
399
|
|
|
359
|
-
const definedTags = getDefinedTags(registry);
|
|
360
|
-
|
|
361
|
-
if (definedTags.has(tagName) || registry.get(tagName)) {
|
|
362
|
-
definedTags.add(tagName);
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
400
|
bootstrapLazy([component], { registry });
|
|
367
|
-
|
|
368
|
-
definedTags.add(tagName);
|
|
369
401
|
}
|
|
370
402
|
|
|
371
403
|
export function defineCustomElements(options = {}) {
|
|
@@ -374,8 +406,6 @@ export function defineCustomElements(options = {}) {
|
|
|
374
406
|
}
|
|
375
407
|
}
|
|
376
408
|
|
|
377
|
-
export const defineLazyElement = defineCustomElement;
|
|
378
|
-
export const defineLazyElements = defineCustomElements;
|
|
379
409
|
`;
|
|
380
410
|
}
|
|
381
411
|
function generateAutoEntry() {
|
|
@@ -390,18 +420,149 @@ function generateLazyIndex() {
|
|
|
390
420
|
return `export {
|
|
391
421
|
defineCustomElement,
|
|
392
422
|
defineCustomElements,
|
|
393
|
-
defineLazyElement,
|
|
394
|
-
defineLazyElements,
|
|
395
423
|
} from "./loader.js";
|
|
396
424
|
`;
|
|
397
425
|
}
|
|
398
426
|
//#endregion
|
|
399
|
-
//#region packages/web-c/output-wc/src/
|
|
400
|
-
function
|
|
401
|
-
|
|
427
|
+
//#region packages/web-c/output-wc/src/generateLazyManifest.ts
|
|
428
|
+
function generateLazyManifest(options) {
|
|
429
|
+
const { components, getEntryFileName } = options;
|
|
430
|
+
return `export const components = [
|
|
431
|
+
${components.map((component) => {
|
|
432
|
+
var _component$runtimePro, _component$methods, _component$meta$shado, _component$meta, _component$meta$formA, _component$meta2;
|
|
433
|
+
const entryFile = getEntryFileName(component.tag).replace(/\\/g, "/");
|
|
434
|
+
const props = generatePropsArray((_component$runtimePro = component.runtimeProps) !== null && _component$runtimePro !== void 0 ? _component$runtimePro : component.props);
|
|
435
|
+
const methods = Object.keys((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {});
|
|
436
|
+
const importPath = entryFile.startsWith(".") ? JSON.stringify(entryFile) : JSON.stringify(`./${entryFile}`);
|
|
437
|
+
const methodLine = methods.length ? ` methods: ${JSON.stringify(methods)},\n` : "";
|
|
438
|
+
return ` {
|
|
439
|
+
tagName: ${JSON.stringify(component.tag)},
|
|
440
|
+
shadow: ${(_component$meta$shado = (_component$meta = component.meta) === null || _component$meta === void 0 ? void 0 : _component$meta.shadow) !== null && _component$meta$shado !== void 0 ? _component$meta$shado : false},
|
|
441
|
+
formAssociated: ${(_component$meta$formA = (_component$meta2 = component.meta) === null || _component$meta2 === void 0 ? void 0 : _component$meta2.formAssociated) !== null && _component$meta$formA !== void 0 ? _component$meta$formA : false},
|
|
442
|
+
load: () => import(${importPath}),
|
|
443
|
+
props: ${props},
|
|
444
|
+
${methodLine}
|
|
445
|
+
}`;
|
|
446
|
+
}).join(",\n")}
|
|
447
|
+
];
|
|
448
|
+
`;
|
|
449
|
+
}
|
|
450
|
+
function generatePropsArray(props) {
|
|
451
|
+
const entries = Object.entries(props);
|
|
452
|
+
if (entries.length === 0) return "[]";
|
|
453
|
+
return `[\n${entries.map(([name, prop]) => {
|
|
454
|
+
const parts = [`name: ${JSON.stringify(name)}`];
|
|
455
|
+
if (!isAttributeBackedType(prop.type) && !prop.deserialize || prop.attr === false) parts.push("attrName: false");
|
|
456
|
+
else {
|
|
457
|
+
var _prop$attr;
|
|
458
|
+
const attrName = (_prop$attr = prop.attr) !== null && _prop$attr !== void 0 ? _prop$attr : toKebabCase(name);
|
|
459
|
+
if (attrName !== toKebabCase(name)) parts.push(`attrName: ${JSON.stringify(attrName)}`);
|
|
460
|
+
}
|
|
461
|
+
parts.push(`type: ${JSON.stringify(prop.type)}`);
|
|
462
|
+
if (isJsonSafeDefault(prop.default)) {
|
|
463
|
+
const encoded = JSON.stringify(prop.default);
|
|
464
|
+
parts.push(`default: ${typeof prop.default === "object" && prop.default !== null ? `JSON.parse(${JSON.stringify(encoded)})` : encoded}`);
|
|
465
|
+
}
|
|
466
|
+
if (prop.reflect && (isAttributeBackedType(prop.type) || Boolean(prop.serialize))) parts.push("reflect: true");
|
|
467
|
+
if (prop.serialize) parts.push("serialize: true");
|
|
468
|
+
if (prop.deserialize) parts.push("deserialize: true");
|
|
469
|
+
return ` { ${parts.join(", ")} }`;
|
|
470
|
+
}).join(",\n")}\n ]`;
|
|
471
|
+
}
|
|
472
|
+
function isJsonSafeDefault(value, parents = /* @__PURE__ */ new Set()) {
|
|
473
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
474
|
+
if (typeof value === "number") return Number.isFinite(value) && !Object.is(value, -0);
|
|
475
|
+
if (typeof value !== "object" || parents.has(value)) return false;
|
|
476
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) return false;
|
|
477
|
+
if (Object.getOwnPropertySymbols(value).length) return false;
|
|
478
|
+
parents.add(value);
|
|
479
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
480
|
+
const valid = Array.isArray(value) ? Array.from({ length: value.length }, (_, index) => descriptors[index]).every((descriptor) => descriptor && "value" in descriptor && isJsonSafeDefault(descriptor.value, parents)) : Object.values(descriptors).every((descriptor) => "value" in descriptor && isJsonSafeDefault(descriptor.value, parents));
|
|
481
|
+
parents.delete(value);
|
|
482
|
+
return valid;
|
|
483
|
+
}
|
|
484
|
+
function isAttributeBackedType(type) {
|
|
485
|
+
return type === "string" || type === "number" || type === "boolean";
|
|
486
|
+
}
|
|
487
|
+
function toKebabCase(value) {
|
|
488
|
+
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
489
|
+
}
|
|
490
|
+
//#endregion
|
|
491
|
+
//#region packages/web-c/output-wc/src/generateRegistration.ts
|
|
492
|
+
function generateLazyRegistration(component, entryFileName) {
|
|
493
|
+
return `import { bootstrapLazy } from "@zeus-js/web-c-runtime";
|
|
494
|
+
${generateLazyManifest({
|
|
495
|
+
components: [component],
|
|
496
|
+
getEntryFileName: () => entryFileName
|
|
497
|
+
})}
|
|
498
|
+
export const component = components[0];
|
|
499
|
+
|
|
500
|
+
export function defineCustomElement(options = {}) {
|
|
501
|
+
bootstrapLazy([component], options);
|
|
502
|
+
}
|
|
503
|
+
`;
|
|
504
|
+
}
|
|
505
|
+
//#endregion
|
|
506
|
+
//#region packages/web-c/output-wc/src/generateVSCodeCustomData.ts
|
|
507
|
+
function generateVSCodeCustomData(customElementsJson) {
|
|
508
|
+
let manifest;
|
|
509
|
+
try {
|
|
510
|
+
manifest = JSON.parse(customElementsJson);
|
|
511
|
+
} catch {
|
|
512
|
+
throw new Error("[ZEUS_VSCODE_CUSTOM_DATA_INVALID] CEM input is not valid JSON.");
|
|
513
|
+
}
|
|
514
|
+
if ((manifest === null || manifest === void 0 ? void 0 : manifest.schemaVersion) !== "1.0.0" || !Array.isArray(manifest.modules)) throw new Error("[ZEUS_VSCODE_CUSTOM_DATA_INVALID] CEM input must use schemaVersion 1.0.0 and contain modules.");
|
|
515
|
+
const tags = manifest.modules.flatMap((module) => {
|
|
516
|
+
var _module$declarations;
|
|
517
|
+
return ((_module$declarations = module.declarations) !== null && _module$declarations !== void 0 ? _module$declarations : []).filter((declaration) => declaration.kind === "class" && declaration.customElement === true && typeof declaration.tagName === "string").map((declaration) => {
|
|
518
|
+
var _declaration$attribut;
|
|
519
|
+
const tagName = declaration.tagName;
|
|
520
|
+
const attributes = ((_declaration$attribut = declaration.attributes) !== null && _declaration$attribut !== void 0 ? _declaration$attribut : []).map((attribute) => {
|
|
521
|
+
var _attribute$type;
|
|
522
|
+
if (typeof attribute.name !== "string") throw new Error(`[ZEUS_VSCODE_CUSTOM_DATA_INVALID] <${tagName}> contains an attribute without a name.`);
|
|
523
|
+
const values = parseStringLiteralUnion((_attribute$type = attribute.type) === null || _attribute$type === void 0 ? void 0 : _attribute$type.text);
|
|
524
|
+
return {
|
|
525
|
+
name: attribute.name,
|
|
526
|
+
...attribute.description ? { description: attribute.description } : {},
|
|
527
|
+
...values ? { values: values.map((name) => ({ name })) } : {}
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
return {
|
|
531
|
+
name: tagName,
|
|
532
|
+
...declaration.description ? { description: declaration.description } : {},
|
|
533
|
+
...attributes.length > 0 ? { attributes } : {}
|
|
534
|
+
};
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
const names = /* @__PURE__ */ new Set();
|
|
538
|
+
for (const tag of tags) {
|
|
539
|
+
if (names.has(tag.name)) throw new Error(`[ZEUS_VSCODE_CUSTOM_DATA_INVALID] CEM declares <${tag.name}> more than once.`);
|
|
540
|
+
names.add(tag.name);
|
|
541
|
+
}
|
|
542
|
+
return `${JSON.stringify({
|
|
543
|
+
version: 1.1,
|
|
544
|
+
tags
|
|
545
|
+
}, null, 2)}\n`;
|
|
546
|
+
}
|
|
547
|
+
function parseStringLiteralUnion(typeText) {
|
|
548
|
+
if (!typeText) return void 0;
|
|
549
|
+
const parts = typeText.split(/\s+\|\s+/);
|
|
550
|
+
const values = [];
|
|
551
|
+
for (const part of parts) {
|
|
552
|
+
if (!part.startsWith("\"") || !part.endsWith("\"")) return void 0;
|
|
553
|
+
try {
|
|
554
|
+
const value = JSON.parse(part);
|
|
555
|
+
if (typeof value !== "string") return void 0;
|
|
556
|
+
values.push(value);
|
|
557
|
+
} catch {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return values.length > 0 ? values : void 0;
|
|
402
562
|
}
|
|
403
563
|
//#endregion
|
|
404
564
|
//#region packages/web-c/output-wc/src/index.ts
|
|
565
|
+
const outputWcModulePath = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
405
566
|
function wc(options = {}) {
|
|
406
567
|
var _options$register, _options$outDir, _options$stripPrefix, _options$manifestFile, _options$customElemen, _options$dts, _options$jsxDts, _options$index, _options$warnOnFileNa, _options$auto, _options$entryFileNam;
|
|
407
568
|
const registerMode = (_options$register = options.register) !== null && _options$register !== void 0 ? _options$register : "lazy";
|
|
@@ -476,15 +637,13 @@ function wc(options = {}) {
|
|
|
476
637
|
modules.push({
|
|
477
638
|
id: "zeus:wc:components.manifest",
|
|
478
639
|
fileName: joinPath("components.manifest.js"),
|
|
479
|
-
code:
|
|
480
|
-
components: ctx.manifest.components,
|
|
481
|
-
getEntryFileName: (tag) => getLazyEntryFileName(normalized.entryFileName, tag)
|
|
482
|
-
})
|
|
640
|
+
code: [...ctx.manifest.components.map((component, index) => `import { component as c${index} } from ${JSON.stringify(getVirtualComponentId(component))};`), `export const components = [${ctx.manifest.components.map((_, index) => `c${index}`).join(", ")}];`].join("\n")
|
|
483
641
|
});
|
|
484
642
|
modules.push({
|
|
485
643
|
id: "zeus:wc:loader",
|
|
486
644
|
fileName: joinPath("loader.js"),
|
|
487
|
-
code: generateLoader()
|
|
645
|
+
code: generateLoader(),
|
|
646
|
+
resolveFrom: outputWcModulePath
|
|
488
647
|
});
|
|
489
648
|
if (normalized.auto) modules.push({
|
|
490
649
|
id: "zeus:wc:auto",
|
|
@@ -501,13 +660,9 @@ function wc(options = {}) {
|
|
|
501
660
|
*/
|
|
502
661
|
modules.push({
|
|
503
662
|
id: getVirtualComponentId(component),
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
defineCustomElements();
|
|
508
|
-
|
|
509
|
-
export {};
|
|
510
|
-
`.trimStart()
|
|
663
|
+
fileName: joinPath(getFileName(component.tag)),
|
|
664
|
+
code: generateLazyRegistration(component, node_path.default.posix.relative(node_path.default.posix.dirname(joinPath(getFileName(component.tag))), joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag)))),
|
|
665
|
+
resolveFrom: outputWcModulePath
|
|
511
666
|
});
|
|
512
667
|
const fileName = joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag));
|
|
513
668
|
modules.push({
|
|
@@ -517,7 +672,8 @@ export {};
|
|
|
517
672
|
component,
|
|
518
673
|
outPath: fileName,
|
|
519
674
|
sourceImport: toAbsoluteImportPath(ctx.root, component.source)
|
|
520
|
-
})
|
|
675
|
+
}),
|
|
676
|
+
resolveFrom: outputWcModulePath
|
|
521
677
|
});
|
|
522
678
|
} else {
|
|
523
679
|
const fileName = joinPath(getFileName(component.tag));
|
|
@@ -562,12 +718,17 @@ export {};
|
|
|
562
718
|
const isLazy = normalized.register === "lazy";
|
|
563
719
|
if (isLazy) {
|
|
564
720
|
if (dts) {
|
|
565
|
-
const loaderDts = (0, _zeus_js_component_dts.generateLoaderDts)(ctx.manifest);
|
|
721
|
+
const loaderDts = [...jsxDts ? ["import './types/jsx'", ""] : [], (0, _zeus_js_component_dts.generateLoaderDts)(ctx.manifest)].join("\n");
|
|
566
722
|
files.push({
|
|
567
723
|
type: "asset",
|
|
568
724
|
fileName: joinPath("loader.d.ts"),
|
|
569
725
|
source: loaderDts
|
|
570
726
|
});
|
|
727
|
+
for (const component of ctx.manifest.components) files.push({
|
|
728
|
+
type: "asset",
|
|
729
|
+
fileName: joinPath(getFileName(component.tag).replace(/\.js$/, ".d.ts")),
|
|
730
|
+
source: "export declare function defineCustomElement(options?: { registry?: CustomElementRegistry }): void\n"
|
|
731
|
+
});
|
|
571
732
|
if (normalized.index) files.push({
|
|
572
733
|
type: "asset",
|
|
573
734
|
fileName: joinPath("index.d.ts"),
|
|
@@ -585,14 +746,22 @@ export {};
|
|
|
585
746
|
fileName: normalized.manifestFile,
|
|
586
747
|
source: generateZeusComponentsManifest(ctx.manifest)
|
|
587
748
|
});
|
|
588
|
-
if (normalized.customElementsFile)
|
|
589
|
-
|
|
590
|
-
fileName: normalized.customElementsFile,
|
|
591
|
-
source: generateCustomElementsJson({
|
|
749
|
+
if (normalized.customElementsFile) {
|
|
750
|
+
const customElementsJson = generateCustomElementsJson({
|
|
592
751
|
manifest: ctx.manifest,
|
|
593
752
|
getModulePath: (component) => isLazy ? joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag)) : joinPath(getFileName(component.tag))
|
|
594
|
-
})
|
|
595
|
-
|
|
753
|
+
});
|
|
754
|
+
files.push({
|
|
755
|
+
type: "asset",
|
|
756
|
+
fileName: normalized.customElementsFile,
|
|
757
|
+
source: customElementsJson
|
|
758
|
+
});
|
|
759
|
+
files.push({
|
|
760
|
+
type: "asset",
|
|
761
|
+
fileName: "vscode.html-custom-data.json",
|
|
762
|
+
source: generateVSCodeCustomData(customElementsJson)
|
|
763
|
+
});
|
|
764
|
+
}
|
|
596
765
|
if (!isLazy && (dts || jsxDts)) {
|
|
597
766
|
const dtsFiles = (0, _zeus_js_component_dts.generateWCDtsFiles)(ctx.manifest, {
|
|
598
767
|
outDir: _outDir,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeus-js/output-wc",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.1-beta.
|
|
4
|
+
"version": "0.1.1-beta.20",
|
|
5
5
|
"description": "Zeus Web Component output plugin",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@zeus-js/component-analyzer": "0.1.1-beta.
|
|
52
|
-
"@zeus-js/
|
|
53
|
-
"@zeus-js/runtime
|
|
54
|
-
"@zeus-js/
|
|
55
|
-
"@zeus-js/
|
|
51
|
+
"@zeus-js/component-analyzer": "0.1.1-beta.20",
|
|
52
|
+
"@zeus-js/bundler-plugin": "0.1.1-beta.20",
|
|
53
|
+
"@zeus-js/web-c-runtime": "0.1.1-beta.20",
|
|
54
|
+
"@zeus-js/component-dts": "0.1.1-beta.20",
|
|
55
|
+
"@zeus-js/runtime-dom": "0.1.1-beta.20"
|
|
56
56
|
},
|
|
57
57
|
"author": "Baicie",
|
|
58
58
|
"buildOptions": {
|