Skip to content

Commit

Permalink
feat(unstable): add JS linting plugin infrastructure (#27416)
Browse files Browse the repository at this point in the history
This PR extracts the core part of
#27203 to make it easier to review
and land in parts.

It contains:
-  The JS plugin code the deserializes and walks the buffer
- The Rust portion to serialize SWC to the buffer format (a bunch of
nodes are still todos, but imo these can land anytime later)
- Basic lint plugin types, without the AST node types to make this PR
easier to review
- Added more code comments to explain the format etc.


More fixes and changes will be done in follow-up PRs.

---------

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
  • Loading branch information
marvinhagemeister and bartlomieju authored Dec 20, 2024
1 parent 77e1af7 commit 26425a1
Show file tree
Hide file tree
Showing 15 changed files with 5,499 additions and 3 deletions.
783 changes: 783 additions & 0 deletions cli/js/40_lint.js

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions cli/js/40_lint_types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

export interface NodeFacade {
type: string;
range: [number, number];
[key: string]: unknown;
}

export interface AstContext {
buf: Uint8Array;
strTable: Map<number, string>;
strTableOffset: number;
rootOffset: number;
nodes: Map<number, NodeFacade>;
strByType: number[];
strByProp: number[];
typeByStr: Map<string, number>;
propByStr: Map<string, 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<string, (node: unknown) => void>;
destroy?(ctx: RuleContext): void;
}

// TODO(@marvinhagemeister) Remove once we land "official" types
export interface LintPlugin {
name: string;
rules: Record<string, LintRule>;
}

export interface LintState {
plugins: LintPlugin[];
installedPlugins: Set<string>;
}

export type VisitorFn = (node: unknown) => void;

export interface CompiledVisitor {
matcher: (offset: number) => boolean;
info: { enter: VisitorFn; exit: VisitorFn };
}

export {};
34 changes: 34 additions & 0 deletions cli/ops/lint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use deno_ast::MediaType;
use deno_ast::ModuleSpecifier;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::op2;

use crate::tools::lint;

deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],);

#[op2]
#[buffer]
fn op_lint_create_serialized_ast(
#[string] file_name: &str,
#[string] source: String,
) -> Result<Vec<u8>, AnyError> {
let file_text = deno_ast::strip_bom(source);
let path = std::env::current_dir()?.join(file_name);
let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| {
generic_error(format!("Failed to parse path as URL: {}", path.display()))
})?;
let media_type = MediaType::from_specifier(&specifier);
let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
specifier,
text: file_text.into(),
media_type,
capture_tokens: false,
scope_analysis: false,
maybe_syntax: None,
})?;
Ok(lint::serialize_ast_to_buffer(&parsed_source))
}
1 change: 1 addition & 0 deletions cli/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

pub mod bench;
pub mod jupyter;
pub mod lint;
pub mod testing;
Loading

0 comments on commit 26425a1

Please sign in to comment.