Skip to content

Commit c0d357c

Browse files
committed
refactor(napi/oxlint): introduce Context class (#12440)
Part of #12437. Use a class `Context` for context objects passed to lint rules' `create` function. Creating a class instance is cheaper than creating a new `report` closure for each file. We have to use a private property `#ruleId`, but it's only accessed when an error is reported (cold path). Also, reuse a single `diagnostics` array, rather than creating a new array for each file that's linted.
1 parent 99e105f commit c0d357c

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

napi/oxlint2/src/index.js

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class PluginRegistry {
4949
// Buffers cache
5050
const buffers = [];
5151

52+
// Diagnostics array. Reused for every file.
53+
const diagnostics = [];
54+
5255
class Linter {
5356
pluginRegistry = new PluginRegistry();
5457

@@ -107,22 +110,9 @@ class Linter {
107110
}
108111

109112
// Get visitors for this file from all rules
110-
const diagnostics = [];
111-
112-
const createContext = (ruleId) => ({
113-
physicalFilename: filePath,
114-
report: (diagnostic) => {
115-
diagnostics.push({
116-
message: diagnostic.message,
117-
loc: { start: diagnostic.node.start, end: diagnostic.node.end },
118-
externalRuleId: ruleId,
119-
});
120-
},
121-
});
122-
123113
const visitors = [];
124114
for (const { rule, ruleId } of this.pluginRegistry.getRules(ruleIds)) {
125-
visitors.push(rule.create(createContext(ruleId)));
115+
visitors.push(rule.create(new Context(ruleId, filePath)));
126116
}
127117

128118
const visitor = new Visitor(
@@ -140,7 +130,9 @@ class Linter {
140130
walkProgram(programPos, ast, getVisitorsArr(visitor));
141131

142132
// Send diagnostics back to Rust
143-
return JSON.stringify(diagnostics);
133+
const ret = JSON.stringify(diagnostics);
134+
diagnostics.length = 0;
135+
return ret;
144136
}
145137
}
146138

@@ -163,6 +155,43 @@ function combineVisitors(visitors) {
163155
return combinedVisitor;
164156
}
165157

158+
/**
159+
* Context class.
160+
*
161+
* A `Context` is passed to each rule's `create` function.
162+
*/
163+
class Context {
164+
// Rule ID. Index into `PluginRegistry`'s `registeredRules` array.
165+
#ruleId;
166+
167+
/**
168+
* @constructor
169+
* @param {number} ruleId - Rule ID
170+
* @param {string} filePath - Absolute path of file being linted
171+
*/
172+
constructor(ruleId, filePath) {
173+
this.#ruleId = ruleId;
174+
this.physicalFilename = filePath;
175+
}
176+
177+
/**
178+
* Report error.
179+
* @param {Object} diagnostic - Diagnostic object
180+
* @param {string} diagnostic.message - Error message
181+
* @param {Object} diagnostic.loc - Node or loc object
182+
* @param {number} diagnostic.loc.start - Start range of diagnostic
183+
* @param {number} diagnostic.loc.end - End range of diagnostic
184+
* @returns {undefined}
185+
*/
186+
report(diagnostic) {
187+
diagnostics.push({
188+
message: diagnostic.message,
189+
loc: { start: diagnostic.node.start, end: diagnostic.node.end },
190+
externalRuleId: this.#ruleId,
191+
});
192+
}
193+
}
194+
166195
async function main() {
167196
const linter = new Linter();
168197

0 commit comments

Comments
 (0)