@fluixi/ts-plugin 0.1.0-alpha.3 → 0.1.0-alpha.4

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.js +244 -224
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  // ../template-parser/dist/index.mjs
4
4
  function x(e) {
5
- let t = (i, n) => {
6
- i.parent = n;
7
- let r = B(i);
8
- for (let s of r) t(s, i);
5
+ let t = (i2, n) => {
6
+ i2.parent = n;
7
+ let r = R(i2);
8
+ for (let s2 of r) t(s2, i2);
9
9
  };
10
10
  return t(e, null), e;
11
11
  }
12
- function B(e) {
12
+ function R(e) {
13
13
  switch (e.kind) {
14
14
  case "Root":
15
15
  case "Element":
@@ -42,8 +42,8 @@ var m = class {
42
42
  }
43
43
  pos() {
44
44
  if (this.eof()) {
45
- let i = this.pieces[this.pieces.length - 1];
46
- return i ? i.kind === "static" ? i.start + i.text.length : i.end : 0;
45
+ let i2 = this.pieces[this.pieces.length - 1];
46
+ return i2 ? i2.kind === "static" ? i2.start + i2.text.length : i2.end : 0;
47
47
  }
48
48
  let t = this.pieces[this.pi];
49
49
  return t.kind === "static" ? t.start + this.oi : t.start;
@@ -55,8 +55,8 @@ var m = class {
55
55
  if (this.eof()) return false;
56
56
  let t = this.pieces[this.pi];
57
57
  if (t.kind !== "static" || this.oi + 1 < t.text.length) return false;
58
- let i = this.pieces[this.pi + 1];
59
- return i !== void 0 && i.kind === "hole";
58
+ let i2 = this.pieces[this.pi + 1];
59
+ return i2 !== void 0 && i2.kind === "hole";
60
60
  }
61
61
  takeHole() {
62
62
  let t = this.pieces[this.pi];
@@ -65,29 +65,29 @@ var m = class {
65
65
  }
66
66
  peek(t = 0) {
67
67
  if (this.eof()) return "";
68
- let i = this.pieces[this.pi];
69
- return i.kind !== "static" ? "" : i.text[this.oi + t] ?? "";
68
+ let i2 = this.pieces[this.pi];
69
+ return i2.kind !== "static" ? "" : i2.text[this.oi + t] ?? "";
70
70
  }
71
71
  startsWith(t) {
72
72
  if (this.eof()) return false;
73
- let i = this.pieces[this.pi];
74
- return i.kind !== "static" ? false : i.text.startsWith(t, this.oi);
73
+ let i2 = this.pieces[this.pi];
74
+ return i2.kind !== "static" ? false : i2.text.startsWith(t, this.oi);
75
75
  }
76
76
  advance() {
77
77
  if (this.eof()) return "";
78
78
  let t = this.pieces[this.pi];
79
79
  if (t.kind !== "static") return "";
80
- let i = t.text[this.oi++] ?? "";
81
- return this.normalize(), i;
80
+ let i2 = t.text[this.oi++] ?? "";
81
+ return this.normalize(), i2;
82
82
  }
83
83
  readWhile(t) {
84
- let i = "";
84
+ let i2 = "";
85
85
  for (; !this.eof() && !this.atHole(); ) {
86
86
  let n = this.peek();
87
87
  if (n === "" || !t(n)) break;
88
- i += n, this.oi++;
88
+ i2 += n, this.oi++;
89
89
  }
90
- return this.normalize(), i;
90
+ return this.normalize(), i2;
91
91
  }
92
92
  skipWhitespace() {
93
93
  this.readWhile((t) => /\s/.test(t));
@@ -100,19 +100,19 @@ var y = /* @__PURE__ */ new Set(["capture", "once", "passive", "prevent", "stop"
100
100
  function p(e, t) {
101
101
  return e.value && e.value.kind === "hole" ? e.value.hole : (e.report("invalid-binding", `${t} requires an expression value: ${e.name}=\${\u2026}`), -1);
102
102
  }
103
- var E = (e, t) => ({ kind: "Attribute", name: t ? e.name.slice(1) : e.name, value: e.value, boolean: t, loc: e.loc });
103
+ var D = (e, t) => ({ kind: "Attribute", name: t ? e.name.slice(1) : e.name, value: e.value, boolean: t, loc: e.loc });
104
104
  var f = [{ id: "event", match: (e) => e[0] === "@" || e.startsWith("on:") || /^on[A-Z]/.test(e), build: (e) => {
105
- let t, i;
106
- e.name[0] === "@" ? (t = "at", i = e.name.slice(1)) : e.name.startsWith("on:") ? (t = "colon", i = e.name.slice(3)) : (t = "on", i = e.name.slice(2));
107
- let [n, ...r] = i.split("."), s = n.toLowerCase();
105
+ let t, i2;
106
+ e.name[0] === "@" ? (t = "at", i2 = e.name.slice(1)) : e.name.startsWith("on:") ? (t = "colon", i2 = e.name.slice(3)) : (t = "on", i2 = e.name.slice(2));
107
+ let [n, ...r] = i2.split("."), s2 = n.toLowerCase();
108
108
  for (let o of r) y.has(o) || e.report("invalid-directive", `Unknown event modifier ".${o}" \u2014 expected one of ${[...y].join(", ")}`);
109
- return { kind: "EventBinding", name: s, syntax: t, modifiers: r, hole: p(e, "event binding"), loc: e.loc };
110
- } }, { id: "bind", elementOnly: true, match: (e) => e.startsWith("bind:"), build: (e) => ({ kind: "BindDirective", name: e.name.slice(5), hole: p(e, "two-way binding"), loc: e.loc }) }, { id: "class-directive", elementOnly: true, match: (e) => e.startsWith("class:"), build: (e) => ({ kind: "ClassDirective", name: e.name.slice(6), hole: p(e, "class directive"), loc: e.loc }) }, { id: "style-directive", elementOnly: true, match: (e) => e.startsWith("style:"), build: (e) => ({ kind: "StyleDirective", name: e.name.slice(6), hole: p(e, "style directive"), loc: e.loc }) }, { id: "use", match: (e) => e === "use" || e.startsWith("use:"), build: (e) => ({ kind: "UseDirective", name: e.name.startsWith("use:") ? e.name.slice(4) : null, hole: e.value && e.value.kind === "hole" ? e.value.hole : null, loc: e.loc }) }, { id: "if", elementOnly: true, match: (e) => e === "if", build: (e) => ({ kind: "IfDirective", hole: p(e, "if directive"), loc: e.loc }) }, { id: "each", elementOnly: true, match: (e) => e === "each", build: (e) => ({ kind: "EachDirective", hole: p(e, "each directive"), key: null, loc: e.loc }) }, { id: "else", elementOnly: true, match: (e) => e === "else", build: (e) => (e.value !== null && e.report("invalid-directive", "`else` takes no value"), { kind: "ElseDirective", loc: e.loc }) }, { id: "ref", match: (e) => e === "ref", build: (e) => ({ kind: "RefBinding", hole: p(e, "ref binding"), loc: e.loc }) }, { id: "property", match: (e) => e[0] === ".", build: (e) => ({ kind: "PropertyBinding", name: e.name.slice(1), hole: p(e, "property binding"), loc: e.loc }) }, { id: "boolean", match: (e) => e[0] === "?", build: (e) => E(e, true) }];
111
- function k(e, t = f, i = { component: false }) {
112
- for (let n of t) if (!(n.elementOnly && i.component) && n.match(e.name)) return n.build(e);
113
- return E(e, false);
109
+ return { kind: "EventBinding", name: s2, syntax: t, modifiers: r, hole: p(e, "event binding"), loc: e.loc };
110
+ } }, { id: "bind", elementOnly: true, match: (e) => e.startsWith("bind:"), build: (e) => ({ kind: "BindDirective", name: e.name.slice(5), hole: p(e, "two-way binding"), loc: e.loc }) }, { id: "class-directive", elementOnly: true, match: (e) => e.startsWith("class:"), build: (e) => ({ kind: "ClassDirective", name: e.name.slice(6), hole: p(e, "class directive"), loc: e.loc }) }, { id: "style-directive", elementOnly: true, match: (e) => e.startsWith("style:"), build: (e) => ({ kind: "StyleDirective", name: e.name.slice(6), hole: p(e, "style directive"), loc: e.loc }) }, { id: "load", match: (e) => e.startsWith("load:"), build: (e) => ({ kind: "LoadDirective", strategy: e.name.slice(5), modifier: e.value && e.value.kind === "static" ? e.value.value : null, loc: e.loc }) }, { id: "use", match: (e) => e === "use" || e.startsWith("use:"), build: (e) => ({ kind: "UseDirective", name: e.name.startsWith("use:") ? e.name.slice(4) : null, hole: e.value && e.value.kind === "hole" ? e.value.hole : null, loc: e.loc }) }, { id: "if", elementOnly: true, match: (e) => e === "if", build: (e) => ({ kind: "IfDirective", hole: p(e, "if directive"), loc: e.loc }) }, { id: "each", elementOnly: true, match: (e) => e === "each", build: (e) => ({ kind: "EachDirective", hole: p(e, "each directive"), key: null, loc: e.loc }) }, { id: "else", elementOnly: true, match: (e) => e === "else", build: (e) => (e.value !== null && e.report("invalid-directive", "`else` takes no value"), { kind: "ElseDirective", loc: e.loc }) }, { id: "ref", match: (e) => e === "ref", build: (e) => ({ kind: "RefBinding", hole: p(e, "ref binding"), loc: e.loc }) }, { id: "property", match: (e) => e[0] === ".", build: (e) => ({ kind: "PropertyBinding", name: e.name.slice(1), hole: p(e, "property binding"), loc: e.loc }) }, { id: "boolean", match: (e) => e[0] === "?", build: (e) => D(e, true) }];
111
+ function k(e, t = f, i2 = { component: false }) {
112
+ for (let n of t) if (!(n.elementOnly && i2.component) && n.match(e.name)) return n.build(e);
113
+ return D(e, false);
114
114
  }
115
- var D = /* @__PURE__ */ new Set(["svg", "path", "circle", "rect", "line", "polygon", "polyline", "ellipse", "g", "defs", "clipPath", "text"]);
115
+ var E = /* @__PURE__ */ new Set(["svg", "path", "circle", "rect", "line", "polygon", "polyline", "ellipse", "g", "defs", "clipPath", "text"]);
116
116
  var S = /* @__PURE__ */ new Set(["script", "style", "textarea", "title"]);
117
117
  var T = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]);
118
118
  function C(e) {
@@ -121,15 +121,15 @@ function C(e) {
121
121
  var P = /* @__PURE__ */ new Set(["a", "button", "input", "select", "textarea", "summary", "details", "option", "label"]);
122
122
  var W = /* @__PURE__ */ new Set(["keydown", "keyup", "keypress"]);
123
123
  function u(e, t) {
124
- return e.attributes.find((i) => "name" in i && i.name === t);
124
+ return e.attributes.find((i2) => "name" in i2 && i2.name === t);
125
125
  }
126
126
  function w(e) {
127
127
  return e.attributes.some((t) => t.kind === "Spread");
128
128
  }
129
129
  function v(e, t) {
130
- let i = u(e, t);
131
- if (!i || i.kind !== "Attribute" || !i.value) return;
132
- let n = i.value;
130
+ let i2 = u(e, t);
131
+ if (!i2 || i2.kind !== "Attribute" || !i2.value) return;
132
+ let n = i2.value;
133
133
  return n.kind === "static" ? n.value : void 0;
134
134
  }
135
135
  function H(e) {
@@ -137,48 +137,48 @@ function H(e) {
137
137
  return t === "presentation" || t === "none" ? true : v(e, "aria-hidden") === "true";
138
138
  }
139
139
  function A(e, t) {
140
- return e.attributes.some((i) => i.kind === "EventBinding" && t(i.name));
140
+ return e.attributes.some((i2) => i2.kind === "EventBinding" && t(i2.name));
141
141
  }
142
- function R(e) {
143
- let t = [], i = (r, s, o) => {
144
- t.push({ code: s, message: o, severity: "warning", loc: r.loc });
142
+ function B(e) {
143
+ let t = [], i2 = (r, s2, o) => {
144
+ t.push({ code: s2, message: o, severity: "warning", loc: r.loc });
145
145
  }, n = (r) => {
146
- for (let s of r) {
147
- s.kind === "Element" && V(s, i);
148
- let o = "children" in s ? s.children : void 0;
146
+ for (let s2 of r) {
147
+ s2.kind === "Element" && L(s2, i2);
148
+ let o = "children" in s2 ? s2.children : void 0;
149
149
  o && n(o);
150
150
  }
151
151
  };
152
152
  return n(e.children), t;
153
153
  }
154
- function V(e, t) {
154
+ function L(e, t) {
155
155
  if (w(e)) return;
156
- let i = e.tag.toLowerCase();
157
- i === "img" && !u(e, "alt") && !H(e) && t(e, "a11y-img-alt", 'An `img` needs an `alt`. Use `alt=""` when the image is decorative.'), i === "a" && !u(e, "href") && !u(e, "role") && t(e, "a11y-anchor-href", "An `a` without `href` is not a link. Use a `button` for an action."), i === "iframe" && !u(e, "title") && t(e, "a11y-iframe-title", "An `iframe` needs a `title` describing its content.");
156
+ let i2 = e.tag.toLowerCase();
157
+ i2 === "img" && !u(e, "alt") && !H(e) && t(e, "a11y-img-alt", 'An `img` needs an `alt`. Use `alt=""` when the image is decorative.'), i2 === "a" && !u(e, "href") && !u(e, "role") && t(e, "a11y-anchor-href", "An `a` without `href` is not a link. Use a `button` for an action."), i2 === "iframe" && !u(e, "title") && t(e, "a11y-iframe-title", "An `iframe` needs a `title` describing its content.");
158
158
  let n = v(e, "tabindex") ?? v(e, "tabIndex");
159
- n !== void 0 && Number(n) > 0 && t(e, "a11y-positive-tabindex", "A positive `tabindex` reorders tab navigation for the entire page. Use `0`, or restructure the markup."), !P.has(i) && A(e, (r) => r === "click") && !u(e, "role") && !A(e, (r) => W.has(r)) && t(e, "a11y-click-without-keyboard", `A click handler on \`${i}\` is unreachable by keyboard. Use a \`button\`, or add a \`role\` and a key handler.`);
159
+ n !== void 0 && Number(n) > 0 && t(e, "a11y-positive-tabindex", "A positive `tabindex` reorders tab navigation for the entire page. Use `0`, or restructure the markup."), !P.has(i2) && A(e, (r) => r === "click") && !u(e, "role") && !A(e, (r) => W.has(r)) && t(e, "a11y-click-without-keyboard", `A click handler on \`${i2}\` is unreachable by keyboard. Use a \`button\`, or add a \`role\` and a key handler.`);
160
160
  }
161
- var I = /[A-Za-z0-9\-_:@.?]/;
162
- var b = class {
163
- constructor(t, i) {
161
+ var V = /[A-Za-z0-9\-_:@.?]/;
162
+ var N = class {
163
+ constructor(t, i2) {
164
164
  this.diagnostics = [];
165
- this.r = new m(t), this.svg = i.svg ?? false, this.directives = i.directives ?? f, this.accessibility = i.accessibility ?? true;
165
+ this.r = new m(t), this.svg = i2.svg ?? false, this.directives = i2.directives ?? f, this.accessibility = i2.accessibility ?? true;
166
166
  }
167
167
  parse() {
168
- let t = this.r.pos(), i = [];
169
- for (; !this.r.eof() && (i.push(...this.parseChildren()), !this.r.eof()); ) {
168
+ let t = this.r.pos(), i2 = [];
169
+ for (; !this.r.eof() && (i2.push(...this.parseChildren()), !this.r.eof()); ) {
170
170
  let r = this.r.pos();
171
171
  this.consumeCloseTag(), this.report("stray-close-tag", "error", "Close tag without a matching open tag", this.r.span(r));
172
172
  }
173
- let n = { kind: "Root", children: i, loc: this.r.span(t) };
174
- return x(n), this.validateTree(n), this.accessibility && this.diagnostics.push(...R(n)), { root: n, diagnostics: this.diagnostics };
173
+ let n = { kind: "Root", children: i2, loc: this.r.span(t) };
174
+ return x(n), this.validateTree(n), this.accessibility && this.diagnostics.push(...B(n)), { root: n, diagnostics: this.diagnostics };
175
175
  }
176
176
  validateTree(t) {
177
- let i = (n) => {
177
+ let i2 = (n) => {
178
178
  let r = null;
179
- for (let s of n) s.kind === "Text" && /^\s*$/.test(s.value) || (s.kind === "Element" || s.kind === "Component" ? (s.attributes.some((l) => l.kind === "ElseDirective") && (r != null && (r.kind === "Element" || r.kind === "Component") && r.attributes.some((a) => a.kind === "IfDirective") || this.report("else-without-if", "error", "`else` must immediately follow an element with `if`", s.loc)), r = s) : r = null, "children" in s && s.children && i(s.children));
179
+ for (let s2 of n) s2.kind === "Text" && /^\s*$/.test(s2.value) || (s2.kind === "Element" || s2.kind === "Component" ? (s2.attributes.some((l2) => l2.kind === "ElseDirective") && (r != null && (r.kind === "Element" || r.kind === "Component") && r.attributes.some((a2) => a2.kind === "IfDirective") || this.report("else-without-if", "error", "`else` must immediately follow an element with `if`", s2.loc)), r = s2) : r = null, "children" in s2 && s2.children && i2(s2.children));
180
180
  };
181
- i(t.children);
181
+ i2(t.children);
182
182
  }
183
183
  parseChildren() {
184
184
  let t = [];
@@ -204,8 +204,8 @@ var b = class {
204
204
  t.push(r);
205
205
  continue;
206
206
  }
207
- let i = this.readText();
208
- i && t.push(i);
207
+ let i2 = this.readText();
208
+ i2 && t.push(i2);
209
209
  }
210
210
  return t;
211
211
  }
@@ -221,93 +221,93 @@ var b = class {
221
221
  parseDynamicComponent() {
222
222
  let t = this.r.pos();
223
223
  this.r.advance();
224
- let i = this.r.takeHole().index, n = this.parseAttributes(true);
224
+ let i2 = this.r.takeHole().index, n = this.parseAttributes(true);
225
225
  this.r.skipWhitespace();
226
- let r = false, s = [];
227
- return this.r.startsWith("/>") ? (this.r.advance(), this.r.advance(), r = true) : (this.r.peek() === ">" && this.r.advance(), s = this.parseChildren(), this.r.startsWith("</") ? (this.r.advance(), this.r.advance(), this.r.atHole() ? this.r.takeHole() : this.readName(), this.r.skipWhitespace(), this.r.peek() === ">" && this.r.advance()) : this.report("unclosed-tag", "error", "Unclosed dynamic component", this.r.span(t))), { kind: "Component", tag: "", tagHole: i, attributes: n, children: s, selfClosing: r, loc: this.r.span(t) };
226
+ let r = false, s2 = [];
227
+ return this.r.startsWith("/>") ? (this.r.advance(), this.r.advance(), r = true) : (this.r.peek() === ">" && this.r.advance(), s2 = this.parseChildren(), this.r.startsWith("</") ? (this.r.advance(), this.r.advance(), this.r.atHole() ? this.r.takeHole() : this.readName(), this.r.skipWhitespace(), this.r.peek() === ">" && this.r.advance()) : this.report("unclosed-tag", "error", "Unclosed dynamic component", this.r.span(t))), { kind: "Component", tag: "", tagHole: i2, attributes: n, children: s2, selfClosing: r, loc: this.r.span(t) };
228
228
  }
229
229
  readText() {
230
- let t = this.r.pos(), i = "";
231
- for (; !this.r.eof() && !this.r.atHole() && !(this.r.startsWith("</") || this.r.startsWith("<!--") || this.isTagStart() || this.isFragmentStart() || this.isDynamicTagStart()); ) i += this.r.advance();
232
- return i ? { kind: "Text", value: i, raw: false, loc: this.r.span(t) } : null;
230
+ let t = this.r.pos(), i2 = "";
231
+ for (; !this.r.eof() && !this.r.atHole() && !(this.r.startsWith("</") || this.r.startsWith("<!--") || this.isTagStart() || this.isFragmentStart() || this.isDynamicTagStart()); ) i2 += this.r.advance();
232
+ return i2 ? { kind: "Text", value: i2, raw: false, loc: this.r.span(t) } : null;
233
233
  }
234
234
  parseComment() {
235
235
  let t = this.r.pos();
236
236
  this.r.advance(), this.r.advance(), this.r.advance(), this.r.advance();
237
- let i = "";
237
+ let i2 = "";
238
238
  for (; !this.r.eof() && !this.r.startsWith("-->"); ) {
239
239
  if (this.r.atHole()) {
240
- this.r.takeHole(), i += "\0";
240
+ this.r.takeHole(), i2 += "\0";
241
241
  continue;
242
242
  }
243
- i += this.r.advance();
243
+ i2 += this.r.advance();
244
244
  }
245
- return this.r.startsWith("-->") ? (this.r.advance(), this.r.advance(), this.r.advance()) : this.report("unclosed-comment", "warning", "Unterminated comment", this.r.span(t)), { kind: "Comment", value: i, loc: this.r.span(t) };
245
+ return this.r.startsWith("-->") ? (this.r.advance(), this.r.advance(), this.r.advance()) : this.report("unclosed-comment", "warning", "Unterminated comment", this.r.span(t)), { kind: "Comment", value: i2, loc: this.r.span(t) };
246
246
  }
247
247
  parseFragment() {
248
248
  let t = this.r.pos();
249
249
  this.r.advance(), this.r.advance();
250
- let i = this.parseChildren();
250
+ let i2 = this.parseChildren();
251
251
  if (this.r.startsWith("</")) {
252
252
  let n = this.consumeCloseTag();
253
253
  n && this.report("mismatched-close-tag", "error", `Expected </> to close fragment, got </${n}>`, this.r.span(t));
254
254
  } else this.report("unclosed-tag", "error", "Unterminated fragment", this.r.span(t));
255
- return { kind: "Fragment", children: i, loc: this.r.span(t) };
255
+ return { kind: "Fragment", children: i2, loc: this.r.span(t) };
256
256
  }
257
257
  parseElement() {
258
258
  let t = this.r.pos();
259
259
  this.r.advance();
260
- let i = this.readName(), n = C(i), r = this.parseAttributes(n);
260
+ let i2 = this.readName(), n = C(i2), r = this.parseAttributes(n);
261
261
  this.foldEachKey(r, t), this.r.skipWhitespace();
262
- let s = i.toLowerCase(), o = !n && S.has(s), l = !n && T.has(s), a = false, c = [];
263
- if (this.r.startsWith("/>")) this.r.advance(), this.r.advance(), a = true;
264
- else if (this.r.peek() === ">" && this.r.advance(), !l) if (c = o ? this.parseRawText(i) : this.parseChildren(), this.r.startsWith("</")) {
262
+ let s2 = i2.toLowerCase(), o = !n && S.has(s2), l2 = !n && T.has(s2), a2 = false, c = [];
263
+ if (this.r.startsWith("/>")) this.r.advance(), this.r.advance(), a2 = true;
264
+ else if (this.r.peek() === ">" && this.r.advance(), !l2) if (c = o ? this.parseRawText(i2) : this.parseChildren(), this.r.startsWith("</")) {
265
265
  let g = this.consumeCloseTag();
266
- g && g !== i && this.report("mismatched-close-tag", "error", `Expected </${i}>, got </${g}>`, this.r.span(t));
267
- } else this.report("unclosed-tag", "error", `Unclosed <${i}>`, this.r.span(t));
266
+ g && g !== i2 && this.report("mismatched-close-tag", "error", `Expected </${i2}>, got </${g}>`, this.r.span(t));
267
+ } else this.report("unclosed-tag", "error", `Unclosed <${i2}>`, this.r.span(t));
268
268
  let h = this.r.span(t);
269
- if (n) return { kind: "Component", tag: i, tagHole: null, attributes: r, children: c, selfClosing: a, loc: h };
270
- let d = this.svg || D.has(i) ? "svg" : "html";
271
- return { kind: "Element", tag: i, namespace: d, attributes: r, children: c, selfClosing: a, rawText: o, loc: h };
269
+ if (n) return { kind: "Component", tag: i2, tagHole: null, attributes: r, children: c, selfClosing: a2, loc: h };
270
+ let d = this.svg || E.has(i2) ? "svg" : "html";
271
+ return { kind: "Element", tag: i2, namespace: d, attributes: r, children: c, selfClosing: a2, rawText: o, loc: h };
272
272
  }
273
273
  parseRawText(t) {
274
- let i = [], n = "</" + t.toLowerCase(), r = "", s = this.r.pos(), o = () => {
275
- r && i.push({ kind: "Text", value: r, raw: true, loc: this.r.span(s) }), r = "";
274
+ let i2 = [], n = "</" + t.toLowerCase(), r = "", s2 = this.r.pos(), o = () => {
275
+ r && i2.push({ kind: "Text", value: r, raw: true, loc: this.r.span(s2) }), r = "";
276
276
  };
277
277
  for (; !this.r.eof() && !this.startsWithCloseFor(n); ) {
278
278
  if (this.r.atHole()) {
279
279
  o();
280
- let l = this.r.takeHole();
281
- i.push({ kind: "Expression", hole: l.index, loc: l.loc }), s = this.r.pos();
280
+ let l2 = this.r.takeHole();
281
+ i2.push({ kind: "Expression", hole: l2.index, loc: l2.loc }), s2 = this.r.pos();
282
282
  continue;
283
283
  }
284
- r || (s = this.r.pos()), r += this.r.advance();
284
+ r || (s2 = this.r.pos()), r += this.r.advance();
285
285
  }
286
- return o(), i;
286
+ return o(), i2;
287
287
  }
288
288
  startsWithCloseFor(t) {
289
- let i = 0;
290
- for (; i < t.length; ) {
291
- let n = this.r.peek(i);
292
- if (n === "" || n.toLowerCase() !== t[i]) return false;
293
- i++;
289
+ let i2 = 0;
290
+ for (; i2 < t.length; ) {
291
+ let n = this.r.peek(i2);
292
+ if (n === "" || n.toLowerCase() !== t[i2]) return false;
293
+ i2++;
294
294
  }
295
295
  return true;
296
296
  }
297
297
  parseAttributes(t) {
298
- let i = [];
298
+ let i2 = [];
299
299
  for (; !this.r.eof() && (this.r.skipWhitespace(), !(this.r.peek() === ">" || this.r.startsWith("/>"))); ) {
300
300
  if (this.r.atHole()) {
301
- let a = this.r.takeHole();
302
- i.push({ kind: "Spread", hole: a.index, loc: a.loc });
301
+ let a2 = this.r.takeHole();
302
+ i2.push({ kind: "Spread", hole: a2.index, loc: a2.loc });
303
303
  continue;
304
304
  }
305
305
  if (this.r.startsWith("...")) {
306
- let a = this.r.pos();
306
+ let a2 = this.r.pos();
307
307
  if (this.r.advance(), this.r.advance(), this.r.advance(), this.r.atHole()) {
308
308
  let c = this.r.takeHole();
309
- i.push({ kind: "Spread", hole: c.index, loc: this.r.span(a) });
310
- } else this.report("invalid-binding", "error", "Spread `...` must be followed by ${\u2026}", this.r.span(a));
309
+ i2.push({ kind: "Spread", hole: c.index, loc: this.r.span(a2) });
310
+ } else this.report("invalid-binding", "error", "Spread `...` must be followed by ${\u2026}", this.r.span(a2));
311
311
  continue;
312
312
  }
313
313
  let n = this.r.pos(), r = this.readName();
@@ -315,14 +315,14 @@ var b = class {
315
315
  this.r.advance();
316
316
  continue;
317
317
  }
318
- let s = this.r.span(n);
318
+ let s2 = this.r.span(n);
319
319
  this.r.skipWhitespace();
320
320
  let o = null;
321
321
  this.r.peek() === "=" && (this.r.advance(), this.r.skipWhitespace(), o = this.parseAttrValue());
322
- let l = { name: r, nameLoc: s, value: o, loc: this.r.span(n), report: (a, c) => this.report(a, "error", c, this.r.span(n)) };
323
- i.push(k(l, this.directives, { component: t }));
322
+ let l2 = { name: r, nameLoc: s2, value: o, loc: this.r.span(n), report: (a2, c) => this.report(a2, "error", c, this.r.span(n)) };
323
+ i2.push(k(l2, this.directives, { component: t }));
324
324
  }
325
- return i;
325
+ return i2;
326
326
  }
327
327
  parseAttrValue() {
328
328
  if (this.r.atHole()) return { kind: "hole", hole: this.r.takeHole().index };
@@ -331,30 +331,30 @@ var b = class {
331
331
  }
332
332
  readQuotedParts(t) {
333
333
  this.r.advance();
334
- let i = [], n = "";
334
+ let i2 = [], n = "";
335
335
  for (; !this.r.eof() && this.r.peek() !== t; ) {
336
336
  if (this.r.atHole()) {
337
- n && (i.push({ text: n }), n = ""), i.push({ hole: this.r.takeHole().index });
337
+ n && (i2.push({ text: n }), n = ""), i2.push({ hole: this.r.takeHole().index });
338
338
  continue;
339
339
  }
340
340
  let r = this.r.advance();
341
341
  if (r === "") break;
342
342
  n += r;
343
343
  }
344
- return n && i.push({ text: n }), this.r.peek() === t && this.r.advance(), i;
344
+ return n && i2.push({ text: n }), this.r.peek() === t && this.r.advance(), i2;
345
345
  }
346
346
  classifyParts(t) {
347
- let i = t.filter((n) => "hole" in n);
348
- return i.length === 0 ? { kind: "static", value: t.map((n) => "text" in n ? n.text : "").join("") } : t.length === 1 ? { kind: "hole", hole: i[0].hole } : { kind: "mixed", parts: t };
349
- }
350
- foldEachKey(t, i) {
351
- let n = null, r = 0, s = 0, o = 0, l = 0;
352
- for (let d of t) d.kind === "EachDirective" ? (n = d, s++) : d.kind === "IfDirective" ? r++ : d.kind === "ElseDirective" ? o++ : d.kind === "RefBinding" && l++;
353
- let a = this.r.span(i);
354
- s > 1 && this.report("duplicate-directive", "error", "Multiple `each` directives on one element", a), r > 1 && this.report("duplicate-directive", "error", "Multiple `if` directives on one element", a), l > 1 && this.report("duplicate-directive", "error", "Multiple `ref` bindings on one element", a), r > 0 && s > 0 && this.report("unsupported-combination", "error", "`if` and `each` cannot both apply to one element \u2014 wrap one in another element", a), r > 0 && o > 0 && this.report("invalid-directive", "error", "`if` and `else` cannot be on the same element", a);
347
+ let i2 = t.filter((n) => "hole" in n);
348
+ return i2.length === 0 ? { kind: "static", value: t.map((n) => "text" in n ? n.text : "").join("") } : t.length === 1 ? { kind: "hole", hole: i2[0].hole } : { kind: "mixed", parts: t };
349
+ }
350
+ foldEachKey(t, i2) {
351
+ let n = null, r = 0, s2 = 0, o = 0, l2 = 0;
352
+ for (let d of t) d.kind === "EachDirective" ? (n = d, s2++) : d.kind === "IfDirective" ? r++ : d.kind === "ElseDirective" ? o++ : d.kind === "RefBinding" && l2++;
353
+ let a2 = this.r.span(i2);
354
+ s2 > 1 && this.report("duplicate-directive", "error", "Multiple `each` directives on one element", a2), r > 1 && this.report("duplicate-directive", "error", "Multiple `if` directives on one element", a2), l2 > 1 && this.report("duplicate-directive", "error", "Multiple `ref` bindings on one element", a2), r > 0 && s2 > 0 && this.report("unsupported-combination", "error", "`if` and `each` cannot both apply to one element \u2014 wrap one in another element", a2), r > 0 && o > 0 && this.report("invalid-directive", "error", "`if` and `else` cannot be on the same element", a2);
355
355
  let c = t.findIndex((d) => d.kind === "Attribute" && d.name === "key");
356
356
  if (!n) {
357
- c !== -1 && this.report("invalid-directive", "error", "`key` requires an `each` directive on the same element", a);
357
+ c !== -1 && this.report("invalid-directive", "error", "`key` requires an `each` directive on the same element", a2);
358
358
  return;
359
359
  }
360
360
  if (c === -1) return;
@@ -362,28 +362,28 @@ var b = class {
362
362
  h.kind === "Attribute" && h.value && (h.value.kind === "static" ? n.key = { static: h.value.value } : h.value.kind === "hole" && (n.key = { hole: h.value.hole })), t.splice(c, 1);
363
363
  }
364
364
  readName() {
365
- return this.r.readWhile((t) => I.test(t));
365
+ return this.r.readWhile((t) => V.test(t));
366
366
  }
367
367
  consumeCloseTag() {
368
368
  this.r.advance(), this.r.advance();
369
369
  let t = this.readName();
370
370
  return this.r.skipWhitespace(), this.r.peek() === ">" && this.r.advance(), t;
371
371
  }
372
- report(t, i, n, r) {
373
- this.diagnostics.push({ code: t, severity: i, message: n, loc: r });
372
+ report(t, i2, n, r) {
373
+ this.diagnostics.push({ code: t, severity: i2, message: n, loc: r });
374
374
  }
375
375
  };
376
- function N(e, t = {}) {
377
- return new b(e, t).parse();
376
+ function b(e, t = {}) {
377
+ return new N(e, t).parse();
378
378
  }
379
- function L(e) {
380
- let t = [], i = 0;
379
+ function I(e) {
380
+ let t = [], i2 = 0;
381
381
  return e.forEach((n, r) => {
382
- t.push({ kind: "static", text: n, start: i }), i += n.length, r < e.length - 1 && t.push({ kind: "hole", index: r, start: i, end: i });
382
+ t.push({ kind: "static", text: n, start: i2 }), i2 += n.length, r < e.length - 1 && t.push({ kind: "hole", index: r, start: i2, end: i2 });
383
383
  }), t;
384
384
  }
385
385
  function Q(e, t = {}) {
386
- return N(L(e), t);
386
+ return b(I(e), t);
387
387
  }
388
388
 
389
389
  // src/collect.ts
@@ -451,15 +451,26 @@ function importedNames(ts, decl) {
451
451
  }
452
452
 
453
453
  // src/pieces.ts
454
+ function rawContent(ts, node, sf) {
455
+ const text = node.getText(sf);
456
+ const closesWithSubstitution = ts.isTemplateHead(node) || ts.isTemplateMiddle(node);
457
+ return text.slice(1, closesWithSubstitution ? -2 : -1);
458
+ }
454
459
  function templatePieces(ts, tpl, sf) {
455
460
  if (ts.isNoSubstitutionTemplateLiteral(tpl)) {
456
- return [{ kind: "static", text: tpl.text, start: tpl.getStart(sf) + 1 }];
461
+ return [{ kind: "static", text: rawContent(ts, tpl, sf), start: tpl.getStart(sf) + 1 }];
457
462
  }
458
- const pieces = [{ kind: "static", text: tpl.head.text, start: tpl.head.getStart(sf) + 1 }];
459
- tpl.templateSpans.forEach((span, i) => {
463
+ const pieces = [
464
+ { kind: "static", text: rawContent(ts, tpl.head, sf), start: tpl.head.getStart(sf) + 1 }
465
+ ];
466
+ tpl.templateSpans.forEach((span, i2) => {
460
467
  const e = span.expression;
461
- pieces.push({ kind: "hole", index: i, start: e.getStart(sf), end: e.getEnd() });
462
- pieces.push({ kind: "static", text: span.literal.text, start: span.literal.getStart(sf) + 1 });
468
+ pieces.push({ kind: "hole", index: i2, start: e.getStart(sf), end: e.getEnd() });
469
+ pieces.push({
470
+ kind: "static",
471
+ text: rawContent(ts, span.literal, sf),
472
+ start: span.literal.getStart(sf) + 1
473
+ });
463
474
  });
464
475
  return pieces;
465
476
  }
@@ -475,7 +486,7 @@ function parseCached(ts, sf, tpl) {
475
486
  const key = tpl.getStart(sf);
476
487
  const hit = byTemplate.get(key);
477
488
  if (hit) return hit;
478
- const result = N(templatePieces(ts, tpl, sf));
489
+ const result = b(templatePieces(ts, tpl, sf));
479
490
  byTemplate.set(key, result);
480
491
  return result;
481
492
  }
@@ -491,7 +502,7 @@ function templatesIn(ts, sf) {
491
502
  ts.forEachChild(node, visit);
492
503
  };
493
504
  visit(sf);
494
- found.sort((a, b2) => a.getStart(sf) - b2.getStart(sf));
505
+ found.sort((a2, b2) => a2.getStart(sf) - b2.getStart(sf));
495
506
  templates.set(sf, found);
496
507
  return found;
497
508
  }
@@ -505,29 +516,22 @@ function templateAtCached(ts, sf, pos) {
505
516
  return match;
506
517
  }
507
518
 
519
+ // ../compiler/dist/resolve/builtins.mjs
520
+ var s = ["Show", "For", "Index", "Switch", "Match", "Portal", "Dynamic", "ErrorBoundary"];
521
+ var i = ["Suspense", "SuspenseList", "Await"];
522
+ var u2 = ["Router", "Outlet", "Redirect", "Link"];
523
+ var p2 = [...s, ...i, ...u2];
524
+ var a = /* @__PURE__ */ new Set([...s, ...i]);
525
+ function l(o = {}) {
526
+ let { controlFlowModule: e = "@fluixi/dom", coreModule: r = "@fluixi/core", routerModule: c = "@fluixi/core/router-next" } = o, n = {};
527
+ for (let t of s) n[t] = e;
528
+ for (let t of i) n[t] = r;
529
+ for (let t of u2) n[t] = c;
530
+ return n;
531
+ }
532
+
508
533
  // src/auto-import.ts
509
- var DOM = "@fluixi/dom";
510
- var CORE = "@fluixi/core";
511
- var ROUTER = "@fluixi/core/router-next";
512
- var AUTO_IMPORTED = {
513
- // Control flow. Suspense and Await live in core; dom doesn't export them.
514
- Show: DOM,
515
- For: DOM,
516
- Index: DOM,
517
- Switch: DOM,
518
- Match: DOM,
519
- Portal: DOM,
520
- Dynamic: DOM,
521
- ErrorBoundary: DOM,
522
- Suspense: CORE,
523
- SuspenseList: CORE,
524
- Await: CORE,
525
- // Router. `Routes` isn't a component and `lazy` is a call, so neither appears.
526
- Router: ROUTER,
527
- Outlet: ROUTER,
528
- Redirect: ROUTER,
529
- Link: ROUTER
530
- };
534
+ var AUTO_IMPORTED = l();
531
535
  var exportsByProgram = /* @__PURE__ */ new WeakMap();
532
536
  function moduleExports(ts, program, host, from, moduleName) {
533
537
  let cache2 = exportsByProgram.get(program);
@@ -623,7 +627,7 @@ function resolveRelative(ts, host, options, from, specifier) {
623
627
  function autoImportedSymbol(ts, program, host, from, name) {
624
628
  const moduleName = AUTO_IMPORTED[name];
625
629
  if (!moduleName) return void 0;
626
- const symbol = moduleExports(ts, program, host, from, moduleName)?.find((s) => s.name === name);
630
+ const symbol = moduleExports(ts, program, host, from, moduleName)?.find((s2) => s2.name === name);
627
631
  if (!symbol) return void 0;
628
632
  if (!(symbol.flags & ts.SymbolFlags.Alias)) return symbol;
629
633
  try {
@@ -644,7 +648,7 @@ function componentQuickInfo(ts, ls, host, fileName, position) {
644
648
  if (!hit) return void 0;
645
649
  const checker = program.getTypeChecker();
646
650
  const flags = ts.SymbolFlags.Value | ts.SymbolFlags.Function | ts.SymbolFlags.Class | ts.SymbolFlags.Alias;
647
- const symbol = checker.getSymbolsInScope(template, flags).find((s) => s.name === hit.name) ?? autoImportedSymbol(ts, program, host, sf, hit.name);
651
+ const symbol = checker.getSymbolsInScope(template, flags).find((s2) => s2.name === hit.name) ?? autoImportedSymbol(ts, program, host, sf, hit.name);
648
652
  const decl = symbol?.valueDeclaration ?? symbol?.declarations?.[0];
649
653
  if (!decl) return void 0;
650
654
  const declFile = decl.getSourceFile();
@@ -781,21 +785,21 @@ function holeRoles(nodes, out) {
781
785
  };
782
786
  for (const node of nodes) {
783
787
  if (node.kind === "Element" || node.kind === "Component") {
784
- for (const a of node.attributes) {
785
- if (a.kind === "EventBinding") out.set(a.hole, { kind: "event", event: a.name.toLowerCase() });
786
- if (node.kind === "Element" && a.kind === "RefBinding") out.set(a.hole, { kind: "refEl", tag: node.tag });
787
- if (node.kind === "Element" && a.kind === "UseDirective" && a.hole != null) out.set(a.hole, { kind: "refEl", tag: node.tag });
788
+ for (const a2 of node.attributes) {
789
+ if (a2.kind === "EventBinding") out.set(a2.hole, { kind: "event", event: a2.name.toLowerCase() });
790
+ if (node.kind === "Element" && a2.kind === "RefBinding") out.set(a2.hole, { kind: "refEl", tag: node.tag });
791
+ if (node.kind === "Element" && a2.kind === "UseDirective" && a2.hole != null) out.set(a2.hole, { kind: "refEl", tag: node.tag });
788
792
  }
789
- const eachDir = node.attributes.find((a) => a.kind === "EachDirective");
793
+ const eachDir = node.attributes.find((a2) => a2.kind === "EachDirective");
790
794
  if (eachDir && eachDir.kind === "EachDirective") {
791
795
  renderChildren(node, { kind: "each", eachHole: eachDir.hole });
792
796
  }
793
797
  if (node.kind === "Component") {
794
798
  const propHole = (name) => {
795
- const a = node.attributes.find(
799
+ const a2 = node.attributes.find(
796
800
  (x2) => x2.kind === "Attribute" && x2.name === name && x2.value != null && x2.value.kind === "hole"
797
801
  );
798
- return a && a.kind === "Attribute" && a.value && a.value.kind === "hole" ? a.value.hole : void 0;
802
+ return a2 && a2.kind === "Attribute" && a2.value && a2.value.kind === "hole" ? a2.value.hole : void 0;
799
803
  };
800
804
  const eachHole = propHole("each");
801
805
  if (node.tag === "For" && eachHole !== void 0) renderChildren(node, { kind: "each", eachHole });
@@ -808,7 +812,7 @@ function holeRoles(nodes, out) {
808
812
  }
809
813
  }
810
814
  function resolveGlobalType(ts, checker, location, name) {
811
- const sym = checker.getSymbolsInScope(location, ts.SymbolFlags.Type).find((s) => s.getName() === name);
815
+ const sym = checker.getSymbolsInScope(location, ts.SymbolFlags.Type).find((s2) => s2.getName() === name);
812
816
  return sym ? checker.getDeclaredTypeOfSymbol(sym) : void 0;
813
817
  }
814
818
  function resolveElementType(ts, checker, location, tag) {
@@ -821,7 +825,7 @@ function inferParamAt(ts, program, sf, position) {
821
825
  const template = templateAtCached(ts, sf, position);
822
826
  if (!template || ts.isNoSubstitutionTemplateLiteral(template.template)) return void 0;
823
827
  const spans = template.template.templateSpans;
824
- const holeExprs = spans.map((s) => s.expression);
828
+ const holeExprs = spans.map((s2) => s2.expression);
825
829
  const holeIndex = holeExprs.findIndex((e) => position >= e.getStart(sf) && position <= e.getEnd());
826
830
  if (holeIndex === -1) return void 0;
827
831
  const roles = /* @__PURE__ */ new Map();
@@ -870,7 +874,7 @@ function inferParamsIn(ts, program, sf) {
870
874
  for (const template of templatesIn(ts, sf)) {
871
875
  const tpl = template.template;
872
876
  if (ts.isNoSubstitutionTemplateLiteral(tpl)) continue;
873
- const holeExprs = tpl.templateSpans.map((s) => s.expression);
877
+ const holeExprs = tpl.templateSpans.map((s2) => s2.expression);
874
878
  const roles = /* @__PURE__ */ new Map();
875
879
  holeRoles(parseCached(ts, sf, tpl).root.children, roles);
876
880
  for (const [holeIndex, role] of roles) {
@@ -924,7 +928,7 @@ function contains(outer, inner) {
924
928
  }
925
929
 
926
930
  // src/props.ts
927
- function componentPropCompletions(ts, ls, fileName, position) {
931
+ function componentPropCompletions(ts, ls, host, fileName, position) {
928
932
  const program = ls.getProgram();
929
933
  const sf = program?.getSourceFile(fileName);
930
934
  if (!program || !sf) return void 0;
@@ -932,28 +936,27 @@ function componentPropCompletions(ts, ls, fileName, position) {
932
936
  if (!template) return void 0;
933
937
  const comp = componentTagAtAttrArea(ts, sf, template.template, position);
934
938
  if (!comp || !comp.tag) return void 0;
939
+ const span = attrNameSpan(sf.text, position);
935
940
  const cf = CONTROL_FLOW_PROPS[comp.tag];
936
941
  if (cf) {
937
942
  const already2 = new Set(comp.attributeNames);
938
- return cf.filter((n) => !already2.has(n)).map((name) => propEntry(ts, name));
943
+ return cf.filter((n) => !already2.has(n)).map((name) => propEntry(ts, name, span));
939
944
  }
940
945
  const checker = program.getTypeChecker();
941
946
  const rootName = comp.tag.split(".")[0];
942
- const decl = findDeclaration(ts, sf, rootName);
943
- if (!decl) return void 0;
944
- const compType = checker.getTypeAtLocation(decl);
945
- const propsType = firstParamType(ts, checker, compType);
947
+ const compType = componentTypeOf(ts, program, checker, host, sf, template.template, rootName);
948
+ const propsType = compType && firstParamType(ts, checker, compType);
946
949
  if (!propsType) return void 0;
947
950
  const already = new Set(comp.attributeNames);
948
951
  const entries = [];
949
- for (const p2 of propsType.getProperties()) {
950
- const name = p2.getName();
952
+ for (const p3 of propsType.getProperties()) {
953
+ const name = p3.getName();
951
954
  if (name === "children" || already.has(name)) continue;
952
- entries.push(propEntry(ts, name));
955
+ entries.push(propEntry(ts, name, span));
953
956
  }
954
957
  return entries.length ? entries : void 0;
955
958
  }
956
- function componentPropHover(ts, ls, fileName, position) {
959
+ function componentPropHover(ts, ls, host, fileName, position) {
957
960
  const program = ls.getProgram();
958
961
  const sf = program?.getSourceFile(fileName);
959
962
  if (!program || !sf) return void 0;
@@ -968,11 +971,13 @@ function componentPropHover(ts, ls, fileName, position) {
968
971
  if (!typeText) return void 0;
969
972
  } else if (hit.tag) {
970
973
  const checker = program.getTypeChecker();
971
- const decl = findDeclaration(ts, sf, hit.tag.split(".")[0]);
972
- const propsType = decl && firstParamType(ts, checker, checker.getTypeAtLocation(decl));
974
+ const root = hit.tag.split(".")[0];
975
+ const compType = componentTypeOf(ts, program, checker, host, sf, template.template, root);
976
+ const propsType = compType && firstParamType(ts, checker, compType);
973
977
  const sym = propsType && propsType.getProperty(hit.prop);
974
978
  if (!sym) return void 0;
975
- typeText = checker.typeToString(checker.getTypeOfSymbolAtLocation(sym, sym.valueDeclaration ?? decl));
979
+ const at = sym.valueDeclaration ?? sym.declarations?.[0] ?? template.template;
980
+ typeText = checker.typeToString(checker.getTypeOfSymbolAtLocation(sym, at));
976
981
  }
977
982
  if (!typeText) return void 0;
978
983
  return {
@@ -999,10 +1004,10 @@ function propNameAt(ts, sf, tpl, position) {
999
1004
  for (const node of nodes) {
1000
1005
  if (node.kind === "Component") {
1001
1006
  const c = node;
1002
- for (const a of c.attributes) {
1003
- if ((a.kind === "Attribute" || a.kind === "PropertyBinding" || a.kind === "BindDirective") && "loc" in a) {
1004
- const start = a.loc.start;
1005
- if (position >= start && position <= start + a.name.length) hit = { tag: c.tag, prop: a.name, start };
1007
+ for (const a2 of c.attributes) {
1008
+ if ((a2.kind === "Attribute" || a2.kind === "PropertyBinding" || a2.kind === "BindDirective") && "loc" in a2) {
1009
+ const start = a2.loc.start;
1010
+ if (position >= start && position <= start + a2.name.length) hit = { tag: c.tag, prop: a2.name, start };
1006
1011
  }
1007
1012
  }
1008
1013
  }
@@ -1039,31 +1044,40 @@ var CONTROL_FLOW_PROPS = {
1039
1044
  Dynamic: ["component"],
1040
1045
  Await: ["value", "fallback"]
1041
1046
  };
1042
- function propEntry(ts, name) {
1043
- return { name, kind: ts.ScriptElementKind.memberVariableElement, kindModifiers: "", sortText: "0_" + name, insertText: name };
1044
- }
1045
- function findDeclaration(ts, sf, name) {
1046
- for (const stmt of sf.statements) {
1047
- if ((ts.isFunctionDeclaration(stmt) || ts.isClassDeclaration(stmt)) && stmt.name?.text === name) return stmt.name;
1048
- if (ts.isVariableStatement(stmt)) {
1049
- for (const d of stmt.declarationList.declarations) {
1050
- if (ts.isIdentifier(d.name) && d.name.text === name) return d.name;
1051
- }
1052
- }
1053
- if (ts.isImportDeclaration(stmt)) {
1054
- const b2 = stmt.importClause?.namedBindings;
1055
- if (b2 && ts.isNamedImports(b2)) {
1056
- for (const el of b2.elements) if (el.name.text === name) return el.name;
1057
- }
1058
- if (stmt.importClause?.name?.text === name) return stmt.importClause.name;
1059
- }
1060
- }
1061
- return void 0;
1047
+ function propEntry(ts, name, replacementSpan) {
1048
+ return {
1049
+ name,
1050
+ kind: ts.ScriptElementKind.memberVariableElement,
1051
+ kindModifiers: "",
1052
+ sortText: "0_" + name,
1053
+ insertText: name,
1054
+ // Without a span the editor filters these against whatever word *it* computes at the
1055
+ // cursor, and inside a template literal that is not the attribute name so the list
1056
+ // showed in full until the first keystroke and then emptied. Saying exactly which
1057
+ // characters are being replaced makes filtering match what is typed.
1058
+ replacementSpan
1059
+ };
1060
+ }
1061
+ function attrNameSpan(text, position) {
1062
+ const isNameChar = (c) => !!c && /[A-Za-z0-9_$:@?.\-]/.test(c);
1063
+ let start = position;
1064
+ while (start > 0 && isNameChar(text[start - 1])) start--;
1065
+ let end = position;
1066
+ while (end < text.length && isNameChar(text[end])) end++;
1067
+ return { start, length: end - start };
1068
+ }
1069
+ function componentTypeOf(ts, program, checker, host, sf, template, name) {
1070
+ const flags = ts.SymbolFlags.Value | ts.SymbolFlags.Function | ts.SymbolFlags.Class | ts.SymbolFlags.Alias;
1071
+ const symbol = checker.getSymbolsInScope(template, flags).find((s2) => s2.name === name) ?? autoImportedSymbol(ts, program, host, sf, name);
1072
+ if (!symbol) return void 0;
1073
+ const resolved = symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
1074
+ const decl = resolved.valueDeclaration ?? resolved.declarations?.[0];
1075
+ return decl ? checker.getTypeOfSymbolAtLocation(resolved, decl) : void 0;
1062
1076
  }
1063
1077
  function firstParamType(ts, checker, type) {
1064
1078
  for (const sig of checker.getSignaturesOfType(type, ts.SignatureKind.Call)) {
1065
- const p2 = sig.getParameters()[0];
1066
- if (p2) return checker.getTypeOfSymbolAtLocation(p2, p2.valueDeclaration ?? sig.getDeclaration());
1079
+ const p3 = sig.getParameters()[0];
1080
+ if (p3) return checker.getTypeOfSymbolAtLocation(p3, p3.valueDeclaration ?? sig.getDeclaration());
1067
1081
  }
1068
1082
  return void 0;
1069
1083
  }
@@ -1076,7 +1090,7 @@ function componentTagAtAttrArea(ts, sf, tpl, position) {
1076
1090
  const c = node;
1077
1091
  const openStart = c.loc.start + 1 + (c.tag ? c.tag.length : 0);
1078
1092
  const openEnd = firstChildOrCloseStart(c);
1079
- if (position > openStart && position <= openEnd) {
1093
+ if (position > openStart && position < openEnd) {
1080
1094
  hit = { tag: c.tag, attributeNames: attributeNames(c) };
1081
1095
  }
1082
1096
  }
@@ -1094,8 +1108,8 @@ function firstChildOrCloseStart(c) {
1094
1108
  }
1095
1109
  function attributeNames(c) {
1096
1110
  const out = [];
1097
- for (const a of c.attributes) {
1098
- if (a.kind === "Attribute" || a.kind === "PropertyBinding" || a.kind === "BindDirective") out.push(a.name);
1111
+ for (const a2 of c.attributes) {
1112
+ if (a2.kind === "Attribute" || a2.kind === "PropertyBinding" || a2.kind === "BindDirective") out.push(a2.name);
1099
1113
  }
1100
1114
  return out;
1101
1115
  }
@@ -1112,13 +1126,13 @@ function paramMemberCompletions(ts, ls, fileName, position) {
1112
1126
  const checker = program.getTypeChecker();
1113
1127
  const already = /* @__PURE__ */ new Set();
1114
1128
  const entries = [];
1115
- for (const p2 of checker.getApparentType(info.type).getProperties()) {
1116
- const name = p2.getName();
1129
+ for (const p3 of checker.getApparentType(info.type).getProperties()) {
1130
+ const name = p3.getName();
1117
1131
  if (already.has(name) || name.startsWith("__")) continue;
1118
1132
  already.add(name);
1119
1133
  entries.push({
1120
1134
  name,
1121
- kind: memberKind(ts, p2),
1135
+ kind: memberKind(ts, p3),
1122
1136
  kindModifiers: "",
1123
1137
  sortText: "0_" + name,
1124
1138
  insertText: name
@@ -1206,8 +1220,8 @@ function elementAtAttributeArea(ts, sf, tpl, position) {
1206
1220
  const openEnd = firstAttributeEnd(el);
1207
1221
  if (position > openStart && position <= openEnd) {
1208
1222
  const present = /* @__PURE__ */ new Set();
1209
- for (const a of el.attributes) {
1210
- if ("loc" in a && a.loc) present.add(writtenName(sf.text, a.loc.start));
1223
+ for (const a2 of el.attributes) {
1224
+ if ("loc" in a2 && a2.loc) present.add(writtenName(sf.text, a2.loc.start));
1211
1225
  }
1212
1226
  hit = { tag: el.tag, present };
1213
1227
  }
@@ -1226,8 +1240,8 @@ function writtenName(text, start) {
1226
1240
  }
1227
1241
  function firstAttributeEnd(el) {
1228
1242
  let end = el.loc.start + 1 + el.tag.length;
1229
- for (const a of el.attributes) {
1230
- if ("loc" in a && a.loc) end = Math.max(end, a.loc.end);
1243
+ for (const a2 of el.attributes) {
1244
+ if ("loc" in a2 && a2.loc) end = Math.max(end, a2.loc.end);
1231
1245
  }
1232
1246
  return end + 1;
1233
1247
  }
@@ -1242,8 +1256,8 @@ function elementAttributeCompletions(ts, ls, host, fileName, position) {
1242
1256
  const props = attributesFor(ts, program, host, sf, hit.tag);
1243
1257
  if (!props) return void 0;
1244
1258
  const entries = [];
1245
- for (const p2 of props) {
1246
- const name = p2.getName();
1259
+ for (const p3 of props) {
1260
+ const name = p3.getName();
1247
1261
  if (name === "children" || hit.present.has(name)) continue;
1248
1262
  entries.push({
1249
1263
  name,
@@ -1261,9 +1275,9 @@ function attributeNameAt(ts, sf, tpl, position) {
1261
1275
  for (const node of nodes) {
1262
1276
  if (node.kind === "Element") {
1263
1277
  const el = node;
1264
- for (const a of el.attributes) {
1265
- if (!("loc" in a) || !a.loc) continue;
1266
- const start = a.loc.start;
1278
+ for (const a2 of el.attributes) {
1279
+ if (!("loc" in a2) || !a2.loc) continue;
1280
+ const start = a2.loc.start;
1267
1281
  const name = writtenName(sf.text, start);
1268
1282
  if (name && position >= start && position <= start + name.length) {
1269
1283
  hit = { tag: el.tag, name, start };
@@ -1286,7 +1300,7 @@ function elementAttributeHover(ts, ls, host, fileName, position) {
1286
1300
  const hit = attributeNameAt(ts, sf, tpl.template, position);
1287
1301
  if (!hit) return void 0;
1288
1302
  const props = attributesFor(ts, program, host, sf, hit.tag);
1289
- const symbol = props?.find((p2) => p2.getName() === hit.name);
1303
+ const symbol = props?.find((p3) => p3.getName() === hit.name);
1290
1304
  if (!symbol) return void 0;
1291
1305
  const decl = symbol.valueDeclaration ?? symbol.declarations?.[0];
1292
1306
  if (!decl) return void 0;
@@ -1326,7 +1340,7 @@ function accessorDiagnostics(ts, program, sf) {
1326
1340
  for (const template of templatesIn(ts, sf)) {
1327
1341
  const tpl = template.template;
1328
1342
  if (ts.isNoSubstitutionTemplateLiteral(tpl)) continue;
1329
- const holes = tpl.templateSpans.map((s) => s.expression);
1343
+ const holes = tpl.templateSpans.map((s2) => s2.expression);
1330
1344
  const visit = (nodes, parent) => {
1331
1345
  for (const node of nodes) {
1332
1346
  if (node.kind === "Expression" && parent?.kind === "Element") {
@@ -1359,7 +1373,7 @@ function isAccessor(ts, checker, node) {
1359
1373
  const signatures = checker.getTypeAtLocation(node).getCallSignatures();
1360
1374
  if (signatures.length !== 1) return false;
1361
1375
  const signature = signatures[0];
1362
- if (signature.getParameters().some((p2) => !isOptional(ts, p2))) return false;
1376
+ if (signature.getParameters().some((p3) => !isOptional(ts, p3))) return false;
1363
1377
  const returned = signature.getReturnType();
1364
1378
  return !(returned.flags & (ts.TypeFlags.Void | ts.TypeFlags.Never));
1365
1379
  }
@@ -1436,7 +1450,7 @@ function templateFixAll(ts, ls, fileName, errorCodes) {
1436
1450
  textChanges.push({ span: { start: at, length: 0 }, newText: "()" });
1437
1451
  }
1438
1452
  if (textChanges.length === 0) return void 0;
1439
- textChanges.sort((a, b2) => b2.span.start - a.span.start);
1453
+ textChanges.sort((a2, b2) => b2.span.start - a2.span.start);
1440
1454
  return { changes: [{ fileName, textChanges }], commands: void 0 };
1441
1455
  }
1442
1456
 
@@ -1475,12 +1489,12 @@ function closingTagName(text, end, tag) {
1475
1489
  }
1476
1490
  function tagAt(ts, sf, position) {
1477
1491
  if (!templateAtCached(ts, sf, position)) return void 0;
1478
- return tagSpans(ts, sf).find((s) => position >= s.start && position <= s.start + s.length);
1492
+ return tagSpans(ts, sf).find((s2) => position >= s2.start && position <= s2.start + s2.length);
1479
1493
  }
1480
1494
  function symbolFor(ts, program, host, location, name) {
1481
1495
  const checker = program.getTypeChecker();
1482
1496
  const flags = ts.SymbolFlags.Value | ts.SymbolFlags.Function | ts.SymbolFlags.Class | ts.SymbolFlags.Alias;
1483
- const symbol = checker.getSymbolsInScope(location, flags).find((s) => s.name === name);
1497
+ const symbol = checker.getSymbolsInScope(location, flags).find((s2) => s2.name === name);
1484
1498
  if (!symbol) return autoImportedSymbol(ts, program, host, location.getSourceFile(), name);
1485
1499
  return symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
1486
1500
  }
@@ -1605,13 +1619,19 @@ function init(modules) {
1605
1619
  isGlobalCompletion: false,
1606
1620
  isMemberCompletion: false,
1607
1621
  isNewIdentifierLocation: true,
1622
+ // Re-ask on every keystroke instead of letting the editor filter what it already
1623
+ // has. Inside a template the valid set changes with the cursor — a tag name, then
1624
+ // that tag's props — and a list cached from one position is wrong at the next.
1625
+ // Without this the props appear only after enough typing to force a fresh
1626
+ // request, which reads as completion working intermittently.
1627
+ isIncomplete: true,
1608
1628
  entries
1609
1629
  });
1610
1630
  const IMPLICIT_ANY = /* @__PURE__ */ new Set([7006, 7044]);
1611
1631
  const dedupe = (items) => {
1612
1632
  const seen = /* @__PURE__ */ new Set();
1613
- return items.filter((i) => {
1614
- const key = `${i.fileName}:${i.textSpan.start}:${i.textSpan.length}`;
1633
+ return items.filter((i2) => {
1634
+ const key = `${i2.fileName}:${i2.textSpan.start}:${i2.textSpan.length}`;
1615
1635
  if (seen.has(key)) return false;
1616
1636
  seen.add(key);
1617
1637
  return true;
@@ -1639,7 +1659,7 @@ function init(modules) {
1639
1659
  proxy.getSuggestionDiagnostics = (fileName) => reliableFilter(fileName, ls.getSuggestionDiagnostics(fileName));
1640
1660
  proxy.getQuickInfoAtPosition = (fileName, position) => {
1641
1661
  try {
1642
- const prop = componentPropHover(ts, ls, fileName, position);
1662
+ const prop = componentPropHover(ts, ls, host, fileName, position);
1643
1663
  if (prop) return prop;
1644
1664
  } catch {
1645
1665
  }
@@ -1662,7 +1682,7 @@ function init(modules) {
1662
1682
  };
1663
1683
  proxy.getCompletionsAtPosition = (fileName, position, options, formatting) => {
1664
1684
  try {
1665
- const props = componentPropCompletions(ts, ls, fileName, position);
1685
+ const props = componentPropCompletions(ts, ls, host, fileName, position);
1666
1686
  if (props) return completionList(props);
1667
1687
  } catch {
1668
1688
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluixi/ts-plugin",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -16,7 +16,8 @@
16
16
  ],
17
17
  "main": "./dist/index.js",
18
18
  "dependencies": {
19
- "@fluixi/template-parser": "0.1.0-alpha.2"
19
+ "@fluixi/template-parser": "0.1.0-alpha.3",
20
+ "@fluixi/compiler": "1.0.0-alpha.70"
20
21
  },
21
22
  "devDependencies": {
22
23
  "esbuild": "^0.24.0",