skyltmax_config 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/boot.sh +55 -16
- data/.devcontainer/devcontainer.json +7 -1
- data/.devcontainer/docker-compose.yml +1 -1
- data/.gitignore +2 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +18 -18
- data/README.md +12 -21
- data/eslint.js +17 -1
- data/fixture/package.json +4 -22
- data/fixture/pnpm-lock.yaml +844 -1040
- data/fixture/pnpm-workspace.yaml +6 -0
- data/lib/skyltmax_config/version.rb +1 -1
- data/package.json +23 -25
- data/pnpm-lock.yaml +1108 -1456
- data/pnpm-workspace.yaml +10 -0
- data/prettier.js +3 -1
- data/skyltmax_config.gemspec +3 -1
- data/tests/configs.test.js +47 -0
- metadata +5 -9
- data/AGENTS.md +0 -677
- data/scripts/peer-deps/audit.js +0 -132
- data/scripts/peer-deps/install.js +0 -206
- data/tests/check-peers.test.js +0 -76
- data/tests/fixtures/manifest-no-peers.json +0 -3
- data/tests/fixtures/manifest-with-peers.json +0 -6
- data/tests/install-peers.test.js +0 -115
data/scripts/peer-deps/audit.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { existsSync, realpathSync } from "node:fs"
|
|
4
|
-
import { readFile } from "node:fs/promises"
|
|
5
|
-
import { createRequire } from "node:module"
|
|
6
|
-
import { dirname, resolve } from "node:path"
|
|
7
|
-
import { fileURLToPath } from "node:url"
|
|
8
|
-
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
10
|
-
const __dirname = dirname(__filename)
|
|
11
|
-
const defaultManifestPath = resolve(__dirname, "..", "..", "package.json")
|
|
12
|
-
const defaultConsumerRoot = process.env.INIT_CWD ?? process.env.npm_config_local_prefix ?? process.cwd()
|
|
13
|
-
|
|
14
|
-
async function readManifest(path) {
|
|
15
|
-
const raw = await readFile(path, "utf8")
|
|
16
|
-
return JSON.parse(raw)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function createConsumerRequire(root) {
|
|
20
|
-
const candidate = resolve(root, "package.json")
|
|
21
|
-
if (existsSync(candidate)) {
|
|
22
|
-
return createRequire(candidate)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return createRequire(import.meta.url)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function auditPeerDependencies({
|
|
29
|
-
manifestPath = defaultManifestPath,
|
|
30
|
-
consumerRoot = defaultConsumerRoot,
|
|
31
|
-
} = {}) {
|
|
32
|
-
const manifest = await readManifest(manifestPath)
|
|
33
|
-
const peers = Object.entries(manifest.peerDependencies ?? {})
|
|
34
|
-
|
|
35
|
-
if (!peers.length) {
|
|
36
|
-
return {
|
|
37
|
-
peers,
|
|
38
|
-
missing: [],
|
|
39
|
-
mismatched: [],
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const requireFromConsumer = createConsumerRequire(consumerRoot)
|
|
44
|
-
const missing = []
|
|
45
|
-
const mismatched = []
|
|
46
|
-
|
|
47
|
-
for (const [name, expectedVersion] of peers) {
|
|
48
|
-
let resolvedPackageJson
|
|
49
|
-
try {
|
|
50
|
-
resolvedPackageJson = requireFromConsumer.resolve(`${name}/package.json`)
|
|
51
|
-
} catch (error) {
|
|
52
|
-
missing.push({ name, expectedVersion, reason: error.message })
|
|
53
|
-
continue
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const pkg = JSON.parse(await readFile(resolvedPackageJson, "utf8"))
|
|
58
|
-
const actualVersion = pkg.version
|
|
59
|
-
if (actualVersion !== expectedVersion) {
|
|
60
|
-
mismatched.push({ name, expectedVersion, actualVersion })
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
mismatched.push({ name, expectedVersion, actualVersion: "unknown", reason: error.message })
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
peers,
|
|
69
|
-
missing,
|
|
70
|
-
mismatched,
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function formatAuditMessage({ missing, mismatched }) {
|
|
75
|
-
if (!missing.length && !mismatched.length) {
|
|
76
|
-
return null
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const lines = ["[skyltmax-config] Peer dependency check detected issues:"]
|
|
80
|
-
|
|
81
|
-
if (missing.length) {
|
|
82
|
-
lines.push(" Missing peers:")
|
|
83
|
-
for (const item of missing) {
|
|
84
|
-
lines.push(` - ${item.name}@${item.expectedVersion}`)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (mismatched.length) {
|
|
89
|
-
lines.push(" Version mismatches:")
|
|
90
|
-
for (const item of mismatched) {
|
|
91
|
-
const details = item.actualVersion ? ` (found ${item.actualVersion})` : ""
|
|
92
|
-
lines.push(` - ${item.name}@${item.expectedVersion}${details}`)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
lines.push(' Run "npx skyltmax-config-peers" to install the correct versions.')
|
|
97
|
-
|
|
98
|
-
return lines.join("\n")
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function runPostinstallAudit() {
|
|
102
|
-
try {
|
|
103
|
-
const result = await auditPeerDependencies()
|
|
104
|
-
const message = formatAuditMessage(result)
|
|
105
|
-
|
|
106
|
-
if (message) {
|
|
107
|
-
console.warn(message)
|
|
108
|
-
}
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.warn(`[skyltmax-config] Peer dependency check skipped: ${error.message}`)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const isDirectExecution = (() => {
|
|
115
|
-
const [argvPath] = process.argv.slice(1, 2)
|
|
116
|
-
|
|
117
|
-
if (!argvPath) return false
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
return realpathSync(argvPath) === realpathSync(__filename)
|
|
121
|
-
} catch (error) {
|
|
122
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
123
|
-
return false
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
throw error
|
|
127
|
-
}
|
|
128
|
-
})()
|
|
129
|
-
|
|
130
|
-
if (isDirectExecution) {
|
|
131
|
-
runPostinstallAudit()
|
|
132
|
-
}
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from "node:child_process"
|
|
3
|
-
import { existsSync, realpathSync } from "node:fs"
|
|
4
|
-
import { readFile } from "node:fs/promises"
|
|
5
|
-
import { dirname, resolve } from "node:path"
|
|
6
|
-
import { fileURLToPath } from "node:url"
|
|
7
|
-
|
|
8
|
-
const HELP = `Usage: skyltmax-config-peers [options]
|
|
9
|
-
|
|
10
|
-
Options:
|
|
11
|
-
--manager <name> npm | pnpm | bun (auto-detected by default)
|
|
12
|
-
--dry-run Print the install command without running it
|
|
13
|
-
--help Show this help message
|
|
14
|
-
`
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
17
|
-
const __dirname = dirname(__filename)
|
|
18
|
-
const defaultManifestPath = resolve(__dirname, "..", "..", "package.json")
|
|
19
|
-
|
|
20
|
-
export async function loadPeerDependencies(manifestPath = defaultManifestPath) {
|
|
21
|
-
const manifest = JSON.parse(await readFile(manifestPath, "utf8"))
|
|
22
|
-
const peers = manifest.peerDependencies ?? {}
|
|
23
|
-
return Object.entries(peers).map(([name, version]) => `${name}@${version}`)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function detectManager({ managerArg, userAgent = "", cwd = process.cwd() } = {}) {
|
|
27
|
-
if (managerArg) return managerArg
|
|
28
|
-
|
|
29
|
-
if (userAgent.startsWith("pnpm/")) return "pnpm"
|
|
30
|
-
if (userAgent.startsWith("bun/")) return "bun"
|
|
31
|
-
if (userAgent.startsWith("npm/")) return "npm"
|
|
32
|
-
|
|
33
|
-
if (existsSync(resolve(cwd, "pnpm-lock.yaml"))) return "pnpm"
|
|
34
|
-
if (existsSync(resolve(cwd, "bun.lockb"))) return "bun"
|
|
35
|
-
if (existsSync(resolve(cwd, "package-lock.json"))) return "npm"
|
|
36
|
-
|
|
37
|
-
return "npm"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function findPnpmWorkspaceRoot(startDir) {
|
|
41
|
-
let current = resolve(startDir)
|
|
42
|
-
|
|
43
|
-
while (true) {
|
|
44
|
-
if (existsSync(resolve(current, "pnpm-workspace.yaml")) || existsSync(resolve(current, "pnpm-workspace.yml"))) {
|
|
45
|
-
return current
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const parent = dirname(current)
|
|
49
|
-
|
|
50
|
-
if (parent === current) {
|
|
51
|
-
return undefined
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
current = parent
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function buildInstallCommand(manager, packages, { cwd = process.cwd() } = {}) {
|
|
59
|
-
if (!packages.length) {
|
|
60
|
-
throw new Error("No peer dependencies to install.")
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (manager === "pnpm") {
|
|
64
|
-
const workspaceRoot = findPnpmWorkspaceRoot(cwd)
|
|
65
|
-
const args = ["add", "-D", "--save-exact", ...packages]
|
|
66
|
-
|
|
67
|
-
if (workspaceRoot) {
|
|
68
|
-
args.splice(2, 0, "-w")
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
command: "pnpm",
|
|
73
|
-
args,
|
|
74
|
-
cwd: workspaceRoot ?? cwd,
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (manager === "npm") {
|
|
79
|
-
return {
|
|
80
|
-
command: "npm",
|
|
81
|
-
args: ["install", "--save-dev", "--save-exact", ...packages],
|
|
82
|
-
cwd,
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (manager === "bun") {
|
|
87
|
-
return {
|
|
88
|
-
command: "bun",
|
|
89
|
-
args: ["add", "--dev", "--exact", ...packages],
|
|
90
|
-
cwd,
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const supported = "npm, pnpm, bun"
|
|
95
|
-
throw new Error(`Unsupported package manager: ${manager}. Supported managers: ${supported}`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function formatCommand({ command, args }) {
|
|
99
|
-
return `${command} ${args.join(" ")}`
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export async function prepareInstall({
|
|
103
|
-
managerArg,
|
|
104
|
-
cwd = process.cwd(),
|
|
105
|
-
env = process.env,
|
|
106
|
-
manifestPath = defaultManifestPath,
|
|
107
|
-
} = {}) {
|
|
108
|
-
const packages = await loadPeerDependencies(manifestPath)
|
|
109
|
-
|
|
110
|
-
if (packages.length === 0) {
|
|
111
|
-
return { packages: [] }
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const manager = detectManager({ managerArg, userAgent: env.npm_config_user_agent ?? "", cwd })
|
|
115
|
-
const command = buildInstallCommand(manager, packages, { cwd })
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
manager,
|
|
119
|
-
packages,
|
|
120
|
-
command: command.command,
|
|
121
|
-
args: command.args,
|
|
122
|
-
cwd: command.cwd ?? cwd,
|
|
123
|
-
printable: formatCommand(command),
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export async function runCli({ args = process.argv.slice(2), env = process.env, cwd = process.cwd() } = {}) {
|
|
128
|
-
if (args.includes("--help")) {
|
|
129
|
-
process.stdout.write(HELP)
|
|
130
|
-
return 0
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const argValue = flag => {
|
|
134
|
-
const index = args.indexOf(flag)
|
|
135
|
-
if (index === -1) return undefined
|
|
136
|
-
return args[index + 1]
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const managerArg = argValue("--manager")
|
|
140
|
-
const dryRun = args.includes("--dry-run")
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
const result = await prepareInstall({ managerArg, cwd, env })
|
|
144
|
-
|
|
145
|
-
if (!result.packages || result.packages.length === 0) {
|
|
146
|
-
process.stdout.write("No peer dependencies found on @skyltmax/config.\n")
|
|
147
|
-
return 0
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (dryRun) {
|
|
151
|
-
process.stdout.write(`${result.printable}\n`)
|
|
152
|
-
return 0
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
process.stdout.write(`Running: ${result.printable}\n`)
|
|
156
|
-
|
|
157
|
-
const child = spawn(result.command, result.args, {
|
|
158
|
-
stdio: "inherit",
|
|
159
|
-
cwd: result.cwd,
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
return await new Promise((resolve, reject) => {
|
|
163
|
-
child.on("close", code => {
|
|
164
|
-
if (code === 0) {
|
|
165
|
-
resolve(0)
|
|
166
|
-
} else {
|
|
167
|
-
reject(new Error(`${result.command} exited with code ${code}`))
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
child.on("error", error => {
|
|
172
|
-
reject(error)
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
} catch (error) {
|
|
176
|
-
process.stderr.write(`${error.message}\n`)
|
|
177
|
-
return 1
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const isDirectExecution = (() => {
|
|
182
|
-
const [argvPath] = process.argv.slice(1, 2)
|
|
183
|
-
|
|
184
|
-
if (!argvPath) return false
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
return realpathSync(argvPath) === realpathSync(__filename)
|
|
188
|
-
} catch (error) {
|
|
189
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
190
|
-
return false
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
throw error
|
|
194
|
-
}
|
|
195
|
-
})()
|
|
196
|
-
|
|
197
|
-
if (isDirectExecution) {
|
|
198
|
-
runCli()
|
|
199
|
-
.then(code => {
|
|
200
|
-
process.exit(code)
|
|
201
|
-
})
|
|
202
|
-
.catch(error => {
|
|
203
|
-
process.stderr.write(`${error.message}\n`)
|
|
204
|
-
process.exit(1)
|
|
205
|
-
})
|
|
206
|
-
}
|
data/tests/check-peers.test.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { mkdtemp, writeFile, mkdir } from "node:fs/promises"
|
|
2
|
-
import { tmpdir } from "node:os"
|
|
3
|
-
import { join } from "node:path"
|
|
4
|
-
import { fileURLToPath } from "node:url"
|
|
5
|
-
import { describe, expect, test } from "vitest"
|
|
6
|
-
|
|
7
|
-
import { auditPeerDependencies, formatAuditMessage } from "../scripts/peer-deps/audit.js"
|
|
8
|
-
|
|
9
|
-
const fixturePath = relative => fileURLToPath(new URL(`./fixtures/${relative}`, import.meta.url))
|
|
10
|
-
|
|
11
|
-
async function createPackage(root, name, version) {
|
|
12
|
-
const parts = name.split("/")
|
|
13
|
-
const packageDir = join(root, "node_modules", ...parts)
|
|
14
|
-
await mkdir(packageDir, { recursive: true })
|
|
15
|
-
await writeFile(join(packageDir, "package.json"), JSON.stringify({ name, version }), "utf8")
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async function createProjectRoot() {
|
|
19
|
-
const root = await mkdtemp(join(tmpdir(), "skyltmax-check-peers-"))
|
|
20
|
-
await writeFile(join(root, "package.json"), JSON.stringify({ name: "example", version: "1.0.0" }), "utf8")
|
|
21
|
-
return root
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe("check-peers audit", () => {
|
|
25
|
-
test("returns empty when all peers match", async () => {
|
|
26
|
-
const root = await createProjectRoot()
|
|
27
|
-
await createPackage(root, "eslint", "9.39.1")
|
|
28
|
-
await createPackage(root, "prettier", "3.6.2")
|
|
29
|
-
|
|
30
|
-
const result = await auditPeerDependencies({
|
|
31
|
-
manifestPath: fixturePath("manifest-with-peers.json"),
|
|
32
|
-
consumerRoot: root,
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
expect(result.missing).toEqual([])
|
|
36
|
-
expect(result.mismatched).toEqual([])
|
|
37
|
-
expect(formatAuditMessage(result)).toBeNull()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test("detects missing peers", async () => {
|
|
41
|
-
const root = await createProjectRoot()
|
|
42
|
-
await createPackage(root, "eslint", "9.39.1")
|
|
43
|
-
|
|
44
|
-
const result = await auditPeerDependencies({
|
|
45
|
-
manifestPath: fixturePath("manifest-with-peers.json"),
|
|
46
|
-
consumerRoot: root,
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
expect(result.missing.map(item => item.name)).toEqual(["prettier"])
|
|
50
|
-
const message = formatAuditMessage(result)
|
|
51
|
-
expect(message).toContain("Missing peers")
|
|
52
|
-
expect(message).toContain("prettier@3.6.2")
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test("detects version mismatches", async () => {
|
|
56
|
-
const root = await createProjectRoot()
|
|
57
|
-
await createPackage(root, "eslint", "9.0.0")
|
|
58
|
-
await createPackage(root, "prettier", "3.6.2")
|
|
59
|
-
|
|
60
|
-
const result = await auditPeerDependencies({
|
|
61
|
-
manifestPath: fixturePath("manifest-with-peers.json"),
|
|
62
|
-
consumerRoot: root,
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
expect(result.mismatched).toEqual([
|
|
66
|
-
{
|
|
67
|
-
name: "eslint",
|
|
68
|
-
expectedVersion: "9.39.1",
|
|
69
|
-
actualVersion: "9.0.0",
|
|
70
|
-
},
|
|
71
|
-
])
|
|
72
|
-
const message = formatAuditMessage(result)
|
|
73
|
-
expect(message).toContain("Version mismatches")
|
|
74
|
-
expect(message).toContain("eslint@9.39.1 (found 9.0.0)")
|
|
75
|
-
})
|
|
76
|
-
})
|
data/tests/install-peers.test.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { mkdir, mkdtemp, writeFile } from "node:fs/promises"
|
|
2
|
-
import { tmpdir } from "node:os"
|
|
3
|
-
import { join } from "node:path"
|
|
4
|
-
import { fileURLToPath } from "node:url"
|
|
5
|
-
import { describe, expect, test } from "vitest"
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
buildInstallCommand,
|
|
9
|
-
detectManager,
|
|
10
|
-
formatCommand,
|
|
11
|
-
loadPeerDependencies,
|
|
12
|
-
prepareInstall,
|
|
13
|
-
} from "../scripts/peer-deps/install.js"
|
|
14
|
-
|
|
15
|
-
const fixturePath = relative => fileURLToPath(new URL(`./fixtures/${relative}`, import.meta.url))
|
|
16
|
-
|
|
17
|
-
describe("install-peers helper", () => {
|
|
18
|
-
test("loadPeerDependencies returns pinned peers", async () => {
|
|
19
|
-
const peers = await loadPeerDependencies(fixturePath("manifest-with-peers.json"))
|
|
20
|
-
expect(peers).toEqual(["eslint@9.39.1", "prettier@3.6.2"])
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test("loadPeerDependencies handles missing peers", async () => {
|
|
24
|
-
const peers = await loadPeerDependencies(fixturePath("manifest-no-peers.json"))
|
|
25
|
-
expect(peers).toEqual([])
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("detectManager respects explicit flag", () => {
|
|
29
|
-
const manager = detectManager({ managerArg: "pnpm" })
|
|
30
|
-
expect(manager).toBe("pnpm")
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test("detectManager infers from user agent", () => {
|
|
34
|
-
const manager = detectManager({ userAgent: "pnpm/9.0.0 npm/?" })
|
|
35
|
-
expect(manager).toBe("pnpm")
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test("detectManager infers from lockfile", async () => {
|
|
39
|
-
const dir = await mkdtemp(join(tmpdir(), "skyltmax-config-"))
|
|
40
|
-
await writeFile(join(dir, "bun.lockb"), "")
|
|
41
|
-
const manager = detectManager({ cwd: dir })
|
|
42
|
-
expect(manager).toBe("bun")
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test("buildInstallCommand supports npm", () => {
|
|
46
|
-
const result = buildInstallCommand("npm", ["eslint@9.39.1"])
|
|
47
|
-
expect(result.command).toBe("npm")
|
|
48
|
-
expect(result.args).toEqual(["install", "--save-dev", "--save-exact", "eslint@9.39.1"])
|
|
49
|
-
expect(formatCommand(result)).toBe("npm install --save-dev --save-exact eslint@9.39.1")
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test("buildInstallCommand adds -w flag in pnpm workspaces", async () => {
|
|
53
|
-
const workspaceDir = await mkdtemp(join(tmpdir(), "skyltmax-config-workspace-"))
|
|
54
|
-
await writeFile(join(workspaceDir, "pnpm-workspace.yaml"), "packages:\n - packages/*\n")
|
|
55
|
-
const packageDir = join(workspaceDir, "packages", "app")
|
|
56
|
-
await mkdir(packageDir, { recursive: true })
|
|
57
|
-
|
|
58
|
-
const result = buildInstallCommand("pnpm", ["eslint@9.39.1"], { cwd: packageDir })
|
|
59
|
-
|
|
60
|
-
expect(result.command).toBe("pnpm")
|
|
61
|
-
expect(result.args).toEqual(["add", "-D", "-w", "--save-exact", "eslint@9.39.1"])
|
|
62
|
-
expect(result.cwd).toBe(workspaceDir)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test("buildInstallCommand throws on unsupported manager", () => {
|
|
66
|
-
expect(() => buildInstallCommand("yarn", ["eslint@9.39.1"])).toThrow(/Unsupported package manager/)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test("prepareInstall returns printable command", async () => {
|
|
70
|
-
const result = await prepareInstall({
|
|
71
|
-
managerArg: "npm",
|
|
72
|
-
env: {},
|
|
73
|
-
cwd: process.cwd(),
|
|
74
|
-
manifestPath: fixturePath("manifest-with-peers.json"),
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
expect(result.manager).toBe("npm")
|
|
78
|
-
expect(result.packages).toEqual(["eslint@9.39.1", "prettier@3.6.2"])
|
|
79
|
-
expect(result.printable).toBe("npm install --save-dev --save-exact eslint@9.39.1 prettier@3.6.2")
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test("prepareInstall targets pnpm workspace root", async () => {
|
|
83
|
-
const workspaceDir = await mkdtemp(join(tmpdir(), "skyltmax-config-workspace-"))
|
|
84
|
-
await writeFile(join(workspaceDir, "pnpm-workspace.yaml"), "packages:\n - packages/*\n")
|
|
85
|
-
const manifestPath = join(workspaceDir, "package.json")
|
|
86
|
-
await writeFile(manifestPath, JSON.stringify({ peerDependencies: { eslint: "9.39.1" } }, null, 2))
|
|
87
|
-
|
|
88
|
-
const packageDir = join(workspaceDir, "packages", "app")
|
|
89
|
-
await mkdir(packageDir, { recursive: true })
|
|
90
|
-
|
|
91
|
-
const result = await prepareInstall({
|
|
92
|
-
managerArg: "pnpm",
|
|
93
|
-
env: {},
|
|
94
|
-
cwd: packageDir,
|
|
95
|
-
manifestPath,
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
expect(result.manager).toBe("pnpm")
|
|
99
|
-
expect(result.packages).toEqual(["eslint@9.39.1"])
|
|
100
|
-
expect(result.args).toEqual(["add", "-D", "-w", "--save-exact", "eslint@9.39.1"])
|
|
101
|
-
expect(result.cwd).toBe(workspaceDir)
|
|
102
|
-
expect(result.printable).toBe("pnpm add -D -w --save-exact eslint@9.39.1")
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
test("prepareInstall returns empty when no peers", async () => {
|
|
106
|
-
const result = await prepareInstall({
|
|
107
|
-
managerArg: "npm",
|
|
108
|
-
env: {},
|
|
109
|
-
cwd: process.cwd(),
|
|
110
|
-
manifestPath: fixturePath("manifest-no-peers.json"),
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
expect(result.packages).toEqual([])
|
|
114
|
-
})
|
|
115
|
-
})
|