Skip to content

Commit ae83bdf

Browse files
marvinhagemeisterbartlomieju
authored andcommitted
feat(unstable): add JS linting plugin infrastructure (#27416)
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 <[email protected]>
1 parent 131a4ea commit ae83bdf

File tree

15 files changed

+5499
-3
lines changed

15 files changed

+5499
-3
lines changed

cli/js/40_lint.js

+783
Large diffs are not rendered by default.

cli/js/40_lint_types.d.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2+
3+
export interface NodeFacade {
4+
type: string;
5+
range: [number, number];
6+
[key: string]: unknown;
7+
}
8+
9+
export interface AstContext {
10+
buf: Uint8Array;
11+
strTable: Map<number, string>;
12+
strTableOffset: number;
13+
rootOffset: number;
14+
nodes: Map<number, NodeFacade>;
15+
strByType: number[];
16+
strByProp: number[];
17+
typeByStr: Map<string, number>;
18+
propByStr: Map<string, number>;
19+
}
20+
21+
// TODO(@marvinhagemeister) Remove once we land "official" types
22+
export interface RuleContext {
23+
id: string;
24+
}
25+
26+
// TODO(@marvinhagemeister) Remove once we land "official" types
27+
export interface LintRule {
28+
create(ctx: RuleContext): Record<string, (node: unknown) => void>;
29+
destroy?(ctx: RuleContext): void;
30+
}
31+
32+
// TODO(@marvinhagemeister) Remove once we land "official" types
33+
export interface LintPlugin {
34+
name: string;
35+
rules: Record<string, LintRule>;
36+
}
37+
38+
export interface LintState {
39+
plugins: LintPlugin[];
40+
installedPlugins: Set<string>;
41+
}
42+
43+
export type VisitorFn = (node: unknown) => void;
44+
45+
export interface CompiledVisitor {
46+
matcher: (offset: number) => boolean;
47+
info: { enter: VisitorFn; exit: VisitorFn };
48+
}
49+
50+
export {};

cli/ops/lint.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2+
3+
use deno_ast::MediaType;
4+
use deno_ast::ModuleSpecifier;
5+
use deno_core::error::generic_error;
6+
use deno_core::error::AnyError;
7+
use deno_core::op2;
8+
9+
use crate::tools::lint;
10+
11+
deno_core::extension!(deno_lint, ops = [op_lint_create_serialized_ast,],);
12+
13+
#[op2]
14+
#[buffer]
15+
fn op_lint_create_serialized_ast(
16+
#[string] file_name: &str,
17+
#[string] source: String,
18+
) -> Result<Vec<u8>, AnyError> {
19+
let file_text = deno_ast::strip_bom(source);
20+
let path = std::env::current_dir()?.join(file_name);
21+
let specifier = ModuleSpecifier::from_file_path(&path).map_err(|_| {
22+
generic_error(format!("Failed to parse path as URL: {}", path.display()))
23+
})?;
24+
let media_type = MediaType::from_specifier(&specifier);
25+
let parsed_source = deno_ast::parse_program(deno_ast::ParseParams {
26+
specifier,
27+
text: file_text.into(),
28+
media_type,
29+
capture_tokens: false,
30+
scope_analysis: false,
31+
maybe_syntax: None,
32+
})?;
33+
Ok(lint::serialize_ast_to_buffer(&parsed_source))
34+
}

cli/ops/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
pub mod bench;
44
pub mod jupyter;
5+
pub mod lint;
56
pub mod testing;

0 commit comments

Comments
 (0)