@sproutboat/toolchain 0.4.23 → 0.5.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/CHANGELOG.md +18 -0
- package/PORFFOR_ALPHA15.md +9 -0
- package/PORFFOR_SCORECARD.md +15 -11
- package/package.json +1 -1
- package/scorecards/alpha-15-72d048d.json +77 -0
- package/src/acquire.test.ts +19 -10
- package/src/acquire.ts +1 -1
- package/src/class-self-native.test.ts +43 -0
- package/src/patch.test.ts +0 -5
- package/src/patch.ts +138 -50
- package/src/pin.ts +4 -4
- package/vendor/porffor-72d048d.tar.gz +0 -0
- package/vendor/porffor-547c781.tar.gz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @sproutboat/toolchain
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 16f9b79: Pin and vendor Porffor alpha-15 (`72d048d`). Alpha-14 and alpha-15 bring stackless coroutines, iterator support, class hoisting and typed-array fixes. Three Sproutboat patches are dropped because upstream now covers them: the typed-array store and `~` conversions (#238) and the coroutine stack size (#178). The #241 write-bounds guard is re-anchored. uWebSockets stays on the same commit and the compatibility suite is unchanged at 30/32. See `PORFFOR_ALPHA15.md`.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- bf4ac00: Named class expressions work inside handlers again (baronunread/sproutboat#256). Inside a function, Porffor gave a class expression's own name, as seen from its methods, a new function object instead of the class, so `var R = class l { static lex() { return new l() } }` failed with "value is not a constructor". Every handler has run inside a function since #238, and bundlers emit this shape for any class whose static members refer to themselves, so marked and similar packages broke. A parse-time rewrite turns such a class into the equivalent `(() => { const l = class { ... }; return l; })()`, which Porffor handles correctly.
|
|
12
|
+
|
|
13
|
+
The ISO date parser no longer reads one byte past the end of the string. When that byte happened to be `+` or `-`, a timezone offset's sign flipped, so `-00:30` could parse as `+00:30` depending on what sat next in memory.
|
|
14
|
+
|
|
15
|
+
## 0.4.24
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 9225026: `join()` and `toString()` work on typed arrays (baronunread/sproutboat#242). Porffor generates typed-array methods from the Array ones by replacing `any[]` with the array's type, which also retyped `join`'s internal helper array. `new Uint8Array([1,2]).join("-")` returned garbage, and a three-element `Uint16Array.join` crashed. The generator now keeps that helper a plain array.
|
|
20
|
+
|
|
3
21
|
## 0.4.23
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Porffor alpha-15 upgrade audit
|
|
2
|
+
|
|
3
|
+
The source pin moves from alpha-13 (`547c781`) to the [alpha-15 release](https://github.com/CanadaHonk/porffor/releases/tag/alpha-15), commit `72d048d73d49e217631ac8a1bc4fa9070d22fbc9`, published October 2, 2026. The vendored codeload archive has SHA-256 `1e12be943b29691ad84bb25baecffa810655dcf7d9a490b8399352509da7a1d5`.
|
|
4
|
+
|
|
5
|
+
Alpha-14 and alpha-15 bring stackless coroutines (async functions compile to state machines), initial iterator support, hoisting of referenced classes, a fix for function-expression self-references, integer typed-array stores that wrap, `~` built on ToUint32, a `parseInt` length check, `Map#forEach` seeing added entries, and ANSI colour only on a TTY. `compiler/uwebsockets.js` still pins uWebSockets `360c276d609d59af56ae6932adb95154ace9f15f`.
|
|
6
|
+
|
|
7
|
+
Three patches are dropped because upstream now does the same thing: the typed-array store conversion and `~` from #238 (upstream emits the same `toUint32` code), and the coroutine stack size from #178 (there are no coroutine stacks any more). The #241 write-bounds guard is re-anchored on upstream's new store line. Two fixes ride along and also apply to alpha-13: the class self-name rewrite for #256 (alpha-15's self-reference fix covers function expressions, not class expressions), and the ISO date parser no longer reads past the end of its string, which flipped an offset's sign whenever the next byte in memory was `+` or `-`. That last bug surfaced on alpha-15 because its memory layout puts a `+` there in the date test.
|
|
8
|
+
|
|
9
|
+
The package suite passed 173 tests, plus the native crypto and UTF-8 suites. Linked to this toolchain, the CLI passed 101 of 102 tests (`SURFACE.md` only needs the new provenance stamp) and both kitchen-sink harnesses: 35 broker checks and 38 standalone checks. The platform's 32-handler comparison compiled all 32 and matched Bun on 30, unchanged; the two misses are still non-ISO date parsing in `15-date-iso.js` and `16-date-parts.js`. `bench/pin-compare.ts` against alpha-13 showed equal binary size, compile time and cold start. Its throughput reading swung between runs; ten alternating runs of each binary afterwards put both at about 25,000 requests a second.
|
package/PORFFOR_SCORECARD.md
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
# Porffor pin scorecard
|
|
2
2
|
|
|
3
|
-
Pin: alpha-
|
|
3
|
+
Pin: alpha-15 (72d048d73d49e217631ac8a1bc4fa9070d22fbc9). Compatibility report: 2026-10-05T00:30:02.525Z.
|
|
4
4
|
|
|
5
5
|
| Measure | Result |
|
|
6
6
|
| --- | ---: |
|
|
7
7
|
| Fixtures compiled | 32/32 |
|
|
8
8
|
| Behavior matches | 30/32 |
|
|
9
|
-
| Median / p95 compile, ms |
|
|
10
|
-
| Median / p95 binary, bytes |
|
|
11
|
-
| Patch markers |
|
|
12
|
-
| Upstream files written |
|
|
9
|
+
| Median / p95 compile, ms | 420 / 822 |
|
|
10
|
+
| Median / p95 binary, bytes | 1033344 / 1049904 |
|
|
11
|
+
| Patch markers | 38 |
|
|
12
|
+
| Upstream files written | 10 |
|
|
13
13
|
| Fresh patch application | pass |
|
|
14
14
|
|
|
15
|
-
Previous snapshot: alpha-
|
|
15
|
+
Previous snapshot: alpha-13-547c781.json. Matches 30/32 to 30/32; patch markers 28 to 38.
|
|
16
16
|
|
|
17
17
|
## Patch inventory
|
|
18
18
|
|
|
19
|
-
- `compiler/render.js`: PORT_MARKER, CONSOLE_MARKER, BYTESTRING_MARKER, READ_RAW_MARKER
|
|
20
|
-
- `compiler/index.js`: LINK_MARKER, CFLAGS_MARKER
|
|
21
|
-
- `compiler/builtins/typedarray.js`: TYPED_ARRAY_FROM_MARKER
|
|
19
|
+
- `compiler/render.js`: PORT_MARKER, CONSOLE_MARKER, BYTESTRING_MARKER, READ_RAW_MARKER
|
|
20
|
+
- `compiler/index.js`: LINK_MARKER, CFLAGS_MARKER, FP_CONTRACT_MARKER, HTTP10_IMPORT_MARKER, HTTP10_CALL_MARKER
|
|
21
|
+
- `compiler/builtins/typedarray.js`: TYPED_ARRAY_FROM_MARKER, TA_SET_OFFSET_MARKER, TA_JOIN_MARKER
|
|
22
22
|
- `compiler/builtins/date.ts`: DATE_PARSER_MARKER
|
|
23
|
-
- `compiler/
|
|
23
|
+
- `compiler/builtins/promise.ts`: PROMISE_NULL_MARKER
|
|
24
|
+
- `compiler/builtins/string.ts`: REPLACE_ALL_MARKER
|
|
25
|
+
- `compiler/codegen.js`: TA_GET_MARKER, TA_SET_BOUNDS_MARKER
|
|
26
|
+
- `compiler/parse.js`: CLASS_SELF_MARKER
|
|
27
|
+
- `compiler/uwebsockets.js`: HTTP10_SHIM_MARKER, BODY_MARKER, STATUS_SIG_MARKER, STATUS_303_MARKER, STATUS_DEFAULT_MARKER, HDR_SIG_MARKER, HDR_CALL_MARKER, HDR_CAP_MARKER, HDR_SKIP_MARKER, HDR_APPEND_MARKER, READ_RAW_DECL_MARKER, FORBIDDEN_HDR_MARKER, WRITE_RESPONSE_MARKER, R2_TRANSFER_MARKER, R2_TRANSFER_CALL_MARKER, R2_DOWNLOAD_CACHE_MARKER, R2_RANGE_CACHE_MARKER, R2_CONDITIONAL_CACHE_MARKER, R2_STREAMING_CACHE_MARKER, R2_RANGE_HEADER_CACHE_MARKER
|
|
24
28
|
- `compiler/builtins_precompiled.js`: regenerated builtin table
|
|
25
29
|
|
|
26
|
-
Patch source SHA-256: `
|
|
30
|
+
Patch source SHA-256: `849997ab545a760019941886780b3fc70c89b67581cc9acf2b51ca6ff8a37d17`.
|
|
27
31
|
|
|
28
32
|
## Known behavior gaps
|
|
29
33
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pin": "alpha-15 (72d048d73d49e217631ac8a1bc4fa9070d22fbc9)",
|
|
3
|
+
"reportGeneratedAt": "2026-10-05T00:30:02.525Z",
|
|
4
|
+
"fixtures": 32,
|
|
5
|
+
"compiled": 32,
|
|
6
|
+
"matched": 30,
|
|
7
|
+
"medianCompileMs": 420,
|
|
8
|
+
"p95CompileMs": 822,
|
|
9
|
+
"medianBinaryBytes": 1033344,
|
|
10
|
+
"p95BinaryBytes": 1049904,
|
|
11
|
+
"patchSourceSha256": "849997ab545a760019941886780b3fc70c89b67581cc9acf2b51ca6ff8a37d17",
|
|
12
|
+
"patchMarkerCount": 38,
|
|
13
|
+
"patchTargets": {
|
|
14
|
+
"compiler/render.js": [
|
|
15
|
+
"PORT_MARKER",
|
|
16
|
+
"CONSOLE_MARKER",
|
|
17
|
+
"BYTESTRING_MARKER",
|
|
18
|
+
"READ_RAW_MARKER"
|
|
19
|
+
],
|
|
20
|
+
"compiler/index.js": [
|
|
21
|
+
"LINK_MARKER",
|
|
22
|
+
"CFLAGS_MARKER",
|
|
23
|
+
"FP_CONTRACT_MARKER",
|
|
24
|
+
"HTTP10_IMPORT_MARKER",
|
|
25
|
+
"HTTP10_CALL_MARKER"
|
|
26
|
+
],
|
|
27
|
+
"compiler/builtins/typedarray.js": [
|
|
28
|
+
"TYPED_ARRAY_FROM_MARKER",
|
|
29
|
+
"TA_SET_OFFSET_MARKER",
|
|
30
|
+
"TA_JOIN_MARKER"
|
|
31
|
+
],
|
|
32
|
+
"compiler/builtins/date.ts": [
|
|
33
|
+
"DATE_PARSER_MARKER"
|
|
34
|
+
],
|
|
35
|
+
"compiler/builtins/promise.ts": [
|
|
36
|
+
"PROMISE_NULL_MARKER"
|
|
37
|
+
],
|
|
38
|
+
"compiler/builtins/string.ts": [
|
|
39
|
+
"REPLACE_ALL_MARKER"
|
|
40
|
+
],
|
|
41
|
+
"compiler/codegen.js": [
|
|
42
|
+
"TA_GET_MARKER",
|
|
43
|
+
"TA_SET_BOUNDS_MARKER"
|
|
44
|
+
],
|
|
45
|
+
"compiler/parse.js": [
|
|
46
|
+
"CLASS_SELF_MARKER"
|
|
47
|
+
],
|
|
48
|
+
"compiler/uwebsockets.js": [
|
|
49
|
+
"HTTP10_SHIM_MARKER",
|
|
50
|
+
"BODY_MARKER",
|
|
51
|
+
"STATUS_SIG_MARKER",
|
|
52
|
+
"STATUS_303_MARKER",
|
|
53
|
+
"STATUS_DEFAULT_MARKER",
|
|
54
|
+
"HDR_SIG_MARKER",
|
|
55
|
+
"HDR_CALL_MARKER",
|
|
56
|
+
"HDR_CAP_MARKER",
|
|
57
|
+
"HDR_SKIP_MARKER",
|
|
58
|
+
"HDR_APPEND_MARKER",
|
|
59
|
+
"READ_RAW_DECL_MARKER",
|
|
60
|
+
"FORBIDDEN_HDR_MARKER",
|
|
61
|
+
"WRITE_RESPONSE_MARKER",
|
|
62
|
+
"R2_TRANSFER_MARKER",
|
|
63
|
+
"R2_TRANSFER_CALL_MARKER",
|
|
64
|
+
"R2_DOWNLOAD_CACHE_MARKER",
|
|
65
|
+
"R2_RANGE_CACHE_MARKER",
|
|
66
|
+
"R2_CONDITIONAL_CACHE_MARKER",
|
|
67
|
+
"R2_STREAMING_CACHE_MARKER",
|
|
68
|
+
"R2_RANGE_HEADER_CACHE_MARKER"
|
|
69
|
+
],
|
|
70
|
+
"compiler/builtins_precompiled.js": []
|
|
71
|
+
},
|
|
72
|
+
"patchApplication": "pass",
|
|
73
|
+
"mismatches": [
|
|
74
|
+
"15-date-iso.js: request 3 mismatch: expected {\"status\":200,\"body\":\"2008-03-04T23:00:00.000Z\",\"content-type\":null}, got {\"status\":200,\"body\":\"0003-05-08T00:00:00.000Z\",\"content-type\":null}",
|
|
75
|
+
"16-date-parts.js: request 3 mismatch: expected {\"status\":200,\"body\":\"{\\\"year\\\":2008,\\\"month\\\":3,\\\"day\\\":4}\",\"content-type\":\"application/json;charset=utf-8\"}, got {\"status\":200,\"body\":\"{\\\"year\\\":3,\\\"month\\\":5,\\\"day\\\":8}\",\"content-type\":\"application/json;charset=utf-8\"}"
|
|
76
|
+
]
|
|
77
|
+
}
|
package/src/acquire.test.ts
CHANGED
|
@@ -27,8 +27,14 @@ async function fixture(): Promise<{ archive: string; sha256: string }> {
|
|
|
27
27
|
" return 0;\n" +
|
|
28
28
|
" }\n" +
|
|
29
29
|
" return -1;\n" +
|
|
30
|
-
"}\n"
|
|
31
|
-
|
|
30
|
+
"}\n",
|
|
31
|
+
"compiler/parse.js":
|
|
32
|
+
"import link from './modules.js';\n" +
|
|
33
|
+
"export default (input) => {\n" +
|
|
34
|
+
" const ast = parse(input);\n" +
|
|
35
|
+
" if (ast._ts) globalThis.typedInput = Prefs.optTypes;\n" +
|
|
36
|
+
" return ast;\n" +
|
|
37
|
+
"};\n",
|
|
32
38
|
"compiler/index.js":
|
|
33
39
|
"import { hashId } from './modules.js';\n" +
|
|
34
40
|
" const uwsDir = uwebsockets.ensureUWebSockets();\n" +
|
|
@@ -40,6 +46,7 @@ async function fixture(): Promise<{ archive: string; sha256: string }> {
|
|
|
40
46
|
"compiler/builtins_precompiled.js": "fixture:precompiled\n",
|
|
41
47
|
"compiler/builtins/date.ts": "export const __ecma262_ParseDTSF = (string: string) => {\n let n: number = 0;\n let nInd: number = 0;\n\n const len: i32 = string.length;\n const endPtr: i32 = Porffor.IR.ptr(string) + len;\n let ptr: i32 = Porffor.IR.ptr(string);\n\n while (ptr <= endPtr) { // <= to include extra null byte to set last n\n const chr: i32 = Porffor.IR.loadU8(ptr++, 4);\n if (Porffor.fastAnd(chr >= 48, chr <= 57)) { // 0-9\n n *= 10;\n n += chr - 48;\n continue;\n }\n\n if (chr == 45) { // -\n if (Porffor.fastOr(ptr == Porffor.IR.ptr(string), nInd == 7)) n = -n;\n }\n\n if (n > 0) {\n if (nInd == 0) y = n;\n else if (nInd == 1) m = n - 1;\n else if (nInd == 2) dt = n;\n else if (nInd == 3) h = n;\n else if (nInd == 4) min = n;\n else if (nInd == 5) s = n;\n else if (nInd == 6) milli = n;\n else if (nInd == 7) tzHour = n;\n else if (nInd == 8) tzMin = n;\n\n n = 0;\n nInd++;\n }\n }\n\n h += tzHour;\n min += tzMin;\n};\n// RFC 7231 or Date.prototype.toString() parser\n",
|
|
42
48
|
"compiler/builtins/typedarray.js":
|
|
49
|
+
"${typedArrayFuncs.reduce((acc, x) => acc + x.replace('// @porf-typed-array\\n', '').replaceAll('Array', name).replaceAll('any[]', name) + '\\n\\n', '')}`;\n" +
|
|
43
50
|
" offset = Math.trunc(offset);\n if (Porffor.fastOr(offset < 0, offset > len)) throw new RangeError('Offset out of bounds');\n" +
|
|
44
51
|
"export const __${name}_from = (arg: any, mapFn: any): ${name} => {\n" +
|
|
45
52
|
" const arr: any[] = Porffor.array.new(4);\n" +
|
|
@@ -122,8 +129,7 @@ async function fixture(): Promise<{ archive: string; sha256: string }> {
|
|
|
122
129
|
"compiler/builtins/json.ts": "// sb_json_utf16_v1\n",
|
|
123
130
|
"runtime/fetch-globals.js": "// sb_text_encoder_scalar_v1\n",
|
|
124
131
|
"compiler/codegen.js":
|
|
125
|
-
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f :
|
|
126
|
-
" return Box(Convert(T.f64, Un('~', T.i32, Convert(T.i32, numValue(toNumeric())))), Const(T.i32, TYPES.number));\n" +
|
|
132
|
+
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f : toUint32(scope, f)));\n" +
|
|
127
133
|
" const taGet = (ctype, size, signed = true) => () => {\n" +
|
|
128
134
|
" const loaded = Load(ctype, taAddr(size), 4);\n" +
|
|
129
135
|
" const f = ctype === 'f32' || ctype === 'f64' ? loaded : Convert(T.f64, loaded, signed ? CONVERT_SIGNED : 0);\n" +
|
|
@@ -217,20 +223,23 @@ test("the default call (no url/expectedSha256 override) never touches the networ
|
|
|
217
223
|
},
|
|
218
224
|
});
|
|
219
225
|
expect(await readFile(join(dir, "runtime/index.js"), "utf8")).not.toBe("");
|
|
226
|
+
// #242: generated typed-array join/toString keep a plain-array `parts`.
|
|
227
|
+
expect(await readFile(join(dir, "compiler/builtins/typedarray.js"), "utf8")).toContain(
|
|
228
|
+
".replaceAll('const parts: ' + name + ' =', 'const parts: any[] =')",
|
|
229
|
+
);
|
|
220
230
|
// #238: TypedArray.prototype.set(source) with no offset copies to index 0.
|
|
221
231
|
expect(await readFile(join(dir, "compiler/builtins/typedarray.js"), "utf8")).toContain(
|
|
222
232
|
"offset = ecma262.ToIntegerOrInfinity(offset);",
|
|
223
233
|
);
|
|
224
|
-
// #238:
|
|
234
|
+
// #238: out-of-range typed-array reads are undefined. (The store and `~`
|
|
235
|
+
// conversions #238 also patched are upstream's own code since alpha-14.)
|
|
225
236
|
const codegen = await readFile(join(dir, "compiler/codegen.js"), "utf8");
|
|
226
|
-
expect(codegen).toContain("Convert(T.i32, toUint32(scope, numValue(toNumeric())), CONVERT_RANGE_KNOWN | CONVERT_SIGNED)");
|
|
227
237
|
expect(codegen).toContain("Box(f, Const(T.i32, TYPES.number)), valUndefined());");
|
|
228
238
|
// #241: out-of-range typed-array writes are ignored in user code.
|
|
229
239
|
expect(codegen).toContain("if (globalThis.precompile) store();");
|
|
230
|
-
// #
|
|
231
|
-
expect(await readFile(join(dir, "compiler/
|
|
232
|
-
|
|
233
|
-
);
|
|
240
|
+
// #256: named class expressions inside functions are rewritten at parse time.
|
|
241
|
+
expect(await readFile(join(dir, "compiler/parse.js"), "utf8")).toContain("sbClassSelf(ast); // sproutboat #256");
|
|
242
|
+
expect(await readFile(join(dir, "compiler/sb-class-self.js"), "utf8")).toContain("sproutboat #256");
|
|
234
243
|
// #237: replaceAll joins its pieces once instead of a strcat per match.
|
|
235
244
|
expect(await readFile(join(dir, "compiler/builtins/string.ts"), "utf8")).toContain(
|
|
236
245
|
"return Porffor.callThis(__Array_prototype_join, pieces, '');",
|
package/src/acquire.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
// @ts-expect-error Bun's file loader supplies a path; see the pinned-commit
|
|
7
7
|
// check below for why this is safe to trust unconditionally.
|
|
8
|
-
import vendoredPorfforArchive from "../vendor/porffor-
|
|
8
|
+
import vendoredPorfforArchive from "../vendor/porffor-72d048d.tar.gz" with { type: "file" };
|
|
9
9
|
import { ensurePorfforPatched } from "./patch";
|
|
10
10
|
import { PORFFOR_ARCHIVE_SHA256, PORFFOR_ARCHIVE_URL, PORFFOR_COMMIT_FULL } from "./pin";
|
|
11
11
|
// Folded into the cache manifest below so a toolchain release that changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import { ensurePorffor } from "./acquire";
|
|
6
|
+
|
|
7
|
+
// baronunread/sproutboat#256: inside a function, a named class expression's own
|
|
8
|
+
// name must be the class itself. marked's minified Lexer has exactly this shape.
|
|
9
|
+
const program = `function inner() {
|
|
10
|
+
var R = class l { constructor(o) { this.o = o || E; } static make(o) { return new l(o); } lex(s) { return s.length; } static lex(s) { return new l().lex(s); } };
|
|
11
|
+
var E = { d: 1 };
|
|
12
|
+
var C = class k extends R { lex(s) { return super.lex(s) + 1; } static make() { return new k(); } };
|
|
13
|
+
var plain = class { static make() { return 7; } };
|
|
14
|
+
return [R === new R().constructor, R.make().o.d, R.lex("abc"), C.make().lex("ab"), C.name, plain.make()].join(" ");
|
|
15
|
+
}
|
|
16
|
+
async function viaAwait() {
|
|
17
|
+
var A = class m { static async load() { await null; return new m(); } ok() { return "ok"; } };
|
|
18
|
+
return (await A.load()).ok();
|
|
19
|
+
}
|
|
20
|
+
console.log(inner());
|
|
21
|
+
viaAwait().then((v) => console.log(v));
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
test("#256: a named class expression inside a function sees itself", async () => {
|
|
25
|
+
const root = await mkdtemp(resolve(tmpdir(), "sb-class-self-"));
|
|
26
|
+
try {
|
|
27
|
+
const porffor = await ensurePorffor();
|
|
28
|
+
const source = resolve(root, "classes.js");
|
|
29
|
+
const binary = resolve(root, "classes");
|
|
30
|
+
await writeFile(source, program);
|
|
31
|
+
const compile = Bun.spawnSync(["bun", resolve(porffor, "runtime/index.js"), "native", source, "-o", binary, "-s"], {
|
|
32
|
+
cwd: root,
|
|
33
|
+
stdout: "pipe",
|
|
34
|
+
stderr: "pipe",
|
|
35
|
+
});
|
|
36
|
+
expect(compile.exitCode, Buffer.from(compile.stderr).toString()).toBe(0);
|
|
37
|
+
const run = Bun.spawnSync([binary], { stdout: "pipe", stderr: "pipe" });
|
|
38
|
+
const lines = Buffer.from(run.stdout).toString().replace(/\u001b\[[0-9;]*m/g, "").trim().split("\n");
|
|
39
|
+
expect(lines).toEqual(["true 1 3 3 k 7", "ok"]);
|
|
40
|
+
} finally {
|
|
41
|
+
await rm(root, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
}, 60_000);
|
package/src/patch.test.ts
CHANGED
|
@@ -36,7 +36,6 @@ int porf_native_fetch_read_value(jsval value, const char** out_buf, size_t* out_
|
|
|
36
36
|
return -1;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
#define PORF_CORO_STACK_SIZE (256u * 1024u)
|
|
40
39
|
#define PORF_CORO_MAX 16384
|
|
41
40
|
`;
|
|
42
41
|
|
|
@@ -294,10 +293,6 @@ test("#165: render.js routes console output to stderr, unbuffered, idempotently"
|
|
|
294
293
|
"int porf_native_fetch_read_value(jsval value, const char** out_buf, size_t* out_len, char** out_owned) {",
|
|
295
294
|
);
|
|
296
295
|
|
|
297
|
-
// #178: fiber stacks big enough for -O0 frames in a few nested awaits.
|
|
298
|
-
expect(once).toContain("#define PORF_CORO_STACK_SIZE (8u * 1024u * 1024u)");
|
|
299
|
-
expect(once).not.toContain("(256u * 1024u)");
|
|
300
|
-
|
|
301
296
|
await patchRenderJs(root);
|
|
302
297
|
expect(await readFile(join(root, "compiler/render.js"), "utf8")).toBe(once);
|
|
303
298
|
} finally {
|
package/src/patch.ts
CHANGED
|
@@ -131,24 +131,6 @@ const READ_RAW_INJECT =
|
|
|
131
131
|
READ_RAW_ANCHOR;
|
|
132
132
|
const READ_RAW_MARKER = "porf_native_fetch_read_raw_bytes(jsval value";
|
|
133
133
|
|
|
134
|
-
/**
|
|
135
|
-
* baronunread/sproutboat#178: every async function runs on its own fiber
|
|
136
|
-
* stack, and Porffor (alpha-10 through alpha-13) fixes those at 256 KiB. A
|
|
137
|
-
* large handler compiled at -O0 (what `sproutboat dev` builds) spends ~40 KiB
|
|
138
|
-
* of stack per call into the biggest generated functions, so a few nested
|
|
139
|
-
* awaits run off the end into the guard page and the sprout dies with SIGBUS
|
|
140
|
-
* on its first request, no log.
|
|
141
|
-
* -O3 frames are smaller, which only raises the threshold: a deep enough
|
|
142
|
-
* async chain hits it in a release build too.
|
|
143
|
-
*
|
|
144
|
-
* Match a thread's usual 8 MiB. The reservation is MAP_NORESERVE with a guard
|
|
145
|
-
* page, so only touched pages cost memory and a shallow handler pays nothing.
|
|
146
|
-
*/
|
|
147
|
-
const CORO_STACK_ANCHOR = "#define PORF_CORO_STACK_SIZE (256u * 1024u)";
|
|
148
|
-
const CORO_STACK_INJECT =
|
|
149
|
-
"// sproutboat #178: 256 KiB overflows -O0 frames in a few nested awaits.\n" +
|
|
150
|
-
"#define PORF_CORO_STACK_SIZE (8u * 1024u * 1024u)";
|
|
151
|
-
const CORO_STACK_MARKER = "sproutboat #178";
|
|
152
134
|
|
|
153
135
|
/**
|
|
154
136
|
* render.js full-block replacements: `[marker, anchor, inject, what]`, each a
|
|
@@ -158,7 +140,6 @@ const CORO_STACK_MARKER = "sproutboat #178";
|
|
|
158
140
|
const RENDER_REPLACEMENTS = [
|
|
159
141
|
[BYTESTRING_MARKER, BYTESTRING_ANCHOR, BYTESTRING_INJECT, "bytestring UTF-8 encoding (#172)"],
|
|
160
142
|
[READ_RAW_MARKER, READ_RAW_ANCHOR, READ_RAW_INJECT, "raw bytestring passthrough function (#176)"],
|
|
161
|
-
[CORO_STACK_MARKER, CORO_STACK_ANCHOR, CORO_STACK_INJECT, "coroutine stack size (#178)"],
|
|
162
143
|
] as const;
|
|
163
144
|
|
|
164
145
|
// #15 — no `--port` flag: Porffor's native-fetch entry point calls
|
|
@@ -180,6 +161,95 @@ const LINK_INJECT =
|
|
|
180
161
|
" ...(process.env.SB_EXTRA_LINK ? process.env.SB_EXTRA_LINK.split(' ').filter(Boolean) : []),\n";
|
|
181
162
|
const LINK_MARKER = "SB_EXTRA_LINK";
|
|
182
163
|
|
|
164
|
+
/**
|
|
165
|
+
* baronunread/sproutboat#256: inside a function, Porffor gives a named class
|
|
166
|
+
* expression's own name, as seen from its methods, a fresh function object
|
|
167
|
+
* instead of the class. So `var R = class l { static lex() { return new l() } }`
|
|
168
|
+
* builds an object with none of the class's methods ("value is not a
|
|
169
|
+
* constructor"). Top level is fine. Since #238 every handler runs inside a
|
|
170
|
+
* function, and bundlers emit exactly this shape for classes whose static
|
|
171
|
+
* members refer to themselves (marked's Lexer and Parser, esbuild's
|
|
172
|
+
* `class _X`).
|
|
173
|
+
*
|
|
174
|
+
* The rewrite keeps the meaning: the name becomes an ordinary const, which
|
|
175
|
+
* Porffor captures correctly, and `const l = class {}` still names it "l".
|
|
176
|
+
*
|
|
177
|
+
* class l { ... } -> (() => { const l = class { ... }; return l; })()
|
|
178
|
+
*
|
|
179
|
+
* Only named class expressions inside a function whose body refers to the name.
|
|
180
|
+
* Skipped when `extends` or a computed key holds await/yield, which an arrow
|
|
181
|
+
* would change.
|
|
182
|
+
*/
|
|
183
|
+
const CLASS_SELF_HELPER = String.raw`// sproutboat #256: a named class expression's own name inside a function.
|
|
184
|
+
const isFn = (n) => n.type === 'FunctionDeclaration' || n.type === 'FunctionExpression' || n.type === 'ArrowFunctionExpression';
|
|
185
|
+
|
|
186
|
+
const mentions = (node, name) => {
|
|
187
|
+
if (node == null || typeof node !== 'object') return false;
|
|
188
|
+
if (Array.isArray(node)) return node.some((x) => mentions(x, name));
|
|
189
|
+
if (node.type === 'Identifier') return node.name === name;
|
|
190
|
+
for (const key in node) {
|
|
191
|
+
if (key[0] === '_' || key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue;
|
|
192
|
+
if (mentions(node[key], name)) return true;
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const suspends = (node) => {
|
|
198
|
+
if (node == null || typeof node !== 'object') return false;
|
|
199
|
+
if (Array.isArray(node)) return node.some(suspends);
|
|
200
|
+
if (node.type === 'AwaitExpression' || node.type === 'YieldExpression') return true;
|
|
201
|
+
if (isFn(node) || node.type === 'ClassExpression' || node.type === 'ClassDeclaration') return false;
|
|
202
|
+
for (const key in node) {
|
|
203
|
+
if (key[0] === '_' || key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue;
|
|
204
|
+
if (suspends(node[key])) return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const rewrite = (cls) => {
|
|
210
|
+
const name = cls.id.name;
|
|
211
|
+
const at = { start: cls.start, end: cls.end };
|
|
212
|
+
const id = () => ({ type: 'Identifier', name, ...at });
|
|
213
|
+
return {
|
|
214
|
+
type: 'CallExpression', optional: false, arguments: [], ...at,
|
|
215
|
+
callee: {
|
|
216
|
+
type: 'ArrowFunctionExpression', id: null, params: [], async: false, generator: false, expression: false, ...at,
|
|
217
|
+
body: {
|
|
218
|
+
type: 'BlockStatement', ...at,
|
|
219
|
+
body: [
|
|
220
|
+
{ type: 'VariableDeclaration', kind: 'const', ...at, declarations: [
|
|
221
|
+
{ type: 'VariableDeclarator', id: id(), init: { ...cls, id: null }, ...at },
|
|
222
|
+
] },
|
|
223
|
+
{ type: 'ReturnStatement', argument: id(), ...at },
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const walk = (node, inFn) => {
|
|
231
|
+
if (node == null || typeof node !== 'object') return node;
|
|
232
|
+
if (Array.isArray(node)) {
|
|
233
|
+
for (let i = 0; i < node.length; i++) node[i] = walk(node[i], inFn);
|
|
234
|
+
return node;
|
|
235
|
+
}
|
|
236
|
+
const childInFn = inFn || isFn(node);
|
|
237
|
+
for (const key in node) {
|
|
238
|
+
if (key[0] === '_' || key === 'start' || key === 'end' || key === 'loc' || key === 'range') continue;
|
|
239
|
+
const value = node[key];
|
|
240
|
+
if (value && typeof value === 'object') node[key] = walk(value, childInFn);
|
|
241
|
+
}
|
|
242
|
+
if (
|
|
243
|
+
inFn && node.type === 'ClassExpression' && node.id?.name &&
|
|
244
|
+
mentions(node.body, node.id.name) &&
|
|
245
|
+
!suspends(node.superClass) && !node.body.body.some((m) => m.computed && suspends(m.key))
|
|
246
|
+
) return rewrite(node);
|
|
247
|
+
return node;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export default (ast) => (globalThis.precompile ? ast : walk(ast, false));
|
|
251
|
+
`;
|
|
252
|
+
|
|
183
253
|
/**
|
|
184
254
|
* #15 — and the same for the compile step, so the prelude's inline C can
|
|
185
255
|
* `#include <bearssl.h>`. The link patch alone is not enough: Porffor's
|
|
@@ -291,30 +361,6 @@ const REPLACE_ALL_EDITS = [
|
|
|
291
361
|
] as const;
|
|
292
362
|
const REPLACE_ALL_MARKER = "sproutboat #237: pieces joined once";
|
|
293
363
|
|
|
294
|
-
// baronunread/sproutboat#238: an integer typed-array element store converted
|
|
295
|
-
// its value with a saturating f64 -> int Convert, so a negative value stored
|
|
296
|
-
// into a Uint32Array became 0 and 4e9 into an Int32Array became 2147483647.
|
|
297
|
-
// ECMA-262 (IntegerIndexedElementSet -> ToUint32 / ToInt32 / ToUint16 ...) wraps
|
|
298
|
-
// modulo 2^n instead. noble-hashes' SHA-256 stores `x | 0` into a Uint32Array,
|
|
299
|
-
// so every negative schedule word was zeroed and the digest came out wrong.
|
|
300
|
-
// Route the store through codegen's own modular toUint32 (what bitwise ops use);
|
|
301
|
-
// narrower stores keep the low bits, which is exactly the modular result.
|
|
302
|
-
const TA_STORE_ANCHOR =
|
|
303
|
-
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f : signed ? Convert(T.i32, f) : Convert(T.u32, f, 0)));";
|
|
304
|
-
const TA_STORE_INJECT =
|
|
305
|
-
" // sproutboat #238: typed-array stores wrap modulo 2^n (ToUint32), not saturate.\n" +
|
|
306
|
-
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f : signed ? Convert(T.i32, toUint32(scope, f), CONVERT_RANGE_KNOWN | CONVERT_SIGNED) : toUint32(scope, f)));";
|
|
307
|
-
const TA_STORE_MARKER = "sproutboat #238: typed-array stores wrap";
|
|
308
|
-
// baronunread/sproutboat#238: unary `~` had the same saturating conversion, so
|
|
309
|
-
// ~x for x >= 2^31 (or ~~x, the common truncation idiom) clamped to
|
|
310
|
-
// +/-2147483648, and ~Infinity gave -2147483648 instead of -1. uuid's SHA-1
|
|
311
|
-
// computes `x & y ^ ~x & z` on words above 2^31, so every v5 UUID was wrong.
|
|
312
|
-
const BITNOT_ANCHOR =
|
|
313
|
-
" return Box(Convert(T.f64, Un('~', T.i32, Convert(T.i32, numValue(toNumeric())))), Const(T.i32, TYPES.number));";
|
|
314
|
-
const BITNOT_INJECT =
|
|
315
|
-
" // sproutboat #238: ~ applies ToInt32 (wrap modulo 2^32), not a saturating cast.\n" +
|
|
316
|
-
" return Box(Convert(T.f64, Un('~', T.i32, Convert(T.i32, toUint32(scope, numValue(toNumeric())), CONVERT_RANGE_KNOWN | CONVERT_SIGNED))), Const(T.i32, TYPES.number));";
|
|
317
|
-
const BITNOT_MARKER = "sproutboat #238: ~ applies ToInt32";
|
|
318
364
|
// baronunread/sproutboat#238: typed-array element reads and writes had no
|
|
319
365
|
// bounds check. A read past the end returned whatever sat in the next
|
|
320
366
|
// allocation instead of undefined (uuid's SHA-1 reads past its buffer, so v5
|
|
@@ -350,12 +396,13 @@ const TA_GET_MARKER = "sproutboat #238: only a valid in-range integer index read
|
|
|
350
396
|
// whatever memory followed it (and a[-1] = x wrote a[0], via the saturating
|
|
351
397
|
// index conversion). ECMA-262 ignores the write. Same check as taGet, in user
|
|
352
398
|
// code only: builtins such as the constructor store elements before they set
|
|
353
|
-
// the length, and they only write in bounds anyway.
|
|
354
|
-
//
|
|
399
|
+
// the length, and they only write in bounds anyway. Alpha-14 fixed the store's
|
|
400
|
+
// conversion upstream (ToUint32, which our #238 patch used to add); the bounds
|
|
401
|
+
// check is still missing there.
|
|
355
402
|
const TA_SET_BOUNDS_ANCHOR =
|
|
356
|
-
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f :
|
|
403
|
+
" stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f : toUint32(scope, f)));";
|
|
357
404
|
const TA_SET_BOUNDS_INJECT =
|
|
358
|
-
" const store = () => stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f :
|
|
405
|
+
" const store = () => stmt(scope, Store(ctype, addr, 4, ctype === 'f64' || ctype === 'f32' ? f : toUint32(scope, f)));\n" +
|
|
359
406
|
" // sproutboat #241: a write outside the array is ignored, not stored into the next allocation.\n" +
|
|
360
407
|
" if (globalThis.precompile) store();\n" +
|
|
361
408
|
" else {\n" +
|
|
@@ -375,6 +422,17 @@ const TA_SET_OFFSET_INJECT =
|
|
|
375
422
|
" offset = ecma262.ToIntegerOrInfinity(offset); // sproutboat #238: undefined offset is 0, not NaN\n if (Porffor.fastOr(offset < 0, offset > len)) throw new RangeError('Offset out of bounds');";
|
|
376
423
|
const TA_SET_OFFSET_MARKER = "sproutboat #238: undefined offset is 0";
|
|
377
424
|
|
|
425
|
+
// baronunread/sproutboat#242: typedarray.js generates each TypedArray method
|
|
426
|
+
// from array.ts with `.replaceAll('any[]', name)`. That also retyped join's and
|
|
427
|
+
// toString's internal `const parts: any[]` helper as e.g. a Uint8Array, so the
|
|
428
|
+
// joined strings were stored into a "typed array": Uint8Array join returned
|
|
429
|
+
// garbage and Uint16Array join crashed. Put `parts` back to a plain array after
|
|
430
|
+
// the replacement; map/filter's intentionally typed `out` is untouched.
|
|
431
|
+
const TA_JOIN_ANCHOR = ".replaceAll('Array', name).replaceAll('any[]', name) + '\\n\\n'";
|
|
432
|
+
const TA_JOIN_INJECT =
|
|
433
|
+
".replaceAll('Array', name).replaceAll('any[]', name).replaceAll('const parts: ' + name + ' =', 'const parts: any[] =') /* sproutboat #242 */ + '\\n\\n'";
|
|
434
|
+
const TA_JOIN_MARKER = "sproutboat #242";
|
|
435
|
+
|
|
378
436
|
// Porffor's TypedArray.from only handles iterables. An array-like input such
|
|
379
437
|
// as { length: 16 } silently becomes an empty typed array, including HMAC
|
|
380
438
|
// keys made with Uint8Array.from({ length: 16 }, mapFn). The compiler uses a
|
|
@@ -448,8 +506,12 @@ const DATE_PARSER_INJECT = ` // sproutboat: ISO timezone offset
|
|
|
448
506
|
const endPtr: i32 = Porffor.IR.ptr(string) + len;
|
|
449
507
|
let ptr: i32 = Porffor.IR.ptr(string);
|
|
450
508
|
|
|
509
|
+
// Loop once past the last character to flush the final number, but read a
|
|
510
|
+
// 0 there, not the byte after the string: if that byte happened to be '+' or
|
|
511
|
+
// '-' it flipped the offset's sign.
|
|
451
512
|
while (ptr <= endPtr) {
|
|
452
|
-
const chr: i32 = Porffor.IR.loadU8(ptr
|
|
513
|
+
const chr: i32 = ptr < endPtr ? Porffor.IR.loadU8(ptr, 4) : 0;
|
|
514
|
+
ptr++;
|
|
453
515
|
if (Porffor.fastAnd(chr >= 48, chr <= 57)) {
|
|
454
516
|
n = n * 10 + chr - 48;
|
|
455
517
|
digits++;
|
|
@@ -1121,6 +1183,28 @@ export async function patchUwebsockets(root: string): Promise<void> {
|
|
|
1121
1183
|
if (changed) await writeFile(file, src);
|
|
1122
1184
|
}
|
|
1123
1185
|
|
|
1186
|
+
const CLASS_SELF_IMPORT_ANCHOR = "import link from './modules.js';";
|
|
1187
|
+
const CLASS_SELF_IMPORT_INJECT = "import link from './modules.js';\nimport sbClassSelf from './sb-class-self.js';";
|
|
1188
|
+
const CLASS_SELF_CALL_ANCHOR = " if (ast._ts) globalThis.typedInput = Prefs.optTypes;";
|
|
1189
|
+
const CLASS_SELF_CALL_INJECT = " sbClassSelf(ast); // sproutboat #256\n if (ast._ts) globalThis.typedInput = Prefs.optTypes;";
|
|
1190
|
+
const CLASS_SELF_MARKER = "sproutboat #256";
|
|
1191
|
+
|
|
1192
|
+
/** #256 — see CLASS_SELF_HELPER. */
|
|
1193
|
+
export async function patchClassSelfName(root: string): Promise<void> {
|
|
1194
|
+
await writeFile(resolve(root, "compiler/sb-class-self.js"), CLASS_SELF_HELPER);
|
|
1195
|
+
const file = resolve(root, "compiler/parse.js");
|
|
1196
|
+
let src = await readFile(file, "utf8");
|
|
1197
|
+
if (src.includes(CLASS_SELF_MARKER)) return;
|
|
1198
|
+
for (const [anchor, what] of [
|
|
1199
|
+
[CLASS_SELF_IMPORT_ANCHOR, "import"],
|
|
1200
|
+
[CLASS_SELF_CALL_ANCHOR, "call"],
|
|
1201
|
+
] as const) {
|
|
1202
|
+
if (!src.includes(anchor)) throw new Error(`could not patch Porffor's class self-name rewrite (${what}): anchor not found in ${file}`);
|
|
1203
|
+
}
|
|
1204
|
+
src = src.replace(CLASS_SELF_IMPORT_ANCHOR, CLASS_SELF_IMPORT_INJECT).replace(CLASS_SELF_CALL_ANCHOR, CLASS_SELF_CALL_INJECT);
|
|
1205
|
+
await writeFile(file, src);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1124
1208
|
async function patchCompilerArgs(root: string): Promise<void> {
|
|
1125
1209
|
await writeFile(resolve(root, "compiler/sb-http10.js"), HTTP10_HELPER);
|
|
1126
1210
|
const file = resolve(root, "compiler/index.js");
|
|
@@ -1198,8 +1282,6 @@ export async function patchTypedArrayStore(root: string): Promise<void> {
|
|
|
1198
1282
|
let src = await readFile(file, "utf8");
|
|
1199
1283
|
let changed = false;
|
|
1200
1284
|
for (const [marker, anchor, inject, what] of [
|
|
1201
|
-
[TA_STORE_MARKER, TA_STORE_ANCHOR, TA_STORE_INJECT, "typed-array store conversion"],
|
|
1202
|
-
[BITNOT_MARKER, BITNOT_ANCHOR, BITNOT_INJECT, "bitwise NOT conversion"],
|
|
1203
1285
|
[TA_GET_MARKER, TA_GET_ANCHOR, TA_GET_INJECT, "typed-array read bounds"],
|
|
1204
1286
|
[TA_SET_BOUNDS_MARKER, TA_SET_BOUNDS_ANCHOR, TA_SET_BOUNDS_INJECT, "typed-array write bounds"],
|
|
1205
1287
|
] as const) {
|
|
@@ -1219,6 +1301,11 @@ export async function patchTypedArrayFrom(root: string): Promise<void> {
|
|
|
1219
1301
|
}
|
|
1220
1302
|
let edited = src;
|
|
1221
1303
|
if (!edited.includes(TYPED_ARRAY_FROM_MARKER)) edited = edited.replace(TYPED_ARRAY_FROM_ANCHOR, TYPED_ARRAY_FROM_INJECT);
|
|
1304
|
+
if (!edited.includes(TA_JOIN_MARKER)) {
|
|
1305
|
+
if (!edited.includes(TA_JOIN_ANCHOR))
|
|
1306
|
+
throw new Error(`could not patch Porffor's typed-array method generator: anchor not found in ${file}`);
|
|
1307
|
+
edited = edited.replace(TA_JOIN_ANCHOR, TA_JOIN_INJECT);
|
|
1308
|
+
}
|
|
1222
1309
|
if (!edited.includes(TA_SET_OFFSET_MARKER)) {
|
|
1223
1310
|
if (!edited.includes(TA_SET_OFFSET_ANCHOR))
|
|
1224
1311
|
throw new Error(`could not patch Porffor's TypedArray.prototype.set offset: anchor not found in ${file}`);
|
|
@@ -1289,6 +1376,7 @@ export async function patchRenderJs(root: string): Promise<void> {
|
|
|
1289
1376
|
export async function ensurePorfforPatched(root: string): Promise<void> {
|
|
1290
1377
|
if (done.has(root)) return;
|
|
1291
1378
|
await patchCompilerArgs(root);
|
|
1379
|
+
await patchClassSelfName(root);
|
|
1292
1380
|
await patchUwebsockets(root);
|
|
1293
1381
|
await patchRenderJs(root);
|
|
1294
1382
|
await patchDateParser(root);
|
package/src/pin.ts
CHANGED
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* uWebSockets archive in `sproutboat-cli/vendor/` — then run both repos'
|
|
12
12
|
* test + conformance suites. See sproutboat-cli/MIGRATION.md.
|
|
13
13
|
*/
|
|
14
|
-
export const PORFFOR_CHANNEL = "alpha-
|
|
15
|
-
export const PORFFOR_COMMIT_FULL = "
|
|
14
|
+
export const PORFFOR_CHANNEL = "alpha-15";
|
|
15
|
+
export const PORFFOR_COMMIT_FULL = "72d048d73d49e217631ac8a1bc4fa9070d22fbc9";
|
|
16
16
|
export const PORFFOR_COMMIT = PORFFOR_COMMIT_FULL.slice(0, 7);
|
|
17
17
|
export const PORFFOR_ARCHIVE_SHA256 =
|
|
18
|
-
"
|
|
18
|
+
"1e12be943b29691ad84bb25baecffa810655dcf7d9a490b8399352509da7a1d5";
|
|
19
19
|
export const PORFFOR_ARCHIVE_URL = `https://codeload.github.com/CanadaHonk/porffor/tar.gz/${PORFFOR_COMMIT_FULL}`;
|
|
20
20
|
|
|
21
|
-
/** A compact identity string for a manifest / report (`alpha-
|
|
21
|
+
/** A compact identity string for a manifest / report (`alpha-15 (72d048d)`). */
|
|
22
22
|
export function porfforVersion(): string {
|
|
23
23
|
return process.env.PORFFOR_VERSION || `${PORFFOR_CHANNEL} (${PORFFOR_COMMIT})`;
|
|
24
24
|
}
|
|
Binary file
|
|
Binary file
|