@vuecast/astro-module 1.0.4 → 1.0.5

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.
Files changed (2) hide show
  1. package/dist/index.mjs +161 -14
  2. package/package.json +4 -1
package/dist/index.mjs CHANGED
@@ -29,14 +29,43 @@ function splitAstroFrontmatter(code) {
29
29
  function isVueTemplate(template) {
30
30
  if (/\{\{\s*[^}]+?\s*\}\}/.test(template))
31
31
  return true;
32
- if (/\sv-(if|else-if|else|for|show|model|bind|on|slot)\b/.test(template))
32
+ if (/\sv-(if|else-if|else|for|show|model|bind|on|slot|html|text)\b/.test(template))
33
33
  return true;
34
34
  if (/(?:\s|<)[:@][a-zA-Z]/.test(template))
35
35
  return true;
36
36
  return false;
37
37
  }
38
38
  function genChildren(children) {
39
- return children.map(genNode).join("");
39
+ let out = "";
40
+ for (let i = 0; i < children.length; i++) {
41
+ const node = children[i];
42
+ if (node.type === NodeTypes.ELEMENT && hasDirective(node, "if")) {
43
+ const chain = [
44
+ { node, type: "if" }
45
+ ];
46
+ let j = i + 1;
47
+ for (; j < children.length; j++) {
48
+ const sib = children[j];
49
+ if (sib.type !== NodeTypes.ELEMENT)
50
+ break;
51
+ if (hasDirective(sib, "else-if")) {
52
+ chain.push({ node: sib, type: "else-if" });
53
+ continue;
54
+ }
55
+ if (hasDirective(sib, "else")) {
56
+ chain.push({ node: sib, type: "else" });
57
+ j++;
58
+ break;
59
+ }
60
+ break;
61
+ }
62
+ out += genIfChain(chain);
63
+ i = j - 1;
64
+ continue;
65
+ }
66
+ out += genNode(node);
67
+ }
68
+ return out;
40
69
  }
41
70
  function genNode(node) {
42
71
  switch (node.type) {
@@ -54,25 +83,37 @@ function genNode(node) {
54
83
  }
55
84
  function genElement(el) {
56
85
  const tag = el.tag;
57
- const { attrs, vIf, vElseIf, vElse, vFor } = splitDirectives(el.props);
86
+ const { attrs, vIf, vElseIf, vElse, vFor, vShow, vText, vHtml } = splitDirectives(el.props);
58
87
  if (vFor) {
59
88
  const { source, value, index } = parseVFor(vFor.exp?.content ?? "");
60
- const inner = genPlainElement(tag, attrs, el.children);
89
+ const inner = genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
61
90
  const args = index ? `${value}, ${index}` : value;
62
91
  return `{${source}.map((${args}) => (${inner}))}`;
63
92
  }
64
93
  if (vIf) {
65
94
  const cond = vIf.exp?.content ?? "false";
66
- const thenBranch = genPlainElement(tag, attrs, el.children);
95
+ const thenBranch = genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
67
96
  return `{${cond} ? (${thenBranch}) : null}`;
68
97
  }
69
98
  if (vElseIf || vElse) {
70
- return genPlainElement(tag, attrs, el.children);
99
+ return genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
71
100
  }
72
- return genPlainElement(tag, attrs, el.children);
101
+ return genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
73
102
  }
74
- function genPlainElement(tag, props, children) {
75
- const attrStr = props.map(genAttr).join("");
103
+ function genPlainElement(tag, props, children, extras) {
104
+ let attrs = props;
105
+ if (extras?.vShow)
106
+ attrs = applyVShow(attrs, extras.vShow);
107
+ let attrStr = attrs.map(genAttr).join("");
108
+ if (extras?.vHtml) {
109
+ const expr = extras.vHtml.exp?.content ?? "''";
110
+ attrStr += ` set:html={${expr}}`;
111
+ children = [];
112
+ } else if (extras?.vText) {
113
+ const expr = extras.vText.exp?.content ?? "''";
114
+ attrStr += ` set:text={${expr}}`;
115
+ children = [];
116
+ }
76
117
  const inner = genChildren(children);
77
118
  return `<${tag}${attrStr}>${inner}</${tag}>`;
78
119
  }
@@ -80,12 +121,20 @@ function genAttr(p) {
80
121
  if (p.type === NodeTypes.ATTRIBUTE) {
81
122
  if (!p.value)
82
123
  return ` ${p.name}`;
83
- return ` ${p.name}="${escapeAttr(p.value.content)}"`;
124
+ const raw = p.value.content ?? "";
125
+ if (/\$\{[^}]+?\}/.test(raw)) {
126
+ const trimmed = raw.startsWith("`") && raw.endsWith("`") ? raw.slice(1, -1) : raw;
127
+ const safe = trimmed.replace(/`/g, "\\`");
128
+ return ` ${p.name}={\`${safe}\`}`;
129
+ }
130
+ return ` ${p.name}="${escapeAttr(raw)}"`;
84
131
  }
85
132
  if (p.type === NodeTypes.DIRECTIVE && p.name === "bind") {
86
133
  const name = p.arg?.content;
87
- if (!name)
88
- return "";
134
+ if (!name) {
135
+ const expr2 = p.exp?.content ?? "{}";
136
+ return ` {...${expr2}}`;
137
+ }
89
138
  const expr = p.exp?.content ?? "true";
90
139
  return ` ${name}={${expr}}`;
91
140
  }
@@ -102,6 +151,9 @@ function splitDirectives(props) {
102
151
  let vElseIf = null;
103
152
  let vElse = null;
104
153
  let vFor = null;
154
+ let vShow = null;
155
+ let vText = null;
156
+ let vHtml = null;
105
157
  for (const p of props) {
106
158
  if (p.type === NodeTypes.DIRECTIVE) {
107
159
  if (p.name === "if")
@@ -112,13 +164,19 @@ function splitDirectives(props) {
112
164
  vElse = p;
113
165
  else if (p.name === "for")
114
166
  vFor = p;
167
+ else if (p.name === "show")
168
+ vShow = p;
169
+ else if (p.name === "text")
170
+ vText = p;
171
+ else if (p.name === "html")
172
+ vHtml = p;
115
173
  else
116
174
  attrs.push(p);
117
175
  } else {
118
176
  attrs.push(p);
119
177
  }
120
178
  }
121
- return { attrs, vIf, vElseIf, vElse, vFor };
179
+ return { attrs, vIf, vElseIf, vElse, vFor, vShow, vText, vHtml };
122
180
  }
123
181
  function parseVFor(exp) {
124
182
  const m = exp.match(/^\s*(.+?)\s+in\s+(.+)\s*$/);
@@ -139,6 +197,95 @@ function parseVFor(exp) {
139
197
  function escapeAttr(s) {
140
198
  return String(s).replace(/&/g, "&amp;").replace(/"/g, "&quot;");
141
199
  }
200
+ function hasDirective(node, name) {
201
+ return !!node.props?.some(
202
+ (p) => p.type === NodeTypes.DIRECTIVE && p.name === name
203
+ );
204
+ }
205
+ function genIfChain(chain) {
206
+ const parts = chain.map((item) => {
207
+ const split = splitDirectives(item.node.props);
208
+ const branch = genElementFromSplit(item.node, split, { ignoreIf: true });
209
+ const cond = item.type === "else" ? null : item.type === "if" ? split.vIf?.exp?.content ?? "false" : split.vElseIf?.exp?.content ?? "false";
210
+ return { cond, branch };
211
+ });
212
+ let expr = "";
213
+ for (let i = 0; i < parts.length; i++) {
214
+ const { cond, branch } = parts[i];
215
+ if (i === 0) {
216
+ expr = `${cond} ? (${branch}) : `;
217
+ } else if (cond) {
218
+ expr += `${cond} ? (${branch}) : `;
219
+ } else {
220
+ expr += `(${branch})`;
221
+ }
222
+ }
223
+ if (!parts.some((p) => p.cond === null))
224
+ expr += "null";
225
+ return `{${expr}}`;
226
+ }
227
+ function genElementFromSplit(el, split, opts) {
228
+ const tag = el.tag;
229
+ const { attrs, vIf, vElseIf, vElse, vFor, vShow, vText, vHtml } = split;
230
+ if (vFor) {
231
+ const { source, value, index } = parseVFor(vFor.exp?.content ?? "");
232
+ const inner = genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
233
+ const args = index ? `${value}, ${index}` : value;
234
+ return `{${source}.map((${args}) => (${inner}))}`;
235
+ }
236
+ if (!opts?.ignoreIf && vIf) {
237
+ const cond = vIf.exp?.content ?? "false";
238
+ const thenBranch = genPlainElement(tag, attrs, el.children, {
239
+ vShow,
240
+ vText,
241
+ vHtml
242
+ });
243
+ return `{${cond} ? (${thenBranch}) : null}`;
244
+ }
245
+ if (!opts?.ignoreIf && (vElseIf || vElse)) {
246
+ return genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
247
+ }
248
+ return genPlainElement(tag, attrs, el.children, { vShow, vText, vHtml });
249
+ }
250
+ function applyVShow(attrs, vShow) {
251
+ const showExpr = vShow.exp?.content ?? "false";
252
+ const showStyleExpr = `(${showExpr}) ? '' : 'display: none;'`;
253
+ const next = [...attrs];
254
+ const styleIdx = next.findIndex((p) => {
255
+ if (p.type === NodeTypes.ATTRIBUTE)
256
+ return p.name === "style";
257
+ return p.type === NodeTypes.DIRECTIVE && p.name === "bind" && p.arg?.content === "style";
258
+ });
259
+ if (styleIdx === -1) {
260
+ next.push({
261
+ type: NodeTypes.DIRECTIVE,
262
+ name: "bind",
263
+ arg: { content: "style" },
264
+ exp: { content: showStyleExpr }
265
+ });
266
+ return next;
267
+ }
268
+ const styleProp = next[styleIdx];
269
+ if (styleProp.type === NodeTypes.ATTRIBUTE) {
270
+ const base = styleProp.value?.content ?? "";
271
+ const sep = base && !/;\s*$/.test(base) ? ";" : "";
272
+ const safe = base.replace(/`/g, "\\`");
273
+ const merged = `\`${safe}${sep}\${${showExpr} ? '' : 'display: none;'}\``;
274
+ next[styleIdx] = {
275
+ type: NodeTypes.DIRECTIVE,
276
+ name: "bind",
277
+ arg: { content: "style" },
278
+ exp: { content: merged }
279
+ };
280
+ return next;
281
+ }
282
+ const baseExpr = styleProp.exp?.content ?? "''";
283
+ styleProp.exp = {
284
+ content: `(${baseExpr} ?? '') + (${showStyleExpr})`
285
+ };
286
+ next[styleIdx] = styleProp;
287
+ return next;
288
+ }
142
289
 
143
290
  function vueTemplatePreAstroPlugin() {
144
291
  return {
@@ -166,7 +313,7 @@ function vueTemplatePreAstroPlugin() {
166
313
 
167
314
  function VuecastAstro() {
168
315
  return {
169
- name: "@vuecast/astro-vue-template",
316
+ name: "@vuecast/astro-module",
170
317
  hooks: {
171
318
  "astro:config:setup": async (params) => {
172
319
  const existingPlugins = params.config.vite?.plugins;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vuecast/astro-module",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "Astro integration for Vue template syntax in .astro pages",
6
6
  "main": "./dist/index.mjs",
@@ -18,6 +18,8 @@
18
18
  ],
19
19
  "scripts": {
20
20
  "build": "unbuild",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
21
23
  "publish-beta": "npm run build && npm run increment-beta-version && npm publish --tag beta",
22
24
  "increment-beta-version": "npm version prerelease --preid=beta",
23
25
  "publish-patch": "npm run build && npm run increment-version && npm publish",
@@ -32,6 +34,7 @@
32
34
  "author": "",
33
35
  "license": "MIT",
34
36
  "devDependencies": {
37
+ "vitest": "^1.3.1",
35
38
  "unbuild": "^2.0.0"
36
39
  },
37
40
  "dependencies": {