@zeus-js/output-vue-wrapper 0.1.0-beta.0
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.
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* output-vue-wrapper v0.1.0-beta.0
|
|
3
|
+
* (c) 2026 baicie
|
|
4
|
+
* Released under the MIT License.
|
|
5
|
+
**/
|
|
6
|
+
Object.defineProperties(exports, {
|
|
7
|
+
__esModule: { value: true },
|
|
8
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
9
|
+
});
|
|
10
|
+
let _zeus_js_bundler_plugin = require("@zeus-js/bundler-plugin");
|
|
11
|
+
let _zeus_js_component_dts = require("@zeus-js/component-dts");
|
|
12
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueIndex.ts
|
|
13
|
+
function generateVueIndex(components, options) {
|
|
14
|
+
const lines = [];
|
|
15
|
+
for (const component of components) {
|
|
16
|
+
const fileName = options.getFileName(component.tag);
|
|
17
|
+
lines.push(`export * from './${fileName}';`);
|
|
18
|
+
}
|
|
19
|
+
lines.push("");
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
|
|
24
|
+
function generateVueWrapper(input) {
|
|
25
|
+
const { component, wcModuleId } = input;
|
|
26
|
+
const propNames = Object.keys(component.props);
|
|
27
|
+
const eventNames = Object.keys(component.events);
|
|
28
|
+
const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
|
|
29
|
+
const syncPropsBody = generateVuePropSyncLines(propNames);
|
|
30
|
+
const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
|
|
31
|
+
const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
|
|
32
|
+
return `
|
|
33
|
+
import {
|
|
34
|
+
cloneVNode,
|
|
35
|
+
defineComponent,
|
|
36
|
+
h,
|
|
37
|
+
onBeforeUnmount,
|
|
38
|
+
onMounted,
|
|
39
|
+
ref,
|
|
40
|
+
watch,
|
|
41
|
+
} from 'vue';
|
|
42
|
+
|
|
43
|
+
import ${JSON.stringify(wcModuleId)};
|
|
44
|
+
|
|
45
|
+
const PROP_KEYS = ${JSON.stringify(propNames)};
|
|
46
|
+
const EVENT_NAMES = ${JSON.stringify(eventNames)};
|
|
47
|
+
const NAMED_SLOTS = ${JSON.stringify(slotNames)};
|
|
48
|
+
|
|
49
|
+
export const ${component.name} = defineComponent({
|
|
50
|
+
name: ${JSON.stringify(component.name)},
|
|
51
|
+
|
|
52
|
+
props: {
|
|
53
|
+
${generateVueProps(component)}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
emits: EVENT_NAMES,
|
|
57
|
+
|
|
58
|
+
setup(props, { attrs, slots, emit }) {
|
|
59
|
+
const elRef = ref(null);
|
|
60
|
+
const cleanups = [];
|
|
61
|
+
|
|
62
|
+
const syncProps = () => {
|
|
63
|
+
const el = elRef.value;
|
|
64
|
+
if (!el) return;
|
|
65
|
+
|
|
66
|
+
${syncPropsBody}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
onMounted(() => {
|
|
70
|
+
syncProps();
|
|
71
|
+
|
|
72
|
+
const el = elRef.value;
|
|
73
|
+
if (!el) return;
|
|
74
|
+
|
|
75
|
+
for (const eventName of EVENT_NAMES) {
|
|
76
|
+
const handler = event => emit(eventName, event);
|
|
77
|
+
el.addEventListener(eventName, handler);
|
|
78
|
+
cleanups.push(() => el.removeEventListener(eventName, handler));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
onBeforeUnmount(() => {
|
|
83
|
+
for (const cleanup of cleanups) cleanup();
|
|
84
|
+
cleanups.length = 0;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
${watchBlock}
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
const children = [];
|
|
91
|
+
|
|
92
|
+
if (slots.default) {
|
|
93
|
+
children.push(...slots.default());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const name of NAMED_SLOTS) {
|
|
97
|
+
const slot = slots[name];
|
|
98
|
+
if (!slot) continue;
|
|
99
|
+
|
|
100
|
+
for (const vnode of slot()) {
|
|
101
|
+
children.push(withSlot(name, vnode));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return h(
|
|
106
|
+
${JSON.stringify(component.tag)},
|
|
107
|
+
{
|
|
108
|
+
...attrs,
|
|
109
|
+
ref: elRef,
|
|
110
|
+
},
|
|
111
|
+
children,
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
function withSlot(name, vnode) {
|
|
118
|
+
if (!vnode) return vnode;
|
|
119
|
+
|
|
120
|
+
if (typeof vnode === 'string') {
|
|
121
|
+
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return cloneVNode(vnode, { slot: name });
|
|
125
|
+
}
|
|
126
|
+
`.trimStart();
|
|
127
|
+
}
|
|
128
|
+
function generateVueProps(component) {
|
|
129
|
+
return Object.entries(component.props).map(([name, prop]) => {
|
|
130
|
+
return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
|
|
131
|
+
}).join(",\n ");
|
|
132
|
+
}
|
|
133
|
+
function toVuePropOption(prop) {
|
|
134
|
+
var _typeMap$prop$type;
|
|
135
|
+
const type = (_typeMap$prop$type = {
|
|
136
|
+
string: "String",
|
|
137
|
+
number: "Number",
|
|
138
|
+
boolean: "Boolean",
|
|
139
|
+
object: "Object",
|
|
140
|
+
array: "Array",
|
|
141
|
+
unknown: "null"
|
|
142
|
+
}[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
|
|
143
|
+
if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
|
|
144
|
+
return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
|
|
145
|
+
}
|
|
146
|
+
function generateVuePropSyncLines(propNames) {
|
|
147
|
+
if (propNames.length === 0) return "// no props to sync";
|
|
148
|
+
return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region packages/web-c/output-vue-wrapper/src/index.ts
|
|
152
|
+
function vueWrapper(options = {}) {
|
|
153
|
+
var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
|
|
154
|
+
const normalized = {
|
|
155
|
+
outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
|
|
156
|
+
stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
|
|
157
|
+
fileName: options.fileName,
|
|
158
|
+
dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
|
|
159
|
+
globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
|
|
160
|
+
index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
name: "zeus-output-vue-wrapper",
|
|
164
|
+
external: ["vue"],
|
|
165
|
+
setup(ctx) {
|
|
166
|
+
ctx.outputs.register("vue", {
|
|
167
|
+
outDir: normalized.outDir,
|
|
168
|
+
stripPrefix: normalized.stripPrefix,
|
|
169
|
+
fileName: normalized.fileName ? (tag) => normalized.fileName(tag) : void 0
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
virtualModules(ctx) {
|
|
173
|
+
if (!ctx.outputs.has("wc")) ctx.error("[zeus-output-vue-wrapper] vue() requires wc() plugin.");
|
|
174
|
+
const modules = [];
|
|
175
|
+
for (const component of ctx.manifest.components) modules.push({
|
|
176
|
+
id: `zeus:vue:${component.tag}`,
|
|
177
|
+
fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
|
|
178
|
+
code: generateVueWrapper({
|
|
179
|
+
component,
|
|
180
|
+
wcModuleId: `zeus:wc:${component.tag}`
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
if (normalized.index) modules.push({
|
|
184
|
+
id: "zeus:vue:index",
|
|
185
|
+
fileName: ctx.outputs.join("vue", "index.js"),
|
|
186
|
+
code: generateVueIndex(ctx.manifest.components, { getFileName: (tag) => ctx.outputs.getFileName("vue", tag) })
|
|
187
|
+
});
|
|
188
|
+
return modules;
|
|
189
|
+
},
|
|
190
|
+
generateBundle(ctx) {
|
|
191
|
+
const files = [];
|
|
192
|
+
if ((0, _zeus_js_bundler_plugin.resolvePluginDts)(normalized.dts, ctx)) files.push({
|
|
193
|
+
type: "asset",
|
|
194
|
+
fileName: ctx.outputs.join("vue", "index.d.ts"),
|
|
195
|
+
source: (0, _zeus_js_component_dts.generateVueDts)(ctx.manifest)
|
|
196
|
+
});
|
|
197
|
+
if ((0, _zeus_js_bundler_plugin.resolvePluginDts)(normalized.globalDts, ctx)) files.push({
|
|
198
|
+
type: "asset",
|
|
199
|
+
fileName: ctx.outputs.join("vue", "global.d.ts"),
|
|
200
|
+
source: (0, _zeus_js_component_dts.generateVueGlobalDts)(ctx.manifest)
|
|
201
|
+
});
|
|
202
|
+
return files;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
exports.default = vueWrapper;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* output-vue-wrapper v0.1.0-beta.0
|
|
3
|
+
* (c) 2026 baicie
|
|
4
|
+
* Released under the MIT License.
|
|
5
|
+
**/
|
|
6
|
+
Object.defineProperties(exports, {
|
|
7
|
+
__esModule: { value: true },
|
|
8
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
9
|
+
});
|
|
10
|
+
let _zeus_js_bundler_plugin = require("@zeus-js/bundler-plugin");
|
|
11
|
+
let _zeus_js_component_dts = require("@zeus-js/component-dts");
|
|
12
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueIndex.ts
|
|
13
|
+
function generateVueIndex(components, options) {
|
|
14
|
+
const lines = [];
|
|
15
|
+
for (const component of components) {
|
|
16
|
+
const fileName = options.getFileName(component.tag);
|
|
17
|
+
lines.push(`export * from './${fileName}';`);
|
|
18
|
+
}
|
|
19
|
+
lines.push("");
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
|
|
24
|
+
function generateVueWrapper(input) {
|
|
25
|
+
const { component, wcModuleId } = input;
|
|
26
|
+
const propNames = Object.keys(component.props);
|
|
27
|
+
const eventNames = Object.keys(component.events);
|
|
28
|
+
const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
|
|
29
|
+
const syncPropsBody = generateVuePropSyncLines(propNames);
|
|
30
|
+
const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
|
|
31
|
+
const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
|
|
32
|
+
return `
|
|
33
|
+
import {
|
|
34
|
+
cloneVNode,
|
|
35
|
+
defineComponent,
|
|
36
|
+
h,
|
|
37
|
+
onBeforeUnmount,
|
|
38
|
+
onMounted,
|
|
39
|
+
ref,
|
|
40
|
+
watch,
|
|
41
|
+
} from 'vue';
|
|
42
|
+
|
|
43
|
+
import ${JSON.stringify(wcModuleId)};
|
|
44
|
+
|
|
45
|
+
const PROP_KEYS = ${JSON.stringify(propNames)};
|
|
46
|
+
const EVENT_NAMES = ${JSON.stringify(eventNames)};
|
|
47
|
+
const NAMED_SLOTS = ${JSON.stringify(slotNames)};
|
|
48
|
+
|
|
49
|
+
export const ${component.name} = defineComponent({
|
|
50
|
+
name: ${JSON.stringify(component.name)},
|
|
51
|
+
|
|
52
|
+
props: {
|
|
53
|
+
${generateVueProps(component)}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
emits: EVENT_NAMES,
|
|
57
|
+
|
|
58
|
+
setup(props, { attrs, slots, emit }) {
|
|
59
|
+
const elRef = ref(null);
|
|
60
|
+
const cleanups = [];
|
|
61
|
+
|
|
62
|
+
const syncProps = () => {
|
|
63
|
+
const el = elRef.value;
|
|
64
|
+
if (!el) return;
|
|
65
|
+
|
|
66
|
+
${syncPropsBody}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
onMounted(() => {
|
|
70
|
+
syncProps();
|
|
71
|
+
|
|
72
|
+
const el = elRef.value;
|
|
73
|
+
if (!el) return;
|
|
74
|
+
|
|
75
|
+
for (const eventName of EVENT_NAMES) {
|
|
76
|
+
const handler = event => emit(eventName, event);
|
|
77
|
+
el.addEventListener(eventName, handler);
|
|
78
|
+
cleanups.push(() => el.removeEventListener(eventName, handler));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
onBeforeUnmount(() => {
|
|
83
|
+
for (const cleanup of cleanups) cleanup();
|
|
84
|
+
cleanups.length = 0;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
${watchBlock}
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
const children = [];
|
|
91
|
+
|
|
92
|
+
if (slots.default) {
|
|
93
|
+
children.push(...slots.default());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const name of NAMED_SLOTS) {
|
|
97
|
+
const slot = slots[name];
|
|
98
|
+
if (!slot) continue;
|
|
99
|
+
|
|
100
|
+
for (const vnode of slot()) {
|
|
101
|
+
children.push(withSlot(name, vnode));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return h(
|
|
106
|
+
${JSON.stringify(component.tag)},
|
|
107
|
+
{
|
|
108
|
+
...attrs,
|
|
109
|
+
ref: elRef,
|
|
110
|
+
},
|
|
111
|
+
children,
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
function withSlot(name, vnode) {
|
|
118
|
+
if (!vnode) return vnode;
|
|
119
|
+
|
|
120
|
+
if (typeof vnode === 'string') {
|
|
121
|
+
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return cloneVNode(vnode, { slot: name });
|
|
125
|
+
}
|
|
126
|
+
`.trimStart();
|
|
127
|
+
}
|
|
128
|
+
function generateVueProps(component) {
|
|
129
|
+
return Object.entries(component.props).map(([name, prop]) => {
|
|
130
|
+
return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
|
|
131
|
+
}).join(",\n ");
|
|
132
|
+
}
|
|
133
|
+
function toVuePropOption(prop) {
|
|
134
|
+
var _typeMap$prop$type;
|
|
135
|
+
const type = (_typeMap$prop$type = {
|
|
136
|
+
string: "String",
|
|
137
|
+
number: "Number",
|
|
138
|
+
boolean: "Boolean",
|
|
139
|
+
object: "Object",
|
|
140
|
+
array: "Array",
|
|
141
|
+
unknown: "null"
|
|
142
|
+
}[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
|
|
143
|
+
if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
|
|
144
|
+
return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
|
|
145
|
+
}
|
|
146
|
+
function generateVuePropSyncLines(propNames) {
|
|
147
|
+
if (propNames.length === 0) return "// no props to sync";
|
|
148
|
+
return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region packages/web-c/output-vue-wrapper/src/index.ts
|
|
152
|
+
function vueWrapper(options = {}) {
|
|
153
|
+
var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
|
|
154
|
+
const normalized = {
|
|
155
|
+
outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
|
|
156
|
+
stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
|
|
157
|
+
fileName: options.fileName,
|
|
158
|
+
dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
|
|
159
|
+
globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
|
|
160
|
+
index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
name: "zeus-output-vue-wrapper",
|
|
164
|
+
external: ["vue"],
|
|
165
|
+
setup(ctx) {
|
|
166
|
+
ctx.outputs.register("vue", {
|
|
167
|
+
outDir: normalized.outDir,
|
|
168
|
+
stripPrefix: normalized.stripPrefix,
|
|
169
|
+
fileName: normalized.fileName ? (tag) => normalized.fileName(tag) : void 0
|
|
170
|
+
});
|
|
171
|
+
},
|
|
172
|
+
virtualModules(ctx) {
|
|
173
|
+
if (!ctx.outputs.has("wc")) ctx.error("[zeus-output-vue-wrapper] vue() requires wc() plugin.");
|
|
174
|
+
const modules = [];
|
|
175
|
+
for (const component of ctx.manifest.components) modules.push({
|
|
176
|
+
id: `zeus:vue:${component.tag}`,
|
|
177
|
+
fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
|
|
178
|
+
code: generateVueWrapper({
|
|
179
|
+
component,
|
|
180
|
+
wcModuleId: `zeus:wc:${component.tag}`
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
if (normalized.index) modules.push({
|
|
184
|
+
id: "zeus:vue:index",
|
|
185
|
+
fileName: ctx.outputs.join("vue", "index.js"),
|
|
186
|
+
code: generateVueIndex(ctx.manifest.components, { getFileName: (tag) => ctx.outputs.getFileName("vue", tag) })
|
|
187
|
+
});
|
|
188
|
+
return modules;
|
|
189
|
+
},
|
|
190
|
+
generateBundle(ctx) {
|
|
191
|
+
const files = [];
|
|
192
|
+
if ((0, _zeus_js_bundler_plugin.resolvePluginDts)(normalized.dts, ctx)) files.push({
|
|
193
|
+
type: "asset",
|
|
194
|
+
fileName: ctx.outputs.join("vue", "index.d.ts"),
|
|
195
|
+
source: (0, _zeus_js_component_dts.generateVueDts)(ctx.manifest)
|
|
196
|
+
});
|
|
197
|
+
if ((0, _zeus_js_bundler_plugin.resolvePluginDts)(normalized.globalDts, ctx)) files.push({
|
|
198
|
+
type: "asset",
|
|
199
|
+
fileName: ctx.outputs.join("vue", "global.d.ts"),
|
|
200
|
+
source: (0, _zeus_js_component_dts.generateVueGlobalDts)(ctx.manifest)
|
|
201
|
+
});
|
|
202
|
+
return files;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
exports.default = vueWrapper;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DtsMode, ZeusComponentPlugin } from '@zeus-js/bundler-plugin';
|
|
2
|
+
|
|
3
|
+
export interface OutputVueWrapperOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Vue wrapper output directory.
|
|
6
|
+
*
|
|
7
|
+
* @default 'vue'
|
|
8
|
+
*/
|
|
9
|
+
outDir?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Strip tag prefix for file name.
|
|
12
|
+
*
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
stripPrefix?: string | false;
|
|
16
|
+
/**
|
|
17
|
+
* Custom file name.
|
|
18
|
+
*/
|
|
19
|
+
fileName?: (tag: string) => string;
|
|
20
|
+
/**
|
|
21
|
+
* Generate vue/index.d.ts.
|
|
22
|
+
*
|
|
23
|
+
* @default 'auto'
|
|
24
|
+
*/
|
|
25
|
+
dts?: DtsMode;
|
|
26
|
+
/**
|
|
27
|
+
* Generate vue/global.d.ts.
|
|
28
|
+
*
|
|
29
|
+
* @default 'auto'
|
|
30
|
+
*/
|
|
31
|
+
globalDts?: DtsMode;
|
|
32
|
+
/**
|
|
33
|
+
* Generate vue/index.js.
|
|
34
|
+
*
|
|
35
|
+
* @default true
|
|
36
|
+
*/
|
|
37
|
+
index?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export declare function vueWrapper(options?: OutputVueWrapperOptions): ZeusComponentPlugin;
|
|
41
|
+
|
|
42
|
+
export { vueWrapper as default };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* output-vue-wrapper v0.1.0-beta.0
|
|
3
|
+
* (c) 2026 baicie
|
|
4
|
+
* Released under the MIT License.
|
|
5
|
+
**/
|
|
6
|
+
import { resolvePluginDts } from "@zeus-js/bundler-plugin";
|
|
7
|
+
import { generateVueDts, generateVueGlobalDts } from "@zeus-js/component-dts";
|
|
8
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueIndex.ts
|
|
9
|
+
function generateVueIndex(components, options) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
for (const component of components) {
|
|
12
|
+
const fileName = options.getFileName(component.tag);
|
|
13
|
+
lines.push(`export * from './${fileName}';`);
|
|
14
|
+
}
|
|
15
|
+
lines.push("");
|
|
16
|
+
return lines.join("\n");
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
|
|
20
|
+
function generateVueWrapper(input) {
|
|
21
|
+
const { component, wcModuleId } = input;
|
|
22
|
+
const propNames = Object.keys(component.props);
|
|
23
|
+
const eventNames = Object.keys(component.events);
|
|
24
|
+
const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
|
|
25
|
+
const syncPropsBody = generateVuePropSyncLines(propNames);
|
|
26
|
+
const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
|
|
27
|
+
const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
|
|
28
|
+
return `
|
|
29
|
+
import {
|
|
30
|
+
cloneVNode,
|
|
31
|
+
defineComponent,
|
|
32
|
+
h,
|
|
33
|
+
onBeforeUnmount,
|
|
34
|
+
onMounted,
|
|
35
|
+
ref,
|
|
36
|
+
watch,
|
|
37
|
+
} from 'vue';
|
|
38
|
+
|
|
39
|
+
import ${JSON.stringify(wcModuleId)};
|
|
40
|
+
|
|
41
|
+
const PROP_KEYS = ${JSON.stringify(propNames)};
|
|
42
|
+
const EVENT_NAMES = ${JSON.stringify(eventNames)};
|
|
43
|
+
const NAMED_SLOTS = ${JSON.stringify(slotNames)};
|
|
44
|
+
|
|
45
|
+
export const ${component.name} = defineComponent({
|
|
46
|
+
name: ${JSON.stringify(component.name)},
|
|
47
|
+
|
|
48
|
+
props: {
|
|
49
|
+
${generateVueProps(component)}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
emits: EVENT_NAMES,
|
|
53
|
+
|
|
54
|
+
setup(props, { attrs, slots, emit }) {
|
|
55
|
+
const elRef = ref(null);
|
|
56
|
+
const cleanups = [];
|
|
57
|
+
|
|
58
|
+
const syncProps = () => {
|
|
59
|
+
const el = elRef.value;
|
|
60
|
+
if (!el) return;
|
|
61
|
+
|
|
62
|
+
${syncPropsBody}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
onMounted(() => {
|
|
66
|
+
syncProps();
|
|
67
|
+
|
|
68
|
+
const el = elRef.value;
|
|
69
|
+
if (!el) return;
|
|
70
|
+
|
|
71
|
+
for (const eventName of EVENT_NAMES) {
|
|
72
|
+
const handler = event => emit(eventName, event);
|
|
73
|
+
el.addEventListener(eventName, handler);
|
|
74
|
+
cleanups.push(() => el.removeEventListener(eventName, handler));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
onBeforeUnmount(() => {
|
|
79
|
+
for (const cleanup of cleanups) cleanup();
|
|
80
|
+
cleanups.length = 0;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
${watchBlock}
|
|
84
|
+
|
|
85
|
+
return () => {
|
|
86
|
+
const children = [];
|
|
87
|
+
|
|
88
|
+
if (slots.default) {
|
|
89
|
+
children.push(...slots.default());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for (const name of NAMED_SLOTS) {
|
|
93
|
+
const slot = slots[name];
|
|
94
|
+
if (!slot) continue;
|
|
95
|
+
|
|
96
|
+
for (const vnode of slot()) {
|
|
97
|
+
children.push(withSlot(name, vnode));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return h(
|
|
102
|
+
${JSON.stringify(component.tag)},
|
|
103
|
+
{
|
|
104
|
+
...attrs,
|
|
105
|
+
ref: elRef,
|
|
106
|
+
},
|
|
107
|
+
children,
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
function withSlot(name, vnode) {
|
|
114
|
+
if (!vnode) return vnode;
|
|
115
|
+
|
|
116
|
+
if (typeof vnode === 'string') {
|
|
117
|
+
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return cloneVNode(vnode, { slot: name });
|
|
121
|
+
}
|
|
122
|
+
`.trimStart();
|
|
123
|
+
}
|
|
124
|
+
function generateVueProps(component) {
|
|
125
|
+
return Object.entries(component.props).map(([name, prop]) => {
|
|
126
|
+
return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
|
|
127
|
+
}).join(",\n ");
|
|
128
|
+
}
|
|
129
|
+
function toVuePropOption(prop) {
|
|
130
|
+
var _typeMap$prop$type;
|
|
131
|
+
const type = (_typeMap$prop$type = {
|
|
132
|
+
string: "String",
|
|
133
|
+
number: "Number",
|
|
134
|
+
boolean: "Boolean",
|
|
135
|
+
object: "Object",
|
|
136
|
+
array: "Array",
|
|
137
|
+
unknown: "null"
|
|
138
|
+
}[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
|
|
139
|
+
if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
|
|
140
|
+
return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
|
|
141
|
+
}
|
|
142
|
+
function generateVuePropSyncLines(propNames) {
|
|
143
|
+
if (propNames.length === 0) return "// no props to sync";
|
|
144
|
+
return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region packages/web-c/output-vue-wrapper/src/index.ts
|
|
148
|
+
function vueWrapper(options = {}) {
|
|
149
|
+
var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
|
|
150
|
+
const normalized = {
|
|
151
|
+
outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
|
|
152
|
+
stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
|
|
153
|
+
fileName: options.fileName,
|
|
154
|
+
dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
|
|
155
|
+
globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
|
|
156
|
+
index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
|
|
157
|
+
};
|
|
158
|
+
return {
|
|
159
|
+
name: "zeus-output-vue-wrapper",
|
|
160
|
+
external: ["vue"],
|
|
161
|
+
setup(ctx) {
|
|
162
|
+
ctx.outputs.register("vue", {
|
|
163
|
+
outDir: normalized.outDir,
|
|
164
|
+
stripPrefix: normalized.stripPrefix,
|
|
165
|
+
fileName: normalized.fileName ? (tag) => normalized.fileName(tag) : void 0
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
virtualModules(ctx) {
|
|
169
|
+
if (!ctx.outputs.has("wc")) ctx.error("[zeus-output-vue-wrapper] vue() requires wc() plugin.");
|
|
170
|
+
const modules = [];
|
|
171
|
+
for (const component of ctx.manifest.components) modules.push({
|
|
172
|
+
id: `zeus:vue:${component.tag}`,
|
|
173
|
+
fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
|
|
174
|
+
code: generateVueWrapper({
|
|
175
|
+
component,
|
|
176
|
+
wcModuleId: `zeus:wc:${component.tag}`
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
if (normalized.index) modules.push({
|
|
180
|
+
id: "zeus:vue:index",
|
|
181
|
+
fileName: ctx.outputs.join("vue", "index.js"),
|
|
182
|
+
code: generateVueIndex(ctx.manifest.components, { getFileName: (tag) => ctx.outputs.getFileName("vue", tag) })
|
|
183
|
+
});
|
|
184
|
+
return modules;
|
|
185
|
+
},
|
|
186
|
+
generateBundle(ctx) {
|
|
187
|
+
const files = [];
|
|
188
|
+
if (resolvePluginDts(normalized.dts, ctx)) files.push({
|
|
189
|
+
type: "asset",
|
|
190
|
+
fileName: ctx.outputs.join("vue", "index.d.ts"),
|
|
191
|
+
source: generateVueDts(ctx.manifest)
|
|
192
|
+
});
|
|
193
|
+
if (resolvePluginDts(normalized.globalDts, ctx)) files.push({
|
|
194
|
+
type: "asset",
|
|
195
|
+
fileName: ctx.outputs.join("vue", "global.d.ts"),
|
|
196
|
+
source: generateVueGlobalDts(ctx.manifest)
|
|
197
|
+
});
|
|
198
|
+
return files;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
export { vueWrapper as default };
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zeus-js/output-vue-wrapper",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "Zeus Vue wrapper output plugin",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"module": "dist/output-vue-wrapper.esm-bundler.js",
|
|
8
|
+
"types": "dist/output-vue-wrapper.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/output-vue-wrapper.d.ts",
|
|
16
|
+
"node": {
|
|
17
|
+
"production": "./dist/output-vue-wrapper.cjs.prod.js",
|
|
18
|
+
"development": "./dist/output-vue-wrapper.cjs.js",
|
|
19
|
+
"default": "./index.js"
|
|
20
|
+
},
|
|
21
|
+
"module": "./dist/output-vue-wrapper.esm-bundler.js",
|
|
22
|
+
"import": "./dist/output-vue-wrapper.esm-bundler.js",
|
|
23
|
+
"require": "./index.js"
|
|
24
|
+
},
|
|
25
|
+
"./*": "./*"
|
|
26
|
+
},
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/baicie/zeus"
|
|
31
|
+
},
|
|
32
|
+
"buildOptions": {
|
|
33
|
+
"name": "ZeusOutputVueWrapper",
|
|
34
|
+
"formats": [
|
|
35
|
+
"esm-bundler",
|
|
36
|
+
"cjs"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@zeus-js/bundler-plugin": "0.1.0-beta.0",
|
|
41
|
+
"@zeus-js/component-analyzer": "0.1.0-beta.0",
|
|
42
|
+
"@zeus-js/component-dts": "0.1.0-beta.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"vue": ">=3"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"vue": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"zeus",
|
|
54
|
+
"vue",
|
|
55
|
+
"web-components"
|
|
56
|
+
],
|
|
57
|
+
"author": "Baicie",
|
|
58
|
+
"license": "MIT"
|
|
59
|
+
}
|