Skip to content

Commit

Permalink
feat: json support
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Jul 23, 2021
1 parent a4a455c commit 81c12af
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 55 deletions.
53 changes: 25 additions & 28 deletions README.md
Expand Up @@ -134,21 +134,6 @@ await loadModule('./hello.mjs', { from: import.meta.url })
Options are same as `evalModule`.
### `readModule`
Resolve module path and read source contents. (currently only file protocol supported)
```js
import { resolve, readModule } from 'mlly'

const indexPath = await resolve('./index.mjs', { from: import.meta.url })

// { code: '...", url: '...' }
console.log(await readModule(indexPath))
```
Options are same as `resolve`.
### `transformModule`
- Resolves all relative imports will be resolved
Expand All @@ -161,20 +146,8 @@ console.log(transformModule(`console.log(import.meta.url)`), { url: 'test.mjs' }
Options are same as `evalModule`.
### `toDataURL`
Convert code to [`data:`](https://nodejs.org/api/esm.html#esm_data_imports) URL using base64 encoding.
```js
import { toDataURL } from 'mlly'

console.log(toDataURL(`
// This is an example
console.log('Hello world')
`))
```
## Other utils
## Other Utils
### `fileURLToPath`
Expand All @@ -201,6 +174,30 @@ import { ensureProtocol } from 'mlly'
console.log(normalizeid('/foo/bar.js'))
```
### `loadURL`
Read source contents of a URL. (currently only file protocol supported)
```js
import { resolve, loadURL } from 'mlly'

const url = await resolve('./index.mjs', { from: import.meta.url })
console.log(await loadURL(url))
```
### `toDataURL`
Convert code to [`data:`](https://nodejs.org/api/esm.html#esm_data_imports) URL using base64 encoding.
```js
import { toDataURL } from 'mlly'

console.log(toDataURL(`
// This is an example
console.log('Hello world')
`))
```
## License
MIT
6 changes: 3 additions & 3 deletions lib/index.d.ts
Expand Up @@ -28,13 +28,13 @@ export interface EvaluateOptions extends ResolveOptions {
url?: string
}

export function loadModule (id: string, opts?: EvaluateOptions) : Promise<any>
export function loadModule (url: string, opts?: EvaluateOptions) : Promise<any>
export function evalModule (code: string, opts?: EvaluateOptions) : Promise<any>
export function readModule (id: string, opts?: EvaluateOptions) : Promise<{ url: string, code: string}>
export function transformModule(code: string, opts?: EvaluateOptions) : Promise<string>
export function toDataURL(code: string) : string

// Utils

export function fileURLToPath (id: URL | string) : string
export function normalizeid (id: URL | string) : string
export function loadURL (id: string) : Promise<string>
export function toDataURL(code: string) : string
48 changes: 25 additions & 23 deletions lib/index.mjs
Expand Up @@ -112,30 +112,20 @@ export function createResolve (defaults) {
const ESM_IMPORT_RE = /(?<=import .* from ['"])([^'"]+)(?=['"])|(?<=export .* from ['"])([^'"]+)(?=['"])|(?<=import\s*['"])([^'"]+)(?=['"])|(?<=import\s*\(['"])([^'"]+)(?=['"]\))/g

export async function loadModule (id, opts = {}) {
const { url, code } = await readModule(id, opts)
return evalModule(code, {
url,
...opts
})
const url = await resolve(id, opts)
const code = await loadURL(url, opts)
return evalModule(code, { url, ...opts })
}

export async function evalModule (code, opts = {}) {
const transformed = await transformModule(code, opts)
return import(toDataURL(transformed, opts))
}

export async function readModule (id, opts) {
const url = await resolve(id, opts)
const code = await fsp.readFile(fileURLToPath(url), 'utf-8')
return { url, code }
}

export async function transformModule (code, opts) {
// Use url <> from as defaults of each other
if (!opts.url && opts.from) {
opts.url = opts.from
} else if (opts.url && !opts.from) {
opts.from = opts.url
// Convert JSON to module
if (opts.url && opts.url.endsWith('.json')) {
return 'export default ' + code
}

// Resolve relative imports
Expand All @@ -149,11 +139,6 @@ export async function transformModule (code, opts) {
return code
}

export function toDataURL (code) {
const base64 = Buffer.from(code).toString('base64')
return `data:text/javascript;base64,${base64}`
}

export async function resolveImports (code, opts) {
const imports = Array.from(code.matchAll(ESM_IMPORT_RE)).map(m => m[0])
if (!imports.length) {
Expand All @@ -162,8 +147,15 @@ export async function resolveImports (code, opts) {

const uniqueImports = Array.from(new Set(imports))
const resolved = new Map()
const resolveOpts = { ...opts, from: opts.url }
await Promise.all(uniqueImports.map(async (id) => { resolved.set(id, await resolve(id, resolveOpts)) }))
const resolveOpts = { from: opts.from || opts.url, ...opts }
await Promise.all(uniqueImports.map(async (id) => {
let url = await resolve(id, resolveOpts)
if (url.endsWith('.json')) {
const code = await loadURL(url)
url = toDataURL(await transformModule(code, { url }))
}
resolved.set(id, url)
}))

const re = new RegExp(uniqueImports.map(i => `(${i})`).join('|'), 'g')
return code.replace(re, id => resolved.get(id))
Expand Down Expand Up @@ -191,6 +183,16 @@ export function normalizeid (id) {
return 'file://' + normalizeSlash(id)
}

export async function loadURL (url) {
const code = await fsp.readFile(fileURLToPath(url), 'utf-8')
return code
}

export function toDataURL (code) {
const base64 = Buffer.from(code).toString('base64')
return `data:text/javascript;base64,${base64}`
}

function normalizeSlash (str) {
return str.replace(/\\/g, '/')
}
Expand Down
2 changes: 2 additions & 0 deletions test/eval.mjs
Expand Up @@ -10,3 +10,5 @@ await evalModule(`
})

await loadModule('./hello.mjs', { from: import.meta.url })

console.log(await loadModule('../package.json', { from: import.meta.url }).then(r => r.default.name))
4 changes: 3 additions & 1 deletion test/hello.mjs
@@ -1 +1,3 @@
console.log('Hello world from', import.meta.url)
import pkg from '../package.json'

console.log('Hello world from', pkg.name, import.meta.url)

0 comments on commit 81c12af

Please sign in to comment.