Skip to content

Commit e2aa3e5

Browse files
Merge pull request #326 from karthik2804/add_regex_precompilation
add precompilation for regex during the build step
2 parents a7953e7 + adfca00 commit e2aa3e5

File tree

4 files changed

+221
-5
lines changed

4 files changed

+221
-5
lines changed

bin/j2w.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { resolve, basename } from 'node:path';
77
import yargs from 'yargs';
88
import { hideBin } from 'yargs/helpers';
99
import path from 'path';
10+
import { precompile } from "./precompile.mjs";
1011

1112
const componentizeVersion = '0.16.0';
1213
const __filename = new URL(import.meta.url).pathname;
@@ -103,14 +104,15 @@ async function saveBuildData(buildDataPath, checksum, version) {
103104
}
104105

105106
const source = await readFile(src, 'utf8');
107+
const precompiledSource = precompile(source, src, true);
106108

107109
// Check if a non-default wit directory is supplied
108110
const witPath = args.witPath ? resolve(args.witPath) : path.join(__dirname, 'wit');
109111
if (args.witPath) {
110112
console.log(`Using user-provided wit in: ${witPath}`);
111113
}
112114

113-
const { component } = await componentize(source, {
115+
const { component } = await componentize(precompiledSource, {
114116
sourceName: basename(src),
115117
witPath,
116118
worldName: args.triggerType,

bin/precompile.mjs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2024 Fastly Inc.
2+
// License: the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
6+
import regexpuc from 'regexpu-core';
7+
import { parse } from 'acorn';
8+
import MagicString from 'magic-string';
9+
import { simple as simpleWalk } from 'acorn-walk';
10+
11+
const PREAMBLE = `;{
12+
// Precompiled regular expressions
13+
const precompile = (r) => { r.exec('a'); r.exec('\\u1000'); };`;
14+
const POSTAMBLE = '}';
15+
16+
/// Emit a block of javascript that will pre-compile the regular expressions given. As spidermonkey
17+
/// will intern regular expressions, duplicating them at the top level and testing them with both
18+
/// an ascii and utf8 string should ensure that they won't be re-compiled when run in the fetch
19+
/// handler.
20+
export function precompile(source, filename = '<input>', moduleMode = false) {
21+
const magicString = new MagicString(source, {
22+
filename,
23+
});
24+
25+
const ast = parse(source, {
26+
ecmaVersion: 'latest',
27+
sourceType: moduleMode ? 'module' : 'script',
28+
});
29+
30+
const precompileCalls = [];
31+
simpleWalk(ast, {
32+
Literal(node) {
33+
if (!node.regex) return;
34+
let transpiledPattern;
35+
try {
36+
transpiledPattern = regexpuc(node.regex.pattern, node.regex.flags, {
37+
unicodePropertyEscapes: 'transform',
38+
});
39+
} catch {
40+
// swallow regex parse errors here to instead throw them at the engine level
41+
// this then also avoids regex parser bugs being thrown unnecessarily
42+
transpiledPattern = node.regex.pattern;
43+
}
44+
const transpiledRegex = `/${transpiledPattern}/${node.regex.flags}`;
45+
precompileCalls.push(`precompile(${transpiledRegex});`);
46+
magicString.overwrite(node.start, node.end, transpiledRegex);
47+
},
48+
});
49+
50+
if (!precompileCalls.length) return source;
51+
52+
magicString.prepend(`${PREAMBLE}${precompileCalls.join('\n')}${POSTAMBLE}`);
53+
54+
// When we're ready to pipe in source maps:
55+
// const map = magicString.generateMap({
56+
// source: 'source.js',
57+
// file: 'converted.js.map',
58+
// includeContent: true
59+
// });
60+
61+
return magicString.toString();
62+
}

package-lock.json

Lines changed: 150 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fermyon/spin-sdk",
3-
"version": "3.0.0",
3+
"version": "3.1.0",
44
"description": "",
55
"main": "lib/index.js",
66
"typings": "lib/index.d.ts",
@@ -28,7 +28,11 @@
2828
"@bytecodealliance/componentize-js": "^0.16.0",
2929
"yargs": "^17.7.2",
3030
"typedoc-plugin-missing-exports": "^3.0.0",
31-
"@fermyon/knitwit": "^0.3.0"
31+
"@fermyon/knitwit": "^0.3.0",
32+
"acorn-walk": "^8.3.4",
33+
"acron": "^1.0.5",
34+
"magic-string": "^0.30.17",
35+
"regexpu-core": "^6.2.0"
3236
},
3337
"files": [
3438
"lib",

0 commit comments

Comments
 (0)