Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eslint plugin no-undeclared-env-vars should detect known framework variables #9110

Merged
merged 20 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
"type": "shell",
"label": "prepare turbo",
"command": "cargo build -p turbo"
"command": "cargo build --package turbo"
}
]
}
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Dependencies

Building

- Building `turbo` CLI: `cargo build -p turbo`
- Building `turbo` CLI: `cargo build --package turbo`
- Using `turbo` to build `turbo` CLI: `./turbow.js`

### TLS Implementation
Expand Down
6 changes: 3 additions & 3 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"private": true,
"version": "0.0.0",
"scripts": {
"clean": "cargo clean -p turbo",
"build": "cargo build -p turbo",
"build:release": "cargo build -p turbo --profile release-turborepo"
"clean": "cargo clean --package turbo",
"build": "cargo build --package turbo",
"build:release": "cargo build --package turbo --profile release-turborepo"
}
}
146 changes: 24 additions & 122 deletions crates/turborepo-lib/src/framework.rs
Original file line number Diff line number Diff line change
@@ -1,146 +1,48 @@
use std::sync::OnceLock;

use serde::Deserialize;
use turborepo_repository::package_graph::PackageInfo;

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
enum Strategy {
All,
Some,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Matcher {
strategy: Strategy,
dependencies: Vec<&'static str>,
dependencies: Vec<String>,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Framework {
slug: &'static str,
env_wildcards: Vec<&'static str>,
slug: String,
env_wildcards: Vec<String>,
dependency_match: Matcher,
}

impl Framework {
pub fn slug(&self) -> &'static str {
self.slug
pub fn slug(&self) -> String {
self.slug.clone()
}

pub fn env_wildcards(&self) -> &[&'static str] {
pub fn env_wildcards(&self) -> &[String] {
&self.env_wildcards
}
}

static FRAMEWORKS: OnceLock<[Framework; 13]> = OnceLock::new();
static FRAMEWORKS: OnceLock<Vec<Framework>> = OnceLock::new();

fn get_frameworks() -> &'static [Framework] {
const FRAMEWORKS_JSON: &str =
include_str!("../../../packages/turbo-types/src/json/frameworks.json");

fn get_frameworks() -> &'static Vec<Framework> {
FRAMEWORKS.get_or_init(|| {
[
Framework {
slug: "blitzjs",
env_wildcards: vec!["NEXT_PUBLIC_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["blitz"],
},
},
Framework {
slug: "nextjs",
env_wildcards: vec!["NEXT_PUBLIC_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["next"],
},
},
Framework {
slug: "gatsby",
env_wildcards: vec!["GATSBY_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["gatsby"],
},
},
Framework {
slug: "astro",
env_wildcards: vec!["PUBLIC_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["astro"],
},
},
Framework {
slug: "solidstart",
env_wildcards: vec!["VITE_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["solid-js", "solid-start"],
},
},
Framework {
slug: "vue",
env_wildcards: vec!["VUE_APP_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["@vue/cli-service"],
},
},
Framework {
slug: "sveltekit",
env_wildcards: vec!["VITE_*", "PUBLIC_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["@sveltejs/kit"],
},
},
Framework {
slug: "create-react-app",
env_wildcards: vec!["REACT_APP_*"],
dependency_match: Matcher {
strategy: Strategy::Some,
dependencies: vec!["react-scripts", "react-dev-utils"],
},
},
Framework {
slug: "nitro",
env_wildcards: vec!["NITRO_*"],
dependency_match: Matcher {
strategy: Strategy::Some,
dependencies: vec!["nitropack", "nitropack-nightly"],
},
},
Framework {
slug: "nuxtjs",
env_wildcards: vec!["NUXT_*", "NITRO_*"],
dependency_match: Matcher {
strategy: Strategy::Some,
dependencies: vec!["nuxt", "nuxt-edge", "nuxt3", "nuxt3-edge"],
},
},
Framework {
slug: "redwoodjs",
env_wildcards: vec!["REDWOOD_ENV_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["@redwoodjs/core"],
},
},
Framework {
slug: "vite",
env_wildcards: vec!["VITE_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["vite"],
},
},
Framework {
slug: "sanity",
env_wildcards: vec!["SANITY_STUDIO_*"],
dependency_match: Matcher {
strategy: Strategy::All,
dependencies: vec!["@sanity/cli"],
},
},
]
serde_json::from_str(FRAMEWORKS_JSON).expect("Unable to parse embedded JSON")
})
}

Expand All @@ -159,16 +61,16 @@ impl Matcher {
Strategy::All => self
.dependencies
.iter()
.all(|dep| deps.map_or(false, |deps| deps.contains_key(*dep))),
.all(|dep| deps.map_or(false, |deps| deps.contains_key(dep))),
Strategy::Some => self
.dependencies
.iter()
.any(|dep| deps.map_or(false, |deps| deps.contains_key(*dep))),
.any(|dep| deps.map_or(false, |deps| deps.contains_key(dep))),
}
}
}

pub fn infer_framework(workspace: &PackageInfo, is_monorepo: bool) -> Option<&'static Framework> {
pub fn infer_framework(workspace: &PackageInfo, is_monorepo: bool) -> Option<&Framework> {
let frameworks = get_frameworks();

frameworks
Expand All @@ -183,7 +85,7 @@ mod tests {

use crate::framework::{get_frameworks, infer_framework, Framework};

fn get_framework_by_slug(slug: &str) -> &'static Framework {
fn get_framework_by_slug(slug: &str) -> &Framework {
get_frameworks()
.iter()
.find(|framework| framework.slug == slug)
Expand Down Expand Up @@ -291,7 +193,7 @@ mod tests {
)]
fn test_infer_framework(
workspace_info: PackageInfo,
expected: Option<&'static Framework>,
expected: Option<&Framework>,
is_monorepo: bool,
) {
let framework = infer_framework(&workspace_info, is_monorepo);
Expand Down
4 changes: 2 additions & 2 deletions crates/turborepo-telemetry/src/events/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ impl PackageTaskEventBuilder {
}

// event methods
pub fn track_framework(&self, framework: &str) -> &Self {
pub fn track_framework(&self, framework: String) -> &Self {
self.track(Event {
key: "framework".to_string(),
value: framework.to_string(),
value: framework,
is_sensitive: EventType::NonSensitive,
send_in_ci: false,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description: Learn how to handle environments for your applications.
import { Callout } from '#/components/callout';
import { Tabs, Tab } from '#/components/tabs';
import { Accordion, Accordions } from '#/components/accordion';
import { frameworks } from '@turbo/types';

Environment variable inputs are a vital part of your applications that you'll need to account for in your Turborepo configuration.

Expand Down Expand Up @@ -56,21 +57,24 @@ Turborepo needs to be aware of your environment variables to account for changes

Turborepo automatically adds prefix wildcards to your [`env`](/repo/docs/reference/configuration#env) key for common frameworks. If you're using one of the frameworks below in a package, you don't need to specify environment variables with these prefixes:

| Framework | `env` wildcard |
| ---------------- | ------------------- |
| Astro | `PUBLIC_*` |
| Blitz | `NEXT_PUBLIC_*` |
| Create React App | `REACT_APP_*` |
| Gatsby | `GATSBY_*` |
| Next.js | `NEXT_PUBLIC_*` |
| Nitro | `NITRO_*` |
| Nuxt.js | `NUXT_*`, `NITRO_*` |
| RedwoodJS | `REDWOOD_ENV_*` |
| Sanity Studio | `SANITY_STUDIO_*` |
| Solid | `VITE_*` |
| SvelteKit | `VITE_*` |
| Vite | `VITE_*` |
| Vue | `VUE_APP_*` |
<table>
<thead>
<tr>
<th>Framework</th>
<th>
<code>env</code> wildcards
</th>
</tr>
</thead>
<tbody>
{frameworks.map(({ name, envWildcards }) => (
<tr key={name}>
<td>{name}</td>
<td>{envWildcards.map((w) => <code>{w}</code>).join(', ')}</td>
</tr>
))}
</tbody>
</table>

<Callout type="good-to-know">Framework inference is per-package.</Callout>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ["plugin:turbo/recommended"],
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
process.env.NEXT_PUBLIC_ZILTOID;
process.env.GATSBY_THE;
process.env.NITRO_OMNISCIENT;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "nextjs",
"dependencies": {
"next": "*",
"blitz": "*",
"react": "*",
"left-pad": "*",
"event-stream": "*",
"gatsby": "*",
"is-promise": "*",
"@faker-js/faker": "*",
"ua-parser-js": "*",
"nitropack": "*"
},
"devDependencies": {
"eslint": "8.57.0",
"eslint-plugin-turbo": "../../../../"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.NEXT_PUBLIC_ZILTOID;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "nextjs",
"dependencies": {
"next": "*"
},
"devDependencies": {
"eslint": "8.57.0",
"eslint-plugin-turbo": "../../../../"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.VITE_THING;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "vite",
"dependencies": {
"vite": "*"
},
"devDependencies": {
"eslint": "8.57.0",
"eslint-plugin-turbo": "../../../../"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "framework-inference",
dimitropoulos marked this conversation as resolved.
Show resolved Hide resolved
"devDependencies": {
"eslint": "8.57.0",
"eslint-plugin-turbo": "../../"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tasks": {
"build": {
"dependsOn": ["^build"]
}
}
}
Loading
Loading