From f08ca6414b9fd16b571332674a50aec520f66e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 5 Feb 2025 16:59:24 +0100 Subject: [PATCH] feat(lint): add JavaScript plugin support (#27203) This commit adds an unstable lint plugin API. Plugins are specified in the `deno.json` file under `lint.plugins` option like so: ``` { "lint": { "plugins": [ "./plugins/my-plugin.ts", "jsr:@deno/lint-plugin1", "npm:@deno/lint-plugin2" ] } } ``` The API is considered unstable and might be subject to changes in the future. Plugin API was modelled after ESLint API for the most part, but there are no guarantees for compatibility. The AST format exposed to plugins is closely modelled after the AST that `typescript-eslint` uses. Lint plugins use the visitor pattern and can add diagnostics like so: ``` export default { name: "lint-plugin", rules: { "plugin-rule": { create(context) { return { Identifier(node) { if (node.name === "a") { context.report({ node, message: "should be b", fix(fixer) { return fixer.replaceText(node, "_b"); }, }); } }, }; }, }, }, } satisfies Deno.lint.Plugin; ``` Besides reporting errors (diagnostics) plugins can provide automatic fixes that use text replacement to apply changes. --------- Co-authored-by: Marvin Hagemeister Co-authored-by: David Sherret --- Cargo.lock | 8 +- cli/Cargo.toml | 2 +- cli/args/flags.rs | 1 + cli/args/mod.rs | 42 +- cli/js/40_lint.js | 241 +- cli/js/40_lint_types.d.ts | 35 +- cli/lsp/analysis.rs | 4 +- cli/lsp/config.rs | 36 +- cli/lsp/diagnostics.rs | 6 +- cli/ops/lint.rs | 225 +- cli/schemas/lint-rules.v1.json | 254 +- cli/tools/lint/ast_buffer/buffer.rs | 19 +- cli/tools/lint/ast_buffer/mod.rs | 9 +- cli/tools/lint/ast_buffer/swc.rs | 7 +- cli/tools/lint/ast_buffer/ts_estree.rs | 5 + cli/tools/lint/linter.rs | 235 +- cli/tools/lint/mod.rs | 92 +- cli/tools/lint/plugins.rs | 543 +++ cli/tools/lint/reporters.rs | 16 +- cli/tools/lint/rules/mod.rs | 12 +- cli/tools/test/mod.rs | 2 +- cli/tsc/dts/lib.deno.unstable.d.ts | 133 + cli/util/text_encoding.rs | 89 + runtime/js/99_main.js | 11 +- tests/integration/js_unit_tests.rs | 12 +- tests/specs/lint/lint_plugin/__test__.jsonc | 17 + tests/specs/lint/lint_plugin/a.ts | 1 + tests/specs/lint/lint_plugin/deno.json | 5 + .../specs/lint/lint_plugin/deno_exclude.json | 10 + tests/specs/lint/lint_plugin/lint.out | 2 + tests/specs/lint/lint_plugin/lint_exclude.out | 1 + tests/specs/lint/lint_plugin/lint_fixed.out | 1 + tests/specs/lint/lint_plugin/plugin.ts | 22 + .../lint/lint_plugin_fix_error/__test__.jsonc | 6 + .../lint/lint_plugin_fix_error/deno.json | 5 + .../specs/lint/lint_plugin_fix_error/fix.out | 11 + .../specs/lint/lint_plugin_fix_error/main.ts | 2 + .../lint/lint_plugin_fix_error/plugin.ts | 20 + .../lint_plugin_infinite_edits/__test__.jsonc | 6 + .../lint/lint_plugin_infinite_edits/deno.json | 5 + .../lint/lint_plugin_infinite_edits/fix.out | 12 + .../lint/lint_plugin_infinite_edits/main.ts | 2 + .../lint/lint_plugin_infinite_edits/plugin.ts | 20 + .../lint/lint_plugin_utf16/__test__.jsonc | 22 + tests/specs/lint/lint_plugin_utf16/deno.json | 5 + tests/specs/lint/lint_plugin_utf16/fix.out | 1 + tests/specs/lint/lint_plugin_utf16/fixed.out | 2 + tests/specs/lint/lint_plugin_utf16/lint.out | 11 + tests/specs/lint/lint_plugin_utf16/main.ts | 2 + tests/specs/lint/lint_plugin_utf16/plugin.ts | 22 + .../__snapshots__/lint_plugin_test.ts.snap | 3022 ++++++++--------- tests/unit/lint_plugin_test.ts | 41 +- tests/unit/ops_test.ts | 2 +- 53 files changed, 3521 insertions(+), 1796 deletions(-) create mode 100644 cli/tools/lint/plugins.rs create mode 100644 tests/specs/lint/lint_plugin/__test__.jsonc create mode 100644 tests/specs/lint/lint_plugin/a.ts create mode 100644 tests/specs/lint/lint_plugin/deno.json create mode 100644 tests/specs/lint/lint_plugin/deno_exclude.json create mode 100644 tests/specs/lint/lint_plugin/lint.out create mode 100644 tests/specs/lint/lint_plugin/lint_exclude.out create mode 100644 tests/specs/lint/lint_plugin/lint_fixed.out create mode 100644 tests/specs/lint/lint_plugin/plugin.ts create mode 100644 tests/specs/lint/lint_plugin_fix_error/__test__.jsonc create mode 100644 tests/specs/lint/lint_plugin_fix_error/deno.json create mode 100644 tests/specs/lint/lint_plugin_fix_error/fix.out create mode 100644 tests/specs/lint/lint_plugin_fix_error/main.ts create mode 100644 tests/specs/lint/lint_plugin_fix_error/plugin.ts create mode 100644 tests/specs/lint/lint_plugin_infinite_edits/__test__.jsonc create mode 100644 tests/specs/lint/lint_plugin_infinite_edits/deno.json create mode 100644 tests/specs/lint/lint_plugin_infinite_edits/fix.out create mode 100644 tests/specs/lint/lint_plugin_infinite_edits/main.ts create mode 100644 tests/specs/lint/lint_plugin_infinite_edits/plugin.ts create mode 100644 tests/specs/lint/lint_plugin_utf16/__test__.jsonc create mode 100644 tests/specs/lint/lint_plugin_utf16/deno.json create mode 100644 tests/specs/lint/lint_plugin_utf16/fix.out create mode 100644 tests/specs/lint/lint_plugin_utf16/fixed.out create mode 100644 tests/specs/lint/lint_plugin_utf16/lint.out create mode 100644 tests/specs/lint/lint_plugin_utf16/main.ts create mode 100644 tests/specs/lint/lint_plugin_utf16/plugin.ts diff --git a/Cargo.lock b/Cargo.lock index e64d40feba7b02..b701073a76db85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,9 +2010,9 @@ dependencies = [ [[package]] name = "deno_lint" -version = "0.70.0" +version = "0.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac94db8d8597b96c92d30a68b11d4bec6822dcbb3e8675ab1e0136816a301a34" +checksum = "810d0f4b19cd44061bbe7252ad37cf7a81753540f97f88e1548ac9f03b3a18cc" dependencies = [ "anyhow", "deno_ast", @@ -4187,9 +4187,9 @@ dependencies = [ [[package]] name = "hstr" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9de2bdef6354361892492bab5e316b2d78a0ee9971db4d36da9b1eb0e11999" +checksum = "dae404c0c5d4e95d4858876ab02eecd6a196bb8caa42050dfa809938833fc412" dependencies = [ "hashbrown 0.14.5", "new_debug_unreachable", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index dee17bd34474a2..1e8d75628c2415 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -74,7 +74,7 @@ deno_doc = { version = "=0.164.0", features = ["rust", "comrak"] } deno_error.workspace = true deno_graph = { version = "=0.87.2" } deno_lib.workspace = true -deno_lint = { version = "0.70.0" } +deno_lint = { version = "0.71.0" } deno_lockfile.workspace = true deno_media_type = { workspace = true, features = ["data_url", "decoding", "module_specifier"] } deno_npm.workspace = true diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 7a817486def07f..96adff8696d6d2 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -499,6 +499,7 @@ impl DenoSubcommand { | Self::Jupyter(_) | Self::Repl(_) | Self::Bench(_) + | Self::Lint(_) | Self::Lsp ) } diff --git a/cli/args/mod.rs b/cli/args/mod.rs index f0d59299d0202a..d59a4e4d362c88 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -366,6 +366,7 @@ pub struct LintOptions { pub rules: LintRulesConfig, pub files: FilePatterns, pub fix: bool, + pub plugins: Vec, } impl Default for LintOptions { @@ -380,20 +381,41 @@ impl LintOptions { rules: Default::default(), files: FilePatterns::new_with_base(base), fix: false, + plugins: vec![], } } - pub fn resolve(lint_config: LintConfig, lint_flags: &LintFlags) -> Self { - Self { + pub fn resolve( + dir_path: PathBuf, + lint_config: LintConfig, + lint_flags: &LintFlags, + ) -> Result { + let rules = resolve_lint_rules_options( + lint_config.options.rules, + lint_flags.maybe_rules_tags.clone(), + lint_flags.maybe_rules_include.clone(), + lint_flags.maybe_rules_exclude.clone(), + ); + + let plugins = { + let plugin_specifiers = lint_config.options.plugins; + let mut plugins = Vec::with_capacity(plugin_specifiers.len()); + for plugin in &plugin_specifiers { + // TODO(bartlomieju): handle import-mapped specifiers + let url = resolve_url_or_path(plugin, &dir_path)?; + plugins.push(url); + } + // ensure stability for hasher + plugins.sort_unstable(); + plugins + }; + + Ok(Self { files: lint_config.files, - rules: resolve_lint_rules_options( - lint_config.options.rules, - lint_flags.maybe_rules_tags.clone(), - lint_flags.maybe_rules_include.clone(), - lint_flags.maybe_rules_exclude.clone(), - ), + rules, fix: lint_flags.fix, - } + plugins, + }) } } @@ -759,7 +781,7 @@ impl CliOptions { .resolve_lint_config_for_members(&cli_arg_patterns)?; let mut result = Vec::with_capacity(member_configs.len()); for (ctx, config) in member_configs { - let options = LintOptions::resolve(config, lint_flags); + let options = LintOptions::resolve(ctx.dir_path(), config, lint_flags)?; result.push((ctx, options)); } Ok(result) diff --git a/cli/js/40_lint.js b/cli/js/40_lint.js index 9f85f0871df2ea..d8e99c7b0a9107 100644 --- a/cli/js/40_lint.js +++ b/cli/js/40_lint.js @@ -10,9 +10,14 @@ import { import { core, internals } from "ext:core/mod.js"; const { + op_lint_get_source, + op_lint_report, op_lint_create_serialized_ast, + op_is_cancelled, } = core.ops; +let doReport = op_lint_report; + // Keep these in sync with Rust const AST_IDX_INVALID = 0; const AST_GROUP_TYPE = 1; @@ -72,29 +77,133 @@ const PropFlags = { /** @typedef {import("./40_lint_types.d.ts").VisitorFn} VisitorFn */ /** @typedef {import("./40_lint_types.d.ts").CompiledVisitor} CompiledVisitor */ /** @typedef {import("./40_lint_types.d.ts").LintState} LintState */ -/** @typedef {import("./40_lint_types.d.ts").RuleContext} RuleContext */ -/** @typedef {import("./40_lint_types.d.ts").NodeFacade} NodeFacade */ -/** @typedef {import("./40_lint_types.d.ts").LintPlugin} LintPlugin */ /** @typedef {import("./40_lint_types.d.ts").TransformFn} TransformFn */ /** @typedef {import("./40_lint_types.d.ts").MatchContext} MatchContext */ -/** @typedef {import("./40_lint_types.d.ts").Node} Node */ /** @type {LintState} */ const state = { plugins: [], installedPlugins: new Set(), + ignoredRules: new Set(), }; +function resetState() { + state.plugins = []; + state.installedPlugins.clear(); + state.ignoredRules.clear(); +} + +/** + * This implementation calls into Rust to check if Tokio's cancellation token + * has already been canceled. + */ +class CancellationToken { + isCancellationRequested() { + return op_is_cancelled(); + } +} + +/** @implements {Deno.lint.Fixer} */ +class Fixer { + /** + * @param {Deno.lint.Node} node + * @param {string} text + */ + insertTextAfter(node, text) { + return { + range: /** @type {[number, number]} */ ([node.range[1], node.range[1]]), + text, + }; + } + + /** + * @param {Deno.lint.Node["range"]} range + * @param {string} text + */ + insertTextAfterRange(range, text) { + return { + range: /** @type {[number, number]} */ ([range[1], range[1]]), + text, + }; + } + + /** + * @param {Deno.lint.Node} node + * @param {string} text + */ + insertTextBefore(node, text) { + return { + range: /** @type {[number, number]} */ ([node.range[0], node.range[0]]), + text, + }; + } + + /** + * @param {Deno.lint.Node["range"]} range + * @param {string} text + */ + insertTextBeforeRange(range, text) { + return { + range: /** @type {[number, number]} */ ([range[0], range[0]]), + text, + }; + } + + /** + * @param {Deno.lint.Node} node + */ + remove(node) { + return { + range: node.range, + text: "", + }; + } + + /** + * @param {Deno.lint.Node["range"]} range + */ + removeRange(range) { + return { + range, + text: "", + }; + } + + /** + * @param {Deno.lint.Node} node + * @param {string} text + */ + replaceText(node, text) { + return { + range: node.range, + text, + }; + } + + /** + * @param {Deno.lint.Node["range"]} range + * @param {string} text + */ + replaceTextRange(range, text) { + return { + range, + text, + }; + } +} + /** * Every rule gets their own instance of this class. This is the main * API lint rules interact with. - * @implements {RuleContext} + * @implements {Deno.lint.RuleContext} */ export class Context { id; fileName; + #source = null; + /** * @param {string} id * @param {string} fileName @@ -103,18 +212,85 @@ export class Context { this.id = id; this.fileName = fileName; } + + source() { + if (this.#source === null) { + this.#source = op_lint_get_source(); + } + return /** @type {*} */ (this.#source); + } + + /** + * @param {Deno.lint.ReportData} data + */ + report(data) { + const range = data.node ? data.node.range : data.range ? data.range : null; + if (range == null) { + throw new Error( + "Either `node` or `range` must be provided when reporting an error", + ); + } + + const start = range[0]; + const end = range[1]; + + let fix; + + if (typeof data.fix === "function") { + const fixer = new Fixer(); + fix = data.fix(fixer); + } + + doReport( + this.id, + data.message, + data.hint, + start, + end, + fix, + ); + } } /** - * @param {LintPlugin} plugin + * @param {Deno.lint.Plugin[]} plugins + * @param {string[]} exclude + */ +export function installPlugins(plugins, exclude) { + if (Array.isArray(exclude)) { + for (let i = 0; i < exclude.length; i++) { + state.ignoredRules.add(exclude[i]); + } + } + + return plugins.map((plugin) => installPlugin(plugin)); +} + +/** + * @param {Deno.lint.Plugin} plugin */ -export function installPlugin(plugin) { +function installPlugin(plugin) { if (typeof plugin !== "object") { throw new Error("Linter plugin must be an object"); } if (typeof plugin.name !== "string") { throw new Error("Linter plugin name must be a string"); } + if (!/^[a-z-]+$/.test(plugin.name)) { + throw new Error( + "Linter plugin name must only contain lowercase letters (a-z) or hyphens (-).", + ); + } + if (plugin.name.startsWith("-") || plugin.name.endsWith("-")) { + throw new Error( + "Linter plugin name must start and end with a lowercase letter.", + ); + } + if (plugin.name.includes("--")) { + throw new Error( + "Linter plugin name must not have consequtive hyphens.", + ); + } if (typeof plugin.rules !== "object") { throw new Error("Linter plugin rules must be an object"); } @@ -123,6 +299,11 @@ export function installPlugin(plugin) { } state.plugins.push(plugin); state.installedPlugins.add(plugin.name); + + return { + name: plugin.name, + ruleNames: Object.keys(plugin.rules), + }; } /** @@ -285,7 +466,7 @@ function readType(buf, idx) { /** * @param {AstContext} ctx * @param {number} idx - * @returns {Node["range"]} + * @returns {Deno.lint.Node["range"]} */ function readSpan(ctx, idx) { let offset = ctx.spansOffset + (idx * SPAN_SIZE); @@ -765,6 +946,12 @@ export function runPluginsForFile(fileName, serializedAst) { for (const name of Object.keys(plugin.rules)) { const rule = plugin.rules[name]; const id = `${plugin.name}/${name}`; + + // Check if this rule is excluded + if (state.ignoredRules.has(id)) { + continue; + } + const ctx = new Context(id, fileName); const visitor = rule.create(ctx); @@ -852,10 +1039,11 @@ export function runPluginsForFile(fileName, serializedAst) { visitors.push({ info, matcher }); } + const token = new CancellationToken(); // Traverse ast with all visitors at the same time to avoid traversing // multiple times. try { - traverse(ctx, visitors, ctx.rootOffset); + traverse(ctx, visitors, ctx.rootOffset, token); } finally { ctx.nodes.clear(); @@ -870,9 +1058,11 @@ export function runPluginsForFile(fileName, serializedAst) { * @param {AstContext} ctx * @param {CompiledVisitor[]} visitors * @param {number} idx + * @param {CancellationToken} cancellationToken */ -function traverse(ctx, visitors, idx) { +function traverse(ctx, visitors, idx, cancellationToken) { if (idx === AST_IDX_INVALID) return; + if (cancellationToken.isCancellationRequested()) return; const { buf } = ctx; const nodeType = readType(ctx.buf, idx); @@ -905,12 +1095,12 @@ function traverse(ctx, visitors, idx) { try { const childIdx = readChild(buf, idx); if (childIdx > AST_IDX_INVALID) { - traverse(ctx, visitors, childIdx); + traverse(ctx, visitors, childIdx, cancellationToken); } const nextIdx = readNext(buf, idx); if (nextIdx > AST_IDX_INVALID) { - traverse(ctx, visitors, nextIdx); + traverse(ctx, visitors, nextIdx, cancellationToken); } } finally { if (exits !== null) { @@ -1064,8 +1254,12 @@ function _dump(ctx) { } } -// TODO(bartlomieju): this is temporary, until we get plugins plumbed through -// the CLI linter +// These are captured by Rust and called when plugins need to be loaded +// or run. +internals.installPlugins = installPlugins; +internals.runPluginsForFile = runPluginsForFile; +internals.resetState = resetState; + /** * @param {LintPlugin} plugin * @param {string} fileName @@ -1074,16 +1268,25 @@ function _dump(ctx) { function runLintPlugin(plugin, fileName, sourceText) { installPlugin(plugin); + const diagnostics = []; + doReport = (id, message, hint, start, end, fix) => { + diagnostics.push({ + id, + message, + hint, + range: [start, end], + fix, + }); + }; try { const serializedAst = op_lint_create_serialized_ast(fileName, sourceText); runPluginsForFile(fileName, serializedAst); } finally { - // During testing we don't want to keep plugins around - state.installedPlugins.clear(); + resetState(); } + doReport = op_lint_report; + return diagnostics; } -// TODO(bartlomieju): this is temporary, until we get plugins plumbed through -// the CLI linter -internals.runLintPlugin = runLintPlugin; +Deno.lint.runPlugin = runLintPlugin; diff --git a/cli/js/40_lint_types.d.ts b/cli/js/40_lint_types.d.ts index f07d16581e8e49..662cfc930f7889 100644 --- a/cli/js/40_lint_types.d.ts +++ b/cli/js/40_lint_types.d.ts @@ -1,17 +1,11 @@ // Copyright 2018-2025 the Deno authors. MIT license. -export interface NodeFacade { - type: string; - range: [number, number]; - [key: string]: unknown; -} - export interface AstContext { buf: Uint8Array; strTable: Map; strTableOffset: number; rootOffset: number; - nodes: Map; + nodes: Map; spansOffset: number; propsOffset: number; strByType: number[]; @@ -21,32 +15,11 @@ export interface AstContext { matcher: MatchContext; } -export interface Node { - range: Range; -} - -export type Range = [number, number]; - -// TODO(@marvinhagemeister) Remove once we land "official" types -export interface RuleContext { - id: string; -} - -// TODO(@marvinhagemeister) Remove once we land "official" types -export interface LintRule { - create(ctx: RuleContext): Record void>; - destroy?(ctx: RuleContext): void; -} - -// TODO(@marvinhagemeister) Remove once we land "official" types -export interface LintPlugin { - name: string; - rules: Record; -} - export interface LintState { - plugins: LintPlugin[]; + plugins: Deno.lint.Plugin[]; installedPlugins: Set; + /** format: `/` */ + ignoredRules: Set; } export type VisitorFn = (node: unknown) => void; diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index fd7337df263dc8..16a815e08ff7bb 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -38,6 +38,7 @@ use node_resolver::ResolutionMode; use once_cell::sync::Lazy; use regex::Regex; use text_lines::LineAndColumnIndex; +use tokio_util::sync::CancellationToken; use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types::Position; use tower_lsp::lsp_types::Range; @@ -186,8 +187,9 @@ fn as_lsp_range( pub fn get_lint_references( parsed_source: &deno_ast::ParsedSource, linter: &CliLinter, + token: CancellationToken, ) -> Result, AnyError> { - let lint_diagnostics = linter.lint_with_ast(parsed_source); + let lint_diagnostics = linter.lint_with_ast(parsed_source, token)?; Ok( lint_diagnostics diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index e4570031fb7884..b76c54c7ed6b5f 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -1629,14 +1629,46 @@ impl ConfigData { sloppy_imports_resolver.clone(), Some(resolver.clone()), ); + + let lint_options = LintOptions::resolve( + member_dir.dir_path(), + (*lint_config).clone(), + &LintFlags::default(), + ) + .inspect_err(|err| lsp_warn!(" Failed to resolve linter options: {}", err)) + .ok() + .unwrap_or_default(); + let mut plugin_runner = None; + if !lint_options.plugins.is_empty() { + fn logger_printer(msg: &str, _is_err: bool) { + lsp_log!("pluggin runner - {}", msg); + } + let logger = crate::tools::lint::PluginLogger::new(logger_printer); + let plugin_load_result = + crate::tools::lint::create_runner_and_load_plugins( + lint_options.plugins.clone(), + logger, + lint_options.rules.exclude.clone(), + ) + .await; + match plugin_load_result { + Ok(runner) => { + plugin_runner = Some(Arc::new(runner)); + } + Err(err) => { + lsp_warn!("Failed to load lint plugins: {}", err); + } + } + } + let linter = Arc::new(CliLinter::new(CliLinterOptions { configured_rules: lint_rule_provider.resolve_lint_rules( - LintOptions::resolve((*lint_config).clone(), &LintFlags::default()) - .rules, + lint_options.rules, member_dir.maybe_deno_json().map(|c| c.as_ref()), ), fix: false, deno_lint_config, + maybe_plugin_runner: plugin_runner, })); ConfigData { diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index dee672d17a73a4..7283f2cf8f684a 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -1021,6 +1021,8 @@ fn generate_lint_diagnostics( default_jsx_factory: None, default_jsx_fragment_factory: None, }, + // TODO(bartlomieju): handle linter plugins here before landing + maybe_plugin_runner: None, })), ) }); @@ -1032,6 +1034,7 @@ fn generate_lint_diagnostics( &document, &lint_config, &linter, + token.clone(), ), }, }); @@ -1043,6 +1046,7 @@ fn generate_document_lint_diagnostics( document: &Document, lint_config: &LintConfig, linter: &CliLinter, + token: CancellationToken, ) -> Vec { if !lint_config.files.matches_specifier(document.specifier()) { return Vec::new(); @@ -1050,7 +1054,7 @@ fn generate_document_lint_diagnostics( match document.maybe_parsed_source() { Some(Ok(parsed_source)) => { if let Ok(references) = - analysis::get_lint_references(parsed_source, linter) + analysis::get_lint_references(parsed_source, linter, token) { references .into_iter() diff --git a/cli/ops/lint.rs b/cli/ops/lint.rs index c13cb21a53d43f..820a64db43e670 100644 --- a/cli/ops/lint.rs +++ b/cli/ops/lint.rs @@ -3,11 +3,187 @@ use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_ast::ParseDiagnostic; +use deno_ast::SourceRange; +use deno_ast::SourceTextInfo; +use deno_ast::SourceTextProvider; use deno_core::op2; +use deno_core::OpState; +use deno_lint::diagnostic::LintDiagnostic; +use deno_lint::diagnostic::LintDiagnosticDetails; +use deno_lint::diagnostic::LintDiagnosticRange; +use deno_lint::diagnostic::LintFix; +use deno_lint::diagnostic::LintFixChange; +use tokio_util::sync::CancellationToken; use crate::tools::lint; +use crate::tools::lint::PluginLogger; +use crate::util::text_encoding::Utf16Map; -deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],); +deno_core::extension!( + deno_lint_ext, + ops = [ + op_lint_create_serialized_ast, + op_lint_report, + op_lint_get_source, + op_is_cancelled + ], + options = { + logger: PluginLogger, + }, + // TODO(bartlomieju): this should only be done, + // if not in the "test worker". + middleware = |op| match op.name { + "op_print" => op_print(), + _ => op, + }, + state = |state, options| { + state.put(options.logger); + state.put(LintPluginContainer::default()); + }, +); + +deno_core::extension!( + deno_lint_ext_for_test, + ops = [op_lint_create_serialized_ast, op_is_cancelled], + state = |state| { + state.put(LintPluginContainer::default()); + }, +); + +#[derive(Default)] +pub struct LintPluginContainer { + pub diagnostics: Vec, + pub source_text_info: Option, + pub utf_16_map: Option, + pub specifier: Option, + pub token: CancellationToken, +} + +impl LintPluginContainer { + pub fn set_cancellation_token( + &mut self, + maybe_token: Option, + ) { + let token = maybe_token.unwrap_or_default(); + self.token = token; + } + + pub fn set_info_for_file( + &mut self, + specifier: ModuleSpecifier, + source_text_info: SourceTextInfo, + utf16_map: Utf16Map, + ) { + self.specifier = Some(specifier); + self.utf_16_map = Some(utf16_map); + self.source_text_info = Some(source_text_info); + } + + fn report( + &mut self, + id: String, + message: String, + hint: Option, + start_utf16: usize, + end_utf16: usize, + fix: Option, + ) -> Result<(), LintReportError> { + fn out_of_range_err( + map: &Utf16Map, + start_utf16: usize, + end_utf16: usize, + ) -> LintReportError { + LintReportError::IncorrectRange { + start: start_utf16, + end: end_utf16, + source_end: map.text_content_length_utf16().into(), + } + } + + fn utf16_to_utf8_range( + utf16_map: &Utf16Map, + source_text_info: &SourceTextInfo, + start_utf16: usize, + end_utf16: usize, + ) -> Result { + let Some(start) = + utf16_map.utf16_to_utf8_offset((start_utf16 as u32).into()) + else { + return Err(out_of_range_err(utf16_map, start_utf16, end_utf16)); + }; + let Some(end) = utf16_map.utf16_to_utf8_offset((end_utf16 as u32).into()) + else { + return Err(out_of_range_err(utf16_map, start_utf16, end_utf16)); + }; + let start_pos = source_text_info.start_pos(); + Ok(SourceRange::new( + start_pos + start.into(), + start_pos + end.into(), + )) + } + + let source_text_info = self.source_text_info.as_ref().unwrap(); + let utf16_map = self.utf_16_map.as_ref().unwrap(); + let specifier = self.specifier.clone().unwrap(); + let diagnostic_range = + utf16_to_utf8_range(utf16_map, source_text_info, start_utf16, end_utf16)?; + let range = LintDiagnosticRange { + range: diagnostic_range, + description: None, + text_info: source_text_info.clone(), + }; + + let mut fixes: Vec = vec![]; + + if let Some(fix) = fix { + let fix_range = utf16_to_utf8_range( + utf16_map, + source_text_info, + fix.range.0, + fix.range.1, + )?; + fixes.push(LintFix { + changes: vec![LintFixChange { + new_text: fix.text.into(), + range: fix_range, + }], + description: format!("Fix this {} problem", id).into(), + }); + } + + let lint_diagnostic = LintDiagnostic { + specifier, + range: Some(range), + details: LintDiagnosticDetails { + message, + code: id, + hint, + fixes, + custom_docs_url: None, + info: vec![], + }, + }; + self.diagnostics.push(lint_diagnostic); + Ok(()) + } +} + +#[op2(fast)] +pub fn op_print(state: &mut OpState, #[string] msg: &str, is_err: bool) { + let logger = state.borrow::(); + + if is_err { + logger.error(msg); + } else { + logger.log(msg); + } +} + +#[op2(fast)] +fn op_is_cancelled(state: &mut OpState) -> bool { + let container = state.borrow::(); + container.token.is_cancelled() +} #[derive(Debug, thiserror::Error, deno_error::JsError)] pub enum LintError { @@ -41,5 +217,50 @@ fn op_lint_create_serialized_ast( scope_analysis: false, maybe_syntax: None, })?; - Ok(lint::serialize_ast_to_buffer(&parsed_source)) + let utf16_map = Utf16Map::new(parsed_source.text().as_ref()); + Ok(lint::serialize_ast_to_buffer(&parsed_source, &utf16_map)) +} + +#[derive(serde::Deserialize)] +struct LintReportFix { + text: String, + range: (usize, usize), +} + +#[derive(Debug, thiserror::Error, deno_error::JsError)] +pub enum LintReportError { + #[class(type)] + #[error("Invalid range [{start}, {end}], the source has a range of [0, {source_end}]")] + IncorrectRange { + start: usize, + end: usize, + source_end: u32, + }, +} + +#[op2] +fn op_lint_report( + state: &mut OpState, + #[string] id: String, + #[string] message: String, + #[string] hint: Option, + #[smi] start_utf16: usize, + #[smi] end_utf16: usize, + #[serde] fix: Option, +) -> Result<(), LintReportError> { + let container = state.borrow_mut::(); + container.report(id, message, hint, start_utf16, end_utf16, fix)?; + Ok(()) +} + +#[op2] +#[string] +fn op_lint_get_source(state: &mut OpState) -> String { + let container = state.borrow_mut::(); + container + .source_text_info + .as_ref() + .unwrap() + .text_str() + .to_string() } diff --git a/cli/schemas/lint-rules.v1.json b/cli/schemas/lint-rules.v1.json index 87bd4e26003ac9..90c1230b410602 100644 --- a/cli/schemas/lint-rules.v1.json +++ b/cli/schemas/lint-rules.v1.json @@ -1,127 +1,135 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "enum": [ - "adjacent-overload-signatures", - "ban-ts-comment", - "ban-types", - "ban-unknown-rule-code", - "ban-untagged-ignore", - "ban-untagged-todo", - "ban-unused-ignore", - "camelcase", - "constructor-super", - "default-param-last", - "eqeqeq", - "explicit-function-return-type", - "explicit-module-boundary-types", - "for-direction", - "fresh-handler-export", - "fresh-server-event-handlers", - "getter-return", - "guard-for-in", - "jsx-boolean-value", - "jsx-button-has-type", - "jsx-curly-braces", - "jsx-key", - "jsx-no-children-prop", - "jsx-no-comment-text-nodes", - "jsx-no-duplicate-props", - "jsx-no-unescaped-entities", - "jsx-no-useless-fragment", - "jsx-props-no-spread-multi", - "jsx-void-dom-elements-no-children", - "no-array-constructor", - "no-async-promise-executor", - "no-await-in-loop", - "no-await-in-sync-fn", - "no-boolean-literal-for-arguments", - "no-case-declarations", - "no-class-assign", - "no-compare-neg-zero", - "no-cond-assign", - "no-console", - "no-const-assign", - "no-constant-condition", - "no-control-regex", - "no-debugger", - "no-delete-var", - "no-deprecated-deno-api", - "no-dupe-args", - "no-dupe-class-members", - "no-dupe-else-if", - "no-dupe-keys", - "no-duplicate-case", - "no-empty", - "no-empty-character-class", - "no-empty-enum", - "no-empty-interface", - "no-empty-pattern", - "no-eval", - "no-ex-assign", - "no-explicit-any", - "no-external-import", - "no-extra-boolean-cast", - "no-extra-non-null-assertion", - "no-fallthrough", - "no-func-assign", - "no-global-assign", - "no-implicit-declare-namespace-export", - "no-import-assertions", - "no-import-assign", - "no-inferrable-types", - "no-inner-declarations", - "no-invalid-regexp", - "no-invalid-triple-slash-reference", - "no-irregular-whitespace", - "no-misused-new", - "no-namespace", - "no-new-symbol", - "no-node-globals", - "no-non-null-asserted-optional-chain", - "no-non-null-assertion", - "no-obj-calls", - "no-octal", - "no-process-global", - "no-prototype-builtins", - "no-redeclare", - "no-regex-spaces", - "no-self-assign", - "no-self-compare", - "no-setter-return", - "no-shadow-restricted-names", - "no-sloppy-imports", - "no-slow-types", - "no-sparse-arrays", - "no-sync-fn-in-async-fn", - "no-this-alias", - "no-this-before-super", - "no-throw-literal", - "no-top-level-await", - "no-undef", - "no-unreachable", - "no-unsafe-finally", - "no-unsafe-negation", - "no-unused-labels", - "no-unused-vars", - "no-useless-rename", - "no-var", - "no-window", - "no-window-prefix", - "no-with", - "prefer-as-const", - "prefer-ascii", - "prefer-const", - "prefer-namespace-keyword", - "prefer-primordials", - "react-no-danger", - "react-no-danger-with-children", - "react-rules-of-hooks", - "require-await", - "require-yield", - "single-var-declarator", - "triple-slash-reference", - "use-isnan", - "valid-typeof", - "verbatim-module-syntax" + "oneOf": [ + { + "type": "string", + "pattern": "^[a-z0-9-]+\\/[a-z0-9-]+$" + }, + { + "enum": [ + "adjacent-overload-signatures", + "ban-ts-comment", + "ban-types", + "ban-unknown-rule-code", + "ban-untagged-ignore", + "ban-untagged-todo", + "ban-unused-ignore", + "camelcase", + "constructor-super", + "default-param-last", + "eqeqeq", + "explicit-function-return-type", + "explicit-module-boundary-types", + "for-direction", + "fresh-handler-export", + "fresh-server-event-handlers", + "getter-return", + "guard-for-in", + "jsx-boolean-value", + "jsx-button-has-type", + "jsx-curly-braces", + "jsx-key", + "jsx-no-children-prop", + "jsx-no-comment-text-nodes", + "jsx-no-duplicate-props", + "jsx-no-unescaped-entities", + "jsx-no-useless-fragment", + "jsx-props-no-spread-multi", + "jsx-void-dom-elements-no-children", + "no-array-constructor", + "no-async-promise-executor", + "no-await-in-loop", + "no-await-in-sync-fn", + "no-boolean-literal-for-arguments", + "no-case-declarations", + "no-class-assign", + "no-compare-neg-zero", + "no-cond-assign", + "no-console", + "no-const-assign", + "no-constant-condition", + "no-control-regex", + "no-debugger", + "no-delete-var", + "no-deprecated-deno-api", + "no-dupe-args", + "no-dupe-class-members", + "no-dupe-else-if", + "no-dupe-keys", + "no-duplicate-case", + "no-empty", + "no-empty-character-class", + "no-empty-enum", + "no-empty-interface", + "no-empty-pattern", + "no-eval", + "no-ex-assign", + "no-explicit-any", + "no-external-import", + "no-extra-boolean-cast", + "no-extra-non-null-assertion", + "no-fallthrough", + "no-func-assign", + "no-global-assign", + "no-implicit-declare-namespace-export", + "no-import-assertions", + "no-import-assign", + "no-inferrable-types", + "no-inner-declarations", + "no-invalid-regexp", + "no-invalid-triple-slash-reference", + "no-irregular-whitespace", + "no-misused-new", + "no-namespace", + "no-new-symbol", + "no-node-globals", + "no-non-null-asserted-optional-chain", + "no-non-null-assertion", + "no-obj-calls", + "no-octal", + "no-process-global", + "no-prototype-builtins", + "no-redeclare", + "no-regex-spaces", + "no-self-assign", + "no-self-compare", + "no-setter-return", + "no-shadow-restricted-names", + "no-sloppy-imports", + "no-slow-types", + "no-sparse-arrays", + "no-sync-fn-in-async-fn", + "no-this-alias", + "no-this-before-super", + "no-throw-literal", + "no-top-level-await", + "no-undef", + "no-unreachable", + "no-unsafe-finally", + "no-unsafe-negation", + "no-unused-labels", + "no-unused-vars", + "no-useless-rename", + "no-var", + "no-window", + "no-window-prefix", + "no-with", + "prefer-as-const", + "prefer-ascii", + "prefer-const", + "prefer-namespace-keyword", + "prefer-primordials", + "react-no-danger", + "react-no-danger-with-children", + "react-rules-of-hooks", + "require-await", + "require-yield", + "single-var-declarator", + "triple-slash-reference", + "use-isnan", + "valid-typeof", + "verbatim-module-syntax" + ] + } ] } diff --git a/cli/tools/lint/ast_buffer/buffer.rs b/cli/tools/lint/ast_buffer/buffer.rs index a884ee24f9e535..b3e4926f241918 100644 --- a/cli/tools/lint/ast_buffer/buffer.rs +++ b/cli/tools/lint/ast_buffer/buffer.rs @@ -6,6 +6,8 @@ use deno_ast::swc::common::Span; use deno_ast::swc::common::DUMMY_SP; use indexmap::IndexMap; +use crate::util::text_encoding::Utf16Map; + /// Each property has this flag to mark what kind of value it holds- /// Plain objects and arrays are not supported yet, but could be easily /// added if needed. @@ -212,6 +214,15 @@ impl SerializeCtx { self.root_idx = idx; } + pub fn map_utf8_spans_to_utf16(&mut self, map: &Utf16Map) { + for value in &mut self.spans { + *value = map + .utf8_to_utf16_offset((*value).into()) + .unwrap_or_else(|| panic!("Failed converting '{value}' to utf16.")) + .into(); + } + } + /// Allocate a node's header fn field_header

(&mut self, prop: P, prop_flags: PropFlags) where @@ -274,7 +285,13 @@ impl SerializeCtx { where K: Into + Display + Clone, { - self.append_inner(kind, span.lo.0, span.hi.0) + let (start, end) = if *span == DUMMY_SP { + (0, 0) + } else { + // -1 is because swc stores spans 1-indexed + (span.lo.0 - 1, span.hi.0 - 1) + }; + self.append_inner(kind, start, end) } pub fn append_inner( diff --git a/cli/tools/lint/ast_buffer/mod.rs b/cli/tools/lint/ast_buffer/mod.rs index fc4045fb60cc8a..b5611af2288f1b 100644 --- a/cli/tools/lint/ast_buffer/mod.rs +++ b/cli/tools/lint/ast_buffer/mod.rs @@ -3,11 +3,16 @@ use deno_ast::ParsedSource; use swc::serialize_swc_to_buffer; +use crate::util::text_encoding::Utf16Map; + mod buffer; mod swc; mod ts_estree; -pub fn serialize_ast_to_buffer(parsed_source: &ParsedSource) -> Vec { +pub fn serialize_ast_to_buffer( + parsed_source: &ParsedSource, + utf16_map: &Utf16Map, +) -> Vec { // TODO: We could support multiple languages here - serialize_swc_to_buffer(parsed_source) + serialize_swc_to_buffer(parsed_source, utf16_map) } diff --git a/cli/tools/lint/ast_buffer/swc.rs b/cli/tools/lint/ast_buffer/swc.rs index 925d1bcd17c032..385035d023ea1c 100644 --- a/cli/tools/lint/ast_buffer/swc.rs +++ b/cli/tools/lint/ast_buffer/swc.rs @@ -93,8 +93,12 @@ use super::buffer::NodeRef; use super::ts_estree::AstNode; use super::ts_estree::TsEsTreeBuilder; use super::ts_estree::TsKeywordKind; +use crate::util::text_encoding::Utf16Map; -pub fn serialize_swc_to_buffer(parsed_source: &ParsedSource) -> Vec { +pub fn serialize_swc_to_buffer( + parsed_source: &ParsedSource, + utf16_map: &Utf16Map, +) -> Vec { let mut ctx = TsEsTreeBuilder::new(); let program = &parsed_source.program(); @@ -125,6 +129,7 @@ pub fn serialize_swc_to_buffer(parsed_source: &ParsedSource) -> Vec { } } + ctx.map_utf8_spans_to_utf16(utf16_map); ctx.serialize() } diff --git a/cli/tools/lint/ast_buffer/ts_estree.rs b/cli/tools/lint/ast_buffer/ts_estree.rs index 340f9f3225510f..f5e89a2bede37d 100644 --- a/cli/tools/lint/ast_buffer/ts_estree.rs +++ b/cli/tools/lint/ast_buffer/ts_estree.rs @@ -10,6 +10,7 @@ use deno_ast::view::TruePlusMinus; use super::buffer::AstBufSerializer; use super::buffer::NodeRef; use super::buffer::SerializeCtx; +use crate::util::text_encoding::Utf16Map; #[derive(Debug, Clone, PartialEq)] pub enum AstNode { @@ -488,6 +489,10 @@ impl TsEsTreeBuilder { } } + pub fn map_utf8_spans_to_utf16(&mut self, map: &Utf16Map) { + self.ctx.map_utf8_spans_to_utf16(map); + } + pub fn write_program( &mut self, span: &Span, diff --git a/cli/tools/lint/linter.rs b/cli/tools/lint/linter.rs index 5d6f8452744847..1b7b999594a13e 100644 --- a/cli/tools/lint/linter.rs +++ b/cli/tools/lint/linter.rs @@ -1,32 +1,45 @@ // Copyright 2018-2025 the Deno authors. MIT license. +use std::borrow::Cow; use std::collections::HashSet; use std::path::Path; +use std::path::PathBuf; +use std::sync::Arc; +use ::tokio_util::sync::CancellationToken; use deno_ast::MediaType; use deno_ast::ModuleSpecifier; use deno_ast::ParsedSource; use deno_ast::SourceTextInfo; use deno_core::anyhow::Context; use deno_core::error::AnyError; +use deno_core::futures::FutureExt as _; +use deno_core::parking_lot::Mutex; use deno_graph::ModuleGraph; use deno_lint::diagnostic::LintDiagnostic; +use deno_lint::linter::ExternalLinterCb; +use deno_lint::linter::ExternalLinterResult; use deno_lint::linter::LintConfig as DenoLintConfig; use deno_lint::linter::LintFileOptions; use deno_lint::linter::Linter as DenoLintLinter; use deno_lint::linter::LinterOptions; use deno_path_util::fs::atomic_write_file_with_retries; +use deno_runtime::tokio_util; +use super::plugins; +use super::plugins::PluginHostProxy; use super::rules::FileOrPackageLintRule; use super::rules::PackageLintRule; use super::ConfiguredRules; use crate::sys::CliSys; use crate::util::fs::specifier_from_file_path; +use crate::util::text_encoding::Utf16Map; pub struct CliLinterOptions { pub configured_rules: ConfiguredRules, pub fix: bool, pub deno_lint_config: DenoLintConfig, + pub maybe_plugin_runner: Option>, } #[derive(Debug)] @@ -35,6 +48,7 @@ pub struct CliLinter { package_rules: Vec>, linter: DenoLintLinter, deno_lint_config: DenoLintConfig, + maybe_plugin_runner: Option>, } impl CliLinter { @@ -62,6 +76,7 @@ impl CliLinter { custom_ignore_diagnostic_directive: None, }), deno_lint_config: options.deno_lint_config, + maybe_plugin_runner: options.maybe_plugin_runner, } } @@ -84,10 +99,22 @@ impl CliLinter { pub fn lint_with_ast( &self, parsed_source: &ParsedSource, - ) -> Vec { - self - .linter - .lint_with_ast(parsed_source, self.deno_lint_config.clone()) + token: CancellationToken, + ) -> Result, AnyError> { + let external_linter_container = ExternalLinterContainer::new( + self.maybe_plugin_runner.clone(), + Some(token), + ); + + let d = self.linter.lint_with_ast( + parsed_source, + self.deno_lint_config.clone(), + external_linter_container.get_callback(), + ); + if let Some(err) = external_linter_container.take_error() { + return Err(err); + } + Ok(d) } pub fn lint_file( @@ -105,18 +132,34 @@ impl CliLinter { MediaType::from_specifier(&specifier) }; + let external_linter_container = + ExternalLinterContainer::new(self.maybe_plugin_runner.clone(), None); + if self.fix { - self.lint_file_and_fix(&specifier, media_type, source_code, file_path) + self.lint_file_and_fix( + &specifier, + media_type, + source_code, + file_path, + external_linter_container, + ) } else { - self + let (source, diagnostics) = self .linter .lint_file(LintFileOptions { specifier, media_type, source_code, config: self.deno_lint_config.clone(), + external_linter: external_linter_container.get_callback(), }) - .map_err(AnyError::from) + .map_err(AnyError::from)?; + + if let Some(err) = external_linter_container.take_error() { + return Err(err); + } + + Ok((source, diagnostics)) } } @@ -126,6 +169,7 @@ impl CliLinter { media_type: MediaType, source_code: String, file_path: &Path, + external_linter_container: ExternalLinterContainer, ) -> Result<(ParsedSource, Vec), deno_core::anyhow::Error> { // initial lint let (source, diagnostics) = self.linter.lint_file(LintFileOptions { @@ -133,8 +177,13 @@ impl CliLinter { media_type, source_code, config: self.deno_lint_config.clone(), + external_linter: external_linter_container.get_callback(), })?; + if let Some(err) = external_linter_container.take_error() { + return Err(err); + } + // Try applying fixes repeatedly until the file has none left or // a maximum number of iterations is reached. This is necessary // because lint fixes may overlap and so we can't always apply @@ -148,8 +197,9 @@ impl CliLinter { media_type, &self.linter, self.deno_lint_config.clone(), - source.text_info_lazy(), + &source, &diagnostics, + &external_linter_container, )?; match change { Some(change) => { @@ -165,7 +215,7 @@ impl CliLinter { log::warn!( concat!( "Reached maximum number of fix iterations for '{}'. There's ", - "probably a bug in Deno. Please fix this file manually.", + "probably a bug in the lint rule. Please fix this file manually.", ), specifier, ); @@ -193,23 +243,81 @@ fn apply_lint_fixes_and_relint( media_type: MediaType, linter: &DenoLintLinter, config: DenoLintConfig, - text_info: &SourceTextInfo, + original_source: &ParsedSource, diagnostics: &[LintDiagnostic], + external_linter_container: &ExternalLinterContainer, ) -> Result)>, AnyError> { + let text_info = original_source.text_info_lazy(); let Some(new_text) = apply_lint_fixes(text_info, diagnostics) else { return Ok(None); }; - linter - .lint_file(LintFileOptions { + + let lint_with_text = |new_text: String| { + let (source, diagnostics) = linter.lint_file(LintFileOptions { specifier: specifier.clone(), source_code: new_text, media_type, - config, - }) - .map(Some) - .context( - "An applied lint fix caused a syntax error. Please report this bug.", - ) + config: config.clone(), + external_linter: external_linter_container.get_callback(), + })?; + let mut new_diagnostics = source.diagnostics().clone(); + new_diagnostics.retain(|d| !original_source.diagnostics().contains(d)); + if let Some(diagnostic) = new_diagnostics.pop() { + return Err(AnyError::from(diagnostic)); + } + Ok((source, diagnostics)) + }; + + let (source, diagnostics) = match lint_with_text(new_text) { + Ok(result) => result, + Err(err) => { + let utf16_map = Utf16Map::new(text_info.text_str()); + // figure out which diagnostic caused a syntax error + let mut diagnostics = diagnostics.to_vec(); + while let Some(last_diagnostic) = diagnostics.pop() { + let Some(lint_fix) = last_diagnostic.details.fixes.first() else { + continue; + }; + let success = match apply_lint_fixes(text_info, &diagnostics) { + Some(new_text) => lint_with_text(new_text).is_ok(), + None => true, + }; + if success { + let mut changes_text = String::new(); + for change in &lint_fix.changes { + let utf8_start = + (change.range.start - text_info.range().start) as u32; + let utf8_end = (change.range.end - text_info.range().start) as u32; + let utf16_start = utf16_map + .utf8_to_utf16_offset(utf8_start.into()) + .unwrap_or(utf8_start.into()); + let utf16_end = utf16_map + .utf8_to_utf16_offset(utf8_end.into()) + .unwrap_or(utf8_end.into()); + changes_text.push_str(&format!( + "Range: [{}, {}]\n", + u32::from(utf16_start), + u32::from(utf16_end) + )); + changes_text.push_str(&format!("Text: {:?}\n\n", &change.new_text)); + } + return Err(err).context(format!( + "The '{}' rule caused a syntax error applying '{}'.\n\n{}", + last_diagnostic.details.code, lint_fix.description, changes_text + )); + } + } + return Err(err).context( + "A lint fix caused a syntax error. This is a bug in a lint rule.", + ); + } + }; + + if let Some(err) = external_linter_container.take_error() { + return Err(err); + } + + Ok(Some((source, diagnostics))) } fn apply_lint_fixes( @@ -258,3 +366,94 @@ fn apply_lint_fixes( deno_ast::apply_text_changes(text_info.text_str(), quick_fixes); Some(new_text) } + +fn run_plugins( + plugin_runner: Arc, + parsed_source: ParsedSource, + file_path: PathBuf, + maybe_token: Option, +) -> Result { + let source_text_info = parsed_source.text_info_lazy().clone(); + let plugin_info = plugin_runner + .get_plugin_rules() + .into_iter() + .map(Cow::from) + .collect(); + + let fut = async move { + let utf16_map = Utf16Map::new(parsed_source.text().as_ref()); + let serialized_ast = + plugin_runner.serialize_ast(&parsed_source, &utf16_map)?; + + plugins::run_rules_for_ast( + &plugin_runner, + &file_path, + serialized_ast, + source_text_info, + utf16_map, + maybe_token, + ) + .await + } + .boxed_local(); + + let plugin_diagnostics = tokio_util::create_and_run_current_thread(fut)?; + + Ok(ExternalLinterResult { + diagnostics: plugin_diagnostics, + rules: plugin_info, + }) +} + +struct ExternalLinterContainer { + cb: Option, + error: Option>>>, +} + +impl ExternalLinterContainer { + pub fn new( + maybe_plugin_runner: Option>, + maybe_token: Option, + ) -> Self { + let mut s = Self { + cb: None, + error: None, + }; + if let Some(plugin_runner) = maybe_plugin_runner { + s.error = Some(Arc::new(Mutex::new(None))); + let error_ = s.error.clone(); + let cb = Arc::new(move |parsed_source: ParsedSource| { + let token_ = maybe_token.clone(); + let file_path = + match deno_path_util::url_to_file_path(parsed_source.specifier()) { + Ok(path) => path, + Err(err) => { + *error_.as_ref().unwrap().lock() = Some(err.into()); + return None; + } + }; + + let r = + run_plugins(plugin_runner.clone(), parsed_source, file_path, token_); + + match r { + Ok(d) => Some(d), + Err(err) => { + *error_.as_ref().unwrap().lock() = Some(err); + None + } + } + }); + s.cb = Some(cb); + } + s + } + + pub fn get_callback(&self) -> Option { + self.cb.clone() + } + + pub fn take_error(&self) -> Option { + self.error.as_ref().and_then(|e| e.lock().take()) + } +} diff --git a/cli/tools/lint/mod.rs b/cli/tools/lint/mod.rs index 49a5c6896bb081..74c46d4c189112 100644 --- a/cli/tools/lint/mod.rs +++ b/cli/tools/lint/mod.rs @@ -26,6 +26,7 @@ use deno_core::serde_json; use deno_core::unsync::future::LocalFutureExt; use deno_core::unsync::future::SharedLocal; use deno_graph::ModuleGraph; +use deno_lib::util::hash::FastInsecureHasher; use deno_lint::diagnostic::LintDiagnostic; use log::debug; use reporters::create_reporter; @@ -55,6 +56,7 @@ use crate::util::sync::AtomicFlag; mod ast_buffer; mod linter; +mod plugins; mod reporters; mod rules; @@ -62,6 +64,8 @@ mod rules; pub use ast_buffer::serialize_ast_to_buffer; pub use linter::CliLinter; pub use linter::CliLinterOptions; +pub use plugins::create_runner_and_load_plugins; +pub use plugins::PluginLogger; pub use rules::collect_no_slow_type_diagnostics; pub use rules::ConfiguredRules; pub use rules::LintRuleProvider; @@ -282,18 +286,52 @@ impl WorkspaceLinter { ) -> Result<(), AnyError> { self.file_count += paths.len(); + let exclude = lint_options.rules.exclude.clone(); + + let plugin_specifiers = lint_options.plugins.clone(); let lint_rules = self.lint_rule_provider.resolve_lint_rules_err_empty( lint_options.rules, member_dir.maybe_deno_json().map(|c| c.as_ref()), )?; - let maybe_incremental_cache = - lint_rules.incremental_cache_state().map(|state| { - Arc::new(IncrementalCache::new( - self.caches.lint_incremental_cache_db(), - CacheDBHash::from_hashable(&state), - &paths, - )) - }); + let mut maybe_incremental_cache = None; + + // TODO(bartlomieju): how do we decide if plugins support incremental cache? + if lint_rules.supports_incremental_cache() { + let mut hasher = FastInsecureHasher::new_deno_versioned(); + hasher.write_hashable(lint_rules.incremental_cache_state()); + if !plugin_specifiers.is_empty() { + hasher.write_hashable(&plugin_specifiers); + } + let state_hash = hasher.finish(); + + maybe_incremental_cache = Some(Arc::new(IncrementalCache::new( + self.caches.lint_incremental_cache_db(), + CacheDBHash::new(state_hash), + &paths, + ))); + } + + #[allow(clippy::print_stdout)] + #[allow(clippy::print_stderr)] + fn logger_printer(msg: &str, is_err: bool) { + if is_err { + eprint!("{}", msg); + } else { + print!("{}", msg); + } + } + + let mut plugin_runner = None; + if !plugin_specifiers.is_empty() { + let logger = plugins::PluginLogger::new(logger_printer); + let runner = plugins::create_runner_and_load_plugins( + plugin_specifiers, + logger, + exclude, + ) + .await?; + plugin_runner = Some(Arc::new(runner)); + } let linter = Arc::new(CliLinter::new(CliLinterOptions { configured_rules: lint_rules, @@ -301,6 +339,7 @@ impl WorkspaceLinter { deno_lint_config: self .tsconfig_resolver .deno_lint_config(member_dir.dir_url())?, + maybe_plugin_runner: plugin_runner, })); let has_error = self.has_error.clone(); @@ -543,7 +582,8 @@ fn lint_stdin( .to_lint_config(FilePatterns::new_with_base(start_dir.dir_path()))?; let deno_lint_config = tsconfig_resolver.deno_lint_config(start_dir.dir_url())?; - let lint_options = LintOptions::resolve(lint_config, &lint_flags); + let lint_options = + LintOptions::resolve(start_dir.dir_path(), lint_config, &lint_flags)?; let configured_rules = lint_rule_provider.resolve_lint_rules_err_empty( lint_options.rules, start_dir.maybe_deno_json().map(|c| c.as_ref()), @@ -561,6 +601,7 @@ fn lint_stdin( fix: false, configured_rules, deno_lint_config, + maybe_plugin_runner: None, }); let r = linter @@ -624,13 +665,24 @@ mod tests { use super::*; + #[derive(Serialize, Deserialize)] + struct RulesPattern { + r#type: String, + pattern: String, + } + + #[derive(Serialize, Deserialize)] + struct RulesEnum { + r#enum: Vec, + } + #[derive(Serialize, Deserialize)] struct RulesSchema { #[serde(rename = "$schema")] schema: String, - #[serde(rename = "enum")] - rules: Vec, + #[serde(rename = "oneOf")] + one_of: (RulesPattern, RulesEnum), } fn get_all_rules() -> Vec { @@ -661,25 +713,25 @@ mod tests { const UPDATE_ENV_VAR_NAME: &str = "UPDATE_EXPECTED"; + let rules_list = schema.one_of.1.r#enum; + if std::env::var(UPDATE_ENV_VAR_NAME).ok().is_none() { assert_eq!( - schema.rules, all_rules, + rules_list, all_rules, "Lint rules schema file not up to date. Run again with {}=1 to update the expected output", UPDATE_ENV_VAR_NAME ); return; } + let new_schema = RulesSchema { + schema: schema.schema, + one_of: (schema.one_of.0, RulesEnum { r#enum: all_rules }), + }; + std::fs::write( &rules_schema_path, - format!( - "{}\n", - serde_json::to_string_pretty(&RulesSchema { - schema: schema.schema, - rules: all_rules, - }) - .unwrap(), - ), + format!("{}\n", serde_json::to_string_pretty(&new_schema).unwrap(),), ) .unwrap(); } diff --git a/cli/tools/lint/plugins.rs b/cli/tools/lint/plugins.rs new file mode 100644 index 00000000000000..3d7acf4f242f04 --- /dev/null +++ b/cli/tools/lint/plugins.rs @@ -0,0 +1,543 @@ +// Copyright 2018-2025 the Deno authors. MIT license. + +use std::path::Path; +use std::path::PathBuf; +use std::rc::Rc; +use std::sync::Arc; + +use ::tokio_util::sync::CancellationToken; +use deno_ast::ModuleSpecifier; +use deno_ast::ParsedSource; +use deno_ast::SourceTextInfo; +use deno_core::anyhow::bail; +use deno_core::error::AnyError; +use deno_core::error::CoreError; +use deno_core::error::JsError; +use deno_core::futures::FutureExt; +use deno_core::parking_lot::Mutex; +use deno_core::resolve_url_or_path; +use deno_core::v8; +use deno_core::PollEventLoopOptions; +use deno_lint::diagnostic::LintDiagnostic; +use deno_runtime::deno_permissions::Permissions; +use deno_runtime::deno_permissions::PermissionsContainer; +use deno_runtime::tokio_util; +use deno_runtime::worker::MainWorker; +use deno_runtime::WorkerExecutionMode; +use tokio::sync::mpsc::channel; +use tokio::sync::mpsc::Receiver; +use tokio::sync::mpsc::Sender; + +use crate::args::DenoSubcommand; +use crate::args::Flags; +use crate::args::LintFlags; +use crate::factory::CliFactory; +use crate::ops::lint::LintPluginContainer; +use crate::tools::lint::serialize_ast_to_buffer; +use crate::util::text_encoding::Utf16Map; + +#[derive(Debug)] +pub enum PluginHostRequest { + LoadPlugins { + specifiers: Vec, + exclude_rules: Option>, + }, + Run { + serialized_ast: Vec, + file_path: PathBuf, + source_text_info: SourceTextInfo, + utf16_map: Utf16Map, + maybe_token: Option, + }, +} + +pub enum PluginHostResponse { + // TODO: write to structs + LoadPlugin(Result, AnyError>), + Run(Result, AnyError>), +} + +impl std::fmt::Debug for PluginHostResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::LoadPlugin(_arg0) => f.debug_tuple("LoadPlugin").finish(), + Self::Run(_arg0) => f.debug_tuple("Run").finish(), + } + } +} + +#[derive(Clone, Debug)] +pub struct PluginLogger { + print: fn(&str, bool), +} + +impl PluginLogger { + pub fn new(print: fn(&str, bool)) -> Self { + Self { print } + } + + pub fn log(&self, msg: &str) { + (self.print)(msg, false); + } + + pub fn error(&self, msg: &str) { + (self.print)(msg, true); + } +} + +macro_rules! v8_static_strings { + ($($ident:ident = $str:literal),* $(,)?) => { + $( + pub static $ident: deno_core::FastStaticString = deno_core::ascii_str!($str); + )* + }; +} + +v8_static_strings! { + DEFAULT = "default", + INSTALL_PLUGINS = "installPlugins", + RUN_PLUGINS_FOR_FILE = "runPluginsForFile", +} + +#[derive(Debug)] +pub struct PluginHostProxy { + tx: Sender, + rx: Arc>>, + pub(crate) plugin_info: Arc>>, + #[allow(unused)] + join_handle: std::thread::JoinHandle>, +} + +impl PluginHostProxy { + pub fn get_plugin_rules(&self) -> Vec { + let infos = self.plugin_info.lock(); + + let mut all_names = vec![]; + + for info in infos.iter() { + all_names.extend_from_slice(&info.get_rules()); + } + + all_names + } +} + +pub struct PluginHost { + worker: MainWorker, + install_plugins_fn: Rc>, + run_plugins_for_file_fn: Rc>, + tx: Sender, + rx: Receiver, +} + +async fn create_plugin_runner_inner( + logger: PluginLogger, + rx_req: Receiver, + tx_res: Sender, +) -> Result { + let flags = Flags { + subcommand: DenoSubcommand::Lint(LintFlags::default()), + ..Default::default() + }; + let flags = Arc::new(flags); + let factory = CliFactory::from_flags(flags.clone()); + let cli_options = factory.cli_options()?; + let main_module = + resolve_url_or_path("./$deno$lint.mts", cli_options.initial_cwd()).unwrap(); + let perm_parser = factory.permission_desc_parser()?; + let permissions = Permissions::from_options( + perm_parser.as_ref(), + &cli_options.permissions_options(), + )?; + let permissions = PermissionsContainer::new(perm_parser.clone(), permissions); + // let npm_resolver = factory.npm_resolver().await?.clone(); + // let resolver = factory.resolver().await?.clone(); + let worker_factory = factory.create_cli_main_worker_factory().await?; + + let worker = worker_factory + .create_custom_worker( + // TODO(bartlomieju): add "lint" execution mode + WorkerExecutionMode::Run, + main_module.clone(), + permissions, + vec![crate::ops::lint::deno_lint_ext::init_ops(logger.clone())], + Default::default(), + ) + .await?; + + let mut worker = worker.into_main_worker(); + let runtime = &mut worker.js_runtime; + + let obj = runtime.execute_script("lint.js", "Deno[Deno.internal]")?; + + log::debug!("Lint plugins loaded, capturing default exports"); + let (install_plugins_fn, run_plugins_for_file_fn) = { + let scope = &mut runtime.handle_scope(); + let module_exports: v8::Local = + v8::Local::new(scope, obj).try_into().unwrap(); + + let install_plugins_fn_name = INSTALL_PLUGINS.v8_string(scope).unwrap(); + let install_plugins_fn_val = module_exports + .get(scope, install_plugins_fn_name.into()) + .unwrap(); + let install_plugins_fn: v8::Local = + install_plugins_fn_val.try_into().unwrap(); + + let run_plugins_for_file_fn_name = + RUN_PLUGINS_FOR_FILE.v8_string(scope).unwrap(); + let run_plugins_for_file_fn_val = module_exports + .get(scope, run_plugins_for_file_fn_name.into()) + .unwrap(); + let run_plugins_for_file_fn: v8::Local = + run_plugins_for_file_fn_val.try_into().unwrap(); + + ( + Rc::new(v8::Global::new(scope, install_plugins_fn)), + Rc::new(v8::Global::new(scope, run_plugins_for_file_fn)), + ) + }; + + Ok(PluginHost { + worker, + install_plugins_fn, + run_plugins_for_file_fn, + tx: tx_res, + rx: rx_req, + }) +} + +#[derive(Debug, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PluginInfo { + pub name: String, + pub rule_names: Vec, +} + +impl PluginInfo { + pub fn get_rules(&self) -> Vec { + let mut rules = Vec::with_capacity(self.rule_names.len()); + + for rule_name in &self.rule_names { + rules.push(format!("{}/{}", self.name, rule_name)); + } + + rules + } +} + +impl PluginHost { + fn create(logger: PluginLogger) -> Result { + let (tx_req, rx_req) = channel(10); + let (tx_res, rx_res) = channel(10); + + let logger_ = logger.clone(); + let join_handle = std::thread::spawn(move || { + let logger = logger_; + log::debug!("Lint PluginHost thread spawned"); + let start = std::time::Instant::now(); + let fut = async move { + let runner = + create_plugin_runner_inner(logger.clone(), rx_req, tx_res).await?; + log::debug!("Lint PlugibnHost running loop"); + runner.run_loop().await?; + log::debug!( + "Lint PluginHost thread finished, took {:?}", + std::time::Instant::now() - start + ); + Ok(()) + } + .boxed_local(); + tokio_util::create_and_run_current_thread(fut) + }); + + let proxy = PluginHostProxy { + tx: tx_req, + rx: Arc::new(tokio::sync::Mutex::new(rx_res)), + plugin_info: Arc::new(Mutex::new(vec![])), + join_handle, + }; + + Ok(proxy) + } + + async fn run_loop(mut self) -> Result<(), AnyError> { + log::debug!("Lint PluginHost is waiting for message"); + while let Some(req) = self.rx.recv().await { + log::debug!("Lint PluginHost has received a message"); + match req { + PluginHostRequest::LoadPlugins { + specifiers, + exclude_rules, + } => { + let r = self.load_plugins(specifiers, exclude_rules).await; + let _ = self.tx.send(PluginHostResponse::LoadPlugin(r)).await; + } + PluginHostRequest::Run { + serialized_ast, + file_path, + source_text_info, + utf16_map, + maybe_token, + } => { + let start = std::time::Instant::now(); + let r = match self.run_plugins( + &file_path, + serialized_ast, + source_text_info, + utf16_map, + maybe_token, + ) { + Ok(()) => Ok(self.take_diagnostics()), + Err(err) => Err(err), + }; + log::debug!( + "Running plugins lint rules took {:?}", + std::time::Instant::now() - start + ); + let _ = self.tx.send(PluginHostResponse::Run(r)).await; + } + } + } + log::debug!("Lint PluginHost run loop finished"); + Ok(()) + } + + fn take_diagnostics(&mut self) -> Vec { + let op_state = self.worker.js_runtime.op_state(); + let mut state = op_state.borrow_mut(); + let container = state.borrow_mut::(); + std::mem::take(&mut container.diagnostics) + } + + fn run_plugins( + &mut self, + file_path: &Path, + serialized_ast: Vec, + source_text_info: SourceTextInfo, + utf16_map: Utf16Map, + maybe_token: Option, + ) -> Result<(), AnyError> { + { + let state = self.worker.js_runtime.op_state(); + let mut state = state.borrow_mut(); + let container = state.borrow_mut::(); + container.set_info_for_file( + ModuleSpecifier::from_file_path(file_path).unwrap(), + source_text_info, + utf16_map, + ); + container.set_cancellation_token(maybe_token); + } + + let scope = &mut self.worker.js_runtime.handle_scope(); + let file_name_v8: v8::Local = + v8::String::new(scope, &file_path.display().to_string()) + .unwrap() + .into(); + + let store = v8::ArrayBuffer::new_backing_store_from_vec(serialized_ast); + let ast_buf = + v8::ArrayBuffer::with_backing_store(scope, &store.make_shared()); + let ast_bin_v8: v8::Local = + v8::Uint8Array::new(scope, ast_buf, 0, ast_buf.byte_length()) + .unwrap() + .into(); + let run_plugins_for_file = + v8::Local::new(scope, &*self.run_plugins_for_file_fn); + let undefined = v8::undefined(scope); + + let mut tc_scope = v8::TryCatch::new(scope); + let _run_plugins_result = run_plugins_for_file.call( + &mut tc_scope, + undefined.into(), + &[file_name_v8, ast_bin_v8], + ); + + if let Some(exception) = tc_scope.exception() { + let error = JsError::from_v8_exception(&mut tc_scope, exception); + let core_err = CoreError::Js(error); + return Err(core_err.into()); + } + drop(tc_scope); + Ok(()) + } + + async fn load_plugins( + &mut self, + plugin_specifiers: Vec, + exclude: Option>, + ) -> Result, AnyError> { + let mut load_futures = Vec::with_capacity(plugin_specifiers.len()); + for specifier in plugin_specifiers { + let mod_id = self + .worker + .js_runtime + .load_side_es_module(&specifier) + .await?; + let mod_future = + self.worker.js_runtime.mod_evaluate(mod_id).boxed_local(); + load_futures.push((mod_future, mod_id)); + } + + self + .worker + .js_runtime + .run_event_loop(PollEventLoopOptions::default()) + .await?; + + let mut plugin_handles = Vec::with_capacity(load_futures.len()); + + for (fut, mod_id) in load_futures { + fut.await?; + let module = self.worker.js_runtime.get_module_namespace(mod_id).unwrap(); + let scope = &mut self.worker.js_runtime.handle_scope(); + let module_local = v8::Local::new(scope, module); + let default_export_str = DEFAULT.v8_string(scope).unwrap(); + let default_export = + module_local.get(scope, default_export_str.into()).unwrap(); + let default_export_global = v8::Global::new(scope, default_export); + plugin_handles.push(default_export_global); + } + + let scope = &mut self.worker.js_runtime.handle_scope(); + let install_plugins_local = + v8::Local::new(scope, &*self.install_plugins_fn.clone()); + let exclude_v8: v8::Local = + exclude.map_or(v8::null(scope).into(), |v| { + let elems = v + .iter() + .map(|item| v8::String::new(scope, item).unwrap().into()) + .collect::>(); + + v8::Array::new_with_elements(scope, elems.as_slice()).into() + }); + + let undefined = v8::undefined(scope); + + let local_handles = { + let arr = v8::Array::new(scope, plugin_handles.len().try_into().unwrap()); + for (idx, plugin_handle) in plugin_handles.into_iter().enumerate() { + let handle = v8::Local::new(scope, plugin_handle); + arr + .set_index(scope, idx.try_into().unwrap(), handle) + .unwrap(); + } + arr + }; + let args = &[local_handles.into(), exclude_v8]; + + log::debug!("Installing lint plugins..."); + + let mut tc_scope = v8::TryCatch::new(scope); + let plugins_info_result = + install_plugins_local.call(&mut tc_scope, undefined.into(), args); + if let Some(exception) = tc_scope.exception() { + let error = JsError::from_v8_exception(&mut tc_scope, exception); + return Err(error.into()); + } + drop(tc_scope); + let plugins_info = plugins_info_result.unwrap(); + let infos: Vec = + deno_core::serde_v8::from_v8(scope, plugins_info)?; + log::debug!("Plugins installed: {}", infos.len()); + + Ok(infos) + } +} + +impl PluginHostProxy { + pub async fn load_plugins( + &self, + specifiers: Vec, + exclude_rules: Option>, + ) -> Result<(), AnyError> { + self + .tx + .send(PluginHostRequest::LoadPlugins { + specifiers, + exclude_rules, + }) + .await?; + let mut rx = self.rx.lock().await; + + if let Some(val) = rx.recv().await { + let PluginHostResponse::LoadPlugin(result) = val else { + unreachable!() + }; + let infos = result?; + *self.plugin_info.lock() = infos; + return Ok(()); + } + bail!("Plugin host has closed") + } + + pub async fn run_rules( + &self, + specifier: &Path, + serialized_ast: Vec, + source_text_info: SourceTextInfo, + utf16_map: Utf16Map, + maybe_token: Option, + ) -> Result, AnyError> { + self + .tx + .send(PluginHostRequest::Run { + serialized_ast, + file_path: specifier.to_path_buf(), + source_text_info, + utf16_map, + maybe_token, + }) + .await?; + let mut rx = self.rx.lock().await; + + if let Some(PluginHostResponse::Run(diagnostics_result)) = rx.recv().await { + return diagnostics_result; + } + bail!("Plugin host has closed") + } + + pub fn serialize_ast( + &self, + parsed_source: &ParsedSource, + utf16_map: &Utf16Map, + ) -> Result, AnyError> { + let start = std::time::Instant::now(); + let r = serialize_ast_to_buffer(parsed_source, utf16_map); + log::debug!( + "Serializing an AST took {:?}", + std::time::Instant::now() - start + ); + Ok(r) + } +} + +pub async fn create_runner_and_load_plugins( + plugin_specifiers: Vec, + logger: PluginLogger, + exclude: Option>, +) -> Result { + let host_proxy = PluginHost::create(logger)?; + host_proxy.load_plugins(plugin_specifiers, exclude).await?; + Ok(host_proxy) +} + +pub async fn run_rules_for_ast( + host_proxy: &PluginHostProxy, + specifier: &Path, + serialized_ast: Vec, + source_text_info: SourceTextInfo, + utf16_map: Utf16Map, + maybe_token: Option, +) -> Result, AnyError> { + let d = host_proxy + .run_rules( + specifier, + serialized_ast, + source_text_info, + utf16_map, + maybe_token, + ) + .await?; + Ok(d) +} diff --git a/cli/tools/lint/reporters.rs b/cli/tools/lint/reporters.rs index 24e04e840f7dcc..2aa50b6de81262 100644 --- a/cli/tools/lint/reporters.rs +++ b/cli/tools/lint/reporters.rs @@ -2,9 +2,11 @@ use deno_ast::diagnostics::Diagnostic; use deno_core::error::AnyError; +use deno_core::error::CoreError; use deno_core::serde_json; use deno_lint::diagnostic::LintDiagnostic; use deno_runtime::colors; +use deno_runtime::fmt_errors::format_js_error; use log::info; use serde::Serialize; @@ -53,7 +55,19 @@ impl LintReporter for PrettyLintReporter { fn visit_error(&mut self, file_path: &str, err: &AnyError) { log::error!("Error linting: {file_path}"); - log::error!(" {err}"); + let text = + if let Some(CoreError::Js(js_error)) = err.downcast_ref::() { + format_js_error(js_error) + } else { + format!("{err:#}") + }; + for line in text.split('\n') { + if line.is_empty() { + log::error!(""); + } else { + log::error!(" {}", line); + } + } } fn close(&mut self, check_count: usize) { diff --git a/cli/tools/lint/rules/mod.rs b/cli/tools/lint/rules/mod.rs index f8c65428aca6ad..9f2cee24fa9b21 100644 --- a/cli/tools/lint/rules/mod.rs +++ b/cli/tools/lint/rules/mod.rs @@ -122,16 +122,16 @@ impl CliLintRule { #[derive(Debug)] pub struct ConfiguredRules { - pub all_rule_codes: HashSet<&'static str>, + pub all_rule_codes: HashSet>, pub rules: Vec, } impl ConfiguredRules { - pub fn incremental_cache_state(&self) -> Option { - if self.rules.iter().any(|r| !r.supports_incremental_cache()) { - return None; - } + pub fn supports_incremental_cache(&self) -> bool { + self.rules.iter().all(|r| r.supports_incremental_cache()) + } + pub fn incremental_cache_state(&self) -> impl std::hash::Hash { // use a hash of the rule names in order to bust the cache let mut codes = self.rules.iter().map(|r| r.code()).collect::>(); // ensure this is stable by sorting it @@ -195,7 +195,7 @@ impl LintRuleProvider { let all_rules = self.all_rules(); let mut all_rule_names = HashSet::with_capacity(all_rules.len()); for rule in &all_rules { - all_rule_names.insert(rule.code()); + all_rule_names.insert(rule.code().into()); } let rules = filtered_rules( all_rules.into_iter(), diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index cb49a9de95817e..697f99aa175c3f 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -626,7 +626,7 @@ async fn configure_main_worker( permissions_container, vec![ ops::testing::deno_test::init_ops(worker_sender.sender), - ops::lint::deno_lint::init_ops(), + ops::lint::deno_lint_ext_for_test::init_ops(), ], Stdio { stdin: StdioPipe::inherit(), diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 6c901b864c79fb..8113f75809db0d 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -1344,6 +1344,139 @@ declare namespace Deno { export {}; // only export exports } + /** + * @category Linter + * @experimental + */ + export namespace lint { + /** + * @category Linter + * @experimental + */ + export type Range = [number, number]; + + /** + * @category Linter + * @experimental + */ + export interface Node { + type: string; + range: Range; + [key: string]: unknown; + } + + /** + * @category Linter + * @experimental + */ + export interface FixData { + range: Range; + text?: string; + } + + /** + * @category Linter + * @experimental + */ + export interface Fixer { + insertTextAfter(node: Node, text: string): FixData; + insertTextAfterRange(range: Range, text: string): FixData; + insertTextBefore(node: Node, text: string): FixData; + insertTextBeforeRange(range: Range, text: string): FixData; + remove(node: Node): FixData; + removeRange(range: Range): FixData; + replaceText(node: Node, text: string): FixData; + replaceTextRange(range: Range, text: string): FixData; + } + + /** + * @category Linter + * @experimental + */ + export interface ReportData { + node?: Node; + range?: Range; + message: string; + hint?: string; + fix?(fixer: Fixer): FixData; + } + + /** + * @category Linter + * @experimental + */ + export interface RuleContext { + id: string; + report(data: ReportData): void; + } + + /** + * @category Linter + * @experimental + */ + export interface Rule { + create(ctx: RuleContext): Record void>; + destroy?(ctx: RuleContext): void; + } + + /** + * In your plugins file do something like + * + * ```ts + * export default { + * name: "my-plugin", + * rules: { + * "no-foo": { + * create(ctx) { + * return { + * VariableDeclaration(node) {} + * } + * } + * } + * } + * } satisfies Deno.lint.Plugin + * ``` + * @category Linter + * @experimental + */ + export interface Plugin { + name: string; + rules: Record; + } + + /** + * @category Linter + * @experimental + */ + export interface Fix { + range: Range; + text?: string; + } + + /** + * @category Linter + * @experimental + */ + export interface Diagnostic { + id: string; + message: string; + hint?: string; + range: Range; + fix?: Fix; + } + + /** + * This API is a noop in `deno run`... + * @category Linter + * @experimental + */ + export function runPlugin( + plugin: Plugin, + fileName: string, + source: string, + ): Diagnostic[]; + } + export {}; // only export exports } diff --git a/cli/util/text_encoding.rs b/cli/util/text_encoding.rs index 4449202384e6a3..3a8044e13bde36 100644 --- a/cli/util/text_encoding.rs +++ b/cli/util/text_encoding.rs @@ -230,6 +230,52 @@ impl Utf16Map { column_index: col.into(), } } + + /// Convert a UTF-16 byte offset to UTF-8 byte offset + pub fn utf16_to_utf8_offset( + &self, + utf16_offset: TextSize, + ) -> Option { + if utf16_offset > self.text_content_length_utf16() { + return None; + } + let pos = self.position_utf16(utf16_offset); + let line_start_utf8 = self.utf8_offsets[pos.line_index]; + let col_utf8 = + self.utf16_to_utf8_col(pos.line_index as u32, pos.column_index as u32); + Some(line_start_utf8 + col_utf8) + } + + /// Convert a UTF-8 byte offset to UTF-16 byte offset + pub fn utf8_to_utf16_offset( + &self, + utf8_offset: TextSize, + ) -> Option { + if utf8_offset > *self.utf8_offsets.last()? { + return None; + } + let line = partition_point(&self.utf8_offsets, |&it| it <= utf8_offset) - 1; + let line_start_utf8 = self.utf8_offsets[line]; + let col_utf8 = utf8_offset - line_start_utf8; + let col_utf16 = self.utf8_to_utf16_col(line as u32, col_utf8); + Some(self.utf16_offsets[line] + TextSize::from(col_utf16)) + } + + fn utf8_to_utf16_col(&self, line: u32, col: TextSize) -> u32 { + let mut utf16_col = u32::from(col); + + if let Some(utf16_chars) = self.utf16_lines.get(&line) { + for c in utf16_chars { + if col > c.start { + utf16_col -= u32::from(c.len()) - c.len_utf16() as u32; + } else { + break; + } + } + } + + utf16_col + } } fn partition_point(slice: &[T], mut predicate: P) -> usize @@ -490,4 +536,47 @@ const C: char = \"メ メ\"; assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15)); } + + #[test] + fn test_offset_out_of_range() { + let text = "hello"; + let map = Utf16Map::new(text); + assert_eq!(map.utf8_to_utf16_offset(TextSize::from(10)), None); + assert_eq!(map.utf16_to_utf8_offset(TextSize::from(10)), None); + } + + #[test] + fn test_offset_basic_ascii() { + let text = "hello\nworld"; + let map = Utf16Map::new(text); + + let utf8_offset = TextSize::from(7); + let utf16_offset = map.utf8_to_utf16_offset(utf8_offset).unwrap(); + assert_eq!(utf16_offset, TextSize::from(7)); + + let result = map.utf16_to_utf8_offset(utf16_offset).unwrap(); + assert_eq!(result, utf8_offset); + } + + #[test] + fn test_offset_emoji() { + let text = "hi 👋\nbye"; + let map = Utf16Map::new(text); + + let utf8_offset = TextSize::from(3); + let utf16_offset = map.utf8_to_utf16_offset(utf8_offset).unwrap(); + assert_eq!(utf16_offset, TextSize::from(3)); + + let utf8_offset_after = TextSize::from(7); + let utf16_offset_after = + map.utf8_to_utf16_offset(utf8_offset_after).unwrap(); + assert_eq!(utf16_offset_after, TextSize::from(5)); + + for (utf8_offset, _) in text.char_indices() { + let utf8_offset = TextSize::from(utf8_offset as u32); + let utf16_offset = map.utf8_to_utf16_offset(utf8_offset).unwrap(); + let reverse_ut8_offset = map.utf16_to_utf8_offset(utf16_offset).unwrap(); + assert_eq!(reverse_ut8_offset, utf8_offset); + } + } } diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 190de549d1bca0..5c7fab6aecec38 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -94,6 +94,7 @@ import { bootstrap as bootstrapOtel } from "ext:deno_telemetry/telemetry.ts"; if (Symbol.metadata) { throw "V8 supports Symbol.metadata now, no need to shim it"; } + ObjectDefineProperties(Symbol, { dispose: { __proto__: null, @@ -533,7 +534,10 @@ const NOT_IMPORTED_OPS = [ "op_base64_encode", // Used in the lint API + "op_lint_report", + "op_lint_get_source", "op_lint_create_serialized_ast", + "op_is_cancelled", // Related to `Deno.test()` API "op_test_event_step_result_failed", @@ -575,11 +579,14 @@ const finalDenoNs = { internal: internalSymbol, [internalSymbol]: internals, ...denoNs, - // Deno.test and Deno.bench are noops here, but kept for compatibility; so - // that they don't cause errors when used outside of `deno test`/`deno bench` + // Deno.test, Deno.bench, Deno.lint are noops here, but kept for compatibility; so + // that they don't cause errors when used outside of `deno test`/`deno bench`/`deno lint` // contexts. test: () => {}, bench: () => {}, + lint: { + runPlugin: () => {}, + }, }; ObjectDefineProperties(finalDenoNs, { diff --git a/tests/integration/js_unit_tests.rs b/tests/integration/js_unit_tests.rs index 9ecec8b426c844..4a61361837b576 100644 --- a/tests/integration/js_unit_tests.rs +++ b/tests/integration/js_unit_tests.rs @@ -165,10 +165,14 @@ fn js_unit_test(test: String) { let mut deno = deno .arg("-A") - .arg(util::tests_path().join("unit").join(format!("{test}.ts"))) - .piped_output() - .spawn() - .expect("failed to spawn script"); + .arg(util::tests_path().join("unit").join(format!("{test}.ts"))); + + // update the snapshots if when `UPDATE=1` + if std::env::var_os("UPDATE") == Some("1".into()) { + deno = deno.arg("--").arg("--update"); + } + + let mut deno = deno.piped_output().spawn().expect("failed to spawn script"); let now = Instant::now(); let stdout = deno.stdout.take().unwrap(); diff --git a/tests/specs/lint/lint_plugin/__test__.jsonc b/tests/specs/lint/lint_plugin/__test__.jsonc new file mode 100644 index 00000000000000..228923b2ac8c0f --- /dev/null +++ b/tests/specs/lint/lint_plugin/__test__.jsonc @@ -0,0 +1,17 @@ +{ + "steps": [ + { + "args": "lint a.ts", + "output": "lint.out", + "exitCode": 1 + }, + { + "args": "lint -c deno_exclude.json a.ts", + "output": "lint_exclude.out" + }, + { + "args": "lint --fix a.ts", + "output": "lint_fixed.out" + } + ] +} diff --git a/tests/specs/lint/lint_plugin/a.ts b/tests/specs/lint/lint_plugin/a.ts new file mode 100644 index 00000000000000..0366a968a76b74 --- /dev/null +++ b/tests/specs/lint/lint_plugin/a.ts @@ -0,0 +1 @@ +const _a = "foo"; diff --git a/tests/specs/lint/lint_plugin/deno.json b/tests/specs/lint/lint_plugin/deno.json new file mode 100644 index 00000000000000..57b9dcb3647975 --- /dev/null +++ b/tests/specs/lint/lint_plugin/deno.json @@ -0,0 +1,5 @@ +{ + "lint": { + "plugins": ["./plugin.ts"] + } +} diff --git a/tests/specs/lint/lint_plugin/deno_exclude.json b/tests/specs/lint/lint_plugin/deno_exclude.json new file mode 100644 index 00000000000000..cce33a873602fe --- /dev/null +++ b/tests/specs/lint/lint_plugin/deno_exclude.json @@ -0,0 +1,10 @@ +{ + "lint": { + "plugins": ["./plugin.ts"], + "rules": { + "exclude": [ + "test-plugin/my-rule" + ] + } + } +} diff --git a/tests/specs/lint/lint_plugin/lint.out b/tests/specs/lint/lint_plugin/lint.out new file mode 100644 index 00000000000000..56166426a7fb2b --- /dev/null +++ b/tests/specs/lint/lint_plugin/lint.out @@ -0,0 +1,2 @@ +[WILDCARD]Found 1 problem (1 fixable via --fix) +Checked 1 file diff --git a/tests/specs/lint/lint_plugin/lint_exclude.out b/tests/specs/lint/lint_plugin/lint_exclude.out new file mode 100644 index 00000000000000..c05ac45a1e7e51 --- /dev/null +++ b/tests/specs/lint/lint_plugin/lint_exclude.out @@ -0,0 +1 @@ +Checked 1 file diff --git a/tests/specs/lint/lint_plugin/lint_fixed.out b/tests/specs/lint/lint_plugin/lint_fixed.out new file mode 100644 index 00000000000000..c05ac45a1e7e51 --- /dev/null +++ b/tests/specs/lint/lint_plugin/lint_fixed.out @@ -0,0 +1 @@ +Checked 1 file diff --git a/tests/specs/lint/lint_plugin/plugin.ts b/tests/specs/lint/lint_plugin/plugin.ts new file mode 100644 index 00000000000000..0a54d73212438a --- /dev/null +++ b/tests/specs/lint/lint_plugin/plugin.ts @@ -0,0 +1,22 @@ +export default { + name: "test-plugin", + rules: { + "my-rule": { + create(context) { + return { + Identifier(node) { + if (node.name === "_a") { + context.report({ + node, + message: "should be _b", + fix(fixer) { + return fixer.replaceText(node, "_b"); + }, + }); + } + }, + }; + }, + }, + }, +}; diff --git a/tests/specs/lint/lint_plugin_fix_error/__test__.jsonc b/tests/specs/lint/lint_plugin_fix_error/__test__.jsonc new file mode 100644 index 00000000000000..57da106ff691fa --- /dev/null +++ b/tests/specs/lint/lint_plugin_fix_error/__test__.jsonc @@ -0,0 +1,6 @@ +{ + "tempDir": true, + "args": "lint --fix", + "output": "fix.out", + "exitCode": 1 +} diff --git a/tests/specs/lint/lint_plugin_fix_error/deno.json b/tests/specs/lint/lint_plugin_fix_error/deno.json new file mode 100644 index 00000000000000..57b9dcb3647975 --- /dev/null +++ b/tests/specs/lint/lint_plugin_fix_error/deno.json @@ -0,0 +1,5 @@ +{ + "lint": { + "plugins": ["./plugin.ts"] + } +} diff --git a/tests/specs/lint/lint_plugin_fix_error/fix.out b/tests/specs/lint/lint_plugin_fix_error/fix.out new file mode 100644 index 00000000000000..aed9d4df8abcf4 --- /dev/null +++ b/tests/specs/lint/lint_plugin_fix_error/fix.out @@ -0,0 +1,11 @@ +Error linting: [WILDLINE]main.ts + The 'test-plugin/my-rule' rule caused a syntax error applying 'Fix this test-plugin/my-rule problem'. + + Range: [14, 18] + Text: "garbage test test" + + : Expected a semicolon at file:///[WILDLINE]/main.ts:1:23 + + const value = garbage test test; + ~~~~ +Checked 2 files diff --git a/tests/specs/lint/lint_plugin_fix_error/main.ts b/tests/specs/lint/lint_plugin_fix_error/main.ts new file mode 100644 index 00000000000000..5a277eecbbcf4f --- /dev/null +++ b/tests/specs/lint/lint_plugin_fix_error/main.ts @@ -0,0 +1,2 @@ +const value = "𝄞"; +console.log(value); diff --git a/tests/specs/lint/lint_plugin_fix_error/plugin.ts b/tests/specs/lint/lint_plugin_fix_error/plugin.ts new file mode 100644 index 00000000000000..3df9f8655d869d --- /dev/null +++ b/tests/specs/lint/lint_plugin_fix_error/plugin.ts @@ -0,0 +1,20 @@ +export default { + name: "test-plugin", + rules: { + "my-rule": { + create(context) { + return { + VariableDeclarator(node) { + context.report({ + node: node.init, + message: 'should be equal to string "1"', + fix(fixer) { + return fixer.replaceText(node.init, "garbage test test"); + }, + }); + }, + }; + }, + }, + }, +}; diff --git a/tests/specs/lint/lint_plugin_infinite_edits/__test__.jsonc b/tests/specs/lint/lint_plugin_infinite_edits/__test__.jsonc new file mode 100644 index 00000000000000..57da106ff691fa --- /dev/null +++ b/tests/specs/lint/lint_plugin_infinite_edits/__test__.jsonc @@ -0,0 +1,6 @@ +{ + "tempDir": true, + "args": "lint --fix", + "output": "fix.out", + "exitCode": 1 +} diff --git a/tests/specs/lint/lint_plugin_infinite_edits/deno.json b/tests/specs/lint/lint_plugin_infinite_edits/deno.json new file mode 100644 index 00000000000000..57b9dcb3647975 --- /dev/null +++ b/tests/specs/lint/lint_plugin_infinite_edits/deno.json @@ -0,0 +1,5 @@ +{ + "lint": { + "plugins": ["./plugin.ts"] + } +} diff --git a/tests/specs/lint/lint_plugin_infinite_edits/fix.out b/tests/specs/lint/lint_plugin_infinite_edits/fix.out new file mode 100644 index 00000000000000..4dde757781a509 --- /dev/null +++ b/tests/specs/lint/lint_plugin_infinite_edits/fix.out @@ -0,0 +1,12 @@ +Reached maximum number of fix iterations for 'file:///[WILDLINE]/main.ts'. There's probably a bug in the lint rule. Please fix this file manually. +error[test-plugin/my-rule]: should be equal to string "1" + --> [WILDLINE]main.ts:1:15 + | +1 | const value = [WILDLINE]; + | [WILDLINE] + + docs: https://docs.deno.com/lint/rules/test-plugin/my-rule + + +Found 1 problem (1 fixable via --fix) +Checked 2 files diff --git a/tests/specs/lint/lint_plugin_infinite_edits/main.ts b/tests/specs/lint/lint_plugin_infinite_edits/main.ts new file mode 100644 index 00000000000000..5a277eecbbcf4f --- /dev/null +++ b/tests/specs/lint/lint_plugin_infinite_edits/main.ts @@ -0,0 +1,2 @@ +const value = "𝄞"; +console.log(value); diff --git a/tests/specs/lint/lint_plugin_infinite_edits/plugin.ts b/tests/specs/lint/lint_plugin_infinite_edits/plugin.ts new file mode 100644 index 00000000000000..5926fb868c1305 --- /dev/null +++ b/tests/specs/lint/lint_plugin_infinite_edits/plugin.ts @@ -0,0 +1,20 @@ +export default { + name: "test-plugin", + rules: { + "my-rule": { + create(context) { + return { + VariableDeclarator(node) { + context.report({ + node: node.init, + message: 'should be equal to string "1"', + fix(fixer) { + return fixer.replaceText(node.init, Date.now().toString()); + }, + }); + }, + }; + }, + }, + }, +}; diff --git a/tests/specs/lint/lint_plugin_utf16/__test__.jsonc b/tests/specs/lint/lint_plugin_utf16/__test__.jsonc new file mode 100644 index 00000000000000..e04db0eaf0483d --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/__test__.jsonc @@ -0,0 +1,22 @@ +{ + "tests": { + "lint": { + "args": "lint", + "output": "lint.out", + "exitCode": 1 + }, + "fix": { + "tempDir": true, + "steps": [{ + "args": "lint --fix", + "output": "fix.out" + }, { + "args": [ + "eval", + "console.log(Deno.readTextFileSync('main.ts').trim())" + ], + "output": "fixed.out" + }] + } + } +} diff --git a/tests/specs/lint/lint_plugin_utf16/deno.json b/tests/specs/lint/lint_plugin_utf16/deno.json new file mode 100644 index 00000000000000..57b9dcb3647975 --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/deno.json @@ -0,0 +1,5 @@ +{ + "lint": { + "plugins": ["./plugin.ts"] + } +} diff --git a/tests/specs/lint/lint_plugin_utf16/fix.out b/tests/specs/lint/lint_plugin_utf16/fix.out new file mode 100644 index 00000000000000..158c556c2968ff --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/fix.out @@ -0,0 +1 @@ +Checked 2 files diff --git a/tests/specs/lint/lint_plugin_utf16/fixed.out b/tests/specs/lint/lint_plugin_utf16/fixed.out new file mode 100644 index 00000000000000..46538595af2352 --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/fixed.out @@ -0,0 +1,2 @@ +const value = "1"; +console.log(value); diff --git a/tests/specs/lint/lint_plugin_utf16/lint.out b/tests/specs/lint/lint_plugin_utf16/lint.out new file mode 100644 index 00000000000000..cf78dcf9f3b31e --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/lint.out @@ -0,0 +1,11 @@ +error[test-plugin/my-rule]: should be equal to string "1" + --> [WILDLINE]main.ts:1:15 + | +1 | const value = "𝄞"; + | ^^^ + + docs: https://docs.deno.com/lint/rules/test-plugin/my-rule + + +Found 1 problem (1 fixable via --fix) +Checked 2 files diff --git a/tests/specs/lint/lint_plugin_utf16/main.ts b/tests/specs/lint/lint_plugin_utf16/main.ts new file mode 100644 index 00000000000000..5a277eecbbcf4f --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/main.ts @@ -0,0 +1,2 @@ +const value = "𝄞"; +console.log(value); diff --git a/tests/specs/lint/lint_plugin_utf16/plugin.ts b/tests/specs/lint/lint_plugin_utf16/plugin.ts new file mode 100644 index 00000000000000..40894f5e0e67dd --- /dev/null +++ b/tests/specs/lint/lint_plugin_utf16/plugin.ts @@ -0,0 +1,22 @@ +export default { + name: "test-plugin", + rules: { + "my-rule": { + create(context) { + return { + VariableDeclarator(node) { + if (node.init.type !== "Literal" || node.init.value !== "1") { + context.report({ + node: node.init, + message: 'should be equal to string "1"', + fix(fixer) { + return fixer.replaceText(node.init, '"1"'); + }, + }); + } + }, + }; + }, + }, + }, +}; diff --git a/tests/unit/__snapshots__/lint_plugin_test.ts.snap b/tests/unit/__snapshots__/lint_plugin_test.ts.snap index 337fcecc8f1e7d..d2a0d2aa8ce001 100644 --- a/tests/unit/__snapshots__/lint_plugin_test.ts.snap +++ b/tests/unit/__snapshots__/lint_plugin_test.ts.snap @@ -4,8 +4,8 @@ snapshot[`Plugin - Program 1`] = ` { body: [], range: [ - 1, - 1, + 0, + 0, ], sourceType: "script", type: "Program", @@ -17,13 +17,13 @@ snapshot[`Plugin - ImportDeclaration 1`] = ` attributes: [], importKind: "value", range: [ - 1, - 14, + 0, + 13, ], source: { range: [ - 8, - 13, + 7, + 12, ], raw: '"foo"', type: "Literal", @@ -39,13 +39,13 @@ snapshot[`Plugin - ImportDeclaration 2`] = ` attributes: [], importKind: "value", range: [ - 1, - 23, + 0, + 22, ], source: { range: [ - 17, - 22, + 16, + 21, ], raw: '"foo"', type: "Literal", @@ -57,15 +57,15 @@ snapshot[`Plugin - ImportDeclaration 2`] = ` name: "foo", optional: false, range: [ - 8, - 11, + 7, + 10, ], type: "Identifier", typeAnnotation: null, }, range: [ - 8, - 11, + 7, + 10, ], type: "ImportDefaultSpecifier", }, @@ -79,13 +79,13 @@ snapshot[`Plugin - ImportDeclaration 3`] = ` attributes: [], importKind: "value", range: [ - 1, - 28, + 0, + 27, ], source: { range: [ - 22, - 27, + 21, + 26, ], raw: '"foo"', type: "Literal", @@ -97,15 +97,15 @@ snapshot[`Plugin - ImportDeclaration 3`] = ` name: "foo", optional: false, range: [ - 13, - 16, + 12, + 15, ], type: "Identifier", typeAnnotation: null, }, range: [ - 8, - 16, + 7, + 15, ], type: "ImportNamespaceSpecifier", }, @@ -119,13 +119,13 @@ snapshot[`Plugin - ImportDeclaration 4`] = ` attributes: [], importKind: "value", range: [ - 1, - 39, + 0, + 38, ], source: { range: [ - 33, - 38, + 32, + 37, ], raw: '"foo"', type: "Literal", @@ -138,8 +138,8 @@ snapshot[`Plugin - ImportDeclaration 4`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, @@ -148,15 +148,15 @@ snapshot[`Plugin - ImportDeclaration 4`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 13, + 9, + 12, ], type: "ImportSpecifier", }, @@ -166,8 +166,8 @@ snapshot[`Plugin - ImportDeclaration 4`] = ` name: "bar", optional: false, range: [ - 15, - 18, + 14, + 17, ], type: "Identifier", typeAnnotation: null, @@ -176,15 +176,15 @@ snapshot[`Plugin - ImportDeclaration 4`] = ` name: "baz", optional: false, range: [ - 22, - 25, + 21, + 24, ], type: "Identifier", typeAnnotation: null, }, range: [ - 15, - 25, + 14, + 24, ], type: "ImportSpecifier", }, @@ -201,21 +201,21 @@ snapshot[`Plugin - ImportDeclaration 5`] = ` name: "type", optional: false, range: [ - 30, - 34, + 29, + 33, ], type: "Identifier", typeAnnotation: null, }, range: [ - 30, - 42, + 29, + 41, ], type: "ImportAttribute", value: { range: [ - 36, - 42, + 35, + 41, ], raw: '"json"', type: "Literal", @@ -225,13 +225,13 @@ snapshot[`Plugin - ImportDeclaration 5`] = ` ], importKind: "value", range: [ - 1, - 45, + 0, + 44, ], source: { range: [ - 17, - 22, + 16, + 21, ], raw: '"foo"', type: "Literal", @@ -243,15 +243,15 @@ snapshot[`Plugin - ImportDeclaration 5`] = ` name: "foo", optional: false, range: [ - 8, - 11, + 7, + 10, ], type: "Identifier", typeAnnotation: null, }, range: [ - 8, - 11, + 7, + 10, ], type: "ImportDefaultSpecifier", }, @@ -264,13 +264,13 @@ snapshot[`Plugin - ExportNamedDeclaration 1`] = ` { attributes: [], range: [ - 1, - 27, + 0, + 26, ], source: { range: [ - 21, - 26, + 20, + 25, ], raw: '"foo"', type: "Literal", @@ -283,8 +283,8 @@ snapshot[`Plugin - ExportNamedDeclaration 1`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, @@ -293,15 +293,15 @@ snapshot[`Plugin - ExportNamedDeclaration 1`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 13, + 9, + 12, ], type: "ExportSpecifier", }, @@ -314,13 +314,13 @@ snapshot[`Plugin - ExportNamedDeclaration 2`] = ` { attributes: [], range: [ - 1, - 34, + 0, + 33, ], source: { range: [ - 28, - 33, + 27, + 32, ], raw: '"foo"', type: "Literal", @@ -333,8 +333,8 @@ snapshot[`Plugin - ExportNamedDeclaration 2`] = ` name: "baz", optional: false, range: [ - 17, - 20, + 16, + 19, ], type: "Identifier", typeAnnotation: null, @@ -343,15 +343,15 @@ snapshot[`Plugin - ExportNamedDeclaration 2`] = ` name: "bar", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 20, + 9, + 19, ], type: "ExportSpecifier", }, @@ -368,21 +368,21 @@ snapshot[`Plugin - ExportNamedDeclaration 3`] = ` name: "type", optional: false, range: [ - 34, - 38, + 33, + 37, ], type: "Identifier", typeAnnotation: null, }, range: [ - 34, - 46, + 33, + 45, ], type: "ImportAttribute", value: { range: [ - 40, - 46, + 39, + 45, ], raw: '"json"', type: "Literal", @@ -391,13 +391,13 @@ snapshot[`Plugin - ExportNamedDeclaration 3`] = ` }, ], range: [ - 1, - 49, + 0, + 48, ], source: { range: [ - 21, - 26, + 20, + 25, ], raw: '"foo"', type: "Literal", @@ -410,8 +410,8 @@ snapshot[`Plugin - ExportNamedDeclaration 3`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, @@ -420,15 +420,15 @@ snapshot[`Plugin - ExportNamedDeclaration 3`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 13, + 9, + 12, ], type: "ExportSpecifier", }, @@ -444,8 +444,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 1`] = ` body: { body: [], range: [ - 31, - 33, + 30, + 32, ], type: "BlockStatement", }, @@ -455,16 +455,16 @@ snapshot[`Plugin - ExportDefaultDeclaration 1`] = ` name: "foo", optional: false, range: [ - 25, - 28, + 24, + 27, ], type: "Identifier", typeAnnotation: null, }, params: [], range: [ - 16, - 33, + 15, + 32, ], returnType: null, type: "FunctionDeclaration", @@ -472,8 +472,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 1`] = ` }, exportKind: "value", range: [ - 1, - 33, + 0, + 32, ], type: "ExportDefaultDeclaration", } @@ -486,8 +486,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 2`] = ` body: { body: [], range: [ - 28, - 30, + 27, + 29, ], type: "BlockStatement", }, @@ -496,8 +496,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 2`] = ` id: null, params: [], range: [ - 16, - 30, + 15, + 29, ], returnType: null, type: "FunctionDeclaration", @@ -505,8 +505,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 2`] = ` }, exportKind: "value", range: [ - 1, - 30, + 0, + 29, ], type: "ExportDefaultDeclaration", } @@ -519,8 +519,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 3`] = ` body: { body: [], range: [ - 16, - 28, + 15, + 27, ], type: "ClassBody", }, @@ -529,24 +529,24 @@ snapshot[`Plugin - ExportDefaultDeclaration 3`] = ` name: "Foo", optional: false, range: [ - 22, - 25, + 21, + 24, ], type: "Identifier", typeAnnotation: null, }, implements: [], range: [ - 16, - 28, + 15, + 27, ], superClass: null, type: "ClassDeclaration", }, exportKind: "value", range: [ - 1, - 28, + 0, + 27, ], type: "ExportDefaultDeclaration", } @@ -559,8 +559,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 4`] = ` body: { body: [], range: [ - 16, - 24, + 15, + 23, ], type: "ClassBody", }, @@ -568,16 +568,16 @@ snapshot[`Plugin - ExportDefaultDeclaration 4`] = ` id: null, implements: [], range: [ - 16, - 24, + 15, + 23, ], superClass: null, type: "ClassDeclaration", }, exportKind: "value", range: [ - 1, - 24, + 0, + 23, ], type: "ExportDefaultDeclaration", } @@ -589,16 +589,16 @@ snapshot[`Plugin - ExportDefaultDeclaration 5`] = ` name: "bar", optional: false, range: [ - 16, - 19, + 15, + 18, ], type: "Identifier", typeAnnotation: null, }, exportKind: "value", range: [ - 1, - 20, + 0, + 19, ], type: "ExportDefaultDeclaration", } @@ -610,8 +610,8 @@ snapshot[`Plugin - ExportDefaultDeclaration 6`] = ` body: { body: [], range: [ - 30, - 32, + 29, + 31, ], type: "TSInterfaceBody", }, @@ -621,23 +621,23 @@ snapshot[`Plugin - ExportDefaultDeclaration 6`] = ` name: "Foo", optional: false, range: [ - 26, - 29, + 25, + 28, ], type: "Identifier", typeAnnotation: null, }, range: [ - 16, - 32, + 15, + 31, ], type: "TSInterfaceDeclaration", typeParameters: [], }, exportKind: "type", range: [ - 1, - 32, + 0, + 31, ], type: "ExportDefaultDeclaration", } @@ -649,13 +649,13 @@ snapshot[`Plugin - ExportAllDeclaration 1`] = ` exportKind: "value", exported: null, range: [ - 1, - 21, + 0, + 20, ], source: { range: [ - 15, - 20, + 14, + 19, ], raw: '"foo"', type: "Literal", @@ -671,23 +671,23 @@ snapshot[`Plugin - ExportAllDeclaration 2`] = ` exportKind: "value", exported: { range: [ - 22, - 27, + 21, + 26, ], raw: '"foo"', type: "Literal", value: "foo", }, range: [ - 1, - 28, + 0, + 27, ], source: { name: "foo", optional: false, range: [ - 13, - 16, + 12, + 15, ], type: "Identifier", typeAnnotation: null, @@ -704,21 +704,21 @@ snapshot[`Plugin - ExportAllDeclaration 3`] = ` name: "type", optional: false, range: [ - 28, - 32, + 27, + 31, ], type: "Identifier", typeAnnotation: null, }, range: [ - 28, - 40, + 27, + 39, ], type: "ImportAttribute", value: { range: [ - 34, - 40, + 33, + 39, ], raw: '"json"', type: "Literal", @@ -729,13 +729,13 @@ snapshot[`Plugin - ExportAllDeclaration 3`] = ` exportKind: "value", exported: null, range: [ - 1, - 43, + 0, + 42, ], source: { range: [ - 15, - 20, + 14, + 19, ], raw: '"foo"', type: "Literal", @@ -751,15 +751,15 @@ snapshot[`Plugin - TSExportAssignment 1`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "TSExportAssignment", } @@ -771,15 +771,15 @@ snapshot[`Plugin - TSNamespaceExportDeclaration 1`] = ` name: "A", optional: false, range: [ + 20, 21, - 22, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 23, + 0, + 22, ], type: "TSNamespaceExportDeclaration", } @@ -791,8 +791,8 @@ snapshot[`Plugin - TSImportEqualsDeclaration 1`] = ` name: "a", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, @@ -802,15 +802,15 @@ snapshot[`Plugin - TSImportEqualsDeclaration 1`] = ` name: "b", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 13, + 0, + 12, ], type: "TSImportEqualsDeclaration", } @@ -822,8 +822,8 @@ snapshot[`Plugin - TSImportEqualsDeclaration 2`] = ` name: "a", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, @@ -832,22 +832,22 @@ snapshot[`Plugin - TSImportEqualsDeclaration 2`] = ` moduleReference: { expression: { range: [ - 20, - 25, + 19, + 24, ], raw: '"foo"', type: "Literal", value: "foo", }, range: [ - 12, - 26, + 11, + 25, ], type: "TSExternalModuleReference", }, range: [ - 1, - 26, + 0, + 25, ], type: "TSImportEqualsDeclaration", } @@ -861,22 +861,22 @@ snapshot[`Plugin - BlockStatement 1`] = ` name: "foo", optional: false, range: [ - 3, - 6, + 2, + 5, ], type: "Identifier", typeAnnotation: null, }, range: [ - 3, - 7, + 2, + 6, ], type: "ExpressionStatement", }, ], range: [ - 1, - 9, + 0, + 8, ], type: "BlockStatement", } @@ -886,8 +886,8 @@ snapshot[`Plugin - BreakStatement 1`] = ` { label: null, range: [ - 15, - 21, + 14, + 20, ], type: "BreakStatement", } @@ -899,15 +899,15 @@ snapshot[`Plugin - BreakStatement 2`] = ` name: "foo", optional: false, range: [ - 26, - 29, + 25, + 28, ], type: "Identifier", typeAnnotation: null, }, range: [ - 20, - 30, + 19, + 29, ], type: "BreakStatement", } @@ -917,8 +917,8 @@ snapshot[`Plugin - ContinueStatement 1`] = ` { label: null, range: [ - 1, - 10, + 0, + 9, ], type: "ContinueStatement", } @@ -930,15 +930,15 @@ snapshot[`Plugin - ContinueStatement 2`] = ` name: "foo", optional: false, range: [ - 10, - 13, + 9, + 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "ContinueStatement", } @@ -947,8 +947,8 @@ snapshot[`Plugin - ContinueStatement 2`] = ` snapshot[`Plugin - DebuggerStatement 1`] = ` { range: [ - 1, - 10, + 0, + 9, ], type: "DebuggerStatement", } @@ -959,21 +959,21 @@ snapshot[`Plugin - DoWhileStatement 1`] = ` body: { body: [], range: [ - 4, - 6, + 3, + 5, ], type: "BlockStatement", }, range: [ - 1, - 19, + 0, + 18, ], test: { name: "foo", optional: false, range: [ - 14, - 17, + 13, + 16, ], type: "Identifier", typeAnnotation: null, @@ -988,15 +988,15 @@ snapshot[`Plugin - ExpressionStatement 1`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 5, + 0, + 4, ], type: "ExpressionStatement", } @@ -1007,8 +1007,8 @@ snapshot[`Plugin - ForInStatement 1`] = ` body: { body: [], range: [ - 14, - 16, + 13, + 15, ], type: "BlockStatement", }, @@ -1016,22 +1016,22 @@ snapshot[`Plugin - ForInStatement 1`] = ` name: "a", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 16, + 0, + 15, ], right: { name: "b", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, @@ -1046,8 +1046,8 @@ snapshot[`Plugin - ForOfStatement 1`] = ` body: { body: [], range: [ - 14, - 16, + 13, + 15, ], type: "BlockStatement", }, @@ -1055,22 +1055,22 @@ snapshot[`Plugin - ForOfStatement 1`] = ` name: "a", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 16, + 0, + 15, ], right: { name: "b", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, @@ -1085,8 +1085,8 @@ snapshot[`Plugin - ForOfStatement 2`] = ` body: { body: [], range: [ - 20, - 22, + 19, + 21, ], type: "BlockStatement", }, @@ -1094,22 +1094,22 @@ snapshot[`Plugin - ForOfStatement 2`] = ` name: "a", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 22, + 0, + 21, ], right: { name: "b", optional: false, range: [ + 16, 17, - 18, ], type: "Identifier", typeAnnotation: null, @@ -1123,15 +1123,15 @@ snapshot[`Plugin - ForStatement 1`] = ` body: { body: [], range: [ - 10, - 12, + 9, + 11, ], type: "BlockStatement", }, init: null, range: [ - 1, - 12, + 0, + 11, ], test: null, type: "ForStatement", @@ -1144,8 +1144,8 @@ snapshot[`Plugin - ForStatement 2`] = ` body: { body: [], range: [ - 15, - 17, + 14, + 16, ], type: "BlockStatement", }, @@ -1153,22 +1153,22 @@ snapshot[`Plugin - ForStatement 2`] = ` name: "a", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 17, + 0, + 16, ], test: { name: "b", optional: false, range: [ + 8, 9, - 10, ], type: "Identifier", typeAnnotation: null, @@ -1178,8 +1178,8 @@ snapshot[`Plugin - ForStatement 2`] = ` name: "c", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, @@ -1193,21 +1193,21 @@ snapshot[`Plugin - IfStatement 1`] = ` consequent: { body: [], range: [ - 10, - 12, + 9, + 11, ], type: "BlockStatement", }, range: [ - 1, - 12, + 0, + 11, ], test: { name: "foo", optional: false, range: [ - 5, - 8, + 4, + 7, ], type: "Identifier", typeAnnotation: null, @@ -1221,29 +1221,29 @@ snapshot[`Plugin - IfStatement 2`] = ` alternate: { body: [], range: [ - 18, - 20, + 17, + 19, ], type: "BlockStatement", }, consequent: { body: [], range: [ - 10, - 12, + 9, + 11, ], type: "BlockStatement", }, range: [ - 1, - 20, + 0, + 19, ], test: { name: "foo", optional: false, range: [ - 5, - 8, + 4, + 7, ], type: "Identifier", typeAnnotation: null, @@ -1257,8 +1257,8 @@ snapshot[`Plugin - LabeledStatement 1`] = ` body: { body: [], range: [ - 6, - 8, + 5, + 7, ], type: "BlockStatement", }, @@ -1266,15 +1266,15 @@ snapshot[`Plugin - LabeledStatement 1`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 8, + 0, + 7, ], type: "LabeledStatement", } @@ -1284,8 +1284,8 @@ snapshot[`Plugin - ReturnStatement 1`] = ` { argument: null, range: [ - 1, - 7, + 0, + 6, ], type: "ReturnStatement", } @@ -1297,15 +1297,15 @@ snapshot[`Plugin - ReturnStatement 2`] = ` name: "foo", optional: false, range: [ - 8, - 11, + 7, + 10, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "ReturnStatement", } @@ -1317,15 +1317,15 @@ snapshot[`Plugin - SwitchStatement 1`] = ` { consequent: [], range: [ - 22, - 31, + 21, + 30, ], test: { name: "foo", optional: false, range: [ - 27, - 30, + 26, + 29, ], type: "Identifier", typeAnnotation: null, @@ -1337,22 +1337,22 @@ snapshot[`Plugin - SwitchStatement 1`] = ` { label: null, range: [ - 56, - 62, + 55, + 61, ], type: "BreakStatement", }, ], range: [ - 38, - 62, + 37, + 61, ], test: { name: "bar", optional: false, range: [ - 43, - 46, + 42, + 45, ], type: "Identifier", typeAnnotation: null, @@ -1364,15 +1364,15 @@ snapshot[`Plugin - SwitchStatement 1`] = ` { body: [], range: [ - 86, - 88, + 85, + 87, ], type: "BlockStatement", }, ], range: [ - 69, - 88, + 68, + 87, ], test: null, type: "SwitchCase", @@ -1382,15 +1382,15 @@ snapshot[`Plugin - SwitchStatement 1`] = ` name: "foo", optional: false, range: [ - 9, - 12, + 8, + 11, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 94, + 0, + 93, ], type: "SwitchStatement", } @@ -1402,15 +1402,15 @@ snapshot[`Plugin - ThrowStatement 1`] = ` name: "foo", optional: false, range: [ - 7, - 10, + 6, + 9, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 11, + 0, + 10, ], type: "ThrowStatement", } @@ -1421,8 +1421,8 @@ snapshot[`Plugin - TryStatement 1`] = ` block: { body: [], range: [ - 5, - 7, + 4, + 6, ], type: "BlockStatement", }, @@ -1431,21 +1431,21 @@ snapshot[`Plugin - TryStatement 1`] = ` body: { body: [], range: [ - 14, - 16, + 13, + 15, ], type: "BlockStatement", }, param: null, range: [ - 8, - 16, + 7, + 15, ], type: "CatchClause", }, range: [ - 1, - 16, + 0, + 15, ], type: "TryStatement", } @@ -1456,8 +1456,8 @@ snapshot[`Plugin - TryStatement 2`] = ` block: { body: [], range: [ - 5, - 7, + 4, + 6, ], type: "BlockStatement", }, @@ -1466,8 +1466,8 @@ snapshot[`Plugin - TryStatement 2`] = ` body: { body: [], range: [ - 18, - 20, + 17, + 19, ], type: "BlockStatement", }, @@ -1475,21 +1475,21 @@ snapshot[`Plugin - TryStatement 2`] = ` name: "e", optional: false, range: [ + 14, 15, - 16, ], type: "Identifier", typeAnnotation: null, }, range: [ - 8, - 20, + 7, + 19, ], type: "CatchClause", }, range: [ - 1, - 20, + 0, + 19, ], type: "TryStatement", } @@ -1500,23 +1500,23 @@ snapshot[`Plugin - TryStatement 3`] = ` block: { body: [], range: [ - 5, - 7, + 4, + 6, ], type: "BlockStatement", }, finalizer: { body: [], range: [ - 16, - 18, + 15, + 17, ], type: "BlockStatement", }, handler: null, range: [ - 1, - 18, + 0, + 17, ], type: "TryStatement", } @@ -1527,21 +1527,21 @@ snapshot[`Plugin - WhileStatement 1`] = ` body: { body: [], range: [ - 13, - 15, + 12, + 14, ], type: "BlockStatement", }, range: [ - 1, - 15, + 0, + 14, ], test: { name: "foo", optional: false, range: [ - 8, - 11, + 7, + 10, ], type: "Identifier", typeAnnotation: null, @@ -1555,22 +1555,22 @@ snapshot[`Plugin - WithStatement 1`] = ` body: { body: [], range: [ - 11, - 13, + 10, + 12, ], type: "BlockStatement", }, object: { elements: [], range: [ - 7, - 9, + 6, + 8, ], type: "ArrayExpression", }, range: [ - 1, - 13, + 0, + 12, ], type: "WithStatement", } @@ -1582,15 +1582,15 @@ snapshot[`Plugin - ArrayExpression 1`] = ` { elements: [], range: [ - 2, - 4, + 1, + 3, ], type: "ArrayExpression", }, ], range: [ - 1, - 9, + 0, + 8, ], type: "ArrayExpression", } @@ -1602,16 +1602,16 @@ snapshot[`Plugin - ArrowFunctionExpression 1`] = ` body: { body: [], range: [ - 7, - 9, + 6, + 8, ], type: "BlockStatement", }, generator: false, params: [], range: [ - 1, - 9, + 0, + 8, ], returnType: null, type: "ArrowFunctionExpression", @@ -1625,16 +1625,16 @@ snapshot[`Plugin - ArrowFunctionExpression 2`] = ` body: { body: [], range: [ - 13, - 15, + 12, + 14, ], type: "BlockStatement", }, generator: false, params: [], range: [ - 1, - 15, + 0, + 14, ], returnType: null, type: "ArrowFunctionExpression", @@ -1648,8 +1648,8 @@ snapshot[`Plugin - ArrowFunctionExpression 3`] = ` body: { body: [], range: [ - 34, - 36, + 33, + 35, ], type: "BlockStatement", }, @@ -1659,20 +1659,20 @@ snapshot[`Plugin - ArrowFunctionExpression 3`] = ` name: "a", optional: false, range: [ - 2, - 11, + 1, + 10, ], type: "Identifier", typeAnnotation: { range: [ - 3, - 11, + 2, + 10, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 5, - 11, + 4, + 10, ], type: "TSNumberKeyword", }, @@ -1683,34 +1683,34 @@ snapshot[`Plugin - ArrowFunctionExpression 3`] = ` name: "b", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, range: [ - 13, - 24, + 12, + 23, ], type: "RestElement", typeAnnotation: { range: [ - 17, - 24, + 16, + 23, ], type: "TSTypeAnnotation", typeAnnotation: { elementType: { range: [ - 19, - 22, + 18, + 21, ], type: "TSAnyKeyword", }, range: [ - 19, - 24, + 18, + 23, ], type: "TSArrayType", }, @@ -1718,19 +1718,19 @@ snapshot[`Plugin - ArrowFunctionExpression 3`] = ` }, ], range: [ - 1, - 36, + 0, + 35, ], returnType: { range: [ - 25, - 30, + 24, + 29, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 27, - 30, + 26, + 29, ], type: "TSAnyKeyword", }, @@ -1746,23 +1746,23 @@ snapshot[`Plugin - AssignmentExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "=", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -1777,39 +1777,39 @@ snapshot[`Plugin - AssignmentExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "=", range: [ - 1, - 12, + 0, + 11, ], right: { left: { name: "a", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, }, operator: "??=", range: [ - 5, - 12, + 4, + 11, ], right: { name: "b", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, @@ -1826,15 +1826,15 @@ snapshot[`Plugin - AwaitExpression 1`] = ` name: "foo", optional: false, range: [ - 7, - 10, + 6, + 9, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 10, + 0, + 9, ], type: "AwaitExpression", } @@ -1846,23 +1846,23 @@ snapshot[`Plugin - BinaryExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: ">", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -1877,23 +1877,23 @@ snapshot[`Plugin - BinaryExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: ">=", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -1908,23 +1908,23 @@ snapshot[`Plugin - BinaryExpression 3`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "<", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -1939,23 +1939,23 @@ snapshot[`Plugin - BinaryExpression 4`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "<=", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -1970,23 +1970,23 @@ snapshot[`Plugin - BinaryExpression 5`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "==", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2001,23 +2001,23 @@ snapshot[`Plugin - BinaryExpression 6`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "===", range: [ - 1, - 8, + 0, + 7, ], right: { name: "b", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -2032,23 +2032,23 @@ snapshot[`Plugin - BinaryExpression 7`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "!=", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2063,23 +2063,23 @@ snapshot[`Plugin - BinaryExpression 8`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "!=", range: [ - 1, - 8, + 0, + 7, ], right: { name: "b", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -2094,23 +2094,23 @@ snapshot[`Plugin - BinaryExpression 9`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "<<", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2125,23 +2125,23 @@ snapshot[`Plugin - BinaryExpression 10`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: ">>", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2156,23 +2156,23 @@ snapshot[`Plugin - BinaryExpression 11`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: ">>>", range: [ - 1, - 8, + 0, + 7, ], right: { name: "b", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -2187,23 +2187,23 @@ snapshot[`Plugin - BinaryExpression 12`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "+", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2218,23 +2218,23 @@ snapshot[`Plugin - BinaryExpression 13`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "-", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2249,23 +2249,23 @@ snapshot[`Plugin - BinaryExpression 14`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "*", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2280,23 +2280,23 @@ snapshot[`Plugin - BinaryExpression 15`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "/", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2311,23 +2311,23 @@ snapshot[`Plugin - BinaryExpression 16`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "%", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2342,23 +2342,23 @@ snapshot[`Plugin - BinaryExpression 17`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "|", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2373,23 +2373,23 @@ snapshot[`Plugin - BinaryExpression 18`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "^", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2404,23 +2404,23 @@ snapshot[`Plugin - BinaryExpression 19`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "&", range: [ - 1, - 6, + 0, + 5, ], right: { name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2435,23 +2435,23 @@ snapshot[`Plugin - BinaryExpression 20`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "in", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2466,23 +2466,23 @@ snapshot[`Plugin - BinaryExpression 21`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "**", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -2498,16 +2498,16 @@ snapshot[`Plugin - CallExpression 1`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 1, - 6, + 0, + 5, ], type: "CallExpression", typeArguments: null, @@ -2521,8 +2521,8 @@ snapshot[`Plugin - CallExpression 2`] = ` name: "a", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2532,15 +2532,15 @@ snapshot[`Plugin - CallExpression 2`] = ` name: "b", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 8, - 11, + 7, + 10, ], type: "SpreadElement", }, @@ -2549,16 +2549,16 @@ snapshot[`Plugin - CallExpression 2`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 1, - 13, + 0, + 12, ], type: "CallExpression", typeArguments: null, @@ -2572,16 +2572,16 @@ snapshot[`Plugin - CallExpression 3`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, optional: true, range: [ - 1, - 8, + 0, + 7, ], type: "CallExpression", typeArguments: null, @@ -2595,24 +2595,24 @@ snapshot[`Plugin - CallExpression 4`] = ` name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 1, - 9, + 0, + 8, ], type: "CallExpression", typeArguments: { params: [ { range: [ + 4, 5, - 6, ], type: "TSTypeReference", typeArguments: null, @@ -2620,8 +2620,8 @@ snapshot[`Plugin - CallExpression 4`] = ` name: "T", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, @@ -2629,8 +2629,8 @@ snapshot[`Plugin - CallExpression 4`] = ` }, ], range: [ - 4, - 7, + 3, + 6, ], type: "TSTypeParameterInstantiation", }, @@ -2645,8 +2645,8 @@ snapshot[`Plugin - ChainExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -2656,21 +2656,21 @@ snapshot[`Plugin - ChainExpression 1`] = ` name: "b", optional: false, range: [ + 3, 4, - 5, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 5, + 0, + 4, ], type: "MemberExpression", }, range: [ - 1, - 5, + 0, + 4, ], type: "ChainExpression", } @@ -2682,8 +2682,8 @@ snapshot[`Plugin - ClassExpression 1`] = ` body: { body: [], range: [ - 5, - 13, + 4, + 12, ], type: "ClassBody", }, @@ -2691,8 +2691,8 @@ snapshot[`Plugin - ClassExpression 1`] = ` id: null, implements: [], range: [ - 5, - 13, + 4, + 12, ], superClass: null, type: "ClassExpression", @@ -2705,8 +2705,8 @@ snapshot[`Plugin - ClassExpression 2`] = ` body: { body: [], range: [ - 5, - 17, + 4, + 16, ], type: "ClassBody", }, @@ -2715,16 +2715,16 @@ snapshot[`Plugin - ClassExpression 2`] = ` name: "Foo", optional: false, range: [ - 11, - 14, + 10, + 13, ], type: "Identifier", typeAnnotation: null, }, implements: [], range: [ - 5, - 17, + 4, + 16, ], superClass: null, type: "ClassExpression", @@ -2737,8 +2737,8 @@ snapshot[`Plugin - ClassExpression 3`] = ` body: { body: [], range: [ - 5, - 29, + 4, + 28, ], type: "ClassBody", }, @@ -2747,23 +2747,23 @@ snapshot[`Plugin - ClassExpression 3`] = ` name: "Foo", optional: false, range: [ - 11, - 14, + 10, + 13, ], type: "Identifier", typeAnnotation: null, }, implements: [], range: [ - 5, - 29, + 4, + 28, ], superClass: { name: "Bar", optional: false, range: [ - 23, - 26, + 22, + 25, ], type: "Identifier", typeAnnotation: null, @@ -2778,8 +2778,8 @@ snapshot[`Plugin - ClassExpression 4`] = ` body: { body: [], range: [ - 5, - 50, + 4, + 49, ], type: "ClassBody", }, @@ -2788,8 +2788,8 @@ snapshot[`Plugin - ClassExpression 4`] = ` name: "Foo", optional: false, range: [ - 11, - 14, + 10, + 13, ], type: "Identifier", typeAnnotation: null, @@ -2800,15 +2800,15 @@ snapshot[`Plugin - ClassExpression 4`] = ` name: "Baz", optional: false, range: [ - 38, - 41, + 37, + 40, ], type: "Identifier", typeAnnotation: null, }, range: [ - 38, - 41, + 37, + 40, ], type: "TSClassImplements", typeArguments: null, @@ -2818,30 +2818,30 @@ snapshot[`Plugin - ClassExpression 4`] = ` name: "Baz2", optional: false, range: [ - 43, - 47, + 42, + 46, ], type: "Identifier", typeAnnotation: null, }, range: [ - 43, - 47, + 42, + 46, ], type: "TSClassImplements", typeArguments: null, }, ], range: [ - 5, - 50, + 4, + 49, ], superClass: { name: "Bar", optional: false, range: [ - 23, - 26, + 22, + 25, ], type: "Identifier", typeAnnotation: null, @@ -2856,8 +2856,8 @@ snapshot[`Plugin - ClassExpression 5`] = ` body: { body: [], range: [ - 5, - 20, + 4, + 19, ], type: "ClassBody", }, @@ -2866,16 +2866,16 @@ snapshot[`Plugin - ClassExpression 5`] = ` name: "Foo", optional: false, range: [ - 11, - 14, + 10, + 13, ], type: "Identifier", typeAnnotation: null, }, implements: [], range: [ - 5, - 20, + 4, + 19, ], superClass: null, type: "ClassExpression", @@ -2895,8 +2895,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` name: "foo", optional: false, range: [ - 13, - 16, + 12, + 15, ], type: "Identifier", typeAnnotation: null, @@ -2905,8 +2905,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` optional: false, override: false, range: [ - 13, - 21, + 12, + 20, ], static: false, type: "MethodDefinition", @@ -2915,8 +2915,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` body: { body: [], range: [ - 19, - 21, + 18, + 20, ], type: "BlockStatement", }, @@ -2924,8 +2924,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` id: null, params: [], range: [ - 13, - 21, + 12, + 20, ], returnType: null, type: "FunctionExpression", @@ -2934,8 +2934,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` }, ], range: [ - 5, - 23, + 4, + 22, ], type: "ClassBody", }, @@ -2943,8 +2943,8 @@ snapshot[`Plugin - ClassExpression 6`] = ` id: null, implements: [], range: [ - 5, - 23, + 4, + 22, ], superClass: null, type: "ClassExpression", @@ -2963,8 +2963,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` key: { name: "foo", range: [ - 13, - 17, + 12, + 16, ], type: "PrivateIdentifier", }, @@ -2972,8 +2972,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` optional: false, override: false, range: [ - 13, - 22, + 12, + 21, ], static: false, type: "MethodDefinition", @@ -2982,8 +2982,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` body: { body: [], range: [ - 20, - 22, + 19, + 21, ], type: "BlockStatement", }, @@ -2991,8 +2991,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` id: null, params: [], range: [ - 13, - 22, + 12, + 21, ], returnType: null, type: "FunctionExpression", @@ -3001,8 +3001,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` }, ], range: [ - 5, - 24, + 4, + 23, ], type: "ClassBody", }, @@ -3010,8 +3010,8 @@ snapshot[`Plugin - ClassExpression 7`] = ` id: null, implements: [], range: [ - 5, - 24, + 4, + 23, ], superClass: null, type: "ClassExpression", @@ -3032,8 +3032,8 @@ snapshot[`Plugin - ClassExpression 8`] = ` name: "foo", optional: false, range: [ - 13, - 16, + 12, + 15, ], type: "Identifier", typeAnnotation: null, @@ -3041,8 +3041,8 @@ snapshot[`Plugin - ClassExpression 8`] = ` optional: false, override: false, range: [ - 13, - 24, + 12, + 23, ], readonly: false, static: false, @@ -3051,8 +3051,8 @@ snapshot[`Plugin - ClassExpression 8`] = ` }, ], range: [ - 5, - 26, + 4, + 25, ], type: "ClassBody", }, @@ -3060,8 +3060,8 @@ snapshot[`Plugin - ClassExpression 8`] = ` id: null, implements: [], range: [ - 5, - 26, + 4, + 25, ], superClass: null, type: "ClassExpression", @@ -3082,8 +3082,8 @@ snapshot[`Plugin - ClassExpression 9`] = ` name: "foo", optional: false, range: [ - 13, - 16, + 12, + 15, ], type: "Identifier", typeAnnotation: null, @@ -3091,8 +3091,8 @@ snapshot[`Plugin - ClassExpression 9`] = ` optional: false, override: false, range: [ - 13, - 22, + 12, + 21, ], readonly: false, static: false, @@ -3101,8 +3101,8 @@ snapshot[`Plugin - ClassExpression 9`] = ` name: "bar", optional: false, range: [ - 19, - 22, + 18, + 21, ], type: "Identifier", typeAnnotation: null, @@ -3110,8 +3110,8 @@ snapshot[`Plugin - ClassExpression 9`] = ` }, ], range: [ - 5, - 24, + 4, + 23, ], type: "ClassBody", }, @@ -3119,8 +3119,8 @@ snapshot[`Plugin - ClassExpression 9`] = ` id: null, implements: [], range: [ - 5, - 24, + 4, + 23, ], superClass: null, type: "ClassExpression", @@ -3140,8 +3140,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` name: "constructor", optional: false, range: [ - 13, - 24, + 12, + 23, ], type: "Identifier", typeAnnotation: null, @@ -3150,8 +3150,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` optional: false, override: false, range: [ - 13, - 47, + 12, + 46, ], static: false, type: "MethodDefinition", @@ -3160,8 +3160,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` body: { body: [], range: [ - 45, - 47, + 44, + 46, ], type: "BlockStatement", }, @@ -3176,28 +3176,28 @@ snapshot[`Plugin - ClassExpression 10`] = ` name: "foo", optional: false, range: [ - 32, - 35, + 31, + 34, ], type: "Identifier", typeAnnotation: { range: [ - 35, - 43, + 34, + 42, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 37, - 43, + 36, + 42, ], type: "TSStringKeyword", }, }, }, range: [ - 25, - 43, + 24, + 42, ], readonly: false, static: false, @@ -3205,8 +3205,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` }, ], range: [ - 13, - 47, + 12, + 46, ], returnType: null, type: "FunctionExpression", @@ -3215,8 +3215,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` }, ], range: [ - 5, - 49, + 4, + 48, ], type: "ClassBody", }, @@ -3224,8 +3224,8 @@ snapshot[`Plugin - ClassExpression 10`] = ` id: null, implements: [], range: [ - 5, - 49, + 4, + 48, ], superClass: null, type: "ClassExpression", @@ -3245,16 +3245,16 @@ snapshot[`Plugin - ClassExpression 11`] = ` key: { name: "foo", range: [ - 13, - 17, + 12, + 16, ], type: "PrivateIdentifier", }, optional: false, override: false, range: [ - 13, - 31, + 12, + 30, ], readonly: false, static: false, @@ -3263,8 +3263,8 @@ snapshot[`Plugin - ClassExpression 11`] = ` name: "bar", optional: false, range: [ - 28, - 31, + 27, + 30, ], type: "Identifier", typeAnnotation: null, @@ -3272,8 +3272,8 @@ snapshot[`Plugin - ClassExpression 11`] = ` }, ], range: [ - 5, - 33, + 4, + 32, ], type: "ClassBody", }, @@ -3281,8 +3281,8 @@ snapshot[`Plugin - ClassExpression 11`] = ` id: null, implements: [], range: [ - 5, - 33, + 4, + 32, ], superClass: null, type: "ClassExpression", @@ -3303,8 +3303,8 @@ snapshot[`Plugin - ClassExpression 12`] = ` name: "foo", optional: false, range: [ - 20, - 23, + 19, + 22, ], type: "Identifier", typeAnnotation: null, @@ -3312,8 +3312,8 @@ snapshot[`Plugin - ClassExpression 12`] = ` optional: false, override: false, range: [ - 13, - 29, + 12, + 28, ], readonly: false, static: true, @@ -3322,8 +3322,8 @@ snapshot[`Plugin - ClassExpression 12`] = ` name: "bar", optional: false, range: [ - 26, - 29, + 25, + 28, ], type: "Identifier", typeAnnotation: null, @@ -3331,8 +3331,8 @@ snapshot[`Plugin - ClassExpression 12`] = ` }, ], range: [ - 5, - 31, + 4, + 30, ], type: "ClassBody", }, @@ -3340,8 +3340,8 @@ snapshot[`Plugin - ClassExpression 12`] = ` id: null, implements: [], range: [ - 5, - 31, + 4, + 30, ], superClass: null, type: "ClassExpression", @@ -3362,8 +3362,8 @@ snapshot[`Plugin - ClassExpression 13`] = ` name: "foo", optional: false, range: [ - 20, - 23, + 19, + 22, ], type: "Identifier", typeAnnotation: null, @@ -3371,8 +3371,8 @@ snapshot[`Plugin - ClassExpression 13`] = ` optional: false, override: false, range: [ - 13, - 24, + 12, + 23, ], readonly: false, static: true, @@ -3388,23 +3388,23 @@ snapshot[`Plugin - ClassExpression 13`] = ` name: "foo", optional: false, range: [ - 34, - 37, + 33, + 36, ], type: "Identifier", typeAnnotation: null, }, operator: "=", range: [ - 34, - 43, + 33, + 42, ], right: { name: "bar", optional: false, range: [ - 40, - 43, + 39, + 42, ], type: "Identifier", typeAnnotation: null, @@ -3412,28 +3412,28 @@ snapshot[`Plugin - ClassExpression 13`] = ` type: "AssignmentExpression", }, range: [ - 34, - 43, + 33, + 42, ], type: "ExpressionStatement", }, ], range: [ - 32, - 45, + 31, + 44, ], type: "BlockStatement", }, range: [ - 25, - 45, + 24, + 44, ], type: "StaticBlock", }, ], range: [ - 5, - 47, + 4, + 46, ], type: "ClassBody", }, @@ -3441,8 +3441,8 @@ snapshot[`Plugin - ClassExpression 13`] = ` id: null, implements: [], range: [ - 5, - 47, + 4, + 46, ], superClass: null, type: "ClassExpression", @@ -3455,8 +3455,8 @@ snapshot[`Plugin - ConditionalExpression 1`] = ` name: "c", optional: false, range: [ + 8, 9, - 10, ], type: "Identifier", typeAnnotation: null, @@ -3465,22 +3465,22 @@ snapshot[`Plugin - ConditionalExpression 1`] = ` name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 10, + 0, + 9, ], test: { name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -3495,8 +3495,8 @@ snapshot[`Plugin - FunctionExpression 1`] = ` body: { body: [], range: [ - 17, - 19, + 16, + 18, ], type: "BlockStatement", }, @@ -3504,8 +3504,8 @@ snapshot[`Plugin - FunctionExpression 1`] = ` id: null, params: [], range: [ - 5, - 19, + 4, + 18, ], returnType: null, type: "FunctionExpression", @@ -3519,8 +3519,8 @@ snapshot[`Plugin - FunctionExpression 2`] = ` body: { body: [], range: [ - 20, - 22, + 19, + 21, ], type: "BlockStatement", }, @@ -3529,16 +3529,16 @@ snapshot[`Plugin - FunctionExpression 2`] = ` name: "foo", optional: false, range: [ - 14, - 17, + 13, + 16, ], type: "Identifier", typeAnnotation: null, }, params: [], range: [ - 5, - 22, + 4, + 21, ], returnType: null, type: "FunctionExpression", @@ -3552,8 +3552,8 @@ snapshot[`Plugin - FunctionExpression 3`] = ` body: { body: [], range: [ - 45, - 47, + 44, + 46, ], type: "BlockStatement", }, @@ -3564,20 +3564,20 @@ snapshot[`Plugin - FunctionExpression 3`] = ` name: "a", optional: true, range: [ + 14, 15, - 16, ], type: "Identifier", typeAnnotation: { range: [ - 17, - 25, + 16, + 24, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 19, - 25, + 18, + 24, ], type: "TSNumberKeyword", }, @@ -3588,34 +3588,34 @@ snapshot[`Plugin - FunctionExpression 3`] = ` name: "b", optional: false, range: [ + 29, 30, - 31, ], type: "Identifier", typeAnnotation: null, }, range: [ - 27, - 38, + 26, + 37, ], type: "RestElement", typeAnnotation: { range: [ - 31, - 38, + 30, + 37, ], type: "TSTypeAnnotation", typeAnnotation: { elementType: { range: [ - 33, - 36, + 32, + 35, ], type: "TSAnyKeyword", }, range: [ - 33, - 38, + 32, + 37, ], type: "TSArrayType", }, @@ -3623,19 +3623,19 @@ snapshot[`Plugin - FunctionExpression 3`] = ` }, ], range: [ - 5, - 47, + 4, + 46, ], returnType: { range: [ - 39, - 44, + 38, + 43, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 41, - 44, + 40, + 43, ], type: "TSAnyKeyword", }, @@ -3651,8 +3651,8 @@ snapshot[`Plugin - FunctionExpression 4`] = ` body: { body: [], range: [ - 24, - 26, + 23, + 25, ], type: "BlockStatement", }, @@ -3660,8 +3660,8 @@ snapshot[`Plugin - FunctionExpression 4`] = ` id: null, params: [], range: [ - 5, - 26, + 4, + 25, ], returnType: null, type: "FunctionExpression", @@ -3674,8 +3674,8 @@ snapshot[`Plugin - Identifier 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -3692,8 +3692,8 @@ snapshot[`Plugin - ImportExpression 1`] = ` name: "with", optional: false, range: [ - 17, - 21, + 16, + 20, ], type: "Identifier", typeAnnotation: null, @@ -3701,8 +3701,8 @@ snapshot[`Plugin - ImportExpression 1`] = ` kind: "init", method: false, range: [ - 17, - 39, + 16, + 38, ], shorthand: false, type: "Property", @@ -3714,8 +3714,8 @@ snapshot[`Plugin - ImportExpression 1`] = ` name: "type", optional: false, range: [ - 25, - 29, + 24, + 28, ], type: "Identifier", typeAnnotation: null, @@ -3723,15 +3723,15 @@ snapshot[`Plugin - ImportExpression 1`] = ` kind: "init", method: false, range: [ - 25, - 37, + 24, + 36, ], shorthand: false, type: "Property", value: { range: [ - 31, - 37, + 30, + 36, ], raw: "'json'", type: "Literal", @@ -3740,27 +3740,27 @@ snapshot[`Plugin - ImportExpression 1`] = ` }, ], range: [ - 23, - 39, + 22, + 38, ], type: "ObjectExpression", }, }, ], range: [ - 15, - 41, + 14, + 40, ], type: "ObjectExpression", }, range: [ - 1, - 42, + 0, + 41, ], source: { range: [ - 8, - 13, + 7, + 12, ], raw: "'foo'", type: "Literal", @@ -3776,23 +3776,23 @@ snapshot[`Plugin - LogicalExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "&&", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -3807,23 +3807,23 @@ snapshot[`Plugin - LogicalExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "||", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -3838,23 +3838,23 @@ snapshot[`Plugin - LogicalExpression 3`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, operator: "??", range: [ - 1, - 7, + 0, + 6, ], right: { name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -3870,8 +3870,8 @@ snapshot[`Plugin - MemberExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -3881,15 +3881,15 @@ snapshot[`Plugin - MemberExpression 1`] = ` name: "b", optional: false, range: [ + 2, 3, - 4, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 4, + 0, + 3, ], type: "MemberExpression", } @@ -3902,8 +3902,8 @@ snapshot[`Plugin - MemberExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -3911,16 +3911,16 @@ snapshot[`Plugin - MemberExpression 2`] = ` optional: false, property: { range: [ - 3, - 6, + 2, + 5, ], raw: "'b'", type: "Literal", value: "b", }, range: [ - 1, - 7, + 0, + 6, ], type: "MemberExpression", } @@ -3932,15 +3932,15 @@ snapshot[`Plugin - MetaProperty 1`] = ` name: "meta", optional: false, range: [ - 1, - 12, + 0, + 11, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "MetaProperty", } @@ -3953,15 +3953,15 @@ snapshot[`Plugin - NewExpression 1`] = ` name: "Foo", optional: false, range: [ - 5, - 8, + 4, + 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 10, + 0, + 9, ], type: "NewExpression", typeArguments: null, @@ -3975,8 +3975,8 @@ snapshot[`Plugin - NewExpression 2`] = ` name: "a", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, @@ -3986,15 +3986,15 @@ snapshot[`Plugin - NewExpression 2`] = ` name: "b", optional: false, range: [ + 17, 18, - 19, ], type: "Identifier", typeAnnotation: null, }, range: [ - 15, - 18, + 14, + 17, ], type: "SpreadElement", }, @@ -4003,23 +4003,23 @@ snapshot[`Plugin - NewExpression 2`] = ` name: "Foo", optional: false, range: [ - 5, - 8, + 4, + 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 20, + 0, + 19, ], type: "NewExpression", typeArguments: { params: [ { range: [ + 8, 9, - 10, ], type: "TSTypeReference", typeArguments: null, @@ -4027,8 +4027,8 @@ snapshot[`Plugin - NewExpression 2`] = ` name: "T", optional: false, range: [ + 8, 9, - 10, ], type: "Identifier", typeAnnotation: null, @@ -4036,8 +4036,8 @@ snapshot[`Plugin - NewExpression 2`] = ` }, ], range: [ - 8, - 11, + 7, + 10, ], type: "TSTypeParameterInstantiation", }, @@ -4048,8 +4048,8 @@ snapshot[`Plugin - ObjectExpression 1`] = ` { properties: [], range: [ - 5, - 7, + 4, + 6, ], type: "ObjectExpression", } @@ -4064,8 +4064,8 @@ snapshot[`Plugin - ObjectExpression 2`] = ` name: "a", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -4073,8 +4073,8 @@ snapshot[`Plugin - ObjectExpression 2`] = ` kind: "init", method: false, range: [ + 6, 7, - 8, ], shorthand: true, type: "Property", @@ -4082,8 +4082,8 @@ snapshot[`Plugin - ObjectExpression 2`] = ` name: "a", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -4091,8 +4091,8 @@ snapshot[`Plugin - ObjectExpression 2`] = ` }, ], range: [ - 5, - 10, + 4, + 9, ], type: "ObjectExpression", } @@ -4107,8 +4107,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` name: "b", optional: false, range: [ + 6, 7, - 8, ], type: "Identifier", typeAnnotation: null, @@ -4116,8 +4116,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` kind: "init", method: false, range: [ - 7, - 11, + 6, + 10, ], shorthand: false, type: "Property", @@ -4125,8 +4125,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` name: "c", optional: false, range: [ + 9, 10, - 11, ], type: "Identifier", typeAnnotation: null, @@ -4138,8 +4138,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` name: "c", optional: false, range: [ + 13, 14, - 15, ], type: "Identifier", typeAnnotation: null, @@ -4147,8 +4147,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` kind: "init", method: false, range: [ - 13, - 19, + 12, + 18, ], shorthand: false, type: "Property", @@ -4156,8 +4156,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` name: "d", optional: false, range: [ + 17, 18, - 19, ], type: "Identifier", typeAnnotation: null, @@ -4165,8 +4165,8 @@ snapshot[`Plugin - ObjectExpression 3`] = ` }, ], range: [ - 5, - 21, + 4, + 20, ], type: "ObjectExpression", } @@ -4176,8 +4176,8 @@ snapshot[`Plugin - PrivateIdentifier 1`] = ` { name: "foo", range: [ - 13, - 17, + 12, + 16, ], type: "PrivateIdentifier", } @@ -4190,8 +4190,8 @@ snapshot[`Plugin - SequenceExpression 1`] = ` name: "a", optional: false, range: [ + 1, 2, - 3, ], type: "Identifier", typeAnnotation: null, @@ -4200,16 +4200,16 @@ snapshot[`Plugin - SequenceExpression 1`] = ` name: "b", optional: false, range: [ + 4, 5, - 6, ], type: "Identifier", typeAnnotation: null, }, ], range: [ - 2, - 6, + 1, + 5, ], type: "SequenceExpression", } @@ -4218,8 +4218,8 @@ snapshot[`Plugin - SequenceExpression 1`] = ` snapshot[`Plugin - Super 1`] = ` { range: [ - 41, - 46, + 40, + 45, ], type: "Super", } @@ -4233,8 +4233,8 @@ snapshot[`Plugin - TaggedTemplateExpression 1`] = ` name: "bar", optional: false, range: [ - 11, - 14, + 10, + 13, ], type: "Identifier", typeAnnotation: null, @@ -4244,8 +4244,8 @@ snapshot[`Plugin - TaggedTemplateExpression 1`] = ` { cooked: "foo ", range: [ - 5, - 9, + 4, + 8, ], raw: "foo ", tail: false, @@ -4254,8 +4254,8 @@ snapshot[`Plugin - TaggedTemplateExpression 1`] = ` { cooked: " baz", range: [ - 15, - 19, + 14, + 18, ], raw: " baz", tail: true, @@ -4263,21 +4263,21 @@ snapshot[`Plugin - TaggedTemplateExpression 1`] = ` }, ], range: [ - 4, - 20, + 3, + 19, ], type: "TemplateLiteral", }, range: [ - 1, - 20, + 0, + 19, ], tag: { name: "foo", optional: false, range: [ - 1, - 4, + 0, + 3, ], type: "Identifier", typeAnnotation: null, @@ -4294,8 +4294,8 @@ snapshot[`Plugin - TemplateLiteral 1`] = ` name: "bar", optional: false, range: [ - 8, - 11, + 7, + 10, ], type: "Identifier", typeAnnotation: null, @@ -4305,8 +4305,8 @@ snapshot[`Plugin - TemplateLiteral 1`] = ` { cooked: "foo ", range: [ - 2, - 6, + 1, + 5, ], raw: "foo ", tail: false, @@ -4315,8 +4315,8 @@ snapshot[`Plugin - TemplateLiteral 1`] = ` { cooked: " baz", range: [ - 12, - 16, + 11, + 15, ], raw: " baz", tail: true, @@ -4324,8 +4324,8 @@ snapshot[`Plugin - TemplateLiteral 1`] = ` }, ], range: [ - 1, - 17, + 0, + 16, ], type: "TemplateLiteral", } @@ -4334,8 +4334,8 @@ snapshot[`Plugin - TemplateLiteral 1`] = ` snapshot[`Plugin - ThisExpression 1`] = ` { range: [ - 1, - 5, + 0, + 4, ], type: "ThisExpression", } @@ -4347,21 +4347,21 @@ snapshot[`Plugin - TSAsExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 7, + 0, + 6, ], type: "TSAsExpression", typeAnnotation: { range: [ + 5, 6, - 7, ], type: "TSTypeReference", typeArguments: null, @@ -4369,8 +4369,8 @@ snapshot[`Plugin - TSAsExpression 1`] = ` name: "b", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -4385,21 +4385,21 @@ snapshot[`Plugin - TSAsExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 11, + 0, + 10, ], type: "TSAsExpression", typeAnnotation: { range: [ - 1, - 11, + 0, + 10, ], type: "TSTypeReference", typeArguments: null, @@ -4407,8 +4407,8 @@ snapshot[`Plugin - TSAsExpression 2`] = ` name: "const", optional: false, range: [ - 1, - 11, + 0, + 10, ], type: "Identifier", typeAnnotation: null, @@ -4423,15 +4423,15 @@ snapshot[`Plugin - TSNonNullExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 3, + 0, + 2, ], type: "TSNonNullExpression", } @@ -4443,21 +4443,21 @@ snapshot[`Plugin - TSSatisfiesExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "TSSatisfiesExpression", typeAnnotation: { range: [ + 12, 13, - 14, ], type: "TSTypeReference", typeArguments: null, @@ -4465,8 +4465,8 @@ snapshot[`Plugin - TSSatisfiesExpression 1`] = ` name: "b", optional: false, range: [ + 12, 13, - 14, ], type: "Identifier", typeAnnotation: null, @@ -4481,16 +4481,16 @@ snapshot[`Plugin - UnaryExpression 1`] = ` name: "a", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, }, operator: "typeof", range: [ - 1, - 9, + 0, + 8, ], type: "UnaryExpression", } @@ -4500,8 +4500,8 @@ snapshot[`Plugin - UnaryExpression 2`] = ` { argument: { range: [ + 5, 6, - 7, ], raw: "0", type: "Literal", @@ -4509,8 +4509,8 @@ snapshot[`Plugin - UnaryExpression 2`] = ` }, operator: "void", range: [ - 1, - 7, + 0, + 6, ], type: "UnaryExpression", } @@ -4522,16 +4522,16 @@ snapshot[`Plugin - UnaryExpression 3`] = ` name: "a", optional: false, range: [ + 1, 2, - 3, ], type: "Identifier", typeAnnotation: null, }, operator: "-", range: [ - 1, - 3, + 0, + 2, ], type: "UnaryExpression", } @@ -4543,16 +4543,16 @@ snapshot[`Plugin - UnaryExpression 4`] = ` name: "a", optional: false, range: [ + 1, 2, - 3, ], type: "Identifier", typeAnnotation: null, }, operator: "+", range: [ - 1, - 3, + 0, + 2, ], type: "UnaryExpression", } @@ -4564,8 +4564,8 @@ snapshot[`Plugin - UpdateExpression 1`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -4573,8 +4573,8 @@ snapshot[`Plugin - UpdateExpression 1`] = ` operator: "++", prefix: false, range: [ - 1, - 4, + 0, + 3, ], type: "UpdateExpression", } @@ -4586,8 +4586,8 @@ snapshot[`Plugin - UpdateExpression 2`] = ` name: "a", optional: false, range: [ + 2, 3, - 4, ], type: "Identifier", typeAnnotation: null, @@ -4595,8 +4595,8 @@ snapshot[`Plugin - UpdateExpression 2`] = ` operator: "++", prefix: true, range: [ - 1, - 4, + 0, + 3, ], type: "UpdateExpression", } @@ -4608,8 +4608,8 @@ snapshot[`Plugin - UpdateExpression 3`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, @@ -4617,8 +4617,8 @@ snapshot[`Plugin - UpdateExpression 3`] = ` operator: "--", prefix: false, range: [ - 1, - 4, + 0, + 3, ], type: "UpdateExpression", } @@ -4630,8 +4630,8 @@ snapshot[`Plugin - UpdateExpression 4`] = ` name: "a", optional: false, range: [ + 2, 3, - 4, ], type: "Identifier", typeAnnotation: null, @@ -4639,8 +4639,8 @@ snapshot[`Plugin - UpdateExpression 4`] = ` operator: "--", prefix: true, range: [ - 1, - 4, + 0, + 3, ], type: "UpdateExpression", } @@ -4652,16 +4652,16 @@ snapshot[`Plugin - YieldExpression 1`] = ` name: "bar", optional: false, range: [ - 25, - 28, + 24, + 27, ], type: "Identifier", typeAnnotation: null, }, delegate: false, range: [ - 19, - 28, + 18, + 27, ], type: "YieldExpression", } @@ -4670,8 +4670,8 @@ snapshot[`Plugin - YieldExpression 1`] = ` snapshot[`Plugin - Literal 1`] = ` { range: [ + 0, 1, - 2, ], raw: "1", type: "Literal", @@ -4682,8 +4682,8 @@ snapshot[`Plugin - Literal 1`] = ` snapshot[`Plugin - Literal 2`] = ` { range: [ - 1, - 6, + 0, + 5, ], raw: "'foo'", type: "Literal", @@ -4694,8 +4694,8 @@ snapshot[`Plugin - Literal 2`] = ` snapshot[`Plugin - Literal 3`] = ` { range: [ - 1, - 6, + 0, + 5, ], raw: '"foo"', type: "Literal", @@ -4706,8 +4706,8 @@ snapshot[`Plugin - Literal 3`] = ` snapshot[`Plugin - Literal 4`] = ` { range: [ - 1, - 5, + 0, + 4, ], raw: "true", type: "Literal", @@ -4718,8 +4718,8 @@ snapshot[`Plugin - Literal 4`] = ` snapshot[`Plugin - Literal 5`] = ` { range: [ - 1, - 6, + 0, + 5, ], raw: "false", type: "Literal", @@ -4730,8 +4730,8 @@ snapshot[`Plugin - Literal 5`] = ` snapshot[`Plugin - Literal 6`] = ` { range: [ - 1, - 5, + 0, + 4, ], raw: "null", type: "Literal", @@ -4743,8 +4743,8 @@ snapshot[`Plugin - Literal 7`] = ` { bigint: "1", range: [ - 1, - 3, + 0, + 2, ], raw: "1n", type: "Literal", @@ -4755,8 +4755,8 @@ snapshot[`Plugin - Literal 7`] = ` snapshot[`Plugin - Literal 8`] = ` { range: [ - 1, - 7, + 0, + 6, ], raw: "/foo/g", regex: { @@ -4777,22 +4777,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 8, + 0, + 7, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 8, + 0, + 7, ], type: "JSXElement", } @@ -4805,14 +4805,14 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 8, - 11, + 7, + 10, ], type: "JSXIdentifier", }, range: [ - 6, - 12, + 5, + 11, ], type: "JSXClosingElement", }, @@ -4821,22 +4821,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 6, + 0, + 5, ], selfClosing: false, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "JSXElement", } @@ -4849,14 +4849,14 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 10, - 13, + 9, + 12, ], type: "JSXIdentifier", }, range: [ - 8, - 14, + 7, + 13, ], type: "JSXClosingElement", }, @@ -4866,14 +4866,14 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "a", range: [ + 5, 6, - 7, ], type: "JSXIdentifier", }, range: [ + 5, 6, - 7, ], type: "JSXAttribute", value: null, @@ -4882,22 +4882,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 8, + 0, + 7, ], selfClosing: false, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "JSXElement", } @@ -4913,20 +4913,20 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "a", range: [ + 5, 6, - 7, ], type: "JSXIdentifier", }, range: [ - 6, - 11, + 5, + 10, ], type: "JSXAttribute", value: { range: [ - 8, - 11, + 7, + 10, ], raw: '"b"', type: "Literal", @@ -4937,22 +4937,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 14, + 0, + 13, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "JSXElement", } @@ -4968,29 +4968,29 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "a", range: [ + 5, 6, - 7, ], type: "JSXIdentifier", }, range: [ - 6, - 11, + 5, + 10, ], type: "JSXAttribute", value: { expression: { range: [ + 8, 9, - 10, ], raw: "2", type: "Literal", value: 2, }, range: [ - 8, - 11, + 7, + 10, ], type: "JSXExpressionContainer", }, @@ -4999,22 +4999,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 14, + 0, + 13, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 14, + 0, + 13, ], type: "JSXElement", } @@ -5025,8 +5025,8 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr children: [ { range: [ - 6, - 9, + 5, + 8, ], raw: "foo", type: "JSXText", @@ -5035,16 +5035,16 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr { expression: { range: [ + 9, 10, - 11, ], raw: "2", type: "Literal", value: 2, }, range: [ - 9, - 12, + 8, + 11, ], type: "JSXExpressionContainer", }, @@ -5053,14 +5053,14 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 14, - 17, + 13, + 16, ], type: "JSXIdentifier", }, range: [ - 12, - 18, + 11, + 17, ], type: "JSXClosingElement", }, @@ -5069,22 +5069,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 6, + 0, + 5, ], selfClosing: false, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 18, + 0, + 17, ], type: "JSXElement", } @@ -5100,36 +5100,36 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr object: { name: "a", range: [ + 1, 2, - 3, ], type: "JSXIdentifier", }, property: { name: "b", range: [ + 3, 4, - 5, ], type: "JSXIdentifier", }, range: [ - 2, - 5, + 1, + 4, ], type: "JSXMemberExpression", }, range: [ - 1, - 8, + 0, + 7, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 8, + 0, + 7, ], type: "JSXElement", } @@ -5146,43 +5146,43 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "b", range: [ + 7, 8, - 9, ], type: "JSXIdentifier", }, namespace: { name: "a", range: [ + 5, 6, - 7, ], type: "JSXIdentifier", }, range: [ - 6, - 9, + 5, + 8, ], type: "JSXNamespacedName", }, range: [ - 6, - 13, + 5, + 12, ], type: "JSXAttribute", value: { expression: { range: [ + 10, 11, - 12, ], raw: "2", type: "Literal", value: 2, }, range: [ - 10, - 13, + 9, + 12, ], type: "JSXExpressionContainer", }, @@ -5191,22 +5191,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "div", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 16, + 0, + 15, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 16, + 0, + 15, ], type: "JSXElement", } @@ -5221,22 +5221,22 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "Foo", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 8, + 0, + 7, ], selfClosing: true, type: "JSXOpeningElement", typeArguments: null, }, range: [ - 1, - 8, + 0, + 7, ], type: "JSXElement", } @@ -5251,14 +5251,14 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: { name: "Foo", range: [ - 2, - 5, + 1, + 4, ], type: "JSXIdentifier", }, range: [ - 1, - 11, + 0, + 10, ], selfClosing: true, type: "JSXOpeningElement", @@ -5266,8 +5266,8 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr params: [ { range: [ + 5, 6, - 7, ], type: "TSTypeReference", typeArguments: null, @@ -5275,8 +5275,8 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr name: "T", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, @@ -5284,15 +5284,15 @@ snapshot[`Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr }, ], range: [ - 5, - 8, + 4, + 7, ], type: "TSTypeParameterInstantiation", }, }, range: [ - 1, - 11, + 0, + 10, ], type: "JSXElement", } @@ -5303,21 +5303,21 @@ snapshot[`Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment 1`] = ` children: [], closingFragment: { range: [ - 3, - 6, + 2, + 5, ], type: "JSXClosingFragment", }, openingFragment: { range: [ - 1, - 3, + 0, + 2, ], type: "JSXOpeningFragment", }, range: [ - 1, - 6, + 0, + 5, ], type: "JSXFragment", } @@ -5328,8 +5328,8 @@ snapshot[`Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment 2`] = ` children: [ { range: [ - 3, - 6, + 2, + 5, ], raw: "foo", type: "JSXText", @@ -5338,37 +5338,37 @@ snapshot[`Plugin - JSXFragment + JSXOpeningFragment + JSXClosingFragment 2`] = ` { expression: { range: [ + 6, 7, - 8, ], raw: "2", type: "Literal", value: 2, }, range: [ - 6, - 9, + 5, + 8, ], type: "JSXExpressionContainer", }, ], closingFragment: { range: [ - 9, - 12, + 8, + 11, ], type: "JSXClosingFragment", }, openingFragment: { range: [ - 1, - 3, + 0, + 2, ], type: "JSXOpeningFragment", }, range: [ - 1, - 12, + 0, + 11, ], type: "JSXFragment", } @@ -5380,21 +5380,21 @@ snapshot[`Plugin - TSAsExpression 3`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 9, + 0, + 8, ], type: "TSAsExpression", typeAnnotation: { range: [ - 6, - 9, + 5, + 8, ], type: "TSAnyKeyword", }, @@ -5405,22 +5405,22 @@ snapshot[`Plugin - TSAsExpression 4`] = ` { expression: { range: [ - 1, - 6, + 0, + 5, ], raw: '"foo"', type: "Literal", value: "foo", }, range: [ - 1, - 15, + 0, + 14, ], type: "TSAsExpression", typeAnnotation: { range: [ - 1, - 15, + 0, + 14, ], type: "TSTypeReference", typeArguments: null, @@ -5428,8 +5428,8 @@ snapshot[`Plugin - TSAsExpression 4`] = ` name: "const", optional: false, range: [ - 1, - 15, + 0, + 14, ], type: "Identifier", typeAnnotation: null, @@ -5443,8 +5443,8 @@ snapshot[`Plugin - TSEnumDeclaration 1`] = ` body: { members: [], range: [ - 1, - 12, + 0, + 11, ], type: "TSEnumBody", }, @@ -5454,15 +5454,15 @@ snapshot[`Plugin - TSEnumDeclaration 1`] = ` name: "Foo", optional: false, range: [ - 6, - 9, + 5, + 8, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "TSEnumDeclaration", } @@ -5473,8 +5473,8 @@ snapshot[`Plugin - TSEnumDeclaration 2`] = ` body: { members: [], range: [ - 1, - 18, + 0, + 17, ], type: "TSEnumBody", }, @@ -5484,15 +5484,15 @@ snapshot[`Plugin - TSEnumDeclaration 2`] = ` name: "Foo", optional: false, range: [ - 12, - 15, + 11, + 14, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 18, + 0, + 17, ], type: "TSEnumDeclaration", } @@ -5507,16 +5507,16 @@ snapshot[`Plugin - TSEnumDeclaration 3`] = ` name: "A", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, }, initializer: null, range: [ + 11, 12, - 13, ], type: "TSEnumMember", }, @@ -5525,23 +5525,23 @@ snapshot[`Plugin - TSEnumDeclaration 3`] = ` name: "B", optional: false, range: [ + 14, 15, - 16, ], type: "Identifier", typeAnnotation: null, }, initializer: null, range: [ + 14, 15, - 16, ], type: "TSEnumMember", }, ], range: [ - 1, - 18, + 0, + 17, ], type: "TSEnumBody", }, @@ -5551,15 +5551,15 @@ snapshot[`Plugin - TSEnumDeclaration 3`] = ` name: "Foo", optional: false, range: [ - 6, - 9, + 5, + 8, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 18, + 0, + 17, ], type: "TSEnumDeclaration", } @@ -5572,8 +5572,8 @@ snapshot[`Plugin - TSEnumDeclaration 4`] = ` { id: { range: [ - 12, - 17, + 11, + 16, ], raw: '"a-b"', type: "Literal", @@ -5581,15 +5581,15 @@ snapshot[`Plugin - TSEnumDeclaration 4`] = ` }, initializer: null, range: [ - 12, - 17, + 11, + 16, ], type: "TSEnumMember", }, ], range: [ - 1, - 19, + 0, + 18, ], type: "TSEnumBody", }, @@ -5599,15 +5599,15 @@ snapshot[`Plugin - TSEnumDeclaration 4`] = ` name: "Foo", optional: false, range: [ - 6, - 9, + 5, + 8, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 19, + 0, + 18, ], type: "TSEnumDeclaration", } @@ -5622,24 +5622,24 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` name: "A", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, }, initializer: { range: [ + 15, 16, - 17, ], raw: "1", type: "Literal", value: 1, }, range: [ - 12, - 17, + 11, + 16, ], type: "TSEnumMember", }, @@ -5648,24 +5648,24 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` name: "B", optional: false, range: [ + 18, 19, - 20, ], type: "Identifier", typeAnnotation: null, }, initializer: { range: [ + 22, 23, - 24, ], raw: "2", type: "Literal", value: 2, }, range: [ - 19, - 24, + 18, + 23, ], type: "TSEnumMember", }, @@ -5674,8 +5674,8 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` name: "C", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: null, @@ -5685,23 +5685,23 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` name: "A", optional: false, range: [ + 29, 30, - 31, ], type: "Identifier", typeAnnotation: null, }, operator: "|", range: [ - 30, - 35, + 29, + 34, ], right: { name: "B", optional: false, range: [ + 33, 34, - 35, ], type: "Identifier", typeAnnotation: null, @@ -5709,15 +5709,15 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` type: "BinaryExpression", }, range: [ - 26, - 35, + 25, + 34, ], type: "TSEnumMember", }, ], range: [ - 1, - 37, + 0, + 36, ], type: "TSEnumBody", }, @@ -5727,15 +5727,15 @@ snapshot[`Plugin - TSEnumDeclaration 5`] = ` name: "Foo", optional: false, range: [ - 6, - 9, + 5, + 8, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 37, + 0, + 36, ], type: "TSEnumDeclaration", } @@ -5746,8 +5746,8 @@ snapshot[`Plugin - TSInterface 1`] = ` body: { body: [], range: [ - 13, - 15, + 12, + 14, ], type: "TSInterfaceBody", }, @@ -5757,15 +5757,15 @@ snapshot[`Plugin - TSInterface 1`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 15, + 0, + 14, ], type: "TSInterface", typeParameters: [], @@ -5777,8 +5777,8 @@ snapshot[`Plugin - TSInterface 2`] = ` body: { body: [], range: [ - 16, - 18, + 15, + 17, ], type: "TSInterfaceBody", }, @@ -5794,23 +5794,23 @@ snapshot[`Plugin - TSInterface 2`] = ` name: "T", optional: false, range: [ + 12, 13, - 14, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 12, 13, - 14, ], type: "TSTypeParameter", }, ], range: [ - 12, - 15, + 11, + 14, ], type: "TSTypeParameterDeclaration", }, @@ -5818,15 +5818,15 @@ snapshot[`Plugin - TSInterface 2`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 18, + 0, + 17, ], type: "TSInterface", typeParameters: [], @@ -5838,8 +5838,8 @@ snapshot[`Plugin - TSInterface 3`] = ` body: { body: [], range: [ - 36, - 38, + 35, + 37, ], type: "TSInterfaceBody", }, @@ -5849,15 +5849,15 @@ snapshot[`Plugin - TSInterface 3`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 38, + 0, + 37, ], type: "TSInterface", typeParameters: [ @@ -5866,23 +5866,23 @@ snapshot[`Plugin - TSInterface 3`] = ` name: "Foo", optional: false, range: [ - 21, - 24, + 20, + 23, ], type: "Identifier", typeAnnotation: null, }, range: [ - 21, - 27, + 20, + 26, ], type: "TSInterfaceHeritage", typeArguments: { params: [ { range: [ + 24, 25, - 26, ], type: "TSTypeReference", typeArguments: null, @@ -5890,8 +5890,8 @@ snapshot[`Plugin - TSInterface 3`] = ` name: "T", optional: false, range: [ + 24, 25, - 26, ], type: "Identifier", typeAnnotation: null, @@ -5899,8 +5899,8 @@ snapshot[`Plugin - TSInterface 3`] = ` }, ], range: [ - 24, - 27, + 23, + 26, ], type: "TSTypeParameterInstantiation", }, @@ -5910,23 +5910,23 @@ snapshot[`Plugin - TSInterface 3`] = ` name: "Bar", optional: false, range: [ - 29, - 32, + 28, + 31, ], type: "Identifier", typeAnnotation: null, }, range: [ - 29, - 35, + 28, + 34, ], type: "TSInterfaceHeritage", typeArguments: { params: [ { range: [ + 32, 33, - 34, ], type: "TSTypeReference", typeArguments: null, @@ -5934,8 +5934,8 @@ snapshot[`Plugin - TSInterface 3`] = ` name: "T", optional: false, range: [ + 32, 33, - 34, ], type: "Identifier", typeAnnotation: null, @@ -5943,9 +5943,9 @@ snapshot[`Plugin - TSInterface 3`] = ` }, ], range: [ - 32, - 35, - ], + 31, + 34, + ], type: "TSTypeParameterInstantiation", }, }, @@ -5963,30 +5963,30 @@ snapshot[`Plugin - TSInterface 4`] = ` name: "foo", optional: false, range: [ - 15, - 18, + 14, + 17, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 15, - 24, + 14, + 23, ], readonly: false, static: false, type: "TSPropertySignature", typeAnnotation: { range: [ - 18, - 23, + 17, + 22, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 20, - 23, + 19, + 22, ], type: "TSAnyKeyword", }, @@ -5998,30 +5998,30 @@ snapshot[`Plugin - TSInterface 4`] = ` name: "bar", optional: false, range: [ - 25, - 28, + 24, + 27, ], type: "Identifier", typeAnnotation: null, }, optional: true, range: [ - 25, - 34, + 24, + 33, ], readonly: false, static: false, type: "TSPropertySignature", typeAnnotation: { range: [ - 29, - 34, + 28, + 33, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 31, - 34, + 30, + 33, ], type: "TSAnyKeyword", }, @@ -6029,8 +6029,8 @@ snapshot[`Plugin - TSInterface 4`] = ` }, ], range: [ - 13, - 36, + 12, + 35, ], type: "TSInterfaceBody", }, @@ -6040,15 +6040,15 @@ snapshot[`Plugin - TSInterface 4`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 36, + 0, + 35, ], type: "TSInterface", typeParameters: [], @@ -6065,20 +6065,20 @@ snapshot[`Plugin - TSInterface 5`] = ` name: "key", optional: false, range: [ - 25, - 36, + 24, + 35, ], type: "Identifier", typeAnnotation: { range: [ - 28, - 36, + 27, + 35, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 30, - 36, + 29, + 35, ], type: "TSStringKeyword", }, @@ -6086,21 +6086,21 @@ snapshot[`Plugin - TSInterface 5`] = ` }, ], range: [ - 15, - 42, + 14, + 41, ], readonly: true, type: "TSIndexSignature", typeAnnotation: { range: [ - 37, - 42, + 36, + 41, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 39, - 42, + 38, + 41, ], type: "TSAnyKeyword", }, @@ -6108,8 +6108,8 @@ snapshot[`Plugin - TSInterface 5`] = ` }, ], range: [ - 13, - 44, + 12, + 43, ], type: "TSInterfaceBody", }, @@ -6119,15 +6119,15 @@ snapshot[`Plugin - TSInterface 5`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 44, + 0, + 43, ], type: "TSInterface", typeParameters: [], @@ -6144,30 +6144,30 @@ snapshot[`Plugin - TSInterface 6`] = ` name: "a", optional: false, range: [ + 23, 24, - 25, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 15, - 30, + 14, + 29, ], readonly: true, static: false, type: "TSPropertySignature", typeAnnotation: { range: [ - 25, - 30, + 24, + 29, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 27, - 30, + 26, + 29, ], type: "TSAnyKeyword", }, @@ -6175,8 +6175,8 @@ snapshot[`Plugin - TSInterface 6`] = ` }, ], range: [ - 13, - 32, + 12, + 31, ], type: "TSInterfaceBody", }, @@ -6186,15 +6186,15 @@ snapshot[`Plugin - TSInterface 6`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 32, + 0, + 31, ], type: "TSInterface", typeParameters: [], @@ -6211,20 +6211,20 @@ snapshot[`Plugin - TSInterface 7`] = ` name: "a", optional: false, range: [ + 18, 19, - 20, ], type: "Identifier", typeAnnotation: { range: [ - 20, - 23, + 19, + 22, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 21, 22, - 23, ], type: "TSTypeReference", typeArguments: null, @@ -6232,8 +6232,8 @@ snapshot[`Plugin - TSInterface 7`] = ` name: "T", optional: false, range: [ + 21, 22, - 23, ], type: "Identifier", typeAnnotation: null, @@ -6243,19 +6243,19 @@ snapshot[`Plugin - TSInterface 7`] = ` }, ], range: [ - 15, - 27, + 14, + 26, ], returnType: { range: [ - 24, - 27, + 23, + 26, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 25, 26, - 27, ], type: "TSTypeReference", typeArguments: null, @@ -6263,8 +6263,8 @@ snapshot[`Plugin - TSInterface 7`] = ` name: "T", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: null, @@ -6283,31 +6283,31 @@ snapshot[`Plugin - TSInterface 7`] = ` name: "T", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 15, 16, - 17, ], type: "TSTypeParameter", }, ], range: [ - 15, - 18, + 14, + 17, ], type: "TSTypeParameterDeclaration", }, }, ], range: [ - 13, - 29, + 12, + 28, ], type: "TSInterfaceBody", }, @@ -6317,15 +6317,15 @@ snapshot[`Plugin - TSInterface 7`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 29, + 0, + 28, ], type: "TSInterface", typeParameters: [], @@ -6342,20 +6342,20 @@ snapshot[`Plugin - TSInterface 8`] = ` name: "a", optional: false, range: [ + 22, 23, - 24, ], type: "Identifier", typeAnnotation: { range: [ - 24, - 27, + 23, + 26, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 25, 26, - 27, ], type: "TSTypeReference", typeArguments: null, @@ -6363,8 +6363,8 @@ snapshot[`Plugin - TSInterface 8`] = ` name: "T", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: null, @@ -6374,19 +6374,19 @@ snapshot[`Plugin - TSInterface 8`] = ` }, ], range: [ - 15, - 31, + 14, + 30, ], returnType: { range: [ - 28, - 31, + 27, + 30, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 29, 30, - 31, ], type: "TSTypeReference", typeArguments: null, @@ -6394,8 +6394,8 @@ snapshot[`Plugin - TSInterface 8`] = ` name: "T", optional: false, range: [ + 29, 30, - 31, ], type: "Identifier", typeAnnotation: null, @@ -6414,31 +6414,31 @@ snapshot[`Plugin - TSInterface 8`] = ` name: "T", optional: false, range: [ + 19, 20, - 21, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 19, 20, - 21, ], type: "TSTypeParameter", }, ], range: [ - 19, - 22, + 18, + 21, ], type: "TSTypeParameterDeclaration", }, }, ], range: [ - 13, - 33, + 12, + 32, ], type: "TSInterfaceBody", }, @@ -6448,15 +6448,15 @@ snapshot[`Plugin - TSInterface 8`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 33, + 0, + 32, ], type: "TSInterface", typeParameters: [], @@ -6473,24 +6473,24 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "a", optional: false, range: [ + 14, 15, - 16, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 15, - 36, + 14, + 35, ], readonly: false, static: false, type: "TSPropertySignature", typeAnnotation: { range: [ - 16, - 36, + 15, + 35, ], type: "TSTypeAnnotation", typeAnnotation: { @@ -6499,20 +6499,20 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "a", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: { range: [ - 27, - 30, + 26, + 29, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 28, 29, - 30, ], type: "TSTypeReference", typeArguments: null, @@ -6520,8 +6520,8 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "T", optional: false, range: [ + 28, 29, - 30, ], type: "Identifier", typeAnnotation: null, @@ -6531,19 +6531,19 @@ snapshot[`Plugin - TSInterface 9`] = ` }, ], range: [ - 18, - 36, + 17, + 35, ], returnType: { range: [ - 32, - 36, + 31, + 35, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ + 34, 35, - 36, ], type: "TSTypeReference", typeArguments: null, @@ -6551,8 +6551,8 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "T", optional: false, range: [ + 34, 35, - 36, ], type: "Identifier", typeAnnotation: null, @@ -6571,23 +6571,23 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "T", optional: false, range: [ + 22, 23, - 24, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 22, 23, - 24, ], type: "TSTypeParameter", }, ], range: [ - 22, - 25, + 21, + 24, ], type: "TSTypeParameterDeclaration", }, @@ -6596,8 +6596,8 @@ snapshot[`Plugin - TSInterface 9`] = ` }, ], range: [ - 13, - 38, + 12, + 37, ], type: "TSInterfaceBody", }, @@ -6607,15 +6607,15 @@ snapshot[`Plugin - TSInterface 9`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 38, + 0, + 37, ], type: "TSInterface", typeParameters: [], @@ -6632,8 +6632,8 @@ snapshot[`Plugin - TSInterface 10`] = ` name: "a", optional: false, range: [ + 18, 19, - 20, ], type: "Identifier", typeAnnotation: null, @@ -6641,20 +6641,20 @@ snapshot[`Plugin - TSInterface 10`] = ` kind: "getter", optional: false, range: [ - 15, - 30, + 14, + 29, ], readonly: false, returnType: { range: [ - 22, - 30, + 21, + 29, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 24, - 30, + 23, + 29, ], type: "TSStringKeyword", }, @@ -6664,8 +6664,8 @@ snapshot[`Plugin - TSInterface 10`] = ` }, ], range: [ - 13, - 32, + 12, + 31, ], type: "TSInterfaceBody", }, @@ -6675,15 +6675,15 @@ snapshot[`Plugin - TSInterface 10`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 32, + 0, + 31, ], type: "TSInterface", typeParameters: [], @@ -6700,8 +6700,8 @@ snapshot[`Plugin - TSInterface 11`] = ` name: "a", optional: false, range: [ + 18, 19, - 20, ], type: "Identifier", typeAnnotation: null, @@ -6713,20 +6713,20 @@ snapshot[`Plugin - TSInterface 11`] = ` name: "v", optional: false, range: [ + 20, 21, - 22, ], type: "Identifier", typeAnnotation: { range: [ - 22, - 30, + 21, + 29, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 24, - 30, + 23, + 29, ], type: "TSStringKeyword", }, @@ -6734,8 +6734,8 @@ snapshot[`Plugin - TSInterface 11`] = ` }, ], range: [ - 15, - 31, + 14, + 30, ], readonly: false, static: false, @@ -6743,8 +6743,8 @@ snapshot[`Plugin - TSInterface 11`] = ` }, ], range: [ - 13, - 33, + 12, + 32, ], type: "TSInterfaceBody", }, @@ -6754,15 +6754,15 @@ snapshot[`Plugin - TSInterface 11`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 33, + 0, + 32, ], type: "TSInterface", typeParameters: [], @@ -6779,8 +6779,8 @@ snapshot[`Plugin - TSInterface 12`] = ` name: "a", optional: false, range: [ + 14, 15, - 16, ], type: "Identifier", typeAnnotation: null, @@ -6792,20 +6792,20 @@ snapshot[`Plugin - TSInterface 12`] = ` name: "arg", optional: true, range: [ - 20, - 23, + 19, + 22, ], type: "Identifier", typeAnnotation: { range: [ - 24, - 29, + 23, + 28, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 26, - 29, + 25, + 28, ], type: "TSAnyKeyword", }, @@ -6816,34 +6816,34 @@ snapshot[`Plugin - TSInterface 12`] = ` name: "args", optional: false, range: [ - 34, - 38, + 33, + 37, ], type: "Identifier", typeAnnotation: null, }, range: [ - 31, - 45, + 30, + 44, ], type: "RestElement", typeAnnotation: { range: [ - 38, - 45, + 37, + 44, ], type: "TSTypeAnnotation", typeAnnotation: { elementType: { range: [ - 40, - 43, + 39, + 42, ], type: "TSAnyKeyword", }, range: [ - 40, - 45, + 39, + 44, ], type: "TSArrayType", }, @@ -6851,20 +6851,20 @@ snapshot[`Plugin - TSInterface 12`] = ` }, ], range: [ - 15, - 51, + 14, + 50, ], readonly: false, returnType: { range: [ - 46, - 51, + 45, + 50, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 48, - 51, + 47, + 50, ], type: "TSAnyKeyword", }, @@ -6882,31 +6882,31 @@ snapshot[`Plugin - TSInterface 12`] = ` name: "T", optional: false, range: [ + 16, 17, - 18, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 16, 17, - 18, ], type: "TSTypeParameter", }, ], range: [ - 16, - 19, + 15, + 18, ], type: "TSTypeParameterDeclaration", }, }, ], range: [ - 13, - 53, + 12, + 52, ], type: "TSInterfaceBody", }, @@ -6916,15 +6916,15 @@ snapshot[`Plugin - TSInterface 12`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 53, + 0, + 52, ], type: "TSInterface", typeParameters: [], @@ -6936,20 +6936,20 @@ snapshot[`Plugin - TSSatisfiesExpression 2`] = ` expression: { properties: [], range: [ - 11, - 13, + 10, + 12, ], type: "ObjectExpression", }, range: [ - 11, - 25, + 10, + 24, ], type: "TSSatisfiesExpression", typeAnnotation: { range: [ + 23, 24, - 25, ], type: "TSTypeReference", typeArguments: null, @@ -6957,8 +6957,8 @@ snapshot[`Plugin - TSSatisfiesExpression 2`] = ` name: "A", optional: false, range: [ + 23, 24, - 25, ], type: "Identifier", typeAnnotation: null, @@ -6974,21 +6974,21 @@ snapshot[`Plugin - TSTypeAliasDeclaration 1`] = ` name: "A", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 13, + 0, + 12, ], type: "TSTypeAliasDeclaration", typeAnnotation: { range: [ - 10, - 13, + 9, + 12, ], type: "TSAnyKeyword", }, @@ -7003,21 +7003,21 @@ snapshot[`Plugin - TSTypeAliasDeclaration 2`] = ` name: "A", optional: false, range: [ + 5, 6, - 7, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 16, + 0, + 15, ], type: "TSTypeAliasDeclaration", typeAnnotation: { range: [ - 13, - 16, + 12, + 15, ], type: "TSAnyKeyword", }, @@ -7032,23 +7032,23 @@ snapshot[`Plugin - TSTypeAliasDeclaration 2`] = ` name: "T", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 7, 8, - 9, ], type: "TSTypeParameter", }, ], range: [ - 7, - 10, + 6, + 9, ], type: "TSTypeParameterDeclaration", }, @@ -7062,21 +7062,21 @@ snapshot[`Plugin - TSTypeAliasDeclaration 3`] = ` name: "A", optional: false, range: [ + 13, 14, - 15, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 24, + 0, + 23, ], type: "TSTypeAliasDeclaration", typeAnnotation: { range: [ - 21, - 24, + 20, + 23, ], type: "TSAnyKeyword", }, @@ -7091,23 +7091,23 @@ snapshot[`Plugin - TSTypeAliasDeclaration 3`] = ` name: "T", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ + 15, 16, - 17, ], type: "TSTypeParameter", }, ], range: [ - 15, - 18, + 14, + 17, ], type: "TSTypeParameterDeclaration", }, @@ -7120,15 +7120,15 @@ snapshot[`Plugin - TSNonNullExpression 2`] = ` name: "a", optional: false, range: [ + 0, 1, - 2, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 3, + 0, + 2, ], type: "TSNonNullExpression", } @@ -7137,15 +7137,15 @@ snapshot[`Plugin - TSNonNullExpression 2`] = ` snapshot[`Plugin - TSUnionType 1`] = ` { range: [ - 10, - 15, + 9, + 14, ], type: "TSUnionType", types: [ { range: [ + 9, 10, - 11, ], type: "TSTypeReference", typeArguments: null, @@ -7153,8 +7153,8 @@ snapshot[`Plugin - TSUnionType 1`] = ` name: "B", optional: false, range: [ + 9, 10, - 11, ], type: "Identifier", typeAnnotation: null, @@ -7162,8 +7162,8 @@ snapshot[`Plugin - TSUnionType 1`] = ` }, { range: [ + 13, 14, - 15, ], type: "TSTypeReference", typeArguments: null, @@ -7171,8 +7171,8 @@ snapshot[`Plugin - TSUnionType 1`] = ` name: "C", optional: false, range: [ + 13, 14, - 15, ], type: "Identifier", typeAnnotation: null, @@ -7185,15 +7185,15 @@ snapshot[`Plugin - TSUnionType 1`] = ` snapshot[`Plugin - TSIntersectionType 1`] = ` { range: [ - 10, - 15, + 9, + 14, ], type: "TSIntersectionType", types: [ { range: [ + 9, 10, - 11, ], type: "TSTypeReference", typeArguments: null, @@ -7201,8 +7201,8 @@ snapshot[`Plugin - TSIntersectionType 1`] = ` name: "B", optional: false, range: [ + 9, 10, - 11, ], type: "Identifier", typeAnnotation: null, @@ -7210,8 +7210,8 @@ snapshot[`Plugin - TSIntersectionType 1`] = ` }, { range: [ + 13, 14, - 15, ], type: "TSTypeReference", typeArguments: null, @@ -7219,8 +7219,8 @@ snapshot[`Plugin - TSIntersectionType 1`] = ` name: "C", optional: false, range: [ + 13, 14, - 15, ], type: "Identifier", typeAnnotation: null, @@ -7235,8 +7235,8 @@ snapshot[`Plugin - TSModuleDeclaration 1`] = ` body: { body: [], range: [ - 10, - 12, + 9, + 11, ], type: "TSModuleBlock", }, @@ -7246,15 +7246,15 @@ snapshot[`Plugin - TSModuleDeclaration 1`] = ` name: "A", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "TSModuleDeclaration", } @@ -7274,27 +7274,27 @@ snapshot[`Plugin - TSModuleDeclaration 2`] = ` name: "A", optional: false, range: [ + 35, 36, - 37, ], type: "Identifier", typeAnnotation: null, }, params: [], range: [ - 27, - 45, + 26, + 44, ], returnType: { range: [ - 39, - 45, + 38, + 44, ], type: "TSTypeAnnotation", typeAnnotation: { range: [ - 41, - 45, + 40, + 44, ], type: "TSVoidKeyword", }, @@ -7303,15 +7303,15 @@ snapshot[`Plugin - TSModuleDeclaration 2`] = ` typeParameters: null, }, range: [ - 20, - 45, + 19, + 44, ], type: "ExportNamedDeclaration", }, ], range: [ - 18, - 47, + 17, + 46, ], type: "TSModuleBlock", }, @@ -7321,15 +7321,15 @@ snapshot[`Plugin - TSModuleDeclaration 2`] = ` name: "A", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 47, + 0, + 46, ], type: "TSModuleDeclaration", } @@ -7340,8 +7340,8 @@ snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 1`] = ` body: { body: [], range: [ - 10, - 12, + 9, + 11, ], type: "TSModuleBlock", }, @@ -7351,15 +7351,15 @@ snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 1`] = ` name: "A", optional: false, range: [ + 7, 8, - 9, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 12, + 0, + 11, ], type: "TSModuleDeclaration", } @@ -7373,8 +7373,8 @@ snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 2`] = ` body: { body: [], range: [ - 27, - 29, + 26, + 28, ], type: "TSModuleBlock", }, @@ -7384,22 +7384,22 @@ snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 2`] = ` name: "B", optional: false, range: [ + 24, 25, - 26, ], type: "Identifier", typeAnnotation: null, }, range: [ - 15, - 29, + 14, + 28, ], type: "TSModuleDeclaration", }, ], range: [ - 13, - 31, + 12, + 30, ], type: "TSModuleBlock", }, @@ -7409,15 +7409,15 @@ snapshot[`Plugin - TSModuleDeclaration + TSModuleBlock 2`] = ` name: "A", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 1, - 31, + 0, + 30, ], type: "TSModuleDeclaration", } @@ -7429,22 +7429,22 @@ snapshot[`Plugin - TSQualifiedName 1`] = ` name: "a", optional: false, range: [ + 9, 10, - 11, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 13, + 9, + 12, ], right: { name: "b", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, @@ -7462,39 +7462,39 @@ snapshot[`Plugin - TSTypeLiteral 1`] = ` name: "a", optional: false, range: [ + 11, 12, - 13, ], type: "Identifier", typeAnnotation: null, }, optional: false, range: [ - 12, - 16, + 11, + 15, ], readonly: false, static: false, type: "TSPropertySignature", typeAnnotation: { range: [ - 13, - 16, + 12, + 15, ], type: "TSTypeAnnotation", typeAnnotation: { literal: { range: [ + 14, 15, - 16, ], raw: "1", type: "Literal", value: 1, }, range: [ + 14, 15, - 16, ], type: "TSLiteralType", }, @@ -7502,8 +7502,8 @@ snapshot[`Plugin - TSTypeLiteral 1`] = ` }, ], range: [ - 10, - 18, + 9, + 17, ], type: "TSTypeLiteral", } @@ -7512,14 +7512,14 @@ snapshot[`Plugin - TSTypeLiteral 1`] = ` snapshot[`Plugin - TSOptionalType 1`] = ` { range: [ - 11, - 18, + 10, + 17, ], type: "TSOptionalType", typeAnnotation: { range: [ - 11, - 17, + 10, + 16, ], type: "TSNumberKeyword", }, @@ -7529,21 +7529,21 @@ snapshot[`Plugin - TSOptionalType 1`] = ` snapshot[`Plugin - TSRestType 1`] = ` { range: [ - 11, - 22, + 10, + 21, ], type: "TSRestType", typeAnnotation: { elementType: { range: [ - 14, - 20, + 13, + 19, ], type: "TSNumberKeyword", }, range: [ - 14, - 22, + 13, + 21, ], type: "TSArrayType", }, @@ -7554,8 +7554,8 @@ snapshot[`Plugin - TSConditionalType 1`] = ` { checkType: { range: [ + 9, 10, - 11, ], type: "TSTypeReference", typeArguments: null, @@ -7563,8 +7563,8 @@ snapshot[`Plugin - TSConditionalType 1`] = ` name: "B", optional: false, range: [ + 9, 10, - 11, ], type: "Identifier", typeAnnotation: null, @@ -7572,8 +7572,8 @@ snapshot[`Plugin - TSConditionalType 1`] = ` }, extendsType: { range: [ + 19, 20, - 21, ], type: "TSTypeReference", typeArguments: null, @@ -7581,8 +7581,8 @@ snapshot[`Plugin - TSConditionalType 1`] = ` name: "C", optional: false, range: [ + 19, 20, - 21, ], type: "Identifier", typeAnnotation: null, @@ -7590,19 +7590,19 @@ snapshot[`Plugin - TSConditionalType 1`] = ` }, falseType: { range: [ - 33, - 39, + 32, + 38, ], type: "TSStringKeyword", }, range: [ - 10, - 39, + 9, + 38, ], trueType: { range: [ - 24, - 30, + 23, + 29, ], type: "TSNumberKeyword", }, @@ -7613,8 +7613,8 @@ snapshot[`Plugin - TSConditionalType 1`] = ` snapshot[`Plugin - TSInferType 1`] = ` { range: [ - 29, - 39, + 28, + 38, ], type: "TSInferType", typeParameter: { @@ -7626,16 +7626,16 @@ snapshot[`Plugin - TSInferType 1`] = ` name: "Item", optional: false, range: [ - 35, - 39, + 34, + 38, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 35, - 39, + 34, + 38, ], type: "TSTypeParameter", }, @@ -7646,14 +7646,14 @@ snapshot[`Plugin - TSTypeOperator 1`] = ` { operator: "keyof", range: [ - 10, - 17, + 9, + 16, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 15, 16, - 17, ], type: "TSTypeReference", typeArguments: null, @@ -7661,8 +7661,8 @@ snapshot[`Plugin - TSTypeOperator 1`] = ` name: "B", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, @@ -7675,14 +7675,14 @@ snapshot[`Plugin - TSTypeOperator 2`] = ` { operator: "unique", range: [ - 21, - 34, + 20, + 33, ], type: "TSTypeOperator", typeAnnotation: { range: [ - 28, - 34, + 27, + 33, ], type: "TSSymbolKeyword", }, @@ -7693,15 +7693,15 @@ snapshot[`Plugin - TSTypeOperator 3`] = ` { operator: "readonly", range: [ - 10, - 21, + 9, + 20, ], type: "TSTypeOperator", typeAnnotation: { elementTypes: [], range: [ - 19, - 21, + 18, + 20, ], type: "TSTupleType", }, @@ -7713,15 +7713,15 @@ snapshot[`Plugin - TSMappedType 1`] = ` nameType: null, optional: undefined, range: [ - 13, - 41, + 12, + 40, ], readonly: undefined, type: "TSMappedType", typeAnnotation: { range: [ - 31, - 38, + 30, + 37, ], type: "TSBooleanKeyword", }, @@ -7730,14 +7730,14 @@ snapshot[`Plugin - TSMappedType 1`] = ` constraint: { operator: "keyof", range: [ - 21, - 28, + 20, + 27, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 26, 27, - 28, ], type: "TSTypeReference", typeArguments: null, @@ -7745,8 +7745,8 @@ snapshot[`Plugin - TSMappedType 1`] = ` name: "T", optional: false, range: [ + 26, 27, - 28, ], type: "Identifier", typeAnnotation: null, @@ -7759,16 +7759,16 @@ snapshot[`Plugin - TSMappedType 1`] = ` name: "P", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 16, - 28, + 15, + 27, ], type: "TSTypeParameter", }, @@ -7780,16 +7780,16 @@ snapshot[`Plugin - TSMappedType 2`] = ` nameType: null, optional: undefined, range: [ - 13, - 45, + 12, + 44, ], readonly: true, type: "TSMappedType", typeAnnotation: { elementTypes: [], range: [ - 40, - 42, + 39, + 41, ], type: "TSTupleType", }, @@ -7798,14 +7798,14 @@ snapshot[`Plugin - TSMappedType 2`] = ` constraint: { operator: "keyof", range: [ - 30, - 37, + 29, + 36, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 35, 36, - 37, ], type: "TSTypeReference", typeArguments: null, @@ -7813,8 +7813,8 @@ snapshot[`Plugin - TSMappedType 2`] = ` name: "T", optional: false, range: [ + 35, 36, - 37, ], type: "Identifier", typeAnnotation: null, @@ -7827,16 +7827,16 @@ snapshot[`Plugin - TSMappedType 2`] = ` name: "P", optional: false, range: [ + 24, 25, - 26, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 25, - 37, + 24, + 36, ], type: "TSTypeParameter", }, @@ -7848,16 +7848,16 @@ snapshot[`Plugin - TSMappedType 3`] = ` nameType: null, optional: undefined, range: [ - 13, - 46, + 12, + 45, ], readonly: "-", type: "TSMappedType", typeAnnotation: { elementTypes: [], range: [ - 41, - 43, + 40, + 42, ], type: "TSTupleType", }, @@ -7866,14 +7866,14 @@ snapshot[`Plugin - TSMappedType 3`] = ` constraint: { operator: "keyof", range: [ - 31, - 38, + 30, + 37, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 36, 37, - 38, ], type: "TSTypeReference", typeArguments: null, @@ -7881,8 +7881,8 @@ snapshot[`Plugin - TSMappedType 3`] = ` name: "T", optional: false, range: [ + 36, 37, - 38, ], type: "Identifier", typeAnnotation: null, @@ -7895,16 +7895,16 @@ snapshot[`Plugin - TSMappedType 3`] = ` name: "P", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 26, - 38, + 25, + 37, ], type: "TSTypeParameter", }, @@ -7916,16 +7916,16 @@ snapshot[`Plugin - TSMappedType 4`] = ` nameType: null, optional: undefined, range: [ - 13, - 46, + 12, + 45, ], readonly: "+", type: "TSMappedType", typeAnnotation: { elementTypes: [], range: [ - 41, - 43, + 40, + 42, ], type: "TSTupleType", }, @@ -7934,14 +7934,14 @@ snapshot[`Plugin - TSMappedType 4`] = ` constraint: { operator: "keyof", range: [ - 31, - 38, + 30, + 37, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 36, 37, - 38, ], type: "TSTypeReference", typeArguments: null, @@ -7949,8 +7949,8 @@ snapshot[`Plugin - TSMappedType 4`] = ` name: "T", optional: false, range: [ + 36, 37, - 38, ], type: "Identifier", typeAnnotation: null, @@ -7963,16 +7963,16 @@ snapshot[`Plugin - TSMappedType 4`] = ` name: "P", optional: false, range: [ + 25, 26, - 27, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 26, - 38, + 25, + 37, ], type: "TSTypeParameter", }, @@ -7984,15 +7984,15 @@ snapshot[`Plugin - TSMappedType 5`] = ` nameType: null, optional: true, range: [ - 13, - 42, + 12, + 41, ], readonly: undefined, type: "TSMappedType", typeAnnotation: { range: [ - 32, - 39, + 31, + 38, ], type: "TSBooleanKeyword", }, @@ -8001,14 +8001,14 @@ snapshot[`Plugin - TSMappedType 5`] = ` constraint: { operator: "keyof", range: [ - 21, - 28, + 20, + 27, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 26, 27, - 28, ], type: "TSTypeReference", typeArguments: null, @@ -8016,8 +8016,8 @@ snapshot[`Plugin - TSMappedType 5`] = ` name: "T", optional: false, range: [ + 26, 27, - 28, ], type: "Identifier", typeAnnotation: null, @@ -8030,16 +8030,16 @@ snapshot[`Plugin - TSMappedType 5`] = ` name: "P", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 16, - 28, + 15, + 27, ], type: "TSTypeParameter", }, @@ -8051,15 +8051,15 @@ snapshot[`Plugin - TSMappedType 6`] = ` nameType: null, optional: "-", range: [ - 13, - 43, + 12, + 42, ], readonly: undefined, type: "TSMappedType", typeAnnotation: { range: [ - 33, - 40, + 32, + 39, ], type: "TSBooleanKeyword", }, @@ -8068,14 +8068,14 @@ snapshot[`Plugin - TSMappedType 6`] = ` constraint: { operator: "keyof", range: [ - 21, - 28, + 20, + 27, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 26, 27, - 28, ], type: "TSTypeReference", typeArguments: null, @@ -8083,8 +8083,8 @@ snapshot[`Plugin - TSMappedType 6`] = ` name: "T", optional: false, range: [ + 26, 27, - 28, ], type: "Identifier", typeAnnotation: null, @@ -8097,16 +8097,16 @@ snapshot[`Plugin - TSMappedType 6`] = ` name: "P", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 16, - 28, + 15, + 27, ], type: "TSTypeParameter", }, @@ -8118,15 +8118,15 @@ snapshot[`Plugin - TSMappedType 7`] = ` nameType: null, optional: "+", range: [ - 13, - 43, + 12, + 42, ], readonly: undefined, type: "TSMappedType", typeAnnotation: { range: [ - 33, - 40, + 32, + 39, ], type: "TSBooleanKeyword", }, @@ -8135,14 +8135,14 @@ snapshot[`Plugin - TSMappedType 7`] = ` constraint: { operator: "keyof", range: [ - 21, - 28, + 20, + 27, ], type: "TSTypeOperator", typeAnnotation: { range: [ + 26, 27, - 28, ], type: "TSTypeReference", typeArguments: null, @@ -8150,8 +8150,8 @@ snapshot[`Plugin - TSMappedType 7`] = ` name: "T", optional: false, range: [ + 26, 27, - 28, ], type: "Identifier", typeAnnotation: null, @@ -8164,16 +8164,16 @@ snapshot[`Plugin - TSMappedType 7`] = ` name: "P", optional: false, range: [ + 15, 16, - 17, ], type: "Identifier", typeAnnotation: null, }, out: false, range: [ - 16, - 28, + 15, + 27, ], type: "TSTypeParameter", }, @@ -8184,16 +8184,16 @@ snapshot[`Plugin - TSLiteralType 1`] = ` { literal: { range: [ - 10, - 14, + 9, + 13, ], raw: "true", type: "Literal", value: true, }, range: [ - 10, - 14, + 9, + 13, ], type: "TSLiteralType", } @@ -8203,16 +8203,16 @@ snapshot[`Plugin - TSLiteralType 2`] = ` { literal: { range: [ - 10, - 15, + 9, + 14, ], raw: "false", type: "Literal", value: false, }, range: [ - 10, - 15, + 9, + 14, ], type: "TSLiteralType", } @@ -8222,16 +8222,16 @@ snapshot[`Plugin - TSLiteralType 3`] = ` { literal: { range: [ + 9, 10, - 11, ], raw: "1", type: "Literal", value: 1, }, range: [ + 9, 10, - 11, ], type: "TSLiteralType", } @@ -8241,16 +8241,16 @@ snapshot[`Plugin - TSLiteralType 4`] = ` { literal: { range: [ - 10, - 15, + 9, + 14, ], raw: '"foo"', type: "Literal", value: "foo", }, range: [ - 10, - 15, + 9, + 14, ], type: "TSLiteralType", } @@ -8262,8 +8262,8 @@ snapshot[`Plugin - TSTemplateLiteralType 1`] = ` { cooked: "a ", range: [ - 11, - 13, + 10, + 12, ], raw: "a ", tail: false, @@ -8272,8 +8272,8 @@ snapshot[`Plugin - TSTemplateLiteralType 1`] = ` { cooked: "", range: [ - 22, - 22, + 21, + 21, ], raw: "", tail: true, @@ -8281,15 +8281,15 @@ snapshot[`Plugin - TSTemplateLiteralType 1`] = ` }, ], range: [ - 10, - 23, + 9, + 22, ], type: "TSTemplateLiteralType", types: [ { range: [ - 15, - 21, + 14, + 20, ], type: "TSStringKeyword", }, @@ -8302,15 +8302,15 @@ snapshot[`Plugin - TSTupleType + TSArrayType 1`] = ` elementTypes: [ { range: [ - 11, - 17, + 10, + 16, ], type: "TSNumberKeyword", }, ], range: [ - 10, - 18, + 9, + 17, ], type: "TSTupleType", } @@ -8322,8 +8322,8 @@ snapshot[`Plugin - TSTupleType + TSArrayType 2`] = ` { elementType: { range: [ - 14, - 20, + 13, + 19, ], type: "TSNumberKeyword", }, @@ -8331,22 +8331,22 @@ snapshot[`Plugin - TSTupleType + TSArrayType 2`] = ` name: "x", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 11, - 20, + 10, + 19, ], type: "TSNamedTupleMember", }, ], range: [ - 10, - 21, + 9, + 20, ], type: "TSTupleType", } @@ -8358,8 +8358,8 @@ snapshot[`Plugin - TSTupleType + TSArrayType 3`] = ` { elementType: { range: [ - 14, - 20, + 13, + 19, ], type: "TSNumberKeyword", }, @@ -8367,22 +8367,22 @@ snapshot[`Plugin - TSTupleType + TSArrayType 3`] = ` name: "x", optional: false, range: [ + 10, 11, - 12, ], type: "Identifier", typeAnnotation: null, }, range: [ - 11, - 20, + 10, + 19, ], type: "TSNamedTupleMember", }, ], range: [ - 10, - 21, + 9, + 20, ], type: "TSTupleType", } @@ -8395,14 +8395,14 @@ snapshot[`Plugin - TSTupleType + TSArrayType 4`] = ` elementType: { elementType: { range: [ - 17, - 23, + 16, + 22, ], type: "TSNumberKeyword", }, range: [ - 17, - 25, + 16, + 24, ], type: "TSArrayType", }, @@ -8411,29 +8411,29 @@ snapshot[`Plugin - TSTupleType + TSArrayType 4`] = ` name: "x", optional: false, range: [ + 13, 14, - 15, ], type: "Identifier", typeAnnotation: null, }, range: [ - 11, - 16, + 10, + 15, ], type: "RestElement", typeAnnotation: null, }, range: [ - 11, - 25, + 10, + 24, ], type: "TSNamedTupleMember", }, ], range: [ - 10, - 26, + 9, + 25, ], type: "TSTupleType", } @@ -8443,14 +8443,14 @@ snapshot[`Plugin - TSArrayType 1`] = ` { elementType: { range: [ - 10, - 16, + 9, + 15, ], type: "TSNumberKeyword", }, range: [ - 10, - 18, + 9, + 17, ], type: "TSArrayType", } @@ -8462,15 +8462,15 @@ snapshot[`Plugin - TSTypeQuery 1`] = ` name: "B", optional: false, range: [ + 16, 17, - 18, ], type: "Identifier", typeAnnotation: null, }, range: [ - 10, - 18, + 9, + 17, ], type: "TSTypeQuery", typeArguments: null, @@ -8480,8 +8480,8 @@ snapshot[`Plugin - TSTypeQuery 1`] = ` snapshot[`Plugin - TS keywords 1`] = ` { range: [ - 10, - 13, + 9, + 12, ], type: "TSAnyKeyword", } @@ -8490,8 +8490,8 @@ snapshot[`Plugin - TS keywords 1`] = ` snapshot[`Plugin - TS keywords 2`] = ` { range: [ - 10, - 16, + 9, + 15, ], type: "TSBigIntKeyword", } @@ -8500,8 +8500,8 @@ snapshot[`Plugin - TS keywords 2`] = ` snapshot[`Plugin - TS keywords 3`] = ` { range: [ - 10, - 17, + 9, + 16, ], type: "TSBooleanKeyword", } @@ -8510,8 +8510,8 @@ snapshot[`Plugin - TS keywords 3`] = ` snapshot[`Plugin - TS keywords 4`] = ` { range: [ - 10, - 19, + 9, + 18, ], type: "TSIntrinsicKeyword", } @@ -8520,8 +8520,8 @@ snapshot[`Plugin - TS keywords 4`] = ` snapshot[`Plugin - TS keywords 5`] = ` { range: [ - 10, - 15, + 9, + 14, ], type: "TSNeverKeyword", } @@ -8530,8 +8530,8 @@ snapshot[`Plugin - TS keywords 5`] = ` snapshot[`Plugin - TS keywords 6`] = ` { range: [ - 10, - 14, + 9, + 13, ], type: "TSNullKeyword", } @@ -8540,8 +8540,8 @@ snapshot[`Plugin - TS keywords 6`] = ` snapshot[`Plugin - TS keywords 7`] = ` { range: [ - 10, - 16, + 9, + 15, ], type: "TSNumberKeyword", } @@ -8550,8 +8550,8 @@ snapshot[`Plugin - TS keywords 7`] = ` snapshot[`Plugin - TS keywords 8`] = ` { range: [ - 10, - 16, + 9, + 15, ], type: "TSObjectKeyword", } @@ -8560,8 +8560,8 @@ snapshot[`Plugin - TS keywords 8`] = ` snapshot[`Plugin - TS keywords 9`] = ` { range: [ - 10, - 16, + 9, + 15, ], type: "TSStringKeyword", } @@ -8570,8 +8570,8 @@ snapshot[`Plugin - TS keywords 9`] = ` snapshot[`Plugin - TS keywords 10`] = ` { range: [ - 10, - 16, + 9, + 15, ], type: "TSSymbolKeyword", } @@ -8580,8 +8580,8 @@ snapshot[`Plugin - TS keywords 10`] = ` snapshot[`Plugin - TS keywords 11`] = ` { range: [ - 10, - 19, + 9, + 18, ], type: "TSUndefinedKeyword", } @@ -8590,8 +8590,8 @@ snapshot[`Plugin - TS keywords 11`] = ` snapshot[`Plugin - TS keywords 12`] = ` { range: [ - 10, - 17, + 9, + 16, ], type: "TSUnknownKeyword", } @@ -8600,8 +8600,8 @@ snapshot[`Plugin - TS keywords 12`] = ` snapshot[`Plugin - TS keywords 13`] = ` { range: [ - 10, - 14, + 9, + 13, ], type: "TSVoidKeyword", } diff --git a/tests/unit/lint_plugin_test.ts b/tests/unit/lint_plugin_test.ts index 6c71501c461191..4f660be29f7e49 100644 --- a/tests/unit/lint_plugin_test.ts +++ b/tests/unit/lint_plugin_test.ts @@ -3,45 +3,14 @@ import { assertEquals } from "./test_util.ts"; import { assertSnapshot } from "@std/testing/snapshot"; -// TODO(@marvinhagemeister) Remove once we land "official" types -export interface LintReportData { - // deno-lint-ignore no-explicit-any - node: any; - message: string; -} -// TODO(@marvinhagemeister) Remove once we land "official" types -interface LintContext { - id: string; -} // TODO(@marvinhagemeister) Remove once we land "official" types // deno-lint-ignore no-explicit-any type LintVisitor = Record void>; -// TODO(@marvinhagemeister) Remove once we land "official" types -interface LintRule { - create(ctx: LintContext): LintVisitor; - destroy?(): void; -} - -// TODO(@marvinhagemeister) Remove once we land "official" types -interface LintPlugin { - name: string; - rules: Record; -} - -function runLintPlugin(plugin: LintPlugin, fileName: string, source: string) { - // deno-lint-ignore no-explicit-any - return (Deno as any)[(Deno as any).internal].runLintPlugin( - plugin, - fileName, - source, - ); -} - function testPlugin( source: string, - rule: LintRule, -) { + rule: Deno.lint.Rule, +): Deno.lint.Diagnostic[] { const plugin = { name: "test-plugin", rules: { @@ -49,7 +18,11 @@ function testPlugin( }, }; - return runLintPlugin(plugin, "source.tsx", source); + return Deno.lint.runPlugin( + plugin, + "source.tsx", + source, + ); } interface VisitResult { diff --git a/tests/unit/ops_test.ts b/tests/unit/ops_test.ts index 60f67cdca67ae8..9998ad6d80685b 100644 --- a/tests/unit/ops_test.ts +++ b/tests/unit/ops_test.ts @@ -1,6 +1,6 @@ // Copyright 2018-2025 the Deno authors. MIT license. -const EXPECTED_OP_COUNT = 13; +const EXPECTED_OP_COUNT = 14; Deno.test(function checkExposedOps() { // @ts-ignore TS doesn't allow to index with symbol