Comparing version 1.1.5 to 1.2.0
export type { Hot } from "dynohot/hot"; | ||
export interface DynohotLoaderOptions { | ||
ignore?: RegExp; | ||
silent?: boolean; | ||
} | ||
//# sourceMappingURL=loader.d.ts.map |
@@ -8,8 +8,13 @@ import * as assert from "node:assert/strict"; | ||
import { transformModuleSource } from "./transform.js"; | ||
const self = new URL(import.meta.url); | ||
const ignoreString = self.searchParams.get("ignore"); | ||
const ignorePattern = ignoreString === null ? /[/\\]node_modules[/\\]/ : new RegExp(ignoreString); | ||
const root = String(new URL("..", self)); | ||
const runtimeURL = `${root}runtime/runtime.js?${String(self.searchParams)}`; | ||
function extractImportAssertions(params) { | ||
let ignorePattern; | ||
let runtimeURL; | ||
/** @internal */ | ||
export const initialize = ({ ignore: ignoreOption = /[/\\]node_modules[/\\]/, silent = false, } = {}) => { | ||
ignorePattern = ignoreOption; | ||
const root = String(new URL("..", new URL(import.meta.url))); | ||
runtimeURL = `${root}runtime/runtime.js?${String(new URLSearchParams({ | ||
...silent ? { silent: "" } : {}, | ||
}))}`; | ||
}; | ||
function extractImportAttributes(params) { | ||
const entries = Array.from(Fn.transform(Fn.filter(params, entry => entry[0] === "with"), entry => new URLSearchParams(entry[1]))); | ||
@@ -19,7 +24,8 @@ entries.sort(Fn.mappedPrimitiveComparator(entry => entry[0])); | ||
} | ||
const makeAdapterModule = (url, importAssertions) => { | ||
const deprecatedAssertSyntax = /^1[6-9]/.test(process.versions.node); | ||
const makeAdapterModule = (url, importAttributes) => { | ||
const encodedURL = JSON.stringify(url); | ||
return ( | ||
// eslint-disable-next-line @stylistic/indent | ||
`import * as namespace from ${encodedURL} assert ${JSON.stringify(importAssertions)}; | ||
`import * as namespace from ${encodedURL} ${deprecatedAssertSyntax ? "assert" : "with"} ${JSON.stringify(importAttributes)}; | ||
import { adapter } from "hot:runtime"; | ||
@@ -29,3 +35,3 @@ const module = adapter(${encodedURL}, namespace); | ||
}; | ||
const makeJsonModule = (url, json, importAssertions) => | ||
const makeJsonModule = (url, json, importAttributes) => | ||
// eslint-disable-next-line @stylistic/indent | ||
@@ -41,4 +47,4 @@ `import { acquire } from "hot:runtime" | ||
} | ||
module().load({ async: false, execute }, null, false, "json", ${JSON.stringify(importAssertions)}, []);\n`; | ||
const makeReloadableModule = async (url, source, importAssertions) => { | ||
module().load({ async: false, execute }, null, false, "json", ${JSON.stringify(importAttributes)}, []);\n`; | ||
const makeReloadableModule = async (url, source, importAttributes) => { | ||
const sourceMap = await async function () { | ||
@@ -62,3 +68,5 @@ try { | ||
// source as a post-transformation process. | ||
return (`${transformModuleSource(url, importAssertions, source, sourceMap)} | ||
return ( | ||
// eslint-disable-next-line @stylistic/indent | ||
`${transformModuleSource(url, importAttributes, source, sourceMap)} | ||
import { acquire } from "hot:runtime"; | ||
@@ -101,3 +109,3 @@ export default function module() { return acquire(${JSON.stringify(url)}); }\n`); | ||
assert.ok(resolutionSpecifier !== null); | ||
const importAssertions = extractImportAssertions(resolutionURL.searchParams); | ||
const importAssertions = extractImportAttributes(resolutionURL.searchParams); | ||
return maybeThen(function* () { | ||
@@ -127,3 +135,3 @@ const result = yield nextResolve(resolutionSpecifier, { | ||
assert.ok(parentModuleURL !== null); | ||
const importAssertions = extractImportAssertions(resolutionURL.searchParams); | ||
const importAssertions = extractImportAttributes(resolutionURL.searchParams); | ||
return maybeThen(function* () { | ||
@@ -183,3 +191,3 @@ const result = yield nextResolve(resolutionSpecifier, { | ||
case "adapter": { | ||
const importAssertions = extractImportAssertions(url.searchParams); | ||
const importAssertions = extractImportAttributes(url.searchParams); | ||
const moduleURL = url.searchParams.get("url"); | ||
@@ -207,10 +215,12 @@ assert.ok(moduleURL); | ||
assert.ok(moduleURL); | ||
const importAssertions = extractImportAssertions(url.searchParams); | ||
const importAttributes = extractImportAttributes(url.searchParams); | ||
const result = await nextLoad(moduleURL, { | ||
...context, | ||
importAssertions, | ||
// TODO [marcel 2024-04-27]: remove after nodejs v18(?) is not supported | ||
importAssertions: importAttributes, | ||
importAttributes, | ||
}); | ||
if (!ignorePattern.test(moduleURL)) { | ||
if (result.format === "module") { | ||
const source = await makeReloadableModule(moduleURL, asString(result.source), importAssertions); | ||
const source = await makeReloadableModule(moduleURL, asString(result.source), importAttributes); | ||
return { ...result, source }; | ||
@@ -222,3 +232,3 @@ } | ||
format: "module", | ||
source: makeJsonModule(moduleURL, asString(result.source), importAssertions), | ||
source: makeJsonModule(moduleURL, asString(result.source), importAttributes), | ||
}; | ||
@@ -230,3 +240,3 @@ } | ||
format: "module", | ||
source: makeAdapterModule(moduleURL, importAssertions), | ||
source: makeAdapterModule(moduleURL, importAttributes), | ||
}; | ||
@@ -233,0 +243,0 @@ }(); |
import { register } from "node:module"; | ||
// I can not believe they did this. | ||
register("dynohot", { | ||
register("dynohot/loader", { | ||
parentURL: import.meta.url, | ||
}); | ||
//# sourceMappingURL=register.js.map |
@@ -1,2 +0,2 @@ | ||
export declare function transformModuleSource(filename: string, importAssertions: Record<string, string>, sourceText: string, sourceMap: unknown): string; | ||
export declare function transformModuleSource(filename: string, importAttributes: Record<string, string>, sourceText: string, sourceMap: unknown): string; | ||
//# sourceMappingURL=transform.d.ts.map |
@@ -9,3 +9,4 @@ import * as assert from "node:assert/strict"; | ||
const extractName = (node) => t.isStringLiteral(node) ? node.value : node.name; | ||
export function transformModuleSource(filename, importAssertions, sourceText, sourceMap) { | ||
const deprecatedAssertSyntax = /^1[6-9]/.test(process.versions.node); | ||
export function transformModuleSource(filename, importAttributes, sourceText, sourceMap) { | ||
const file = function () { | ||
@@ -67,3 +68,3 @@ try { | ||
}), ", ")} ]`; | ||
const loader = `module().load(${body}, ${importMeta}, ${state.usesDynamicImport}, "module", ${JSON.stringify(importAssertions)}, ${requestEntries});`; | ||
const loader = `module().load(${body}, ${importMeta}, ${state.usesDynamicImport}, "module", ${JSON.stringify(importAttributes)}, ${requestEntries});`; | ||
// Build final module source | ||
@@ -79,4 +80,4 @@ return `${result.code}\n${sourceMapComment}\n${imports}\n${loader}\n`; | ||
assert.ok(moduleRequest.source); | ||
// Convert import assertions into `with` URL search parameters. That way the underlying | ||
// loader can pass forward the assertions, but the runtime imports will be plain. | ||
// Convert import attributes into `with` URL search parameters. That way the underlying | ||
// loader can pass forward the attributes, but the runtime imports will be plain. | ||
const attributes = moduleRequest.attributes ?? moduleRequest.assertions ?? []; | ||
@@ -86,5 +87,5 @@ const specifier = moduleRequest.source.value; | ||
["specifier", specifier], | ||
...Fn.map(attributes, assertion => [ | ||
...Fn.map(attributes, attribute => [ | ||
"with", | ||
String(new URLSearchParams([[extractName(assertion.key), extractName(assertion.value)]])), | ||
String(new URLSearchParams([[extractName(attribute.key), extractName(attribute.value)]])), | ||
]), | ||
@@ -91,0 +92,0 @@ ]); |
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" resolution-mode="require"/> | ||
import type { DynamicImport } from "./declaration.js"; | ||
@@ -3,0 +2,0 @@ import { EventEmitter } from "node:events"; |
@@ -157,3 +157,3 @@ import * as assert from "node:assert/strict"; | ||
assert.ok(instance !== undefined); | ||
const { importAssertions } = instance.declaration; | ||
const { importAttributes } = instance.declaration; | ||
const params = new URLSearchParams([ | ||
@@ -163,3 +163,3 @@ ["url", this.url], | ||
["format", instance.declaration.format], | ||
...Fn.map(Object.entries(importAssertions), ([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
...Fn.map(Object.entries(importAttributes), ([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
]); | ||
@@ -244,3 +244,3 @@ try { | ||
// Invoked from transformed module source | ||
load(body, meta, usesDynamicImport, format, importAssertions, loadedModules) { | ||
load(body, meta, usesDynamicImport, format, importAttributes, loadedModules) { | ||
if (evictModule) { | ||
@@ -252,3 +252,3 @@ // Experimental module eviction | ||
["version", String(this.version)], | ||
...Object.entries(importAssertions).map(([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
...Object.entries(importAttributes).map(([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
]); | ||
@@ -263,3 +263,3 @@ const backingModuleURL = `hot:module?${String(backingModuleParams)}`; | ||
format, | ||
importAssertions, | ||
importAttributes, | ||
usesDynamicImport, | ||
@@ -266,0 +266,0 @@ loadedModules, |
@@ -238,3 +238,3 @@ import * as assert from "node:assert/strict"; | ||
} | ||
async dynamicImport(specifier, importAssertions) { | ||
async dynamicImport(specifier, importAttributes) { | ||
assert.ok(this.state.status === ModuleStatus.linked || | ||
@@ -247,5 +247,5 @@ this.state.status === ModuleStatus.evaluating || | ||
["specifier", specifier], | ||
...Fn.map(Object.entries(importAssertions ?? {}), ([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
...Fn.map(Object.entries(importAttributes ?? {}), ([key, value]) => ["with", String(new URLSearchParams([[key, value]]))]), | ||
]); | ||
const { default: acquire } = await this.controller.application.dynamicImport(`hot:import?${String(specifierParams)}`, importAssertions); | ||
const { default: acquire } = await this.controller.application.dynamicImport(`hot:import?${String(specifierParams)}`, importAttributes); | ||
const controller = acquire(); | ||
@@ -252,0 +252,0 @@ didDynamicImport(this, controller); |
@@ -6,3 +6,3 @@ import { AdapterModuleController } from "./adapter.js"; | ||
/** @internal */ | ||
export const acquire = makeAcquire((specifier, assertions) => import(specifier, assertions), Object.fromEntries(params)); | ||
export const acquire = makeAcquire((specifier, attributes) => import(specifier, attributes), Object.fromEntries(params)); | ||
/** @internal */ | ||
@@ -9,0 +9,0 @@ export function adapter(url, namespace) { |
@@ -28,3 +28,2 @@ import * as fs from "node:fs"; | ||
}; | ||
// @ts-expect-error - https://nodejs.org/api/fs.html#watcherunref | ||
holder.watcher.unref(); | ||
@@ -31,0 +30,0 @@ this.watchers.set(directory, holder); |
{ | ||
"name": "dynohot", | ||
"type": "module", | ||
"version": "1.1.5", | ||
"version": "1.2.0", | ||
"exports": { | ||
".": "./dist/loader/loader.js", | ||
"./?": "./dist/loader/loader.js", | ||
"./?*": "./dist/loader/loader.js?*", | ||
".": "./dist/loader/register.js", | ||
"./loader": "./dist/loader/loader.js", | ||
"./register": "./dist/loader/register.js", | ||
"./register?": "./dist/loader/register.js", | ||
"./register?*": "./dist/loader/register.js?*", | ||
"./import-meta": { | ||
@@ -26,18 +23,18 @@ "types": "./import-meta.d.ts" | ||
"dependencies": { | ||
"@babel/core": "^7.24.4", | ||
"@babel/generator": "^7.23.0", | ||
"@babel/traverse": "^7.23.2", | ||
"@babel/core": "^7.24.7", | ||
"@babel/generator": "^7.24.7", | ||
"@babel/traverse": "^7.24.7", | ||
"convert-source-map": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/preset-env": "^7.23.2", | ||
"@babel/preset-typescript": "^7.23.2", | ||
"@babel/preset-env": "^7.24.7", | ||
"@babel/preset-typescript": "^7.24.7", | ||
"@braidai/eslintrc": "^1.0.0", | ||
"@jest/globals": "^29.7.0", | ||
"@jest/types": "^29.6.3", | ||
"@types/babel__core": "^7.20.3", | ||
"@types/babel__generator": "^7.6.6", | ||
"@types/babel__traverse": "^7.20.3", | ||
"@types/babel__core": "^7.20.5", | ||
"@types/babel__generator": "^7.6.8", | ||
"@types/babel__traverse": "^7.20.6", | ||
"@types/convert-source-map": "^2.0.2", | ||
"@types/node": "^20.8.9", | ||
"@types/node": "^20.14.9", | ||
"babel-jest": "^29.7.0", | ||
@@ -47,3 +44,3 @@ "babel-plugin-transform-import-meta": "^2.2.1", | ||
"jest": "^29.7.0", | ||
"typescript": "^5.2.2" | ||
"typescript": "^5.5.2" | ||
}, | ||
@@ -50,0 +47,0 @@ "repository": { |
@@ -14,5 +14,5 @@ [![npm version](https://badgen.now.sh/npm/v/dynohot)](https://www.npmjs.com/package/dynohot) | ||
challenging to get them to run server-side apps. With the experimental nodejs loader API you can get | ||
HMR running with a simple `--loader dynohot` [or `--import dynohot/register`] flag. You should | ||
probably also add `--enable-source-maps` because dynohot applies a [transformation](#transformation) | ||
to your source code. | ||
HMR running with a simple `--import dynohot` flag. You should probably also add | ||
`--enable-source-maps` because dynohot applies a [transformation](#transformation) to your source | ||
code. | ||
@@ -192,3 +192,3 @@ Note that your project *must* be using proper [JavaScript | ||
``` | ||
node --import @loaderkit/ts/register --import dynohot/register ./main.ts | ||
node --import @loaderkit/ts/register --import dynohot ./main.ts | ||
``` | ||
@@ -294,10 +294,25 @@ | ||
You can pass options to dynohot using `--import dynohot/register?option=value` or `--loader dynohot/?option=value`. | ||
You can pass options to dynohot by creating a registration runtime JavaScript file and importing it | ||
instead of `--import dynohot`. For example: | ||
* `ignore` - Pass `?ignore=regexpPattern` to explicitly ignore certain file paths. By default this is | ||
`ignore=[/\]node_modules[/\]`. | ||
* `silent` - Pass `?silent` to prevent logging messages to stderr console. You might want this if | ||
you're using something like Winston or Pino. Be sure to use `import.meta.on("message", ...)` to | ||
raise informative dynohot messages to the developer's attention. | ||
`loaders.js`: | ||
```js | ||
import { register } from "node:module"; | ||
register("dynohot/loader", { | ||
parentURL: import.meta.url, | ||
data: { | ||
silent: true, | ||
}, | ||
}); | ||
``` | ||
* `ignore` - `RegExp` used to filter out modules which should not take place in hot reloading. The | ||
string applied to the regular expression will be a fully-resolved file URL. The default value of | ||
this parameter is `/[/\\]node_modules[/\\]/`. | ||
* `silent` - `boolean` which will prevent `dynohot` from outputting diagnostic messages to stderr. | ||
You might want this if you're using something like Winston or Pino. Be sure to use | ||
`import.meta.on("message", ...)` to raise informative dynohot messages to the developer's | ||
attention. | ||
TRANSFORMATION | ||
@@ -345,3 +360,3 @@ -------------- | ||
"module", | ||
// import assertions `import .. with { type: "json" }` | ||
// import attributes `import .. with { type: "json" }` | ||
{}, | ||
@@ -348,0 +363,0 @@ // imports |
@@ -120,3 +120,3 @@ import type { ReloadableModuleInstance } from "./instance.js"; | ||
if (acceptedModules.every(module => module != null)) { | ||
return acceptedModules as ReloadableModuleController[]; | ||
return acceptedModules; | ||
} else { | ||
@@ -180,3 +180,3 @@ if (hot !== null) { | ||
accepts, | ||
modules: acceptedModules as ReloadableModuleController[], | ||
modules: acceptedModules, | ||
}; | ||
@@ -183,0 +183,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
155032
3295
382
Updated@babel/core@^7.24.7
Updated@babel/generator@^7.24.7
Updated@babel/traverse@^7.24.7