refactor(tooling): add turbo eslint plugin (#65734)

This commit is contained in:
Oliver Eyton-Williams
2026-02-06 13:03:05 +01:00
committed by GitHub
parent f054de20fd
commit ae50644091
18 changed files with 97 additions and 24 deletions
+1 -6
View File
@@ -159,12 +159,7 @@ if (process.env.FREECODECAMP_NODE_ENV !== 'development') {
export const HOME_LOCATION = process.env.HOME_LOCATION;
// Mailpit is used in development and test environments, hence the localhost
// default.
// TODO: Remove MAILHOG_HOST in a few months
// We renamed MailHog to MailPit, but kept the same port and API
// This is to keep backward compatibility with existing setups
// that might still use MAILHOG_HOST environment variable
export const MAILPIT_HOST =
process.env.MAILPIT_HOST ?? process.env.MAILHOG_HOST ?? 'localhost';
export const MAILPIT_HOST = process.env.MAILPIT_HOST ?? 'localhost';
export const MONGOHQ_URL =
process.env.NODE_ENV === 'test'
? createTestConnectionURL(
+45
View File
@@ -0,0 +1,45 @@
{
"$schema": "https://v2-8-1.turborepo.dev/schema.json",
"extends": ["//"],
"tasks": {
"build": {
"env": [
"API_LOCATION",
"AUTH0_CLIENT_ID",
"AUTH0_CLIENT_SECRET",
"AUTH0_DOMAIN",
"COOKIE_DOMAIN",
"COOKIE_SECRET",
"DEPLOYMENT_ENV",
"DEPLOYMENT_VERSION",
"EMAIL_PROVIDER",
"FCC_API_LOG_LEVEL",
"FCC_API_LOG_TRANSPORT",
"FCC_ENABLE_DEV_LOGIN_MODE",
"FCC_ENABLE_SENTRY_ROUTES",
"FCC_ENABLE_SHADOW_CAPTURE",
"FCC_ENABLE_SWAGGER_UI",
"FCC_ENABLE_TEST_LOGGING",
"FREECODECAMP_NODE_ENV",
"GROWTHBOOK_FASTIFY_API_HOST",
"GROWTHBOOK_FASTIFY_CLIENT_KEY",
"HOME_LOCATION",
"HOST",
"JWT_SECRET",
"MAILPIT_HOST",
"NODE_ENV",
"PORT",
"SENTRY_DSN",
"SENTRY_ENVIRONMENT",
"SES_ID",
"SES_REGION",
"SES_SECRET",
"SHOW_UPCOMING_CHANGES",
"STRIPE_SECRET_KEY"
]
},
"test": {
"passThroughEnv": ["VITEST_WORKER_ID"]
}
}
}
+5
View File
@@ -26,6 +26,11 @@ module.exports = {
resolve: 'gatsby-plugin-webpack-bundle-analyser-v2',
options: {
analyzerMode: 'disabled',
// It doesn't matter if the file is generated or not as far as caching
// is concerned. It doesn't affect any tasks in any way, so we can
// ignore it.
// eslint-disable-next-line turbo/no-undeclared-env-vars
generateStatsFile: process.env.CI
}
},
+5 -3
View File
@@ -4,13 +4,15 @@
"tasks": {
"build": {
"outputs": ["dist/**", "generated/**"],
"env": ["FCC_*"]
"env": ["FCC_*", "SHOW_UPCOMING_CHANGES"]
},
"test": {
"env": ["FCC_*"]
"passThroughEnv": ["VITEST_POOL_ID", "PUPPETEER_WS_ENDPOINT"],
"env": ["FCC_*", "CURRICULUM_LOCALE", "SHOW_UPCOMING_CHANGES"]
},
"test-content": {
"env": ["FCC_*"]
"passThroughEnv": ["VITEST_POOL_ID", "PUPPETEER_WS_ENDPOINT"],
"env": ["FCC_*", "CURRICULUM_LOCALE", "SHOW_UPCOMING_CHANGES"]
}
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ import {
getAllEmails,
getFirstEmail,
getSubject
} from './utils/mailhog';
} from './utils/email';
test.describe('Claim a certification - almost certified user', () => {
test.beforeEach(async () => {
+2 -1
View File
@@ -6,6 +6,7 @@ export default defineConfig(globalIgnores(['./playwright']), {
rules: {
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off'
'@typescript-eslint/no-unsafe-assignment': 'off',
'turbo/no-undeclared-env-vars': 'off' // If/when we make e2e tests into a turbo task, we can enable this rule again.
}
});
+1 -1
View File
@@ -4,7 +4,7 @@ import {
getAllEmails,
getFirstEmail,
getSubject
} from './utils/mailhog';
} from './utils/email';
test.beforeEach(async () => {
await deleteAllEmails();
+1 -1
View File
@@ -6,7 +6,7 @@ import {
getAllEmails,
getFirstEmail,
getSubject
} from './utils/mailhog';
} from './utils/email';
test.beforeEach(async () => {
await deleteAllEmails();
+1 -6
View File
@@ -11,12 +11,7 @@ type AllEmails = {
count: number;
};
// TODO: Remove MAILHOG_HOST in a few months
// We renamed MailHog to MailPit, but kept the same port and API
// This is to keep backward compatibility with existing setups
// that might still use MAILHOG_HOST environment variable
const host =
process.env.MAILPIT_HOST || process.env.MAILHOG_HOST || 'localhost';
const host = process.env.MAILPIT_HOST || 'localhost';
export const getAllEmails = async (): Promise<AllEmails> => {
const res = await fetch(`http://${host}:8025/api/v1/messages`);
+2
View File
@@ -11,6 +11,7 @@ import jsxAllyPlugin from 'eslint-plugin-jsx-a11y';
import importPlugin from 'eslint-plugin-import';
import testingLibraryPlugin from 'eslint-plugin-testing-library';
import babelParser from '@babel/eslint-parser'; // TODO: can we get away from using babel?
import turbo from 'eslint-plugin-turbo';
import { FlatCompat } from '@eslint/eslintrc';
@@ -32,6 +33,7 @@ const testFiles = [
const base = defineConfig(
globalIgnores(['dist', '.turbo']),
turbo.configs['flat/recommended'],
js.configs.recommended,
eslintConfigPrettier,
{
+1
View File
@@ -27,6 +27,7 @@
"eslint-plugin-react": "7.37.4",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-testing-library": "7.1.1",
"eslint-plugin-turbo": "^2.8.3",
"typescript": "5.9.3",
"typescript-eslint": "^8.47.0"
}
+26 -5
View File
@@ -936,6 +936,9 @@ importers:
eslint-plugin-testing-library:
specifier: 7.1.1
version: 7.1.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint-plugin-turbo:
specifier: ^2.8.3
version: 2.8.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.1)
typescript:
specifier: 5.9.3
version: 5.9.3
@@ -7617,6 +7620,10 @@ packages:
resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
engines: {node: '>=12'}
dotenv@16.0.3:
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
engines: {node: '>=12'}
dotenv@16.4.5:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
@@ -7998,6 +8005,12 @@ packages:
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
eslint-plugin-turbo@2.8.3:
resolution: {integrity: sha512-9ACQrrjzOfrbBGG1CqzyC67NtOSRcA+vyc9cjbyLyIoVtcK27czO7/WM+R5K3Opz0fb4Uezo6X+csMfL//RfJQ==}
peerDependencies:
eslint: '>6.6.0'
turbo: '>2.0.0'
eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
@@ -23399,6 +23412,8 @@ snapshots:
dotenv-expand@10.0.0: {}
dotenv@16.0.3: {}
dotenv@16.4.5: {}
dotenv@16.6.1: {}
@@ -23793,7 +23808,7 @@ snapshots:
confusing-browser-globals: 1.0.11
eslint: 7.32.0
eslint-plugin-flowtype: 5.10.0(eslint@7.32.0)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.4(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-hooks: 4.6.0(eslint@9.39.2(jiti@2.6.1))
@@ -23823,7 +23838,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)):
eslint-module-utils@2.12.0(@typescript-eslint/parser@4.33.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -23877,7 +23892,7 @@ snapshots:
- typescript
- utf-8-validate
eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)):
eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.8
@@ -23888,7 +23903,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1))
eslint-module-utils: 2.12.0(@typescript-eslint/parser@4.33.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -24023,6 +24038,12 @@ snapshots:
- supports-color
- typescript
eslint-plugin-turbo@2.8.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.1):
dependencies:
dotenv: 16.0.3
eslint: 9.39.2(jiti@2.6.1)
turbo: 2.8.1
eslint-scope@5.1.1:
dependencies:
esrecurse: 4.3.0
@@ -25118,7 +25139,7 @@ snapshots:
eslint-config-react-app: 6.0.0(@typescript-eslint/eslint-plugin@4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint@7.32.0)(typescript@5.9.3))(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(babel-eslint@10.1.0(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-flowtype@5.10.0(eslint@7.32.0))(eslint-plugin-import@2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint@7.32.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@7.32.0))(eslint-plugin-react-hooks@4.6.0(eslint@7.32.0))(eslint-plugin-react@7.37.4(eslint@7.32.0))(eslint@7.32.0)(typescript@5.9.3)
eslint-plugin-flowtype: 5.10.0(eslint@7.32.0)
eslint-plugin-graphql: 4.0.0(@types/node@24.10.9)(graphql@15.8.0)(typescript@5.9.3)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@4.33.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.4(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-hooks: 4.6.0(eslint@9.39.2(jiti@2.6.1))
@@ -1,3 +1,4 @@
/* eslint-disable turbo/no-undeclared-env-vars */
import fs from 'fs';
import { join } from 'path';
@@ -1,3 +1,4 @@
/* eslint-disable turbo/no-undeclared-env-vars */
import { describe, it, expect } from 'vitest';
import { getProjectName, getProjectPath } from './get-project-info.js';
@@ -1,4 +1,5 @@
export function getProjectPath(): string {
// eslint-disable-next-line turbo/no-undeclared-env-vars
return (process.env.INIT_CWD || process.cwd()) + '/';
}
@@ -1,3 +1,4 @@
/* eslint-disable turbo/no-undeclared-env-vars */
import { join } from 'path';
import { describe, it, expect, vi } from 'vitest';
import { getBlockStructure } from '@freecodecamp/curriculum/file-handler';
@@ -1,3 +1,4 @@
/* eslint-disable turbo/no-undeclared-env-vars */
import fs from 'fs';
import path, { join } from 'path';
import matter from 'gray-matter';
+1
View File
@@ -1,5 +1,6 @@
{
"$schema": "https://v2-8-1.turborepo.dev/schema.json",
"globalPassThroughEnv": ["MONGOHQ_URL"],
"tasks": {
"build": { "dependsOn": ["setup"], "outputs": ["dist/**"] },
"develop": { "dependsOn": ["setup"], "cache": false, "persistent": true },