From 71173a918178fef49b7e0f2d9645ee72dda8469e Mon Sep 17 00:00:00 2001 From: Yuji Sugiura <6259812+leaysgur@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:29:55 +0900 Subject: [PATCH] feat(tasks): Add @typescript-eslint to lint_rules CI task (#2134) Part of #2020 - Add `@typescript-eslint` plugin rules - w/ refactoring - Fix compile errors to add other plugins - Remove not intended unsupported rule in `eslint` (Use #2117 for updating for a while?) --- .github/workflows/lint-rules.yml | 2 + tasks/lint_rules/src/generate_list/eslint.rs | 12 ++-- tasks/lint_rules/src/generate_list/mod.rs | 13 ++-- .../src/generate_list/typescript.rs | 67 +++++++++++++++++++ tasks/lint_rules/src/update_comment/mod.rs | 5 +- 5 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 tasks/lint_rules/src/generate_list/typescript.rs diff --git a/.github/workflows/lint-rules.yml b/.github/workflows/lint-rules.yml index bf8c0649068c5..8437f3a05dfe6 100644 --- a/.github/workflows/lint-rules.yml +++ b/.github/workflows/lint-rules.yml @@ -27,3 +27,5 @@ jobs: - name: Update eslint run: cargo run -p lint_rules eslint --update + - name: Update @typescript-eslint + run: cargo run -p lint_rules typescript --update diff --git a/tasks/lint_rules/src/generate_list/eslint.rs b/tasks/lint_rules/src/generate_list/eslint.rs index b12814a8e2d2e..69a41171a7c70 100644 --- a/tasks/lint_rules/src/generate_list/eslint.rs +++ b/tasks/lint_rules/src/generate_list/eslint.rs @@ -5,18 +5,20 @@ use oxc_semantic::SemanticBuilder; use oxc_span::SourceType; use std::collections::HashSet; -pub const ORIGINAL_JS_SOURCE_URL: &str = +const ORIGINAL_JS_SOURCE_URL: &str = "https://raw.githubusercontent.com/eslint/eslint/main/packages/js/src/configs/eslint-all.js"; -const UNSUPPORTED_RULES: &[&str] = &["yoda"]; +const UNSUPPORTED_RULES: &[&str] = &[]; + +pub fn find_to_be_implemented_rules() -> Result, String> { + let source_text = super::fetch_plugin_rules_js_string(ORIGINAL_JS_SOURCE_URL)?; -pub fn find_to_be_implemented_rules(source_text: &str) -> Result, String> { let allocator = Allocator::default(); let source_type = SourceType::default(); - let ret = Parser::new(&allocator, source_text, source_type).parse(); + let ret = Parser::new(&allocator, &source_text, source_type).parse(); let program = allocator.alloc(ret.program); - let semantic_ret = SemanticBuilder::new(source_text, source_type).build(program); + let semantic_ret = SemanticBuilder::new(&source_text, source_type).build(program); let mut rules = vec![]; let unsupported_rules = UNSUPPORTED_RULES.iter().collect::>(); diff --git a/tasks/lint_rules/src/generate_list/mod.rs b/tasks/lint_rules/src/generate_list/mod.rs index 0e5c4fd3c94a0..ddefe5df2115a 100644 --- a/tasks/lint_rules/src/generate_list/mod.rs +++ b/tasks/lint_rules/src/generate_list/mod.rs @@ -3,18 +3,17 @@ use std::collections::HashSet; use ureq::Response; mod eslint; +mod typescript; pub fn run(plugin_name: &str) -> Result { - let (js_source_url, find_to_be_implemented_rules) = match plugin_name { - "eslint" => (eslint::ORIGINAL_JS_SOURCE_URL, eslint::find_to_be_implemented_rules), + let (rules_to_be_implemented, rules_implemented) = match plugin_name { + "eslint" => (eslint::find_to_be_implemented_rules()?, list_implemented_rules("eslint")), + "typescript" => { + (typescript::find_to_be_implemented_rules()?, list_implemented_rules("typescript")) + } _ => return Err(format!("😢 Unknown plugin name: {plugin_name}")), }; - let js_string = fetch_plugin_rules_js_string(js_source_url)?; - let rules_to_be_implemented = find_to_be_implemented_rules(&js_string)?; - - let rules_implemented = list_implemented_rules(plugin_name); - let list = render_markdown_todo_list(&rules_to_be_implemented, &rules_implemented); let list = render_markdown_comment(plugin_name, &list); Ok(list) diff --git a/tasks/lint_rules/src/generate_list/typescript.rs b/tasks/lint_rules/src/generate_list/typescript.rs new file mode 100644 index 0000000000000..8024556c75650 --- /dev/null +++ b/tasks/lint_rules/src/generate_list/typescript.rs @@ -0,0 +1,67 @@ +use oxc_allocator::Allocator; +use oxc_ast::{ast::ObjectPropertyKind, syntax_directed_operations::PropName, AstKind}; +use oxc_parser::Parser; +use oxc_semantic::SemanticBuilder; +use oxc_span::SourceType; +use std::collections::HashSet; + +const ORIGINAL_JS_SOURCE_URL: &str = + "https://raw.githubusercontent.com/typescript-eslint/typescript-eslint/main/packages/eslint-plugin/src/configs/recommended.ts"; + +const UNSUPPORTED_RULES: &[&str] = &[]; + +pub fn find_to_be_implemented_rules() -> Result, String> { + let source_text = super::fetch_plugin_rules_js_string(ORIGINAL_JS_SOURCE_URL)?; + + let allocator = Allocator::default(); + let source_type = SourceType::default().with_typescript(true); + let ret = Parser::new(&allocator, &source_text, source_type).parse(); + + let program = allocator.alloc(ret.program); + let semantic_ret = SemanticBuilder::new(&source_text, source_type).build(program); + + let mut rules = vec![]; + let unsupported_rules = UNSUPPORTED_RULES.iter().collect::>(); + + // This code assumes that the `rules` property appears only once + let mut is_rules = false; + for node in semantic_ret.semantic.nodes().iter() { + if let AstKind::ObjectProperty(prop) = node.kind() { + if let Some((name, _)) = prop.key.prop_name() { + if name == "rules" { + is_rules = true; + continue; + } + } + } + + if is_rules { + if let AstKind::ObjectExpression(obj) = node.kind() { + for prop in &obj.properties { + if let ObjectPropertyKind::ObjectProperty(prop) = prop { + if let Some((name, _)) = prop.key.prop_name() { + // Almost all rules are prefixed, but some are not + // And prefixed and non-prefixed has the same name like `no-unused-vars` + if !name.starts_with("@typescript-eslint/") { + continue; + } + + let name = name.trim_start_matches("@typescript-eslint/"); + if unsupported_rules.contains(&name) { + continue; + } + + rules.push(name.to_string()); + } + } + } + } + } + } + + if rules.is_empty() { + return Err("No rules are found".to_string()); + } + + Ok(rules) +} diff --git a/tasks/lint_rules/src/update_comment/mod.rs b/tasks/lint_rules/src/update_comment/mod.rs index 5297c1f871791..f0d1ce7a35572 100644 --- a/tasks/lint_rules/src/update_comment/mod.rs +++ b/tasks/lint_rules/src/update_comment/mod.rs @@ -1,12 +1,15 @@ use ureq::Response; const ESLINT_ISSUE_API_URL: &str = "https://api.github.com/repos/oxc-project/oxc/issues/2117"; -// TODO: Restore it after update text is fixed and unsupported list is updated +const TYPESCRIPT_ISSUE_API_URL: &str = "https://api.github.com/repos/oxc-project/oxc/issues/2117"; +// TODO: Restore these after update text is fixed and unsupported list is updated // const ESLINT_ISSUE_API_URL: &str = "https://api.github.com/repos/oxc-project/oxc/issues/479"; +// const TYPESCRIPT_ISSUE_API_URL: &str = "https://api.github.com/repos/oxc-project/oxc/issues/503"; pub fn run(plugin_name: &str, token: &str, comment_body: &str) -> Result { let api_url = match plugin_name { "eslint" => ESLINT_ISSUE_API_URL, + "typescript" => TYPESCRIPT_ISSUE_API_URL, _ => return Err(format!("😢 Unknown plugin name: {plugin_name}")), };