gofront 1.7.0 → 1.8.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.
- package/README.md +13 -13
- package/package.json +8 -37
- package/src/backend/js/expressions.js +1341 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +375 -57
- package/src/backend/js/runtime.js +1460 -133
- package/src/backend/js/statements.js +900 -86
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +2 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +8 -3
- package/src/backend/js/stdlib/json.js +247 -52
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +10 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +436 -80
- package/src/backend/wasm/emit-builtins.js +303 -13
- package/src/backend/wasm/emit-exprs.js +1397 -203
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +512 -77
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +0 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +200 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +47 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +107 -269
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +176 -32
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +69 -9
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +176 -17
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +931 -122
- package/src/typechecker/index.js +459 -67
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +451 -56
- package/src/typechecker/statements.js +90 -9
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +322 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +5 -5
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +149 -25
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -4,25 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
// Parsers return [value, msg|null] from the shared __strconv_* helpers
|
|
6
6
|
// (runtime.js); the message becomes a Go error value.
|
|
7
|
-
const parsed = (call, toValue = "r[0]") =>
|
|
8
|
-
`((r) => [${toValue}, r[1] === null ? null : __error(r[1], r[1].includes("invalid syntax") ? __strconv_err_syntax : r[1].includes("value out of range") ? __strconv_err_range : null)])(${call})`;
|
|
7
|
+
const parsed = (fnName, numArg, call, toValue = "r[0]") =>
|
|
8
|
+
`((r, s) => [${toValue}, r[1] === null ? null : (typeof NumError$$strconv !== "undefined" ? ((o) => { o.__p = true; return o; })(new NumError$$strconv("${fnName}", String(s), r[1].includes("value out of range") ? __strconv_err_range : __strconv_err_syntax)) : __error(r[1], r[1].includes("invalid syntax") ? __strconv_err_syntax : r[1].includes("value out of range") ? __strconv_err_range : null))])(${call}, ${numArg})`;
|
|
9
9
|
|
|
10
10
|
const STRCONV_DISPATCH = {
|
|
11
11
|
Itoa: (a) => `String(${a[0]})`,
|
|
12
|
-
Atoi: (a) => parsed(`__strconv_atoi(${a[0]})`, "Number(r[0])"),
|
|
12
|
+
Atoi: (a) => parsed("Atoi", a[0], `__strconv_atoi(${a[0]})`, "Number(r[0])"),
|
|
13
13
|
FormatBool: (a) => `String(${a[0]})`,
|
|
14
14
|
FormatInt: (a) => `(${a[0]}).toString(${a[1]})`,
|
|
15
15
|
FormatFloat: (a) =>
|
|
16
16
|
a.length < 3
|
|
17
17
|
? `String(${a[0]})`
|
|
18
18
|
: `__strconv_format_float(${a[0]}, ${a[1]}, ${a[2]})`,
|
|
19
|
-
ParseFloat: (a) =>
|
|
19
|
+
ParseFloat: (a) =>
|
|
20
|
+
parsed("ParseFloat", a[0], `__strconv_parse_float(${a[0]})`),
|
|
20
21
|
ParseInt: (a) =>
|
|
21
22
|
parsed(
|
|
23
|
+
"ParseInt",
|
|
24
|
+
a[0],
|
|
22
25
|
`__strconv_parse_int(${a[0]}, ${a[1]}, ${a[2] ?? 64})`,
|
|
23
26
|
"Number(r[0])",
|
|
24
27
|
),
|
|
25
|
-
ParseBool: (a) => parsed(`__strconv_parse_bool(${a[0]})`),
|
|
28
|
+
ParseBool: (a) => parsed("ParseBool", a[0], `__strconv_parse_bool(${a[0]})`),
|
|
26
29
|
Quote: (a) => `JSON.stringify(${a[0]})`,
|
|
27
30
|
Unquote: (a) =>
|
|
28
31
|
`((s) => { if (typeof s === "string" && s.startsWith("\`") && s.endsWith("\`") && s.length >= 2) { if (s.slice(1, -1).includes("\`")) return ["", __strconv_err_syntax]; return [s.slice(1, -1), null]; } try { const v = JSON.parse(s); if (typeof v !== "string") throw 0; return [v, null]; } catch(e) { return ["", __strconv_err_syntax]; } })(${a[0]})`,
|
|
@@ -37,6 +40,8 @@ const STRCONV_DISPATCH = {
|
|
|
37
40
|
FormatUint: (a) => `(BigInt.asUintN(64, BigInt(${a[0]}))).toString(${a[1]})`,
|
|
38
41
|
ParseUint: (a) =>
|
|
39
42
|
parsed(
|
|
43
|
+
"ParseUint",
|
|
44
|
+
a[0],
|
|
40
45
|
`__strconv_parse_uint(${a[0]}, ${a[1]}, ${a[2] ?? 64})`,
|
|
41
46
|
"Number(r[0])",
|
|
42
47
|
),
|
|
@@ -16,9 +16,9 @@ const STRINGS_M2 = {
|
|
|
16
16
|
LastIndex: "lastIndexOf",
|
|
17
17
|
Repeat: "repeat",
|
|
18
18
|
Split: "split",
|
|
19
|
-
Join: "join",
|
|
20
19
|
};
|
|
21
20
|
const STRINGS_DISPATCH = {
|
|
21
|
+
Join: ([a, sep]) => `(${a} ?? []).join(${sep})`,
|
|
22
22
|
Count: ([s, s2]) =>
|
|
23
23
|
`((s, sep) => sep === "" ? s.length + 1 : s.split(sep).length - 1)(${s}, ${s2})`,
|
|
24
24
|
Replace: ([s, s2, s3, n]) =>
|
|
@@ -37,7 +37,8 @@ const STRINGS_DISPATCH = {
|
|
|
37
37
|
TrimRight: ([s, s2]) =>
|
|
38
38
|
`((str, cut) => { const cs = new Set(cut); let j = str.length; while (j > 0 && cs.has(str[j - 1])) j--; return str.slice(0, j); })(${s}, ${s2})`,
|
|
39
39
|
EqualFold: ([s, s2]) => `${s}.toLowerCase() === ${s2}.toLowerCase()`,
|
|
40
|
-
Fields: ([s]) =>
|
|
40
|
+
Fields: ([s]) =>
|
|
41
|
+
`(${s}).split(/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+/).filter(p => p !== "")`,
|
|
41
42
|
FieldsFunc: ([s, f]) =>
|
|
42
43
|
`((s, fn) => { const res = []; const runes = Array.from(s ?? ""); let cur = ""; for (const ch of runes) { const cp = ch.codePointAt(0); if (fn(cp)) { if (cur.length > 0) { res.push(cur); cur = ""; } } else { cur += ch; } } if (cur.length > 0) res.push(cur); return res; })(${s}, ${f})`,
|
|
43
44
|
Cut: ([s, s2]) =>
|
|
@@ -169,8 +170,83 @@ const STRINGS_DISPATCH = {
|
|
|
169
170
|
`((s, f) => { for (let i = 0; i < s.length; i++) { const cp = s.codePointAt(i); if (f(cp)) return i; if (cp > 0xFFFF) i++; } return -1; })(${s}, ${s2})`,
|
|
170
171
|
LastIndexFunc: ([s, s2]) =>
|
|
171
172
|
`((s, f) => { for (let i = s.length - 1; i >= 0; i--) { let cp = s.codePointAt(i); if (i > 0 && s.charCodeAt(i) >= 0xDC00 && s.charCodeAt(i) <= 0xDFFF && s.charCodeAt(i - 1) >= 0xD800 && s.charCodeAt(i - 1) <= 0xDBFF) { cp = s.codePointAt(i - 1); i--; } if (f(cp)) return i; } return -1; })(${s}, ${s2})`,
|
|
173
|
+
ToValidUTF8: ([s, repl]) =>
|
|
174
|
+
`(${s} ? ${s}.replace(/(?:[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF])+/g, ${repl} ?? "") : (${s} ?? ""))`,
|
|
172
175
|
NewReader: ([s]) =>
|
|
173
|
-
`((s) => ({
|
|
176
|
+
`((s) => ({
|
|
177
|
+
_bytes: new TextEncoder().encode(s ?? ""),
|
|
178
|
+
_pos: 0,
|
|
179
|
+
_prevRune: -1,
|
|
180
|
+
Read(p) {
|
|
181
|
+
if (this._pos >= this._bytes.length) return [0, __io_eof];
|
|
182
|
+
const n = Math.min(p.length, this._bytes.length - this._pos);
|
|
183
|
+
for (let i = 0; i < n; i++) p[i] = this._bytes[this._pos + i];
|
|
184
|
+
this._pos += n;
|
|
185
|
+
this._prevRune = -1;
|
|
186
|
+
return [n, null];
|
|
187
|
+
},
|
|
188
|
+
ReadAt(b, off) {
|
|
189
|
+
const o = Number(off);
|
|
190
|
+
if (o < 0) return [0, __error("strings.Reader.ReadAt: negative offset")];
|
|
191
|
+
if (o >= this._bytes.length) return [0, __io_eof];
|
|
192
|
+
const n = Math.min(b.length, this._bytes.length - o);
|
|
193
|
+
for (let i = 0; i < n; i++) b[i] = this._bytes[o + i];
|
|
194
|
+
return [n, n < b.length ? __io_eof : null];
|
|
195
|
+
},
|
|
196
|
+
ReadByte() {
|
|
197
|
+
if (this._pos >= this._bytes.length) return [0, __io_eof];
|
|
198
|
+
this._prevRune = -1;
|
|
199
|
+
return [this._bytes[this._pos++], null];
|
|
200
|
+
},
|
|
201
|
+
UnreadByte() {
|
|
202
|
+
if (this._pos <= 0) return __error("strings.Reader.UnreadByte: at beginning of string");
|
|
203
|
+
this._prevRune = -1;
|
|
204
|
+
this._pos--;
|
|
205
|
+
return null;
|
|
206
|
+
},
|
|
207
|
+
ReadRune() {
|
|
208
|
+
if (this._pos >= this._bytes.length) return [0, 0, __io_eof];
|
|
209
|
+
const rem = this._bytes.subarray(this._pos);
|
|
210
|
+
const str = new TextDecoder().decode(rem);
|
|
211
|
+
const cp = str.codePointAt(0);
|
|
212
|
+
const runeStr = str.slice(0, cp > 0xffff ? 2 : 1);
|
|
213
|
+
const sz = new TextEncoder().encode(runeStr).length;
|
|
214
|
+
this._prevRune = this._pos;
|
|
215
|
+
this._pos += sz;
|
|
216
|
+
return [cp, sz, null];
|
|
217
|
+
},
|
|
218
|
+
UnreadRune() {
|
|
219
|
+
if (this._prevRune === undefined || this._prevRune < 0 || this._prevRune >= this._pos) {
|
|
220
|
+
return __error("strings.Reader.UnreadRune: previous operation was not ReadRune");
|
|
221
|
+
}
|
|
222
|
+
this._pos = this._prevRune;
|
|
223
|
+
this._prevRune = -1;
|
|
224
|
+
return null;
|
|
225
|
+
},
|
|
226
|
+
Seek(offset, whence) {
|
|
227
|
+
const off = BigInt(offset);
|
|
228
|
+
const w = Number(whence);
|
|
229
|
+
let newPos;
|
|
230
|
+
if (w === 0) newPos = off;
|
|
231
|
+
else if (w === 1) newPos = BigInt(this._pos) + off;
|
|
232
|
+
else if (w === 2) newPos = BigInt(this._bytes.length) + off;
|
|
233
|
+
else return [0n, __error("strings.Reader.Seek: invalid whence")];
|
|
234
|
+
if (newPos < 0n) return [0n, __error("strings.Reader.Seek: negative position")];
|
|
235
|
+
this._pos = Number(newPos);
|
|
236
|
+
this._prevRune = -1;
|
|
237
|
+
return [newPos, null];
|
|
238
|
+
},
|
|
239
|
+
Size() { return BigInt(this._bytes.length); },
|
|
240
|
+
WriteTo(w) {
|
|
241
|
+
if (this._pos >= this._bytes.length) return [0, null];
|
|
242
|
+
const rem = this._bytes.subarray(this._pos);
|
|
243
|
+
const [n, err] = w.Write(rem);
|
|
244
|
+
this._pos += n;
|
|
245
|
+
return [n, err];
|
|
246
|
+
},
|
|
247
|
+
Len() { return Math.max(0, this._bytes.length - this._pos); },
|
|
248
|
+
Reset(s2) { this._bytes = new TextEncoder().encode(s2 ?? ""); this._pos = 0; this._prevRune = -1; }
|
|
249
|
+
}))(${s})`,
|
|
174
250
|
NewReplacer: (args) =>
|
|
175
251
|
`((...pairs) => {
|
|
176
252
|
const p = [];
|
|
@@ -211,7 +287,10 @@ const STRINGS_DISPATCH = {
|
|
|
211
287
|
/** @type {ThisType<CodeGen>} */
|
|
212
288
|
export const stringsMethods = {
|
|
213
289
|
_genStrings(fn, a) {
|
|
214
|
-
if (fn === "NewReader")
|
|
290
|
+
if (fn === "NewReader") {
|
|
291
|
+
this.useHelper("ioEOF");
|
|
292
|
+
this.useHelper("error");
|
|
293
|
+
}
|
|
215
294
|
const args = a();
|
|
216
295
|
const [s, s2] = args;
|
|
217
296
|
if (STRINGS_M1[fn]) return `${s}.${STRINGS_M1[fn]}()`;
|
|
@@ -10,6 +10,13 @@ export const testingMethods = {
|
|
|
10
10
|
return "false";
|
|
11
11
|
case "Verbose":
|
|
12
12
|
return "Boolean(globalThis.__gofront_verbose)";
|
|
13
|
+
case "Testing":
|
|
14
|
+
return "true";
|
|
15
|
+
case "Init":
|
|
16
|
+
return "/* testing.Init */";
|
|
17
|
+
case "Benchmark":
|
|
18
|
+
this.useHelper("testing");
|
|
19
|
+
return `__testing_Benchmark(${_a()[0]})`;
|
|
13
20
|
}
|
|
14
21
|
return undefined;
|
|
15
22
|
},
|
|
@@ -3,53 +3,52 @@
|
|
|
3
3
|
/** @typedef {import('../index.js').CodeGen} CodeGen */
|
|
4
4
|
|
|
5
5
|
const TIME_METHOD_DISPATCH = {
|
|
6
|
-
Year: (r) =>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Minute: (r) =>
|
|
14
|
-
`(${r}._offset === 0 ? ${r}._d.getUTCMinutes() : ${r}._d.getMinutes())`,
|
|
15
|
-
Second: (r) =>
|
|
16
|
-
`(${r}._offset === 0 ? ${r}._d.getUTCSeconds() : ${r}._d.getSeconds())`,
|
|
17
|
-
Weekday: (r) =>
|
|
18
|
-
`(${r}._offset === 0 ? ${r}._d.getUTCDay() : ${r}._d.getDay())`,
|
|
6
|
+
Year: (r) => `__timeYear(${r})`,
|
|
7
|
+
Month: (r) => `__timeMonth(${r})`,
|
|
8
|
+
Day: (r) => `__timeDay(${r})`,
|
|
9
|
+
Hour: (r) => `__timeHour(${r})`,
|
|
10
|
+
Minute: (r) => `__timeMinute(${r})`,
|
|
11
|
+
Second: (r) => `__timeSecond(${r})`,
|
|
12
|
+
Weekday: (r) => `__timeWeekday(${r})`,
|
|
19
13
|
Unix: (r) => `Math.floor(${r}._d.getTime() / 1000)`,
|
|
20
14
|
UnixMilli: (r) => `${r}._d.getTime()`,
|
|
21
15
|
Add: (r, a) =>
|
|
22
|
-
`{_d: new Date(${r}._d.getTime() + Math.round(Number(${a[0]}) / 1000000))}`,
|
|
16
|
+
`{_d: new Date(${r}._d.getTime() + Math.round(Number(${a[0]}) / 1000000)), _offset: ${r}._offset, _loc: ${r}._loc, _ns: ${r}._ns}`,
|
|
23
17
|
Sub: (r, a) =>
|
|
24
18
|
`Math.round((${r}._d.getTime() - (${a[0]})._d.getTime()) * 1000000)`,
|
|
25
19
|
Before: (r, a) => `(${r}._d < (${a[0]})._d)`,
|
|
26
20
|
After: (r, a) => `(${r}._d > (${a[0]})._d)`,
|
|
27
|
-
Equal: (r, a) =>
|
|
21
|
+
Equal: (r, a) =>
|
|
22
|
+
`(${r}._d.getTime() === (${a[0]})._d.getTime() && (${r}._ns || 0) === ((${a[0]})._ns || 0))`,
|
|
28
23
|
IsZero: (r) =>
|
|
29
24
|
`(!${r} || !${r}._d || ${r}._isZero === true || ${r}._d.getTime() === -62135596800000 || (${r}._d.getUTCFullYear() <= 1 && ${r}._d.getUTCMonth() === 0 && ${r}._d.getUTCDate() === 1 && ${r}._d.getUTCHours() === 0 && ${r}._d.getUTCMinutes() === 0 && ${r}._d.getUTCSeconds() === 0 && ${r}._d.getUTCMilliseconds() === 0))`,
|
|
30
|
-
UnixNano: (r) =>
|
|
25
|
+
UnixNano: (r) =>
|
|
26
|
+
`(${r}?._d ? Math.round(${r}._d.getTime() * 1000000) + (${r}._ns || 0) : 0)`,
|
|
31
27
|
Nanosecond: (r) =>
|
|
32
|
-
`(${r}?._d ? (${r}._offset ===
|
|
33
|
-
UTC: (r) =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
`({_d:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Round: (r, a) =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Clock: (r) =>
|
|
44
|
-
`[${r}._offset === 0 ? ${r}._d.getUTCHours() : ${r}._d.getHours(), ${r}._offset === 0 ? ${r}._d.getUTCMinutes() : ${r}._d.getMinutes(), ${r}._offset === 0 ? ${r}._d.getUTCSeconds() : ${r}._d.getSeconds()]`,
|
|
45
|
-
YearDay: (r) =>
|
|
46
|
-
`Math.floor((${r}._d - new Date(${r}._d.getFullYear(), 0, 0)) / 86400000)`,
|
|
28
|
+
`(${r}?._d ? (typeof ${r}._offset === "number" ? ${r}._d.getUTCMilliseconds() : ${r}._d.getMilliseconds()) * 1000000 + (${r}._ns || 0) : 0)`,
|
|
29
|
+
UTC: (r) =>
|
|
30
|
+
`({_d: ${r}?._d ?? new Date(0), _offset: 0, _loc: null, _ns: ${r}?._ns || 0})`,
|
|
31
|
+
Local: (r) =>
|
|
32
|
+
`({_d: ${r}?._d ?? new Date(0), _offset: undefined, _loc: null, _ns: ${r}?._ns || 0})`,
|
|
33
|
+
AddDate: (r, a) => `__timeAddDate(${r}, ${a[0]}, ${a[1]}, ${a[2]})`,
|
|
34
|
+
Truncate: (r, a) => `__timeTruncate(${r}, ${a[0]})`,
|
|
35
|
+
Round: (r, a) => `__timeRound(${r}, ${a[0]})`,
|
|
36
|
+
Date: (r) => `__timeDate(${r})`,
|
|
37
|
+
Clock: (r) => `__timeClock(${r})`,
|
|
38
|
+
YearDay: (r) => `__timeYearDay(${r})`,
|
|
47
39
|
Compare: (r, a) =>
|
|
48
|
-
`(${r}._d.getTime() < (${a[0]})._d.getTime() ? -1 : (${r}._d.getTime() > (${a[0]})._d.getTime() ? 1 : 0))`,
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
`(${r}._d.getTime() < (${a[0]})._d.getTime() ? -1 : (${r}._d.getTime() > (${a[0]})._d.getTime() ? 1 : ((${r}._ns || 0) < ((${a[0]})._ns || 0) ? -1 : ((${r}._ns || 0) > ((${a[0]})._ns || 0) ? 1 : 0))))`,
|
|
41
|
+
ISOWeek: (r) => `__timeISOWeek(${r})`,
|
|
42
|
+
In: (r, a) =>
|
|
43
|
+
`((() => { const _loc = ${a[0]}; const _off = _loc && typeof _loc._offset === "number" ? _loc._offset : 0; return { _d: ${r}._d, _offset: _off, _loc, _ns: ${r}._ns }; })())`,
|
|
44
|
+
Location: (r) =>
|
|
45
|
+
`(${r}._loc ?? (${r}._offset === 0 ? { _name: "UTC", _offset: 0, String() { return "UTC"; } } : { _name: "Local", _offset: -${r}._d.getTimezoneOffset() * 60, String() { return "Local"; } }))`,
|
|
51
46
|
Zone: (r) =>
|
|
52
|
-
`[${r}._offset === 0 ? "UTC" : "LOCAL", ${r}._offset === 0 ? 0 : -${r}._d.getTimezoneOffset() * 60]`,
|
|
47
|
+
`[${r}._loc ? ${r}._loc._name : (${r}._offset === 0 ? "UTC" : "LOCAL"), ${r}._loc ? ${r}._loc._offset : (${r}._offset === 0 ? 0 : -${r}._d.getTimezoneOffset() * 60)]`,
|
|
48
|
+
MarshalJSON: (r) => `__timeMarshalJSON(${r})`,
|
|
49
|
+
UnmarshalJSON: (r, a) => `__timeUnmarshalJSON(${r}, ${a[0]})`,
|
|
50
|
+
MarshalText: (r) => `__timeMarshalText(${r})`,
|
|
51
|
+
UnmarshalText: (r, a) => `__timeUnmarshalText(${r}, ${a[0]})`,
|
|
53
52
|
};
|
|
54
53
|
|
|
55
54
|
const DURATION_METHOD_DISPATCH = {
|
|
@@ -60,6 +59,9 @@ const DURATION_METHOD_DISPATCH = {
|
|
|
60
59
|
Minutes: (r) => `(Number(${r}) / 60000000000)`,
|
|
61
60
|
Hours: (r) => `(Number(${r}) / 3600000000000)`,
|
|
62
61
|
String: (r) => `__durationString(${r})`,
|
|
62
|
+
Truncate: (r, a) => `(${a[0]} <= 0 ? ${r} : ${r} - (${r} % ${a[0]}))`,
|
|
63
|
+
Round: (r, a) => `__durationRound(${r}, ${a[0]})`,
|
|
64
|
+
Abs: (r) => `(${r} >= 0 ? ${r} : -(${r}))`,
|
|
63
65
|
};
|
|
64
66
|
|
|
65
67
|
const TIME_DISPATCH = {
|
|
@@ -69,11 +71,16 @@ const TIME_DISPATCH = {
|
|
|
69
71
|
`(Math.round(((typeof globalThis.__GOFRONT_CLOCK === "function" ? globalThis.__GOFRONT_CLOCK() : Date.now()) - (${a[0]})._d.getTime()) * 1000000))`,
|
|
70
72
|
Sleep: (a) => `await new Promise(r => setTimeout(r, ${a[0]} / 1000000))`,
|
|
71
73
|
Unix: (a) =>
|
|
72
|
-
`{_d: new Date(Number(${a[0]}) * 1000 + Math.round(Number(${a[1] || 0}) / 1000000))}`,
|
|
73
|
-
UnixMicro: (a) =>
|
|
74
|
+
`{_d: new Date(Number(${a[0]}) * 1000 + Math.round(Number(${a[1] || 0}) / 1000000)), _ns: Math.round(Number(${a[1] || 0}) % 1000000)}`,
|
|
75
|
+
UnixMicro: (a) =>
|
|
76
|
+
`{_d: new Date(Math.round(Number(${a[0]}) / 1000)), _ns: Math.round((Number(${a[0]}) % 1000) * 1000)}`,
|
|
74
77
|
UnixMilli: (a) => `{_d: new Date(Number(${a[0]}))}`,
|
|
75
78
|
Date: (a) =>
|
|
76
|
-
`{_d: new Date(${a[0]}, ${a[1]} - 1, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, Math.round(Number(${a[6] || 0}) / 1000000))}`,
|
|
79
|
+
`{_d: new Date(${a[0]}, ${a[1]} - 1, ${a[2]}, ${a[3]}, ${a[4]}, ${a[5]}, Math.round(Number(${a[6] || 0}) / 1000000)), _ns: Math.round(Number(${a[6] || 0}) % 1000000)}`,
|
|
80
|
+
ParseDuration: (a) => `__timeParseDuration(${a[0]})`,
|
|
81
|
+
FixedZone: (a) =>
|
|
82
|
+
`({ _name: ${a[0]}, _offset: ${a[1]}, String() { return this._name; } })`,
|
|
83
|
+
AfterFunc: (a) => `__timeAfterFunc(${a[0]}, ${a[1]})`,
|
|
77
84
|
};
|
|
78
85
|
|
|
79
86
|
/** @type {ThisType<CodeGen>} */
|
|
@@ -82,12 +89,13 @@ export const timeMethods = {
|
|
|
82
89
|
const recv = expr.func.expr;
|
|
83
90
|
const recvJs = this.genExpr(recv);
|
|
84
91
|
const args = expr.args.map((a) => this.genExpr(a));
|
|
92
|
+
this.useHelper("timeFmt");
|
|
93
|
+
this.useHelper("duration");
|
|
94
|
+
this.useHelper("timeParse");
|
|
85
95
|
if (method === "Format") {
|
|
86
|
-
this.useHelper("timeFmt");
|
|
87
96
|
return `__timeFmt(${recvJs}, ${args[0]})`;
|
|
88
97
|
}
|
|
89
98
|
if (method === "String") {
|
|
90
|
-
this.useHelper("timeFmt");
|
|
91
99
|
return `__timeFmt(${recvJs}, "2006-01-02 15:04:05.999999999 -0700 MST")`;
|
|
92
100
|
}
|
|
93
101
|
const gen = TIME_METHOD_DISPATCH[method];
|
|
@@ -97,30 +105,46 @@ export const timeMethods = {
|
|
|
97
105
|
_genDurationMethodCall(method, expr) {
|
|
98
106
|
const recv = expr.func.expr;
|
|
99
107
|
const recvJs = this.genExpr(recv);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
108
|
+
const args = expr.args.map((a) => this.genExpr(a));
|
|
109
|
+
this.useHelper("duration");
|
|
103
110
|
const gen = DURATION_METHOD_DISPATCH[method];
|
|
104
|
-
return gen ? gen(recvJs) : undefined;
|
|
111
|
+
return gen ? gen(recvJs, args) : undefined;
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
_genTimeDate(args, expr) {
|
|
115
|
+
this.useHelper("timeFmt");
|
|
116
|
+
const locArg = expr?.args?.[7];
|
|
117
|
+
const isUtc =
|
|
118
|
+
(locArg?.kind === "SelectorExpr" &&
|
|
119
|
+
(locArg.sel?.name === "UTC" || locArg.field === "UTC")) ||
|
|
120
|
+
(locArg?.kind === "Ident" && locArg.name === "UTC") ||
|
|
121
|
+
args[7] === '"UTC"';
|
|
122
|
+
if (isUtc) {
|
|
123
|
+
return `{_d: new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.floor(Number(${args[6] || 0}) / 1000000))), _offset: 0, _loc: null, _ns: Math.floor(Number(${args[6] || 0}) % 1000000)}`;
|
|
124
|
+
}
|
|
125
|
+
return `((() => { const _loc = ${args[7]}; const _off = _loc && typeof _loc._offset === "number" ? _loc._offset : undefined; const _ms = Math.floor(Number(${args[6] || 0}) / 1000000); const _remNs = Math.floor(Number(${args[6] || 0}) % 1000000); if (_off !== undefined) { const _d = new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, _ms) - _off * 1000); return { _d, _offset: _off, _loc, _ns: _remNs }; } return { _d: new Date(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, _ms), _offset: undefined, _loc: null, _ns: _remNs }; })())`;
|
|
105
126
|
},
|
|
106
127
|
|
|
107
128
|
_genTime(fn, a, expr) {
|
|
129
|
+
if (fn === "Date") return this._genTimeDate(a(), expr);
|
|
108
130
|
if (fn === "Parse") {
|
|
109
131
|
this.useHelper("timeParse");
|
|
132
|
+
this.useHelper("timeFmt");
|
|
110
133
|
return `__timeParse(${a()[0]}, ${a()[1]})`;
|
|
111
134
|
}
|
|
112
|
-
if (fn === "
|
|
135
|
+
if (fn === "ParseDuration") {
|
|
136
|
+
this.useHelper("duration");
|
|
137
|
+
return `__timeParseDuration(${a()[0]})`;
|
|
138
|
+
}
|
|
139
|
+
if (fn === "FixedZone") {
|
|
140
|
+
this.useHelper("timeFmt");
|
|
141
|
+
const args = a();
|
|
142
|
+
return `({ _name: ${args[0]}, _offset: ${args[1]}, String() { return this._name; } })`;
|
|
143
|
+
}
|
|
144
|
+
if (fn === "AfterFunc") {
|
|
145
|
+
this.useHelper("timeFmt");
|
|
113
146
|
const args = a();
|
|
114
|
-
|
|
115
|
-
const isUtc =
|
|
116
|
-
(locArg?.kind === "SelectorExpr" &&
|
|
117
|
-
(locArg.sel?.name === "UTC" || locArg.field === "UTC")) ||
|
|
118
|
-
(locArg?.kind === "Ident" && locArg.name === "UTC") ||
|
|
119
|
-
args[7] === '"UTC"';
|
|
120
|
-
if (isUtc) {
|
|
121
|
-
return `{_d: new Date(Date.UTC(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.round(Number(${args[6] || 0}) / 1000000))), _offset: 0}`;
|
|
122
|
-
}
|
|
123
|
-
return `{_d: new Date(${args[0]}, ${args[1]} - 1, ${args[2]}, ${args[3]}, ${args[4]}, ${args[5]}, Math.round(Number(${args[6] || 0}) / 1000000))}`;
|
|
147
|
+
return `__timeAfterFunc(${args[0]}, ${args[1]})`;
|
|
124
148
|
}
|
|
125
149
|
const gen = TIME_DISPATCH[fn];
|
|
126
150
|
return gen ? gen(a()) : undefined;
|
|
@@ -10,7 +10,7 @@ export const unicodeMethods = {
|
|
|
10
10
|
const UNICODE_TEST = {
|
|
11
11
|
IsLetter: `/\\p{L}/u.test(${cp})`,
|
|
12
12
|
IsDigit: `/\\p{Nd}/u.test(${cp})`,
|
|
13
|
-
IsSpace:
|
|
13
|
+
IsSpace: `/[ \\t\\n\\v\\f\\r\\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]/.test(${cp})`,
|
|
14
14
|
IsUpper: `/\\p{Lu}/u.test(${cp})`,
|
|
15
15
|
IsLower: `/\\p{Ll}/u.test(${cp})`,
|
|
16
16
|
IsPunct: `/\\p{P}/u.test(${cp})`,
|
|
@@ -9,7 +9,7 @@ const UTF8_DISPATCH = {
|
|
|
9
9
|
ValidString: (a) =>
|
|
10
10
|
`/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/.test(${a[0]}) === false`,
|
|
11
11
|
ValidRune: (a) =>
|
|
12
|
-
`(${a[0]}) >= 0 && (${a[0]}) <= 0x10FFFF && !((${a[0]}) >= 0xD800 && (${a[0]}) <= 0xDFFF)`,
|
|
12
|
+
`((${a[0]}) >= 0 && (${a[0]}) <= 0x10FFFF && !((${a[0]}) >= 0xD800 && (${a[0]}) <= 0xDFFF))`,
|
|
13
13
|
DecodeRuneInString: (a) =>
|
|
14
14
|
`((s) => { if (!s) return [0xFFFD, 0]; const cp = s.codePointAt(0); return [cp, cp > 0xFFFF ? 2 : 1]; })(${a[0]})`,
|
|
15
15
|
DecodeLastRuneInString: (a) =>
|
package/src/backend/js/templ.js
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
// Mounts an HTML/expression tree onto a parent DOM node by emitting plain
|
|
3
3
|
// document.createElement / appendChild / setAttribute calls.
|
|
4
4
|
|
|
5
|
-
import { Parser } from "../../parser/index.js";
|
|
6
|
-
import { T, Token } from "../../tokens.js";
|
|
7
|
-
|
|
8
5
|
/** @typedef {import('./index.js').CodeGen} CodeGen */
|
|
9
6
|
|
|
10
7
|
/** @type {ThisType<CodeGen>} */
|
|
@@ -17,6 +14,12 @@ export const templGenMethods = {
|
|
|
17
14
|
.join(", ");
|
|
18
15
|
this.line(`function ${decl.name}(${params}) {`);
|
|
19
16
|
this.indented(() => {
|
|
17
|
+
// `@W(xs...)` passes `{ __sp: xs }` like any Go variadic call.
|
|
18
|
+
const last = decl.params[decl.params.length - 1];
|
|
19
|
+
if (last?.variadic && last.name && last.name !== "_") {
|
|
20
|
+
this.useHelper("va");
|
|
21
|
+
this.line(`${last.name} = __va(${last.name});`);
|
|
22
|
+
}
|
|
20
23
|
this.line(`return {Mount(___p, ___refs) {`);
|
|
21
24
|
this.indented(() => {
|
|
22
25
|
this._genTemplNodes(decl.body, "___p");
|
|
@@ -79,7 +82,7 @@ export const templGenMethods = {
|
|
|
79
82
|
);
|
|
80
83
|
case "TemplExpr":
|
|
81
84
|
return this.line(
|
|
82
|
-
`${p}.appendChild(document.createTextNode(String(${this.
|
|
85
|
+
`${p}.appendChild(document.createTextNode(String(${this._genTemplExpr(node, '""')})));`,
|
|
83
86
|
);
|
|
84
87
|
case "TemplComponent":
|
|
85
88
|
return this._genTemplComponentMount(node, p);
|
|
@@ -101,20 +104,12 @@ export const templGenMethods = {
|
|
|
101
104
|
|
|
102
105
|
_genTemplComponentMount(node, p) {
|
|
103
106
|
// Special case: @templ.Raw(expr) → insertAdjacentHTML
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
toks.length >= 4 &&
|
|
107
|
-
toks[0]?.value === "templ" &&
|
|
108
|
-
toks[1]?.type === T.DOT &&
|
|
109
|
-
toks[2]?.value === "Raw" &&
|
|
110
|
-
toks[3]?.type === T.LPAREN
|
|
111
|
-
) {
|
|
112
|
-
const argTokens = toks.slice(4, toks.length - 1);
|
|
113
|
-
const argJs = this._genTemplTokenExpr(argTokens);
|
|
107
|
+
if (node.raw) {
|
|
108
|
+
const argJs = this._genTemplExpr(node, '""');
|
|
114
109
|
return this.line(`${p}.insertAdjacentHTML("beforeend", ${argJs});`);
|
|
115
110
|
}
|
|
116
111
|
return this.line(
|
|
117
|
-
`(${this.
|
|
112
|
+
`(${this._genTemplExpr(node, "null")}).Mount(${p}, ___refs);`,
|
|
118
113
|
);
|
|
119
114
|
},
|
|
120
115
|
|
|
@@ -160,7 +155,7 @@ export const templGenMethods = {
|
|
|
160
155
|
);
|
|
161
156
|
}
|
|
162
157
|
} else if (attr.kind === "expr") {
|
|
163
|
-
const exprJs = this.
|
|
158
|
+
const exprJs = this._genTemplExpr(attr, '""');
|
|
164
159
|
if (name === "class") {
|
|
165
160
|
this.line(setClass(exprJs));
|
|
166
161
|
} else {
|
|
@@ -171,7 +166,7 @@ export const templGenMethods = {
|
|
|
171
166
|
} else if (attr.kind === "bool") {
|
|
172
167
|
this.line(`${el}.setAttribute(${JSON.stringify(name)}, "");`);
|
|
173
168
|
} else if (attr.kind === "cond-bool") {
|
|
174
|
-
const exprJs = this.
|
|
169
|
+
const exprJs = this._genTemplExpr(attr, '""');
|
|
175
170
|
this.line(
|
|
176
171
|
`if(${exprJs})${el}.setAttribute(${JSON.stringify(name)}, "");`,
|
|
177
172
|
);
|
|
@@ -179,7 +174,7 @@ export const templGenMethods = {
|
|
|
179
174
|
},
|
|
180
175
|
|
|
181
176
|
_genTemplIf(node, p) {
|
|
182
|
-
const condJs = this.
|
|
177
|
+
const condJs = this._genTemplExpr(node, "false");
|
|
183
178
|
this.line(`if (${condJs}) {`);
|
|
184
179
|
this.indented(() => this._genTemplNodes(node.then, p));
|
|
185
180
|
this._genTemplIfElse(node.else_, p);
|
|
@@ -192,7 +187,7 @@ export const templGenMethods = {
|
|
|
192
187
|
}
|
|
193
188
|
if (else_.length === 1 && else_[0].kind === "TemplIf") {
|
|
194
189
|
const elseIf = else_[0];
|
|
195
|
-
this.line(`} else if (${this.
|
|
190
|
+
this.line(`} else if (${this._genTemplExpr(elseIf, "false")}) {`);
|
|
196
191
|
this.indented(() => this._genTemplNodes(elseIf.then, p));
|
|
197
192
|
this._genTemplIfElse(elseIf.else_, p);
|
|
198
193
|
} else {
|
|
@@ -203,16 +198,16 @@ export const templGenMethods = {
|
|
|
203
198
|
},
|
|
204
199
|
|
|
205
200
|
_genTemplSwitch(node, p) {
|
|
206
|
-
const {
|
|
201
|
+
const { cases } = node;
|
|
207
202
|
if (cases.length === 0) return;
|
|
208
|
-
const exprJs = this.
|
|
203
|
+
const exprJs = this._genTemplExpr(node, '""');
|
|
209
204
|
this.line(`switch (${exprJs}) {`);
|
|
210
205
|
this.indented(() => {
|
|
211
206
|
for (const c of cases) {
|
|
212
207
|
const label =
|
|
213
208
|
c.caseTokens === null
|
|
214
209
|
? "default"
|
|
215
|
-
: `case ${this.
|
|
210
|
+
: `case ${this._genTemplExpr(c, '""')}`;
|
|
216
211
|
this.line(`${label}: {`);
|
|
217
212
|
this.indented(() => this._genTemplNodes(c.body, p));
|
|
218
213
|
this.line(`break; }`);
|
|
@@ -222,35 +217,10 @@ export const templGenMethods = {
|
|
|
222
217
|
},
|
|
223
218
|
|
|
224
219
|
_genTemplFor(node, p) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
while (tokens.length > 0 && tokens[tokens.length - 1].type === T.SEMICOLON)
|
|
230
|
-
tokens = tokens.slice(0, -1);
|
|
231
|
-
const eofTok = new Token(T.EOF, "", 1, 1);
|
|
232
|
-
const lbrace = new Token(T.LBRACE, "{", 1, 1);
|
|
233
|
-
const rbrace = new Token(T.RBRACE, "}", 1, 1);
|
|
234
|
-
const semi = new Token(T.SEMICOLON, ";", 1, 1);
|
|
235
|
-
const withFor =
|
|
236
|
-
tokens[0]?.type === T.FOR
|
|
237
|
-
? [...tokens, lbrace, rbrace, semi, eofTok]
|
|
238
|
-
: [
|
|
239
|
-
new Token(T.FOR, "for", 1, 1),
|
|
240
|
-
...tokens,
|
|
241
|
-
lbrace,
|
|
242
|
-
rbrace,
|
|
243
|
-
semi,
|
|
244
|
-
eofTok,
|
|
245
|
-
];
|
|
246
|
-
try {
|
|
247
|
-
const p2 = new Parser(withFor);
|
|
248
|
-
const forStmt = p2.parseFor();
|
|
249
|
-
this._genTemplRangeFor(forStmt, node.body, p);
|
|
250
|
-
} catch {
|
|
251
|
-
// Fallback for non-range loops: emit a comment + skip
|
|
252
|
-
this.line(`/* templ for: ${this._tokensToSource(tokens)} */`);
|
|
253
|
-
}
|
|
220
|
+
if (node.forError) throw node.forError;
|
|
221
|
+
if (!node.forStmt)
|
|
222
|
+
throw new Error("templ for header was not parsed by TemplParser");
|
|
223
|
+
this._genTemplRangeFor(node.forStmt, node.body, p);
|
|
254
224
|
},
|
|
255
225
|
|
|
256
226
|
_genTemplRangeFor(forStmt, templBody, mountParent) {
|
|
@@ -290,37 +260,29 @@ export const templGenMethods = {
|
|
|
290
260
|
return `for (const [${keyName}, ${valName}] of __s(${iterJs}).entries()) {`;
|
|
291
261
|
},
|
|
292
262
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
263
|
+
// Emit JS for the Go expression TemplParser parsed onto `node`. `emptyJs` is
|
|
264
|
+
// the value when the node holds no tokens. A parse error is raised here,
|
|
265
|
+
// not in the parser, so it surfaces at the same point as it always did.
|
|
266
|
+
_genTemplExpr(node, emptyJs) {
|
|
267
|
+
if (node.exprError) throw node.exprError;
|
|
268
|
+
if (node.expr === undefined)
|
|
269
|
+
throw new Error("templ expression was not parsed by TemplParser");
|
|
270
|
+
return node.expr ? this.genExpr(node.expr) : emptyJs;
|
|
300
271
|
},
|
|
301
272
|
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const ast = p.parseExpr();
|
|
308
|
-
return this.genExpr(ast);
|
|
273
|
+
// Rename handlers for `_renameReservedIdents`: templ bodies keep their Go
|
|
274
|
+
// expressions in non-enumerable props (see parser/templ.js), which its
|
|
275
|
+
// generic walk does not visit, so `class` in `{ class }` would stay unsafe.
|
|
276
|
+
_renameTemplExprNode(node) {
|
|
277
|
+
this._renameReservedIdents(node.expr);
|
|
309
278
|
},
|
|
310
279
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (!tokens || tokens.length === 0) return "false";
|
|
314
|
-
let toks = tokens;
|
|
315
|
-
if (toks[0]?.type === T.IF) toks = toks.slice(1); // skip `if` keyword
|
|
316
|
-
const eofTok = new Token(T.EOF, "", 1, 1);
|
|
317
|
-
const p = new Parser([...toks, eofTok]);
|
|
318
|
-
const ast = p.parseExpr();
|
|
319
|
-
return this.genExpr(ast);
|
|
280
|
+
_renameTemplForNode(node) {
|
|
281
|
+
this._renameReservedIdents(node.forStmt);
|
|
320
282
|
},
|
|
321
283
|
|
|
322
|
-
|
|
323
|
-
|
|
284
|
+
_renameTemplElementNode(node) {
|
|
285
|
+
for (const attr of node.attrs ?? []) this._renameReservedIdents(attr.expr);
|
|
324
286
|
},
|
|
325
287
|
|
|
326
288
|
// Fresh variable name counter
|