Skip to content
Merged
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
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@knighted/module",
"version": "1.5.1",
"version": "1.5.2",
"description": "Bidirectional transform for ES modules and CommonJS.",
"type": "module",
"main": "dist/module.js",
Expand Down Expand Up @@ -75,7 +75,6 @@
"typescript": "^5.9.3"
},
"dependencies": {
"glob": "^13.0.6",
"magic-string": "^0.30.21",
"oxc-parser": "^0.116.0",
"periscopic": "^4.0.2"
Expand Down
17 changes: 8 additions & 9 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import {
stderr as defaultStderr,
} from 'node:process'
import { parseArgs } from 'node:util'
import { readFile, mkdir, writeFile } from 'node:fs/promises'
import { readFile, mkdir, writeFile, glob } from 'node:fs/promises'
import { dirname, resolve, relative, join, basename } from 'node:path'
import { glob } from 'glob'

import type { TemplateLiteral } from '@oxc-project/types'

Expand Down Expand Up @@ -539,14 +538,14 @@ const normalizeSourceMapArgv = (argv: string[]) => {
const expandFiles = async (patterns: string[], cwd: string, ignore?: string[]) => {
const files = new Set<string>()
for (const pattern of patterns) {
const matches = await glob(pattern, {
for await (const match of glob(pattern, {
cwd,
absolute: true,
nodir: true,
windowsPathsNoEscape: true,
ignore,
})
for (const m of matches) files.add(resolve(m))
exclude: ignore,
withFileTypes: true,
})) {
if (match.isDirectory()) continue
files.add(resolve(match.parentPath, match.name))
}
}
return [...files]
}
Expand Down
121 changes: 121 additions & 0 deletions test/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,59 @@ test('--ignore excludes glob matches', async () => {
}
})

test('glob expansion excludes directories', async () => {
const temp = await mkdtemp(join(tmpdir(), 'module-cli-glob-nodir-'))
const nested = join(temp, 'nested')
const input = join(temp, 'input.cjs')

await mkdir(nested, { recursive: true })
await copyFile(fixture, input)

try {
const result = runCli(['--list', '--target', 'module', '--cwd', temp, '*'])

assert.equal(result.status, 0)
assert.ok(result.stdout.includes('input.cjs'))
assert.ok(!result.stdout.includes('nested'))
} finally {
await rm(temp, { recursive: true, force: true })
}
})

test('windows: backslash glob and ignore patterns are honored', async () => {
if (process.platform !== 'win32') return

const temp = await mkdtemp(join(tmpdir(), 'module-cli-win-glob-'))
const srcDir = join(temp, 'src')
const keep = join(srcDir, 'keep.cjs')
const ignoredDir = join(temp, 'node_modules', 'pkg')
const ignored = join(ignoredDir, 'index.cjs')

await mkdir(srcDir, { recursive: true })
await mkdir(ignoredDir, { recursive: true })
await copyFile(fixture, keep)
await copyFile(fixture, ignored)

try {
const result = runCli([
'--list',
'--target',
'module',
'--cwd',
temp,
'src\\**\\*.cjs',
'--ignore',
'node_modules\\**',
])

assert.equal(result.status, 0)
assert.ok(result.stdout.includes('keep.cjs'))
assert.ok(!result.stdout.includes('node_modules'))
} finally {
await rm(temp, { recursive: true, force: true })
}
})

test('-H error exits on dual package hazard', async () => {
const temp = await mkdtemp(join(tmpdir(), 'module-cli-dual-hazard-'))
const file = join(temp, 'entry.mjs')
Expand Down Expand Up @@ -670,6 +723,74 @@ test('globals-only pre-tsc flow matches README example', async () => {
}
})

test('globals-only pre-tsc flow with README glob pattern', async () => {
const temp = await mkdtemp(join(tmpdir(), 'module-cli-pre-tsc-glob-'))
const srcDir = join(temp, 'src')
const nestedDir = join(srcDir, 'nested')
const file = join(nestedDir, 'index.ts')

await mkdir(nestedDir, { recursive: true })
await writeFile(
join(temp, 'tsconfig.json'),
JSON.stringify(
{
compilerOptions: {
target: 'ES2020',
module: 'commonjs',
outDir: 'dist',
strict: false,
esModuleInterop: true,
types: ['node'],
typeRoots: [join(projectRoot, 'node_modules', '@types')],
},
include: ['src'],
},
null,
2,
),
'utf8',
)
await writeFile(
file,
[
"import fs from 'node:fs'",
'export const meta = import.meta.url',
'export const size = fs.statSync(__filename).size',
'',
].join('\n'),
'utf8',
)

try {
const before = spawnSync(process.execPath, [tscBin, '-p', temp], { encoding: 'utf8' })
assert.notEqual(before.status, 0)

const result = runCli(
[
'--target',
'commonjs',
'--transform-syntax',
'globals-only',
'--ignore',
'node_modules/**',
'--in-place',
'src/**/*.{ts,js,mts,cts}',
],
undefined,
{ cwd: temp },
)

assert.equal(result.status, 0)
const transformed = await readFile(file, 'utf8')
assert.ok(!transformed.includes('import.meta'))

const after = spawnSync(process.execPath, [tscBin, '-p', temp], { encoding: 'utf8' })
assert.equal(after.status, 0, after.stderr || after.stdout)
} finally {
await rm(temp, { recursive: true, force: true })
}
})

test('--dry-run does not create outputs when out-dir provided', async () => {
const temp = await mkdtemp(join(tmpdir(), 'module-cli-'))
const outDir = join(temp, 'out')
Expand Down