Skip to content

Commit 673773e

Browse files
zgliczvdiez
andauthored
JS-380 Bundle bridge using esbuild (#4901)
Co-authored-by: Victor Diez <[email protected]>
1 parent 7ff98bd commit 673773e

File tree

26 files changed

+1922
-2491
lines changed

26 files changed

+1922
-2491
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Maven
22
target/
3+
bin/
34

45
lib/
56
node_modules/

esbuild.mjs

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import esbuild from 'esbuild';
2+
import textReplace from 'esbuild-plugin-text-replace';
3+
import { copy } from 'esbuild-plugin-copy';
4+
5+
await esbuild.build({
6+
entryPoints: ['./server.mjs'],
7+
outfile: './bin/server.cjs',
8+
format: 'cjs',
9+
bundle: true,
10+
// we mark this file as external because it does not exist on EsLint any more and in any case
11+
// the code never reaches this dynamic require as this is a fallback if 'eslint/use-at-your-own-risk'
12+
// does not exist. we need to keep an eye on this in the future.
13+
external: ['eslint/lib/util/glob-util'],
14+
platform: 'node',
15+
minify: true,
16+
plugins: [
17+
textReplace({
18+
include: /server\.mjs$/,
19+
pattern: [['new URL(import.meta.url)', '__filename']],
20+
}),
21+
textReplace({
22+
include: /lib[\/\\]jsts[\/\\]src[\/\\]parsers[\/\\]ast\.js$/,
23+
pattern: [['path.dirname(fileURLToPath(import.meta.url))', '__dirname']],
24+
}),
25+
// Simplify the loader function in babel. At the end it's just importing Babel parser
26+
// This matches the result of the TS compilation of the following lines
27+
// https://github.com/babel/babel/blob/v7.25.1/eslint/babel-eslint-parser/src/parse.cts#L8-L12
28+
textReplace({
29+
include: /node_modules[\/\\]@babel[\/\\]eslint-parser[\/\\]lib[\/\\]parse\.cjs$/,
30+
pattern: [
31+
[/const babelParser = require.*}\)\)/gms, 'const babelParser = require("@babel/parser")'],
32+
],
33+
}),
34+
// Remove dynamic import of espree on ESLint Rule tester. In any case, it's never used in the bundle
35+
textReplace({
36+
include: /node_modules[\/\\]eslint[\/\\]lib[\/\\]rule-tester[\/\\]rule-tester\.js$/,
37+
pattern: [
38+
// https://github.com/eslint/eslint/blob/v8.57.0/lib/rule-tester/rule-tester.js#L56
39+
['const espreePath = require.resolve("espree");', ''],
40+
// https://github.com/eslint/eslint/blob/v8.57.0/lib/rule-tester/rule-tester.js#L781
41+
['config.parser = espreePath;', ''],
42+
],
43+
}),
44+
// Dynamic import in module used by eslint-import-plugin. It always resolves to node resolver
45+
textReplace({
46+
include: /node_modules[\/\\]eslint-module-utils[\/\\]resolve\.js$/,
47+
pattern: [
48+
[
49+
// https://github.com/import-js/eslint-plugin-import/blob/v2.11.0/utils/resolve.js#L157
50+
'tryRequire(`eslint-import-resolver-${name}`, sourceFile)',
51+
'require("eslint-import-resolver-node")',
52+
],
53+
],
54+
}),
55+
// the html extractor for stylelint calls a "loadSyntax" function in postcss-syntax/load-syntax.js
56+
// That function has a dynamic require which always resolves to same dependencies given
57+
// our stylelint options.
58+
textReplace({
59+
include: /node_modules[\/\\]postcss-html[\/\\]extract\.js$/,
60+
pattern: [
61+
[
62+
//https://github.com/ota-meshi/postcss-html/blob/v0.36.0/extract.js#L108
63+
'style.syntax = loadSyntax(opts, __dirname);',
64+
`style.syntax = {
65+
parse: require("postcss-html/template-parse"),
66+
stringify: require("postcss/lib/stringify")
67+
};
68+
opts.syntax.config["css"] = {
69+
stringify: require("postcss/lib/stringify"),
70+
parse: require("postcss/lib/parse")
71+
}`,
72+
// ^^ modifying "opts.syntax.config" is a side effect done in postcss-syntax/get-syntax.js
73+
],
74+
],
75+
}),
76+
// The comparison by constructor name made by stylelint is not valid in the bundle because
77+
// the Document object is named differently. We need to compare constructor object directly
78+
textReplace({
79+
include: /node_modules[\/\\]stylelint[\/\\]lib[\/\\]lintPostcssResult\.js$/,
80+
pattern: [
81+
[
82+
// https://github.com/stylelint/stylelint/blob/15.10.0/lib/lintPostcssResult.js#L52
83+
"postcssDoc && postcssDoc.constructor.name === 'Document' ? postcssDoc.nodes : [postcssDoc]",
84+
"postcssDoc && postcssDoc.constructor === require('postcss-syntax/document') ? postcssDoc.nodes : [postcssDoc]",
85+
],
86+
],
87+
}),
88+
copy({
89+
resolveFrom: 'cwd',
90+
assets: [
91+
// We need to copy all typescript declaration files for type-checking, as typescript will
92+
// look for those in the filesystem
93+
{
94+
from: ['./node_modules/typescript/lib/*.d.ts'],
95+
to: ['./bin/'],
96+
},
97+
// We copy run-node into the bundle, as it's used from the java side on Mac
98+
{
99+
from: ['./run-node'],
100+
to: ['./bin/'],
101+
},
102+
// We copy the protofile as it needs to be accessible for the bundle
103+
{
104+
from: ['./packages/jsts/src/parsers/estree.proto'],
105+
to: ['./bin/'],
106+
},
107+
],
108+
}),
109+
],
110+
});

its/plugin/plugins/eslint-custom-rules-plugin/bundle/dist/rules.js

-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ exports.rules = [
2020
],
2121
},
2222
create(context) {
23-
const ts = require('typescript');
24-
console.log(`TS API in custom rule: TS version ${ts.version}`); // should print embedded typescript version
25-
2623
console.log('Rule context options: ', context.options);
2724
return {
2825
CallExpression(node) {

its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/EslintCustomRulesTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ void test() {
127127
)
128128
)
129129
.isEmpty();
130-
assertThat(buildResult.getLogsLines(l -> l.contains("TS API in custom rule: TS version 5.6.2")))
130+
assertThat(buildResult.getLogsLines(l -> l.contains("Rule context options:")))
131131
.hasSize(2);
132132
List<Issue> issues = findIssues("eslint-custom-rules:sqKey", orchestrator);
133133
assertThat(issues).hasSize(2);

its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/SonarJsIntegrationTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void start(Path dest) throws IOException {
174174
port = findOpenPort();
175175
String[] cmd = {
176176
"node",
177-
dest.resolve("package/bin/server.mjs").toString(),
177+
dest.resolve("package/bin/server.cjs").toString(),
178178
String.valueOf(port),
179179
"127.0.0.1",
180180
temp.toString(),

its/ruling/src/test/java/org/sonar/javascript/it/JsTsRulingTest.java

+10-11
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import java.util.Set;
4242
import java.util.stream.Stream;
4343
import org.apache.commons.lang.StringUtils;
44-
import org.junit.jupiter.api.AfterAll;
4544
import org.junit.jupiter.api.BeforeAll;
4645
import org.junit.jupiter.api.extension.RegisterExtension;
4746
import org.junit.jupiter.api.parallel.Execution;
@@ -334,13 +333,13 @@ private static void instantiateTemplateRule(
334333
Arrays.asList(
335334
(
336335
"name=\"" +
337-
instantiationKey +
338-
"\";key=\"" +
339-
instantiationKey +
340-
"\";markdown_description=\"" +
341-
instantiationKey +
342-
"\";" +
343-
params
336+
instantiationKey +
337+
"\";key=\"" +
338+
instantiationKey +
339+
"\";markdown_description=\"" +
340+
instantiationKey +
341+
"\";" +
342+
params
344343
).split(";", 0)
345344
)
346345
)
@@ -372,8 +371,8 @@ private static void instantiateTemplateRule(
372371
} else {
373372
throw new IllegalStateException(
374373
"Could not retrieve profile key : Template rule " +
375-
ruleTemplateKey +
376-
" has not been activated"
374+
ruleTemplateKey +
375+
" has not been activated"
377376
);
378377
}
379378
}
@@ -389,4 +388,4 @@ static WsClient newAdminWsClient(Orchestrator orchestrator) {
389388
.build()
390389
);
391390
}
392-
}
391+
}

0 commit comments

Comments
 (0)