@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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-wc v0.1.1-beta.2
2
+ * output-wc v0.1.1-beta.20
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -9,7 +9,7 @@ Object.defineProperties(exports, {
9
9
  });
10
10
  const ZEUS_OUTPUT_WC_CAPABILITIES = {
11
11
  packageName: "@zeus-js/output-wc",
12
- version: "0.1.1-beta.2",
12
+ version: "0.1.1-beta.20",
13
13
  output: {
14
14
  webComponent: true,
15
15
  customElements: true,
@@ -1,6 +1,6 @@
1
1
  const ZEUS_OUTPUT_WC_CAPABILITIES = {
2
2
  packageName: "@zeus-js/output-wc",
3
- version: "0.1.1-beta.2",
3
+ version: "0.1.1-beta.20",
4
4
  output: {
5
5
  webComponent: true,
6
6
  customElements: true,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-wc v0.1.1-beta.2
2
+ * output-wc v0.1.1-beta.20
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -9,7 +9,7 @@ Object.defineProperties(exports, {
9
9
  });
10
10
  const ZEUS_OUTPUT_WC_CAPABILITIES = {
11
11
  packageName: "@zeus-js/output-wc",
12
- version: "0.1.1-beta.2",
12
+ version: "0.1.1-beta.20",
13
13
  output: {
14
14
  webComponent: true,
15
15
  customElements: true,
@@ -1,6 +1,6 @@
1
1
  const ZEUS_OUTPUT_WC_CAPABILITIES = {
2
2
  packageName: "@zeus-js/output-wc",
3
- version: "0.1.1-beta.2",
3
+ version: "0.1.1-beta.20",
4
4
  output: {
5
5
  webComponent: true,
6
6
  customElements: true,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-wc v0.1.1-beta.2
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.keys((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {}).map((name) => {
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(name, oldValue, newValue) {`,
237
- ` lifecycle.current()?.propertyChanged(name, oldValue, newValue);`,
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/generateManifest.ts
400
- function generateZeusComponentsManifest(manifest) {
401
- return `${JSON.stringify(manifest, null, 2)}\n`;
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: generateLazyManifest({
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
- code: `
505
- import { defineCustomElements } from "zeus:wc:loader";
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) files.push({
589
- type: "asset",
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,