Skip to content

BREAKING(fs,dotenv): drop Deno v1.x support #6624

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

Closed
wants to merge 5 commits into from
Closed
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
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ jobs:
fail-fast: false
matrix:
deno:
- v1.x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we drop v1 CI, we don't what packages work in v1 anymore (any package could randomly break in v1 in the future development)

- v2.x
- canary
os:
5 changes: 2 additions & 3 deletions _tools/lint_plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright 2018-2025 the Deno authors. MIT license.
// @ts-nocheck Deno.lint namespace does not pass type checking in Deno 1.x

/**
* Lint plugin that enforces the
@@ -260,15 +259,15 @@ export default {
const value = argument.value;
if (typeof value !== "string") return;

if (value[0] !== value[0].toUpperCase()) {
if (value[0] !== value[0]!.toUpperCase()) {
context.report({
node: argument,
message: "Error message starts with a lowercase.",
hint:
"Capitalize the error message. See https://docs.deno.com/runtime/contributing/style_guide/#error-messages for more details.",
fix(fixer) {
const newValue = argument.raw.at(0) +
value[0].toUpperCase() +
value[0]!.toUpperCase() +
value.slice(1) +
argument.raw.at(-1);
return fixer.replaceText(argument, newValue);
24 changes: 6 additions & 18 deletions _tools/lint_plugin_test.ts
Original file line number Diff line number Diff line change
@@ -17,9 +17,7 @@ function assertLintPluginDiagnostics(
assertEquals(actualDiagnostics, expectedDiagnostics);
}

Deno.test("deno-style-guide/prefer-private-field", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/prefer-private-field", () => {
// Good
assertLintPluginDiagnostics(
`
@@ -56,9 +54,7 @@ class MyClass {
);
});

Deno.test("deno-style-guide/no-top-level-arrow-syntax", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/no-top-level-arrow-syntax", () => {
// Bad
assertLintPluginDiagnostics(
`
@@ -97,9 +93,7 @@ function foo() {
);
});

Deno.test("deno-style-guide/no-external-code", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/no-external-code", () => {
// Good
assertLintPluginDiagnostics('import { walk } from "@std/fs/walk";', []);

@@ -127,9 +121,7 @@ import { bad } from "jsr:@malicious-muffin/bad";
);
});

Deno.test("deno-style-guide/naming-convention", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/naming-convention", () => {
// Good
assertLintPluginDiagnostics(
`
@@ -242,9 +234,7 @@ enum enumName {
);
});

Deno.test("deno-style-guide/error-message", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/error-message", () => {
// Good
assertLintPluginDiagnostics(
`
@@ -311,9 +301,7 @@ new CustomError("Can't parse input");
);
});

Deno.test("deno-style-guide/exported-function-args-maximum", {
ignore: !Deno.version.deno.startsWith("2"),
}, () => {
Deno.test("deno-style-guide/exported-function-args-maximum", () => {
// Good
assertLintPluginDiagnostics(
`
7 changes: 1 addition & 6 deletions dotenv/mod_test.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ import {
} from "@std/assert";
import { load, type LoadOptions, loadSync } from "./mod.ts";
import * as path from "@std/path";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";

const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
@@ -174,11 +173,7 @@ Deno.test(
};
assertThrows(
() => loadSync(loadOptions),
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
Deno.errors.NotCapable,
`Requires env access to "EMPTY", run again with the --allow-env flag`,
);
},
19 changes: 2 additions & 17 deletions fs/ensure_dir_test.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@ import { assertEquals, assertRejects, assertThrows } from "@std/assert";
import * as path from "@std/path";
import { ensureDir, ensureDirSync } from "./ensure_dir.ts";
import { ensureFile, ensureFileSync } from "./ensure_file.ts";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";

const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata", "ensure_dir");
@@ -182,14 +181,7 @@ Deno.test({

// ensureDir fails because this test doesn't have write permissions,
// but don't swallow that error.
await assertRejects(
async () => await ensureDir(baseDir),
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
);
await assertRejects(() => ensureDir(baseDir), Deno.errors.NotCapable);
},
});

@@ -204,14 +196,7 @@ Deno.test({

// ensureDirSync fails because this test doesn't have write permissions,
// but don't swallow that error.
assertThrows(
() => ensureDirSync(baseDir),
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
);
assertThrows(() => ensureDirSync(baseDir), Deno.errors.NotCapable);
},
});

19 changes: 2 additions & 17 deletions fs/ensure_file_test.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
import { assertRejects, assertThrows } from "@std/assert";
import * as path from "@std/path";
import { ensureFile, ensureFileSync } from "./ensure_file.ts";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";

const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
@@ -132,14 +131,7 @@ Deno.test({

// ensureFile fails because this test doesn't have write permissions,
// but don't swallow that error.
await assertRejects(
async () => await ensureFile(testFile),
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
);
await assertRejects(() => ensureFile(testFile), Deno.errors.NotCapable);
},
});

@@ -152,14 +144,7 @@ Deno.test({

// ensureFileSync fails because this test doesn't have write permissions,
// but don't swallow that error.
assertThrows(
() => ensureFileSync(testFile),
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
);
assertThrows(() => ensureFileSync(testFile), Deno.errors.NotCapable);
},
});

21 changes: 4 additions & 17 deletions fs/ensure_symlink_test.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ import {
} from "@std/assert";
import * as path from "@std/path";
import { ensureSymlink, ensureSymlinkSync } from "./ensure_symlink.ts";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";

const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
const testdataDir = path.resolve(moduleDir, "testdata");
@@ -354,14 +353,8 @@ Deno.test(
const linkFile = path.join(testdataDir, "link.ts");

await assertRejects(
async () => {
await ensureSymlink(testFile, linkFile);
},
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
() => ensureSymlink(testFile, linkFile),
Deno.errors.NotCapable,
);
},
);
@@ -374,14 +367,8 @@ Deno.test(
const linkFile = path.join(testdataDir, "link.ts");

assertThrows(
() => {
ensureSymlinkSync(testFile, linkFile);
},
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
() => ensureSymlinkSync(testFile, linkFile),
Deno.errors.NotCapable,
);
},
);
27 changes: 5 additions & 22 deletions fs/expand_glob_test.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@ import {
type ExpandGlobOptions,
expandGlobSync,
} from "./expand_glob.ts";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";

async function expandGlobArray(
globString: string,
@@ -114,28 +113,16 @@ Deno.test(
async function () {
{
await assertRejects(
async () => {
await expandGlobArray("*", EG_OPTIONS);
},
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
() => expandGlobArray("*", EG_OPTIONS),
Deno.errors.NotCapable,
"run again with the --allow-read flag",
);
}

{
assertThrows(
() => {
expandGlobSyncArray("*", EG_OPTIONS);
},
IS_DENO_2
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
// deno-lint-ignore no-explicit-any
? (Deno as any).errors.NotCapable
: Deno.errors.PermissionDenied,
() => expandGlobSyncArray("*", EG_OPTIONS),
Deno.errors.NotCapable,
"run again with the --allow-read flag",
);
}
@@ -307,11 +294,7 @@ Deno.test(
assert(!success);
assertEquals(code, 1);
assertEquals(decoder.decode(stdout), "");
assertStringIncludes(
decoder.decode(stderr),
// TODO(iuioiua): Just use `Deno.errors.NotCapable` once Deno 2 is released.
IS_DENO_2 ? "NotCapable" : "PermissionDenied",
);
assertStringIncludes(decoder.decode(stderr), "NotCapable");
},
);

109 changes: 0 additions & 109 deletions fs/unstable_rename_test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license.

import { assert, assertRejects, assertThrows } from "@std/assert";
import { lessOrEqual, parse as parseSemver } from "@std/semver";
import { rename, renameSync } from "./unstable_rename.ts";
import { NotFound } from "./unstable_errors.js";
import { mkdir, mkdtemp, open, rm, stat, symlink } from "node:fs/promises";
@@ -18,12 +17,6 @@ import {
symlinkSync,
} from "node:fs";

// In Deno 2.2.2 or earlier, the `rename` function has an issue on Windows.
const RENAME_HAS_ISSUE = Deno.version &&
parseSemver(Deno.version.deno).build?.length === 0 && // not canary
lessOrEqual(parseSemver(Deno.version.deno), parseSemver("2.2.2")) &&
platform() === "win32";

/** Tests if the original file/directory is missing since the file is renamed.
* Uses Node.js Error instances to check because the `lstatSync` function is
* pulled in from the `node:fs` package without using `mapError`. */
@@ -93,46 +86,6 @@ Deno.test("rename() rejects with Error when an existing directory is renamed wit
await rm(tempDirPath, { recursive: true, force: true });
});

Deno.test(
"rename() succeeds when an existing directory is renamed with another directory path",
{ ignore: RENAME_HAS_ISSUE },
async () => {
const tempDirPath = await mkdtemp(resolve(tmpdir(), "rename_"));
const testDir = join(tempDirPath, "testDir");
const anotherDir = join(tempDirPath, "anotherDir");

await mkdir(testDir);
await mkdir(anotherDir);

await rename(testDir, anotherDir);
assertMissing(testDir);
const anotherDirStat = await stat(anotherDir);
assert(anotherDirStat.isDirectory());

await rm(tempDirPath, { recursive: true, force: true });
},
);

Deno.test(
"rename() rejects with Error when an existing directory is renamed with an existing regular file path",
{ ignore: RENAME_HAS_ISSUE },
async () => {
const tempDirPath = await mkdtemp(resolve(tmpdir(), "rename_"));
const testFile = join(tempDirPath, "testFile.txt");
const testDir = join(tempDirPath, "testDir");

const testFh = await open(testFile, "w");
await testFh.close();
await mkdir(testDir);

await assertRejects(async () => {
await rename(testDir, testFile);
}, Error);

await rm(tempDirPath, { recursive: true, force: true });
},
);

Deno.test({
name:
"rename() rejects with Error when renaming an existing directory with a valid symlink'd regular file path",
@@ -250,68 +203,6 @@ Deno.test("renameSync() throws with Error when an existing file path is renamed
rmSync(tempDirPath, { recursive: true, force: true });
});

Deno.test(
"renameSync() throws with Error when an existing directory is renamed with an existing directory containing a file",
{ ignore: RENAME_HAS_ISSUE },
() => {
const tempDirPath = mkdtempSync(resolve(tmpdir(), "renameSync_"));
const emptyDir = join(tempDirPath, "emptyDir");
const fullDir = join(tempDirPath, "fullDir");
const testFile = join(fullDir, "testFile.txt");

mkdirSync(fullDir);
mkdirSync(emptyDir);
const testFd = openSync(testFile, "w");
closeSync(testFd);

assertThrows(() => {
renameSync(emptyDir, fullDir);
}, Error);

rmSync(tempDirPath, { recursive: true, force: true });
},
);

Deno.test(
"renameSync() succeeds when an existing directory is renamed with another directory path",
{ ignore: RENAME_HAS_ISSUE },
() => {
const tempDirPath = mkdtempSync(resolve(tmpdir(), "renameSync_"));
const testDir = join(tempDirPath, "testDir");
const anotherDir = join(tempDirPath, "anotherDir");

mkdirSync(testDir);
mkdirSync(anotherDir);

renameSync(testDir, anotherDir);
assertMissing(testDir);
const anotherDirStat = statSync(anotherDir);
assert(anotherDirStat.isDirectory());

rmSync(tempDirPath, { recursive: true, force: true });
},
);

Deno.test(
"renameSync() throws with Error when an existing directory is renamed with an existing regular file path",
{ ignore: RENAME_HAS_ISSUE },
() => {
const tempDirPath = mkdtempSync(resolve(tmpdir(), "renameSync_"));
const testFile = join(tempDirPath, "testFile.txt");
const testDir = join(tempDirPath, "testDir");

const testFd = openSync(testFile, "w");
closeSync(testFd);
mkdirSync(testDir);

assertThrows(() => {
renameSync(testDir, testFile);
}, Error);

rmSync(tempDirPath, { recursive: true, force: true });
},
);

Deno.test({
name:
"renameSync() throws with Error when renaming an existing directory with a valid symlink'd regular file path",
18 changes: 2 additions & 16 deletions http/file_server_test.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,6 @@ import denoConfig from "./deno.json" with { type: "json" };
import { MINUTE } from "@std/datetime/constants";
import { getAvailablePort } from "@std/net/get-available-port";
import { concat } from "@std/bytes/concat";
import { lessThan, parse as parseSemver } from "@std/semver";

const moduleDir = dirname(fromFileUrl(import.meta.url));
const testdataDir = resolve(moduleDir, "testdata");
@@ -33,11 +32,6 @@ const serveDirOptions: ServeDirOptions = {
showDotfiles: true,
enableCors: true,
};
const denoVersion = parseSemver(Deno.version.deno);
const isCanary = denoVersion.build ? denoVersion.build.length > 0 : false;
// FileInfo.mode is not available on Windows before Deno 2.1.0
const fsModeUnavailable = Deno.build.os === "windows" &&
lessThan(denoVersion, parseSemver("2.1.0")) && !isCanary;

const TEST_FILE_PATH = join(testdataDir, "test_file.txt");
const TEST_FILE_STAT = await Deno.stat(TEST_FILE_PATH);
@@ -181,11 +175,7 @@ Deno.test("serveDir() serves directory index", async () => {
assertStringIncludes(page, '<a href="./hello.html">hello.html</a>');
assertStringIncludes(page, '<a href="./tls/">tls/</a>');
assertStringIncludes(page, "%2525A.txt");
if (fsModeUnavailable) {
assertMatch(page, /<td class="mode">(\s)*\(unknown mode\)(\s)*<\/td>/);
} else {
assertMatch(page, /<td class="mode">(\s)*[a-zA-Z- ]{14}(\s)*<\/td>/);
}
assertMatch(page, /<td class="mode">(\s)*[a-zA-Z- ]{14}(\s)*<\/td>/);

await Deno.remove(filePath);
});
@@ -216,11 +206,7 @@ Deno.test("serveDir() serves directory index with file containing space in the f
assertStringIncludes(page, '<a href="./hello.html">hello.html</a>');
assertStringIncludes(page, '<a href="./tls/">tls/</a>');
assertStringIncludes(page, "test%20file.txt");
if (fsModeUnavailable) {
assertMatch(page, /<td class="mode">(\s)*\(unknown mode\)(\s)*<\/td>/);
} else {
assertMatch(page, /<td class="mode">(\s)*[a-zA-Z- ]{14}(\s)*<\/td>/);
}
assertMatch(page, /<td class="mode">(\s)*\(unknown mode\)(\s)*<\/td>/);

await Deno.remove(filePath);
});
3 changes: 0 additions & 3 deletions internal/_is_deno_2.ts

This file was deleted.

3 changes: 0 additions & 3 deletions testing/_snapshot_utils.ts
Original file line number Diff line number Diff line change
@@ -99,6 +99,3 @@ export function getSnapshotNotMatchMessage(
`Snapshot does not match:\n${diffMsg}\nTo update snapshots, run\n deno test --allow-read --allow-write [files]... -- --update\n`;
return getErrorMessage(message, options);
}

// TODO (WWRS): Remove this when we drop support for Deno 1.x
export const LINT_SUPPORTED = !Deno.version.deno.startsWith("1.");