gofront 1.7.0 → 1.9.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 +14 -14
- package/package.json +10 -38
- package/src/backend/js/expressions.js +2060 -389
- package/src/backend/js/index.js +586 -174
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +936 -1644
- package/src/backend/js/statements.js +1349 -132
- package/src/backend/js/stdlib/index.js +51 -94
- package/src/backend/js/templ.js +67 -118
- package/src/backend/js/type-info.js +436 -0
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +80 -0
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +753 -872
- package/src/backend/wasm/emit-builtins.js +914 -237
- package/src/backend/wasm/emit-exprs.js +1456 -195
- package/src/backend/wasm/emit-maps.js +78 -380
- package/src/backend/wasm/emit-stmts.js +1659 -214
- package/src/backend/wasm/emit.js +614 -88
- package/src/backend/wasm/encode.js +43 -13
- package/src/backend/wasm/globals.js +491 -0
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +406 -3195
- package/src/backend/wasm/method-expr.js +392 -0
- package/src/backend/wasm/module-emitter.js +1615 -0
- package/src/backend/wasm/monomorph.js +164 -9
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +249 -0
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -37
- package/src/backend/wasm/stdlib/simd.js +293 -28
- package/src/backend/wasm/types.js +260 -27
- 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} +241 -11
- package/src/{test-runner.js → cli/test-runner.js} +188 -122
- package/src/{vendor.js → cli/vendor.js} +3 -4
- package/src/compiler.js +202 -386
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +203 -62
- package/src/{templ-lexer.js → lexer/templ-lexer.js} +61 -18
- package/src/{tokens.js → lexer/tokens.js} +2 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +737 -0
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +318 -0
- package/src/lower/bounds.js +547 -0
- package/src/lower/boxing.js +1 -1
- package/src/lower/captures.js +267 -64
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +33 -19
- package/src/lower/json-codecs.js +1379 -0
- package/src/lower/ownership.js +47 -8
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +150 -0
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +83 -15
- package/src/parser/expressions.js +110 -18
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +38 -22
- package/src/{templ-parser.js → parser/templ.js} +179 -17
- package/src/parser/types.js +70 -9
- package/src/resolver.js +21 -1
- package/src/typechecker/assignability.js +291 -19
- package/src/typechecker/const-fold.js +399 -0
- package/src/typechecker/constants.js +282 -0
- package/src/typechecker/expressions.js +1220 -183
- package/src/typechecker/index.js +659 -92
- package/src/typechecker/init-order.js +426 -0
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +613 -62
- package/src/typechecker/statements.js +212 -20
- package/src/typechecker/stdlib/excluded.js +902 -0
- package/src/typechecker/stdlib/index.js +38 -0
- package/src/typechecker/stdlib/simd.js +65 -15
- package/src/typechecker/termination.js +11 -2
- package/src/typechecker/types.js +268 -514
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +871 -0
- package/stdlib/internal/jsonrt/enc.go +516 -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 +658 -0
- package/stdlib/io/io.go +502 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +272 -0
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +500 -0
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +526 -0
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +250 -0
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -46
- package/src/backend/js/stdlib/builder.js +0 -63
- package/src/backend/js/stdlib/bytes.js +0 -122
- package/src/backend/js/stdlib/errors.js +0 -44
- package/src/backend/js/stdlib/fmt.js +0 -178
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -972
- package/src/backend/js/stdlib/maps.js +0 -45
- package/src/backend/js/stdlib/math.js +0 -69
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -24
- package/src/backend/js/stdlib/slices.js +0 -77
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -74
- package/src/backend/js/stdlib/strings.js +0 -222
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -34
- package/src/backend/js/stdlib/time.js +0 -128
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- package/src/backend/wasm/stdlib/bytes.js +0 -5039
- package/src/backend/wasm/stdlib/core.js +0 -8903
- package/src/backend/wasm/stdlib/io.js +0 -2161
- package/src/backend/wasm/stdlib/packages.js +0 -2400
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -1200
- package/src/typechecker/stdlib/core.js +0 -801
- package/src/typechecker/stdlib/extended.js +0 -914
- package/src/typechecker/stdlib.js +0 -22
- /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
|
@@ -1,74 +1,56 @@
|
|
|
1
1
|
// CodeGen stdlib call generation — installed as a mixin on CodeGen.prototype.
|
|
2
|
-
//
|
|
2
|
+
// Dispatches `gofront/shared` and `gofront/simd` calls to inline JS.
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { binaryMethods } from "./binary.js";
|
|
6
|
-
import { bitsMethods } from "./bits.js";
|
|
7
|
-
import { builderMethods } from "./builder.js";
|
|
8
|
-
import { bytesMethods } from "./bytes.js";
|
|
9
|
-
import { errorsMethods } from "./errors.js";
|
|
10
|
-
import { fmtMethods } from "./fmt.js";
|
|
11
|
-
import { gomMethods } from "./gom.js";
|
|
12
|
-
import { hexMethods } from "./hex.js";
|
|
13
|
-
import { htmlMethods } from "./html.js";
|
|
14
|
-
import { ioMethods } from "./io.js";
|
|
15
|
-
import { jsonMethods } from "./json.js";
|
|
16
|
-
import { mapsMethods } from "./maps.js";
|
|
17
|
-
import { mathMethods } from "./math.js";
|
|
18
|
-
import { osMethods } from "./os.js";
|
|
19
|
-
import { pathMethods } from "./path.js";
|
|
20
|
-
import { randMethods } from "./rand.js";
|
|
21
|
-
import { regexpMethods } from "./regexp.js";
|
|
22
|
-
import { sha256Methods } from "./sha256.js";
|
|
23
|
-
import { sharedMethods } from "./shared.js";
|
|
24
|
-
import { simdMethods } from "./simd.js";
|
|
25
|
-
import { slicesMethods } from "./slices.js";
|
|
26
|
-
import { sortMethods } from "./sort.js";
|
|
27
|
-
import { strconvMethods } from "./strconv.js";
|
|
28
|
-
import { stringsMethods } from "./strings.js";
|
|
29
|
-
import { syncMethods } from "./sync.js";
|
|
30
|
-
import { testingMethods } from "./testing.js";
|
|
31
|
-
import { timeMethods } from "./time.js";
|
|
32
|
-
import { unicodeMethods } from "./unicode.js";
|
|
33
|
-
import { utf8Methods } from "./utf8.js";
|
|
4
|
+
import { SHARED_KINDS } from "../../../typechecker/stdlib/shared.js";
|
|
34
5
|
|
|
35
6
|
/** @typedef {import('../index.js').CodeGen} CodeGen */
|
|
36
7
|
|
|
37
8
|
// Stdlib namespace → handler method name. Used by _genStdlibCall to dispatch
|
|
38
9
|
// dynamically without creating static call edges.
|
|
39
10
|
const STDLIB_METHOD_MAP = {
|
|
40
|
-
fmt: "_genFmt",
|
|
41
|
-
strings: "_genStrings",
|
|
42
|
-
bytes: "_genBytes",
|
|
43
|
-
strconv: "_genStrconv",
|
|
44
|
-
sort: "_genSort",
|
|
45
|
-
math: "_genMath",
|
|
46
|
-
bits: "_genBits",
|
|
47
|
-
unicode: "_genUnicode",
|
|
48
|
-
os: "_genOs",
|
|
49
|
-
errors: "_genErrors",
|
|
50
|
-
time: "_genTime",
|
|
51
|
-
regexp: "_genRegexp",
|
|
52
|
-
slices: "_genSlices",
|
|
53
|
-
maps: "_genMaps",
|
|
54
|
-
html: "_genHtml",
|
|
55
|
-
io: "_genIo",
|
|
56
|
-
rand: "_genRand",
|
|
57
|
-
utf8: "_genUtf8",
|
|
58
|
-
path: "_genPath",
|
|
59
|
-
filepath: "_genPath",
|
|
60
|
-
testing: "_genTesting",
|
|
61
11
|
shared: "_genShared",
|
|
62
|
-
sync: "_genSync",
|
|
63
|
-
sha256: "_genSha256",
|
|
64
|
-
binary: "_genBinary",
|
|
65
|
-
hex: "_genHex",
|
|
66
|
-
base64: "_genBase64",
|
|
67
|
-
json: "_genJson",
|
|
68
12
|
simd: "_genSimd",
|
|
69
13
|
};
|
|
70
14
|
|
|
71
15
|
const dispatchMethods = {
|
|
16
|
+
// `gofront/shared`: in js packages a shared buffer is just a TypedArray (no
|
|
17
|
+
// linear memory is involved); in wasm packages the facade hands out
|
|
18
|
+
// zero-copy views onto the module memory.
|
|
19
|
+
_genShared(fn, a) {
|
|
20
|
+
if (!fn.startsWith("New")) return undefined;
|
|
21
|
+
const info = SHARED_KINDS[fn.slice(3)];
|
|
22
|
+
if (!info) return undefined;
|
|
23
|
+
return `new ${info.ctor}(${a()[0]})`;
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
// `gofront/simd` in JS packages.
|
|
27
|
+
_genSimd(fn, a) {
|
|
28
|
+
this.useHelper("simd");
|
|
29
|
+
const args = a();
|
|
30
|
+
switch (fn) {
|
|
31
|
+
case "Splat":
|
|
32
|
+
return `__simd_splat(${args[0]})`;
|
|
33
|
+
case "NewF32x4":
|
|
34
|
+
return `__simd_f32x4(${args[0]}, ${args[1]}, ${args[2]}, ${args[3]})`;
|
|
35
|
+
case "Select":
|
|
36
|
+
return `__simd_select(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
37
|
+
case "Shuffle":
|
|
38
|
+
return `__simd_shuffle(${args.join(", ")})`;
|
|
39
|
+
case "LoadF32x4":
|
|
40
|
+
return `__simd_load(${args[0]}, ${args[1]})`;
|
|
41
|
+
case "StoreF32x4":
|
|
42
|
+
return `__simd_store(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
43
|
+
case "LoadF32x4Slice":
|
|
44
|
+
return `__simd_load_slice(${args[0]}, ${args[1]})`;
|
|
45
|
+
case "StoreF32x4Slice":
|
|
46
|
+
return `__simd_store_slice(${args[0]}, ${args[1]}, ${args[2]})`;
|
|
47
|
+
case "Pad4":
|
|
48
|
+
return `(Math.floor((${args[0]} + 3) / 4) * 4)`;
|
|
49
|
+
default:
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
|
|
72
54
|
typeComment(typeNode) {
|
|
73
55
|
if (!typeNode) return "unknown";
|
|
74
56
|
switch (typeNode.kind) {
|
|
@@ -86,50 +68,25 @@ const dispatchMethods = {
|
|
|
86
68
|
// Dispatch table for stdlib namespace calls (pkg.Func → inline JS).
|
|
87
69
|
// Returns the generated JS string, or undefined if not handled.
|
|
88
70
|
_genStdlibCall(ns, fn, expr) {
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
const method = STDLIB_METHOD_MAP[ns];
|
|
72
|
+
if (!method) return undefined;
|
|
73
|
+
// A member written in Go is an ordinary call of its mangled name.
|
|
74
|
+
if (expr.func?._stdName) return undefined;
|
|
75
|
+
// Stdlib shims take raw values, not the interface box of a named value.
|
|
91
76
|
const isNamespace = expr.func?.expr?._type?.kind === "namespace";
|
|
92
|
-
if (isNamespace
|
|
77
|
+
if (isNamespace) {
|
|
93
78
|
for (const e of expr.args) if (e) e._noNamedBox = true;
|
|
94
79
|
}
|
|
95
80
|
const a = () => expr.args.map((e) => this.genExpr(e));
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
81
|
+
const res = this[method](fn, a, expr);
|
|
82
|
+
if (res === undefined && isNamespace) {
|
|
83
|
+
for (const e of expr.args) if (e) delete e._noNamedBox;
|
|
84
|
+
}
|
|
85
|
+
return res;
|
|
99
86
|
},
|
|
100
87
|
};
|
|
101
88
|
|
|
102
89
|
/** @type {ThisType<CodeGen>} */
|
|
103
90
|
export const stdlibGenMethods = {
|
|
104
|
-
...bitsMethods,
|
|
105
|
-
...builderMethods,
|
|
106
|
-
...bytesMethods,
|
|
107
|
-
...errorsMethods,
|
|
108
|
-
...fmtMethods,
|
|
109
|
-
...gomMethods,
|
|
110
|
-
...htmlMethods,
|
|
111
|
-
...ioMethods,
|
|
112
|
-
...mapsMethods,
|
|
113
|
-
...mathMethods,
|
|
114
|
-
...osMethods,
|
|
115
|
-
...pathMethods,
|
|
116
|
-
...randMethods,
|
|
117
|
-
...regexpMethods,
|
|
118
|
-
...sharedMethods,
|
|
119
|
-
...simdMethods,
|
|
120
|
-
...slicesMethods,
|
|
121
|
-
...sortMethods,
|
|
122
|
-
...strconvMethods,
|
|
123
|
-
...stringsMethods,
|
|
124
|
-
...timeMethods,
|
|
125
|
-
...unicodeMethods,
|
|
126
|
-
...utf8Methods,
|
|
127
|
-
...testingMethods,
|
|
128
|
-
...syncMethods,
|
|
129
|
-
...sha256Methods,
|
|
130
|
-
...binaryMethods,
|
|
131
|
-
...hexMethods,
|
|
132
|
-
...base64Methods,
|
|
133
|
-
...jsonMethods,
|
|
134
91
|
...dispatchMethods,
|
|
135
92
|
};
|
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>} */
|
|
@@ -16,13 +13,22 @@ export const templGenMethods = {
|
|
|
16
13
|
)
|
|
17
14
|
.join(", ");
|
|
18
15
|
this.line(`function ${decl.name}(${params}) {`);
|
|
16
|
+
const prevBoxed = this._boxedVars;
|
|
17
|
+
this._boxedVars = new Set(this._boxedGlobals);
|
|
19
18
|
this.indented(() => {
|
|
19
|
+
// `@W(xs...)` passes `{ __sp: xs }` like any Go variadic call.
|
|
20
|
+
const last = decl.params[decl.params.length - 1];
|
|
21
|
+
if (last?.variadic && last.name && last.name !== "_") {
|
|
22
|
+
this.useHelper("va");
|
|
23
|
+
this.line(`${last.name} = __va(${last.name});`);
|
|
24
|
+
}
|
|
20
25
|
this.line(`return {Mount(___p, ___refs) {`);
|
|
21
26
|
this.indented(() => {
|
|
22
27
|
this._genTemplNodes(decl.body, "___p");
|
|
23
28
|
});
|
|
24
29
|
this.line(`}};`);
|
|
25
30
|
});
|
|
31
|
+
this._boxedVars = prevBoxed;
|
|
26
32
|
this.line("}");
|
|
27
33
|
},
|
|
28
34
|
|
|
@@ -79,15 +85,21 @@ export const templGenMethods = {
|
|
|
79
85
|
);
|
|
80
86
|
case "TemplExpr":
|
|
81
87
|
return this.line(
|
|
82
|
-
`${p}.appendChild(document.createTextNode(String(${this.
|
|
88
|
+
`${p}.appendChild(document.createTextNode(String(${this._genTemplExpr(node, '""')})));`,
|
|
83
89
|
);
|
|
84
90
|
case "TemplComponent":
|
|
85
91
|
return this._genTemplComponentMount(node, p);
|
|
86
|
-
case "TemplChildren":
|
|
87
|
-
//
|
|
92
|
+
case "TemplChildren": {
|
|
93
|
+
// `{ name... }`: mount each node of a variadic gom.Node parameter
|
|
94
|
+
// (nil mounts nothing). `children` may also be absent altogether.
|
|
95
|
+
const slot =
|
|
96
|
+
node.name === "children"
|
|
97
|
+
? `(typeof children!=="undefined"?children:null)`
|
|
98
|
+
: this._genTemplExpr(node, "null");
|
|
88
99
|
return this.line(
|
|
89
|
-
`
|
|
100
|
+
`for (const ___c of ${slot} ?? []) ___c?.Mount?.(${p});`,
|
|
90
101
|
);
|
|
102
|
+
}
|
|
91
103
|
case "TemplIf":
|
|
92
104
|
return this._genTemplIf(node, p);
|
|
93
105
|
case "TemplFor":
|
|
@@ -101,20 +113,12 @@ export const templGenMethods = {
|
|
|
101
113
|
|
|
102
114
|
_genTemplComponentMount(node, p) {
|
|
103
115
|
// 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);
|
|
116
|
+
if (node.raw) {
|
|
117
|
+
const argJs = this._genTemplExpr(node, '""');
|
|
114
118
|
return this.line(`${p}.insertAdjacentHTML("beforeend", ${argJs});`);
|
|
115
119
|
}
|
|
116
120
|
return this.line(
|
|
117
|
-
`(${this.
|
|
121
|
+
`(${this._genTemplExpr(node, "null")}).Mount(${p}, ___refs);`,
|
|
118
122
|
);
|
|
119
123
|
},
|
|
120
124
|
|
|
@@ -160,7 +164,7 @@ export const templGenMethods = {
|
|
|
160
164
|
);
|
|
161
165
|
}
|
|
162
166
|
} else if (attr.kind === "expr") {
|
|
163
|
-
const exprJs = this.
|
|
167
|
+
const exprJs = this._genTemplExpr(attr, '""');
|
|
164
168
|
if (name === "class") {
|
|
165
169
|
this.line(setClass(exprJs));
|
|
166
170
|
} else {
|
|
@@ -171,7 +175,7 @@ export const templGenMethods = {
|
|
|
171
175
|
} else if (attr.kind === "bool") {
|
|
172
176
|
this.line(`${el}.setAttribute(${JSON.stringify(name)}, "");`);
|
|
173
177
|
} else if (attr.kind === "cond-bool") {
|
|
174
|
-
const exprJs = this.
|
|
178
|
+
const exprJs = this._genTemplExpr(attr, '""');
|
|
175
179
|
this.line(
|
|
176
180
|
`if(${exprJs})${el}.setAttribute(${JSON.stringify(name)}, "");`,
|
|
177
181
|
);
|
|
@@ -179,7 +183,7 @@ export const templGenMethods = {
|
|
|
179
183
|
},
|
|
180
184
|
|
|
181
185
|
_genTemplIf(node, p) {
|
|
182
|
-
const condJs = this.
|
|
186
|
+
const condJs = this._genTemplExpr(node, "false");
|
|
183
187
|
this.line(`if (${condJs}) {`);
|
|
184
188
|
this.indented(() => this._genTemplNodes(node.then, p));
|
|
185
189
|
this._genTemplIfElse(node.else_, p);
|
|
@@ -192,7 +196,7 @@ export const templGenMethods = {
|
|
|
192
196
|
}
|
|
193
197
|
if (else_.length === 1 && else_[0].kind === "TemplIf") {
|
|
194
198
|
const elseIf = else_[0];
|
|
195
|
-
this.line(`} else if (${this.
|
|
199
|
+
this.line(`} else if (${this._genTemplExpr(elseIf, "false")}) {`);
|
|
196
200
|
this.indented(() => this._genTemplNodes(elseIf.then, p));
|
|
197
201
|
this._genTemplIfElse(elseIf.else_, p);
|
|
198
202
|
} else {
|
|
@@ -203,17 +207,20 @@ export const templGenMethods = {
|
|
|
203
207
|
},
|
|
204
208
|
|
|
205
209
|
_genTemplSwitch(node, p) {
|
|
206
|
-
const {
|
|
210
|
+
const { cases } = node;
|
|
207
211
|
if (cases.length === 0) return;
|
|
208
|
-
|
|
212
|
+
// `switch { case cond: }` compares each condition with `true`.
|
|
213
|
+
const exprJs = this._genTemplExpr(node, "true");
|
|
209
214
|
this.line(`switch (${exprJs}) {`);
|
|
210
215
|
this.indented(() => {
|
|
211
216
|
for (const c of cases) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
if (c.caseTokens === null) this.line("default: {");
|
|
218
|
+
else {
|
|
219
|
+
// One JS label per value of `case a, b:`.
|
|
220
|
+
if (c.exprError) throw c.exprError;
|
|
221
|
+
const labels = (c.exprs ?? []).map((e) => `case ${this.genExpr(e)}:`);
|
|
222
|
+
this.line(`${labels.join(" ") || 'case "":'} {`);
|
|
223
|
+
}
|
|
217
224
|
this.indented(() => this._genTemplNodes(c.body, p));
|
|
218
225
|
this.line(`break; }`);
|
|
219
226
|
}
|
|
@@ -221,106 +228,48 @@ export const templGenMethods = {
|
|
|
221
228
|
this.line(`}`);
|
|
222
229
|
},
|
|
223
230
|
|
|
231
|
+
// The header is a parsed Go `for` statement, so it goes through the regular
|
|
232
|
+
// loop generator; its body is a statement that mounts the templ nodes.
|
|
224
233
|
_genTemplFor(node, p) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
}
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
_genTemplRangeFor(forStmt, templBody, mountParent) {
|
|
257
|
-
const init = forStmt.init;
|
|
258
|
-
if (init?.rhs?.[0]?.kind !== "RangeExpr") {
|
|
259
|
-
// Plain for loop (cond-only or three-clause)
|
|
260
|
-
const condJs = forStmt.cond ? this.genExpr(forStmt.cond) : "true";
|
|
261
|
-
this.line(`while (${condJs}) {`);
|
|
262
|
-
this.indented(() => this._genTemplNodes(templBody, mountParent));
|
|
263
|
-
this.line("}");
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
// Range for: for key, val := range iter
|
|
267
|
-
const range = init.rhs[0];
|
|
268
|
-
const iterJs = this.genExpr(range.expr);
|
|
269
|
-
const lhs = init.lhs.map((e) => e.name ?? "_");
|
|
270
|
-
const keyName = lhs[0] ?? "_";
|
|
271
|
-
const valName = lhs[1] ?? null;
|
|
272
|
-
|
|
273
|
-
const loopHeader = this._genTemplRangeHeader(keyName, valName, iterJs);
|
|
274
|
-
this.line(loopHeader);
|
|
275
|
-
this.indented(() => this._genTemplNodes(templBody, mountParent));
|
|
276
|
-
this.line("}");
|
|
234
|
+
if (node.forError) throw node.forError;
|
|
235
|
+
if (!node.forStmt)
|
|
236
|
+
throw new Error("templ for header was not parsed by TemplParser");
|
|
237
|
+
const mount = { kind: "TemplMount", parent: p };
|
|
238
|
+
// Hidden from the generic AST walkers: they know no templ node kinds.
|
|
239
|
+
Object.defineProperty(mount, "nodes", { value: node.body });
|
|
240
|
+
this.genFor({
|
|
241
|
+
...node.forStmt,
|
|
242
|
+
body: { kind: "Block", stmts: [mount] },
|
|
243
|
+
});
|
|
277
244
|
},
|
|
278
245
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return `for (const ${keyName === "_" ? "_$" : keyName} of ${iterJs}) {`;
|
|
282
|
-
}
|
|
283
|
-
if (keyName === "_" && valName === "_")
|
|
284
|
-
return `for (const _$ of ${iterJs}) {`;
|
|
285
|
-
if (keyName === "_") return `for (const ${valName} of ${iterJs}) {`;
|
|
286
|
-
if (valName === "_")
|
|
287
|
-
return `for (const [${keyName}] of Object.entries(${iterJs})) {`;
|
|
288
|
-
// Default to .entries() for arrays, Object.entries for objects
|
|
289
|
-
this.useHelper("sliceGuard");
|
|
290
|
-
return `for (const [${keyName}, ${valName}] of __s(${iterJs}).entries()) {`;
|
|
246
|
+
_genTemplMountStmt(stmt) {
|
|
247
|
+
this._genTemplNodes(stmt.nodes, stmt.parent);
|
|
291
248
|
},
|
|
292
249
|
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
250
|
+
// Emit JS for the Go expression TemplParser parsed onto `node`. `emptyJs` is
|
|
251
|
+
// the value when the node holds no tokens. A parse error is raised here,
|
|
252
|
+
// not in the parser, so it surfaces at the same point as it always did.
|
|
253
|
+
_genTemplExpr(node, emptyJs) {
|
|
254
|
+
if (node.exprError) throw node.exprError;
|
|
255
|
+
if (node.expr === undefined)
|
|
256
|
+
throw new Error("templ expression was not parsed by TemplParser");
|
|
257
|
+
return node.expr ? this.genExpr(node.expr) : emptyJs;
|
|
300
258
|
},
|
|
301
259
|
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
const ast = p.parseExpr();
|
|
308
|
-
return this.genExpr(ast);
|
|
260
|
+
// Rename handlers for `_renameReservedIdents`: templ bodies keep their Go
|
|
261
|
+
// expressions in non-enumerable props (see parser/templ.js), which its
|
|
262
|
+
// generic walk does not visit, so `class` in `{ class }` would stay unsafe.
|
|
263
|
+
_renameTemplExprNode(node) {
|
|
264
|
+
this._renameReservedIdents(node.expr);
|
|
309
265
|
},
|
|
310
266
|
|
|
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);
|
|
267
|
+
_renameTemplForNode(node) {
|
|
268
|
+
this._renameReservedIdents(node.forStmt);
|
|
320
269
|
},
|
|
321
270
|
|
|
322
|
-
|
|
323
|
-
|
|
271
|
+
_renameTemplElementNode(node) {
|
|
272
|
+
for (const attr of node.attrs ?? []) this._renameReservedIdents(attr.expr);
|
|
324
273
|
},
|
|
325
274
|
|
|
326
275
|
// Fresh variable name counter
|