Skip to content

Commit 285d932

Browse files
anthonyshewautofix-ci[bot]dyc3coderabbitai[bot]
authored
feat: new Turborepo domain and noUndeclaredEnvVars rule (#8426)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Carson McManus <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent ec43141 commit 285d932

File tree

65 files changed

+2386
-99
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2386
-99
lines changed

.changeset/rich-icons-talk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Added a Turborepo domain and a new "noUndeclaredEnvVars" rule in it for warning users of unsafe environment variable usage in Turborepos.

crates/biome_analyze/src/rule.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ pub enum RuleSource {
165165
GraphqlSchemaLinter(&'static str),
166166
/// Rules from [Stylelint](https://github.com/stylelint/stylelint)
167167
Stylelint(&'static str),
168+
/// Rules from [Eslint Plugin Turbo](https://github.com/vercel/turborepo/tree/main/packages/eslint-plugin-turbo)
169+
EslintTurbo(&'static str),
168170
}
169171

170172
impl PartialEq for RuleSource {
@@ -215,6 +217,7 @@ impl std::fmt::Display for RuleSource {
215217
Self::EslintVueJs(_) => write!(f, "eslint-plugin-vue"),
216218
Self::GraphqlSchemaLinter(_) => write!(f, "graphql-schema-linter"),
217219
Self::Stylelint(_) => write!(f, "Stylelint"),
220+
Self::EslintTurbo(_) => write!(f, "eslint-plugin-turbo"),
218221
}
219222
}
220223
}
@@ -294,7 +297,8 @@ impl RuleSource {
294297
| Self::EslintVitest(rule_name)
295298
| Self::EslintVueJs(rule_name)
296299
| Self::GraphqlSchemaLinter(rule_name)
297-
| Self::Stylelint(rule_name) => rule_name,
300+
| Self::Stylelint(rule_name)
301+
| Self::EslintTurbo(rule_name) => rule_name,
298302
}
299303
}
300304

@@ -339,6 +343,7 @@ impl RuleSource {
339343
Self::EslintUnusedImports(rule_name) => format!("unused-imports/{rule_name}"),
340344
Self::EslintVitest(rule_name) => format!("vitest/{rule_name}"),
341345
Self::EslintVueJs(rule_name) => format!("vue/{rule_name}"),
346+
Self::EslintTurbo(rule_name) => format!("turbo/{rule_name}"),
342347
}
343348
}
344349

@@ -379,6 +384,7 @@ impl RuleSource {
379384
Self::EslintVueJs(rule_name) => format!("https://eslint.vuejs.org/rules/{rule_name}"),
380385
Self::GraphqlSchemaLinter(rule_name) => format!("https://github.com/cjoudrey/graphql-schema-linter?tab=readme-ov-file#{rule_name}"),
381386
Self::Stylelint(rule_name) => format!("https://github.com/stylelint/stylelint/blob/main/lib/rules/{rule_name}/README.md"),
387+
Self::EslintTurbo(rule_name) => format!("https://github.com/vercel/turborepo/blob/main/packages/eslint-plugin-turbo/docs/rules/{rule_name}.md"),
382388
}
383389
}
384390

@@ -464,6 +470,8 @@ pub enum RuleDomain {
464470
Project,
465471
/// Tailwind CSS rules
466472
Tailwind,
473+
/// Turborepo build system rules
474+
Turborepo,
467475
}
468476

469477
impl Display for RuleDomain {
@@ -478,6 +486,7 @@ impl Display for RuleDomain {
478486
Self::Vue => fmt.write_str("vue"),
479487
Self::Project => fmt.write_str("project"),
480488
Self::Tailwind => fmt.write_str("tailwind"),
489+
Self::Turborepo => fmt.write_str("turborepo"),
481490
}
482491
}
483492
}
@@ -517,6 +526,7 @@ impl RuleDomain {
517526
Self::Vue => &[&("vue", ">=3.0.0")],
518527
Self::Project => &[],
519528
Self::Tailwind => &[&("tailwindcss", ">=3.0.0")],
529+
Self::Turborepo => &[&("turbo", ">=1.0.0")],
520530
}
521531
}
522532

@@ -542,6 +552,7 @@ impl RuleDomain {
542552
Self::Vue => &[],
543553
Self::Project => &[],
544554
Self::Tailwind => &[],
555+
Self::Turborepo => &[],
545556
}
546557
}
547558

@@ -555,6 +566,7 @@ impl RuleDomain {
555566
Self::Vue => "vue",
556567
Self::Project => "project",
557568
Self::Tailwind => "tailwind",
569+
Self::Turborepo => "turborepo",
558570
}
559571
}
560572
}
@@ -572,6 +584,7 @@ impl FromStr for RuleDomain {
572584
"vue" => Ok(Self::Vue),
573585
"project" => Ok(Self::Project),
574586
"tailwind" => Ok(Self::Tailwind),
587+
"turborepo" => Ok(Self::Turborepo),
575588

576589
_ => Err("Invalid rule domain"),
577590
}

crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/src/analyzer/linter/rules.rs

Lines changed: 101 additions & 80 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/src/generated/domain_selector.rs

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/tests/invalid/domains.json.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ domains.json:4:7 deserialize ━━━━━━━━━━━━━━━━━
2323
- vue
2424
- project
2525
- tailwind
26+
- turborepo
2627

2728

2829

crates/biome_diagnostics_categories/src/categories.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,11 @@ define_categories! {
185185
"lint/nursery/noParametersOnlyUsedInRecursion": "https://biomejs.dev/linter/rules/no-parameters-only-used-in-recursion",
186186
"lint/nursery/noProto": "https://biomejs.dev/linter/rules/no-proto",
187187
"lint/nursery/noReactForwardRef": "https://biomejs.dev/linter/rules/no-react-forward-ref",
188+
"lint/nursery/noScriptUrl": "https://biomejs.dev/linter/rules/no-script-url",
188189
"lint/nursery/noShadow": "https://biomejs.dev/linter/rules/no-shadow",
189190
"lint/nursery/noSyncScripts": "https://biomejs.dev/linter/rules/no-sync-scripts",
190191
"lint/nursery/noTernary": "https://biomejs.dev/linter/rules/no-ternary",
192+
"lint/nursery/noUndeclaredEnvVars": "https://biomejs.dev/linter/rules/no-undeclared-env-vars",
191193
"lint/nursery/noUnknownAttribute": "https://biomejs.dev/linter/rules/no-unknown-attribute",
192194
"lint/nursery/noUnnecessaryConditions": "https://biomejs.dev/linter/rules/no-unnecessary-conditions",
193195
"lint/nursery/noUnresolvedImports": "https://biomejs.dev/linter/rules/no-unresolved-imports",
@@ -253,7 +255,6 @@ define_categories! {
253255
"lint/security/noDangerouslySetInnerHtml": "https://biomejs.dev/linter/rules/no-dangerously-set-inner-html",
254256
"lint/security/noDangerouslySetInnerHtmlWithChildren": "https://biomejs.dev/linter/rules/no-dangerously-set-inner-html-with-children",
255257
"lint/security/noGlobalEval": "https://biomejs.dev/linter/rules/no-global-eval",
256-
"lint/nursery/noScriptUrl": "https://biomejs.dev/linter/rules/no-script-url",
257258
"lint/security/noSecrets": "https://biomejs.dev/linter/rules/no-secrets",
258259
"lint/style/noCommonJs": "https://biomejs.dev/linter/rules/no-common-js",
259260
"lint/style/noDefaultExport": "https://biomejs.dev/linter/rules/no-default-export",

crates/biome_fs/src/path.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ impl BiomePath {
107107

108108
/// The priority of the file.
109109
/// - `biome.json` and `biome.jsonc` have the highest priority
110-
/// - `package.json` and `tsconfig.json`/`jsconfig.json` have the second-highest priority, and they are considered as manifest files
110+
/// - `package.json`, `tsconfig.json`/`jsconfig.json`, and `turbo.json` have the second-highest priority, and they are considered as manifest files
111111
/// - Other files are considered as files to handle
112112
fn priority(file_name: &str) -> FileKinds {
113113
if file_name == ConfigName::biome_json() || file_name == ConfigName::biome_jsonc() {
114114
FileKinds::Config
115115
} else if matches!(
116116
file_name,
117-
"package.json" | "tsconfig.json" | "jsconfig.json"
117+
"package.json" | "tsconfig.json" | "jsconfig.json" | "turbo.json" | "turbo.jsonc"
118118
) {
119119
FileKinds::Manifest
120120
} else if matches!(file_name, ".gitignore" | ".ignore") {
@@ -298,6 +298,8 @@ mod test {
298298
let biome_path = BiomePath::new(path);
299299
assert_eq!(biome_path.file_name(), Some("package.json"));
300300
assert_eq!(BiomePath::priority("package.json"), FileKinds::Manifest);
301+
assert_eq!(BiomePath::priority("turbo.json"), FileKinds::Manifest);
302+
assert_eq!(BiomePath::priority("turbo.jsonc"), FileKinds::Manifest);
301303
assert_eq!(BiomePath::priority("biome.json"), FileKinds::Config);
302304
assert_eq!(BiomePath::priority("biome.jsonc"), FileKinds::Config);
303305
assert_eq!(BiomePath::priority(".gitignore"), FileKinds::Ignore);

crates/biome_js_analyze/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use biome_aria::AriaRoles;
1212
use biome_diagnostics::Error as DiagnosticError;
1313
use biome_js_syntax::{JsFileSource, JsLanguage};
1414
use biome_module_graph::{ModuleGraph, ModuleResolver};
15+
use biome_package::TurboJson;
1516
use biome_project_layout::ProjectLayout;
1617
use biome_rowan::TextRange;
1718
use biome_suppression::{SuppressionDiagnostic, parse_suppression_comment};
@@ -158,6 +159,9 @@ where
158159
.find_node_manifest_for_path(file_path.as_ref())
159160
.map(|(path, manifest)| (path, Arc::new(manifest)));
160161

162+
let turborepo_configs: Vec<Arc<TurboJson>> =
163+
project_layout.find_all_turbo_json_for_path(file_path.as_ref());
164+
161165
let type_resolver = module_graph
162166
.module_info_for_path(file_path.as_ref())
163167
.map(|module_info| ModuleResolver::for_module(module_info, module_graph.clone()))
@@ -167,6 +171,7 @@ where
167171
services.insert_service(source_type);
168172
services.insert_service(module_graph);
169173
services.insert_service(node_manifest);
174+
services.insert_service(turborepo_configs);
170175
services.insert_service(file_path);
171176
services.insert_service(type_resolver);
172177
services.insert_service(project_layout);

crates/biome_js_analyze/src/lint/nursery.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub mod no_script_url;
2424
pub mod no_shadow;
2525
pub mod no_sync_scripts;
2626
pub mod no_ternary;
27+
pub mod no_undeclared_env_vars;
2728
pub mod no_unknown_attribute;
2829
pub mod no_unnecessary_conditions;
2930
pub mod no_unresolved_imports;
@@ -50,4 +51,4 @@ pub mod use_sorted_classes;
5051
pub mod use_spread;
5152
pub mod use_vue_define_macros_order;
5253
pub mod use_vue_multi_word_component_names;
53-
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_continue :: NoContinue , self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_duplicated_spread_props :: NoDuplicatedSpreadProps , self :: no_empty_source :: NoEmptySource , self :: no_equals_to_null :: NoEqualsToNull , self :: no_floating_promises :: NoFloatingPromises , self :: no_for_in :: NoForIn , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_leaked_render :: NoLeakedRender , self :: no_misused_promises :: NoMisusedPromises , self :: no_multi_str :: NoMultiStr , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_proto :: NoProto , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_script_url :: NoScriptUrl , self :: no_shadow :: NoShadow , self :: no_sync_scripts :: NoSyncScripts , self :: no_ternary :: NoTernary , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLoss , self :: use_array_sort_compare :: UseArraySortCompare , self :: use_await_thenable :: UseAwaitThenable , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_destructuring :: UseDestructuring , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_regexp_exec :: UseRegexpExec , self :: use_sorted_classes :: UseSortedClasses , self :: use_spread :: UseSpread , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
54+
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_continue :: NoContinue , self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_duplicated_spread_props :: NoDuplicatedSpreadProps , self :: no_empty_source :: NoEmptySource , self :: no_equals_to_null :: NoEqualsToNull , self :: no_floating_promises :: NoFloatingPromises , self :: no_for_in :: NoForIn , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_leaked_render :: NoLeakedRender , self :: no_misused_promises :: NoMisusedPromises , self :: no_multi_str :: NoMultiStr , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_proto :: NoProto , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_script_url :: NoScriptUrl , self :: no_shadow :: NoShadow , self :: no_sync_scripts :: NoSyncScripts , self :: no_ternary :: NoTernary , self :: no_undeclared_env_vars :: NoUndeclaredEnvVars , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLoss , self :: use_array_sort_compare :: UseArraySortCompare , self :: use_await_thenable :: UseAwaitThenable , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_destructuring :: UseDestructuring , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_regexp_exec :: UseRegexpExec , self :: use_sorted_classes :: UseSortedClasses , self :: use_spread :: UseSpread , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }

0 commit comments

Comments
 (0)