@normed/bundle 4.8.3 → 4.8.6
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/CHANGELOG.md +8 -0
- package/bundles/bin/cli.js +128 -42
- package/bundles/bin/cli.js.map +3 -3
- package/bundles/esbuild-plugins/load_pug.d.ts +11 -0
- package/bundles/index.js +128 -42
- package/bundles/index.js.map +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ Given a version number MAJOR.MINOR.PATCH, increment the:
|
|
|
6
6
|
2. MINOR version when you add functionality in a backwards compatible manner, and
|
|
7
7
|
3. PATCH version when you make backwards compatible bug fixes.
|
|
8
8
|
|
|
9
|
+
# 4.8.6
|
|
10
|
+
|
|
11
|
+
* PATCH: Fix pug-to-pug auto-discovery failing for `<a href="...pug">` links (and other elements) because the AST-based asset collector only checked a hardcoded element whitelist. Linking attributes (`src`, `srcset`, `href`) are now matched universally on all elements, with element-specific extras (`video[poster]`, `form[action]`, `object[data]`).
|
|
12
|
+
|
|
13
|
+
# 4.8.5
|
|
14
|
+
|
|
15
|
+
* PATCH: Fix asset attribute regex in pug plugin incorrectly matching strings inside inline `<script>` blocks. Asset references are now resolved exclusively from the pug AST (via `createAssetCollectorPlugin`), which is element-aware and only matches attributes on actual asset-bearing elements.
|
|
16
|
+
|
|
9
17
|
# 4.8.3
|
|
10
18
|
|
|
11
19
|
* PATCH: Add `--short` CLI flag and automatic coding agent detection (`CLAUDECODE`, `CURSOR_AGENT`, `AGENT` env vars) for condensed build output — prints file counts instead of file lists. Respects the `NO_COLOR` convention. Internal warnings in the pug plugin now go through the logger instead of `console.warn`.
|
package/bundles/bin/cli.js
CHANGED
|
@@ -68797,19 +68797,17 @@ function computeContentHash(content) {
|
|
|
68797
68797
|
const num = hash.readUInt32BE(0);
|
|
68798
68798
|
return num.toString(36).toUpperCase().padStart(8, "0").slice(0, 8);
|
|
68799
68799
|
}
|
|
68800
|
-
var
|
|
68801
|
-
|
|
68802
|
-
|
|
68803
|
-
audio: ["src"],
|
|
68804
|
-
source: ["src", "srcset"],
|
|
68805
|
-
link: ["href"],
|
|
68806
|
-
script: ["src"],
|
|
68800
|
+
var UNIVERSAL_LINKING_ATTRS = ["src", "srcset", "href"];
|
|
68801
|
+
var ELEMENT_SPECIFIC_LINKING_ATTRS = {
|
|
68802
|
+
form: ["action"],
|
|
68807
68803
|
object: ["data"],
|
|
68808
|
-
|
|
68809
|
-
track: ["src"],
|
|
68810
|
-
input: ["src"]
|
|
68811
|
-
// for type="image"
|
|
68804
|
+
video: ["poster"]
|
|
68812
68805
|
};
|
|
68806
|
+
function getLinkingAttrs(elementName) {
|
|
68807
|
+
if (!elementName) return void 0;
|
|
68808
|
+
const extra = ELEMENT_SPECIFIC_LINKING_ATTRS[elementName];
|
|
68809
|
+
return extra ? [...UNIVERSAL_LINKING_ATTRS, ...extra] : UNIVERSAL_LINKING_ATTRS;
|
|
68810
|
+
}
|
|
68813
68811
|
function isRelativeAssetPath(assetPath) {
|
|
68814
68812
|
if (!assetPath) return false;
|
|
68815
68813
|
if (assetPath.startsWith("#")) return false;
|
|
@@ -68878,6 +68876,42 @@ function resolvePackagePath(packageSpecifier, fromFile) {
|
|
|
68878
68876
|
return null;
|
|
68879
68877
|
}
|
|
68880
68878
|
}
|
|
68879
|
+
var packageRootCache = /* @__PURE__ */ new Map();
|
|
68880
|
+
function findPackageRoot(filePath) {
|
|
68881
|
+
let dir = path5.dirname(path5.resolve(filePath));
|
|
68882
|
+
const cacheKey = dir;
|
|
68883
|
+
if (packageRootCache.has(cacheKey)) return packageRootCache.get(cacheKey);
|
|
68884
|
+
while (true) {
|
|
68885
|
+
if (fs6.existsSync(path5.join(dir, "package.json"))) {
|
|
68886
|
+
packageRootCache.set(cacheKey, dir);
|
|
68887
|
+
return dir;
|
|
68888
|
+
}
|
|
68889
|
+
const parent = path5.dirname(dir);
|
|
68890
|
+
if (parent === dir) {
|
|
68891
|
+
packageRootCache.set(cacheKey, null);
|
|
68892
|
+
return null;
|
|
68893
|
+
}
|
|
68894
|
+
dir = parent;
|
|
68895
|
+
}
|
|
68896
|
+
}
|
|
68897
|
+
function resolveAssetPath(assetPath, pugDir, srcWebRoot) {
|
|
68898
|
+
if (assetPath.startsWith("/")) {
|
|
68899
|
+
return path5.resolve(srcWebRoot, assetPath.slice(1));
|
|
68900
|
+
}
|
|
68901
|
+
return path5.resolve(pugDir, assetPath);
|
|
68902
|
+
}
|
|
68903
|
+
function assertWithinAllowedRoots(absolutePath, allowedRoots, originalValue, pugFilePath) {
|
|
68904
|
+
const normalizedPath = path5.resolve(absolutePath);
|
|
68905
|
+
const withinARoot = allowedRoots.some((root) => {
|
|
68906
|
+
const normalizedRoot = path5.resolve(root);
|
|
68907
|
+
return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + path5.sep);
|
|
68908
|
+
});
|
|
68909
|
+
if (!withinARoot) {
|
|
68910
|
+
throw new Error(
|
|
68911
|
+
`Security: asset path "${originalValue}" resolves to "${normalizedPath}" which is outside the allowed source directories [${allowedRoots.join(", ")}]. Referenced in ${pugFilePath}. Use the copy: or build: prefix to resolve via Node module resolution.`
|
|
68912
|
+
);
|
|
68913
|
+
}
|
|
68914
|
+
}
|
|
68881
68915
|
var discoveredPugReferences = /* @__PURE__ */ new Map();
|
|
68882
68916
|
var discoveredLessReferences = /* @__PURE__ */ new Map();
|
|
68883
68917
|
var discoveredScriptReferences = /* @__PURE__ */ new Map();
|
|
@@ -68912,7 +68946,7 @@ function computeHtmlAssetPath(opts) {
|
|
|
68912
68946
|
}
|
|
68913
68947
|
return path5.relative(opts.htmlOutputDir, opts.absoluteOutput);
|
|
68914
68948
|
}
|
|
68915
|
-
async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
68949
|
+
async function processHtmlAssets(html, pugFilePath, options2, webRoot, collectedReferences = []) {
|
|
68916
68950
|
const assets = [];
|
|
68917
68951
|
const pugReferences = [];
|
|
68918
68952
|
const lessReferences = [];
|
|
@@ -68923,30 +68957,24 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
68923
68957
|
const outbase = options2.outbase || path5.dirname(pugFilePath);
|
|
68924
68958
|
const pugDir = path5.dirname(pugFilePath);
|
|
68925
68959
|
const publicPath = options2.publicPath || "";
|
|
68926
|
-
const
|
|
68927
|
-
const
|
|
68928
|
-
|
|
68960
|
+
const srcWebRoot = webRoot ? path5.join(outbase, webRoot) : outbase;
|
|
68961
|
+
const normalizedOutbase = path5.resolve(outbase);
|
|
68962
|
+
const normalizedPug = path5.resolve(pugFilePath);
|
|
68963
|
+
const pugWithinOutbase = normalizedPug === normalizedOutbase || normalizedPug.startsWith(normalizedOutbase + path5.sep);
|
|
68964
|
+
const packageRoot = pugWithinOutbase ? null : findPackageRoot(pugFilePath);
|
|
68965
|
+
const allowedRoots = [outbase, packageRoot].filter(
|
|
68966
|
+
(r) => r != null
|
|
68929
68967
|
);
|
|
68930
|
-
const
|
|
68968
|
+
const processedAssets = /* @__PURE__ */ new Map();
|
|
68931
68969
|
let modifiedHtml = html;
|
|
68932
|
-
const matches =
|
|
68933
|
-
|
|
68934
|
-
|
|
68935
|
-
const attr = match[1];
|
|
68936
|
-
const value = match[2];
|
|
68937
|
-
if (attr && value) {
|
|
68938
|
-
matches.push({
|
|
68939
|
-
fullMatch: match[0],
|
|
68940
|
-
attr: attr.toLowerCase(),
|
|
68941
|
-
value
|
|
68942
|
-
});
|
|
68943
|
-
}
|
|
68944
|
-
}
|
|
68970
|
+
const matches = collectedReferences.map(
|
|
68971
|
+
(ref) => ({ attr: ref.attr, value: ref.value })
|
|
68972
|
+
);
|
|
68945
68973
|
const discoveredPugPaths = /* @__PURE__ */ new Set();
|
|
68946
68974
|
const discoveredLessPaths = /* @__PURE__ */ new Set();
|
|
68947
68975
|
const discoveredScriptPaths = /* @__PURE__ */ new Set();
|
|
68948
68976
|
const discoveredPackageCssPaths = /* @__PURE__ */ new Set();
|
|
68949
|
-
for (const {
|
|
68977
|
+
for (const { attr, value } of matches) {
|
|
68950
68978
|
let newValue = value;
|
|
68951
68979
|
if (attr === "srcset") {
|
|
68952
68980
|
const srcsetParts = value.split(",");
|
|
@@ -68959,7 +68987,13 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
68959
68987
|
[getVerbatimPath(assetPath), ...descriptors].filter(Boolean).join(" ")
|
|
68960
68988
|
);
|
|
68961
68989
|
} else if (assetPath && isPugReference(assetPath)) {
|
|
68962
|
-
const absolutePath =
|
|
68990
|
+
const absolutePath = resolveAssetPath(assetPath, pugDir, srcWebRoot);
|
|
68991
|
+
assertWithinAllowedRoots(
|
|
68992
|
+
absolutePath,
|
|
68993
|
+
allowedRoots,
|
|
68994
|
+
assetPath,
|
|
68995
|
+
pugFilePath
|
|
68996
|
+
);
|
|
68963
68997
|
if (!discoveredPugPaths.has(absolutePath)) {
|
|
68964
68998
|
discoveredPugPaths.add(absolutePath);
|
|
68965
68999
|
pugReferences.push({ originalHref: assetPath, absolutePath });
|
|
@@ -68976,6 +69010,8 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
68976
69010
|
publicPath,
|
|
68977
69011
|
assets,
|
|
68978
69012
|
processedAssets,
|
|
69013
|
+
srcWebRoot,
|
|
69014
|
+
allowedRoots,
|
|
68979
69015
|
webRoot
|
|
68980
69016
|
);
|
|
68981
69017
|
if (hashedPath) {
|
|
@@ -68993,19 +69029,22 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
68993
69029
|
} else if (isVerbatimReference(value)) {
|
|
68994
69030
|
newValue = getVerbatimPath(value);
|
|
68995
69031
|
} else if (isPugReference(value)) {
|
|
68996
|
-
const absolutePath =
|
|
69032
|
+
const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
|
|
69033
|
+
assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
|
|
68997
69034
|
if (!discoveredPugPaths.has(absolutePath)) {
|
|
68998
69035
|
discoveredPugPaths.add(absolutePath);
|
|
68999
69036
|
pugReferences.push({ originalHref: value, absolutePath });
|
|
69000
69037
|
}
|
|
69001
69038
|
} else if (isLessReference(value)) {
|
|
69002
|
-
const absolutePath =
|
|
69039
|
+
const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
|
|
69040
|
+
assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
|
|
69003
69041
|
if (!discoveredLessPaths.has(absolutePath)) {
|
|
69004
69042
|
discoveredLessPaths.add(absolutePath);
|
|
69005
69043
|
lessReferences.push({ originalHref: value, absolutePath });
|
|
69006
69044
|
}
|
|
69007
69045
|
} else if (isScriptReference(value)) {
|
|
69008
|
-
const absolutePath =
|
|
69046
|
+
const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
|
|
69047
|
+
assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
|
|
69009
69048
|
if (!discoveredScriptPaths.has(absolutePath)) {
|
|
69010
69049
|
discoveredScriptPaths.add(absolutePath);
|
|
69011
69050
|
scriptReferences.push({ originalHref: value, absolutePath });
|
|
@@ -69137,6 +69176,8 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
69137
69176
|
publicPath,
|
|
69138
69177
|
assets,
|
|
69139
69178
|
processedAssets,
|
|
69179
|
+
srcWebRoot,
|
|
69180
|
+
allowedRoots,
|
|
69140
69181
|
webRoot
|
|
69141
69182
|
);
|
|
69142
69183
|
if (hashedPath) {
|
|
@@ -69144,8 +69185,9 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
69144
69185
|
}
|
|
69145
69186
|
}
|
|
69146
69187
|
if (newValue !== value) {
|
|
69147
|
-
const
|
|
69148
|
-
|
|
69188
|
+
const escapedValue = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
69189
|
+
const valueRegex = new RegExp(`(["'])${escapedValue}\\1`);
|
|
69190
|
+
modifiedHtml = modifiedHtml.replace(valueRegex, `$1${newValue}$1`);
|
|
69149
69191
|
}
|
|
69150
69192
|
}
|
|
69151
69193
|
return {
|
|
@@ -69157,8 +69199,14 @@ async function processHtmlAssets(html, pugFilePath, options2, webRoot) {
|
|
|
69157
69199
|
packageCssReferences
|
|
69158
69200
|
};
|
|
69159
69201
|
}
|
|
69160
|
-
async function processAsset(assetPath, pugDir, pugFilePath, outdir, outbase, assetNames, publicPath, assets, processedAssets, webRoot) {
|
|
69161
|
-
const absoluteSource =
|
|
69202
|
+
async function processAsset(assetPath, pugDir, pugFilePath, outdir, outbase, assetNames, publicPath, assets, processedAssets, srcWebRoot, allowedRoots, webRoot) {
|
|
69203
|
+
const absoluteSource = resolveAssetPath(assetPath, pugDir, srcWebRoot);
|
|
69204
|
+
assertWithinAllowedRoots(
|
|
69205
|
+
absoluteSource,
|
|
69206
|
+
allowedRoots,
|
|
69207
|
+
assetPath,
|
|
69208
|
+
pugFilePath
|
|
69209
|
+
);
|
|
69162
69210
|
if (processedAssets.has(absoluteSource)) {
|
|
69163
69211
|
return processedAssets.get(absoluteSource);
|
|
69164
69212
|
}
|
|
@@ -69312,11 +69360,11 @@ function createRebaseAssetsPlugin(entryFilePath) {
|
|
|
69312
69360
|
if (node.nodes) {
|
|
69313
69361
|
pending.push(...node.nodes);
|
|
69314
69362
|
}
|
|
69315
|
-
const
|
|
69316
|
-
if (!
|
|
69363
|
+
const linkingAttrs = getLinkingAttrs(node.name);
|
|
69364
|
+
if (!linkingAttrs) continue;
|
|
69317
69365
|
if (!node.attrs) continue;
|
|
69318
69366
|
for (const attr of node.attrs) {
|
|
69319
|
-
if (!
|
|
69367
|
+
if (!linkingAttrs.includes(attr.name)) continue;
|
|
69320
69368
|
const sourceFile = attr.filename || node.filename;
|
|
69321
69369
|
if (!sourceFile) continue;
|
|
69322
69370
|
const sourceDir = path5.dirname(sourceFile);
|
|
@@ -69353,6 +69401,36 @@ function createRebaseAssetsPlugin(entryFilePath) {
|
|
|
69353
69401
|
}
|
|
69354
69402
|
};
|
|
69355
69403
|
}
|
|
69404
|
+
function createAssetCollectorPlugin(collectedReferences) {
|
|
69405
|
+
return {
|
|
69406
|
+
preCodeGen(ast) {
|
|
69407
|
+
const pending = [...ast?.nodes || []];
|
|
69408
|
+
while (pending.length > 0) {
|
|
69409
|
+
const node = pending.shift();
|
|
69410
|
+
if (!node) continue;
|
|
69411
|
+
if (node.block?.nodes) {
|
|
69412
|
+
pending.push(...node.block.nodes);
|
|
69413
|
+
}
|
|
69414
|
+
if (node.nodes) {
|
|
69415
|
+
pending.push(...node.nodes);
|
|
69416
|
+
}
|
|
69417
|
+
const linkingAttrs = getLinkingAttrs(node.name);
|
|
69418
|
+
if (!linkingAttrs) continue;
|
|
69419
|
+
if (!node.attrs) continue;
|
|
69420
|
+
for (const attr of node.attrs) {
|
|
69421
|
+
if (!linkingAttrs.includes(attr.name)) continue;
|
|
69422
|
+
const extracted = extractStaticString(attr.val);
|
|
69423
|
+
if (!extracted) continue;
|
|
69424
|
+
collectedReferences.push({
|
|
69425
|
+
attr: attr.name,
|
|
69426
|
+
value: extracted.value
|
|
69427
|
+
});
|
|
69428
|
+
}
|
|
69429
|
+
}
|
|
69430
|
+
return ast;
|
|
69431
|
+
}
|
|
69432
|
+
};
|
|
69433
|
+
}
|
|
69356
69434
|
async function loadAsText2(_filepath) {
|
|
69357
69435
|
return {
|
|
69358
69436
|
loader: "text"
|
|
@@ -69394,12 +69472,14 @@ async function loadAsHtml(filepath, options2) {
|
|
|
69394
69472
|
}
|
|
69395
69473
|
async function loadAsEntrypoint(filepath, options2, webRoot) {
|
|
69396
69474
|
const fileData = await fs6.promises.readFile(filepath, "utf8");
|
|
69475
|
+
const collectedReferences = [];
|
|
69397
69476
|
let contents = import_pug.default.render(fileData, {
|
|
69398
69477
|
filename: filepath,
|
|
69399
69478
|
basedir: options2.outbase,
|
|
69400
69479
|
name: "render",
|
|
69401
69480
|
plugins: [
|
|
69402
69481
|
createRebaseAssetsPlugin(filepath),
|
|
69482
|
+
createAssetCollectorPlugin(collectedReferences),
|
|
69403
69483
|
pugTransformer(isScriptNodeWithSrcAttr, (nodes) => {
|
|
69404
69484
|
nodes;
|
|
69405
69485
|
})
|
|
@@ -69413,7 +69493,13 @@ async function loadAsEntrypoint(filepath, options2, webRoot) {
|
|
|
69413
69493
|
lessReferences,
|
|
69414
69494
|
scriptReferences,
|
|
69415
69495
|
packageCssReferences
|
|
69416
|
-
} = await processHtmlAssets(
|
|
69496
|
+
} = await processHtmlAssets(
|
|
69497
|
+
contents,
|
|
69498
|
+
filepath,
|
|
69499
|
+
options2,
|
|
69500
|
+
webRoot,
|
|
69501
|
+
collectedReferences
|
|
69502
|
+
);
|
|
69417
69503
|
contents = processedHtml;
|
|
69418
69504
|
if (pugReferences.length > 0) {
|
|
69419
69505
|
discoveredPugReferences.set(filepath, pugReferences);
|