Skip to content
Open
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
4 changes: 3 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"singleQuote": true
"singleQuote": true,
"endOfLine": "lf",
"trailingComma": "es5"
}
23 changes: 23 additions & 0 deletions e2e/oxlint-e2e/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {}
}
]
}
11 changes: 11 additions & 0 deletions e2e/oxlint-e2e/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
displayName: 'oxlint-e2e',
preset: '../../jest.preset.js',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/packages/oxlint-e2e',
globalSetup: '../../tools/scripts/start-local-registry.ts',
globalTeardown: '../../tools/scripts/stop-local-registry.ts',
};
21 changes: 21 additions & 0 deletions e2e/oxlint-e2e/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "oxlint-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "e2e/oxlint-e2e/src",
"implicitDependencies": ["oxlint"],
"targets": {
"e2e": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "e2e/oxlint-e2e/jest.config.ts",
"runInBand": true
},
"dependsOn": ["^build"]
},
"lint": {
"executor": "@nx/eslint:lint"
}
}
}
73 changes: 73 additions & 0 deletions e2e/oxlint-e2e/src/oxlint.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { execSync } from 'child_process';
import {
cleanupTestProject,
createTestProject,
getChildWorkspaceEnv,
getNxVersion,
runCommand,
} from './utils';

describe('oxlint plugin', () => {
let projectDirectory: string;

beforeAll(() => {
const nxVersion = getNxVersion();
projectDirectory = createTestProject(nxVersion);
// The plugin has been built and published to a local registry in the jest globalSetup
// Install the plugin built with the latest source code into the test repo
execSync(`yarn add -D -W @nx/oxlint@e2e`, {
cwd: projectDirectory,
stdio: 'inherit',
env: getChildWorkspaceEnv(),
});

execSync('yarn nx add @nx/oxlint --no-interactive', {
cwd: projectDirectory,
stdio: 'inherit',
env: getChildWorkspaceEnv(),
});

execSync(
'yarn nx g @nx/js:lib lib-a --unitTestRunner=none --bundler=none --linter=none --no-interactive',
{
cwd: projectDirectory,
stdio: 'inherit',
env: getChildWorkspaceEnv(),
}
);
});

afterAll(() => {
cleanupTestProject(projectDirectory);
});

it('should be installed', () => {
// npm ls will fail if the package is not installed properly
execSync('yarn list @nx/oxlint', {
cwd: projectDirectory,
stdio: 'inherit',
});
});

it('should register the plugin in nx.json', () => {
const nxJson = runCommand('cat nx.json', projectDirectory);
expect(nxJson).toContain('@nx/oxlint/plugin');
});

it('should infer an oxlint target for the generated library', () => {
const projectJson = runCommand(
'yarn nx show project lib-a --json',
projectDirectory
);
expect(projectJson).toContain('"lint"');
expect(projectJson).toContain('oxlint lib-a');
});

it('should run oxlint successfully', () => {
execSync('yarn nx run lib-a:lint', {
cwd: projectDirectory,
stdio: 'inherit',
env: getChildWorkspaceEnv(),
});
});
});
107 changes: 107 additions & 0 deletions e2e/oxlint-e2e/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { readJsonFile, workspaceRoot } from '@nx/devkit';
import { execSync } from 'child_process';
import { mkdirSync, rmSync } from 'fs';
import { dirname, join } from 'path';

export function getStrippedEnvironmentVariables() {
return Object.fromEntries(
Object.entries(process.env).filter(([key]) => {
if (key.startsWith('NX_E2E_')) {
return true;
}

const allowedKeys = [
'NX_ADD_PLUGINS',
'NX_ISOLATE_PLUGINS',
'NX_VERBOSE_LOGGING',
'NX_NATIVE_LOGGING',
'NX_USE_LOCAL',
];

if (key.startsWith('NX_') && !allowedKeys.includes(key)) {
return false;
}

if (key === 'JEST_WORKER_ID') {
return false;
}

if (key === 'NODE_PATH') {
return false;
}

return true;
})
);
}

export function getChildWorkspaceEnv() {
return {
CI: 'true',
NX_NO_CLOUD: 'true',
NX_INTERNAL_USE_LEGACY_VERSIONING: 'false',
...getStrippedEnvironmentVariables(),
};
}

/**
* Gets the version of Nx to use for the test project
* @returns The version of Nx to use for the test project
*/
export function getNxVersion() {
const nxVersion = readJsonFile(join(workspaceRoot, 'package.json'))
.devDependencies['nx'];
return nxVersion;
}

/**
* Creates a test project with create-nx-workspace and installs the plugin
* @returns The directory where the test project was created
*/
export function createTestProject(nxVersion: string) {
const projectName = 'test-project';
const projectDirectory = join(process.cwd(), 'tmp', projectName);

// Ensure projectDirectory is empty
rmSync(projectDirectory, {
recursive: true,
force: true,
});
mkdirSync(dirname(projectDirectory), {
recursive: true,
});

execSync(
`npx -y create-nx-workspace@${nxVersion} ${projectName} --preset apps --nxCloud=skip --no-interactive`,
{
cwd: dirname(projectDirectory),
stdio: 'inherit',
env: getChildWorkspaceEnv(),
}
);
console.log(`Created test project in "${projectDirectory}"`);

return projectDirectory;
}

/**
* Cleans up the test project
* @param projectDirectory The directory where the test project was created
*/
export function cleanupTestProject(projectDirectory: string) {
if (projectDirectory && !process.env.PRESERVE_TEST_PROJECT) {
rmSync(projectDirectory, {
recursive: true,
force: true,
});
}
}

export function runCommand(command: string, cwd: string): string {
return execSync(command, {
cwd,
stdio: 'pipe',
env: getChildWorkspaceEnv(),
encoding: 'utf-8',
});
}
10 changes: 10 additions & 0 deletions e2e/oxlint-e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.spec.json"
}
]
}
15 changes: 15 additions & 0 deletions e2e/oxlint-e2e/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"moduleResolution": "node10",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
44 changes: 44 additions & 0 deletions packages/oxlint/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": [
"error",
{
"ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"],
"ignoredDependencies": [
"nx",
"oxlint",
"minimatch",
"@nx/devkit",
"@nx/eslint-plugin"
]
}
]
}
},
{
"files": ["./package.json", "./generators.json", "./executors.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/nx-plugin-checks": "error"
}
}
]
}
16 changes: 16 additions & 0 deletions packages/oxlint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Nx Oxlint Plugin

The Nx Oxlint plugin integrates [Oxlint](https://oxc.rs/docs/guide/usage/linter/) with Nx.

It provides:

- Inferred Oxlint tasks via `@nx/oxlint/plugin`
- A compatibility executor (`@nx/oxlint:lint`) for explicit targets
- Generators for setup and hybrid migration
- Experimental module-boundary enforcement bridge for Oxlint JS plugins

## Installation

```bash
nx add @nx/oxlint
```
9 changes: 9 additions & 0 deletions packages/oxlint/executors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"executors": {
"lint": {
"implementation": "./src/executors/lint/lint.impl",
"schema": "./src/executors/lint/schema.json",
"description": "Run Oxlint on a project."
}
}
}
22 changes: 22 additions & 0 deletions packages/oxlint/generators.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "Nx Oxlint",
"version": "0.1",
"generators": {
"init": {
"factory": "./src/generators/init/init#initGeneratorInternal",
"schema": "./src/generators/init/schema.json",
"description": "Set up the Oxlint plugin.",
"hidden": true
},
"lint-project": {
"factory": "./src/generators/lint-project/lint-project#lintProjectGeneratorInternal",
"schema": "./src/generators/lint-project/schema.json",
"description": "Add Oxlint to an existing project."
},
"convert-from-eslint": {
"factory": "./src/generators/convert-from-eslint/convert-from-eslint#convertFromEslintGenerator",
"schema": "./src/generators/convert-from-eslint/schema.json",
"description": "Register @nx/oxlint and add optional hybrid Oxlint targets without removing ESLint."
}
}
}
7 changes: 7 additions & 0 deletions packages/oxlint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {
OxlintExecutorSchema,
oxlintExecutor,
} from './src/executors/lint/lint.impl';
export { convertFromEslintGenerator } from './src/generators/convert-from-eslint/convert-from-eslint';
export { initGenerator } from './src/generators/init/init';
export { lintProjectGenerator } from './src/generators/lint-project/lint-project';
10 changes: 10 additions & 0 deletions packages/oxlint/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default {
displayName: 'oxlint',
preset: '../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/packages/oxlint',
};
Loading
Loading