@jsenv/core 41.5.25 → 41.5.26
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.
- package/dist/build/build.js +137 -139
- package/dist/start_dev_server/start_dev_server.js +141 -141
- package/package.json +8 -8
- package/src/build/build.js +4 -1
- package/src/dev/start_dev_server.js +6 -1
- package/src/plugins/plugins.js +0 -5
package/dist/build/build.js
CHANGED
|
@@ -4883,6 +4883,140 @@ const isBareSpecifier = (specifier) => {
|
|
|
4883
4883
|
}
|
|
4884
4884
|
};
|
|
4885
4885
|
|
|
4886
|
+
/*
|
|
4887
|
+
* Text patches applied to files as they are served and built, keyed by file:
|
|
4888
|
+
*
|
|
4889
|
+
* patches: {
|
|
4890
|
+
* "preact/dist/preact.mjs": [{ from: "a&&b", to: "a&&b&&c" }],
|
|
4891
|
+
* }
|
|
4892
|
+
*
|
|
4893
|
+
* A key is a url pattern relative to the root directory ("./main.js",
|
|
4894
|
+
* "**\/*.css"), or a path inside a package ("preact/dist/preact.mjs") found by
|
|
4895
|
+
* walking up from the root directory into node_modules, the way node does,
|
|
4896
|
+
* so the key holds wherever the package manager hoists the package.
|
|
4897
|
+
*
|
|
4898
|
+
* Every `from` must occur exactly once in the file, otherwise the file fails
|
|
4899
|
+
* to cook and says which patch did not apply: a dependency update that moved
|
|
4900
|
+
* the patched code must be looked at, never silently unpatched.
|
|
4901
|
+
*/
|
|
4902
|
+
|
|
4903
|
+
|
|
4904
|
+
const jsenvPluginPatches = (rawPatches) => {
|
|
4905
|
+
if (!rawPatches || Object.keys(rawPatches).length === 0) {
|
|
4906
|
+
return [];
|
|
4907
|
+
}
|
|
4908
|
+
let findPatches;
|
|
4909
|
+
const patchesPlugin = {
|
|
4910
|
+
name: "jsenv:patches",
|
|
4911
|
+
appliesDuring: "*",
|
|
4912
|
+
init: (context) => {
|
|
4913
|
+
const { rootDirectoryUrl } = context;
|
|
4914
|
+
const patchesByPattern = {};
|
|
4915
|
+
for (const key of Object.keys(rawPatches)) {
|
|
4916
|
+
const patches = rawPatches[key];
|
|
4917
|
+
assertPatches(patches, key);
|
|
4918
|
+
patchesByPattern[resolvePatchKey(key, rootDirectoryUrl)] = patches;
|
|
4919
|
+
}
|
|
4920
|
+
const associations = URL_META.resolveAssociations(
|
|
4921
|
+
{ patches: patchesByPattern },
|
|
4922
|
+
rootDirectoryUrl,
|
|
4923
|
+
);
|
|
4924
|
+
findPatches = (url) => {
|
|
4925
|
+
const { patches } = URL_META.applyAssociations({
|
|
4926
|
+
url: asUrlWithoutSearch(url),
|
|
4927
|
+
associations,
|
|
4928
|
+
});
|
|
4929
|
+
return patches;
|
|
4930
|
+
};
|
|
4931
|
+
},
|
|
4932
|
+
transformUrlContent: (urlInfo) => {
|
|
4933
|
+
const patches = findPatches(urlInfo.url);
|
|
4934
|
+
if (!patches) {
|
|
4935
|
+
return null;
|
|
4936
|
+
}
|
|
4937
|
+
const { content } = urlInfo;
|
|
4938
|
+
const magicSource = createMagicSource(content);
|
|
4939
|
+
for (const { from, to } of patches) {
|
|
4940
|
+
const start = content.indexOf(from);
|
|
4941
|
+
const occurrenceCount =
|
|
4942
|
+
start === -1 ? 0 : content.indexOf(from, start + 1) === -1 ? 1 : 2;
|
|
4943
|
+
if (occurrenceCount !== 1) {
|
|
4944
|
+
const fileRelativeUrl = urlToRelativeUrl(
|
|
4945
|
+
urlInfo.url,
|
|
4946
|
+
urlInfo.context.rootDirectoryUrl,
|
|
4947
|
+
);
|
|
4948
|
+
throw new Error(
|
|
4949
|
+
`patch cannot apply on "${fileRelativeUrl}": ${JSON.stringify(from)} found ${occurrenceCount === 0 ? "nowhere" : "more than once"} in the file. The file may have changed since the patch was written.`,
|
|
4950
|
+
);
|
|
4951
|
+
}
|
|
4952
|
+
magicSource.replace({
|
|
4953
|
+
start,
|
|
4954
|
+
end: start + from.length,
|
|
4955
|
+
replacement: to,
|
|
4956
|
+
});
|
|
4957
|
+
}
|
|
4958
|
+
return magicSource.toContentAndSourcemap();
|
|
4959
|
+
},
|
|
4960
|
+
};
|
|
4961
|
+
return [patchesPlugin];
|
|
4962
|
+
};
|
|
4963
|
+
|
|
4964
|
+
const assertPatches = (patches, key) => {
|
|
4965
|
+
if (!Array.isArray(patches)) {
|
|
4966
|
+
throw new TypeError(
|
|
4967
|
+
`patches["${key}"] must be an array of { from, to }, got ${patches}`,
|
|
4968
|
+
);
|
|
4969
|
+
}
|
|
4970
|
+
for (const patch of patches) {
|
|
4971
|
+
if (
|
|
4972
|
+
!patch ||
|
|
4973
|
+
typeof patch.from !== "string" ||
|
|
4974
|
+
patch.from === "" ||
|
|
4975
|
+
typeof patch.to !== "string"
|
|
4976
|
+
) {
|
|
4977
|
+
throw new TypeError(
|
|
4978
|
+
`patches["${key}"] entries must be { from: string, to: string } with a non-empty "from"`,
|
|
4979
|
+
);
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
};
|
|
4983
|
+
|
|
4984
|
+
// "./x", "../x", "/x", "file:///x" and "**/x" are url patterns; anything
|
|
4985
|
+
// else names a path inside a package, looked up in node_modules
|
|
4986
|
+
const resolvePatchKey = (key, rootDirectoryUrl) => {
|
|
4987
|
+
if (
|
|
4988
|
+
key.startsWith("./") ||
|
|
4989
|
+
key.startsWith("../") ||
|
|
4990
|
+
key.startsWith("/") ||
|
|
4991
|
+
key.startsWith("file:") ||
|
|
4992
|
+
key.startsWith("*")
|
|
4993
|
+
) {
|
|
4994
|
+
return key;
|
|
4995
|
+
}
|
|
4996
|
+
const segments = key.split("/");
|
|
4997
|
+
const packageName = key.startsWith("@")
|
|
4998
|
+
? `${segments[0]}/${segments[1]}`
|
|
4999
|
+
: segments[0];
|
|
5000
|
+
const pathInsidePackage = key.slice(packageName.length);
|
|
5001
|
+
let directoryUrl = new URL(rootDirectoryUrl);
|
|
5002
|
+
while (true) {
|
|
5003
|
+
const packageDirectoryUrl = new URL(
|
|
5004
|
+
`./node_modules/${packageName}/`,
|
|
5005
|
+
directoryUrl,
|
|
5006
|
+
);
|
|
5007
|
+
if (existsSync(packageDirectoryUrl)) {
|
|
5008
|
+
return String(new URL(`.${pathInsidePackage}`, packageDirectoryUrl));
|
|
5009
|
+
}
|
|
5010
|
+
const parentDirectoryUrl = new URL("../", directoryUrl);
|
|
5011
|
+
if (parentDirectoryUrl.href === directoryUrl.href) {
|
|
5012
|
+
throw new Error(
|
|
5013
|
+
`patches["${key}"]: package "${packageName}" not found in any node_modules above ${rootDirectoryUrl}`,
|
|
5014
|
+
);
|
|
5015
|
+
}
|
|
5016
|
+
directoryUrl = parentDirectoryUrl;
|
|
5017
|
+
}
|
|
5018
|
+
};
|
|
5019
|
+
|
|
4886
5020
|
/*
|
|
4887
5021
|
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
4888
5022
|
*/
|
|
@@ -8175,140 +8309,6 @@ const asInheritedInjections = (injections) => {
|
|
|
8175
8309
|
return inheritedInjections;
|
|
8176
8310
|
};
|
|
8177
8311
|
|
|
8178
|
-
/*
|
|
8179
|
-
* Text patches applied to files as they are served and built, keyed by file:
|
|
8180
|
-
*
|
|
8181
|
-
* patches: {
|
|
8182
|
-
* "preact/dist/preact.mjs": [{ from: "a&&b", to: "a&&b&&c" }],
|
|
8183
|
-
* }
|
|
8184
|
-
*
|
|
8185
|
-
* A key is a url pattern relative to the root directory ("./main.js",
|
|
8186
|
-
* "**\/*.css"), or a path inside a package ("preact/dist/preact.mjs") found by
|
|
8187
|
-
* walking up from the root directory into node_modules, the way node does,
|
|
8188
|
-
* so the key holds wherever the package manager hoists the package.
|
|
8189
|
-
*
|
|
8190
|
-
* Every `from` must occur exactly once in the file, otherwise the file fails
|
|
8191
|
-
* to cook and says which patch did not apply: a dependency update that moved
|
|
8192
|
-
* the patched code must be looked at, never silently unpatched.
|
|
8193
|
-
*/
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
const jsenvPluginPatches = (rawPatches) => {
|
|
8197
|
-
if (!rawPatches || Object.keys(rawPatches).length === 0) {
|
|
8198
|
-
return [];
|
|
8199
|
-
}
|
|
8200
|
-
let findPatches;
|
|
8201
|
-
const patchesPlugin = {
|
|
8202
|
-
name: "jsenv:patches",
|
|
8203
|
-
appliesDuring: "*",
|
|
8204
|
-
init: (context) => {
|
|
8205
|
-
const { rootDirectoryUrl } = context;
|
|
8206
|
-
const patchesByPattern = {};
|
|
8207
|
-
for (const key of Object.keys(rawPatches)) {
|
|
8208
|
-
const patches = rawPatches[key];
|
|
8209
|
-
assertPatches(patches, key);
|
|
8210
|
-
patchesByPattern[resolvePatchKey(key, rootDirectoryUrl)] = patches;
|
|
8211
|
-
}
|
|
8212
|
-
const associations = URL_META.resolveAssociations(
|
|
8213
|
-
{ patches: patchesByPattern },
|
|
8214
|
-
rootDirectoryUrl,
|
|
8215
|
-
);
|
|
8216
|
-
findPatches = (url) => {
|
|
8217
|
-
const { patches } = URL_META.applyAssociations({
|
|
8218
|
-
url: asUrlWithoutSearch(url),
|
|
8219
|
-
associations,
|
|
8220
|
-
});
|
|
8221
|
-
return patches;
|
|
8222
|
-
};
|
|
8223
|
-
},
|
|
8224
|
-
transformUrlContent: (urlInfo) => {
|
|
8225
|
-
const patches = findPatches(urlInfo.url);
|
|
8226
|
-
if (!patches) {
|
|
8227
|
-
return null;
|
|
8228
|
-
}
|
|
8229
|
-
const { content } = urlInfo;
|
|
8230
|
-
const magicSource = createMagicSource(content);
|
|
8231
|
-
for (const { from, to } of patches) {
|
|
8232
|
-
const start = content.indexOf(from);
|
|
8233
|
-
const occurrenceCount =
|
|
8234
|
-
start === -1 ? 0 : content.indexOf(from, start + 1) === -1 ? 1 : 2;
|
|
8235
|
-
if (occurrenceCount !== 1) {
|
|
8236
|
-
const fileRelativeUrl = urlToRelativeUrl(
|
|
8237
|
-
urlInfo.url,
|
|
8238
|
-
urlInfo.context.rootDirectoryUrl,
|
|
8239
|
-
);
|
|
8240
|
-
throw new Error(
|
|
8241
|
-
`patch cannot apply on "${fileRelativeUrl}": ${JSON.stringify(from)} found ${occurrenceCount === 0 ? "nowhere" : "more than once"} in the file. The file may have changed since the patch was written.`,
|
|
8242
|
-
);
|
|
8243
|
-
}
|
|
8244
|
-
magicSource.replace({
|
|
8245
|
-
start,
|
|
8246
|
-
end: start + from.length,
|
|
8247
|
-
replacement: to,
|
|
8248
|
-
});
|
|
8249
|
-
}
|
|
8250
|
-
return magicSource.toContentAndSourcemap();
|
|
8251
|
-
},
|
|
8252
|
-
};
|
|
8253
|
-
return [patchesPlugin];
|
|
8254
|
-
};
|
|
8255
|
-
|
|
8256
|
-
const assertPatches = (patches, key) => {
|
|
8257
|
-
if (!Array.isArray(patches)) {
|
|
8258
|
-
throw new TypeError(
|
|
8259
|
-
`patches["${key}"] must be an array of { from, to }, got ${patches}`,
|
|
8260
|
-
);
|
|
8261
|
-
}
|
|
8262
|
-
for (const patch of patches) {
|
|
8263
|
-
if (
|
|
8264
|
-
!patch ||
|
|
8265
|
-
typeof patch.from !== "string" ||
|
|
8266
|
-
patch.from === "" ||
|
|
8267
|
-
typeof patch.to !== "string"
|
|
8268
|
-
) {
|
|
8269
|
-
throw new TypeError(
|
|
8270
|
-
`patches["${key}"] entries must be { from: string, to: string } with a non-empty "from"`,
|
|
8271
|
-
);
|
|
8272
|
-
}
|
|
8273
|
-
}
|
|
8274
|
-
};
|
|
8275
|
-
|
|
8276
|
-
// "./x", "../x", "/x", "file:///x" and "**/x" are url patterns; anything
|
|
8277
|
-
// else names a path inside a package, looked up in node_modules
|
|
8278
|
-
const resolvePatchKey = (key, rootDirectoryUrl) => {
|
|
8279
|
-
if (
|
|
8280
|
-
key.startsWith("./") ||
|
|
8281
|
-
key.startsWith("../") ||
|
|
8282
|
-
key.startsWith("/") ||
|
|
8283
|
-
key.startsWith("file:") ||
|
|
8284
|
-
key.startsWith("*")
|
|
8285
|
-
) {
|
|
8286
|
-
return key;
|
|
8287
|
-
}
|
|
8288
|
-
const segments = key.split("/");
|
|
8289
|
-
const packageName = key.startsWith("@")
|
|
8290
|
-
? `${segments[0]}/${segments[1]}`
|
|
8291
|
-
: segments[0];
|
|
8292
|
-
const pathInsidePackage = key.slice(packageName.length);
|
|
8293
|
-
let directoryUrl = new URL(rootDirectoryUrl);
|
|
8294
|
-
while (true) {
|
|
8295
|
-
const packageDirectoryUrl = new URL(
|
|
8296
|
-
`./node_modules/${packageName}/`,
|
|
8297
|
-
directoryUrl,
|
|
8298
|
-
);
|
|
8299
|
-
if (existsSync(packageDirectoryUrl)) {
|
|
8300
|
-
return String(new URL(`.${pathInsidePackage}`, packageDirectoryUrl));
|
|
8301
|
-
}
|
|
8302
|
-
const parentDirectoryUrl = new URL("../", directoryUrl);
|
|
8303
|
-
if (parentDirectoryUrl.href === directoryUrl.href) {
|
|
8304
|
-
throw new Error(
|
|
8305
|
-
`patches["${key}"]: package "${packageName}" not found in any node_modules above ${rootDirectoryUrl}`,
|
|
8306
|
-
);
|
|
8307
|
-
}
|
|
8308
|
-
directoryUrl = parentDirectoryUrl;
|
|
8309
|
-
}
|
|
8310
|
-
};
|
|
8311
|
-
|
|
8312
8312
|
/*
|
|
8313
8313
|
* Some code uses globals specific to Node.js in code meant to run in browsers...
|
|
8314
8314
|
* This plugin will replace some node globals to things compatible with web:
|
|
@@ -10435,7 +10435,6 @@ const getCorePlugins = ({
|
|
|
10435
10435
|
directoryListing = true,
|
|
10436
10436
|
directoryReferenceEffect,
|
|
10437
10437
|
supervisor,
|
|
10438
|
-
patches,
|
|
10439
10438
|
injections,
|
|
10440
10439
|
transpilation = true,
|
|
10441
10440
|
inlining = true,
|
|
@@ -10477,9 +10476,6 @@ const getCorePlugins = ({
|
|
|
10477
10476
|
...(packageBundle
|
|
10478
10477
|
? [jsenvPluginWorkspaceBundle({ packageDirectory })]
|
|
10479
10478
|
: []),
|
|
10480
|
-
// before everything else: what the other plugins read must be the
|
|
10481
|
-
// patched file
|
|
10482
|
-
...jsenvPluginPatches(patches),
|
|
10483
10479
|
// before reference analysis: an url written by an injection must hold its
|
|
10484
10480
|
// final value when references are analyzed
|
|
10485
10481
|
jsenvPluginInjections(injections),
|
|
@@ -13837,6 +13833,9 @@ const prepareEntryPointBuild = async (
|
|
|
13837
13833
|
|
|
13838
13834
|
let _getOtherEntryBuildInfo;
|
|
13839
13835
|
const rawJsenvPluginStore = await createJsenvPluginStore([
|
|
13836
|
+
// First, ahead of the plugins given by the caller: what every other plugin
|
|
13837
|
+
// reads must be the patched file (see start_dev_server.js).
|
|
13838
|
+
...jsenvPluginPatches(patches),
|
|
13840
13839
|
...(mappings ? [jsenvPluginMappings(mappings)] : []),
|
|
13841
13840
|
{
|
|
13842
13841
|
name: "jsenv:other_entry_point_build_during_craft",
|
|
@@ -13871,7 +13870,6 @@ const prepareEntryPointBuild = async (
|
|
|
13871
13870
|
magicExtensions,
|
|
13872
13871
|
magicDirectoryIndex,
|
|
13873
13872
|
directoryReferenceEffect,
|
|
13874
|
-
patches,
|
|
13875
13873
|
injections,
|
|
13876
13874
|
transpilation: {
|
|
13877
13875
|
babelHelpersAsImport: !explicitJsModuleConversion,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { WebSocketResponse, pickContentType, ServerEvents, serverPluginErrorHandler, fetchDirectory, composeTwoResponses, serverPluginCORS, jsenvAccessControlAllowedHeaders, startServer } from "@jsenv/server";
|
|
2
2
|
import { existsSync, statSync, readFileSync, realpathSync, readdirSync, lstatSync } from "node:fs";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import { urlToRelativeUrl, registerFileLifecycle, lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, errorToHTML, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, createDetailedMessage, UNICODE, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution,
|
|
4
|
+
import { urlToRelativeUrl, registerFileLifecycle, lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, errorToHTML, URL_META, asUrlWithoutSearch, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, createDetailedMessage, UNICODE, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, collectFiles, registerDirectoryLifecycle, readEntryStatSync, applyFileSystemMagicResolution, getExtensionsToTry, urlToFilename, ensurePathnameTrailingSlash, compareFileUrls, setUrlExtension, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT, formatError, assertAndNormalizeDirectoryUrl, browserDefaultRuntimeCompat, inferRuntimeCompatFromClosestPackage, createTaskLog } from "./jsenv_core_packages.js";
|
|
5
5
|
import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
|
|
6
6
|
import { parseHtml, injectJsenvScript, stringifyHtmlAst, parseCssUrls, getHtmlNodeAttribute, getHtmlNodePosition, getHtmlNodeAttributePosition, setHtmlNodeAttributes, parseSrcSet, getUrlForContentInsideHtml, removeHtmlNodeText, setHtmlNodeText, getHtmlNodeText, analyzeScriptNode, visitHtmlNodes, parseJsUrls, hasCssOpaqueDirective, getUrlForContentInsideJs, renderCssTemplateLiteral, applyBabelPlugins, visitJsAst, getImportMetaPropertyName, visitJsAstUntil, analyzeLinkNode, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn } from "@jsenv/ast";
|
|
7
|
+
import { createMagicSource, composeTwoSourcemaps, generateSourcemapFileUrl, generateSourcemapDataUrl, SOURCEMAP, applyContentEditsOnSourcemap, composeSourcemaps } from "@jsenv/sourcemap";
|
|
7
8
|
import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
|
|
8
9
|
import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation";
|
|
9
|
-
import { createMagicSource, composeTwoSourcemaps, generateSourcemapFileUrl, generateSourcemapDataUrl, SOURCEMAP, applyContentEditsOnSourcemap, composeSourcemaps } from "@jsenv/sourcemap";
|
|
10
10
|
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/plugins/filesystem/filesystem_error_to_response.js";
|
|
@@ -1574,6 +1574,140 @@ const jsenvPluginPageSwitcher = () => {
|
|
|
1574
1574
|
};
|
|
1575
1575
|
};
|
|
1576
1576
|
|
|
1577
|
+
/*
|
|
1578
|
+
* Text patches applied to files as they are served and built, keyed by file:
|
|
1579
|
+
*
|
|
1580
|
+
* patches: {
|
|
1581
|
+
* "preact/dist/preact.mjs": [{ from: "a&&b", to: "a&&b&&c" }],
|
|
1582
|
+
* }
|
|
1583
|
+
*
|
|
1584
|
+
* A key is a url pattern relative to the root directory ("./main.js",
|
|
1585
|
+
* "**\/*.css"), or a path inside a package ("preact/dist/preact.mjs") found by
|
|
1586
|
+
* walking up from the root directory into node_modules, the way node does,
|
|
1587
|
+
* so the key holds wherever the package manager hoists the package.
|
|
1588
|
+
*
|
|
1589
|
+
* Every `from` must occur exactly once in the file, otherwise the file fails
|
|
1590
|
+
* to cook and says which patch did not apply: a dependency update that moved
|
|
1591
|
+
* the patched code must be looked at, never silently unpatched.
|
|
1592
|
+
*/
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
const jsenvPluginPatches = (rawPatches) => {
|
|
1596
|
+
if (!rawPatches || Object.keys(rawPatches).length === 0) {
|
|
1597
|
+
return [];
|
|
1598
|
+
}
|
|
1599
|
+
let findPatches;
|
|
1600
|
+
const patchesPlugin = {
|
|
1601
|
+
name: "jsenv:patches",
|
|
1602
|
+
appliesDuring: "*",
|
|
1603
|
+
init: (context) => {
|
|
1604
|
+
const { rootDirectoryUrl } = context;
|
|
1605
|
+
const patchesByPattern = {};
|
|
1606
|
+
for (const key of Object.keys(rawPatches)) {
|
|
1607
|
+
const patches = rawPatches[key];
|
|
1608
|
+
assertPatches(patches, key);
|
|
1609
|
+
patchesByPattern[resolvePatchKey(key, rootDirectoryUrl)] = patches;
|
|
1610
|
+
}
|
|
1611
|
+
const associations = URL_META.resolveAssociations(
|
|
1612
|
+
{ patches: patchesByPattern },
|
|
1613
|
+
rootDirectoryUrl,
|
|
1614
|
+
);
|
|
1615
|
+
findPatches = (url) => {
|
|
1616
|
+
const { patches } = URL_META.applyAssociations({
|
|
1617
|
+
url: asUrlWithoutSearch(url),
|
|
1618
|
+
associations,
|
|
1619
|
+
});
|
|
1620
|
+
return patches;
|
|
1621
|
+
};
|
|
1622
|
+
},
|
|
1623
|
+
transformUrlContent: (urlInfo) => {
|
|
1624
|
+
const patches = findPatches(urlInfo.url);
|
|
1625
|
+
if (!patches) {
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1628
|
+
const { content } = urlInfo;
|
|
1629
|
+
const magicSource = createMagicSource(content);
|
|
1630
|
+
for (const { from, to } of patches) {
|
|
1631
|
+
const start = content.indexOf(from);
|
|
1632
|
+
const occurrenceCount =
|
|
1633
|
+
start === -1 ? 0 : content.indexOf(from, start + 1) === -1 ? 1 : 2;
|
|
1634
|
+
if (occurrenceCount !== 1) {
|
|
1635
|
+
const fileRelativeUrl = urlToRelativeUrl(
|
|
1636
|
+
urlInfo.url,
|
|
1637
|
+
urlInfo.context.rootDirectoryUrl,
|
|
1638
|
+
);
|
|
1639
|
+
throw new Error(
|
|
1640
|
+
`patch cannot apply on "${fileRelativeUrl}": ${JSON.stringify(from)} found ${occurrenceCount === 0 ? "nowhere" : "more than once"} in the file. The file may have changed since the patch was written.`,
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
magicSource.replace({
|
|
1644
|
+
start,
|
|
1645
|
+
end: start + from.length,
|
|
1646
|
+
replacement: to,
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
return magicSource.toContentAndSourcemap();
|
|
1650
|
+
},
|
|
1651
|
+
};
|
|
1652
|
+
return [patchesPlugin];
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
const assertPatches = (patches, key) => {
|
|
1656
|
+
if (!Array.isArray(patches)) {
|
|
1657
|
+
throw new TypeError(
|
|
1658
|
+
`patches["${key}"] must be an array of { from, to }, got ${patches}`,
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1661
|
+
for (const patch of patches) {
|
|
1662
|
+
if (
|
|
1663
|
+
!patch ||
|
|
1664
|
+
typeof patch.from !== "string" ||
|
|
1665
|
+
patch.from === "" ||
|
|
1666
|
+
typeof patch.to !== "string"
|
|
1667
|
+
) {
|
|
1668
|
+
throw new TypeError(
|
|
1669
|
+
`patches["${key}"] entries must be { from: string, to: string } with a non-empty "from"`,
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
|
|
1675
|
+
// "./x", "../x", "/x", "file:///x" and "**/x" are url patterns; anything
|
|
1676
|
+
// else names a path inside a package, looked up in node_modules
|
|
1677
|
+
const resolvePatchKey = (key, rootDirectoryUrl) => {
|
|
1678
|
+
if (
|
|
1679
|
+
key.startsWith("./") ||
|
|
1680
|
+
key.startsWith("../") ||
|
|
1681
|
+
key.startsWith("/") ||
|
|
1682
|
+
key.startsWith("file:") ||
|
|
1683
|
+
key.startsWith("*")
|
|
1684
|
+
) {
|
|
1685
|
+
return key;
|
|
1686
|
+
}
|
|
1687
|
+
const segments = key.split("/");
|
|
1688
|
+
const packageName = key.startsWith("@")
|
|
1689
|
+
? `${segments[0]}/${segments[1]}`
|
|
1690
|
+
: segments[0];
|
|
1691
|
+
const pathInsidePackage = key.slice(packageName.length);
|
|
1692
|
+
let directoryUrl = new URL(rootDirectoryUrl);
|
|
1693
|
+
while (true) {
|
|
1694
|
+
const packageDirectoryUrl = new URL(
|
|
1695
|
+
`./node_modules/${packageName}/`,
|
|
1696
|
+
directoryUrl,
|
|
1697
|
+
);
|
|
1698
|
+
if (existsSync(packageDirectoryUrl)) {
|
|
1699
|
+
return String(new URL(`.${pathInsidePackage}`, packageDirectoryUrl));
|
|
1700
|
+
}
|
|
1701
|
+
const parentDirectoryUrl = new URL("../", directoryUrl);
|
|
1702
|
+
if (parentDirectoryUrl.href === directoryUrl.href) {
|
|
1703
|
+
throw new Error(
|
|
1704
|
+
`patches["${key}"]: package "${packageName}" not found in any node_modules above ${rootDirectoryUrl}`,
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1707
|
+
directoryUrl = parentDirectoryUrl;
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
|
|
1577
1711
|
/*
|
|
1578
1712
|
* https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/css/src/CSSTransformer.js
|
|
1579
1713
|
*/
|
|
@@ -5762,140 +5896,6 @@ const asInheritedInjections = (injections) => {
|
|
|
5762
5896
|
return inheritedInjections;
|
|
5763
5897
|
};
|
|
5764
5898
|
|
|
5765
|
-
/*
|
|
5766
|
-
* Text patches applied to files as they are served and built, keyed by file:
|
|
5767
|
-
*
|
|
5768
|
-
* patches: {
|
|
5769
|
-
* "preact/dist/preact.mjs": [{ from: "a&&b", to: "a&&b&&c" }],
|
|
5770
|
-
* }
|
|
5771
|
-
*
|
|
5772
|
-
* A key is a url pattern relative to the root directory ("./main.js",
|
|
5773
|
-
* "**\/*.css"), or a path inside a package ("preact/dist/preact.mjs") found by
|
|
5774
|
-
* walking up from the root directory into node_modules, the way node does,
|
|
5775
|
-
* so the key holds wherever the package manager hoists the package.
|
|
5776
|
-
*
|
|
5777
|
-
* Every `from` must occur exactly once in the file, otherwise the file fails
|
|
5778
|
-
* to cook and says which patch did not apply: a dependency update that moved
|
|
5779
|
-
* the patched code must be looked at, never silently unpatched.
|
|
5780
|
-
*/
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
const jsenvPluginPatches = (rawPatches) => {
|
|
5784
|
-
if (!rawPatches || Object.keys(rawPatches).length === 0) {
|
|
5785
|
-
return [];
|
|
5786
|
-
}
|
|
5787
|
-
let findPatches;
|
|
5788
|
-
const patchesPlugin = {
|
|
5789
|
-
name: "jsenv:patches",
|
|
5790
|
-
appliesDuring: "*",
|
|
5791
|
-
init: (context) => {
|
|
5792
|
-
const { rootDirectoryUrl } = context;
|
|
5793
|
-
const patchesByPattern = {};
|
|
5794
|
-
for (const key of Object.keys(rawPatches)) {
|
|
5795
|
-
const patches = rawPatches[key];
|
|
5796
|
-
assertPatches(patches, key);
|
|
5797
|
-
patchesByPattern[resolvePatchKey(key, rootDirectoryUrl)] = patches;
|
|
5798
|
-
}
|
|
5799
|
-
const associations = URL_META.resolveAssociations(
|
|
5800
|
-
{ patches: patchesByPattern },
|
|
5801
|
-
rootDirectoryUrl,
|
|
5802
|
-
);
|
|
5803
|
-
findPatches = (url) => {
|
|
5804
|
-
const { patches } = URL_META.applyAssociations({
|
|
5805
|
-
url: asUrlWithoutSearch(url),
|
|
5806
|
-
associations,
|
|
5807
|
-
});
|
|
5808
|
-
return patches;
|
|
5809
|
-
};
|
|
5810
|
-
},
|
|
5811
|
-
transformUrlContent: (urlInfo) => {
|
|
5812
|
-
const patches = findPatches(urlInfo.url);
|
|
5813
|
-
if (!patches) {
|
|
5814
|
-
return null;
|
|
5815
|
-
}
|
|
5816
|
-
const { content } = urlInfo;
|
|
5817
|
-
const magicSource = createMagicSource(content);
|
|
5818
|
-
for (const { from, to } of patches) {
|
|
5819
|
-
const start = content.indexOf(from);
|
|
5820
|
-
const occurrenceCount =
|
|
5821
|
-
start === -1 ? 0 : content.indexOf(from, start + 1) === -1 ? 1 : 2;
|
|
5822
|
-
if (occurrenceCount !== 1) {
|
|
5823
|
-
const fileRelativeUrl = urlToRelativeUrl(
|
|
5824
|
-
urlInfo.url,
|
|
5825
|
-
urlInfo.context.rootDirectoryUrl,
|
|
5826
|
-
);
|
|
5827
|
-
throw new Error(
|
|
5828
|
-
`patch cannot apply on "${fileRelativeUrl}": ${JSON.stringify(from)} found ${occurrenceCount === 0 ? "nowhere" : "more than once"} in the file. The file may have changed since the patch was written.`,
|
|
5829
|
-
);
|
|
5830
|
-
}
|
|
5831
|
-
magicSource.replace({
|
|
5832
|
-
start,
|
|
5833
|
-
end: start + from.length,
|
|
5834
|
-
replacement: to,
|
|
5835
|
-
});
|
|
5836
|
-
}
|
|
5837
|
-
return magicSource.toContentAndSourcemap();
|
|
5838
|
-
},
|
|
5839
|
-
};
|
|
5840
|
-
return [patchesPlugin];
|
|
5841
|
-
};
|
|
5842
|
-
|
|
5843
|
-
const assertPatches = (patches, key) => {
|
|
5844
|
-
if (!Array.isArray(patches)) {
|
|
5845
|
-
throw new TypeError(
|
|
5846
|
-
`patches["${key}"] must be an array of { from, to }, got ${patches}`,
|
|
5847
|
-
);
|
|
5848
|
-
}
|
|
5849
|
-
for (const patch of patches) {
|
|
5850
|
-
if (
|
|
5851
|
-
!patch ||
|
|
5852
|
-
typeof patch.from !== "string" ||
|
|
5853
|
-
patch.from === "" ||
|
|
5854
|
-
typeof patch.to !== "string"
|
|
5855
|
-
) {
|
|
5856
|
-
throw new TypeError(
|
|
5857
|
-
`patches["${key}"] entries must be { from: string, to: string } with a non-empty "from"`,
|
|
5858
|
-
);
|
|
5859
|
-
}
|
|
5860
|
-
}
|
|
5861
|
-
};
|
|
5862
|
-
|
|
5863
|
-
// "./x", "../x", "/x", "file:///x" and "**/x" are url patterns; anything
|
|
5864
|
-
// else names a path inside a package, looked up in node_modules
|
|
5865
|
-
const resolvePatchKey = (key, rootDirectoryUrl) => {
|
|
5866
|
-
if (
|
|
5867
|
-
key.startsWith("./") ||
|
|
5868
|
-
key.startsWith("../") ||
|
|
5869
|
-
key.startsWith("/") ||
|
|
5870
|
-
key.startsWith("file:") ||
|
|
5871
|
-
key.startsWith("*")
|
|
5872
|
-
) {
|
|
5873
|
-
return key;
|
|
5874
|
-
}
|
|
5875
|
-
const segments = key.split("/");
|
|
5876
|
-
const packageName = key.startsWith("@")
|
|
5877
|
-
? `${segments[0]}/${segments[1]}`
|
|
5878
|
-
: segments[0];
|
|
5879
|
-
const pathInsidePackage = key.slice(packageName.length);
|
|
5880
|
-
let directoryUrl = new URL(rootDirectoryUrl);
|
|
5881
|
-
while (true) {
|
|
5882
|
-
const packageDirectoryUrl = new URL(
|
|
5883
|
-
`./node_modules/${packageName}/`,
|
|
5884
|
-
directoryUrl,
|
|
5885
|
-
);
|
|
5886
|
-
if (existsSync(packageDirectoryUrl)) {
|
|
5887
|
-
return String(new URL(`.${pathInsidePackage}`, packageDirectoryUrl));
|
|
5888
|
-
}
|
|
5889
|
-
const parentDirectoryUrl = new URL("../", directoryUrl);
|
|
5890
|
-
if (parentDirectoryUrl.href === directoryUrl.href) {
|
|
5891
|
-
throw new Error(
|
|
5892
|
-
`patches["${key}"]: package "${packageName}" not found in any node_modules above ${rootDirectoryUrl}`,
|
|
5893
|
-
);
|
|
5894
|
-
}
|
|
5895
|
-
directoryUrl = parentDirectoryUrl;
|
|
5896
|
-
}
|
|
5897
|
-
};
|
|
5898
|
-
|
|
5899
5899
|
const jsenvPluginInliningAsDataUrl = () => {
|
|
5900
5900
|
return {
|
|
5901
5901
|
name: "jsenv:inlining_as_data_url",
|
|
@@ -8335,7 +8335,6 @@ const getCorePlugins = ({
|
|
|
8335
8335
|
directoryListing = true,
|
|
8336
8336
|
directoryReferenceEffect,
|
|
8337
8337
|
supervisor,
|
|
8338
|
-
patches,
|
|
8339
8338
|
injections,
|
|
8340
8339
|
transpilation = true,
|
|
8341
8340
|
inlining = true,
|
|
@@ -8377,9 +8376,6 @@ const getCorePlugins = ({
|
|
|
8377
8376
|
...(packageBundle
|
|
8378
8377
|
? [jsenvPluginWorkspaceBundle({ packageDirectory })]
|
|
8379
8378
|
: []),
|
|
8380
|
-
// before everything else: what the other plugins read must be the
|
|
8381
|
-
// patched file
|
|
8382
|
-
...jsenvPluginPatches(patches),
|
|
8383
8379
|
// before reference analysis: an url written by an injection must hold its
|
|
8384
8380
|
// final value when references are analyzed
|
|
8385
8381
|
jsenvPluginInjections(injections),
|
|
@@ -12751,6 +12747,11 @@ const startDevServer = async ({
|
|
|
12751
12747
|
serverStopCallbackSet.add(dependencyWatcher.stop);
|
|
12752
12748
|
|
|
12753
12749
|
const devServerJsenvPluginStore = await createJsenvPluginStore([
|
|
12750
|
+
// First, ahead of the plugins given by the caller: what every other plugin
|
|
12751
|
+
// reads must be the patched file, and a caller's plugin may rewrite a file
|
|
12752
|
+
// (plugin-preact reprints one it instruments) before a patch written
|
|
12753
|
+
// against its text on disk gets to see it.
|
|
12754
|
+
...jsenvPluginPatches(patches),
|
|
12754
12755
|
jsenvPluginServerEvents({ clientAutoreload }),
|
|
12755
12756
|
// The client-monitoring dashboard is a dev-time convenience; a test-plan run
|
|
12756
12757
|
// doesn't use it and shouldn't pay for the reporter being injected into
|
|
@@ -12778,7 +12779,6 @@ const startDevServer = async ({
|
|
|
12778
12779
|
magicDirectoryIndex,
|
|
12779
12780
|
directoryListing,
|
|
12780
12781
|
supervisor,
|
|
12781
|
-
patches,
|
|
12782
12782
|
injections,
|
|
12783
12783
|
transpilation,
|
|
12784
12784
|
spa,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "41.5.
|
|
3
|
+
"version": "41.5.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Tool to develop, test and build js projects",
|
|
6
6
|
"repository": {
|
|
@@ -73,14 +73,14 @@
|
|
|
73
73
|
"test:snapshot_clear": "npx @jsenv/filesystem clear **/tests/**/side_effects/"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"@jsenv/ast": "6.10.
|
|
77
|
-
"@jsenv/js-module-fallback": "1.6.
|
|
78
|
-
"@jsenv/plugin-bundling": "2.10.
|
|
79
|
-
"@jsenv/plugin-minification": "1.7.
|
|
80
|
-
"@jsenv/plugin-supervisor": "1.8.
|
|
81
|
-
"@jsenv/plugin-transpilation": "1.7.
|
|
76
|
+
"@jsenv/ast": "6.10.7",
|
|
77
|
+
"@jsenv/js-module-fallback": "1.6.11",
|
|
78
|
+
"@jsenv/plugin-bundling": "2.10.29",
|
|
79
|
+
"@jsenv/plugin-minification": "1.7.24",
|
|
80
|
+
"@jsenv/plugin-supervisor": "1.8.26",
|
|
81
|
+
"@jsenv/plugin-transpilation": "1.7.11",
|
|
82
82
|
"@jsenv/server": "17.6.6",
|
|
83
|
-
"@jsenv/sourcemap": "1.4.
|
|
83
|
+
"@jsenv/sourcemap": "1.4.10",
|
|
84
84
|
"react-table": "7.8.0"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
package/src/build/build.js
CHANGED
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
createJsenvPluginStore,
|
|
68
68
|
} from "../plugins/jsenv_plugins_controller.js";
|
|
69
69
|
import { isBareSpecifier } from "../helpers/bare_specifier.js";
|
|
70
|
+
import { jsenvPluginPatches } from "../plugins/patches/jsenv_plugin_patches.js";
|
|
70
71
|
import { getCorePlugins } from "../plugins/plugins.js";
|
|
71
72
|
import { jsenvPluginReferenceAnalysis } from "../plugins/reference_analysis/jsenv_plugin_reference_analysis.js";
|
|
72
73
|
import { renderBuildDoneLog } from "./build_content_report.js";
|
|
@@ -1219,6 +1220,9 @@ const prepareEntryPointBuild = async (
|
|
|
1219
1220
|
|
|
1220
1221
|
let _getOtherEntryBuildInfo;
|
|
1221
1222
|
const rawJsenvPluginStore = await createJsenvPluginStore([
|
|
1223
|
+
// First, ahead of the plugins given by the caller: what every other plugin
|
|
1224
|
+
// reads must be the patched file (see start_dev_server.js).
|
|
1225
|
+
...jsenvPluginPatches(patches),
|
|
1222
1226
|
...(mappings ? [jsenvPluginMappings(mappings)] : []),
|
|
1223
1227
|
{
|
|
1224
1228
|
name: "jsenv:other_entry_point_build_during_craft",
|
|
@@ -1253,7 +1257,6 @@ const prepareEntryPointBuild = async (
|
|
|
1253
1257
|
magicExtensions,
|
|
1254
1258
|
magicDirectoryIndex,
|
|
1255
1259
|
directoryReferenceEffect,
|
|
1256
|
-
patches,
|
|
1257
1260
|
injections,
|
|
1258
1261
|
transpilation: {
|
|
1259
1262
|
babelHelpersAsImport: !explicitJsModuleConversion,
|
|
@@ -27,6 +27,7 @@ import { createPackageDirectory } from "../kitchen/package_directory.js";
|
|
|
27
27
|
import { createJsenvPluginStore } from "../plugins/jsenv_plugins_controller.js";
|
|
28
28
|
import { jsenvPluginClientMonitoring } from "../plugins/client_monitoring/jsenv_plugin_client_monitoring.js";
|
|
29
29
|
import { jsenvPluginPageSwitcher } from "../plugins/page_switcher/jsenv_plugin_page_switcher.js";
|
|
30
|
+
import { jsenvPluginPatches } from "../plugins/patches/jsenv_plugin_patches.js";
|
|
30
31
|
import { getCorePlugins } from "../plugins/plugins.js";
|
|
31
32
|
import { jsenvPluginServerEvents } from "../plugins/server_events/jsenv_plugin_server_events.js";
|
|
32
33
|
import { devServerPluginChromeDevToolsJson } from "./dev_server_plugins/dev_server_plugin_chrome_devtools_json.js";
|
|
@@ -284,6 +285,11 @@ export const startDevServer = async ({
|
|
|
284
285
|
serverStopCallbackSet.add(dependencyWatcher.stop);
|
|
285
286
|
|
|
286
287
|
const devServerJsenvPluginStore = await createJsenvPluginStore([
|
|
288
|
+
// First, ahead of the plugins given by the caller: what every other plugin
|
|
289
|
+
// reads must be the patched file, and a caller's plugin may rewrite a file
|
|
290
|
+
// (plugin-preact reprints one it instruments) before a patch written
|
|
291
|
+
// against its text on disk gets to see it.
|
|
292
|
+
...jsenvPluginPatches(patches),
|
|
287
293
|
jsenvPluginServerEvents({ clientAutoreload }),
|
|
288
294
|
// The client-monitoring dashboard is a dev-time convenience; a test-plan run
|
|
289
295
|
// doesn't use it and shouldn't pay for the reporter being injected into
|
|
@@ -311,7 +317,6 @@ export const startDevServer = async ({
|
|
|
311
317
|
magicDirectoryIndex,
|
|
312
318
|
directoryListing,
|
|
313
319
|
supervisor,
|
|
314
|
-
patches,
|
|
315
320
|
injections,
|
|
316
321
|
transpilation,
|
|
317
322
|
spa,
|
package/src/plugins/plugins.js
CHANGED
|
@@ -11,7 +11,6 @@ import { jsenvPluginProtocolFile } from "./protocol_file/jsenv_plugin_protocol_f
|
|
|
11
11
|
import { jsenvPluginProtocolHttp } from "./protocol_http/jsenv_plugin_protocol_http.js";
|
|
12
12
|
import { jsenvPluginDirectoryReferenceEffect } from "./directory_reference_effect/jsenv_plugin_directory_reference_effect.js";
|
|
13
13
|
import { jsenvPluginInjections } from "./injections/jsenv_plugin_injections.js";
|
|
14
|
-
import { jsenvPluginPatches } from "./patches/jsenv_plugin_patches.js";
|
|
15
14
|
import { jsenvPluginInlining } from "./inlining/jsenv_plugin_inlining.js";
|
|
16
15
|
import { jsenvPluginCommonJsGlobals } from "./commonjs_globals/jsenv_plugin_commonjs_globals.js";
|
|
17
16
|
import { jsenvPluginImportMetaScenarios } from "./import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js";
|
|
@@ -52,7 +51,6 @@ export const getCorePlugins = ({
|
|
|
52
51
|
directoryListing = true,
|
|
53
52
|
directoryReferenceEffect,
|
|
54
53
|
supervisor,
|
|
55
|
-
patches,
|
|
56
54
|
injections,
|
|
57
55
|
transpilation = true,
|
|
58
56
|
inlining = true,
|
|
@@ -94,9 +92,6 @@ export const getCorePlugins = ({
|
|
|
94
92
|
...(packageBundle
|
|
95
93
|
? [jsenvPluginWorkspaceBundle({ packageDirectory })]
|
|
96
94
|
: []),
|
|
97
|
-
// before everything else: what the other plugins read must be the
|
|
98
|
-
// patched file
|
|
99
|
-
...jsenvPluginPatches(patches),
|
|
100
95
|
// before reference analysis: an url written by an injection must hold its
|
|
101
96
|
// final value when references are analyzed
|
|
102
97
|
jsenvPluginInjections(injections),
|