Skip to content

Commit

Permalink
feat!: specifier, out options. (#3)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: renamed option specifiers to specifier.
  • Loading branch information
knightedcodemonkey authored May 28, 2024
1 parent 077f985 commit a034fd6
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 72 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,13 @@ type ModuleOptions = {
/* Whether import/export and require/exports should be transformed. */
modules?: boolean
/* Whether to change specifier extensions to the assigned value. If omitted they are left alone. */
specifiers?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
/* What filepath to write the transformed source to. If omitted the transformed source is returned. */
specifier?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
/* What filepath to write the transformed source to. */
out?: string
}
```
## Roadmap
- Support option `modules`.
- Remove `@knighted/specifier` and avoid double parsing.
4 changes: 3 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ export default tseslint.config(
},
},
{
files: ['test/**/*.cjs'],
files: ['test/fixtures/**/*'],
rules: {
'no-undef': 'off',
'n/no-missing-import': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
},
},
)
116 changes: 65 additions & 51 deletions package-lock.json

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

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@knighted/module",
"version": "1.0.0-alpha.2",
"version": "1.0.0-alpha.3",
"description": "Converts module differences in source files between ES and CommonJS.",
"type": "module",
"main": "dist/module.js",
Expand Down Expand Up @@ -70,11 +70,12 @@
"prettier": "^3.2.5",
"tsx": "^4.11.0",
"typescript": "^5.4.5",
"typescript-eslint": "^8.0.0-alpha.16"
"typescript-eslint": "^8.0.0-alpha.18"
},
"dependencies": {
"@babel/parser": "^7.24.6",
"@babel/traverse": "^7.24.6",
"@knighted/specifier": "^2.0.0-rc.1",
"magic-string": "^0.30.10"
},
"prettier": {
Expand Down
34 changes: 27 additions & 7 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
import { resolve } from 'node:path'
import { readFile } from 'node:fs/promises'
import { readFile, writeFile } from 'node:fs/promises'

import { specifier } from '@knighted/specifier'

import { parse } from './parse.js'
import { format } from './format.js'
import type { ModuleOptions } from './types.js'

/**
* Defaults to only transforming ES module globals to CommonJS.
*/
const defaultOptions = {
type: 'commonjs',
out: undefined,
modules: false,
specifiers: undefined,
specifier: undefined,
} satisfies ModuleOptions

const transform = async (filename: string, options: ModuleOptions = defaultOptions) => {
const opts = { ...defaultOptions, ...options }
const file = resolve(filename)
const code = (await readFile(file)).toString()
const ast = parse(code)
let source = format(code, ast, opts).toString()

if (options.specifier) {
const { code, error } = await specifier.updateSrc(source, ({ value }) => {
// Collapse any BinaryExpression or NewExpression to test for a relative specifier
const collapsed = value.replace(/['"`+)\s]|new String\(/g, '')
const relative = /^(?:\.|\.\.)\//

if (relative.test(collapsed)) {
// $2 is for any closing quotation/parens around BE or NE
return value.replace(/(.+)\.(?:m|c)?(?:j|t)s([)'"`]*)?$/, `$1${options.specifier}$2`)
}
})

if (code && !error) {
source = code
}
}

if (opts.out) {
await writeFile(resolve(opts.out), source)
}

// TODO: Support `out` option.
return format(code, ast, opts).toString()
return source
}

export { transform }
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export type ModuleOptions = {
/* Whether import/export and require/exports should be transformed. */
modules?: boolean
/* Whether to change specifier extensions to the assigned value. If omitted they are left alone. */
specifiers?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
/* What filepath to write the transformed source to. If omitted the transformed source is returned. */
specifier?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
/* What filepath to write the transformed source to. */
out?: string
}

Expand Down
5 changes: 3 additions & 2 deletions test/fixtures/file.cjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// CommonJS was like the Wild Wild West (require.extensions is deprecated so meh).
// Too much implied behavior without requiring explicitness.

const { foo } = require('./test.js')
const { esmodule } = require('./file.mjs')

__filename
__dirname
require.main
require.cache
require.resolve('./test.js')
require.resolve('./file.mjs')

module
module.exports
module.exports = foo

exports
exports.commonjs = true
exports.esmodule = esmodule
2 changes: 1 addition & 1 deletion test/fixtures/file.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import.meta
import.meta.url
import.meta.dirname
import.meta.filename
import.meta.resolve('./test.js')
import.meta.resolve('./file.cjs')

export const esmodule = true
export { commonjs }
3 changes: 3 additions & 0 deletions test/fixtures/specifier.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require('./file.cjs')
require.resolve('./file.cjs')
import('./file.cjs')
10 changes: 10 additions & 0 deletions test/fixtures/specifier.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import foo from './file.mts'
import bar from './file.cts'
import baz from './file.ts'

import(`./${foo}${bar}${baz}.cjs`)
import(new String('not-relative.js'))
import(new String('./file.mjs'))

import.meta.resolve('./file.cjs')
import.meta.resolve('./file.js')
Loading

0 comments on commit a034fd6

Please sign in to comment.