Skip to content

Commit

Permalink
feat(eslint-plugin): add 'node-builtin-module-url-import' rule
Browse files Browse the repository at this point in the history
This rule auto-fixes imports from Node.js builtin modules to use the `node:` import specifier.
  • Loading branch information
dirkdev98 committed Jul 31, 2023
1 parent 64e0b24 commit 923e7b0
Show file tree
Hide file tree
Showing 57 changed files with 191 additions and 91 deletions.
2 changes: 1 addition & 1 deletion benchmark/validate.bench.js
@@ -1,4 +1,4 @@
import { readFileSync } from "fs";
import { readFileSync } from "node:fs";
import { bench, mainBenchFn } from "@compas/cli";
import { Generator } from "@compas/code-gen";
import { AppError, mainFn, pathJoin } from "@compas/stdlib";
Expand Down
2 changes: 1 addition & 1 deletion benchmark/validators.bench.js
@@ -1,6 +1,6 @@
/* eslint-disable import/no-unresolved */

import { pathToFileURL } from "url";
import { pathToFileURL } from "node:url";
import { bench, mainBenchFn } from "@compas/cli";
import { TypeCreator, Generator } from "@compas/code-gen";
import { mainFn, pathJoin } from "@compas/stdlib";
Expand Down
2 changes: 1 addition & 1 deletion examples/file-handling/test/e2e.test.js
@@ -1,4 +1,4 @@
import { createReadStream } from "fs";
import { createReadStream } from "node:fs";
import { blob } from "node:stream/consumers";
import { mainTestFn, test } from "@compas/cli";
import { dirnameForModule, pathJoin } from "@compas/stdlib";
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/benchmarking/printer.js
@@ -1,4 +1,4 @@
import { inspect } from "util";
import { inspect } from "node:util";
import { AppError, isNil } from "@compas/stdlib";
import { benchLogger, state } from "./state.js";

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/cli/internal-commands/completions.js
@@ -1,5 +1,5 @@
import { appendFileSync } from "fs";
import { writeFile } from "fs/promises";
import { appendFileSync } from "node:fs";
import { writeFile } from "node:fs/promises";
import { AppError, environment, isNil } from "@compas/stdlib";
import { cliParserGetKnownFlags, cliParserSplitArgs } from "../parser.js";

Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/cli/loader.js
@@ -1,6 +1,6 @@
import { existsSync } from "fs";
import { readdir, readFile } from "fs/promises";
import { pathToFileURL } from "url";
import { existsSync } from "node:fs";
import { readdir, readFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
import {
AppError,
environment,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/code-mod/constants.js
@@ -1,4 +1,4 @@
import { cpus } from "os";
import { cpus } from "node:os";
import { executeApiClientToExperimentalCodeGen } from "./mods/api-client-to-experimental-code-gen.js";
import { executeLintConfigToEslintPlugin } from "./mods/lint-config-to-eslint-plugin.js";
import { executeUpdateQueriesSignatureChange } from "./mods/update-queries-signature-change.js";
Expand Down
@@ -1,6 +1,6 @@
// @ts-nocheck

import { existsSync, readFileSync, writeFileSync } from "fs";
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { exec, processDirectoryRecursiveSync } from "@compas/stdlib";

/**
Expand Down
@@ -1,4 +1,4 @@
import { readFile, rm, writeFile } from "fs/promises";
import { readFile, rm, writeFile } from "node:fs/promises";

/**
* Convert all known usages from @compas/lint-config to eslint-plugin
Expand Down
@@ -1,6 +1,6 @@
// @ts-nocheck

import { readFile, writeFile } from "fs/promises";
import { readFile, writeFile } from "node:fs/promises";
import { AppError, processDirectoryRecursive } from "@compas/stdlib";
import { PARALLEL_COUNT } from "../constants.js";

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/compas/commands/check-env.js
@@ -1,5 +1,5 @@
import { existsSync } from "fs";
import { readFile } from "fs/promises";
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import {
dirnameForModule,
exec,
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/compas/commands/init.js
@@ -1,5 +1,5 @@
import { existsSync } from "fs";
import { readFile, writeFile } from "fs/promises";
import { existsSync } from "node:fs";
import { readFile, writeFile } from "node:fs/promises";
import { pathJoin } from "@compas/stdlib";

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/compas/commands/migrate.js
@@ -1,6 +1,6 @@
import { existsSync } from "fs";
import path from "path";
import { pathToFileURL } from "url";
import { existsSync } from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { isNil, isPlainObject, pathJoin } from "@compas/stdlib";

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/compas/commands/run.js
@@ -1,5 +1,5 @@
import { existsSync, statSync } from "fs";
import path from "path";
import { existsSync, statSync } from "node:fs";
import path from "node:path";
import { isNil, spawn } from "@compas/stdlib";
import { collectScripts } from "../../utils.js";

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/compas/commands/test.js
@@ -1,4 +1,4 @@
import { isMainThread, Worker } from "worker_threads";
import { isMainThread, Worker } from "node:worker_threads";
import { isNil, spawn } from "@compas/stdlib";
import { testingLoadConfig } from "../../testing/config.js";
import { printTestResultsFromWorkers } from "../../testing/printer.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/compas/commands/version.js
@@ -1,4 +1,4 @@
import { readFile } from "fs/promises";
import { readFile } from "node:fs/promises";
import { dirnameForModule, pathJoin } from "@compas/stdlib";

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/migrate/migrate.test.js
@@ -1,4 +1,4 @@
import { mkdir, rm, writeFile } from "fs/promises";
import { mkdir, rm, writeFile } from "node:fs/promises";
import { exec, uuid } from "@compas/stdlib";
import { mainTestFn, test } from "../../index.js";

Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/testing/config.js
@@ -1,8 +1,8 @@
import { existsSync } from "fs";
import { existsSync } from "node:fs";
import inspector from "node:inspector";
import { cpus } from "os";
import { pathToFileURL } from "url";
import { isMainThread, threadId } from "worker_threads";
import { cpus } from "node:os";
import { pathToFileURL } from "node:url";
import { isMainThread, threadId } from "node:worker_threads";
import {
environment,
isNil,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/testing/printer.js
@@ -1,4 +1,4 @@
import { inspect } from "util";
import { inspect } from "node:util";
import { AppError, isNil } from "@compas/stdlib";
import { state, testLogger } from "./state.js";

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/testing/runner.js
@@ -1,4 +1,4 @@
import { AssertionError, deepStrictEqual } from "assert";
import { AssertionError, deepStrictEqual } from "node:assert";
import { AppError, isNil, newLogger } from "@compas/stdlib";
import { markTestFailuresRecursively } from "./printer.js";
import { state, testLogger } from "./state.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/testing/runner.test.js
@@ -1,4 +1,4 @@
import { match, strictEqual } from "assert";
import { match, strictEqual } from "node:assert";
import { setTimeout } from "node:timers/promises";
import { mainTestFn, test } from "@compas/cli";
import { AppError } from "@compas/stdlib";
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/testing/worker-thread.js
@@ -1,6 +1,6 @@
import { setTimeout } from "timers/promises";
import { pathToFileURL } from "url";
import { isMainThread, parentPort, threadId } from "worker_threads";
import { setTimeout } from "node:timers/promises";
import { pathToFileURL } from "node:url";
import { isMainThread, parentPort, threadId } from "node:worker_threads";
import { AppError, mainFn } from "@compas/stdlib";
import { testingLoadConfig } from "./config.js";
import {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/utils.js
@@ -1,4 +1,4 @@
import { existsSync, readdirSync, readFileSync } from "fs";
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { pathJoin } from "@compas/stdlib";

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/watcher/index.js
@@ -1,4 +1,4 @@
import { spawn as cpSpawn } from "child_process";
import { spawn as cpSpawn } from "node:child_process";
import { AppError } from "@compas/stdlib";
import treeKill from "tree-kill";

Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/src/generate.js
@@ -1,4 +1,4 @@
import { mkdirSync, rmSync, writeFileSync } from "fs";
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
import { AppError, isNil, pathJoin } from "@compas/stdlib";
import { apiClientGenerator } from "./api-client/generator.js";
import { crudEventsGenerate } from "./crud/events.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/src/generator.js
@@ -1,4 +1,4 @@
import { readFileSync } from "fs";
import { readFileSync } from "node:fs";
import {
AppError,
environment,
Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/src/open-api-importer.test.js
@@ -1,4 +1,4 @@
import { readFileSync } from "fs";
import { readFileSync } from "node:fs";
import { mainTestFn, test } from "@compas/cli";
import { convertOpenAPISpec } from "./open-api-importer.js";

Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/src/open-api/generator.js
@@ -1,4 +1,4 @@
import { readFileSync } from "fs";
import { readFileSync } from "node:fs";
import { environment, isNil, merge, pathJoin } from "@compas/stdlib";
import { fileContextCreateGeneric } from "../file/context.js";
import { fileWrite } from "../file/write.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/test/spec-implementations/ts.js
@@ -1,4 +1,4 @@
import { writeFileSync } from "fs";
import { writeFileSync } from "node:fs";
import {
AppError,
environment,
Expand Down
2 changes: 1 addition & 1 deletion packages/code-gen/test/testing.js
@@ -1,4 +1,4 @@
import { existsSync } from "fs";
import { existsSync } from "node:fs";
import { AppError, isNil, pathJoin, uuid } from "@compas/stdlib";
import { testTemporaryDirectory } from "../../../src/testing.js";
import { TypeCreator } from "../src/builders/index.js";
Expand Down
4 changes: 2 additions & 2 deletions packages/create-compas/src/create-compas.js
@@ -1,7 +1,7 @@
#! /usr/bin/env node

import { existsSync, readdirSync } from "fs";
import { readFile } from "fs/promises";
import { existsSync, readdirSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { dirnameForModule, mainFn, pathJoin } from "@compas/stdlib";
import {
argParserParse,
Expand Down
14 changes: 7 additions & 7 deletions packages/create-compas/src/template.js
@@ -1,10 +1,10 @@
import { createWriteStream } from "fs";
import { mkdir, readFile, writeFile } from "fs/promises";
import https from "https";
import os from "os";
import { normalize } from "path";
import { Readable } from "stream";
import { pipeline } from "stream/promises";
import { createWriteStream } from "node:fs";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import https from "node:https";
import os from "node:os";
import { normalize } from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import {
AppError,
environment,
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/index.js
Expand Up @@ -44,6 +44,7 @@ module.exports = {
// Plugin rules
"@compas/enforce-event-stop": "error",
"@compas/check-event-name": "error",
"@compas/node-builtin-module-url-import": "error",

// ESLint base
"default-case-last": "error",
Expand Down Expand Up @@ -137,5 +138,6 @@ module.exports = {
rules: {
"enforce-event-stop": require("./lint-rules/enforce-event-stop"),
"check-event-name": require("./lint-rules/check-event-name"),
"node-builtin-module-url-import": require("./lint-rules/node-builtin-module-url-import"),
},
};
@@ -0,0 +1,47 @@
/* eslint-disable import/no-commonjs */

const { builtinModules } = require("node:module");

/** @type {import("eslint").Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: `Suggest that imports of Node.js builtin modules use the 'node:' specifier.`,
},
fixable: "code",
hasSuggestions: true,

messages: {
consistentImport: `Always use the 'node:' specifier when importing Node.js builtins.`,
replaceImport: `Replace '{{value}}' with 'node:{{value}}'`,
},
},

create(context) {
return {
ImportDeclaration(node) {
if (!builtinModules.includes(node.source.value)) {
return;
}

context.report({
node: node,
messageId: "consistentImport",
fix: (fixer) =>
fixer.replaceText(node.source, `"node:${node.source.value}"`),
suggest: [
{
messageId: "replaceImport",
data: {
value: node.source.value,
},
fix: (fixer) =>
fixer.replaceText(node.source, `"node:${node.source.value}"`),
},
],
});
},
};
},
};
50 changes: 50 additions & 0 deletions packages/eslint-plugin/test/node-builtin-module-url-import.js
@@ -0,0 +1,50 @@
/* eslint-disable import/no-commonjs,import/order */

const rule = require("../lint-rules/node-builtin-module-url-import");
const RuleTester = require("eslint").RuleTester;
const { join } = require("path");

const ruleTester = new RuleTester({
parser: join(process.cwd(), "./node_modules/@babel/eslint-parser"),
parserOptions: {
requireConfigFile: false,
babelOptions: {
plugins: ["@babel/plugin-syntax-class-properties"],
},
},
env: {
node: true,
es2021: true,
},
});

ruleTester.run("node-builtin-module-url-import", rule, {
valid: [
{
code: `import foo from "node:path";`,
},
{
code: `import * as foo from "node:path";`,
},
{
code: `import * as foo from "other-module";`,
},
],
invalid: [
{
code: `import { join } from "path";`,
errors: [
{
message: rule.meta.messages.consistentImport,
suggestions: [
{
messageId: "replaceImport",
data: { value: "path" },
output: `import { join } from "node:path";`,
},
],
},
],
},
],
});
6 changes: 5 additions & 1 deletion packages/eslint-plugin/test/rules.test.mjs
Expand Up @@ -4,7 +4,11 @@ import { spawn } from "@compas/stdlib";
mainTestFn(import.meta);

test("eslint-plugin", async (t) => {
for (const f of ["enforce-event-stop.js", "check-event-name.js"]) {
for (const f of [
"enforce-event-stop.js",
"check-event-name.js",
"node-builtin-module-url-import.js",
]) {
t.test(f, async (t) => {
const { exitCode } = await spawn(`node`, [
`./packages/eslint-plugin/test/${f}`,
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/middleware/body.test.js
@@ -1,4 +1,4 @@
import { createReadStream } from "fs";
import { createReadStream } from "node:fs";
import { mainTestFn, test } from "@compas/cli";
import axios from "axios";
import FormData from "form-data";
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/middleware/log.js
@@ -1,4 +1,4 @@
import { Transform } from "stream";
import { Transform } from "node:stream";
import {
AppError,
eventStart,
Expand Down
2 changes: 1 addition & 1 deletion packages/stdlib/src/config-loader.js
@@ -1,7 +1,7 @@
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import os from "node:os";
import { pathToFileURL } from "url";
import { pathToFileURL } from "node:url";
import { environment } from "./env.js";
import { AppError } from "./error.js";
import { isNil } from "./lodash.js";
Expand Down
2 changes: 1 addition & 1 deletion packages/stdlib/src/datatypes.js
@@ -1,6 +1,6 @@
// @ts-nocheck

import { randomUUID } from "crypto";
import { randomUUID } from "node:crypto";

/**
* This function also has an `uuid.isValid` function, which returns a boolean depending
Expand Down

0 comments on commit 923e7b0

Please sign in to comment.