@normed/bundle 4.8.2 → 4.8.4

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.
@@ -1,4 +1,14 @@
1
1
  import type * as esbuild from "esbuild";
2
+ export declare function findPackageRoot(filePath: string): string | null;
3
+ /**
4
+ * Resolve an asset path from a pug file, treating "/" as srcWebRoot (not filesystem root).
5
+ */
6
+ export declare function resolveAssetPath(assetPath: string, pugDir: string, srcWebRoot: string): string;
7
+ /**
8
+ * Assert that an absolute path is within one of the allowed source roots.
9
+ * Throws if the path escapes all allowed roots.
10
+ */
11
+ export declare function assertWithinAllowedRoots(absolutePath: string, allowedRoots: string[], originalValue: string, pugFilePath: string): void;
2
12
  /**
3
13
  * Discovered pug file reference from HTML.
4
14
  */
package/bundles/index.js CHANGED
@@ -68367,6 +68367,10 @@ var refinePackageJSON = makePartialRefinement({
68367
68367
 
68368
68368
  // pnp:/builds/normed/bundle/packages/bundle/src/log.ts
68369
68369
  var import_chalk = __toESM(require_source());
68370
+ var isAgent = !!process.env["CLAUDECODE"] || !!process.env["CURSOR_AGENT"] || !!process.env["AGENT"];
68371
+ if (process.env["NO_COLOR"] !== void 0) {
68372
+ import_chalk.default.level = 0;
68373
+ }
68370
68374
  function logStdOut(colour, ...message) {
68371
68375
  console.log(...message.map((m) => typeof m === "string" ? colour(m) : m));
68372
68376
  }
@@ -68629,7 +68633,9 @@ var NoMatchingBuilder = class extends Error {
68629
68633
 
68630
68634
  // pnp:/builds/normed/bundle/packages/bundle/src/builders/copy.ts
68631
68635
  var import_chalk2 = __toESM(require_source());
68632
- import_chalk2.default.level = 3;
68636
+ if (process.env["NO_COLOR"] === void 0) {
68637
+ import_chalk2.default.level = 3;
68638
+ }
68633
68639
  var copyBuilder = {
68634
68640
  name: "copy",
68635
68641
  color: import_chalk2.default.hex("#CDCDCD"),
@@ -68872,6 +68878,42 @@ function resolvePackagePath(packageSpecifier, fromFile) {
68872
68878
  return null;
68873
68879
  }
68874
68880
  }
68881
+ var packageRootCache = /* @__PURE__ */ new Map();
68882
+ function findPackageRoot(filePath) {
68883
+ let dir = path5.dirname(path5.resolve(filePath));
68884
+ const cacheKey = dir;
68885
+ if (packageRootCache.has(cacheKey)) return packageRootCache.get(cacheKey);
68886
+ while (true) {
68887
+ if (fs6.existsSync(path5.join(dir, "package.json"))) {
68888
+ packageRootCache.set(cacheKey, dir);
68889
+ return dir;
68890
+ }
68891
+ const parent = path5.dirname(dir);
68892
+ if (parent === dir) {
68893
+ packageRootCache.set(cacheKey, null);
68894
+ return null;
68895
+ }
68896
+ dir = parent;
68897
+ }
68898
+ }
68899
+ function resolveAssetPath(assetPath, pugDir, srcWebRoot) {
68900
+ if (assetPath.startsWith("/")) {
68901
+ return path5.resolve(srcWebRoot, assetPath.slice(1));
68902
+ }
68903
+ return path5.resolve(pugDir, assetPath);
68904
+ }
68905
+ function assertWithinAllowedRoots(absolutePath, allowedRoots, originalValue, pugFilePath) {
68906
+ const normalizedPath = path5.resolve(absolutePath);
68907
+ const withinARoot = allowedRoots.some((root) => {
68908
+ const normalizedRoot = path5.resolve(root);
68909
+ return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + path5.sep);
68910
+ });
68911
+ if (!withinARoot) {
68912
+ throw new Error(
68913
+ `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.`
68914
+ );
68915
+ }
68916
+ }
68875
68917
  var discoveredPugReferences = /* @__PURE__ */ new Map();
68876
68918
  var discoveredLessReferences = /* @__PURE__ */ new Map();
68877
68919
  var discoveredScriptReferences = /* @__PURE__ */ new Map();
@@ -68906,7 +68948,7 @@ function computeHtmlAssetPath(opts) {
68906
68948
  }
68907
68949
  return path5.relative(opts.htmlOutputDir, opts.absoluteOutput);
68908
68950
  }
68909
- async function processHtmlAssets(html, pugFilePath, options, webRoot) {
68951
+ async function processHtmlAssets(html, pugFilePath, options, webRoot, collectedReferences) {
68910
68952
  const assets = [];
68911
68953
  const pugReferences = [];
68912
68954
  const lessReferences = [];
@@ -68917,30 +68959,43 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
68917
68959
  const outbase = options.outbase || path5.dirname(pugFilePath);
68918
68960
  const pugDir = path5.dirname(pugFilePath);
68919
68961
  const publicPath = options.publicPath || "";
68920
- const processedAssets = /* @__PURE__ */ new Map();
68921
- const allAttrs = [...new Set(Object.values(ASSET_ATTRIBUTES).flat())].join(
68922
- "|"
68962
+ const srcWebRoot = webRoot ? path5.join(outbase, webRoot) : outbase;
68963
+ const normalizedOutbase = path5.resolve(outbase);
68964
+ const normalizedPug = path5.resolve(pugFilePath);
68965
+ const pugWithinOutbase = normalizedPug === normalizedOutbase || normalizedPug.startsWith(normalizedOutbase + path5.sep);
68966
+ const packageRoot = pugWithinOutbase ? null : findPackageRoot(pugFilePath);
68967
+ const allowedRoots = [outbase, packageRoot].filter(
68968
+ (r) => r != null
68923
68969
  );
68924
- const attrRegex = new RegExp(`(${allAttrs})\\s*=\\s*["']([^"']+)["']`, "gi");
68970
+ const processedAssets = /* @__PURE__ */ new Map();
68925
68971
  let modifiedHtml = html;
68926
68972
  const matches = [];
68927
- let match;
68928
- while ((match = attrRegex.exec(html)) !== null) {
68929
- const attr = match[1];
68930
- const value = match[2];
68931
- if (attr && value) {
68932
- matches.push({
68933
- fullMatch: match[0],
68934
- attr: attr.toLowerCase(),
68935
- value
68936
- });
68973
+ if (collectedReferences && collectedReferences.length > 0) {
68974
+ for (const ref of collectedReferences) {
68975
+ matches.push({ attr: ref.attr, value: ref.value });
68976
+ }
68977
+ } else {
68978
+ const allAttrs = [...new Set(Object.values(ASSET_ATTRIBUTES).flat())].join(
68979
+ "|"
68980
+ );
68981
+ const attrRegex = new RegExp(
68982
+ `(${allAttrs})\\s*=\\s*["']([^"']+)["']`,
68983
+ "gi"
68984
+ );
68985
+ let match;
68986
+ while ((match = attrRegex.exec(html)) !== null) {
68987
+ const attr = match[1];
68988
+ const value = match[2];
68989
+ if (attr && value) {
68990
+ matches.push({ attr: attr.toLowerCase(), value });
68991
+ }
68937
68992
  }
68938
68993
  }
68939
68994
  const discoveredPugPaths = /* @__PURE__ */ new Set();
68940
68995
  const discoveredLessPaths = /* @__PURE__ */ new Set();
68941
68996
  const discoveredScriptPaths = /* @__PURE__ */ new Set();
68942
68997
  const discoveredPackageCssPaths = /* @__PURE__ */ new Set();
68943
- for (const { fullMatch, attr, value } of matches) {
68998
+ for (const { attr, value } of matches) {
68944
68999
  let newValue = value;
68945
69000
  if (attr === "srcset") {
68946
69001
  const srcsetParts = value.split(",");
@@ -68953,7 +69008,13 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
68953
69008
  [getVerbatimPath(assetPath), ...descriptors].filter(Boolean).join(" ")
68954
69009
  );
68955
69010
  } else if (assetPath && isPugReference(assetPath)) {
68956
- const absolutePath = path5.resolve(pugDir, assetPath);
69011
+ const absolutePath = resolveAssetPath(assetPath, pugDir, srcWebRoot);
69012
+ assertWithinAllowedRoots(
69013
+ absolutePath,
69014
+ allowedRoots,
69015
+ assetPath,
69016
+ pugFilePath
69017
+ );
68957
69018
  if (!discoveredPugPaths.has(absolutePath)) {
68958
69019
  discoveredPugPaths.add(absolutePath);
68959
69020
  pugReferences.push({ originalHref: assetPath, absolutePath });
@@ -68970,6 +69031,8 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
68970
69031
  publicPath,
68971
69032
  assets,
68972
69033
  processedAssets,
69034
+ srcWebRoot,
69035
+ allowedRoots,
68973
69036
  webRoot
68974
69037
  );
68975
69038
  if (hashedPath) {
@@ -68987,19 +69050,22 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
68987
69050
  } else if (isVerbatimReference(value)) {
68988
69051
  newValue = getVerbatimPath(value);
68989
69052
  } else if (isPugReference(value)) {
68990
- const absolutePath = path5.resolve(pugDir, value);
69053
+ const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
69054
+ assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
68991
69055
  if (!discoveredPugPaths.has(absolutePath)) {
68992
69056
  discoveredPugPaths.add(absolutePath);
68993
69057
  pugReferences.push({ originalHref: value, absolutePath });
68994
69058
  }
68995
69059
  } else if (isLessReference(value)) {
68996
- const absolutePath = path5.resolve(pugDir, value);
69060
+ const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
69061
+ assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
68997
69062
  if (!discoveredLessPaths.has(absolutePath)) {
68998
69063
  discoveredLessPaths.add(absolutePath);
68999
69064
  lessReferences.push({ originalHref: value, absolutePath });
69000
69065
  }
69001
69066
  } else if (isScriptReference(value)) {
69002
- const absolutePath = path5.resolve(pugDir, value);
69067
+ const absolutePath = resolveAssetPath(value, pugDir, srcWebRoot);
69068
+ assertWithinAllowedRoots(absolutePath, allowedRoots, value, pugFilePath);
69003
69069
  if (!discoveredScriptPaths.has(absolutePath)) {
69004
69070
  discoveredScriptPaths.add(absolutePath);
69005
69071
  scriptReferences.push({ originalHref: value, absolutePath });
@@ -69008,7 +69074,7 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69008
69074
  const specifier = getResolvedSpecifier(value);
69009
69075
  const absolutePath = resolvePackagePath(specifier, pugFilePath);
69010
69076
  if (!absolutePath) {
69011
- console.warn(
69077
+ log_default.warn(
69012
69078
  `Warning: Cannot resolve build reference: "${specifier}" (from ${value})
69013
69079
  Referenced in rendered HTML of ${pugFilePath}`
69014
69080
  );
@@ -69036,7 +69102,7 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69036
69102
  packageCssReferences.push({ originalHref: value, absolutePath });
69037
69103
  }
69038
69104
  } else {
69039
- console.warn(
69105
+ log_default.warn(
69040
69106
  `Warning: build: prefix used on non-compilable file "${specifier}" (extension: ${ext}). Did you mean copy:?
69041
69107
  Referenced in rendered HTML of ${pugFilePath}`
69042
69108
  );
@@ -69046,7 +69112,7 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69046
69112
  const specifier = getResolvedSpecifier(value);
69047
69113
  const absolutePath = resolvePackagePath(specifier, pugFilePath);
69048
69114
  if (!absolutePath) {
69049
- console.warn(
69115
+ log_default.warn(
69050
69116
  `Warning: Cannot resolve copy reference: "${specifier}" (from ${value})
69051
69117
  Referenced in rendered HTML of ${pugFilePath}`
69052
69118
  );
@@ -69076,14 +69142,14 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69076
69142
  }
69077
69143
  }
69078
69144
  } else if (isPackageCssReference(value)) {
69079
- console.warn(
69145
+ log_default.warn(
69080
69146
  `Warning: pkg: prefix is deprecated, use copy: instead: "${value}"
69081
69147
  Referenced in rendered HTML of ${pugFilePath}`
69082
69148
  );
69083
69149
  const packageSpecifier = getPackageSpecifier(value);
69084
69150
  const absolutePath = resolvePackagePath(packageSpecifier, pugFilePath);
69085
69151
  if (!absolutePath) {
69086
- console.warn(
69152
+ log_default.warn(
69087
69153
  `Warning: Package not found: "${packageSpecifier}" (from ${value})
69088
69154
  Referenced in rendered HTML of ${pugFilePath}`
69089
69155
  );
@@ -69092,14 +69158,14 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69092
69158
  packageCssReferences.push({ originalHref: value, absolutePath });
69093
69159
  }
69094
69160
  } else if (isPackageReference(value)) {
69095
- console.warn(
69161
+ log_default.warn(
69096
69162
  `Warning: pkg: prefix is deprecated, use copy: instead: "${value}"
69097
69163
  Referenced in rendered HTML of ${pugFilePath}`
69098
69164
  );
69099
69165
  const packageSpecifier = getPackageSpecifier(value);
69100
69166
  const absolutePath = resolvePackagePath(packageSpecifier, pugFilePath);
69101
69167
  if (!absolutePath) {
69102
- console.warn(
69168
+ log_default.warn(
69103
69169
  `Warning: Package not found: "${packageSpecifier}" (from ${value})
69104
69170
  Referenced in rendered HTML of ${pugFilePath}`
69105
69171
  );
@@ -69131,6 +69197,8 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69131
69197
  publicPath,
69132
69198
  assets,
69133
69199
  processedAssets,
69200
+ srcWebRoot,
69201
+ allowedRoots,
69134
69202
  webRoot
69135
69203
  );
69136
69204
  if (hashedPath) {
@@ -69138,8 +69206,9 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69138
69206
  }
69139
69207
  }
69140
69208
  if (newValue !== value) {
69141
- const newFullMatch = fullMatch.replace(value, newValue);
69142
- modifiedHtml = modifiedHtml.replace(fullMatch, newFullMatch);
69209
+ const escapedValue = value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69210
+ const valueRegex = new RegExp(`(["'])${escapedValue}\\1`);
69211
+ modifiedHtml = modifiedHtml.replace(valueRegex, `$1${newValue}$1`);
69143
69212
  }
69144
69213
  }
69145
69214
  return {
@@ -69151,13 +69220,19 @@ async function processHtmlAssets(html, pugFilePath, options, webRoot) {
69151
69220
  packageCssReferences
69152
69221
  };
69153
69222
  }
69154
- async function processAsset(assetPath, pugDir, pugFilePath, outdir, outbase, assetNames, publicPath, assets, processedAssets, webRoot) {
69155
- const absoluteSource = path5.resolve(pugDir, assetPath);
69223
+ async function processAsset(assetPath, pugDir, pugFilePath, outdir, outbase, assetNames, publicPath, assets, processedAssets, srcWebRoot, allowedRoots, webRoot) {
69224
+ const absoluteSource = resolveAssetPath(assetPath, pugDir, srcWebRoot);
69225
+ assertWithinAllowedRoots(
69226
+ absoluteSource,
69227
+ allowedRoots,
69228
+ assetPath,
69229
+ pugFilePath
69230
+ );
69156
69231
  if (processedAssets.has(absoluteSource)) {
69157
69232
  return processedAssets.get(absoluteSource);
69158
69233
  }
69159
69234
  if (!fs6.existsSync(absoluteSource)) {
69160
- console.warn(
69235
+ log_default.warn(
69161
69236
  `Warning: Asset not found: "${assetPath}" (resolved to ${absoluteSource})
69162
69237
  Referenced in rendered HTML of ${pugFilePath}`
69163
69238
  );
@@ -69347,6 +69422,36 @@ function createRebaseAssetsPlugin(entryFilePath) {
69347
69422
  }
69348
69423
  };
69349
69424
  }
69425
+ function createAssetCollectorPlugin(collectedReferences) {
69426
+ return {
69427
+ preCodeGen(ast) {
69428
+ const pending = [...ast?.nodes || []];
69429
+ while (pending.length > 0) {
69430
+ const node = pending.shift();
69431
+ if (!node) continue;
69432
+ if (node.block?.nodes) {
69433
+ pending.push(...node.block.nodes);
69434
+ }
69435
+ if (node.nodes) {
69436
+ pending.push(...node.nodes);
69437
+ }
69438
+ const assetAttrs = ASSET_ATTRIBUTES[node.name];
69439
+ if (!assetAttrs) continue;
69440
+ if (!node.attrs) continue;
69441
+ for (const attr of node.attrs) {
69442
+ if (!assetAttrs.includes(attr.name)) continue;
69443
+ const extracted = extractStaticString(attr.val);
69444
+ if (!extracted) continue;
69445
+ collectedReferences.push({
69446
+ attr: attr.name,
69447
+ value: extracted.value
69448
+ });
69449
+ }
69450
+ }
69451
+ return ast;
69452
+ }
69453
+ };
69454
+ }
69350
69455
  async function loadAsText2(_filepath) {
69351
69456
  return {
69352
69457
  loader: "text"
@@ -69388,12 +69493,14 @@ async function loadAsHtml(filepath, options) {
69388
69493
  }
69389
69494
  async function loadAsEntrypoint(filepath, options, webRoot) {
69390
69495
  const fileData = await fs6.promises.readFile(filepath, "utf8");
69496
+ const collectedReferences = [];
69391
69497
  let contents = import_pug.default.render(fileData, {
69392
69498
  filename: filepath,
69393
69499
  basedir: options.outbase,
69394
69500
  name: "render",
69395
69501
  plugins: [
69396
69502
  createRebaseAssetsPlugin(filepath),
69503
+ createAssetCollectorPlugin(collectedReferences),
69397
69504
  pugTransformer(isScriptNodeWithSrcAttr, (nodes) => {
69398
69505
  nodes;
69399
69506
  })
@@ -69407,7 +69514,13 @@ async function loadAsEntrypoint(filepath, options, webRoot) {
69407
69514
  lessReferences,
69408
69515
  scriptReferences,
69409
69516
  packageCssReferences
69410
- } = await processHtmlAssets(contents, filepath, options, webRoot);
69517
+ } = await processHtmlAssets(
69518
+ contents,
69519
+ filepath,
69520
+ options,
69521
+ webRoot,
69522
+ collectedReferences
69523
+ );
69411
69524
  contents = processedHtml;
69412
69525
  if (pugReferences.length > 0) {
69413
69526
  discoveredPugReferences.set(filepath, pugReferences);
@@ -69660,7 +69773,9 @@ var import_esbuild_plugin_pnp = __toESM(require_lib15());
69660
69773
  import * as ts from "typescript";
69661
69774
  import path8 from "path";
69662
69775
  import fs9 from "fs";
69663
- import_chalk3.default.level = 3;
69776
+ if (process.env["NO_COLOR"] === void 0) {
69777
+ import_chalk3.default.level = 3;
69778
+ }
69664
69779
  function rewritePugReferencesInHtml(html, pugReferences, pugToOutputPath, htmlOutputDir, outdir) {
69665
69780
  let result = html;
69666
69781
  for (const ref of pugReferences) {
@@ -70329,7 +70444,9 @@ async function compileToTypeDeclarations(fileNames, options) {
70329
70444
 
70330
70445
  // pnp:/builds/normed/bundle/packages/bundle/src/builders/index.ts
70331
70446
  var import_chalk4 = __toESM(require_source());
70332
- import_chalk4.default.level = 3;
70447
+ if (process.env["NO_COLOR"] === void 0) {
70448
+ import_chalk4.default.level = 3;
70449
+ }
70333
70450
  function verifyBuilder(builder) {
70334
70451
  const tests = [
70335
70452
  (builder2) => {