CI / lint (pull_request) Successful in 1m51s
CI / format (pull_request) Successful in 2m3s
CI / install (pull_request) Successful in 6m59s
CI / typetest (pull_request) Successful in 1m53s
CI / typecheck (pull_request) Successful in 2m30s
CI / node-tests (pull_request) Successful in 2m58s
CI / browser-tests (pull_request) Successful in 3m45s
Co-Authored-By: gpt-5.6-sol <noreply@openai.com>
126 lines
5.2 KiB
JavaScript
126 lines
5.2 KiB
JavaScript
import assert from "node:assert/strict"
|
|
import fs from "node:fs/promises"
|
|
import path from "node:path"
|
|
import { test } from "node:test"
|
|
import { ESLint } from "eslint"
|
|
|
|
const eslint = new ESLint()
|
|
|
|
async function messages(
|
|
source,
|
|
filePath = "packages/sftp/src/package-boundary-check.ts",
|
|
instance = eslint,
|
|
) {
|
|
const [result] = await instance.lintText(source, { filePath })
|
|
return result.messages.map(({ message, ruleId }) => ({ message, ruleId }))
|
|
}
|
|
|
|
test("rejects non-exact cross-package internal dependencies", async () => {
|
|
for (const specifier of [
|
|
"@webnet/ssh/_internals",
|
|
"@webnet/ssh/_internals.js",
|
|
"@webnet/transport/loopback/_internals",
|
|
"@webnet/transport/loopback/_internals.js",
|
|
]) {
|
|
const result = await messages(`import { Reader } from "${specifier}"; void Reader`)
|
|
assert.ok(
|
|
result.some(
|
|
({ message, ruleId }) =>
|
|
ruleId === "package-boundary/exact-internal-dependencies" && message.includes("found *"),
|
|
),
|
|
)
|
|
}
|
|
})
|
|
|
|
test("rejects other internal imports from non-exact dependencies", async () => {
|
|
for (const source of [
|
|
'await import("@webnet/ssh/_internals.js")',
|
|
"await import(`@webnet/ssh/_internals.js`)",
|
|
'await import("@webnet/ssh/_internals.js" as string)',
|
|
'await import("@webnet/ssh/_internals.js" satisfies string)',
|
|
'type Reader = import("@webnet/ssh/_internals").Reader; let reader: Reader; void reader',
|
|
'import { createRequire } from "node:module"; const require = createRequire(import.meta.url); require("@webnet/ssh/_internals")',
|
|
'import { createRequire } from "node:module"; const require = createRequire(import.meta.url); (require as typeof require)("@webnet/ssh/_internals")',
|
|
'import { createRequire } from "node:module"; const require = createRequire(import.meta.url); (<typeof require>require)("@webnet/ssh/_internals")',
|
|
'import { createRequire } from "node:module"; const require = createRequire(import.meta.url); require!("@webnet/ssh/_internals")',
|
|
'import { createRequire } from "node:module"; const require = createRequire(import.meta.url); (require satisfies typeof require)("@webnet/ssh/_internals")',
|
|
]) {
|
|
const result = await messages(source)
|
|
assert.ok(
|
|
result.some(
|
|
({ message, ruleId }) =>
|
|
ruleId === "package-boundary/exact-internal-dependencies" && message.includes("found *"),
|
|
),
|
|
)
|
|
}
|
|
})
|
|
|
|
test("allows internal imports from exact dependencies", async () => {
|
|
const fixture = await fs.mkdtemp(path.resolve("packages/package-boundary-"))
|
|
try {
|
|
await fs.writeFile(
|
|
path.join(fixture, "package.json"),
|
|
JSON.stringify({
|
|
name: "@webnet/package-boundary-fixture",
|
|
dependencies: { "@webnet/ssh": "0.1.0" },
|
|
}),
|
|
)
|
|
const result = await messages(
|
|
'import { createRequire } from "node:module"; import { Reader } from "@webnet/ssh/_internals"; type InternalReader = import("@webnet/ssh/_internals").Reader; const require = createRequire(import.meta.url); void Reader; void (null as unknown as InternalReader); await import(`@webnet/ssh/_internals.js`); require("@webnet/ssh/_internals")',
|
|
path.join(fixture, "src/check.ts"),
|
|
)
|
|
assert.deepEqual(result, [])
|
|
} finally {
|
|
await fs.rm(fixture, { recursive: true })
|
|
}
|
|
})
|
|
|
|
test("rejects relative cross-package source escapes", async () => {
|
|
for (const [source, filePath] of [
|
|
['import { Reader } from "../../ssh/src/cursor.js"; void Reader'],
|
|
[
|
|
'await import("../../../ssh/src/cursor.js")',
|
|
"packages/sftp/src/server/package-boundary-check.ts",
|
|
],
|
|
['export { Reader } from "../../ssh/src/cursor.js"'],
|
|
['import { Reader } from "../../ssh/./src/cursor.js"; void Reader'],
|
|
['await import("../.././ssh/src/cursor.js")'],
|
|
['export { Reader } from "../../ssh/other/../src/cursor.js"'],
|
|
['import "../../ssh/dist/index.js"'],
|
|
]) {
|
|
const result = await messages(source, filePath)
|
|
assert.ok(
|
|
result.some(
|
|
({ message, ruleId }) =>
|
|
ruleId === "package-boundary/no-relative-source-escapes" &&
|
|
message.includes("Relative cross-package"),
|
|
),
|
|
)
|
|
}
|
|
})
|
|
|
|
test("rejects relative source escapes when invoked from a package directory", async () => {
|
|
const packageEslint = new ESLint({ cwd: path.resolve("packages/sftp") })
|
|
const result = await messages(
|
|
'import { Reader } from "../../ssh/src/cursor.js"; void Reader',
|
|
"src/package-boundary-check.ts",
|
|
packageEslint,
|
|
)
|
|
assert.ok(result.some(({ ruleId }) => ruleId === "package-boundary/no-relative-source-escapes"))
|
|
})
|
|
|
|
test("rejects wildcard and cross-package re-exports", async () => {
|
|
const wildcard = await messages('export * from "./local.js"')
|
|
assert.ok(wildcard.some(({ message }) => message.includes("Wildcard exports")))
|
|
|
|
const crossPackage = await messages('export { VFSError } from "@webnet/vfs"')
|
|
assert.ok(crossPackage.some(({ message }) => message.includes("Cross-package re-exports")))
|
|
})
|
|
|
|
test("allows public imports and explicit package-local exports", async () => {
|
|
const result = await messages(
|
|
'import { SSHClientConnection } from "@webnet/ssh"; import { Reader } from "./sftp/cursor.js"; export { SSHClientConnection, Reader }',
|
|
)
|
|
assert.deepEqual(result, [])
|
|
})
|