@zeus-js/output-wc 0.1.1-beta.13 → 0.1.1-beta.15

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.13
2
+ * output-wc v0.1.1-beta.15
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.13",
12
+ version: "0.1.1-beta.15",
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.13",
3
+ version: "0.1.1-beta.15",
4
4
  output: {
5
5
  webComponent: true,
6
6
  customElements: true,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-wc v0.1.1-beta.13
2
+ * output-wc v0.1.1-beta.15
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.13",
12
+ version: "0.1.1-beta.15",
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.13",
3
+ version: "0.1.1-beta.15",
4
4
  output: {
5
5
  webComponent: true,
6
6
  customElements: true,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-wc v0.1.1-beta.13
2
+ * output-wc v0.1.1-beta.15
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -31,11 +31,87 @@ 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 : {})) 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.`);
69
+ for (const [propName, prop] of Object.entries((_component$props2 = component.props) !== null && _component$props2 !== void 0 ? _component$props2 : {})) {
70
+ if (prop.hasDefault !== void 0 && typeof prop.hasDefault !== "boolean") throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName}.hasDefault must be boolean.`);
71
+ 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.`);
72
+ 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.`);
73
+ 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.`);
74
+ if (Object.prototype.hasOwnProperty.call(prop, "default")) {
75
+ if (prop.default === void 0) throw new Error(`[ZEUS_WC_INVALID_DEFAULT_META] ${componentPath}.props.${propName}.default cannot be undefined.`);
76
+ assertJsonSafe(prop.default, `${componentPath}.props.${propName}.default`, /* @__PURE__ */ new Set(), "ZEUS_WC_INVALID_DEFAULT_META", true);
77
+ }
78
+ }
79
+ }
80
+ assertJsonSafe(manifest, "manifest");
81
+ }
82
+ function assertJsonSafe(value, path, parents = /* @__PURE__ */ new Set(), code = "ZEUS_WC_INVALID_MANIFEST", rejectUndefined = false) {
83
+ if (value === void 0) {
84
+ if (rejectUndefined) throw invalidManifest(path, "undefined values are not supported", code);
85
+ return;
86
+ }
87
+ if (value === null) return;
88
+ if (typeof value === "string" || typeof value === "boolean") return;
89
+ if (typeof value === "number") {
90
+ if (!Number.isFinite(value) || Object.is(value, -0)) throw invalidManifest(path, "numbers must be finite and cannot be -0", code);
91
+ return;
92
+ }
93
+ if (typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") throw invalidManifest(path, "functions, symbols, and bigint values are not supported", code);
94
+ if (typeof value !== "object") throw invalidManifest(path, "value is not JSON-safe", code);
95
+ if (parents.has(value)) throw invalidManifest(path, "cyclic values are not supported", code);
96
+ const prototype = Object.getPrototypeOf(value);
97
+ if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) throw invalidManifest(path, "only plain objects and arrays are supported", code);
98
+ if (Object.getOwnPropertySymbols(value).length > 0) throw invalidManifest(path, "symbol keys are not supported", code);
99
+ parents.add(value);
100
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
101
+ if ("get" in descriptor || "set" in descriptor) throw invalidManifest(`${path}.${key}`, "accessor properties are not supported", code);
102
+ if (descriptor.value === void 0 && !rejectUndefined) continue;
103
+ assertJsonSafe(descriptor.value, Array.isArray(value) ? `${path}[${key}]` : `${path}.${key}`, parents, code, rejectUndefined);
104
+ }
105
+ parents.delete(value);
106
+ }
107
+ function invalidManifest(path, reason, code) {
108
+ return /* @__PURE__ */ new Error(`[${code}] ${path}: ${reason}.`);
109
+ }
110
+ //#endregion
36
111
  //#region packages/web-c/output-wc/src/generateCustomElementsJson.ts
37
112
  function generateCustomElementsJson(options) {
38
113
  const { manifest, getModulePath } = options;
114
+ validateComponentManifest(manifest);
39
115
  const result = {
40
116
  schemaVersion: "1.0.0",
41
117
  modules: manifest.components.map((component) => {
@@ -97,14 +173,24 @@ function generateMembers(component) {
97
173
  default: prop.default === void 0 ? void 0 : JSON.stringify(prop.default)
98
174
  };
99
175
  });
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
- });
176
+ const methods = Object.entries((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {}).map(([name, method]) => generateMethodMember(name, method));
106
177
  return [...fields, ...methods];
107
178
  }
179
+ function generateMethodMember(name, method) {
180
+ var _method$returns, _method$returns2;
181
+ const member = {
182
+ kind: "method",
183
+ name,
184
+ 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" } }
185
+ };
186
+ if (method.parameters) member.parameters = method.parameters.map((parameter) => ({
187
+ name: parameter.name,
188
+ type: { text: parameter.type },
189
+ optional: parameter.optional,
190
+ rest: parameter.rest
191
+ }));
192
+ return member;
193
+ }
108
194
  function generateEvents(component) {
109
195
  return Object.entries(component.events).map(([key, event]) => {
110
196
  var _event$name, _event$key;
@@ -179,6 +265,15 @@ function generateWCEntry(options) {
179
265
  `import { ${component.exportName} } from ${JSON.stringify(source)};`,
180
266
  "",
181
267
  `export { ${component.exportName} };`,
268
+ "",
269
+ `export function defineCustomElement(options = {}) {`,
270
+ ` const registry = options.registry ?? (typeof customElements === 'undefined' ? undefined : customElements);`,
271
+ ` if (!registry) return;`,
272
+ ` const existing = registry.get(${JSON.stringify(component.tag)});`,
273
+ ` if (existing === ${component.exportName}) return;`,
274
+ ` if (existing) throw new Error(${JSON.stringify(`[ZEUS_WC_DUPLICATE_TAG] <${component.tag}> is already registered with a different definition.`)});`,
275
+ ` registry.define(${JSON.stringify(component.tag)}, ${component.exportName});`,
276
+ `}`,
182
277
  ""
183
278
  ].join("\n");
184
279
  }
@@ -204,16 +299,19 @@ function getVirtualIndexId() {
204
299
  //#region packages/web-c/output-wc/src/generateLazyEntry.ts
205
300
  function generateLazyEntry(options) {
206
301
  const { component, outPath, sourceImport } = options;
207
- const source = sourceImport !== null && sourceImport !== void 0 ? sourceImport : toRelativeImport(component.source, outPath);
302
+ const source = `${sourceImport !== null && sourceImport !== void 0 ? sourceImport : toRelativeImport(component.source, outPath)}?zeus-lazy-component=${component.exportName}`;
208
303
  return [
209
- `import { createCustomElementMountLifecycle, mountElementDefinition } from "@zeus-js/runtime-dom";`,
304
+ `import { createCustomElementMountLifecycle, getElementDefinition, mountElementDefinition } from "@zeus-js/runtime-dom";`,
305
+ `import { resolveHostProperties } from "@zeus-js/web-c-runtime";`,
210
306
  `import { ${component.exportName} } from ${JSON.stringify(source)};`,
211
307
  "",
212
308
  `export function createComponent(hostRef) {`,
309
+ ` resolveHostProperties(hostRef, getElementDefinition(${component.exportName}).propDefs);`,
213
310
  ` const mountState = {`,
214
311
  ` attributeProps: hostRef.attributeProps,`,
215
312
  ` internals: hostRef.internals,`,
216
313
  ` reflectingAttrs: hostRef.reflectingAttrs,`,
314
+ ` exposedMethods: hostRef.exposedMethods,`,
217
315
  ` };`,
218
316
  ` const lifecycle = createCustomElementMountLifecycle(() =>`,
219
317
  ` mountElementDefinition(`,
@@ -233,8 +331,8 @@ function generateLazyEntry(options) {
233
331
  ` lifecycle.disconnect();`,
234
332
  ` },`,
235
333
  "",
236
- ` propertyChanged(name, oldValue, newValue) {`,
237
- ` lifecycle.current()?.propertyChanged(name, oldValue, newValue);`,
334
+ ` propertyChanged(change) {`,
335
+ ` lifecycle.current()?.propertyChanged(change);`,
238
336
  ` },`,
239
337
  "",
240
338
  ` formAssociated(form) {`,
@@ -268,54 +366,6 @@ function toRelativeImport(source, outPath) {
268
366
  return [...outParts.slice(common).map(() => ".."), ...sourceParts.slice(common)].join("/");
269
367
  }
270
368
  //#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
369
  //#region packages/web-c/output-wc/src/generateLoader.ts
320
370
  function generateLoader() {
321
371
  return `import { bootstrapLazy } from "@zeus-js/web-c-runtime";
@@ -325,24 +375,11 @@ const componentsByTagName = new Map(
325
375
  components.map(component => [component.tagName, component]),
326
376
  );
327
377
 
328
- const definedTagsByRegistry = new WeakMap();
329
-
330
378
  function resolveRegistry(options) {
331
379
  return options.registry ??
332
380
  (typeof customElements === "undefined" ? undefined : customElements);
333
381
  }
334
382
 
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
383
  export function defineCustomElement(tagName, options = {}) {
347
384
  const registry = resolveRegistry(options);
348
385
 
@@ -356,16 +393,7 @@ export function defineCustomElement(tagName, options = {}) {
356
393
  throw new Error(\`[zeus:web-c] Unknown custom element: <\${tagName}>.\`);
357
394
  }
358
395
 
359
- const definedTags = getDefinedTags(registry);
360
-
361
- if (definedTags.has(tagName) || registry.get(tagName)) {
362
- definedTags.add(tagName);
363
- return;
364
- }
365
-
366
396
  bootstrapLazy([component], { registry });
367
-
368
- definedTags.add(tagName);
369
397
  }
370
398
 
371
399
  export function defineCustomElements(options = {}) {
@@ -374,8 +402,6 @@ export function defineCustomElements(options = {}) {
374
402
  }
375
403
  }
376
404
 
377
- export const defineLazyElement = defineCustomElement;
378
- export const defineLazyElements = defineCustomElements;
379
405
  `;
380
406
  }
381
407
  function generateAutoEntry() {
@@ -390,18 +416,149 @@ function generateLazyIndex() {
390
416
  return `export {
391
417
  defineCustomElement,
392
418
  defineCustomElements,
393
- defineLazyElement,
394
- defineLazyElements,
395
419
  } from "./loader.js";
396
420
  `;
397
421
  }
398
422
  //#endregion
399
- //#region packages/web-c/output-wc/src/generateManifest.ts
400
- function generateZeusComponentsManifest(manifest) {
401
- return `${JSON.stringify(manifest, null, 2)}\n`;
423
+ //#region packages/web-c/output-wc/src/generateLazyManifest.ts
424
+ function generateLazyManifest(options) {
425
+ const { components, getEntryFileName } = options;
426
+ return `export const components = [
427
+ ${components.map((component) => {
428
+ var _component$runtimePro, _component$methods, _component$meta$shado, _component$meta, _component$meta$formA, _component$meta2;
429
+ const entryFile = getEntryFileName(component.tag).replace(/\\/g, "/");
430
+ const props = generatePropsArray((_component$runtimePro = component.runtimeProps) !== null && _component$runtimePro !== void 0 ? _component$runtimePro : component.props);
431
+ const methods = Object.keys((_component$methods = component.methods) !== null && _component$methods !== void 0 ? _component$methods : {});
432
+ const importPath = entryFile.startsWith(".") ? JSON.stringify(entryFile) : JSON.stringify(`./${entryFile}`);
433
+ const methodLine = methods.length ? ` methods: ${JSON.stringify(methods)},\n` : "";
434
+ return ` {
435
+ tagName: ${JSON.stringify(component.tag)},
436
+ 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},
437
+ 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},
438
+ load: () => import(${importPath}),
439
+ props: ${props},
440
+ ${methodLine}
441
+ }`;
442
+ }).join(",\n")}
443
+ ];
444
+ `;
445
+ }
446
+ function generatePropsArray(props) {
447
+ const entries = Object.entries(props);
448
+ if (entries.length === 0) return "[]";
449
+ return `[\n${entries.map(([name, prop]) => {
450
+ const parts = [`name: ${JSON.stringify(name)}`];
451
+ if (!isAttributeBackedType(prop.type) && !prop.deserialize || prop.attr === false) parts.push("attrName: false");
452
+ else {
453
+ var _prop$attr;
454
+ const attrName = (_prop$attr = prop.attr) !== null && _prop$attr !== void 0 ? _prop$attr : toKebabCase(name);
455
+ if (attrName !== toKebabCase(name)) parts.push(`attrName: ${JSON.stringify(attrName)}`);
456
+ }
457
+ parts.push(`type: ${JSON.stringify(prop.type)}`);
458
+ if (isJsonSafeDefault(prop.default)) {
459
+ const encoded = JSON.stringify(prop.default);
460
+ parts.push(`default: ${typeof prop.default === "object" && prop.default !== null ? `JSON.parse(${JSON.stringify(encoded)})` : encoded}`);
461
+ }
462
+ if (prop.reflect && (isAttributeBackedType(prop.type) || Boolean(prop.serialize))) parts.push("reflect: true");
463
+ if (prop.serialize) parts.push("serialize: true");
464
+ if (prop.deserialize) parts.push("deserialize: true");
465
+ return ` { ${parts.join(", ")} }`;
466
+ }).join(",\n")}\n ]`;
467
+ }
468
+ function isJsonSafeDefault(value, parents = /* @__PURE__ */ new Set()) {
469
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
470
+ if (typeof value === "number") return Number.isFinite(value) && !Object.is(value, -0);
471
+ if (typeof value !== "object" || parents.has(value)) return false;
472
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) return false;
473
+ if (Object.getOwnPropertySymbols(value).length) return false;
474
+ parents.add(value);
475
+ const descriptors = Object.getOwnPropertyDescriptors(value);
476
+ 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));
477
+ parents.delete(value);
478
+ return valid;
479
+ }
480
+ function isAttributeBackedType(type) {
481
+ return type === "string" || type === "number" || type === "boolean";
482
+ }
483
+ function toKebabCase(value) {
484
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
485
+ }
486
+ //#endregion
487
+ //#region packages/web-c/output-wc/src/generateRegistration.ts
488
+ function generateLazyRegistration(component, entryFileName) {
489
+ return `import { bootstrapLazy } from "@zeus-js/web-c-runtime";
490
+ ${generateLazyManifest({
491
+ components: [component],
492
+ getEntryFileName: () => entryFileName
493
+ })}
494
+ export const component = components[0];
495
+
496
+ export function defineCustomElement(options = {}) {
497
+ bootstrapLazy([component], options);
498
+ }
499
+ `;
500
+ }
501
+ //#endregion
502
+ //#region packages/web-c/output-wc/src/generateVSCodeCustomData.ts
503
+ function generateVSCodeCustomData(customElementsJson) {
504
+ let manifest;
505
+ try {
506
+ manifest = JSON.parse(customElementsJson);
507
+ } catch {
508
+ throw new Error("[ZEUS_VSCODE_CUSTOM_DATA_INVALID] CEM input is not valid JSON.");
509
+ }
510
+ 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.");
511
+ const tags = manifest.modules.flatMap((module) => {
512
+ var _module$declarations;
513
+ 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) => {
514
+ var _declaration$attribut;
515
+ const tagName = declaration.tagName;
516
+ const attributes = ((_declaration$attribut = declaration.attributes) !== null && _declaration$attribut !== void 0 ? _declaration$attribut : []).map((attribute) => {
517
+ var _attribute$type;
518
+ if (typeof attribute.name !== "string") throw new Error(`[ZEUS_VSCODE_CUSTOM_DATA_INVALID] <${tagName}> contains an attribute without a name.`);
519
+ const values = parseStringLiteralUnion((_attribute$type = attribute.type) === null || _attribute$type === void 0 ? void 0 : _attribute$type.text);
520
+ return {
521
+ name: attribute.name,
522
+ ...attribute.description ? { description: attribute.description } : {},
523
+ ...values ? { values: values.map((name) => ({ name })) } : {}
524
+ };
525
+ });
526
+ return {
527
+ name: tagName,
528
+ ...declaration.description ? { description: declaration.description } : {},
529
+ ...attributes.length > 0 ? { attributes } : {}
530
+ };
531
+ });
532
+ });
533
+ const names = /* @__PURE__ */ new Set();
534
+ for (const tag of tags) {
535
+ if (names.has(tag.name)) throw new Error(`[ZEUS_VSCODE_CUSTOM_DATA_INVALID] CEM declares <${tag.name}> more than once.`);
536
+ names.add(tag.name);
537
+ }
538
+ return `${JSON.stringify({
539
+ version: 1.1,
540
+ tags
541
+ }, null, 2)}\n`;
542
+ }
543
+ function parseStringLiteralUnion(typeText) {
544
+ if (!typeText) return void 0;
545
+ const parts = typeText.split(/\s+\|\s+/);
546
+ const values = [];
547
+ for (const part of parts) {
548
+ if (!part.startsWith("\"") || !part.endsWith("\"")) return void 0;
549
+ try {
550
+ const value = JSON.parse(part);
551
+ if (typeof value !== "string") return void 0;
552
+ values.push(value);
553
+ } catch {
554
+ return;
555
+ }
556
+ }
557
+ return values.length > 0 ? values : void 0;
402
558
  }
403
559
  //#endregion
404
560
  //#region packages/web-c/output-wc/src/index.ts
561
+ const outputWcModulePath = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
405
562
  function wc(options = {}) {
406
563
  var _options$register, _options$outDir, _options$stripPrefix, _options$manifestFile, _options$customElemen, _options$dts, _options$jsxDts, _options$index, _options$warnOnFileNa, _options$auto, _options$entryFileNam;
407
564
  const registerMode = (_options$register = options.register) !== null && _options$register !== void 0 ? _options$register : "lazy";
@@ -476,15 +633,13 @@ function wc(options = {}) {
476
633
  modules.push({
477
634
  id: "zeus:wc:components.manifest",
478
635
  fileName: joinPath("components.manifest.js"),
479
- code: generateLazyManifest({
480
- components: ctx.manifest.components,
481
- getEntryFileName: (tag) => getLazyEntryFileName(normalized.entryFileName, tag)
482
- })
636
+ 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
637
  });
484
638
  modules.push({
485
639
  id: "zeus:wc:loader",
486
640
  fileName: joinPath("loader.js"),
487
- code: generateLoader()
641
+ code: generateLoader(),
642
+ resolveFrom: outputWcModulePath
488
643
  });
489
644
  if (normalized.auto) modules.push({
490
645
  id: "zeus:wc:auto",
@@ -501,13 +656,9 @@ function wc(options = {}) {
501
656
  */
502
657
  modules.push({
503
658
  id: getVirtualComponentId(component),
504
- code: `
505
- import { defineCustomElements } from "zeus:wc:loader";
506
-
507
- defineCustomElements();
508
-
509
- export {};
510
- `.trimStart()
659
+ fileName: joinPath(getFileName(component.tag)),
660
+ code: generateLazyRegistration(component, node_path.default.posix.relative(node_path.default.posix.dirname(joinPath(getFileName(component.tag))), joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag)))),
661
+ resolveFrom: outputWcModulePath
511
662
  });
512
663
  const fileName = joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag));
513
664
  modules.push({
@@ -517,7 +668,8 @@ export {};
517
668
  component,
518
669
  outPath: fileName,
519
670
  sourceImport: toAbsoluteImportPath(ctx.root, component.source)
520
- })
671
+ }),
672
+ resolveFrom: outputWcModulePath
521
673
  });
522
674
  } else {
523
675
  const fileName = joinPath(getFileName(component.tag));
@@ -568,6 +720,11 @@ export {};
568
720
  fileName: joinPath("loader.d.ts"),
569
721
  source: loaderDts
570
722
  });
723
+ for (const component of ctx.manifest.components) files.push({
724
+ type: "asset",
725
+ fileName: joinPath(getFileName(component.tag).replace(/\.js$/, ".d.ts")),
726
+ source: "export declare function defineCustomElement(options?: { registry?: CustomElementRegistry }): void\n"
727
+ });
571
728
  if (normalized.index) files.push({
572
729
  type: "asset",
573
730
  fileName: joinPath("index.d.ts"),
@@ -585,14 +742,22 @@ export {};
585
742
  fileName: normalized.manifestFile,
586
743
  source: generateZeusComponentsManifest(ctx.manifest)
587
744
  });
588
- if (normalized.customElementsFile) files.push({
589
- type: "asset",
590
- fileName: normalized.customElementsFile,
591
- source: generateCustomElementsJson({
745
+ if (normalized.customElementsFile) {
746
+ const customElementsJson = generateCustomElementsJson({
592
747
  manifest: ctx.manifest,
593
748
  getModulePath: (component) => isLazy ? joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag)) : joinPath(getFileName(component.tag))
594
- })
595
- });
749
+ });
750
+ files.push({
751
+ type: "asset",
752
+ fileName: normalized.customElementsFile,
753
+ source: customElementsJson
754
+ });
755
+ files.push({
756
+ type: "asset",
757
+ fileName: "vscode.html-custom-data.json",
758
+ source: generateVSCodeCustomData(customElementsJson)
759
+ });
760
+ }
596
761
  if (!isLazy && (dts || jsxDts)) {
597
762
  const dtsFiles = (0, _zeus_js_component_dts.generateWCDtsFiles)(ctx.manifest, {
598
763
  outDir: _outDir,