Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions apps/oxlint/conformance/snapshots/stylistic.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,10 @@ Skip: 0 / 217 (0.0%)
```

Error: Overlapping token/comments: last end: 75, next start: 24
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)


#### jsx-tag-spacing > valid
Expand Down Expand Up @@ -292,10 +292,10 @@ Error: Overlapping token/comments: last end: 75, next start: 24
```

Error: Overlapping token/comments: last end: 88, next start: 24
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)


#### jsx-tag-spacing > invalid
Expand Down Expand Up @@ -332,10 +332,10 @@ Error: Overlapping token/comments: last end: 88, next start: 24
```

Error: Overlapping token/comments: last end: 81, next start: 30
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)


#### jsx-tag-spacing > invalid
Expand Down Expand Up @@ -399,10 +399,10 @@ Error: Overlapping token/comments: last end: 81, next start: 30
```

Error: Overlapping token/comments: last end: 94, next start: 30
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)


#### jsx-tag-spacing > invalid
Expand Down Expand Up @@ -442,10 +442,10 @@ Error: Overlapping token/comments: last end: 94, next start: 30
```

Error: Overlapping token/comments: last end: 105, next start: 54
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)


#### jsx-tag-spacing > invalid
Expand Down Expand Up @@ -512,8 +512,8 @@ Error: Overlapping token/comments: last end: 105, next start: 54
```

Error: Overlapping token/comments: last end: 118, next start: 54
at debugCheckValidRanges (apps/oxlint/dist/load.js)
at debugCheckTokensAndComments (apps/oxlint/dist/load.js)
at initTokensAndComments (apps/oxlint/dist/load.js)
at Object.isSpaceBetween (apps/oxlint/dist/load.js)
at debugCheckValidRanges (apps/oxlint/dist/lint.js)
at debugCheckTokensAndComments (apps/oxlint/dist/lint.js)
at initTokensAndComments (apps/oxlint/dist/lint.js)
at Object.isSpaceBetween (apps/oxlint/dist/lint.js)

15 changes: 4 additions & 11 deletions apps/oxlint/src-js/package/rule_tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ import { join as pathJoin, isAbsolute as isAbsolutePath, dirname } from "node:pa
import util from "node:util";
import stableJsonStringify from "json-stable-stringify-without-jsonify";
import { ecmaFeaturesOverride, setEcmaVersion, ECMA_VERSION } from "../plugins/context.ts";
import { registerPlugin } from "../plugins/load.ts";
import { registerPlugin, registeredRules } from "../plugins/load.ts";
import { lintFileImpl, resetStateAfterError } from "../plugins/lint.ts";
import { getLineColumnFromOffset, getNodeByRangeIndex } from "../plugins/location.ts";
import { setOptions, DEFAULT_OPTIONS_ID } from "../plugins/options.ts";
import { allOptions, setOptions, DEFAULT_OPTIONS_ID } from "../plugins/options.ts";
import { diagnostics, replacePlaceholders, PLACEHOLDER_REGEX } from "../plugins/report.ts";
import { parse } from "./parse.ts";
import { createWorkspace, destroyWorkspace } from "../workspace/index.ts";

import type { RequireAtLeastOne } from "type-fest";
import type { Plugin, Rule } from "../plugins/load.ts";
Expand Down Expand Up @@ -358,11 +357,6 @@ const DEFAULT_FILENAME_BASE = "file";
// Root of `oxlint` package once bundled into `dist`.
const DEFAULT_CWD = dirname(import.meta.dirname);

// Dummy workspace URI.
// This just needs to be unique, and we only have a single workspace in existence at any time.
// It can be anything, so just use empty string.
const WORKSPACE_URI = "";

// ------------------------------------------------------------------------------
// `RuleTester` class
// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -1019,8 +1013,6 @@ function lint(test: TestCase, plugin: Plugin): Diagnostic[] {
path = pathJoin(cwd, filename);
}

createWorkspace(WORKSPACE_URI);

try {
// Register plugin. This adds rule to `registeredRules` array.
registerPlugin(plugin, null, false, null);
Expand Down Expand Up @@ -1081,7 +1073,8 @@ function lint(test: TestCase, plugin: Plugin): Diagnostic[] {
});
} finally {
// Reset state
destroyWorkspace(WORKSPACE_URI);
registeredRules.length = 0;
if (allOptions !== null) allOptions.length = 1;

// Even if there hasn't been an error, do a full reset of state just to be sure.
// This includes emptying `diagnostics`.
Expand Down
23 changes: 15 additions & 8 deletions apps/oxlint/src-js/plugins/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,23 @@ import type { ModuleKind, Program } from "../generated/types.d.ts";
export let filePath: string | null = null;

// Current working directory for file being linted.
// When `null`, indicates that no file is currently being linted (in `createOnce`, or between linting files).
let cwd: string | null = null;
// Set by `setOptions` at end of registering all plugins, and may also be changed when switching workspaces.
export let cwd: string | null = null;

/**
* Set CWD. Used when switching workspaces.
* @param cwdInput - CWD
*/
export function setCwd(cwdInput: string) {
cwd = cwdInput;
}

/**
* Set up context for linting a file.
* @param filePathInput - Absolute path of file being linted
* @param cwdInput - Current working directory for file being linted
*/
export function setupFileContext(filePathInput: string, cwdInput: string): void {
export function setupFileContext(filePathInput: string): void {
filePath = filePathInput;
cwd = cwdInput;
}

/**
Expand All @@ -68,7 +74,6 @@ export function setupFileContext(filePathInput: string, cwdInput: string): void
*/
export function resetFileContext(): void {
filePath = null;
cwd = null;
}

// ECMAScript version. This matches ESLint's default.
Expand Down Expand Up @@ -367,7 +372,8 @@ const FILE_CONTEXT = Object.freeze({
*/
get cwd(): string {
// Note: If we change this implementation, also change `getCwd` method below
if (cwd === null) throw new Error("Cannot access `context.cwd` in `createOnce`");
if (filePath === null) throw new Error("Cannot access `context.cwd` in `createOnce`");
debugAssertIsNonNull(cwd, "`cwd` should not be null");
return cwd;
},

Expand All @@ -377,7 +383,8 @@ const FILE_CONTEXT = Object.freeze({
* @deprecated Use `context.cwd` property instead.
*/
getCwd(): string {
if (cwd === null) throw new Error("Cannot call `context.getCwd` in `createOnce`");
if (filePath === null) throw new Error("Cannot call `context.getCwd` in `createOnce`");
debugAssertIsNonNull(cwd, "`cwd` should not be null");
return cwd;
},

Expand Down
34 changes: 13 additions & 21 deletions apps/oxlint/src-js/plugins/lint.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { walkProgramWithCfg, resetCfgWalk } from "./cfg.ts";
import { setupFileContext, resetFileContext } from "./context.ts";
import { registeredRules } from "./load.ts";
import { allOptions, cwds, DEFAULT_OPTIONS_ID } from "./options.ts";
import { allOptions, DEFAULT_OPTIONS_ID } from "./options.ts";
import { diagnostics } from "./report.ts";
import { setSettingsForFile, resetSettings } from "./settings.ts";
import { ast, initAst, resetSourceAndAst, setupSourceForFile } from "./source_code.ts";
import { HAS_BOM_FLAG_POS } from "../generated/constants.ts";
import { typeAssertIs, debugAssert, debugAssertIsNonNull } from "../utils/asserts.ts";
import { getErrorMessage } from "../utils/utils.ts";
import { setGlobalsForFile, resetGlobals } from "./globals.ts";
import { getCliWorkspace } from "../workspace/index.ts";
import { switchWorkspace } from "./workspace.ts";
import {
addVisitorToCompiled,
compiledVisitor,
Expand Down Expand Up @@ -154,22 +154,14 @@ export function lintFileImpl(
"`ruleIds` and `optionsIds` should be same length",
);

// Get workspace containing file.
// In CLI (`workspaceUri` is `null`), use the single workspace (the CWD passed to `setupRuleConfigs`).
// In LSP, use the provided workspace URI.
if (workspaceUri === null) workspaceUri = getCliWorkspace();
// Switch to requested workspace.
// In CLI, `workspaceUri` is `null`, and there's only 1 workspace, so no need to switch.
// In LSP, there can be multiple workspaces, so we need to switch if we're not already in the right one.
if (workspaceUri !== null) switchWorkspace(workspaceUri);
debugAssertIsNonNull(allOptions, "`allOptions` should be initialized");

const cwd = cwds.get(workspaceUri);
debugAssertIsNonNull(cwd, `No CWD registered for workspace "${workspaceUri}"`);

// Pass file path and CWD to context module, so `Context`s know what file is being linted
setupFileContext(filePath, cwd);

// Load all relevant workspace configurations
const rules = registeredRules.get(workspaceUri)!;
const workspaceOptions = allOptions.get(workspaceUri);
debugAssertIsNonNull(rules, "No rules registered for workspace");
debugAssertIsNonNull(workspaceOptions, "No options registered for workspace");
// Pass file path to context module, so `Context`s know what file is being linted
setupFileContext(filePath);

// Pass buffer to source code module, so it can decode source text and deserialize AST on demand.
//
Expand All @@ -191,20 +183,20 @@ export function lintFileImpl(

for (let i = 0, len = ruleIds.length; i < len; i++) {
const ruleId = ruleIds[i];
debugAssert(ruleId < rules.length, "Rule ID out of bounds");
const ruleDetails = rules[ruleId];
debugAssert(ruleId < registeredRules.length, "Rule ID out of bounds");
const ruleDetails = registeredRules[ruleId];

// Set `ruleIndex` for rule. It's used when sending diagnostics back to Rust.
ruleDetails.ruleIndex = i;

// Set `options` for rule
const optionsId = optionsIds[i];
debugAssert(optionsId < workspaceOptions.length, "Options ID out of bounds");
debugAssert(optionsId < allOptions.length, "Options ID out of bounds");

// If the rule has no user-provided options, use the plugin-provided default
// options (which falls back to `DEFAULT_OPTIONS`)
ruleDetails.options =
optionsId === DEFAULT_OPTIONS_ID ? ruleDetails.defaultOptions : workspaceOptions[optionsId];
optionsId === DEFAULT_OPTIONS_ID ? ruleDetails.defaultOptions : allOptions[optionsId];

let { visitor } = ruleDetails;
if (visitor === null) {
Expand Down
44 changes: 18 additions & 26 deletions apps/oxlint/src-js/plugins/load.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { getCliWorkspace } from "../workspace/index.ts";
import { createContext } from "./context.ts";
import { deepFreezeJsonArray } from "./json.ts";
import { compileSchema, DEFAULT_OPTIONS } from "./options.ts";
import { switchWorkspace } from "./workspace.ts";
import { getErrorMessage } from "../utils/utils.ts";
import { debugAssert, debugAssertIsNonNull } from "../utils/asserts.ts";
import { debugAssertIsNonNull } from "../utils/asserts.ts";

import type { Writable } from "type-fest";
import type { Context } from "./context.ts";
Expand Down Expand Up @@ -82,7 +82,16 @@ interface CreateOnceRuleDetails extends RuleDetailsBase {

// Rule objects for loaded rules.
// Indexed by `ruleId`, which is passed to `lintFile`.
export const registeredRules: Map<string, RuleDetails[]> = new Map();
// May be changed when switching workspaces.
export let registeredRules: RuleDetails[] = [];

/**
* Set `registeredRules`. Used when switching workspaces.
* @param rules - Array of `RuleDetails` objects
*/
export function setRegisteredRules(rules: RuleDetails[]) {
registeredRules = rules;
}

// `before` hook which makes rule never run.
const neverRunBeforeHook: BeforeHook = () => false;
Expand Down Expand Up @@ -145,14 +154,12 @@ export function registerPlugin(

pluginName = getPluginName(plugin, pluginName, pluginNameIsAlias);

// In CLI mode (`workspaceUri` is `null`), use the CWD from `setupRuleConfigs` (stored as CLI_WORKSPACE).
// In LSP mode, use the provided workspace URI.
if (workspaceUri === null) workspaceUri = getCliWorkspace();

const registeredRulesForWorkspace = registeredRules.get(workspaceUri);
debugAssertIsNonNull(registeredRulesForWorkspace, "Workspace must have registered rules array");
// Switch to requested workspace.
// In CLI, `workspaceUri` is `null`, and there's only 1 workspace, so no need to switch.
// In LSP, there can be multiple workspaces, so we need to switch if we're not already in the right one.
if (workspaceUri !== null) switchWorkspace(workspaceUri);

const offset = registeredRulesForWorkspace.length ?? 0;
const offset = registeredRules.length;
const { rules } = plugin;
const ruleNames = Object.keys(rules);
const ruleNamesLen = ruleNames.length;
Expand Down Expand Up @@ -277,7 +284,7 @@ export function registerPlugin(
(ruleDetails as unknown as Writable<CreateOnceRuleDetails>).afterHook = afterHook;
}

registeredRulesForWorkspace.push(ruleDetails);
registeredRules.push(ruleDetails);
}

return { name: pluginName, offset, ruleNames };
Expand Down Expand Up @@ -431,18 +438,3 @@ function conformHookFn<H>(hookFn: H | null | undefined, hookName: string): H | n
}
return hookFn;
}

export function setupPluginSystemForWorkspace(workspace: string) {
debugAssert(
!registeredRules.has(workspace),
"Workspace must not already have registered rules array",
);
registeredRules.set(workspace, []);
}

/**
* Remove all plugins and rules associated with a workspace.
*/
export function removePluginsInWorkspace(workspace: string) {
registeredRules.delete(workspace);
}
Loading
Loading