@dereekb/firebase 13.12.1 → 13.12.2

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,7 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var node_module = require('node:module');
3
4
  var node_fs = require('node:fs');
4
5
  var node_path = require('node:path');
6
+ var typescriptEstree = require('@typescript-eslint/typescript-estree');
5
7
  var parser = require('@typescript-eslint/parser');
6
8
 
7
9
  /**
@@ -243,15 +245,15 @@ var parser = require('@typescript-eslint/parser');
243
245
  description: 'Reject function signatures with more than four positional parameters; require a single config object.'
244
246
  });
245
247
 
246
- function _array_like_to_array$f(arr, len) {
248
+ function _array_like_to_array$h(arr, len) {
247
249
  if (len == null || len > arr.length) len = arr.length;
248
250
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
249
251
  return arr2;
250
252
  }
251
- function _array_with_holes$9(arr) {
253
+ function _array_with_holes$a(arr) {
252
254
  if (Array.isArray(arr)) return arr;
253
255
  }
254
- function _iterable_to_array_limit$9(arr, i) {
256
+ function _iterable_to_array_limit$a(arr, i) {
255
257
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
256
258
  if (_i == null) return;
257
259
  var _arr = [];
@@ -275,19 +277,19 @@ function _iterable_to_array_limit$9(arr, i) {
275
277
  }
276
278
  return _arr;
277
279
  }
278
- function _non_iterable_rest$9() {
280
+ function _non_iterable_rest$a() {
279
281
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
280
282
  }
281
- function _sliced_to_array$9(arr, i) {
282
- return _array_with_holes$9(arr) || _iterable_to_array_limit$9(arr, i) || _unsupported_iterable_to_array$f(arr, i) || _non_iterable_rest$9();
283
+ function _sliced_to_array$a(arr, i) {
284
+ return _array_with_holes$a(arr) || _iterable_to_array_limit$a(arr, i) || _unsupported_iterable_to_array$h(arr, i) || _non_iterable_rest$a();
283
285
  }
284
- function _unsupported_iterable_to_array$f(o, minLen) {
286
+ function _unsupported_iterable_to_array$h(o, minLen) {
285
287
  if (!o) return;
286
- if (typeof o === "string") return _array_like_to_array$f(o, minLen);
288
+ if (typeof o === "string") return _array_like_to_array$h(o, minLen);
287
289
  var n = Object.prototype.toString.call(o).slice(8, -1);
288
290
  if (n === "Object" && o.constructor) n = o.constructor.name;
289
291
  if (n === "Map" || n === "Set") return Array.from(n);
290
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$f(o, minLen);
292
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$h(o, minLen);
291
293
  }
292
294
  var TAG_LINE_REGEX = /^@([A-Za-z_]\w*)\s*(.*)$/;
293
295
  var TYPE_ANNOTATION_REGEX = /^\{([^}]*)\}\s*(.*)$/;
@@ -343,19 +345,28 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
343
345
  });
344
346
  }
345
347
  /**
346
- * Returns the index of the first line that begins with a JSDoc `@tag`, or `-1` when none exists.
348
+ * Computes, per line, whether it sits inside a fenced code block (a ```` ``` ```` block, typically
349
+ * an `@example` body) and therefore must not be treated as a tag boundary. Fence delimiter lines
350
+ * themselves are flagged too. Without this, `@`-prefixed lines inside a fence — decorators like
351
+ * `@Global()` / `@Module()`, or JSDoc snippets — would be mis-parsed as standalone JSDoc tags.
347
352
  *
348
353
  * @param lines - Parsed lines in source order.
349
- * @returns Zero-based line index of the first tag, or `-1` when no tag is present.
350
- */ function findFirstTagIndex(lines) {
351
- var firstTagIndex = -1;
354
+ * @returns Boolean mask where `true` marks a line that must not start a tag.
355
+ */ function computeFenceMask(lines) {
356
+ var mask = lines.map(function() {
357
+ return false;
358
+ });
359
+ var fenceOpen = false;
352
360
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
353
361
  try {
354
362
  for(var _iterator = lines.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
355
- var _step_value = _sliced_to_array$9(_step.value, 2), i = _step_value[0], line = _step_value[1];
356
- if (TAG_LINE_REGEX.test(line.text)) {
357
- firstTagIndex = i;
358
- break;
363
+ var _step_value = _sliced_to_array$a(_step.value, 2), i = _step_value[0], line = _step_value[1];
364
+ var isDelimiter = line.text.trimStart().startsWith('```');
365
+ if (isDelimiter) {
366
+ mask[i] = true;
367
+ fenceOpen = !fenceOpen;
368
+ } else {
369
+ mask[i] = fenceOpen;
359
370
  }
360
371
  }
361
372
  } catch (err) {
@@ -372,6 +383,32 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
372
383
  }
373
384
  }
374
385
  }
386
+ return mask;
387
+ }
388
+ /**
389
+ * Returns true when the line at `index` opens a JSDoc tag and is not masked out by a code fence.
390
+ *
391
+ * @param lines - Parsed lines in source order.
392
+ * @param fenceMask - Mask from {@link computeFenceMask} marking fenced lines.
393
+ * @param index - Line index to test.
394
+ * @returns True when the line begins a tag that should be treated as a tag boundary.
395
+ */ function isTagStart(lines, fenceMask, index) {
396
+ return !fenceMask[index] && TAG_LINE_REGEX.test(lines[index].text);
397
+ }
398
+ /**
399
+ * Returns the index of the first line that begins with a JSDoc `@tag`, or `-1` when none exists.
400
+ *
401
+ * @param lines - Parsed lines in source order.
402
+ * @param fenceMask - Mask from {@link computeFenceMask} marking fenced lines.
403
+ * @returns Zero-based line index of the first tag, or `-1` when no tag is present.
404
+ */ function findFirstTagIndex(lines, fenceMask) {
405
+ var firstTagIndex = -1;
406
+ for(var i = 0; i < lines.length; i += 1){
407
+ if (isTagStart(lines, fenceMask, i)) {
408
+ firstTagIndex = i;
409
+ break;
410
+ }
411
+ }
375
412
  return firstTagIndex;
376
413
  }
377
414
  /**
@@ -469,15 +506,16 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
469
506
  * Collects the tag line at `startIndex` plus every following non-tag continuation line.
470
507
  *
471
508
  * @param lines - All parsed lines in the comment.
509
+ * @param fenceMask - Mask from {@link computeFenceMask} marking fenced lines.
472
510
  * @param startIndex - Index of the `@tag` opening line.
473
511
  * @returns The collected tag lines and the index of the next unconsumed line.
474
- */ function collectTagLines(lines, startIndex) {
512
+ */ function collectTagLines(lines, fenceMask, startIndex) {
475
513
  var tagLines = [
476
514
  lines[startIndex]
477
515
  ];
478
516
  var j = startIndex + 1;
479
517
  while(j < lines.length){
480
- if (TAG_LINE_REGEX.test(lines[j].text)) break;
518
+ if (isTagStart(lines, fenceMask, j)) break;
481
519
  tagLines.push(lines[j]);
482
520
  j += 1;
483
521
  }
@@ -508,15 +546,16 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
508
546
  * Builds a single parsed-tag record starting at `startIndex` in the line array.
509
547
  *
510
548
  * @param lines - All parsed lines in the comment.
549
+ * @param fenceMask - Mask from {@link computeFenceMask} marking fenced lines.
511
550
  * @param startIndex - Index of the `@tag` opening line.
512
551
  * @returns The parsed tag and the next unconsumed line index.
513
- */ function parseTagAt(lines, startIndex) {
552
+ */ function parseTagAt(lines, fenceMask, startIndex) {
514
553
  var line = lines[startIndex];
515
554
  var match = TAG_LINE_REGEX.exec(line.text);
516
555
  var tagName = match[1];
517
556
  var _extractTypeAnnotation = extractTypeAnnotation(match[2]), type = _extractTypeAnnotation.type, afterType = _extractTypeAnnotation.rest;
518
557
  var _extractParamName = extractParamName(tagName, afterType), name = _extractParamName.name, afterName = _extractParamName.rest;
519
- var _collectTagLines = collectTagLines(lines, startIndex), tagLines = _collectTagLines.tagLines, nextIndex = _collectTagLines.nextIndex;
558
+ var _collectTagLines = collectTagLines(lines, fenceMask, startIndex), tagLines = _collectTagLines.tagLines, nextIndex = _collectTagLines.nextIndex;
520
559
  var description = buildTagDescription(afterName, tagLines);
521
560
  return {
522
561
  tag: {
@@ -535,18 +574,19 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
535
574
  * Parses every `@tag` block starting from `firstTagIndex` to the end of the line array.
536
575
  *
537
576
  * @param lines - All parsed lines in the comment.
577
+ * @param fenceMask - Mask from {@link computeFenceMask} marking fenced lines.
538
578
  * @param firstTagIndex - Index where tag parsing should begin (`-1` skips entirely).
539
579
  * @returns All parsed tags in source order.
540
- */ function parseTags(lines, firstTagIndex) {
580
+ */ function parseTags(lines, fenceMask, firstTagIndex) {
541
581
  var tags = [];
542
582
  if (firstTagIndex !== -1) {
543
583
  var i = firstTagIndex;
544
584
  while(i < lines.length){
545
- if (!TAG_LINE_REGEX.test(lines[i].text)) {
585
+ if (!isTagStart(lines, fenceMask, i)) {
546
586
  i += 1;
547
587
  continue;
548
588
  }
549
- var _parseTagAt = parseTagAt(lines, i), tag = _parseTagAt.tag, nextIndex = _parseTagAt.nextIndex;
589
+ var _parseTagAt = parseTagAt(lines, fenceMask, i), tag = _parseTagAt.tag, nextIndex = _parseTagAt.nextIndex;
550
590
  tags.push(tag);
551
591
  i = nextIndex;
552
592
  }
@@ -570,14 +610,15 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
570
610
  */ function parseJsdocComment(commentValue) {
571
611
  var singleLine = !commentValue.includes('\n');
572
612
  var lines = buildParsedLines(commentValue);
573
- var firstTagIndex = findFirstTagIndex(lines);
613
+ var fenceMask = computeFenceMask(lines);
614
+ var firstTagIndex = findFirstTagIndex(lines, fenceMask);
574
615
  var descriptionLines = firstTagIndex === -1 ? lines.slice() : lines.slice(0, firstTagIndex);
575
616
  var trimmedDescription = trimBlankBoundaries(descriptionLines);
576
617
  var description = trimmedDescription.map(function(l) {
577
618
  return l.text;
578
619
  }).join('\n');
579
620
  var descriptionParagraphs = buildDescriptionParagraphs(trimmedDescription);
580
- var tags = parseTags(lines, firstTagIndex);
621
+ var tags = parseTags(lines, fenceMask, firstTagIndex);
581
622
  return {
582
623
  lines: lines,
583
624
  descriptionLines: descriptionLines,
@@ -597,15 +638,15 @@ var LINE_PREFIX_REGEX = /^(\s*\*?\s?)(.*)$/;
597
638
  * companions are required/optional, what value format each accepts, and which
598
639
  * messageId to emit when a check fails. The rule body itself only wires the
599
640
  * visitors and message map; all value-format validation lives here.
600
- */ function _array_like_to_array$e(arr, len) {
641
+ */ function _array_like_to_array$g(arr, len) {
601
642
  if (len == null || len > arr.length) len = arr.length;
602
643
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
603
644
  return arr2;
604
645
  }
605
- function _array_with_holes$8(arr) {
646
+ function _array_with_holes$9(arr) {
606
647
  if (Array.isArray(arr)) return arr;
607
648
  }
608
- function _iterable_to_array_limit$8(arr, i) {
649
+ function _iterable_to_array_limit$9(arr, i) {
609
650
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
610
651
  if (_i == null) return;
611
652
  var _arr = [];
@@ -629,19 +670,19 @@ function _iterable_to_array_limit$8(arr, i) {
629
670
  }
630
671
  return _arr;
631
672
  }
632
- function _non_iterable_rest$8() {
673
+ function _non_iterable_rest$9() {
633
674
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
634
675
  }
635
- function _sliced_to_array$8(arr, i) {
636
- return _array_with_holes$8(arr) || _iterable_to_array_limit$8(arr, i) || _unsupported_iterable_to_array$e(arr, i) || _non_iterable_rest$8();
676
+ function _sliced_to_array$9(arr, i) {
677
+ return _array_with_holes$9(arr) || _iterable_to_array_limit$9(arr, i) || _unsupported_iterable_to_array$g(arr, i) || _non_iterable_rest$9();
637
678
  }
638
- function _unsupported_iterable_to_array$e(o, minLen) {
679
+ function _unsupported_iterable_to_array$g(o, minLen) {
639
680
  if (!o) return;
640
- if (typeof o === "string") return _array_like_to_array$e(o, minLen);
681
+ if (typeof o === "string") return _array_like_to_array$g(o, minLen);
641
682
  var n = Object.prototype.toString.call(o).slice(8, -1);
642
683
  if (n === "Object" && o.constructor) n = o.constructor.name;
643
684
  if (n === "Map" || n === "Set") return Array.from(n);
644
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$e(o, minLen);
685
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$g(o, minLen);
645
686
  }
646
687
  /**
647
688
  * Kebab-case slug pattern: lowercase letters/digits, words separated by single hyphens,
@@ -915,7 +956,7 @@ function emitUnknownCompanions(groups, knownSuffixes, emit) {
915
956
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
916
957
  try {
917
958
  for(var _iterator = groups.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
918
- var _step_value = _sliced_to_array$8(_step.value, 2), suffix = _step_value[0], instances = _step_value[1];
959
+ var _step_value = _sliced_to_array$9(_step.value, 2), suffix = _step_value[0], instances = _step_value[1];
919
960
  if (knownSuffixes.has(suffix)) continue;
920
961
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
921
962
  try {
@@ -1089,34 +1130,137 @@ function checkCompanion(input) {
1089
1130
  return result;
1090
1131
  }
1091
1132
 
1092
- function _array_like_to_array$d(arr, len) {
1133
+ function _array_like_to_array$f(arr, len) {
1093
1134
  if (len == null || len > arr.length) len = arr.length;
1094
1135
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1095
1136
  return arr2;
1096
1137
  }
1097
- function _array_without_holes$9(arr) {
1098
- if (Array.isArray(arr)) return _array_like_to_array$d(arr);
1138
+ function _array_without_holes$a(arr) {
1139
+ if (Array.isArray(arr)) return _array_like_to_array$f(arr);
1099
1140
  }
1100
- function _iterable_to_array$9(iter) {
1141
+ function _iterable_to_array$a(iter) {
1101
1142
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1102
1143
  }
1103
- function _non_iterable_spread$9() {
1144
+ function _non_iterable_spread$a() {
1104
1145
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1105
1146
  }
1106
- function _to_consumable_array$9(arr) {
1107
- return _array_without_holes$9(arr) || _iterable_to_array$9(arr) || _unsupported_iterable_to_array$d(arr) || _non_iterable_spread$9();
1147
+ function _to_consumable_array$a(arr) {
1148
+ return _array_without_holes$a(arr) || _iterable_to_array$a(arr) || _unsupported_iterable_to_array$f(arr) || _non_iterable_spread$a();
1108
1149
  }
1109
- function _unsupported_iterable_to_array$d(o, minLen) {
1150
+ function _unsupported_iterable_to_array$f(o, minLen) {
1110
1151
  if (!o) return;
1111
- if (typeof o === "string") return _array_like_to_array$d(o, minLen);
1152
+ if (typeof o === "string") return _array_like_to_array$f(o, minLen);
1112
1153
  var n = Object.prototype.toString.call(o).slice(8, -1);
1113
1154
  if (n === "Object" && o.constructor) n = o.constructor.name;
1114
1155
  if (n === "Map" || n === "Set") return Array.from(n);
1115
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$d(o, minLen);
1156
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$f(o, minLen);
1116
1157
  }
1117
1158
  /**
1118
1159
  * Module that publishes the `@dereekb/firebase` Firestore constraint factories (`where`, `orderBy`, etc.).
1119
1160
  */ var FIREBASE_MODULE = '@dereekb/firebase';
1161
+ /**
1162
+ * Subpath, relative to the `@dereekb/firebase` package root, where the framework Firestore model
1163
+ * declarations live (`firestoreModelIdentity(...)` calls in source, identity type-annotations in the
1164
+ * shipped `.d.ts`).
1165
+ */ var FIREBASE_MODEL_SUBPATH = node_path.join('src', 'lib', 'model');
1166
+ var installedFirebaseModelDirCache = new Map();
1167
+ /**
1168
+ * Directory names the layout-agnostic discovery globs never descend into: installed dependencies
1169
+ * and build/cache output. Excluding these keeps a broad `**\/*.ts` scan from walking a downstream
1170
+ * consumer's `node_modules` (which can hold tens of thousands of declaration files) and from
1171
+ * double-counting compiled output under `dist`.
1172
+ */ var DEFAULT_DISCOVERY_EXCLUDED_DIRS = [
1173
+ 'node_modules',
1174
+ 'dist',
1175
+ '.git',
1176
+ '.nx',
1177
+ 'coverage',
1178
+ 'tmp'
1179
+ ];
1180
+ /**
1181
+ * Builds the `exclude` predicate passed to `fs.globSync(pattern, { cwd, exclude })` for the broad,
1182
+ * layout-agnostic discovery globs. Node invokes the predicate on each visited path (directories
1183
+ * included) and prunes the subtree when it returns true, so excluding a directory name here stops
1184
+ * the walk from ever descending into it.
1185
+ *
1186
+ * @param excludedDirs - Directory names to prune. Defaults to {@link DEFAULT_DISCOVERY_EXCLUDED_DIRS}.
1187
+ * @returns A predicate that returns true for any path containing an excluded directory segment.
1188
+ */ function discoveryGlobExcludeFilter() {
1189
+ var excludedDirs = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : DEFAULT_DISCOVERY_EXCLUDED_DIRS;
1190
+ var excluded = new Set(excludedDirs);
1191
+ return function(path) {
1192
+ return path.split(/[\\/]/).some(function(segment) {
1193
+ return excluded.has(segment);
1194
+ });
1195
+ };
1196
+ }
1197
+ /**
1198
+ * Resolves the absolute path to the installed `@dereekb/firebase` package's `src/lib/model`
1199
+ * directory, as seen from the ESLint `cwd`. Used by rules that need to read the framework model
1200
+ * declarations (identities, service factories) directly from the package a consumer has installed —
1201
+ * the downstream case where these live under `node_modules/@dereekb/firebase/...` as compiled
1202
+ * bundles plus `.d.ts` rather than a scannable source tree.
1203
+ *
1204
+ * Resolution uses Node's own module resolver (`require.resolve('@dereekb/firebase/package.json')`
1205
+ * anchored at `cwd`), so it transparently handles hoisting / nested `node_modules`. Returns null
1206
+ * when `@dereekb/firebase` is not resolvable as a dependency from `cwd` (e.g. inside the
1207
+ * dbx-components monorepo itself, where it is consumed via TS path mapping rather than
1208
+ * `node_modules`) — callers fall back to their cwd-relative source globs in that case.
1209
+ *
1210
+ * @param cwd - The ESLint working directory to resolve the dependency from.
1211
+ * @returns The absolute model directory, or null when it cannot be resolved.
1212
+ */ function resolveInstalledFirebaseModelDir(cwd) {
1213
+ var result;
1214
+ if (installedFirebaseModelDirCache.has(cwd)) {
1215
+ var _installedFirebaseModelDirCache_get;
1216
+ result = (_installedFirebaseModelDirCache_get = installedFirebaseModelDirCache.get(cwd)) !== null && _installedFirebaseModelDirCache_get !== void 0 ? _installedFirebaseModelDirCache_get : null;
1217
+ } else {
1218
+ result = null;
1219
+ try {
1220
+ var requireFromCwd = node_module.createRequire(node_path.join(cwd, '__dbx_firebase_model_resolver__.js'));
1221
+ var packageJsonPath = requireFromCwd.resolve("".concat(FIREBASE_MODULE, "/package.json"), {
1222
+ paths: [
1223
+ cwd
1224
+ ]
1225
+ });
1226
+ var candidate = node_path.join(node_path.dirname(packageJsonPath), FIREBASE_MODEL_SUBPATH);
1227
+ if (node_fs.existsSync(candidate)) {
1228
+ result = candidate;
1229
+ }
1230
+ } catch (unused) {
1231
+ result = null;
1232
+ }
1233
+ installedFirebaseModelDirCache.set(cwd, result);
1234
+ }
1235
+ return result;
1236
+ }
1237
+ /**
1238
+ * Resolves the referenced type name from either a `TSTypeReference` (`Foo<…>` / `ns.Foo<…>`) or a
1239
+ * `TSImportType` (`import("…").Foo<…>` — the form the TypeScript compiler emits in declaration
1240
+ * files for cross-module type references). Returns the rightmost identifier name in a qualified
1241
+ * name.
1242
+ *
1243
+ * @param node - A `TSTypeReference` or `TSImportType` node (or anything else).
1244
+ * @returns The referenced type name, or null when the node is neither shape.
1245
+ */ function referencedTypeName(node) {
1246
+ var result = null;
1247
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'TSTypeReference') {
1248
+ result = qualifiedNameTail(node.typeName);
1249
+ } else if ((node === null || node === void 0 ? void 0 : node.type) === 'TSImportType') {
1250
+ result = qualifiedNameTail(node.qualifier);
1251
+ }
1252
+ return result;
1253
+ }
1254
+ function qualifiedNameTail(node) {
1255
+ var _node_right;
1256
+ var result = null;
1257
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'Identifier') {
1258
+ result = node.name;
1259
+ } else if ((node === null || node === void 0 ? void 0 : node.type) === 'TSQualifiedName' && ((_node_right = node.right) === null || _node_right === void 0 ? void 0 : _node_right.type) === 'Identifier') {
1260
+ result = node.right.name;
1261
+ }
1262
+ return result;
1263
+ }
1120
1264
  /**
1121
1265
  * JSDoc tag name that marks an exported query factory whose body should be scanned by
1122
1266
  * `dbx-components-mcp`'s index extractor (`packages/dbx-components-mcp/src/scan/model-firebase-index-extract.ts`).
@@ -1158,7 +1302,7 @@ function _unsupported_iterable_to_array$d(o, minLen) {
1158
1302
  * Combined list of every Firestore constraint factory exported from `@dereekb/firebase`. Used
1159
1303
  * by the body-coherence rule to ensure a tagged factory body contains at least one constraint
1160
1304
  * call of any kind (index-affecting or pagination) before warning that the marker is orphaned.
1161
- */ var DEFAULT_CONSTRAINT_FACTORY_NAMES = _to_consumable_array$9(DEFAULT_INDEX_AFFECTING_CONSTRAINT_NAMES).concat(_to_consumable_array$9(DEFAULT_PAGINATION_CONSTRAINT_NAMES));
1305
+ */ var DEFAULT_CONSTRAINT_FACTORY_NAMES = _to_consumable_array$a(DEFAULT_INDEX_AFFECTING_CONSTRAINT_NAMES).concat(_to_consumable_array$a(DEFAULT_PAGINATION_CONSTRAINT_NAMES));
1162
1306
  /**
1163
1307
  * Creates an empty {@link ImportRegistry}.
1164
1308
  *
@@ -1619,30 +1763,30 @@ function _unsupported_iterable_to_array$d(o, minLen) {
1619
1763
  });
1620
1764
  }
1621
1765
 
1622
- function _array_like_to_array$c(arr, len) {
1766
+ function _array_like_to_array$e(arr, len) {
1623
1767
  if (len == null || len > arr.length) len = arr.length;
1624
1768
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1625
1769
  return arr2;
1626
1770
  }
1627
- function _array_without_holes$8(arr) {
1628
- if (Array.isArray(arr)) return _array_like_to_array$c(arr);
1771
+ function _array_without_holes$9(arr) {
1772
+ if (Array.isArray(arr)) return _array_like_to_array$e(arr);
1629
1773
  }
1630
- function _iterable_to_array$8(iter) {
1774
+ function _iterable_to_array$9(iter) {
1631
1775
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1632
1776
  }
1633
- function _non_iterable_spread$8() {
1777
+ function _non_iterable_spread$9() {
1634
1778
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1635
1779
  }
1636
- function _to_consumable_array$8(arr) {
1637
- return _array_without_holes$8(arr) || _iterable_to_array$8(arr) || _unsupported_iterable_to_array$c(arr) || _non_iterable_spread$8();
1780
+ function _to_consumable_array$9(arr) {
1781
+ return _array_without_holes$9(arr) || _iterable_to_array$9(arr) || _unsupported_iterable_to_array$e(arr) || _non_iterable_spread$9();
1638
1782
  }
1639
- function _unsupported_iterable_to_array$c(o, minLen) {
1783
+ function _unsupported_iterable_to_array$e(o, minLen) {
1640
1784
  if (!o) return;
1641
- if (typeof o === "string") return _array_like_to_array$c(o, minLen);
1785
+ if (typeof o === "string") return _array_like_to_array$e(o, minLen);
1642
1786
  var n = Object.prototype.toString.call(o).slice(8, -1);
1643
1787
  if (n === "Object" && o.constructor) n = o.constructor.name;
1644
1788
  if (n === "Map" || n === "Set") return Array.from(n);
1645
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$c(o, minLen);
1789
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$e(o, minLen);
1646
1790
  }
1647
1791
  /**
1648
1792
  * ESLint rule that forbids inline `@dereekb/firebase` Firestore constraint factory calls
@@ -1700,7 +1844,7 @@ function _unsupported_iterable_to_array$c(o, minLen) {
1700
1844
  var options = (_context_options_ = context.options[0]) !== null && _context_options_ !== void 0 ? _context_options_ : {};
1701
1845
  var sourceCode = context.sourceCode;
1702
1846
  var baseNames = (_options_constraintNames = options.constraintNames) !== null && _options_constraintNames !== void 0 ? _options_constraintNames : DEFAULT_INDEX_AFFECTING_CONSTRAINT_NAMES;
1703
- var constraintNames = new Set(_to_consumable_array$8(baseNames).concat(_to_consumable_array$8((_options_additionalConstraintNames = options.additionalConstraintNames) !== null && _options_additionalConstraintNames !== void 0 ? _options_additionalConstraintNames : [])));
1847
+ var constraintNames = new Set(_to_consumable_array$9(baseNames).concat(_to_consumable_array$9((_options_additionalConstraintNames = options.additionalConstraintNames) !== null && _options_additionalConstraintNames !== void 0 ? _options_additionalConstraintNames : [])));
1704
1848
  var allowedSources = new Set((_options_allowedImportSources = options.allowedImportSources) !== null && _options_allowedImportSources !== void 0 ? _options_allowedImportSources : [
1705
1849
  FIREBASE_MODULE
1706
1850
  ]);
@@ -2783,30 +2927,30 @@ function _type_of$8(obj) {
2783
2927
  }
2784
2928
  };
2785
2929
 
2786
- function _array_like_to_array$b(arr, len) {
2930
+ function _array_like_to_array$d(arr, len) {
2787
2931
  if (len == null || len > arr.length) len = arr.length;
2788
2932
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2789
2933
  return arr2;
2790
2934
  }
2791
- function _array_without_holes$7(arr) {
2792
- if (Array.isArray(arr)) return _array_like_to_array$b(arr);
2935
+ function _array_without_holes$8(arr) {
2936
+ if (Array.isArray(arr)) return _array_like_to_array$d(arr);
2793
2937
  }
2794
- function _iterable_to_array$7(iter) {
2938
+ function _iterable_to_array$8(iter) {
2795
2939
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2796
2940
  }
2797
- function _non_iterable_spread$7() {
2941
+ function _non_iterable_spread$8() {
2798
2942
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2799
2943
  }
2800
- function _to_consumable_array$7(arr) {
2801
- return _array_without_holes$7(arr) || _iterable_to_array$7(arr) || _unsupported_iterable_to_array$b(arr) || _non_iterable_spread$7();
2944
+ function _to_consumable_array$8(arr) {
2945
+ return _array_without_holes$8(arr) || _iterable_to_array$8(arr) || _unsupported_iterable_to_array$d(arr) || _non_iterable_spread$8();
2802
2946
  }
2803
- function _unsupported_iterable_to_array$b(o, minLen) {
2947
+ function _unsupported_iterable_to_array$d(o, minLen) {
2804
2948
  if (!o) return;
2805
- if (typeof o === "string") return _array_like_to_array$b(o, minLen);
2949
+ if (typeof o === "string") return _array_like_to_array$d(o, minLen);
2806
2950
  var n = Object.prototype.toString.call(o).slice(8, -1);
2807
2951
  if (n === "Object" && o.constructor) n = o.constructor.name;
2808
2952
  if (n === "Map" || n === "Set") return Array.from(n);
2809
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$b(o, minLen);
2953
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$d(o, minLen);
2810
2954
  }
2811
2955
  /**
2812
2956
  * ESLint rule that warns when an `@dereekb/firebase` field-path-narrowing constraint factory
@@ -2861,7 +3005,7 @@ function _unsupported_iterable_to_array$b(o, minLen) {
2861
3005
  var _context_options_, _options_constraintNames, _options_additionalConstraintNames, _options_allowedImportSources;
2862
3006
  var options = (_context_options_ = context.options[0]) !== null && _context_options_ !== void 0 ? _context_options_ : {};
2863
3007
  var baseNames = (_options_constraintNames = options.constraintNames) !== null && _options_constraintNames !== void 0 ? _options_constraintNames : DEFAULT_INDEX_AFFECTING_CONSTRAINT_NAMES;
2864
- var constraintNames = new Set(_to_consumable_array$7(baseNames).concat(_to_consumable_array$7((_options_additionalConstraintNames = options.additionalConstraintNames) !== null && _options_additionalConstraintNames !== void 0 ? _options_additionalConstraintNames : [])));
3008
+ var constraintNames = new Set(_to_consumable_array$8(baseNames).concat(_to_consumable_array$8((_options_additionalConstraintNames = options.additionalConstraintNames) !== null && _options_additionalConstraintNames !== void 0 ? _options_additionalConstraintNames : [])));
2865
3009
  var allowedSources = new Set((_options_allowedImportSources = options.allowedImportSources) !== null && _options_allowedImportSources !== void 0 ? _options_allowedImportSources : [
2866
3010
  FIREBASE_MODULE
2867
3011
  ]);
@@ -2907,15 +3051,15 @@ function _unsupported_iterable_to_array$b(o, minLen) {
2907
3051
  }
2908
3052
  };
2909
3053
 
2910
- function _array_like_to_array$a(arr, len) {
3054
+ function _array_like_to_array$c(arr, len) {
2911
3055
  if (len == null || len > arr.length) len = arr.length;
2912
3056
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2913
3057
  return arr2;
2914
3058
  }
2915
- function _array_with_holes$7(arr) {
3059
+ function _array_with_holes$8(arr) {
2916
3060
  if (Array.isArray(arr)) return arr;
2917
3061
  }
2918
- function _iterable_to_array_limit$7(arr, i) {
3062
+ function _iterable_to_array_limit$8(arr, i) {
2919
3063
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
2920
3064
  if (_i == null) return;
2921
3065
  var _arr = [];
@@ -2939,19 +3083,19 @@ function _iterable_to_array_limit$7(arr, i) {
2939
3083
  }
2940
3084
  return _arr;
2941
3085
  }
2942
- function _non_iterable_rest$7() {
3086
+ function _non_iterable_rest$8() {
2943
3087
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2944
3088
  }
2945
- function _sliced_to_array$7(arr, i) {
2946
- return _array_with_holes$7(arr) || _iterable_to_array_limit$7(arr, i) || _unsupported_iterable_to_array$a(arr, i) || _non_iterable_rest$7();
3089
+ function _sliced_to_array$8(arr, i) {
3090
+ return _array_with_holes$8(arr) || _iterable_to_array_limit$8(arr, i) || _unsupported_iterable_to_array$c(arr, i) || _non_iterable_rest$8();
2947
3091
  }
2948
- function _unsupported_iterable_to_array$a(o, minLen) {
3092
+ function _unsupported_iterable_to_array$c(o, minLen) {
2949
3093
  if (!o) return;
2950
- if (typeof o === "string") return _array_like_to_array$a(o, minLen);
3094
+ if (typeof o === "string") return _array_like_to_array$c(o, minLen);
2951
3095
  var n = Object.prototype.toString.call(o).slice(8, -1);
2952
3096
  if (n === "Object" && o.constructor) n = o.constructor.name;
2953
3097
  if (n === "Map" || n === "Set") return Array.from(n);
2954
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$a(o, minLen);
3098
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$c(o, minLen);
2955
3099
  }
2956
3100
  /**
2957
3101
  * Type-reference name that triggers this rule. Variables whose declared type is
@@ -3623,7 +3767,7 @@ function validateModelEntry(input) {
3623
3767
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
3624
3768
  try {
3625
3769
  for(var _iterator1 = expected.models[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
3626
- var _step_value = _sliced_to_array$7(_step1.value, 2), expectedKey = _step_value[0], expectedModel1 = _step_value[1];
3770
+ var _step_value = _sliced_to_array$8(_step1.value, 2), expectedKey = _step_value[0], expectedModel1 = _step_value[1];
3627
3771
  if (!expectedModel1.disabled && !seenKeys.has(expectedKey)) {
3628
3772
  context.report({
3629
3773
  node: initializer,
@@ -4519,12 +4663,12 @@ var RESERVED = new Set([
4519
4663
  'prototype'
4520
4664
  ]);
4521
4665
 
4522
- function _array_like_to_array$9(arr, len) {
4666
+ function _array_like_to_array$b(arr, len) {
4523
4667
  if (len == null || len > arr.length) len = arr.length;
4524
4668
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4525
4669
  return arr2;
4526
4670
  }
4527
- function _array_with_holes$6(arr) {
4671
+ function _array_with_holes$7(arr) {
4528
4672
  if (Array.isArray(arr)) return arr;
4529
4673
  }
4530
4674
  function _check_private_redeclaration$3(obj, privateCollection) {
@@ -4594,7 +4738,7 @@ function _instanceof$7(left, right) {
4594
4738
  return left instanceof right;
4595
4739
  }
4596
4740
  }
4597
- function _iterable_to_array_limit$6(arr, i) {
4741
+ function _iterable_to_array_limit$7(arr, i) {
4598
4742
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
4599
4743
  if (_i == null) return;
4600
4744
  var _arr = [];
@@ -4618,23 +4762,23 @@ function _iterable_to_array_limit$6(arr, i) {
4618
4762
  }
4619
4763
  return _arr;
4620
4764
  }
4621
- function _non_iterable_rest$6() {
4765
+ function _non_iterable_rest$7() {
4622
4766
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
4623
4767
  }
4624
- function _sliced_to_array$6(arr, i) {
4625
- return _array_with_holes$6(arr) || _iterable_to_array_limit$6(arr, i) || _unsupported_iterable_to_array$9(arr, i) || _non_iterable_rest$6();
4768
+ function _sliced_to_array$7(arr, i) {
4769
+ return _array_with_holes$7(arr) || _iterable_to_array_limit$7(arr, i) || _unsupported_iterable_to_array$b(arr, i) || _non_iterable_rest$7();
4626
4770
  }
4627
4771
  function _type_of$6(obj) {
4628
4772
  "@swc/helpers - typeof";
4629
4773
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
4630
4774
  }
4631
- function _unsupported_iterable_to_array$9(o, minLen) {
4775
+ function _unsupported_iterable_to_array$b(o, minLen) {
4632
4776
  if (!o) return;
4633
- if (typeof o === "string") return _array_like_to_array$9(o, minLen);
4777
+ if (typeof o === "string") return _array_like_to_array$b(o, minLen);
4634
4778
  var n = Object.prototype.toString.call(o).slice(8, -1);
4635
4779
  if (n === "Object" && o.constructor) n = o.constructor.name;
4636
4780
  if (n === "Map" || n === "Set") return Array.from(n);
4637
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$9(o, minLen);
4781
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$b(o, minLen);
4638
4782
  }
4639
4783
  var _value = /*#__PURE__*/ new WeakMap();
4640
4784
  var _Symbol_for = Symbol.for('nodejs.util.inspect.custom');
@@ -5236,7 +5380,7 @@ function registerFunctions(registry) {
5236
5380
  if (match.index !== 0) throw evaluationError('invalid_duration', "Invalid duration string: ".concat(string));
5237
5381
  string = string.slice(match[0].length);
5238
5382
  var unitNanos = UNIT_NANOSECONDS[match[2]];
5239
- var _match__split = _sliced_to_array$6(match[1].split('.'), 2), tmp = _match__split[0], intPart = tmp === void 0 ? '0' : tmp, tmp1 = _match__split[1], fracPart = tmp1 === void 0 ? '' : tmp1;
5383
+ var _match__split = _sliced_to_array$7(match[1].split('.'), 2), tmp = _match__split[0], intPart = tmp === void 0 ? '0' : tmp, tmp1 = _match__split[1], fracPart = tmp1 === void 0 ? '' : tmp1;
5240
5384
  var intVal = BigInt(intPart) * unitNanos;
5241
5385
  var fracNanos = fracPart ? BigInt(fracPart.slice(0, 13).padEnd(13, '0')) * unitNanos / 10000000000000n : 0n;
5242
5386
  nanoseconds += intVal + fracNanos;
@@ -5289,16 +5433,16 @@ function stringSize(str) {
5289
5433
  return count;
5290
5434
  }
5291
5435
 
5292
- function _array_like_to_array$8(arr, len) {
5436
+ function _array_like_to_array$a(arr, len) {
5293
5437
  if (len == null || len > arr.length) len = arr.length;
5294
5438
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
5295
5439
  return arr2;
5296
5440
  }
5297
- function _array_with_holes$5(arr) {
5441
+ function _array_with_holes$6(arr) {
5298
5442
  if (Array.isArray(arr)) return arr;
5299
5443
  }
5300
- function _array_without_holes$6(arr) {
5301
- if (Array.isArray(arr)) return _array_like_to_array$8(arr);
5444
+ function _array_without_holes$7(arr) {
5445
+ if (Array.isArray(arr)) return _array_like_to_array$a(arr);
5302
5446
  }
5303
5447
  function _assert_this_initialized$2(self) {
5304
5448
  if (self === void 0) {
@@ -5454,10 +5598,10 @@ function _instanceof$6(left, right) {
5454
5598
  function _is_native_function(fn) {
5455
5599
  return Function.toString.call(fn).indexOf("[native code]") !== -1;
5456
5600
  }
5457
- function _iterable_to_array$6(iter) {
5601
+ function _iterable_to_array$7(iter) {
5458
5602
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
5459
5603
  }
5460
- function _iterable_to_array_limit$5(arr, i) {
5604
+ function _iterable_to_array_limit$6(arr, i) {
5461
5605
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
5462
5606
  if (_i == null) return;
5463
5607
  var _arr = [];
@@ -5481,10 +5625,10 @@ function _iterable_to_array_limit$5(arr, i) {
5481
5625
  }
5482
5626
  return _arr;
5483
5627
  }
5484
- function _non_iterable_rest$5() {
5628
+ function _non_iterable_rest$6() {
5485
5629
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
5486
5630
  }
5487
- function _non_iterable_spread$6() {
5631
+ function _non_iterable_spread$7() {
5488
5632
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
5489
5633
  }
5490
5634
  function _possible_constructor_return$2(self, call) {
@@ -5500,8 +5644,8 @@ function _set_prototype_of$2(o, p) {
5500
5644
  };
5501
5645
  return _set_prototype_of$2(o, p);
5502
5646
  }
5503
- function _sliced_to_array$5(arr, i) {
5504
- return _array_with_holes$5(arr) || _iterable_to_array_limit$5(arr, i) || _unsupported_iterable_to_array$8(arr, i) || _non_iterable_rest$5();
5647
+ function _sliced_to_array$6(arr, i) {
5648
+ return _array_with_holes$6(arr) || _iterable_to_array_limit$6(arr, i) || _unsupported_iterable_to_array$a(arr, i) || _non_iterable_rest$6();
5505
5649
  }
5506
5650
  function _super_prop_base(object, property) {
5507
5651
  while(!Object.prototype.hasOwnProperty.call(object, property)){
@@ -5510,20 +5654,20 @@ function _super_prop_base(object, property) {
5510
5654
  }
5511
5655
  return object;
5512
5656
  }
5513
- function _to_consumable_array$6(arr) {
5514
- return _array_without_holes$6(arr) || _iterable_to_array$6(arr) || _unsupported_iterable_to_array$8(arr) || _non_iterable_spread$6();
5657
+ function _to_consumable_array$7(arr) {
5658
+ return _array_without_holes$7(arr) || _iterable_to_array$7(arr) || _unsupported_iterable_to_array$a(arr) || _non_iterable_spread$7();
5515
5659
  }
5516
5660
  function _type_of$5(obj) {
5517
5661
  "@swc/helpers - typeof";
5518
5662
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
5519
5663
  }
5520
- function _unsupported_iterable_to_array$8(o, minLen) {
5664
+ function _unsupported_iterable_to_array$a(o, minLen) {
5521
5665
  if (!o) return;
5522
- if (typeof o === "string") return _array_like_to_array$8(o, minLen);
5666
+ if (typeof o === "string") return _array_like_to_array$a(o, minLen);
5523
5667
  var n = Object.prototype.toString.call(o).slice(8, -1);
5524
5668
  if (n === "Object" && o.constructor) n = o.constructor.name;
5525
5669
  if (n === "Map" || n === "Set") return Array.from(n);
5526
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$8(o, minLen);
5670
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$a(o, minLen);
5527
5671
  }
5528
5672
  function _wrap_native_super(Class) {
5529
5673
  var _cache = typeof Map === "function" ? new Map() : undefined;
@@ -6369,7 +6513,7 @@ var objTypesDecls = [
6369
6513
  TYPES.bytes,
6370
6514
  celTypes.bytes
6371
6515
  ]
6372
- ].concat(_to_consumable_array$6(typeof Buffer !== 'undefined' ? [
6516
+ ].concat(_to_consumable_array$7(typeof Buffer !== 'undefined' ? [
6373
6517
  [
6374
6518
  Buffer,
6375
6519
  'bytes',
@@ -6377,7 +6521,7 @@ var objTypesDecls = [
6377
6521
  celTypes.bytes
6378
6522
  ]
6379
6523
  ] : [])).map(function(param) {
6380
- var _param = _sliced_to_array$5(param, 4), ctor = _param[0], name = _param[1], typeType = _param[2], type = _param[3];
6524
+ var _param = _sliced_to_array$6(param, 4), ctor = _param[0], name = _param[1], typeType = _param[2], type = _param[3];
6381
6525
  return Object.freeze({
6382
6526
  name: name,
6383
6527
  typeType: typeType,
@@ -6744,7 +6888,7 @@ var Registry = /*#__PURE__*/ function() {
6744
6888
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
6745
6889
  try {
6746
6890
  for(var _iterator = this.variables[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
6747
- var _step_value = _sliced_to_array$5(_step.value, 2), varDecl = _step_value[1];
6891
+ var _step_value = _sliced_to_array$6(_step.value, 2), varDecl = _step_value[1];
6748
6892
  if (!varDecl) continue;
6749
6893
  variables.push({
6750
6894
  name: varDecl.name,
@@ -6858,12 +7002,12 @@ var Registry = /*#__PURE__*/ function() {
6858
7002
  // Parse with optional return type: "Vector + Vector: Vector" or "Vector + Vector"
6859
7003
  var unaryParts = string.match(/^([-!])([\w.<>]+)(?::\s*([\w.<>]+))?$/);
6860
7004
  if (unaryParts) {
6861
- var _unaryParts = _sliced_to_array$5(unaryParts, 4), op = _unaryParts[1], operandType = _unaryParts[2], returnType = _unaryParts[3];
7005
+ var _unaryParts = _sliced_to_array$6(unaryParts, 4), op = _unaryParts[1], operandType = _unaryParts[2], returnType = _unaryParts[3];
6862
7006
  return this.unaryOverload(op, operandType, handler, returnType, opts === null || opts === void 0 ? void 0 : opts.async);
6863
7007
  }
6864
7008
  var parts = string.match(/^([\w.<>]+) ([-+*%/]|==|!=|<|<=|>|>=|in) ([\w.<>]+)(?::\s*([\w.<>]+))?$/);
6865
7009
  if (!parts) throw new Error("Operator overload invalid: ".concat(string));
6866
- var _parts = _sliced_to_array$5(parts, 5), leftType = _parts[1], op1 = _parts[2], rightType = _parts[3], returnType1 = _parts[4];
7010
+ var _parts = _sliced_to_array$6(parts, 5), leftType = _parts[1], op1 = _parts[2], rightType = _parts[3], returnType1 = _parts[4];
6867
7011
  return this.binaryOverload(leftType, op1, rightType, handler, returnType1);
6868
7012
  }
6869
7013
  },
@@ -7012,11 +7156,11 @@ function ensureCandiate(c, key) {
7012
7156
  }
7013
7157
  function getOperators() {
7014
7158
  if (_class_private_field_get$2(this, _operators)) return _class_private_field_get$2(this, _operators);
7015
- return _class_private_field_set$2(this, _operators, _to_consumable_array$6(_class_private_field_get$2(this, _others).operators));
7159
+ return _class_private_field_set$2(this, _operators, _to_consumable_array$7(_class_private_field_get$2(this, _others).operators));
7016
7160
  }
7017
7161
  function getFunctions() {
7018
7162
  if (_class_private_field_get$2(this, _functions)) return _class_private_field_get$2(this, _functions);
7019
- return _class_private_field_set$2(this, _functions, _to_consumable_array$6(_class_private_field_get$2(this, _others).functions));
7163
+ return _class_private_field_set$2(this, _functions, _to_consumable_array$7(_class_private_field_get$2(this, _others).functions));
7020
7164
  }
7021
7165
  function functionCandidates(key) {
7022
7166
  if (_class_private_field_get$2(this, _functionsByKey)) return _class_private_method_get$2(this, _ensureCandiate, ensureCandiate).call(this, _class_private_field_get$2(this, _functionsByKey), key);
@@ -7128,7 +7272,7 @@ function createDeclaration(creator, key) {
7128
7272
  for(var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
7129
7273
  args[_key - 2] = arguments[_key];
7130
7274
  }
7131
- return _class_private_field_get$2(this, _typeDeclarations).get(key) || _class_private_field_get$2(this, _typeDeclarations).set(key, creator.apply(void 0, _to_consumable_array$6(args))).get(key);
7275
+ return _class_private_field_get$2(this, _typeDeclarations).get(key) || _class_private_field_get$2(this, _typeDeclarations).set(key, creator.apply(void 0, _to_consumable_array$7(args))).get(key);
7132
7276
  }
7133
7277
  function toCelFieldType(field) {
7134
7278
  if (typeof field === 'string') return {
@@ -7581,16 +7725,16 @@ var OverlayContext = /*#__PURE__*/ function() {
7581
7725
  }
7582
7726
  }
7583
7727
 
7584
- function _array_like_to_array$7(arr, len) {
7728
+ function _array_like_to_array$9(arr, len) {
7585
7729
  if (len == null || len > arr.length) len = arr.length;
7586
7730
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
7587
7731
  return arr2;
7588
7732
  }
7589
- function _array_with_holes$4(arr) {
7733
+ function _array_with_holes$5(arr) {
7590
7734
  if (Array.isArray(arr)) return arr;
7591
7735
  }
7592
- function _array_without_holes$5(arr) {
7593
- if (Array.isArray(arr)) return _array_like_to_array$7(arr);
7736
+ function _array_without_holes$6(arr) {
7737
+ if (Array.isArray(arr)) return _array_like_to_array$9(arr);
7594
7738
  }
7595
7739
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
7596
7740
  try {
@@ -7660,10 +7804,10 @@ function _instanceof$5(left, right) {
7660
7804
  return left instanceof right;
7661
7805
  }
7662
7806
  }
7663
- function _iterable_to_array$5(iter) {
7807
+ function _iterable_to_array$6(iter) {
7664
7808
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
7665
7809
  }
7666
- function _iterable_to_array_limit$4(arr, i) {
7810
+ function _iterable_to_array_limit$5(arr, i) {
7667
7811
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
7668
7812
  if (_i == null) return;
7669
7813
  var _arr = [];
@@ -7687,29 +7831,29 @@ function _iterable_to_array_limit$4(arr, i) {
7687
7831
  }
7688
7832
  return _arr;
7689
7833
  }
7690
- function _non_iterable_rest$4() {
7834
+ function _non_iterable_rest$5() {
7691
7835
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
7692
7836
  }
7693
- function _non_iterable_spread$5() {
7837
+ function _non_iterable_spread$6() {
7694
7838
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
7695
7839
  }
7696
- function _sliced_to_array$4(arr, i) {
7697
- return _array_with_holes$4(arr) || _iterable_to_array_limit$4(arr, i) || _unsupported_iterable_to_array$7(arr, i) || _non_iterable_rest$4();
7840
+ function _sliced_to_array$5(arr, i) {
7841
+ return _array_with_holes$5(arr) || _iterable_to_array_limit$5(arr, i) || _unsupported_iterable_to_array$9(arr, i) || _non_iterable_rest$5();
7698
7842
  }
7699
- function _to_consumable_array$5(arr) {
7700
- return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$7(arr) || _non_iterable_spread$5();
7843
+ function _to_consumable_array$6(arr) {
7844
+ return _array_without_holes$6(arr) || _iterable_to_array$6(arr) || _unsupported_iterable_to_array$9(arr) || _non_iterable_spread$6();
7701
7845
  }
7702
7846
  function _type_of$4(obj) {
7703
7847
  "@swc/helpers - typeof";
7704
7848
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
7705
7849
  }
7706
- function _unsupported_iterable_to_array$7(o, minLen) {
7850
+ function _unsupported_iterable_to_array$9(o, minLen) {
7707
7851
  if (!o) return;
7708
- if (typeof o === "string") return _array_like_to_array$7(o, minLen);
7852
+ if (typeof o === "string") return _array_like_to_array$9(o, minLen);
7709
7853
  var n = Object.prototype.toString.call(o).slice(8, -1);
7710
7854
  if (n === "Object" && o.constructor) n = o.constructor.name;
7711
7855
  if (n === "Map" || n === "Set") return Array.from(n);
7712
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
7856
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$9(o, minLen);
7713
7857
  }
7714
7858
  function _ts_generator(thisArg, body) {
7715
7859
  var f, y, t, _ = {
@@ -8064,7 +8208,7 @@ function callFn(args, ast, ev) {
8064
8208
  }).join(', '), ")'"), ast);
8065
8209
  }
8066
8210
  function callRecFn(args, ev, ast) {
8067
- var _ast_args = _sliced_to_array$4(ast.args, 3), receiverAst = _ast_args[1], argAst = _ast_args[2];
8211
+ var _ast_args = _sliced_to_array$5(ast.args, 3), receiverAst = _ast_args[1], argAst = _ast_args[2];
8068
8212
  var types = ast.argTypes;
8069
8213
  for(var i = 0; i < types.length; i++)types[i] = ev.debugRuntimeType(args[i + 1], argAst[i].checkedType);
8070
8214
  var receiverType = ev.debugRuntimeType(args[0], receiverAst.checkedType);
@@ -8085,7 +8229,7 @@ function resolveAstArray(ev, astArray, ctx) {
8085
8229
  function safeFromEntries(entries) {
8086
8230
  var obj = {};
8087
8231
  for(var i = 0; i < entries.length; i++){
8088
- var _entries_i = _sliced_to_array$4(entries[i], 2), k = _entries_i[0], v = _entries_i[1];
8232
+ var _entries_i = _sliced_to_array$5(entries[i], 2), k = _entries_i[0], v = _entries_i[1];
8089
8233
  if (k === '__proto__' || k === 'constructor' || k === 'prototype') continue;
8090
8234
  obj[k] = v;
8091
8235
  }
@@ -8099,8 +8243,8 @@ function comprehensionElementType(chk, iterable, ctx) {
8099
8243
  throw chk.createError('invalid_comprehension_range', "Expression of type '".concat(chk.formatType(iterType), "' cannot be range of a comprehension (must be list, map, or dynamic)."), iterable);
8100
8244
  }
8101
8245
  function toIterable(ev, args, coll) {
8102
- if (_instanceof$5(coll, Set)) return _to_consumable_array$5(coll);
8103
- if (_instanceof$5(coll, Map)) return _to_consumable_array$5(coll.keys());
8246
+ if (_instanceof$5(coll, Set)) return _to_consumable_array$6(coll);
8247
+ if (_instanceof$5(coll, Map)) return _to_consumable_array$6(coll.keys());
8104
8248
  if (coll && (typeof coll === "undefined" ? "undefined" : _type_of$4(coll)) === 'object') return objKeys(coll);
8105
8249
  throw ev.createError('invalid_comprehension_range', "Expression of type '".concat(ev.debugType(coll), "' cannot be range of a comprehension (must be list, map, or dynamic)."), args.iterable);
8106
8250
  }
@@ -8340,7 +8484,7 @@ var OPERATORS = {
8340
8484
  call: {
8341
8485
  check: function check(chk, ast, ctx) {
8342
8486
  var _decl_handler, ___handle;
8343
- var _ast_args = _sliced_to_array$4(ast.args, 2), functionName = _ast_args[0], args = _ast_args[1];
8487
+ var _ast_args = _sliced_to_array$5(ast.args, 2), functionName = _ast_args[0], args = _ast_args[1];
8344
8488
  var candidates = ast.candidates = chk.registry.functionCandidates(false, functionName, args.length);
8345
8489
  var argTypes = ast.argTypes = args.map(function(a) {
8346
8490
  return chk.check(a, ctx);
@@ -8363,7 +8507,7 @@ var OPERATORS = {
8363
8507
  },
8364
8508
  rcall: {
8365
8509
  check: function check(chk, ast, ctx) {
8366
- var _ast_args = _sliced_to_array$4(ast.args, 3), methodName = _ast_args[0], receiver = _ast_args[1], args = _ast_args[2];
8510
+ var _ast_args = _sliced_to_array$5(ast.args, 3), methodName = _ast_args[0], receiver = _ast_args[1], args = _ast_args[2];
8367
8511
  var receiverType = chk.check(receiver, ctx);
8368
8512
  var candidates = ast.candidates = chk.registry.functionCandidates(true, methodName, args.length);
8369
8513
  var argTypes = ast.argTypes = args.map(function(a) {
@@ -8371,7 +8515,7 @@ var OPERATORS = {
8371
8515
  });
8372
8516
  ast.receiverWithArgs = [
8373
8517
  receiver
8374
- ].concat(_to_consumable_array$5(args));
8518
+ ].concat(_to_consumable_array$6(args));
8375
8519
  ast.handle = maybeAsync(ast.receiverWithArgs, false, callRecFn);
8376
8520
  if (receiverType.kind === 'dyn' && candidates.returnType) return candidates.returnType;
8377
8521
  var decl = candidates.findFunction(argTypes, receiverType);
@@ -8624,12 +8768,12 @@ try {
8624
8768
  }
8625
8769
  }
8626
8770
 
8627
- function _array_like_to_array$6(arr, len) {
8771
+ function _array_like_to_array$8(arr, len) {
8628
8772
  if (len == null || len > arr.length) len = arr.length;
8629
8773
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
8630
8774
  return arr2;
8631
8775
  }
8632
- function _array_with_holes$3(arr) {
8776
+ function _array_with_holes$4(arr) {
8633
8777
  if (Array.isArray(arr)) return arr;
8634
8778
  }
8635
8779
  function _class_call_check$3(instance, Constructor) {
@@ -8645,7 +8789,7 @@ function _instanceof$4(left, right) {
8645
8789
  return left instanceof right;
8646
8790
  }
8647
8791
  }
8648
- function _iterable_to_array_limit$3(arr, i) {
8792
+ function _iterable_to_array_limit$4(arr, i) {
8649
8793
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
8650
8794
  if (_i == null) return;
8651
8795
  var _arr = [];
@@ -8669,19 +8813,19 @@ function _iterable_to_array_limit$3(arr, i) {
8669
8813
  }
8670
8814
  return _arr;
8671
8815
  }
8672
- function _non_iterable_rest$3() {
8816
+ function _non_iterable_rest$4() {
8673
8817
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
8674
8818
  }
8675
- function _sliced_to_array$3(arr, i) {
8676
- return _array_with_holes$3(arr) || _iterable_to_array_limit$3(arr, i) || _unsupported_iterable_to_array$6(arr, i) || _non_iterable_rest$3();
8819
+ function _sliced_to_array$4(arr, i) {
8820
+ return _array_with_holes$4(arr) || _iterable_to_array_limit$4(arr, i) || _unsupported_iterable_to_array$8(arr, i) || _non_iterable_rest$4();
8677
8821
  }
8678
- function _unsupported_iterable_to_array$6(o, minLen) {
8822
+ function _unsupported_iterable_to_array$8(o, minLen) {
8679
8823
  if (!o) return;
8680
- if (typeof o === "string") return _array_like_to_array$6(o, minLen);
8824
+ if (typeof o === "string") return _array_like_to_array$8(o, minLen);
8681
8825
  var n = Object.prototype.toString.call(o).slice(8, -1);
8682
8826
  if (n === "Object" && o.constructor) n = o.constructor.name;
8683
8827
  if (n === "Map" || n === "Set") return Array.from(n);
8684
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
8828
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$8(o, minLen);
8685
8829
  }
8686
8830
  var identity = function identity(x) {
8687
8831
  return x;
@@ -8696,7 +8840,7 @@ function createMapExpander(hasFilter) {
8696
8840
  var label = "".concat(functionDesc, " filter predicate must return bool");
8697
8841
  return function(param) {
8698
8842
  var args = param.args, receiver = param.receiver, callAst = param.ast;
8699
- var _ref = _sliced_to_array$3(hasFilter ? args : [
8843
+ var _ref = _sliced_to_array$4(hasFilter ? args : [
8700
8844
  args[0],
8701
8845
  null,
8702
8846
  args[1]
@@ -8921,16 +9065,16 @@ function registerMacros(registry) {
8921
9065
  });
8922
9066
  }
8923
9067
 
8924
- function _array_like_to_array$5(arr, len) {
9068
+ function _array_like_to_array$7(arr, len) {
8925
9069
  if (len == null || len > arr.length) len = arr.length;
8926
9070
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
8927
9071
  return arr2;
8928
9072
  }
8929
- function _array_with_holes$2(arr) {
9073
+ function _array_with_holes$3(arr) {
8930
9074
  if (Array.isArray(arr)) return arr;
8931
9075
  }
8932
- function _array_without_holes$4(arr) {
8933
- if (Array.isArray(arr)) return _array_like_to_array$5(arr);
9076
+ function _array_without_holes$5(arr) {
9077
+ if (Array.isArray(arr)) return _array_like_to_array$7(arr);
8934
9078
  }
8935
9079
  function _instanceof$3(left, right) {
8936
9080
  "@swc/helpers - instanceof";
@@ -8940,10 +9084,10 @@ function _instanceof$3(left, right) {
8940
9084
  return left instanceof right;
8941
9085
  }
8942
9086
  }
8943
- function _iterable_to_array$4(iter) {
9087
+ function _iterable_to_array$5(iter) {
8944
9088
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
8945
9089
  }
8946
- function _iterable_to_array_limit$2(arr, i) {
9090
+ function _iterable_to_array_limit$3(arr, i) {
8947
9091
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
8948
9092
  if (_i == null) return;
8949
9093
  var _arr = [];
@@ -8967,29 +9111,29 @@ function _iterable_to_array_limit$2(arr, i) {
8967
9111
  }
8968
9112
  return _arr;
8969
9113
  }
8970
- function _non_iterable_rest$2() {
9114
+ function _non_iterable_rest$3() {
8971
9115
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
8972
9116
  }
8973
- function _non_iterable_spread$4() {
9117
+ function _non_iterable_spread$5() {
8974
9118
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
8975
9119
  }
8976
- function _sliced_to_array$2(arr, i) {
8977
- return _array_with_holes$2(arr) || _iterable_to_array_limit$2(arr, i) || _unsupported_iterable_to_array$5(arr, i) || _non_iterable_rest$2();
9120
+ function _sliced_to_array$3(arr, i) {
9121
+ return _array_with_holes$3(arr) || _iterable_to_array_limit$3(arr, i) || _unsupported_iterable_to_array$7(arr, i) || _non_iterable_rest$3();
8978
9122
  }
8979
- function _to_consumable_array$4(arr) {
8980
- return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$5(arr) || _non_iterable_spread$4();
9123
+ function _to_consumable_array$5(arr) {
9124
+ return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$7(arr) || _non_iterable_spread$5();
8981
9125
  }
8982
9126
  function _type_of$3(obj) {
8983
9127
  "@swc/helpers - typeof";
8984
9128
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
8985
9129
  }
8986
- function _unsupported_iterable_to_array$5(o, minLen) {
9130
+ function _unsupported_iterable_to_array$7(o, minLen) {
8987
9131
  if (!o) return;
8988
- if (typeof o === "string") return _array_like_to_array$5(o, minLen);
9132
+ if (typeof o === "string") return _array_like_to_array$7(o, minLen);
8989
9133
  var n = Object.prototype.toString.call(o).slice(8, -1);
8990
9134
  if (n === "Object" && o.constructor) n = o.constructor.name;
8991
9135
  if (n === "Map" || n === "Set") return Array.from(n);
8992
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$5(o, minLen);
9136
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
8993
9137
  }
8994
9138
  function registerOverloads(registry) {
8995
9139
  var unaryOverload = function unaryOverload(op, t, h, ret) {
@@ -9056,7 +9200,7 @@ function registerOverloads(registry) {
9056
9200
  return a + b;
9057
9201
  });
9058
9202
  binaryOverload('list<V>', '+', 'list<V>', function(a, b) {
9059
- return _to_consumable_array$4(a).concat(_to_consumable_array$4(b));
9203
+ return _to_consumable_array$5(a).concat(_to_consumable_array$5(b));
9060
9204
  });
9061
9205
  binaryOverload('bytes', '+', 'bytes', function(a, b) {
9062
9206
  if (!a.length) return b;
@@ -9193,7 +9337,7 @@ function registerOverloads(registry) {
9193
9337
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
9194
9338
  try {
9195
9339
  for(var _iterator = a[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
9196
- var _step_value = _sliced_to_array$2(_step.value, 2), key = _step_value[0], value = _step_value[1];
9340
+ var _step_value = _sliced_to_array$3(_step.value, 2), key = _step_value[0], value = _step_value[1];
9197
9341
  if (!(b.has(key) && isEqual(value, b.get(key), ast, ev))) return false;
9198
9342
  }
9199
9343
  } catch (err) {
@@ -9220,7 +9364,7 @@ function registerOverloads(registry) {
9220
9364
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
9221
9365
  try {
9222
9366
  for(var _iterator1 = map[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
9223
- var _step_value1 = _sliced_to_array$2(_step1.value, 2), key1 = _step_value1[0], value1 = _step_value1[1];
9367
+ var _step_value1 = _sliced_to_array$3(_step1.value, 2), key1 = _step_value1[0], value1 = _step_value1[1];
9224
9368
  if (!(key1 in obj && isEqual(value1, obj[key1], ast, ev))) return false;
9225
9369
  }
9226
9370
  } catch (err) {
@@ -9325,7 +9469,7 @@ function registerOverloads(registry) {
9325
9469
  'double'
9326
9470
  ]
9327
9471
  ]; _i1 < _iter1.length; _i1++){
9328
- var _iter__i = _sliced_to_array$2(_iter1[_i1], 2), left = _iter__i[0], right = _iter__i[1];
9472
+ var _iter__i = _sliced_to_array$3(_iter1[_i1], 2), left = _iter__i[0], right = _iter__i[1];
9329
9473
  binaryOverload(left, '<', right, function(a, b) {
9330
9474
  return a < b;
9331
9475
  });
@@ -9529,13 +9673,13 @@ var toDynTypeBinding = new Map().set('A', 'dyn').set('T', 'dyn').set('K', 'dyn')
9529
9673
  return TypeChecker;
9530
9674
  }(Base);
9531
9675
 
9532
- function _array_like_to_array$4(arr, len) {
9676
+ function _array_like_to_array$6(arr, len) {
9533
9677
  if (len == null || len > arr.length) len = arr.length;
9534
9678
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
9535
9679
  return arr2;
9536
9680
  }
9537
- function _array_without_holes$3(arr) {
9538
- if (Array.isArray(arr)) return _array_like_to_array$4(arr);
9681
+ function _array_without_holes$4(arr) {
9682
+ if (Array.isArray(arr)) return _array_like_to_array$6(arr);
9539
9683
  }
9540
9684
  function _check_private_redeclaration$1(obj, privateCollection) {
9541
9685
  if (privateCollection.has(obj)) {
@@ -9626,22 +9770,22 @@ function _instanceof$2(left, right) {
9626
9770
  return left instanceof right;
9627
9771
  }
9628
9772
  }
9629
- function _iterable_to_array$3(iter) {
9773
+ function _iterable_to_array$4(iter) {
9630
9774
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
9631
9775
  }
9632
- function _non_iterable_spread$3() {
9776
+ function _non_iterable_spread$4() {
9633
9777
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
9634
9778
  }
9635
- function _to_consumable_array$3(arr) {
9636
- return _array_without_holes$3(arr) || _iterable_to_array$3(arr) || _unsupported_iterable_to_array$4(arr) || _non_iterable_spread$3();
9779
+ function _to_consumable_array$4(arr) {
9780
+ return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$6(arr) || _non_iterable_spread$4();
9637
9781
  }
9638
- function _unsupported_iterable_to_array$4(o, minLen) {
9782
+ function _unsupported_iterable_to_array$6(o, minLen) {
9639
9783
  if (!o) return;
9640
- if (typeof o === "string") return _array_like_to_array$4(o, minLen);
9784
+ if (typeof o === "string") return _array_like_to_array$6(o, minLen);
9641
9785
  var n = Object.prototype.toString.call(o).slice(8, -1);
9642
9786
  if (n === "Object" && o.constructor) n = o.constructor.name;
9643
9787
  if (n === "Map" || n === "Set") return Array.from(n);
9644
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$4(o, minLen);
9788
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
9645
9789
  }
9646
9790
  var TOKEN = {
9647
9791
  EOF: 0,
@@ -9838,7 +9982,7 @@ var ASTNode = /*#__PURE__*/ function() {
9838
9982
  ];
9839
9983
  return [
9840
9984
  this.op
9841
- ].concat(_to_consumable_array$3(args.map(function(a) {
9985
+ ].concat(_to_consumable_array$4(args.map(function(a) {
9842
9986
  return _instanceof$2(a, ASTNode) ? a.toOldStructure() : a;
9843
9987
  })));
9844
9988
  }
@@ -11183,16 +11327,16 @@ function parse(expression) {
11183
11327
  return globalEnvironment.parse(expression);
11184
11328
  }
11185
11329
 
11186
- function _array_like_to_array$3(arr, len) {
11330
+ function _array_like_to_array$5(arr, len) {
11187
11331
  if (len == null || len > arr.length) len = arr.length;
11188
11332
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
11189
11333
  return arr2;
11190
11334
  }
11191
- function _array_with_holes$1(arr) {
11335
+ function _array_with_holes$2(arr) {
11192
11336
  if (Array.isArray(arr)) return arr;
11193
11337
  }
11194
- function _array_without_holes$2(arr) {
11195
- if (Array.isArray(arr)) return _array_like_to_array$3(arr);
11338
+ function _array_without_holes$3(arr) {
11339
+ if (Array.isArray(arr)) return _array_like_to_array$5(arr);
11196
11340
  }
11197
11341
  function _instanceof(left, right) {
11198
11342
  "@swc/helpers - instanceof";
@@ -11202,10 +11346,10 @@ function _instanceof(left, right) {
11202
11346
  return left instanceof right;
11203
11347
  }
11204
11348
  }
11205
- function _iterable_to_array$2(iter) {
11349
+ function _iterable_to_array$3(iter) {
11206
11350
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
11207
11351
  }
11208
- function _iterable_to_array_limit$1(arr, i) {
11352
+ function _iterable_to_array_limit$2(arr, i) {
11209
11353
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
11210
11354
  if (_i == null) return;
11211
11355
  var _arr = [];
@@ -11229,29 +11373,29 @@ function _iterable_to_array_limit$1(arr, i) {
11229
11373
  }
11230
11374
  return _arr;
11231
11375
  }
11232
- function _non_iterable_rest$1() {
11376
+ function _non_iterable_rest$2() {
11233
11377
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
11234
11378
  }
11235
- function _non_iterable_spread$2() {
11379
+ function _non_iterable_spread$3() {
11236
11380
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
11237
11381
  }
11238
- function _sliced_to_array$1(arr, i) {
11239
- return _array_with_holes$1(arr) || _iterable_to_array_limit$1(arr, i) || _unsupported_iterable_to_array$3(arr, i) || _non_iterable_rest$1();
11382
+ function _sliced_to_array$2(arr, i) {
11383
+ return _array_with_holes$2(arr) || _iterable_to_array_limit$2(arr, i) || _unsupported_iterable_to_array$5(arr, i) || _non_iterable_rest$2();
11240
11384
  }
11241
- function _to_consumable_array$2(arr) {
11242
- return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$3(arr) || _non_iterable_spread$2();
11385
+ function _to_consumable_array$3(arr) {
11386
+ return _array_without_holes$3(arr) || _iterable_to_array$3(arr) || _unsupported_iterable_to_array$5(arr) || _non_iterable_spread$3();
11243
11387
  }
11244
11388
  function _type_of(obj) {
11245
11389
  "@swc/helpers - typeof";
11246
11390
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
11247
11391
  }
11248
- function _unsupported_iterable_to_array$3(o, minLen) {
11392
+ function _unsupported_iterable_to_array$5(o, minLen) {
11249
11393
  if (!o) return;
11250
- if (typeof o === "string") return _array_like_to_array$3(o, minLen);
11394
+ if (typeof o === "string") return _array_like_to_array$5(o, minLen);
11251
11395
  var n = Object.prototype.toString.call(o).slice(8, -1);
11252
11396
  if (n === "Object" && o.constructor) n = o.constructor.name;
11253
11397
  if (n === "Map" || n === "Set") return Array.from(n);
11254
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
11398
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$5(o, minLen);
11255
11399
  }
11256
11400
  var REGEX_METACHARS_RE = /[.*+?^${}()|[\]\\]/;
11257
11401
  var HELPER_INLINE_MAX_DEPTH = 8;
@@ -11402,7 +11546,7 @@ function collectUniqueBranches(ast, helpers) {
11402
11546
  if (op === 'value' || op === 'id') {
11403
11547
  result = node;
11404
11548
  } else if (op === '.' || op === '.?') {
11405
- var _args = _sliced_to_array$1(args, 2), receiver = _args[0], prop = _args[1];
11549
+ var _args = _sliced_to_array$2(args, 2), receiver = _args[0], prop = _args[1];
11406
11550
  result = {
11407
11551
  op: op,
11408
11552
  args: [
@@ -11411,7 +11555,7 @@ function collectUniqueBranches(ast, helpers) {
11411
11555
  ]
11412
11556
  };
11413
11557
  } else if (op === 'call') {
11414
- var _args1 = _sliced_to_array$1(args, 2), name = _args1[0], callArgs = _args1[1];
11558
+ var _args1 = _sliced_to_array$2(args, 2), name = _args1[0], callArgs = _args1[1];
11415
11559
  result = {
11416
11560
  op: op,
11417
11561
  args: [
@@ -11420,7 +11564,7 @@ function collectUniqueBranches(ast, helpers) {
11420
11564
  ]
11421
11565
  };
11422
11566
  } else if (op === 'rcall') {
11423
- var _args2 = _sliced_to_array$1(args, 3), name1 = _args2[0], receiver1 = _args2[1], callArgs1 = _args2[2];
11567
+ var _args2 = _sliced_to_array$2(args, 3), name1 = _args2[0], receiver1 = _args2[1], callArgs1 = _args2[2];
11424
11568
  result = {
11425
11569
  op: op,
11426
11570
  args: [
@@ -11435,7 +11579,7 @@ function collectUniqueBranches(ast, helpers) {
11435
11579
  args: fn(args)
11436
11580
  };
11437
11581
  } else if (op === '?:') {
11438
- var _args3 = _sliced_to_array$1(args, 3), c = _args3[0], t = _args3[1], e = _args3[2];
11582
+ var _args3 = _sliced_to_array$2(args, 3), c = _args3[0], t = _args3[1], e = _args3[2];
11439
11583
  result = {
11440
11584
  op: op,
11441
11585
  args: [
@@ -11455,7 +11599,7 @@ function collectUniqueBranches(ast, helpers) {
11455
11599
  result = {
11456
11600
  op: op,
11457
11601
  args: entries.map(function(param) {
11458
- var _param = _sliced_to_array$1(param, 2), k = _param[0], v = _param[1];
11602
+ var _param = _sliced_to_array$2(param, 2), k = _param[0], v = _param[1];
11459
11603
  return [
11460
11604
  fn(k),
11461
11605
  fn(v)
@@ -11494,10 +11638,10 @@ function collectUniqueBranches(ast, helpers) {
11494
11638
  */ function toDnf(node) {
11495
11639
  var result;
11496
11640
  if (node.op === '||') {
11497
- var _node_args = _sliced_to_array$1(node.args, 2), l = _node_args[0], r = _node_args[1];
11498
- result = _to_consumable_array$2(toDnf(l)).concat(_to_consumable_array$2(toDnf(r)));
11641
+ var _node_args = _sliced_to_array$2(node.args, 2), l = _node_args[0], r = _node_args[1];
11642
+ result = _to_consumable_array$3(toDnf(l)).concat(_to_consumable_array$3(toDnf(r)));
11499
11643
  } else if (node.op === '&&') {
11500
- var _node_args1 = _sliced_to_array$1(node.args, 2), l1 = _node_args1[0], r1 = _node_args1[1];
11644
+ var _node_args1 = _sliced_to_array$2(node.args, 2), l1 = _node_args1[0], r1 = _node_args1[1];
11501
11645
  var left = toDnf(l1);
11502
11646
  var right = toDnf(r1);
11503
11647
  result = [];
@@ -11509,7 +11653,7 @@ function collectUniqueBranches(ast, helpers) {
11509
11653
  try {
11510
11654
  for(var _iterator1 = right[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
11511
11655
  var rd = _step1.value;
11512
- result.push(_to_consumable_array$2(ld).concat(_to_consumable_array$2(rd)));
11656
+ result.push(_to_consumable_array$3(ld).concat(_to_consumable_array$3(rd)));
11513
11657
  }
11514
11658
  } catch (err) {
11515
11659
  _didIteratorError1 = true;
@@ -11641,7 +11785,7 @@ function collectUniqueBranches(ast, helpers) {
11641
11785
  * @param atom - The comparison atom (already known to be `<` or `<=`).
11642
11786
  * @param acc - The clause accumulator.
11643
11787
  */ function extractSizeCap(atom, acc) {
11644
- var _atom_args = _sliced_to_array$1(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11788
+ var _atom_args = _sliced_to_array$2(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11645
11789
  if (isMemberPath(lhs, REQUEST_RESOURCE_SIZE_PATH)) {
11646
11790
  var cap = foldNumericNode(rhs);
11647
11791
  if (typeof cap === 'number') {
@@ -11656,7 +11800,7 @@ function collectUniqueBranches(ast, helpers) {
11656
11800
  * @param atom - The equality atom.
11657
11801
  * @param acc - The clause accumulator.
11658
11802
  */ function extractMimeEquality(atom, acc) {
11659
- var _atom_args = _sliced_to_array$1(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11803
+ var _atom_args = _sliced_to_array$2(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11660
11804
  var mimeNode = null;
11661
11805
  if (isMemberPath(lhs, REQUEST_RESOURCE_CONTENT_TYPE_PATH)) {
11662
11806
  mimeNode = rhs;
@@ -11675,7 +11819,7 @@ function collectUniqueBranches(ast, helpers) {
11675
11819
  * @param atom - The `rcall` atom.
11676
11820
  * @param acc - The clause accumulator.
11677
11821
  */ function extractMimeMatches(atom, acc) {
11678
- var _atom_args = _sliced_to_array$1(atom.args, 3), method = _atom_args[0], receiver = _atom_args[1], args = _atom_args[2];
11822
+ var _atom_args = _sliced_to_array$2(atom.args, 3), method = _atom_args[0], receiver = _atom_args[1], args = _atom_args[2];
11679
11823
  if (method === 'matches' && isMemberPath(receiver, REQUEST_RESOURCE_CONTENT_TYPE_PATH) && args.length === 1) {
11680
11824
  var arg = args[0];
11681
11825
  if (arg.op === 'value' && typeof arg.args === 'string') {
@@ -11695,7 +11839,7 @@ function collectUniqueBranches(ast, helpers) {
11695
11839
  * @param atom - The `in` atom.
11696
11840
  * @param acc - The clause accumulator.
11697
11841
  */ function extractMimeInList(atom, acc) {
11698
- var _atom_args = _sliced_to_array$1(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11842
+ var _atom_args = _sliced_to_array$2(atom.args, 2), lhs = _atom_args[0], rhs = _atom_args[1];
11699
11843
  if (isMemberPath(lhs, REQUEST_RESOURCE_CONTENT_TYPE_PATH) && rhs.op === 'list') {
11700
11844
  var items = rhs.args;
11701
11845
  var collected = [];
@@ -11763,7 +11907,7 @@ function collectUniqueBranches(ast, helpers) {
11763
11907
  if (endIndex === 1) {
11764
11908
  result = node.op === 'id' && node.args === segments[0];
11765
11909
  } else if (endIndex > 1 && node.op === '.') {
11766
- var _node_args = _sliced_to_array$1(node.args, 2), receiver = _node_args[0], prop = _node_args[1];
11910
+ var _node_args = _sliced_to_array$2(node.args, 2), receiver = _node_args[0], prop = _node_args[1];
11767
11911
  if (prop === segments[endIndex - 1]) {
11768
11912
  result = isMemberPath(receiver, segments, endIndex - 1);
11769
11913
  }
@@ -11791,7 +11935,7 @@ function collectUniqueBranches(ast, helpers) {
11791
11935
  result = -inner;
11792
11936
  }
11793
11937
  } else if (node.op === '+' || node.op === '-' || node.op === '*' || node.op === '/') {
11794
- var _node_args = _sliced_to_array$1(node.args, 2), l = _node_args[0], r = _node_args[1];
11938
+ var _node_args = _sliced_to_array$2(node.args, 2), l = _node_args[0], r = _node_args[1];
11795
11939
  var left = foldNumericNode(l);
11796
11940
  var right = foldNumericNode(r);
11797
11941
  if (typeof left === 'number' && typeof right === 'number') {
@@ -11833,10 +11977,10 @@ function applyNumericBinaryOp(op, left, right) {
11833
11977
  * @param branch - The parsed branch.
11834
11978
  * @returns A signature string usable as a Map/Set key.
11835
11979
  */ function branchSignature(branch) {
11836
- var literals = _to_consumable_array$2(branch.allowedMimeLiterals).sort(function(a, b) {
11980
+ var literals = _to_consumable_array$3(branch.allowedMimeLiterals).sort(function(a, b) {
11837
11981
  return a.localeCompare(b);
11838
11982
  });
11839
- var regexes = _to_consumable_array$2(branch.allowedMimeRegexes).sort(function(a, b) {
11983
+ var regexes = _to_consumable_array$3(branch.allowedMimeRegexes).sort(function(a, b) {
11840
11984
  return a.localeCompare(b);
11841
11985
  });
11842
11986
  return "".concat(branch.maxFileSizeBytes, "|").concat(literals.join(','), "|").concat(regexes.join(','));
@@ -12109,6 +12253,46 @@ function _object_spread$1(target) {
12109
12253
  * in `STORAGE_FILE_PURPOSE_UPLOAD_POLICIES`. The capture group is the policy key constant
12110
12254
  * name, e.g. `USER_AVATAR_PURPOSE`.
12111
12255
  */ var MIRRORS_POLICY_KEY_MARKER_REGEX = /\/\/\s*Mirrors\s+STORAGE_FILE_PURPOSE_UPLOAD_POLICIES\[(\w+)\]/g;
12256
+ /**
12257
+ * Converts a parsed leaf block's `matchPath` (e.g. `/uploads/u/{uid}/jr/{shortKey}`) into a
12258
+ * structural segment list for comparison against a folded upload-policy path. Empty segments
12259
+ * (leading/trailing/duplicate slashes) are dropped; `{var}` / `{var=**}` path variables become
12260
+ * wildcards; every other segment is a literal.
12261
+ *
12262
+ * @param matchPath - The accumulated match-path string.
12263
+ * @returns The structural segment list.
12264
+ */ function rulesMatchPathToSegments(matchPath) {
12265
+ var segments = [];
12266
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12267
+ try {
12268
+ for(var _iterator = matchPath.split('/')[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12269
+ var raw = _step.value;
12270
+ if (raw.length > 0) {
12271
+ segments.push(/^\{[^}]*\}$/.test(raw) ? {
12272
+ kind: 'wildcard',
12273
+ value: ''
12274
+ } : {
12275
+ kind: 'literal',
12276
+ value: raw
12277
+ });
12278
+ }
12279
+ }
12280
+ } catch (err) {
12281
+ _didIteratorError = true;
12282
+ _iteratorError = err;
12283
+ } finally{
12284
+ try {
12285
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
12286
+ _iterator.return();
12287
+ }
12288
+ } finally{
12289
+ if (_didIteratorError) {
12290
+ throw _iteratorError;
12291
+ }
12292
+ }
12293
+ }
12294
+ return segments;
12295
+ }
12112
12296
  var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|update))*\s*:\s*if\s+([\s\S]+?);/g;
12113
12297
  /**
12114
12298
  * Collects every `// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[<KEY>]` marker in the
@@ -12257,9 +12441,10 @@ var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|u
12257
12441
  return trimmed.startsWith('service ') || /^match\s+\/b\/[^]+\/o\s*$/.test(trimmed);
12258
12442
  }
12259
12443
  /**
12260
- * Processes a single `match /<segment> { ... }` block: descends into nested matches,
12261
- * skips catch-all deny blocks, and (when a `Mirrors ...` marker precedes the block)
12262
- * reduces the `allow write` predicate to `ParsedRuleBranch[]`.
12444
+ * Processes a single `match /<segment> { ... }` block: skips catch-all deny blocks, records
12445
+ * the block as a leaf when it carries an `allow write|create|update` predicate (reducing the
12446
+ * predicate to `ParsedRuleBranch[]`), and always descends into nested matches so deeper leaf
12447
+ * blocks are collected too.
12263
12448
  *
12264
12449
  * @param input - The match-block inputs: block descriptor, unmasked path segment,
12265
12450
  * enclosing body offset, parent path, scope functions, and walk context.
@@ -12269,13 +12454,14 @@ var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|u
12269
12454
  var headerSourceOffset = bodyOffset + block.headerStart;
12270
12455
  var markerKey = consumePrecedingMarker(ctx.pendingMarkers, headerSourceOffset);
12271
12456
  if (!isCatchAllSegment(matchSegment)) {
12272
- if (markerKey) {
12273
- recordMirroredBlock({
12274
- block: block,
12457
+ var predicate = extractAllowWritePredicate(topLevelBlockText(block.body));
12458
+ if (predicate) {
12459
+ recordLeafBlock({
12275
12460
  fullPath: fullPath,
12276
12461
  headerSourceOffset: headerSourceOffset,
12277
12462
  scopeFunctions: scopeFunctions,
12278
12463
  markerKey: markerKey,
12464
+ predicate: predicate,
12279
12465
  ctx: ctx
12280
12466
  });
12281
12467
  }
@@ -12289,40 +12475,70 @@ var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|u
12289
12475
  }
12290
12476
  }
12291
12477
  /**
12292
- * Reduces a match block paired with a `// Mirrors ...` marker and pushes a
12293
- * `ParsedStorageRulesBlock` onto the results.
12478
+ * Reduces a leaf match block's `allow write` predicate and pushes a `ParsedStorageRulesBlock`
12479
+ * onto the results. Pairing with a TypeScript upload policy is by `matchPath`; any legacy
12480
+ * `// Mirrors ...` marker key is recorded for backward compatibility only.
12294
12481
  *
12295
- * @param input - The record inputs: block descriptor, accumulated unmasked path,
12296
- * header source offset, scope functions, marker key, and walk context.
12297
- */ function recordMirroredBlock(input) {
12298
- var block = input.block, fullPath = input.fullPath, headerSourceOffset = input.headerSourceOffset, scopeFunctions = input.scopeFunctions, markerKey = input.markerKey, ctx = input.ctx;
12299
- var predicate = extractAllowWritePredicate(block.body);
12482
+ * @param input - The record inputs: accumulated unmasked path, header source offset, scope
12483
+ * functions, optional marker key, the allow-write predicate text, and walk context.
12484
+ */ function recordLeafBlock(input) {
12485
+ var fullPath = input.fullPath, headerSourceOffset = input.headerSourceOffset, scopeFunctions = input.scopeFunctions, markerKey = input.markerKey, predicate = input.predicate, ctx = input.ctx;
12300
12486
  var _indexToLineColumn = indexToLineColumn(ctx.source, headerSourceOffset), line = _indexToLineColumn.line, column = _indexToLineColumn.column;
12301
- if (predicate) {
12302
- var helpers = {
12303
- definitions: scopeFunctions
12304
- };
12305
- var reduced = evaluatePredicate(predicate, helpers);
12306
- var entry = _object_spread$1({
12307
- mirrorsPolicyKey: markerKey,
12308
- matchPath: fullPath,
12309
- branches: reduced.branches,
12310
- sourceLine: line,
12311
- sourceColumn: column
12312
- }, reduced.unsupported ? {
12313
- unsupported: reduced.unsupported
12314
- } : {});
12315
- ctx.results.push(entry);
12316
- } else {
12317
- ctx.results.push({
12318
- mirrorsPolicyKey: markerKey,
12319
- matchPath: fullPath,
12320
- branches: [],
12321
- sourceLine: line,
12322
- sourceColumn: column,
12323
- unsupported: 'no allow write/create/update predicate found in match block'
12324
- });
12487
+ var helpers = {
12488
+ definitions: scopeFunctions
12489
+ };
12490
+ var reduced = evaluatePredicate(predicate, helpers);
12491
+ var entry = _object_spread$1({
12492
+ mirrorsPolicyKey: markerKey,
12493
+ matchPath: fullPath,
12494
+ branches: reduced.branches,
12495
+ sourceLine: line,
12496
+ sourceColumn: column
12497
+ }, reduced.unsupported ? {
12498
+ unsupported: reduced.unsupported
12499
+ } : {});
12500
+ ctx.results.push(entry);
12501
+ }
12502
+ /**
12503
+ * Blanks out everything nested inside braces, leaving only this block's own top-level text.
12504
+ * Used so a block's `allow write` predicate is detected only when it belongs to the block
12505
+ * itself — not when it appears inside a nested `match` / `function` block (whose predicates
12506
+ * belong to those deeper leaf blocks instead).
12507
+ *
12508
+ * @param body - The (masked) block body.
12509
+ * @returns The body with nested-brace content replaced by spaces (offsets preserved).
12510
+ */ function topLevelBlockText(body) {
12511
+ var depth = 0;
12512
+ var result = '';
12513
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12514
+ try {
12515
+ for(var _iterator = body[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12516
+ var char = _step.value;
12517
+ if (char === '{') {
12518
+ depth += 1;
12519
+ result += ' ';
12520
+ } else if (char === '}') {
12521
+ depth -= 1;
12522
+ result += ' ';
12523
+ } else {
12524
+ result += depth === 0 ? char : ' ';
12525
+ }
12526
+ }
12527
+ } catch (err) {
12528
+ _didIteratorError = true;
12529
+ _iteratorError = err;
12530
+ } finally{
12531
+ try {
12532
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
12533
+ _iterator.return();
12534
+ }
12535
+ } finally{
12536
+ if (_didIteratorError) {
12537
+ throw _iteratorError;
12538
+ }
12539
+ }
12325
12540
  }
12541
+ return result;
12326
12542
  }
12327
12543
  /**
12328
12544
  * Pulls the first `allow write|create|update: if <predicate>;` predicate from a match
@@ -12340,12 +12556,14 @@ var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|u
12340
12556
  return result;
12341
12557
  }
12342
12558
  /**
12343
- * Parses a `storage.rules` source string and returns every match block paired with a
12344
- * `// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[<KEY>]` marker. Catch-all deny blocks
12345
- * are skipped; the rest of the tree is walked normally.
12559
+ * Parses a `storage.rules` source string and returns every leaf `match` block that carries an
12560
+ * `allow write|create|update` predicate, each with its full accumulated `matchPath`. Catch-all
12561
+ * deny blocks are skipped; the rest of the tree is walked normally. Pairing with TypeScript
12562
+ * upload policies is by path (see {@link rulesMatchPathToSegments}); the `// Mirrors ...` marker
12563
+ * is no longer required.
12346
12564
  *
12347
12565
  * @param source - The raw rules source text.
12348
- * @returns Parsed mirrored blocks in source order.
12566
+ * @returns Parsed leaf blocks in source order.
12349
12567
  */ function parseStorageRules(source) {
12350
12568
  var stripped = stripLineComments(source);
12351
12569
  var masked = maskPathVariables(stripped);
@@ -12364,168 +12582,134 @@ var ALLOW_WRITE_RE = /allow\s+(?:write|create|update)(?:\s*,\s*(?:write|create|u
12364
12582
  return ctx.results;
12365
12583
  }
12366
12584
 
12585
+ function _array_like_to_array$4(arr, len) {
12586
+ if (len == null || len > arr.length) len = arr.length;
12587
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
12588
+ return arr2;
12589
+ }
12590
+ function _array_without_holes$2(arr) {
12591
+ if (Array.isArray(arr)) return _array_like_to_array$4(arr);
12592
+ }
12593
+ function _iterable_to_array$2(iter) {
12594
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
12595
+ }
12596
+ function _non_iterable_spread$2() {
12597
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
12598
+ }
12599
+ function _to_consumable_array$2(arr) {
12600
+ return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$4(arr) || _non_iterable_spread$2();
12601
+ }
12602
+ function _unsupported_iterable_to_array$4(o, minLen) {
12603
+ if (!o) return;
12604
+ if (typeof o === "string") return _array_like_to_array$4(o, minLen);
12605
+ var n = Object.prototype.toString.call(o).slice(8, -1);
12606
+ if (n === "Object" && o.constructor) n = o.constructor.name;
12607
+ if (n === "Map" || n === "Set") return Array.from(n);
12608
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$4(o, minLen);
12609
+ }
12610
+ var MAX_FOLD_DEPTH = 24;
12611
+ var PATH_SEPARATOR = '/';
12367
12612
  /**
12368
- * Default type name the rule looks for on top-level declarators. Variables whose type
12369
- * annotation resolves to this identifier are treated as upload policies and validated
12370
- * against `storage.rules`.
12371
- */ var DEFAULT_STORAGE_FILE_UPLOAD_POLICY_TYPE_NAME = 'StorageFilePurposeUploadPolicy';
12613
+ * `@dereekb/util` path combinators that merge a single array argument of path parts. Modeled
12614
+ * exactly: drop statically-empty parts, join with a `/` boundary, collapse empty segments.
12615
+ */ var MERGE_COMBINATOR_NAMES = new Set([
12616
+ 'mergeSlashPaths'
12617
+ ]);
12372
12618
  /**
12373
- * Default file name searched relative to the lint root when `storageRulesPath` is omitted.
12374
- */ var DEFAULT_STORAGE_RULES_FILENAME = 'storage.rules';
12375
- var rulesFileCache = new Map();
12619
+ * `@dereekb/util` path combinators that take a single path argument and only normalize
12620
+ * slashes (collapse `//`, prepend a leading `/`). Structurally these are identity over the
12621
+ * abstract domain because {@link fragsToSegments} already collapses empty segments.
12622
+ */ var NORMALIZE_COMBINATOR_NAMES = new Set([
12623
+ 'fixMultiSlashesInSlashPath',
12624
+ 'replaceMultipleFilePathsInSlashPath',
12625
+ 'toAbsoluteSlashPathStartType',
12626
+ 'toRelativeSlashPathStartType',
12627
+ 'removeTrailingSlashes',
12628
+ 'addTrailingSlash'
12629
+ ]);
12376
12630
  /**
12377
- * Reads and parses a `storage.rules` file, caching by absolute path so repeated rule
12378
- * activations across files in the same lint pass don't re-read disk.
12631
+ * Statically folds a `StorageFilePurposeUploadPolicy.buildUploadPath` builder to an abstract
12632
+ * path template. The builder is an arrow `(input) => <path expression>` whose destructured /
12633
+ * positional params become wildcards and whose body is a composition of string literals,
12634
+ * `const`s, `@dereekb/util` path combinators, and foldable single-`return` helper functions.
12379
12635
  *
12380
- * @param absolutePath - Absolute path to the rules file.
12381
- * @returns The parsed blocks, or null when the file cannot be read.
12382
- */ function loadParsedRulesFromPath(absolutePath) {
12383
- var result = null;
12384
- var cached = rulesFileCache.get(absolutePath);
12385
- if (cached) {
12386
- result = cached;
12636
+ * @param builderNode - The `buildUploadPath` value node (arrow / function expression, possibly behind a type assertion).
12637
+ * @param scope - The lexical scope the builder lives in.
12638
+ * @returns The folded path, or a reason the builder is unresolvable.
12639
+ */ function foldUploadPath(builderNode, scope) {
12640
+ var result;
12641
+ var fn = unwrapTypeAssertion$1(builderNode);
12642
+ if ((fn === null || fn === void 0 ? void 0 : fn.type) !== 'ArrowFunctionExpression' && (fn === null || fn === void 0 ? void 0 : fn.type) !== 'FunctionExpression') {
12643
+ result = {
12644
+ ok: false,
12645
+ reason: 'buildUploadPath is not an inline arrow/function expression'
12646
+ };
12387
12647
  } else {
12388
- try {
12389
- var source = node_fs.readFileSync(absolutePath, 'utf8');
12390
- var parsed = parseStorageRules(source);
12391
- rulesFileCache.set(absolutePath, parsed);
12392
- result = parsed;
12393
- } catch (unused) {
12394
- result = null;
12395
- }
12396
- }
12397
- return result;
12398
- }
12399
- /**
12400
- * Folds a numeric expression node to a number using literals, binary `*`/`+`/`-`/`/`,
12401
- * unary `-`/`+`, parenthesized expressions, and identifier lookups in `constants`.
12402
- *
12403
- * @param node - The expression node.
12404
- * @param constants - Numeric constants resolvable by identifier name.
12405
- * @returns The folded number, or null when any operand is unresolvable.
12406
- */ function evaluateNumericNode(node, constants) {
12407
- var result = null;
12408
- if (node) {
12409
- if (node.type === 'Literal' && typeof node.value === 'number') {
12410
- result = node.value;
12411
- } else if (node.type === 'UnaryExpression' && (node.operator === '-' || node.operator === '+')) {
12412
- result = evaluateNumericUnary(node, constants);
12413
- } else if (node.type === 'BinaryExpression') {
12414
- result = evaluateNumericBinary(node, constants);
12415
- } else if (node.type === 'Identifier') {
12416
- var value = constants.get(node.name);
12417
- if (typeof value === 'number') {
12418
- result = value;
12648
+ var _fn_params;
12649
+ var env = new Map();
12650
+ bindParamsAsWildcards((_fn_params = fn.params) !== null && _fn_params !== void 0 ? _fn_params : [], env);
12651
+ var body = functionBodyExpression(fn);
12652
+ if (!body) {
12653
+ result = {
12654
+ ok: false,
12655
+ reason: 'buildUploadPath body is not a single return expression'
12656
+ };
12657
+ } else {
12658
+ var frags = foldFrags(body, {
12659
+ scope: scope,
12660
+ env: env
12661
+ }, 0);
12662
+ if (!frags) {
12663
+ result = {
12664
+ ok: false,
12665
+ reason: 'buildUploadPath does not fold to a constant path (unknown const, unmodeled call, or runtime value)'
12666
+ };
12667
+ } else {
12668
+ result = {
12669
+ ok: true,
12670
+ path: {
12671
+ segments: fragsToSegments(frags)
12672
+ }
12673
+ };
12419
12674
  }
12420
- } else if (node.type === 'TSAsExpression' && node.expression) {
12421
- result = evaluateNumericNode(node.expression, constants);
12422
12675
  }
12423
12676
  }
12424
12677
  return result;
12425
12678
  }
12426
- function evaluateNumericUnary(node, constants) {
12427
- var result = null;
12428
- var arg = evaluateNumericNode(node.argument, constants);
12429
- if (typeof arg === 'number') {
12430
- result = node.operator === '-' ? -arg : arg;
12431
- }
12432
- return result;
12433
- }
12434
- function evaluateNumericBinary(node, constants) {
12435
- var result = null;
12436
- var left = evaluateNumericNode(node.left, constants);
12437
- var right = evaluateNumericNode(node.right, constants);
12438
- if (typeof left === 'number' && typeof right === 'number') {
12439
- result = applyBinaryOperator(node.operator, left, right);
12440
- }
12441
- return result;
12442
- }
12443
- /**
12444
- * Applies a binary operator to two folded operands, returning null for unsupported operators.
12445
- *
12446
- * @param operator - The binary operator (`+`, `-`, `*`, `/`).
12447
- * @param left - Left operand.
12448
- * @param right - Right operand.
12449
- * @returns The result, or null when the operator is unsupported.
12450
- */ function applyBinaryOperator(operator, left, right) {
12451
- var result = null;
12452
- if (operator === '*') {
12453
- result = left * right;
12454
- } else if (operator === '+') {
12455
- result = left + right;
12456
- } else if (operator === '-') {
12457
- result = left - right;
12458
- } else if (operator === '/' && right !== 0) {
12459
- result = left / right;
12460
- }
12461
- return result;
12462
- }
12463
12679
  /**
12464
- * Extracts the cross-reference key used to pair a policy with its `storage.rules` `Mirrors`
12465
- * block.
12466
- *
12467
- * - When `purpose` is an `Identifier`, the constant name (e.g. `USER_AVATAR_PURPOSE`) is the
12468
- * key — this is what `// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[USER_AVATAR_PURPOSE]`
12469
- * comments reference.
12470
- * - When `purpose` is a string literal, the literal value is used so a policy that inlines
12471
- * `purpose: 'avatar'` can still pair with `Mirrors ...[avatar]`.
12472
- * - `TSAsExpression` is unwrapped transparently.
12473
- * - Anything else (computed expression, member access, function call) returns null and
12474
- * triggers `unresolvedPolicyField`.
12680
+ * Returns the single expression a function-like node evaluates to: an arrow's expression
12681
+ * body directly, or the argument of a lone `return` statement in a block body.
12475
12682
  *
12476
- * @param node - The expression node for the policy's `purpose` field.
12477
- * @returns The mirror-cross-reference key, or null when unresolvable.
12478
- */ function extractPolicyKey(node) {
12683
+ * @param fn - The arrow / function expression node.
12684
+ * @returns The returned expression, or null when the body is not a single return.
12685
+ */ function functionBodyExpression(fn) {
12479
12686
  var result = null;
12480
- if (node) {
12481
- if (node.type === 'Identifier') {
12482
- result = node.name;
12483
- } else if (node.type === 'Literal' && typeof node.value === 'string') {
12484
- result = node.value;
12485
- } else if (node.type === 'TSAsExpression' && node.expression) {
12486
- result = extractPolicyKey(node.expression);
12687
+ var body = fn.body;
12688
+ if (body && body.type !== 'BlockStatement') {
12689
+ result = body;
12690
+ } else if ((body === null || body === void 0 ? void 0 : body.type) === 'BlockStatement') {
12691
+ var _body_body;
12692
+ var _statements_;
12693
+ var statements = (_body_body = body.body) !== null && _body_body !== void 0 ? _body_body : [];
12694
+ if (statements.length === 1 && ((_statements_ = statements[0]) === null || _statements_ === void 0 ? void 0 : _statements_.type) === 'ReturnStatement' && statements[0].argument) {
12695
+ result = statements[0].argument;
12487
12696
  }
12488
12697
  }
12489
12698
  return result;
12490
12699
  }
12491
12700
  /**
12492
- * Folds a string-array expression node to a list of strings using array literals of string
12493
- * literals and identifier lookups in `constants`.
12701
+ * Binds each parameter pattern to a wildcard (or a wildcard-per-property for an object
12702
+ * destructure). The builder never needs a param's runtime content — a param maps to a single
12703
+ * path segment, which compares equal to a rules `{var}`.
12494
12704
  *
12495
- * @param node - The expression node.
12496
- * @param constants - String-array constants resolvable by identifier name.
12497
- * @returns The resolved string array, or null when any element is unresolvable.
12498
- */ function evaluateStringArrayNode(node, constants) {
12499
- var result = null;
12500
- if (node) {
12501
- if (node.type === 'ArrayExpression') {
12502
- result = evaluateStringArrayLiteral(node);
12503
- } else if (node.type === 'Identifier') {
12504
- var value = constants.get(node.name);
12505
- if (value) {
12506
- result = value;
12507
- }
12508
- } else if (node.type === 'TSAsExpression' && node.expression) {
12509
- result = evaluateStringArrayNode(node.expression, constants);
12510
- }
12511
- }
12512
- return result;
12513
- }
12514
- function evaluateStringArrayLiteral(node) {
12515
- var _node_elements;
12516
- var result = null;
12517
- var items = [];
12518
- var allLiterals = true;
12705
+ * @param params - The parameter pattern nodes.
12706
+ * @param env - The environment to mutate.
12707
+ */ function bindParamsAsWildcards(params, env) {
12519
12708
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12520
12709
  try {
12521
- for(var _iterator = ((_node_elements = node.elements) !== null && _node_elements !== void 0 ? _node_elements : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12522
- var element = _step.value;
12523
- if ((element === null || element === void 0 ? void 0 : element.type) === 'Literal' && typeof element.value === 'string') {
12524
- items.push(element.value);
12525
- } else {
12526
- allLiterals = false;
12527
- break;
12528
- }
12710
+ for(var _iterator = params[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12711
+ var param = _step.value;
12712
+ bindPatternAsWildcards(param, env);
12529
12713
  }
12530
12714
  } catch (err) {
12531
12715
  _didIteratorError = true;
@@ -12541,43 +12725,1122 @@ function evaluateStringArrayLiteral(node) {
12541
12725
  }
12542
12726
  }
12543
12727
  }
12544
- if (allLiterals) {
12545
- result = items;
12546
- }
12547
- return result;
12548
12728
  }
12549
- /**
12550
- * Walks the Program body to index every top-level numeric / string / string-array `const` so
12551
- * later folding can resolve identifier references inside policy literals.
12552
- *
12553
- * @param programNode - The Program AST node.
12554
- * @returns The constants index for the file.
12555
- */ function indexProgramConstants(programNode) {
12556
- var numericConstants = new Map();
12557
- var stringArrayConstants = new Map();
12558
- var declarators = collectTopLevelDeclarators$1(programNode);
12559
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12560
- try {
12561
- for(var _iterator = declarators[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12562
- var declarator = _step.value;
12563
- var _declarator_id;
12564
- if (((_declarator_id = declarator.id) === null || _declarator_id === void 0 ? void 0 : _declarator_id.type) === 'Identifier' && declarator.init) {
12565
- var name = declarator.id.name;
12566
- var init = declarator.init.type === 'TSAsExpression' ? declarator.init.expression : declarator.init;
12567
- var numeric = evaluateNumericNode(init, numericConstants);
12568
- if (typeof numeric === 'number') {
12569
- numericConstants.set(name, numeric);
12729
+ function bindPatternAsWildcards(param, env) {
12730
+ var _param_argument;
12731
+ if ((param === null || param === void 0 ? void 0 : param.type) === 'Identifier') {
12732
+ env.set(param.name, wildcardScalar());
12733
+ } else if ((param === null || param === void 0 ? void 0 : param.type) === 'ObjectPattern') {
12734
+ var _param_properties;
12735
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12736
+ try {
12737
+ for(var _iterator = ((_param_properties = param.properties) !== null && _param_properties !== void 0 ? _param_properties : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12738
+ var property = _step.value;
12739
+ var _property_key, _property_argument;
12740
+ if (property.type === 'Property' && ((_property_key = property.key) === null || _property_key === void 0 ? void 0 : _property_key.type) === 'Identifier') {
12741
+ env.set(property.key.name, wildcardScalar());
12742
+ } else if (property.type === 'RestElement' && ((_property_argument = property.argument) === null || _property_argument === void 0 ? void 0 : _property_argument.type) === 'Identifier') {
12743
+ env.set(property.argument.name, {
12744
+ kind: 'list',
12745
+ items: []
12746
+ });
12570
12747
  }
12571
- var stringArray = evaluateStringArrayNode(init, stringArrayConstants);
12572
- if (stringArray) {
12573
- stringArrayConstants.set(name, stringArray);
12748
+ }
12749
+ } catch (err) {
12750
+ _didIteratorError = true;
12751
+ _iteratorError = err;
12752
+ } finally{
12753
+ try {
12754
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
12755
+ _iterator.return();
12756
+ }
12757
+ } finally{
12758
+ if (_didIteratorError) {
12759
+ throw _iteratorError;
12574
12760
  }
12575
12761
  }
12576
12762
  }
12577
- } catch (err) {
12578
- _didIteratorError = true;
12579
- _iteratorError = err;
12580
- } finally{
12763
+ } else if ((param === null || param === void 0 ? void 0 : param.type) === 'RestElement' && ((_param_argument = param.argument) === null || _param_argument === void 0 ? void 0 : _param_argument.type) === 'Identifier') {
12764
+ env.set(param.argument.name, {
12765
+ kind: 'list',
12766
+ items: []
12767
+ });
12768
+ } else if ((param === null || param === void 0 ? void 0 : param.type) === 'AssignmentPattern' && param.left) {
12769
+ bindPatternAsWildcards(param.left, env);
12770
+ }
12771
+ }
12772
+ function wildcardScalar() {
12773
+ return {
12774
+ kind: 'scalar',
12775
+ frags: [
12776
+ {
12777
+ kind: 'wildcard'
12778
+ }
12779
+ ]
12780
+ };
12781
+ }
12782
+ /**
12783
+ * Folds an expression node to a fragment stream, or null when any sub-expression is
12784
+ * statically unknown.
12785
+ *
12786
+ * @param node - The expression node.
12787
+ * @param frame - The current scope + environment.
12788
+ * @param depth - Recursion depth guard.
12789
+ * @returns The fragment stream, or null when unfoldable.
12790
+ */ function foldFrags(node, frame, depth) {
12791
+ var result = null;
12792
+ if (node && depth <= MAX_FOLD_DEPTH) {
12793
+ if (node.type === 'Literal') {
12794
+ result = typeof node.value === 'string' ? [
12795
+ {
12796
+ kind: 'literal',
12797
+ value: node.value
12798
+ }
12799
+ ] : null;
12800
+ } else if (node.type === 'TemplateLiteral') {
12801
+ result = foldTemplateLiteral(node, frame, depth);
12802
+ } else if (node.type === 'Identifier') {
12803
+ result = foldIdentifier(node, frame, depth);
12804
+ } else if (node.type === 'TSAsExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSNonNullExpression') {
12805
+ result = node.expression ? foldFrags(node.expression, frame, depth) : null;
12806
+ } else if (node.type === 'BinaryExpression' && node.operator === '+') {
12807
+ result = foldStringConcat(node, frame, depth);
12808
+ } else if (node.type === 'CallExpression') {
12809
+ result = foldCall(node, frame, depth);
12810
+ }
12811
+ }
12812
+ return result;
12813
+ }
12814
+ function foldTemplateLiteral(node, frame, depth) {
12815
+ var _node_quasis, _node_expressions;
12816
+ var result = [];
12817
+ var quasis = (_node_quasis = node.quasis) !== null && _node_quasis !== void 0 ? _node_quasis : [];
12818
+ var expressions = (_node_expressions = node.expressions) !== null && _node_expressions !== void 0 ? _node_expressions : [];
12819
+ for(var i = 0; i < quasis.length && result; i++){
12820
+ var _ref;
12821
+ var _quasis_i_value, _quasis_i;
12822
+ var cooked = (_ref = (_quasis_i = quasis[i]) === null || _quasis_i === void 0 ? void 0 : (_quasis_i_value = _quasis_i.value) === null || _quasis_i_value === void 0 ? void 0 : _quasis_i_value.cooked) !== null && _ref !== void 0 ? _ref : '';
12823
+ var next = _to_consumable_array$2(result).concat([
12824
+ {
12825
+ kind: 'literal',
12826
+ value: cooked
12827
+ }
12828
+ ]);
12829
+ if (i < expressions.length) {
12830
+ var exprFrags = foldFrags(expressions[i], frame, depth + 1);
12831
+ result = exprFrags ? _to_consumable_array$2(next).concat(_to_consumable_array$2(exprFrags)) : null;
12832
+ } else {
12833
+ result = next;
12834
+ }
12835
+ }
12836
+ return result;
12837
+ }
12838
+ function foldStringConcat(node, frame, depth) {
12839
+ var result = null;
12840
+ var left = foldFrags(node.left, frame, depth + 1);
12841
+ var right = foldFrags(node.right, frame, depth + 1);
12842
+ if (left && right) {
12843
+ result = _to_consumable_array$2(left).concat(_to_consumable_array$2(right));
12844
+ }
12845
+ return result;
12846
+ }
12847
+ /**
12848
+ * Folds an identifier: a bound (scalar) param/local, then a top-level const in the current
12849
+ * module, then an imported const in another module. A list-bound identifier (rest param) used
12850
+ * as a string is unfoldable.
12851
+ *
12852
+ * @param node - The identifier node.
12853
+ * @param frame - The current scope + environment.
12854
+ * @param depth - Recursion depth guard.
12855
+ * @returns The fragment stream, or null.
12856
+ */ function foldIdentifier(node, frame, depth) {
12857
+ var result = null;
12858
+ var name = node.name;
12859
+ var bound = frame.env.get(name);
12860
+ if (bound) {
12861
+ result = bound.kind === 'scalar' ? bound.frags : null;
12862
+ } else {
12863
+ var local = findTopLevelConstInit(frame.scope.program, name);
12864
+ if (local) {
12865
+ result = foldFrags(local, {
12866
+ scope: frame.scope,
12867
+ env: new Map()
12868
+ }, depth + 1);
12869
+ } else {
12870
+ var imported = resolveImported(name, node, frame.scope);
12871
+ var init = imported ? declaratorInit(imported.node) : null;
12872
+ if (imported && init) {
12873
+ result = foldFrags(init, {
12874
+ scope: imported.scope,
12875
+ env: new Map()
12876
+ }, depth + 1);
12877
+ }
12878
+ }
12879
+ }
12880
+ return result;
12881
+ }
12882
+ /**
12883
+ * Folds a call expression: a modeled `@dereekb/util` path combinator, or an inlinable
12884
+ * single-`return` helper function (local or imported).
12885
+ *
12886
+ * @param node - The CallExpression node.
12887
+ * @param frame - The current scope + environment.
12888
+ * @param depth - Recursion depth guard.
12889
+ * @returns The fragment stream, or null.
12890
+ */ function foldCall(node, frame, depth) {
12891
+ var _node_arguments;
12892
+ var result = null;
12893
+ var calleeName = callExpressionCalleeName(node.callee);
12894
+ var args = (_node_arguments = node.arguments) !== null && _node_arguments !== void 0 ? _node_arguments : [];
12895
+ if (calleeName && MERGE_COMBINATOR_NAMES.has(calleeName)) {
12896
+ result = foldMergeCombinator(args[0], frame, depth);
12897
+ } else if (calleeName && NORMALIZE_COMBINATOR_NAMES.has(calleeName)) {
12898
+ result = args.length === 1 ? foldFrags(args[0], frame, depth + 1) : null;
12899
+ } else if (calleeName) {
12900
+ result = foldInlinedFunction({
12901
+ calleeName: calleeName,
12902
+ call: node,
12903
+ frame: frame,
12904
+ depth: depth
12905
+ });
12906
+ }
12907
+ return result;
12908
+ }
12909
+ /**
12910
+ * Models `mergeSlashPaths([...])`: folds the single array argument to a list of parts, drops
12911
+ * statically-empty parts, and joins them with a `/` boundary. Empty-segment collapse is left
12912
+ * to {@link fragsToSegments}.
12913
+ *
12914
+ * @param arrayArg - The array argument node.
12915
+ * @param frame - The current scope + environment.
12916
+ * @param depth - Recursion depth guard.
12917
+ * @returns The joined fragment stream, or null when any element is unfoldable.
12918
+ */ function foldMergeCombinator(arrayArg, frame, depth) {
12919
+ var result = null;
12920
+ var items = arrayArg ? foldList(arrayArg, frame, depth) : null;
12921
+ if (items) {
12922
+ var joined = [];
12923
+ var first = true;
12924
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12925
+ try {
12926
+ for(var _iterator = items[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12927
+ var item = _step.value;
12928
+ if (!isStaticallyEmpty(item)) {
12929
+ var _joined;
12930
+ if (!first) {
12931
+ joined.push({
12932
+ kind: 'literal',
12933
+ value: PATH_SEPARATOR
12934
+ });
12935
+ }
12936
+ (_joined = joined).push.apply(_joined, _to_consumable_array$2(item));
12937
+ first = false;
12938
+ }
12939
+ }
12940
+ } catch (err) {
12941
+ _didIteratorError = true;
12942
+ _iteratorError = err;
12943
+ } finally{
12944
+ try {
12945
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
12946
+ _iterator.return();
12947
+ }
12948
+ } finally{
12949
+ if (_didIteratorError) {
12950
+ throw _iteratorError;
12951
+ }
12952
+ }
12953
+ }
12954
+ result = joined;
12955
+ }
12956
+ return result;
12957
+ }
12958
+ /**
12959
+ * Inlines a foldable single-`return` helper function called by name: binds its parameters to
12960
+ * the folded arguments (a rest parameter collects the remaining arguments as a list), then
12961
+ * folds its body in the function's own scope.
12962
+ *
12963
+ * @param input - The callee name, the CallExpression node, the caller's frame, and the depth guard.
12964
+ * @returns The fragment stream, or null when the function is not foldable.
12965
+ */ function foldInlinedFunction(input) {
12966
+ var calleeName = input.calleeName, call = input.call, frame = input.frame, depth = input.depth;
12967
+ var result = null;
12968
+ var resolved = resolveFunctionBinding(calleeName, call.callee, frame.scope);
12969
+ var fn = resolved ? functionFromBinding(resolved.node) : null;
12970
+ var body = fn ? functionBodyExpression(fn) : null;
12971
+ if (resolved && fn && body) {
12972
+ var _fn_params, _call_arguments;
12973
+ var env = bindCallArguments({
12974
+ params: (_fn_params = fn.params) !== null && _fn_params !== void 0 ? _fn_params : [],
12975
+ callArgs: (_call_arguments = call.arguments) !== null && _call_arguments !== void 0 ? _call_arguments : [],
12976
+ frame: frame,
12977
+ depth: depth
12978
+ });
12979
+ if (env) {
12980
+ result = foldFrags(body, {
12981
+ scope: resolved.scope,
12982
+ env: env
12983
+ }, depth + 1);
12984
+ }
12985
+ }
12986
+ return result;
12987
+ }
12988
+ /**
12989
+ * Binds call arguments to parameter patterns. Positional identifiers take the folded
12990
+ * argument; a trailing rest parameter collects the remaining folded arguments as a list.
12991
+ * Spread arguments are expanded from a list-valued operand. Any unfoldable argument fails the
12992
+ * whole binding (sound bail).
12993
+ *
12994
+ * @param input - The parameter patterns, the call argument nodes, the caller's frame, and the depth guard.
12995
+ * @returns The new environment, or null when an argument is unfoldable.
12996
+ */ function bindCallArguments(input) {
12997
+ var params = input.params, callArgs = input.callArgs, frame = input.frame, depth = input.depth;
12998
+ var argValues = foldArgumentList(callArgs, frame, depth);
12999
+ var result = null;
13000
+ if (argValues) {
13001
+ var env = new Map();
13002
+ var ok = true;
13003
+ var argIndex = 0;
13004
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13005
+ try {
13006
+ for(var _iterator = params[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13007
+ var param = _step.value;
13008
+ var _param_argument;
13009
+ if ((param === null || param === void 0 ? void 0 : param.type) === 'RestElement' && ((_param_argument = param.argument) === null || _param_argument === void 0 ? void 0 : _param_argument.type) === 'Identifier') {
13010
+ env.set(param.argument.name, {
13011
+ kind: 'list',
13012
+ items: argValues.slice(argIndex)
13013
+ });
13014
+ argIndex = argValues.length;
13015
+ } else if ((param === null || param === void 0 ? void 0 : param.type) === 'Identifier') {
13016
+ var _argValues_argIndex;
13017
+ env.set(param.name, {
13018
+ kind: 'scalar',
13019
+ frags: (_argValues_argIndex = argValues[argIndex]) !== null && _argValues_argIndex !== void 0 ? _argValues_argIndex : []
13020
+ });
13021
+ argIndex += 1;
13022
+ } else {
13023
+ ok = false;
13024
+ break;
13025
+ }
13026
+ }
13027
+ } catch (err) {
13028
+ _didIteratorError = true;
13029
+ _iteratorError = err;
13030
+ } finally{
13031
+ try {
13032
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13033
+ _iterator.return();
13034
+ }
13035
+ } finally{
13036
+ if (_didIteratorError) {
13037
+ throw _iteratorError;
13038
+ }
13039
+ }
13040
+ }
13041
+ result = ok ? env : null;
13042
+ }
13043
+ return result;
13044
+ }
13045
+ /**
13046
+ * Folds a positional argument list to a flat list of fragment streams, expanding any spread
13047
+ * whose operand folds to a list.
13048
+ *
13049
+ * @param callArgs - The call argument nodes.
13050
+ * @param frame - The current scope + environment.
13051
+ * @param depth - Recursion depth guard.
13052
+ * @returns The expanded list, or null when any argument is unfoldable.
13053
+ */ function foldArgumentList(callArgs, frame, depth) {
13054
+ var result = [];
13055
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13056
+ try {
13057
+ for(var _iterator = callArgs[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13058
+ var arg = _step.value;
13059
+ if (!result) {
13060
+ break;
13061
+ }
13062
+ if ((arg === null || arg === void 0 ? void 0 : arg.type) === 'SpreadElement') {
13063
+ var list = foldSpreadOperand(arg.argument, frame, depth);
13064
+ result = list ? _to_consumable_array$2(result).concat(_to_consumable_array$2(list)) : null;
13065
+ } else {
13066
+ var frags = foldFrags(arg, frame, depth + 1);
13067
+ result = frags ? _to_consumable_array$2(result).concat([
13068
+ frags
13069
+ ]) : null;
13070
+ }
13071
+ }
13072
+ } catch (err) {
13073
+ _didIteratorError = true;
13074
+ _iteratorError = err;
13075
+ } finally{
13076
+ try {
13077
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13078
+ _iterator.return();
13079
+ }
13080
+ } finally{
13081
+ if (_didIteratorError) {
13082
+ throw _iteratorError;
13083
+ }
13084
+ }
13085
+ }
13086
+ return result;
13087
+ }
13088
+ /**
13089
+ * Folds the operand of a spread (`...x`) to a list of fragment streams: a list-bound rest
13090
+ * parameter, or an inline array literal.
13091
+ *
13092
+ * @param operand - The spread operand node.
13093
+ * @param frame - The current scope + environment.
13094
+ * @param depth - Recursion depth guard.
13095
+ * @returns The list, or null when the operand is statically unknown.
13096
+ */ function foldSpreadOperand(operand, frame, depth) {
13097
+ var result = null;
13098
+ if ((operand === null || operand === void 0 ? void 0 : operand.type) === 'Identifier') {
13099
+ var bound = frame.env.get(operand.name);
13100
+ if ((bound === null || bound === void 0 ? void 0 : bound.kind) === 'list') {
13101
+ result = bound.items;
13102
+ }
13103
+ } else if ((operand === null || operand === void 0 ? void 0 : operand.type) === 'ArrayExpression') {
13104
+ result = foldList(operand, frame, depth);
13105
+ }
13106
+ return result;
13107
+ }
13108
+ /**
13109
+ * Folds an array-literal expression to a list of fragment streams, expanding spreads. Returns
13110
+ * null when any element is unfoldable or a spread operand is statically unknown.
13111
+ *
13112
+ * @param node - The ArrayExpression node.
13113
+ * @param frame - The current scope + environment.
13114
+ * @param depth - Recursion depth guard.
13115
+ * @returns The element list, or null.
13116
+ */ function foldList(node, frame, depth) {
13117
+ var result = null;
13118
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'ArrayExpression') {
13119
+ var _node_elements;
13120
+ result = [];
13121
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13122
+ try {
13123
+ for(var _iterator = ((_node_elements = node.elements) !== null && _node_elements !== void 0 ? _node_elements : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13124
+ var element = _step.value;
13125
+ if (!result) {
13126
+ break;
13127
+ }
13128
+ if (element == null) {
13129
+ result = null;
13130
+ } else if (element.type === 'SpreadElement') {
13131
+ var list = foldSpreadOperand(element.argument, frame, depth);
13132
+ result = list ? _to_consumable_array$2(result).concat(_to_consumable_array$2(list)) : null;
13133
+ } else {
13134
+ var frags = foldFrags(element, frame, depth + 1);
13135
+ result = frags ? _to_consumable_array$2(result).concat([
13136
+ frags
13137
+ ]) : null;
13138
+ }
13139
+ }
13140
+ } catch (err) {
13141
+ _didIteratorError = true;
13142
+ _iteratorError = err;
13143
+ } finally{
13144
+ try {
13145
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13146
+ _iterator.return();
13147
+ }
13148
+ } finally{
13149
+ if (_didIteratorError) {
13150
+ throw _iteratorError;
13151
+ }
13152
+ }
13153
+ }
13154
+ }
13155
+ return result;
13156
+ }
13157
+ /**
13158
+ * Returns true when a fragment stream is statically the empty string (no wildcards, no
13159
+ * literal characters) — `mergeSlashPaths`'s `.filter(Boolean)` drops such parts.
13160
+ *
13161
+ * @param frags - The fragment stream.
13162
+ * @returns True when the stream contributes nothing.
13163
+ */ function isStaticallyEmpty(frags) {
13164
+ return frags.every(function(frag) {
13165
+ return frag.kind === 'literal' && frag.value.length === 0;
13166
+ });
13167
+ }
13168
+ /**
13169
+ * Splits a fragment stream into path segments on `/` boundaries, collapsing empty segments
13170
+ * (so leading/trailing/duplicate slashes vanish, mirroring `mergeSlashPaths` /
13171
+ * `fixMultiSlashesInSlashPath`). A segment containing any wildcard is a wildcard segment.
13172
+ *
13173
+ * @param frags - The fragment stream.
13174
+ * @returns The folded segments.
13175
+ */ function fragsToSegments(frags) {
13176
+ var segments = [];
13177
+ var text = '';
13178
+ var wild = false;
13179
+ var flush = function flush() {
13180
+ if (wild) {
13181
+ segments.push({
13182
+ kind: 'wildcard',
13183
+ value: ''
13184
+ });
13185
+ } else if (text.length > 0) {
13186
+ segments.push({
13187
+ kind: 'literal',
13188
+ value: text
13189
+ });
13190
+ }
13191
+ text = '';
13192
+ wild = false;
13193
+ };
13194
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13195
+ try {
13196
+ for(var _iterator = frags[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13197
+ var frag = _step.value;
13198
+ if (frag.kind === 'wildcard') {
13199
+ wild = true;
13200
+ } else {
13201
+ var pieces = frag.value.split(PATH_SEPARATOR);
13202
+ text += pieces[0];
13203
+ for(var i = 1; i < pieces.length; i++){
13204
+ flush();
13205
+ text = pieces[i];
13206
+ }
13207
+ }
13208
+ }
13209
+ } catch (err) {
13210
+ _didIteratorError = true;
13211
+ _iteratorError = err;
13212
+ } finally{
13213
+ try {
13214
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13215
+ _iterator.return();
13216
+ }
13217
+ } finally{
13218
+ if (_didIteratorError) {
13219
+ throw _iteratorError;
13220
+ }
13221
+ }
13222
+ }
13223
+ flush();
13224
+ return segments;
13225
+ }
13226
+ /**
13227
+ * Finds a top-level `const`/`let`/`var` declarator's initializer by name in a Program,
13228
+ * looking through `export` wrappers. Used to resolve in-module path consts.
13229
+ *
13230
+ * @param programNode - The Program AST node.
13231
+ * @param name - The declarator name.
13232
+ * @returns The initializer node, or null.
13233
+ */ function findTopLevelConstInit(programNode, name) {
13234
+ var _ref;
13235
+ var result = null;
13236
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13237
+ try {
13238
+ for(var _iterator = ((_ref = programNode === null || programNode === void 0 ? void 0 : programNode.body) !== null && _ref !== void 0 ? _ref : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13239
+ var statement = _step.value;
13240
+ var declaration = (statement === null || statement === void 0 ? void 0 : statement.type) === 'ExportNamedDeclaration' ? statement.declaration : statement;
13241
+ if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'VariableDeclaration') {
13242
+ var _declaration_declarations;
13243
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
13244
+ try {
13245
+ for(var _iterator1 = ((_declaration_declarations = declaration.declarations) !== null && _declaration_declarations !== void 0 ? _declaration_declarations : [])[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13246
+ var declarator = _step1.value;
13247
+ var _declarator_id;
13248
+ if (((_declarator_id = declarator.id) === null || _declarator_id === void 0 ? void 0 : _declarator_id.type) === 'Identifier' && declarator.id.name === name && declarator.init) {
13249
+ result = declarator.init;
13250
+ }
13251
+ }
13252
+ } catch (err) {
13253
+ _didIteratorError1 = true;
13254
+ _iteratorError1 = err;
13255
+ } finally{
13256
+ try {
13257
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13258
+ _iterator1.return();
13259
+ }
13260
+ } finally{
13261
+ if (_didIteratorError1) {
13262
+ throw _iteratorError1;
13263
+ }
13264
+ }
13265
+ }
13266
+ }
13267
+ }
13268
+ } catch (err) {
13269
+ _didIteratorError = true;
13270
+ _iteratorError = err;
13271
+ } finally{
13272
+ try {
13273
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13274
+ _iterator.return();
13275
+ }
13276
+ } finally{
13277
+ if (_didIteratorError) {
13278
+ throw _iteratorError;
13279
+ }
13280
+ }
13281
+ }
13282
+ return result;
13283
+ }
13284
+ /**
13285
+ * Finds a top-level function-like binding by name in a Program (function declaration, or a
13286
+ * declarator whose initializer is an arrow / function expression), looking through `export`
13287
+ * wrappers.
13288
+ *
13289
+ * @param programNode - The Program AST node.
13290
+ * @param name - The binding name.
13291
+ * @returns The function-like node, or null.
13292
+ */ function findTopLevelFunction(programNode, name) {
13293
+ var _ref;
13294
+ var result = null;
13295
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13296
+ try {
13297
+ for(var _iterator = ((_ref = programNode === null || programNode === void 0 ? void 0 : programNode.body) !== null && _ref !== void 0 ? _ref : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13298
+ var statement = _step.value;
13299
+ var _declaration_id;
13300
+ var declaration = (statement === null || statement === void 0 ? void 0 : statement.type) === 'ExportNamedDeclaration' ? statement.declaration : statement;
13301
+ if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'FunctionDeclaration' && ((_declaration_id = declaration.id) === null || _declaration_id === void 0 ? void 0 : _declaration_id.name) === name) {
13302
+ result = declaration;
13303
+ } else if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'VariableDeclaration') {
13304
+ var _declaration_declarations;
13305
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
13306
+ try {
13307
+ for(var _iterator1 = ((_declaration_declarations = declaration.declarations) !== null && _declaration_declarations !== void 0 ? _declaration_declarations : [])[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13308
+ var declarator = _step1.value;
13309
+ var _declarator_id;
13310
+ var init = declarator.init ? unwrapTypeAssertion$1(declarator.init) : null;
13311
+ if (((_declarator_id = declarator.id) === null || _declarator_id === void 0 ? void 0 : _declarator_id.type) === 'Identifier' && declarator.id.name === name && ((init === null || init === void 0 ? void 0 : init.type) === 'ArrowFunctionExpression' || (init === null || init === void 0 ? void 0 : init.type) === 'FunctionExpression')) {
13312
+ result = init;
13313
+ }
13314
+ }
13315
+ } catch (err) {
13316
+ _didIteratorError1 = true;
13317
+ _iteratorError1 = err;
13318
+ } finally{
13319
+ try {
13320
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13321
+ _iterator1.return();
13322
+ }
13323
+ } finally{
13324
+ if (_didIteratorError1) {
13325
+ throw _iteratorError1;
13326
+ }
13327
+ }
13328
+ }
13329
+ }
13330
+ }
13331
+ } catch (err) {
13332
+ _didIteratorError = true;
13333
+ _iteratorError = err;
13334
+ } finally{
13335
+ try {
13336
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13337
+ _iterator.return();
13338
+ }
13339
+ } finally{
13340
+ if (_didIteratorError) {
13341
+ throw _iteratorError;
13342
+ }
13343
+ }
13344
+ }
13345
+ return result;
13346
+ }
13347
+ /**
13348
+ * Returns the function-like node for a resolved binding: a function declaration directly, or
13349
+ * the unwrapped arrow / function-expression initializer of a const declarator.
13350
+ *
13351
+ * @param node - The resolved binding node.
13352
+ * @returns The function-like node, or null.
13353
+ */ function functionFromBinding(node) {
13354
+ var result = null;
13355
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'FunctionDeclaration' || (node === null || node === void 0 ? void 0 : node.type) === 'ArrowFunctionExpression' || (node === null || node === void 0 ? void 0 : node.type) === 'FunctionExpression') {
13356
+ result = node;
13357
+ } else if ((node === null || node === void 0 ? void 0 : node.type) === 'VariableDeclarator' && node.init) {
13358
+ var init = unwrapTypeAssertion$1(node.init);
13359
+ if ((init === null || init === void 0 ? void 0 : init.type) === 'ArrowFunctionExpression' || (init === null || init === void 0 ? void 0 : init.type) === 'FunctionExpression') {
13360
+ result = init;
13361
+ }
13362
+ }
13363
+ return result;
13364
+ }
13365
+ /**
13366
+ * Returns the initializer of a resolved const binding (a declarator node, or an
13367
+ * already-initializer node), unwrapping type assertions.
13368
+ *
13369
+ * @param node - The resolved binding node.
13370
+ * @returns The initializer node, or null.
13371
+ */ function declaratorInit(node) {
13372
+ var result = null;
13373
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'VariableDeclarator' && node.init) {
13374
+ result = unwrapTypeAssertion$1(node.init);
13375
+ } else if (node) {
13376
+ result = unwrapTypeAssertion$1(node);
13377
+ }
13378
+ return result;
13379
+ }
13380
+ /**
13381
+ * Resolves an imported const/value binding to its declaration in another module.
13382
+ *
13383
+ * @param name - The identifier name.
13384
+ * @param referenceNode - The reference node (for type-checker mapping).
13385
+ * @param scope - The current scope.
13386
+ * @returns The resolved binding, or null.
13387
+ */ function resolveImported(name, referenceNode, scope) {
13388
+ var result = null;
13389
+ if (scope.resolver && scope.importRegistry.localToSource.has(name)) {
13390
+ result = scope.resolver.resolve(name, referenceNode, scope);
13391
+ }
13392
+ return result;
13393
+ }
13394
+ /**
13395
+ * Resolves a called function to its declaration: first in the current module, then via the
13396
+ * imported-binding resolver.
13397
+ *
13398
+ * @param name - The callee name.
13399
+ * @param calleeNode - The callee reference node.
13400
+ * @param scope - The current scope.
13401
+ * @returns The resolved binding, or null.
13402
+ */ function resolveFunctionBinding(name, calleeNode, scope) {
13403
+ var result = null;
13404
+ var local = findTopLevelFunction(scope.program, name);
13405
+ if (local) {
13406
+ result = {
13407
+ node: local,
13408
+ scope: scope
13409
+ };
13410
+ } else {
13411
+ result = resolveImported(name, calleeNode, scope);
13412
+ }
13413
+ return result;
13414
+ }
13415
+ /**
13416
+ * Resolves an identifier to the initializer of its `const` declaration: first a top-level const
13417
+ * in the current module, then an imported const in another module via the binding resolver. Reads
13418
+ * the AST initializer — not the checker's type — so annotated-widened / branded consts
13419
+ * (`X: BrandedMime = 'image/jpeg'`) still fold to their literal value.
13420
+ *
13421
+ * @param node - The identifier node.
13422
+ * @param scope - The current scope.
13423
+ * @returns The initializer node + declaring scope, or null when unresolvable.
13424
+ */ function resolveIdentifierInit(node, scope) {
13425
+ var result = null;
13426
+ var local = findTopLevelConstInit(scope.program, node.name);
13427
+ if (local) {
13428
+ result = {
13429
+ init: local,
13430
+ scope: scope
13431
+ };
13432
+ } else {
13433
+ var imported = resolveImported(node.name, node, scope);
13434
+ var init = imported ? declaratorInit(imported.node) : null;
13435
+ if (imported && init) {
13436
+ result = {
13437
+ init: init,
13438
+ scope: imported.scope
13439
+ };
13440
+ }
13441
+ }
13442
+ return result;
13443
+ }
13444
+ /**
13445
+ * Collapses a fragment stream to a concrete string, returning null when any fragment is a
13446
+ * wildcard (a param/runtime value) — a MIME literal or size constant must be fully known.
13447
+ *
13448
+ * @param frags - The fragment stream.
13449
+ * @returns The concrete string, or null when a wildcard is present.
13450
+ */ function fragsToConcreteString(frags) {
13451
+ var result = null;
13452
+ var text = '';
13453
+ var ok = true;
13454
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13455
+ try {
13456
+ for(var _iterator = frags[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13457
+ var frag = _step.value;
13458
+ if (frag.kind === 'wildcard') {
13459
+ ok = false;
13460
+ break;
13461
+ }
13462
+ text += frag.value;
13463
+ }
13464
+ } catch (err) {
13465
+ _didIteratorError = true;
13466
+ _iteratorError = err;
13467
+ } finally{
13468
+ try {
13469
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13470
+ _iterator.return();
13471
+ }
13472
+ } finally{
13473
+ if (_didIteratorError) {
13474
+ throw _iteratorError;
13475
+ }
13476
+ }
13477
+ }
13478
+ if (ok) {
13479
+ result = text;
13480
+ }
13481
+ return result;
13482
+ }
13483
+ /**
13484
+ * Folds an expression to a list of concrete strings: an inline array literal (each element folded
13485
+ * via {@link foldStringExpression}, spreads of statically-known lists expanded), or an identifier
13486
+ * resolving to such an array const (local or cross-module). Returns null when any element is
13487
+ * unfoldable, so a genuinely dynamic element (e.g. a function call) still surfaces as unresolvable.
13488
+ *
13489
+ * @param node - The expression node (e.g. an `allowedMimeTypes` value).
13490
+ * @param scope - The lexical scope the expression lives in.
13491
+ * @returns The folded string list, or null when unresolvable.
13492
+ */ function foldStringArrayExpression(node, scope) {
13493
+ return foldStringArray(node, scope, 0);
13494
+ }
13495
+ function foldStringArray(node, scope, depth) {
13496
+ var result = null;
13497
+ if (node && depth <= MAX_FOLD_DEPTH) {
13498
+ var unwrapped = unwrapTypeAssertion$1(node);
13499
+ if ((unwrapped === null || unwrapped === void 0 ? void 0 : unwrapped.type) === 'ArrayExpression') {
13500
+ var items = foldList(unwrapped, {
13501
+ scope: scope,
13502
+ env: new Map()
13503
+ }, depth);
13504
+ result = items ? fragListsToStrings(items) : null;
13505
+ } else if ((unwrapped === null || unwrapped === void 0 ? void 0 : unwrapped.type) === 'Identifier') {
13506
+ var resolved = resolveIdentifierInit(unwrapped, scope);
13507
+ result = resolved ? foldStringArray(resolved.init, resolved.scope, depth + 1) : null;
13508
+ }
13509
+ }
13510
+ return result;
13511
+ }
13512
+ function fragListsToStrings(items) {
13513
+ var result = [];
13514
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13515
+ try {
13516
+ for(var _iterator = items[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13517
+ var item = _step.value;
13518
+ if (!result) {
13519
+ break;
13520
+ }
13521
+ var str = fragsToConcreteString(item);
13522
+ result = str != null ? _to_consumable_array$2(result).concat([
13523
+ str
13524
+ ]) : null;
13525
+ }
13526
+ } catch (err) {
13527
+ _didIteratorError = true;
13528
+ _iteratorError = err;
13529
+ } finally{
13530
+ try {
13531
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13532
+ _iterator.return();
13533
+ }
13534
+ } finally{
13535
+ if (_didIteratorError) {
13536
+ throw _iteratorError;
13537
+ }
13538
+ }
13539
+ }
13540
+ return result;
13541
+ }
13542
+ /**
13543
+ * Folds a numeric expression to a number: literals, unary `-`/`+`, binary `*`/`+`/`-`/`/`,
13544
+ * type-assertion see-through, and identifiers resolving to a numeric `const` (local or
13545
+ * cross-module, read from the AST initializer). Returns null when any operand is unresolvable.
13546
+ *
13547
+ * @param node - The expression node (e.g. a `maxFileSizeBytes` value).
13548
+ * @param scope - The lexical scope the expression lives in.
13549
+ * @returns The folded number, or null when unresolvable.
13550
+ */ function foldNumericExpression(node, scope) {
13551
+ return foldNumeric(node, scope, 0);
13552
+ }
13553
+ function foldNumeric(node, scope, depth) {
13554
+ var result = null;
13555
+ if (node && depth <= MAX_FOLD_DEPTH) {
13556
+ if (node.type === 'Literal' && typeof node.value === 'number') {
13557
+ result = node.value;
13558
+ } else if (node.type === 'UnaryExpression' && (node.operator === '-' || node.operator === '+')) {
13559
+ result = foldNumericUnary(node, scope, depth);
13560
+ } else if (node.type === 'BinaryExpression') {
13561
+ result = foldNumericBinary(node, scope, depth);
13562
+ } else if ((node.type === 'TSAsExpression' || node.type === 'TSTypeAssertion' || node.type === 'TSNonNullExpression') && node.expression) {
13563
+ result = foldNumeric(node.expression, scope, depth + 1);
13564
+ } else if (node.type === 'Identifier') {
13565
+ var resolved = resolveIdentifierInit(node, scope);
13566
+ result = resolved ? foldNumeric(resolved.init, resolved.scope, depth + 1) : null;
13567
+ }
13568
+ }
13569
+ return result;
13570
+ }
13571
+ function foldNumericUnary(node, scope, depth) {
13572
+ var result = null;
13573
+ var arg = foldNumeric(node.argument, scope, depth + 1);
13574
+ if (typeof arg === 'number') {
13575
+ result = node.operator === '-' ? -arg : arg;
13576
+ }
13577
+ return result;
13578
+ }
13579
+ function foldNumericBinary(node, scope, depth) {
13580
+ var result = null;
13581
+ var left = foldNumeric(node.left, scope, depth + 1);
13582
+ var right = foldNumeric(node.right, scope, depth + 1);
13583
+ if (typeof left === 'number' && typeof right === 'number') {
13584
+ result = applyNumericOperator(node.operator, left, right);
13585
+ }
13586
+ return result;
13587
+ }
13588
+ function applyNumericOperator(operator, left, right) {
13589
+ var result = null;
13590
+ if (operator === '*') {
13591
+ result = left * right;
13592
+ } else if (operator === '+') {
13593
+ result = left + right;
13594
+ } else if (operator === '-') {
13595
+ result = left - right;
13596
+ } else if (operator === '/' && right !== 0) {
13597
+ result = left / right;
13598
+ }
13599
+ return result;
13600
+ }
13601
+ /**
13602
+ * Structurally compares a folded upload path against a Firebase rules match-path segment list
13603
+ * (`{var}` / `{var=**}` → wildcard, otherwise literal). Literal segments must match value;
13604
+ * wildcard segments compare equal to one another.
13605
+ *
13606
+ * @param folded - The folded upload path.
13607
+ * @param ruleSegments - The rules match-path segments.
13608
+ * @returns True when the two segment lists match position-for-position.
13609
+ */ function foldedPathMatchesRuleSegments(folded, ruleSegments) {
13610
+ var result = folded.segments.length === ruleSegments.length;
13611
+ for(var i = 0; result && i < folded.segments.length; i++){
13612
+ var a = folded.segments[i];
13613
+ var b = ruleSegments[i];
13614
+ if (a.kind !== b.kind) {
13615
+ result = false;
13616
+ } else if (a.kind === 'literal' && a.value !== b.value) {
13617
+ result = false;
13618
+ }
13619
+ }
13620
+ return result;
13621
+ }
13622
+ /**
13623
+ * Renders a folded path for diagnostics, e.g. `uploads/u/{*}/jr/{*}`.
13624
+ *
13625
+ * @param folded - The folded path.
13626
+ * @returns The display string.
13627
+ */ function describeFoldedPath(folded) {
13628
+ return folded.segments.map(function(segment) {
13629
+ return segment.kind === 'wildcard' ? '{*}' : segment.value;
13630
+ }).join(PATH_SEPARATOR);
13631
+ }
13632
+
13633
+ /**
13634
+ * Builds an {@link ImportedBindingResolver} backed by the TypeScript type checker, or null when
13635
+ * type information is unavailable (e.g. a lint config without `parserOptions.project`, or a
13636
+ * pure-AST test harness). The resolver performs a single hop: it maps an imported identifier in
13637
+ * the linted file to the declaration's source file, re-parses that file to ESTree (cached), and
13638
+ * returns the named binding plus that module's scope. Identifiers local to the resolved module
13639
+ * fold via the re-parsed program directly; transitive re-imports from a third module are not
13640
+ * followed.
13641
+ *
13642
+ * Every failure mode (no symbol, unreadable file, parse error, identifier from an already
13643
+ * re-parsed module) returns null so the analyzer falls back to reporting an unresolvable path —
13644
+ * it never throws into the lint pass.
13645
+ *
13646
+ * @param services - The parser services, when present.
13647
+ * @returns A resolver, or null when type information is unavailable.
13648
+ */ function createImportedBindingResolver(services) {
13649
+ var result = null;
13650
+ if ((services === null || services === void 0 ? void 0 : services.program) && services.esTreeNodeToTSNodeMap) {
13651
+ var moduleCache = new Map();
13652
+ result = {
13653
+ resolve: function resolve(name, referenceNode, fromScope) {
13654
+ return resolveBinding({
13655
+ name: name,
13656
+ referenceNode: referenceNode,
13657
+ fromScope: fromScope,
13658
+ services: services,
13659
+ moduleCache: moduleCache
13660
+ });
13661
+ }
13662
+ };
13663
+ }
13664
+ return result;
13665
+ }
13666
+ function resolveBinding(input) {
13667
+ var name = input.name, referenceNode = input.referenceNode, services = input.services, moduleCache = input.moduleCache;
13668
+ var result = null;
13669
+ try {
13670
+ var fileName = declarationSourceFile(referenceNode, services);
13671
+ if (fileName) {
13672
+ var parsedModule = loadModule(fileName, moduleCache);
13673
+ var node = parsedModule ? findExportedBinding(parsedModule.program, name) : null;
13674
+ if (parsedModule && node) {
13675
+ result = {
13676
+ node: node,
13677
+ scope: {
13678
+ program: parsedModule.program,
13679
+ importRegistry: parsedModule.importRegistry,
13680
+ resolver: input.fromScope.resolver
13681
+ }
13682
+ };
13683
+ }
13684
+ }
13685
+ } catch (unused) {
13686
+ result = null;
13687
+ }
13688
+ return result;
13689
+ }
13690
+ /**
13691
+ * Maps a reference identifier to the absolute path of its declaration's source file via the
13692
+ * type checker, following an import alias when present. Returns null when the reference is not
13693
+ * in the current file's node map (e.g. it came from an already re-parsed module) or has no
13694
+ * resolvable declaration.
13695
+ *
13696
+ * @param referenceNode - The ESTree reference node in the linted file.
13697
+ * @param services - The parser services.
13698
+ * @returns The declaration's source file path, or null.
13699
+ */ function declarationSourceFile(referenceNode, services) {
13700
+ var _ref;
13701
+ var _services_esTreeNodeToTSNodeMap;
13702
+ var result = null;
13703
+ var tsNode = (_ref = (_services_esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap) === null || _services_esTreeNodeToTSNodeMap === void 0 ? void 0 : _services_esTreeNodeToTSNodeMap.get(referenceNode)) !== null && _ref !== void 0 ? _ref : null;
13704
+ if (tsNode) {
13705
+ var _ref1, _ref2, _ref3, _ref4;
13706
+ var _services_program;
13707
+ var checker = (_services_program = services.program) === null || _services_program === void 0 ? void 0 : _services_program.getTypeChecker();
13708
+ var symbol = aliasedSymbol(checker, checker.getSymbolAtLocation(tsNode));
13709
+ var declarations = (_ref1 = symbol === null || symbol === void 0 ? void 0 : symbol.getDeclarations()) !== null && _ref1 !== void 0 ? _ref1 : null;
13710
+ var declaration = (_ref2 = (_ref3 = declarations === null || declarations === void 0 ? void 0 : declarations.find(function(decl) {
13711
+ return isValueDeclarationKind(decl.kind);
13712
+ })) !== null && _ref3 !== void 0 ? _ref3 : declarations === null || declarations === void 0 ? void 0 : declarations[0]) !== null && _ref2 !== void 0 ? _ref2 : null;
13713
+ result = (_ref4 = declaration === null || declaration === void 0 ? void 0 : declaration.getSourceFile().fileName) !== null && _ref4 !== void 0 ? _ref4 : null;
13714
+ }
13715
+ return result;
13716
+ }
13717
+ function aliasedSymbol(checker, symbol) {
13718
+ var result = symbol;
13719
+ if (symbol) {
13720
+ try {
13721
+ var _checker_getAliasedSymbol;
13722
+ result = (_checker_getAliasedSymbol = checker.getAliasedSymbol(symbol)) !== null && _checker_getAliasedSymbol !== void 0 ? _checker_getAliasedSymbol : symbol;
13723
+ } catch (unused) {
13724
+ result = symbol;
13725
+ }
13726
+ }
13727
+ return result;
13728
+ }
13729
+ /**
13730
+ * TS `SyntaxKind` values for the declarations we fold: `VariableDeclaration` (244) and
13731
+ * `FunctionDeclaration` (262) in TypeScript 5.x. Other kinds (interfaces, type aliases) carry no
13732
+ * foldable value.
13733
+ *
13734
+ * @param kind - The TS `SyntaxKind` numeric value.
13735
+ * @returns True when the declaration kind can carry a foldable value.
13736
+ */ function isValueDeclarationKind(kind) {
13737
+ return kind === 244 || kind === 262;
13738
+ }
13739
+ /**
13740
+ * Reads and parses a module to ESTree, indexing its imports, caching by absolute path. A
13741
+ * `null` cache entry records an unreadable/unparsable file so repeated lookups stay cheap.
13742
+ *
13743
+ * @param fileName - The absolute module path.
13744
+ * @param cache - The per-resolver module cache.
13745
+ * @returns The parsed module, or null.
13746
+ */ function loadModule(fileName, cache) {
13747
+ var result;
13748
+ if (cache.has(fileName)) {
13749
+ var _cache_get;
13750
+ result = (_cache_get = cache.get(fileName)) !== null && _cache_get !== void 0 ? _cache_get : null;
13751
+ } else {
13752
+ result = null;
13753
+ try {
13754
+ var _program_body;
13755
+ var source = node_fs.readFileSync(fileName, 'utf8');
13756
+ var program = typescriptEstree.parse(source, {
13757
+ range: true,
13758
+ loc: true,
13759
+ jsx: false
13760
+ });
13761
+ var importRegistry = createImportRegistry();
13762
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13763
+ try {
13764
+ for(var _iterator = ((_program_body = program.body) !== null && _program_body !== void 0 ? _program_body : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13765
+ var statement = _step.value;
13766
+ if ((statement === null || statement === void 0 ? void 0 : statement.type) === 'ImportDeclaration') {
13767
+ trackImportDeclaration(importRegistry, statement);
13768
+ }
13769
+ }
13770
+ } catch (err) {
13771
+ _didIteratorError = true;
13772
+ _iteratorError = err;
13773
+ } finally{
13774
+ try {
13775
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
13776
+ _iterator.return();
13777
+ }
13778
+ } finally{
13779
+ if (_didIteratorError) {
13780
+ throw _iteratorError;
13781
+ }
13782
+ }
13783
+ }
13784
+ result = {
13785
+ program: program,
13786
+ importRegistry: importRegistry
13787
+ };
13788
+ } catch (unused) {
13789
+ result = null;
13790
+ }
13791
+ cache.set(fileName, result);
13792
+ }
13793
+ return result;
13794
+ }
13795
+ /**
13796
+ * Finds the named top-level binding in a re-parsed module: the matching `VariableDeclarator`
13797
+ * (with initializer) or `FunctionDeclaration`, looking through `export` wrappers.
13798
+ *
13799
+ * @param programNode - The module's Program node.
13800
+ * @param name - The binding name.
13801
+ * @returns The binding node, or null.
13802
+ */ function findExportedBinding(programNode, name) {
13803
+ var _ref;
13804
+ var result = null;
13805
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13806
+ try {
13807
+ for(var _iterator = ((_ref = programNode === null || programNode === void 0 ? void 0 : programNode.body) !== null && _ref !== void 0 ? _ref : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13808
+ var statement = _step.value;
13809
+ var _declaration_id;
13810
+ var declaration = (statement === null || statement === void 0 ? void 0 : statement.type) === 'ExportNamedDeclaration' ? statement.declaration : statement;
13811
+ if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'FunctionDeclaration' && ((_declaration_id = declaration.id) === null || _declaration_id === void 0 ? void 0 : _declaration_id.name) === name) {
13812
+ result = declaration;
13813
+ } else if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'VariableDeclaration') {
13814
+ var _declaration_declarations;
13815
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
13816
+ try {
13817
+ for(var _iterator1 = ((_declaration_declarations = declaration.declarations) !== null && _declaration_declarations !== void 0 ? _declaration_declarations : [])[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13818
+ var declarator = _step1.value;
13819
+ var _declarator_id;
13820
+ if (((_declarator_id = declarator.id) === null || _declarator_id === void 0 ? void 0 : _declarator_id.type) === 'Identifier' && declarator.id.name === name && declarator.init) {
13821
+ result = declarator;
13822
+ }
13823
+ }
13824
+ } catch (err) {
13825
+ _didIteratorError1 = true;
13826
+ _iteratorError1 = err;
13827
+ } finally{
13828
+ try {
13829
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13830
+ _iterator1.return();
13831
+ }
13832
+ } finally{
13833
+ if (_didIteratorError1) {
13834
+ throw _iteratorError1;
13835
+ }
13836
+ }
13837
+ }
13838
+ }
13839
+ }
13840
+ } catch (err) {
13841
+ _didIteratorError = true;
13842
+ _iteratorError = err;
13843
+ } finally{
12581
13844
  try {
12582
13845
  if (!_iteratorNormalCompletion && _iterator.return != null) {
12583
13846
  _iterator.return();
@@ -12588,10 +13851,68 @@ function evaluateStringArrayLiteral(node) {
12588
13851
  }
12589
13852
  }
12590
13853
  }
12591
- return {
12592
- numericConstants: numericConstants,
12593
- stringArrayConstants: stringArrayConstants
12594
- };
13854
+ return result;
13855
+ }
13856
+
13857
+ /**
13858
+ * Default type name the rule looks for on top-level declarators. Variables whose type
13859
+ * annotation resolves to this identifier are treated as upload policies and validated
13860
+ * against `storage.rules`.
13861
+ */ var DEFAULT_STORAGE_FILE_UPLOAD_POLICY_TYPE_NAME = 'StorageFilePurposeUploadPolicy';
13862
+ /**
13863
+ * Default file name searched relative to the lint root when `storageRulesPath` is omitted.
13864
+ */ var DEFAULT_STORAGE_RULES_FILENAME = 'storage.rules';
13865
+ var rulesFileCache = new Map();
13866
+ /**
13867
+ * Reads and parses a `storage.rules` file, caching by absolute path so repeated rule
13868
+ * activations across files in the same lint pass don't re-read disk.
13869
+ *
13870
+ * @param absolutePath - Absolute path to the rules file.
13871
+ * @returns The parsed blocks, or null when the file cannot be read.
13872
+ */ function loadParsedRulesFromPath(absolutePath) {
13873
+ var result = null;
13874
+ var cached = rulesFileCache.get(absolutePath);
13875
+ if (cached) {
13876
+ result = cached;
13877
+ } else {
13878
+ try {
13879
+ var source = node_fs.readFileSync(absolutePath, 'utf8');
13880
+ var parsed = parseStorageRules(source);
13881
+ rulesFileCache.set(absolutePath, parsed);
13882
+ result = parsed;
13883
+ } catch (unused) {
13884
+ result = null;
13885
+ }
13886
+ }
13887
+ return result;
13888
+ }
13889
+ /**
13890
+ * Extracts the cross-reference key used to pair a policy with its `storage.rules` `Mirrors`
13891
+ * block.
13892
+ *
13893
+ * - When `purpose` is an `Identifier`, the constant name (e.g. `USER_AVATAR_PURPOSE`) is the
13894
+ * key — this is what `// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[USER_AVATAR_PURPOSE]`
13895
+ * comments reference.
13896
+ * - When `purpose` is a string literal, the literal value is used so a policy that inlines
13897
+ * `purpose: 'avatar'` can still pair with `Mirrors ...[avatar]`.
13898
+ * - `TSAsExpression` is unwrapped transparently.
13899
+ * - Anything else (computed expression, member access, function call) returns null and
13900
+ * triggers `unresolvedPolicyField`.
13901
+ *
13902
+ * @param node - The expression node for the policy's `purpose` field.
13903
+ * @returns The mirror-cross-reference key, or null when unresolvable.
13904
+ */ function extractPolicyKey(node) {
13905
+ var result = null;
13906
+ if (node) {
13907
+ if (node.type === 'Identifier') {
13908
+ result = node.name;
13909
+ } else if (node.type === 'Literal' && typeof node.value === 'string') {
13910
+ result = node.value;
13911
+ } else if (node.type === 'TSAsExpression' && node.expression) {
13912
+ result = extractPolicyKey(node.expression);
13913
+ }
13914
+ }
13915
+ return result;
12595
13916
  }
12596
13917
  /**
12597
13918
  * Collects every `VariableDeclarator` directly under the Program body, looking through
@@ -12705,18 +14026,24 @@ function unwrapVariableDeclaration$1(statement) {
12705
14026
  return matched;
12706
14027
  }
12707
14028
  /**
12708
- * Pulls `purpose`, `maxFileSizeBytes`, and `allowedMimeTypes` from a policy declarator's
12709
- * object literal, folding numeric / string / string-array references via `constants`.
14029
+ * Pulls `purpose`, `maxFileSizeBytes`, and `allowedMimeTypes` from a policy declarator's object
14030
+ * literal. `maxFileSizeBytes` and `allowedMimeTypes` are folded with the same scope-based scalar
14031
+ * folders the path evaluator uses, so an imported / annotated-widened const (e.g. a branded MIME
14032
+ * constant from `@dereekb/util`) resolves to its literal value via the AST initializer rather than
14033
+ * bailing on the checker's widened type.
12710
14034
  *
12711
14035
  * @param declarator - The policy declarator (e.g. `USER_AVATAR_UPLOAD_POLICY = {...}`).
12712
- * @param constants - The Program constants index.
14036
+ * @param scope - The fold scope (import registry + cross-module resolver) for the linted file.
12713
14037
  * @returns The resolved policy with folded values.
12714
- */ function buildResolvedPolicy(declarator, constants) {
14038
+ */ function buildResolvedPolicy(declarator, scope) {
14039
+ var _declarator_id;
12715
14040
  var init = declarator.init;
12716
14041
  while((init === null || init === void 0 ? void 0 : init.type) === 'TSAsExpression'){
12717
14042
  init = init.expression;
12718
14043
  }
14044
+ var declaratorName = ((_declarator_id = declarator.id) === null || _declarator_id === void 0 ? void 0 : _declarator_id.type) === 'Identifier' ? declarator.id.name : null;
12719
14045
  var policyKey = null;
14046
+ var buildUploadPathNode = null;
12720
14047
  var maxFileSizeBytes = null;
12721
14048
  var allowedMimeTypes = null;
12722
14049
  if ((init === null || init === void 0 ? void 0 : init.type) === 'ObjectExpression') {
@@ -12729,10 +14056,12 @@ function unwrapVariableDeclaration$1(statement) {
12729
14056
  if (property.type === 'Property' && ((_property_key = property.key) === null || _property_key === void 0 ? void 0 : _property_key.type) === 'Identifier' && !property.computed) {
12730
14057
  if (property.key.name === 'purpose') {
12731
14058
  policyKey = extractPolicyKey(property.value);
14059
+ } else if (property.key.name === 'buildUploadPath') {
14060
+ buildUploadPathNode = property.value;
12732
14061
  } else if (property.key.name === 'maxFileSizeBytes') {
12733
- maxFileSizeBytes = evaluateNumericNode(property.value, constants.numericConstants);
14062
+ maxFileSizeBytes = foldNumericExpression(property.value, scope);
12734
14063
  } else if (property.key.name === 'allowedMimeTypes') {
12735
- allowedMimeTypes = evaluateStringArrayNode(property.value, constants.stringArrayConstants);
14064
+ allowedMimeTypes = foldStringArrayExpression(property.value, scope);
12736
14065
  }
12737
14066
  }
12738
14067
  }
@@ -12753,7 +14082,9 @@ function unwrapVariableDeclaration$1(statement) {
12753
14082
  }
12754
14083
  return {
12755
14084
  policyKey: policyKey,
14085
+ declaratorName: declaratorName,
12756
14086
  policyDeclaratorNode: declarator,
14087
+ buildUploadPathNode: buildUploadPathNode,
12757
14088
  maxFileSizeBytes: maxFileSizeBytes,
12758
14089
  allowedMimeTypes: allowedMimeTypes
12759
14090
  };
@@ -12847,17 +14178,25 @@ function unwrapVariableDeclaration$1(statement) {
12847
14178
  }
12848
14179
  /**
12849
14180
  * ESLint rule that cross-checks every `StorageFilePurposeUploadPolicy`-typed declaration in
12850
- * a `*-firebase` component against the workspace's `storage.rules`. Each policy must have a
12851
- * paired `// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[<KEY>]` match block whose
12852
- * `request.resource.size` cap and `request.resource.contentType` predicate are at least as
12853
- * permissive as the TypeScript policy's `maxFileSizeBytes` and `allowedMimeTypes`.
14181
+ * a `*-firebase` component against the workspace's `storage.rules`. The policy's
14182
+ * `buildUploadPath` builder is statically folded to a concrete path template (an ordered list
14183
+ * of literal / wildcard segments) and paired with the `storage.rules` `allow write` match
14184
+ * block at the same path. On the paired block the `request.resource.size` cap and
14185
+ * `request.resource.contentType` predicate must be at least as permissive as the policy's
14186
+ * `maxFileSizeBytes` and `allowedMimeTypes`.
14187
+ *
14188
+ * Pairing is derived from the resolved path — not a marker comment — so the linker proves the
14189
+ * policy's actual upload path lands in the rules block rather than trusting an unchecked
14190
+ * assertion. When the builder cannot be folded (unknown const, unmodeled call, runtime value)
14191
+ * the rule reports `unresolvablePolicyPath` and never guesses; genuinely dynamic builders opt
14192
+ * out via `allowUnresolvablePolicies`.
12854
14193
  *
12855
14194
  * Reports on the TS side so drift surfaces in the normal lint pipeline; mismatches almost
12856
14195
  * always originate from editing one side and forgetting the other.
12857
14196
  *
12858
14197
  * @example
12859
14198
  * ```ts
12860
- * // OK — storage.rules has `Mirrors ...[USER_AVATAR_PURPOSE]` block with matching constraints
14199
+ * // OK — storage.rules has `match /uploads/u/{uid}/avatar.img` with matching constraints
12861
14200
  * export const USER_AVATAR_UPLOAD_POLICY: StorageFilePurposeUploadPolicy = {
12862
14201
  * purpose: USER_AVATAR_PURPOSE,
12863
14202
  * allowedMimeTypes: ['image/jpeg', 'image/png'],
@@ -12875,13 +14214,13 @@ function unwrapVariableDeclaration$1(statement) {
12875
14214
  recommended: true
12876
14215
  },
12877
14216
  messages: {
12878
- maxFileSizeMismatch: "Upload policy '{{policy}}' has maxFileSizeBytes {{tsValue}} but storage.rules allows < {{rulesValue}} for MIME type '{{mime}}'. Update either side so the rules cap matches or exceeds the policy cap.",
12879
- mimeTypeNotAllowed: "Upload policy '{{policy}}' allows MIME type '{{mime}}' but no storage.rules branch under 'Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[{{policy}}]' accepts it.",
12880
- missingRuleBlock: "Upload policy '{{policy}}' has no matching '// Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[{{policy}}]' block in storage.rules at {{path}}.",
12881
- orphanRuleBlock: "storage.rules block 'Mirrors STORAGE_FILE_PURPOSE_UPLOAD_POLICIES[{{policy}}]' (line {{line}}) has no matching StorageFilePurposeUploadPolicy declaration in this file.",
12882
- unsupportedRuleShape: "storage.rules block for '{{policy}}' (line {{line}}) could not be parsed: {{reason}}. Refactor the rule or extend the validator.",
14217
+ maxFileSizeMismatch: "Upload policy '{{policy}}' has maxFileSizeBytes {{tsValue}} but storage.rules allows < {{rulesValue}} for MIME type '{{mime}}' at path '{{path}}'. Update either side so the rules cap matches or exceeds the policy cap.",
14218
+ mimeTypeNotAllowed: "Upload policy '{{policy}}' allows MIME type '{{mime}}' but no storage.rules branch at path '{{path}}' accepts it.",
14219
+ noMatchingRuleBlock: "Upload policy '{{policy}}' resolves to upload path '{{path}}' but storage.rules has no matching `allow write` match block. Add a match block for that path or fix the path builder.",
14220
+ unsupportedRuleShape: "storage.rules block at path '{{path}}' (line {{line}}) could not be parsed: {{reason}}. Refactor the rule or extend the validator.",
12883
14221
  rulesFileMissing: 'Could not read storage.rules at {{path}}. Set the rule option `storageRulesPath` or place the file at the workspace root.',
12884
- unresolvedPolicyField: 'Upload policy{{policyLabel}} has unresolvable {{field}}; the rule cannot statically fold the value to compare against storage.rules.'
14222
+ unresolvedPolicyField: 'Upload policy{{policyLabel}} has unresolvable {{field}}; the rule cannot statically fold the value to compare against storage.rules.',
14223
+ unresolvablePolicyPath: "Upload policy '{{policy}}' has a buildUploadPath that cannot be statically folded to a concrete path: {{reason}}. Make the builder a composition of literals, consts, and @dereekb/util path combinators, or add the purpose/declarator name to the `allowUnresolvablePolicies` option."
12885
14224
  },
12886
14225
  schema: [
12887
14226
  {
@@ -12896,54 +14235,116 @@ function unwrapVariableDeclaration$1(statement) {
12896
14235
  },
12897
14236
  policyTypeName: {
12898
14237
  type: 'string'
14238
+ },
14239
+ allowUnresolvablePolicies: {
14240
+ type: 'array',
14241
+ items: {
14242
+ type: 'string'
14243
+ }
12899
14244
  }
12900
14245
  }
12901
14246
  }
12902
14247
  ]
12903
14248
  },
12904
14249
  create: function create(context) {
12905
- var _context_options_, _options_policyTypeName, _context_cwd;
14250
+ var _context_options_, _options_policyTypeName, _context_cwd, _options_allowUnresolvablePolicies;
12906
14251
  var options = (_context_options_ = context.options[0]) !== null && _context_options_ !== void 0 ? _context_options_ : {};
12907
14252
  var policyTypeName = (_options_policyTypeName = options.policyTypeName) !== null && _options_policyTypeName !== void 0 ? _options_policyTypeName : DEFAULT_STORAGE_FILE_UPLOAD_POLICY_TYPE_NAME;
12908
14253
  var cwd = (_context_cwd = context.cwd) !== null && _context_cwd !== void 0 ? _context_cwd : process.cwd();
14254
+ var allowUnresolvable = new Set((_options_allowUnresolvablePolicies = options.allowUnresolvablePolicies) !== null && _options_allowUnresolvablePolicies !== void 0 ? _options_allowUnresolvablePolicies : []);
12909
14255
  return {
12910
14256
  Program: function Program(programNode) {
12911
- var _rulesResolution_blocks, _rulesResolution_absolutePath;
14257
+ var _rulesResolution_blocks;
12912
14258
  var typedDeclarators = collectTypedPolicyDeclarators(programNode, policyTypeName);
12913
14259
  if (typedDeclarators.length === 0) return;
12914
14260
  var rulesResolution = loadParsedRules(options, cwd);
12915
14261
  if (rulesResolution.error) {
12916
- var _rulesResolution_absolutePath1;
14262
+ var _rulesResolution_absolutePath;
12917
14263
  context.report({
12918
14264
  node: typedDeclarators[0],
12919
14265
  messageId: 'rulesFileMissing',
12920
14266
  data: {
12921
- path: (_rulesResolution_absolutePath1 = rulesResolution.absolutePath) !== null && _rulesResolution_absolutePath1 !== void 0 ? _rulesResolution_absolutePath1 : DEFAULT_STORAGE_RULES_FILENAME
14267
+ path: (_rulesResolution_absolutePath = rulesResolution.absolutePath) !== null && _rulesResolution_absolutePath !== void 0 ? _rulesResolution_absolutePath : DEFAULT_STORAGE_RULES_FILENAME
12922
14268
  }
12923
14269
  });
12924
14270
  return;
12925
14271
  }
12926
14272
  var parsedBlocks = (_rulesResolution_blocks = rulesResolution.blocks) !== null && _rulesResolution_blocks !== void 0 ? _rulesResolution_blocks : [];
12927
- var constants = indexProgramConstants(programNode);
14273
+ var scope = buildFoldScope(programNode, context);
12928
14274
  var resolvedPolicies = typedDeclarators.map(function(declarator) {
12929
- return buildResolvedPolicy(declarator, constants);
12930
- });
12931
- compareResolvedPolicies({
12932
- resolvedPolicies: resolvedPolicies,
12933
- parsedBlocks: parsedBlocks,
12934
- rulesPath: (_rulesResolution_absolutePath = rulesResolution.absolutePath) !== null && _rulesResolution_absolutePath !== void 0 ? _rulesResolution_absolutePath : DEFAULT_STORAGE_RULES_FILENAME,
12935
- context: context
12936
- });
12937
- reportOrphanRuleBlocks({
12938
- parsedBlocks: parsedBlocks,
12939
- resolvedPolicies: resolvedPolicies,
12940
- programNode: programNode,
12941
- context: context
14275
+ return buildResolvedPolicy(declarator, scope);
12942
14276
  });
14277
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
14278
+ try {
14279
+ for(var _iterator = resolvedPolicies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
14280
+ var policy = _step.value;
14281
+ evaluatePolicy({
14282
+ policy: policy,
14283
+ parsedBlocks: parsedBlocks,
14284
+ scope: scope,
14285
+ allowUnresolvable: allowUnresolvable,
14286
+ context: context
14287
+ });
14288
+ }
14289
+ } catch (err) {
14290
+ _didIteratorError = true;
14291
+ _iteratorError = err;
14292
+ } finally{
14293
+ try {
14294
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
14295
+ _iterator.return();
14296
+ }
14297
+ } finally{
14298
+ if (_didIteratorError) {
14299
+ throw _iteratorError;
14300
+ }
14301
+ }
14302
+ }
12943
14303
  }
12944
14304
  };
12945
14305
  }
12946
14306
  };
14307
+ /**
14308
+ * Builds the {@link FoldScope} for the linted file: the module's import registry plus a
14309
+ * type-checker-backed cross-module resolver when parser services are available (a no-op
14310
+ * resolver otherwise, so pure-AST folding still works).
14311
+ *
14312
+ * @param programNode - The Program AST node.
14313
+ * @param context - The ESLint rule context.
14314
+ * @returns The fold scope.
14315
+ */ function buildFoldScope(programNode, context) {
14316
+ var _programNode_body, _ref, _ref1;
14317
+ var _context_sourceCode;
14318
+ var importRegistry = createImportRegistry();
14319
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
14320
+ try {
14321
+ for(var _iterator = ((_programNode_body = programNode.body) !== null && _programNode_body !== void 0 ? _programNode_body : [])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
14322
+ var statement = _step.value;
14323
+ if ((statement === null || statement === void 0 ? void 0 : statement.type) === 'ImportDeclaration') {
14324
+ trackImportDeclaration(importRegistry, statement);
14325
+ }
14326
+ }
14327
+ } catch (err) {
14328
+ _didIteratorError = true;
14329
+ _iteratorError = err;
14330
+ } finally{
14331
+ try {
14332
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
14333
+ _iterator.return();
14334
+ }
14335
+ } finally{
14336
+ if (_didIteratorError) {
14337
+ throw _iteratorError;
14338
+ }
14339
+ }
14340
+ }
14341
+ var services = (_ref = (_ref1 = (_context_sourceCode = context.sourceCode) === null || _context_sourceCode === void 0 ? void 0 : _context_sourceCode.parserServices) !== null && _ref1 !== void 0 ? _ref1 : context.parserServices) !== null && _ref !== void 0 ? _ref : null;
14342
+ return {
14343
+ program: programNode,
14344
+ importRegistry: importRegistry,
14345
+ resolver: createImportedBindingResolver(services)
14346
+ };
14347
+ }
12947
14348
  /**
12948
14349
  * Loads parsed `storage.rules` blocks from either the inline `virtualStorageRules` option
12949
14350
  * (used by specs) or the resolved rules-file path.
@@ -12975,17 +14376,123 @@ function unwrapVariableDeclaration$1(statement) {
12975
14376
  return result;
12976
14377
  }
12977
14378
  /**
12978
- * Reports each resolved policy that mismatches the parsed `storage.rules` blocks.
14379
+ * Returns the human-readable label for a policy in diagnostics: its `purpose` key, else its
14380
+ * declarator name, else a placeholder.
14381
+ *
14382
+ * @param policy - The resolved policy.
14383
+ * @returns The display label.
14384
+ */ function policyLabelOf(policy) {
14385
+ var _ref, _policy_policyKey;
14386
+ return (_ref = (_policy_policyKey = policy.policyKey) !== null && _policy_policyKey !== void 0 ? _policy_policyKey : policy.declaratorName) !== null && _ref !== void 0 ? _ref : '(anonymous policy)';
14387
+ }
14388
+ /**
14389
+ * Returns true when a policy is opted out of path folding via `allowUnresolvablePolicies`
14390
+ * (matched by `purpose` key or declarator name).
14391
+ *
14392
+ * @param policy - The resolved policy.
14393
+ * @param allowUnresolvable - The opt-out set.
14394
+ * @returns True when the policy is exempt from `unresolvablePolicyPath`.
14395
+ */ function isPolicyOptedOut(policy, allowUnresolvable) {
14396
+ return typeof policy.policyKey === 'string' && allowUnresolvable.has(policy.policyKey) || typeof policy.declaratorName === 'string' && allowUnresolvable.has(policy.declaratorName);
14397
+ }
14398
+ /**
14399
+ * Folds one policy's `buildUploadPath`, pairs it with the matching `storage.rules` leaf block
14400
+ * by path, then cross-checks the block's size + MIME constraints. Reports the first failure on
14401
+ * the policy declarator; an unfoldable builder reports `unresolvablePolicyPath` unless opted out.
14402
+ *
14403
+ * @param input - The policy, parsed blocks, fold scope, opt-out set, and ESLint context.
14404
+ */ function evaluatePolicy(input) {
14405
+ var policy = input.policy, parsedBlocks = input.parsedBlocks, scope = input.scope, allowUnresolvable = input.allowUnresolvable, context = input.context;
14406
+ var label = policyLabelOf(policy);
14407
+ var fold = policy.buildUploadPathNode ? foldUploadPath(policy.buildUploadPathNode, scope) : {
14408
+ ok: false,
14409
+ reason: 'policy has no buildUploadPath property'
14410
+ };
14411
+ if (!fold.ok) {
14412
+ if (!isPolicyOptedOut(policy, allowUnresolvable)) {
14413
+ context.report({
14414
+ node: policy.policyDeclaratorNode,
14415
+ messageId: 'unresolvablePolicyPath',
14416
+ data: {
14417
+ policy: label,
14418
+ reason: fold.reason
14419
+ }
14420
+ });
14421
+ }
14422
+ return;
14423
+ }
14424
+ var folded = fold.path;
14425
+ var pathDisplay = describeFoldedPath(folded);
14426
+ var block = findMatchingBlock(parsedBlocks, folded);
14427
+ if (!block) {
14428
+ context.report({
14429
+ node: policy.policyDeclaratorNode,
14430
+ messageId: 'noMatchingRuleBlock',
14431
+ data: {
14432
+ policy: label,
14433
+ path: pathDisplay
14434
+ }
14435
+ });
14436
+ return;
14437
+ }
14438
+ if (block.unsupported) {
14439
+ context.report({
14440
+ node: policy.policyDeclaratorNode,
14441
+ messageId: 'unsupportedRuleShape',
14442
+ data: {
14443
+ path: pathDisplay,
14444
+ line: String(block.sourceLine),
14445
+ reason: block.unsupported
14446
+ }
14447
+ });
14448
+ return;
14449
+ }
14450
+ if (typeof policy.maxFileSizeBytes !== 'number') {
14451
+ context.report({
14452
+ node: policy.policyDeclaratorNode,
14453
+ messageId: 'unresolvedPolicyField',
14454
+ data: {
14455
+ policyLabel: " '".concat(label, "'"),
14456
+ field: 'maxFileSizeBytes'
14457
+ }
14458
+ });
14459
+ return;
14460
+ }
14461
+ if (!policy.allowedMimeTypes) {
14462
+ context.report({
14463
+ node: policy.policyDeclaratorNode,
14464
+ messageId: 'unresolvedPolicyField',
14465
+ data: {
14466
+ policyLabel: " '".concat(label, "'"),
14467
+ field: 'allowedMimeTypes'
14468
+ }
14469
+ });
14470
+ return;
14471
+ }
14472
+ comparePolicyToBlock({
14473
+ policyLabel: label,
14474
+ pathDisplay: pathDisplay,
14475
+ policy: policy,
14476
+ block: block,
14477
+ context: context
14478
+ });
14479
+ }
14480
+ /**
14481
+ * Finds the first parsed leaf block whose match path structurally matches the folded upload
14482
+ * path (literal==literal, wildcard=={var}).
12979
14483
  *
12980
- * @param input - Bundle of resolved policies, parsed blocks, rules path, and ESLint context.
12981
- */ function compareResolvedPolicies(input) {
12982
- var resolvedPolicies = input.resolvedPolicies, parsedBlocks = input.parsedBlocks, rulesPath = input.rulesPath, context = input.context;
12983
- var blocksByKey = new Map();
14484
+ * @param parsedBlocks - The parsed leaf blocks.
14485
+ * @param folded - The folded upload path.
14486
+ * @returns The matching block, or null.
14487
+ */ function findMatchingBlock(parsedBlocks, folded) {
14488
+ var result = null;
12984
14489
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
12985
14490
  try {
12986
14491
  for(var _iterator = parsedBlocks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
12987
14492
  var block = _step.value;
12988
- blocksByKey.set(block.mirrorsPolicyKey, block);
14493
+ if (!result && foldedPathMatchesRuleSegments(folded, rulesMatchPathToSegments(block.matchPath))) {
14494
+ result = block;
14495
+ }
12989
14496
  }
12990
14497
  } catch (err) {
12991
14498
  _didIteratorError = true;
@@ -12996,102 +14503,20 @@ function unwrapVariableDeclaration$1(statement) {
12996
14503
  _iterator.return();
12997
14504
  }
12998
14505
  } finally{
12999
- if (_didIteratorError) {
13000
- throw _iteratorError;
13001
- }
13002
- }
13003
- }
13004
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
13005
- try {
13006
- for(var _iterator1 = resolvedPolicies[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13007
- var policy = _step1.value;
13008
- if (typeof policy.policyKey !== 'string') {
13009
- context.report({
13010
- node: policy.policyDeclaratorNode,
13011
- messageId: 'unresolvedPolicyField',
13012
- data: {
13013
- policyLabel: '',
13014
- field: 'purpose'
13015
- }
13016
- });
13017
- continue;
13018
- }
13019
- var policyKey = policy.policyKey;
13020
- var block1 = blocksByKey.get(policyKey);
13021
- if (!block1) {
13022
- context.report({
13023
- node: policy.policyDeclaratorNode,
13024
- messageId: 'missingRuleBlock',
13025
- data: {
13026
- policy: policyKey,
13027
- path: rulesPath
13028
- }
13029
- });
13030
- continue;
13031
- }
13032
- if (block1.unsupported) {
13033
- context.report({
13034
- node: policy.policyDeclaratorNode,
13035
- messageId: 'unsupportedRuleShape',
13036
- data: {
13037
- policy: policyKey,
13038
- line: String(block1.sourceLine),
13039
- reason: block1.unsupported
13040
- }
13041
- });
13042
- continue;
13043
- }
13044
- if (typeof policy.maxFileSizeBytes !== 'number') {
13045
- context.report({
13046
- node: policy.policyDeclaratorNode,
13047
- messageId: 'unresolvedPolicyField',
13048
- data: {
13049
- policyLabel: " '".concat(policyKey, "'"),
13050
- field: 'maxFileSizeBytes'
13051
- }
13052
- });
13053
- continue;
13054
- }
13055
- if (!policy.allowedMimeTypes) {
13056
- context.report({
13057
- node: policy.policyDeclaratorNode,
13058
- messageId: 'unresolvedPolicyField',
13059
- data: {
13060
- policyLabel: " '".concat(policyKey, "'"),
13061
- field: 'allowedMimeTypes'
13062
- }
13063
- });
13064
- continue;
13065
- }
13066
- comparePolicyToBlock({
13067
- policyKey: policyKey,
13068
- policy: policy,
13069
- block: block1,
13070
- context: context
13071
- });
13072
- }
13073
- } catch (err) {
13074
- _didIteratorError1 = true;
13075
- _iteratorError1 = err;
13076
- } finally{
13077
- try {
13078
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13079
- _iterator1.return();
13080
- }
13081
- } finally{
13082
- if (_didIteratorError1) {
13083
- throw _iteratorError1;
14506
+ if (_didIteratorError) {
14507
+ throw _iteratorError;
13084
14508
  }
13085
14509
  }
13086
14510
  }
14511
+ return result;
13087
14512
  }
13088
14513
  /**
13089
14514
  * Validates that each MIME the policy permits is accepted by at least one branch and that
13090
14515
  * the branch's size cap is ≥ the policy cap. Emits ESLint reports for any mismatch.
13091
14516
  *
13092
- * @param input - Policy/block pair plus the ESLint context.
14517
+ * @param input - Policy/block pair, the display path, and the ESLint context.
13093
14518
  */ function comparePolicyToBlock(input) {
13094
- var policyKey = input.policyKey, policy = input.policy, block = input.block, context = input.context;
14519
+ var policyLabel = input.policyLabel, pathDisplay = input.pathDisplay, policy = input.policy, block = input.block, context = input.context;
13095
14520
  var tsCap = policy.maxFileSizeBytes;
13096
14521
  var mimes = policy.allowedMimeTypes;
13097
14522
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -13104,8 +14529,9 @@ function unwrapVariableDeclaration$1(statement) {
13104
14529
  node: policy.policyDeclaratorNode,
13105
14530
  messageId: 'mimeTypeNotAllowed',
13106
14531
  data: {
13107
- policy: policyKey,
13108
- mime: mime
14532
+ policy: policyLabel,
14533
+ mime: mime,
14534
+ path: pathDisplay
13109
14535
  }
13110
14536
  });
13111
14537
  } else {
@@ -13137,10 +14563,11 @@ function unwrapVariableDeclaration$1(statement) {
13137
14563
  node: policy.policyDeclaratorNode,
13138
14564
  messageId: 'maxFileSizeMismatch',
13139
14565
  data: {
13140
- policy: policyKey,
14566
+ policy: policyLabel,
13141
14567
  tsValue: String(tsCap),
13142
14568
  rulesValue: String(largest),
13143
- mime: mime
14569
+ mime: mime,
14570
+ path: pathDisplay
13144
14571
  }
13145
14572
  });
13146
14573
  }
@@ -13161,75 +14588,14 @@ function unwrapVariableDeclaration$1(statement) {
13161
14588
  }
13162
14589
  }
13163
14590
  }
13164
- /**
13165
- * Reports each parsed rules block whose `mirrorsPolicyKey` has no corresponding typed
13166
- * declaration in this file — signals stale `Mirrors ...` markers left over after a policy
13167
- * was removed.
13168
- *
13169
- * @param input - Parsed blocks, resolved policies, program node, and ESLint context.
13170
- */ function reportOrphanRuleBlocks(input) {
13171
- var parsedBlocks = input.parsedBlocks, resolvedPolicies = input.resolvedPolicies, programNode = input.programNode, context = input.context;
13172
- var knownKeys = new Set();
13173
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13174
- try {
13175
- for(var _iterator = resolvedPolicies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13176
- var policy = _step.value;
13177
- if (typeof policy.policyKey === 'string') {
13178
- knownKeys.add(policy.policyKey);
13179
- }
13180
- }
13181
- } catch (err) {
13182
- _didIteratorError = true;
13183
- _iteratorError = err;
13184
- } finally{
13185
- try {
13186
- if (!_iteratorNormalCompletion && _iterator.return != null) {
13187
- _iterator.return();
13188
- }
13189
- } finally{
13190
- if (_didIteratorError) {
13191
- throw _iteratorError;
13192
- }
13193
- }
13194
- }
13195
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
13196
- try {
13197
- for(var _iterator1 = parsedBlocks[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13198
- var block = _step1.value;
13199
- if (!knownKeys.has(block.mirrorsPolicyKey)) {
13200
- context.report({
13201
- node: programNode,
13202
- messageId: 'orphanRuleBlock',
13203
- data: {
13204
- policy: block.mirrorsPolicyKey,
13205
- line: String(block.sourceLine)
13206
- }
13207
- });
13208
- }
13209
- }
13210
- } catch (err) {
13211
- _didIteratorError1 = true;
13212
- _iteratorError1 = err;
13213
- } finally{
13214
- try {
13215
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13216
- _iterator1.return();
13217
- }
13218
- } finally{
13219
- if (_didIteratorError1) {
13220
- throw _iteratorError1;
13221
- }
13222
- }
13223
- }
13224
- }
13225
14591
 
13226
- function _array_like_to_array$2(arr, len) {
14592
+ function _array_like_to_array$3(arr, len) {
13227
14593
  if (len == null || len > arr.length) len = arr.length;
13228
14594
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
13229
14595
  return arr2;
13230
14596
  }
13231
14597
  function _array_without_holes$1(arr) {
13232
- if (Array.isArray(arr)) return _array_like_to_array$2(arr);
14598
+ if (Array.isArray(arr)) return _array_like_to_array$3(arr);
13233
14599
  }
13234
14600
  function _iterable_to_array$1(iter) {
13235
14601
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
@@ -13238,15 +14604,15 @@ function _non_iterable_spread$1() {
13238
14604
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
13239
14605
  }
13240
14606
  function _to_consumable_array$1(arr) {
13241
- return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$2(arr) || _non_iterable_spread$1();
14607
+ return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$3(arr) || _non_iterable_spread$1();
13242
14608
  }
13243
- function _unsupported_iterable_to_array$2(o, minLen) {
14609
+ function _unsupported_iterable_to_array$3(o, minLen) {
13244
14610
  if (!o) return;
13245
- if (typeof o === "string") return _array_like_to_array$2(o, minLen);
14611
+ if (typeof o === "string") return _array_like_to_array$3(o, minLen);
13246
14612
  var n = Object.prototype.toString.call(o).slice(8, -1);
13247
14613
  if (n === "Object" && o.constructor) n = o.constructor.name;
13248
14614
  if (n === "Map" || n === "Set") return Array.from(n);
13249
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
14615
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
13250
14616
  }
13251
14617
  var ALLOW_RE = /\ballow\s+([A-Za-z, \t]+?)\s*:\s*if\b/g;
13252
14618
  var COLLECTION_GROUP_PREFIX = /^\/\{[A-Za-z_]\w*=\*\*\}\//;
@@ -13452,6 +14818,14 @@ var BARE_IDENTIFIER_RE = /^[A-Za-z_]\w*$/;
13452
14818
  return walkBlock(masked, 0, source);
13453
14819
  }
13454
14820
 
14821
+ function _array_like_to_array$2(arr, len) {
14822
+ if (len == null || len > arr.length) len = arr.length;
14823
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
14824
+ return arr2;
14825
+ }
14826
+ function _array_with_holes$1(arr) {
14827
+ if (Array.isArray(arr)) return arr;
14828
+ }
13455
14829
  function _define_property(obj, key, value) {
13456
14830
  if (key in obj) {
13457
14831
  Object.defineProperty(obj, key, {
@@ -13465,6 +14839,33 @@ function _define_property(obj, key, value) {
13465
14839
  }
13466
14840
  return obj;
13467
14841
  }
14842
+ function _iterable_to_array_limit$1(arr, i) {
14843
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
14844
+ if (_i == null) return;
14845
+ var _arr = [];
14846
+ var _n = true;
14847
+ var _d = false;
14848
+ var _s, _e;
14849
+ try {
14850
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
14851
+ _arr.push(_s.value);
14852
+ if (i && _arr.length === i) break;
14853
+ }
14854
+ } catch (err) {
14855
+ _d = true;
14856
+ _e = err;
14857
+ } finally{
14858
+ try {
14859
+ if (!_n && _i["return"] != null) _i["return"]();
14860
+ } finally{
14861
+ if (_d) throw _e;
14862
+ }
14863
+ }
14864
+ return _arr;
14865
+ }
14866
+ function _non_iterable_rest$1() {
14867
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
14868
+ }
13468
14869
  function _object_spread(target) {
13469
14870
  for(var i = 1; i < arguments.length; i++){
13470
14871
  var source = arguments[i] != null ? arguments[i] : {};
@@ -13480,6 +14881,36 @@ function _object_spread(target) {
13480
14881
  }
13481
14882
  return target;
13482
14883
  }
14884
+ function ownKeys(object, enumerableOnly) {
14885
+ var keys = Object.keys(object);
14886
+ if (Object.getOwnPropertySymbols) {
14887
+ var symbols = Object.getOwnPropertySymbols(object);
14888
+ keys.push.apply(keys, symbols);
14889
+ }
14890
+ return keys;
14891
+ }
14892
+ function _object_spread_props(target, source) {
14893
+ source = source != null ? source : {};
14894
+ if (Object.getOwnPropertyDescriptors) {
14895
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
14896
+ } else {
14897
+ ownKeys(Object(source)).forEach(function(key) {
14898
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
14899
+ });
14900
+ }
14901
+ return target;
14902
+ }
14903
+ function _sliced_to_array$1(arr, i) {
14904
+ return _array_with_holes$1(arr) || _iterable_to_array_limit$1(arr, i) || _unsupported_iterable_to_array$2(arr, i) || _non_iterable_rest$1();
14905
+ }
14906
+ function _unsupported_iterable_to_array$2(o, minLen) {
14907
+ if (!o) return;
14908
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
14909
+ var n = Object.prototype.toString.call(o).slice(8, -1);
14910
+ if (n === "Object" && o.constructor) n = o.constructor.name;
14911
+ if (n === "Map" || n === "Set") return Array.from(n);
14912
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
14913
+ }
13483
14914
  /**
13484
14915
  * Default file name searched relative to the lint root when `firestoreRulesPath` is omitted.
13485
14916
  */ var DEFAULT_FIRESTORE_RULES_FILENAME = 'firestore.rules';
@@ -13500,6 +14931,18 @@ function _object_spread(target) {
13500
14931
  'components/*/src/lib/model/**/*.ts',
13501
14932
  'apps/*/src/app/**/*.ts'
13502
14933
  ];
14934
+ /**
14935
+ * Identity-type-reference names emitted into `@dereekb/firebase`'s shipped `.d.ts` for the two
14936
+ * `firestoreModelIdentity(...)` return shapes. Downstream consumers only have these declaration
14937
+ * files (no `firestoreModelIdentity(...)` call expressions), so the rule reads model name +
14938
+ * collection name + parent chain from these type annotations — they carry every literal inline,
14939
+ * e.g. `FirestoreModelIdentityWithParent<RootFirestoreModelIdentity<"notificationBox","nb">, "notification","nbn">`.
14940
+ */ var ROOT_IDENTITY_TYPE_NAME = 'RootFirestoreModelIdentity';
14941
+ var WITH_PARENT_IDENTITY_TYPE_NAME = 'FirestoreModelIdentityWithParent';
14942
+ /**
14943
+ * Cheap substring used to skip files that cannot contain an identity type-annotation before paying
14944
+ * for a full parse (`RootFirestoreModelIdentity` / `FirestoreModelIdentityWithParent` both contain it).
14945
+ */ var IDENTITY_TYPE_SOURCE_MARKER = 'FirestoreModelIdentity';
13503
14946
  var firestoreRulesFileCache = new Map();
13504
14947
  var identityRegistryCache = new Map();
13505
14948
  /**
@@ -13621,6 +15064,181 @@ var identityRegistryCache = new Map();
13621
15064
  */ function isStringLiteralNode(node) {
13622
15065
  return (node === null || node === void 0 ? void 0 : node.type) === 'Literal' && typeof node.value === 'string';
13623
15066
  }
15067
+ /**
15068
+ * Walks a parsed file's Program body for top-level `export declare const <name>: <IdentityType>`
15069
+ * declarations and records each resolvable identity. This is the downstream path: a consumer only
15070
+ * has `@dereekb/firebase`'s shipped `.d.ts`, which carries no `firestoreModelIdentity(...)` calls —
15071
+ * only the identity *type annotation* on each exported const. The parent chain is embedded inline in
15072
+ * the type arguments, so the parent's model name is captured here and linked to its declaring
15073
+ * variable in a later pass ({@link resolveTypeAnnotationParents}).
15074
+ *
15075
+ * @param programNode - The Program AST node.
15076
+ * @param state - The scan state whose accumulator + pending-parent map are populated.
15077
+ */ function collectIdentityTypeAnnotationsFromProgram(programNode, state) {
15078
+ var declarators = collectTopLevelDeclarators(programNode);
15079
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
15080
+ try {
15081
+ for(var _iterator = declarators[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
15082
+ var declarator = _step.value;
15083
+ var _id_typeAnnotation;
15084
+ var id = declarator.id;
15085
+ if ((id === null || id === void 0 ? void 0 : id.type) !== 'Identifier' || state.accumulator.has(id.name)) continue;
15086
+ var typeNode = (_id_typeAnnotation = id.typeAnnotation) === null || _id_typeAnnotation === void 0 ? void 0 : _id_typeAnnotation.typeAnnotation;
15087
+ if (!typeNode) continue;
15088
+ var parsed = parseIdentityTypeAnnotation(typeNode);
15089
+ if (parsed) {
15090
+ state.accumulator.set(id.name, {
15091
+ modelName: parsed.modelName,
15092
+ collectionName: parsed.collectionName,
15093
+ identityVariableName: id.name
15094
+ });
15095
+ if (parsed.parentModelName != null) {
15096
+ state.pendingParentModelNameByVariable.set(id.name, parsed.parentModelName);
15097
+ }
15098
+ }
15099
+ }
15100
+ } catch (err) {
15101
+ _didIteratorError = true;
15102
+ _iteratorError = err;
15103
+ } finally{
15104
+ try {
15105
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
15106
+ _iterator.return();
15107
+ }
15108
+ } finally{
15109
+ if (_didIteratorError) {
15110
+ throw _iteratorError;
15111
+ }
15112
+ }
15113
+ }
15114
+ }
15115
+ /**
15116
+ * Reduces an identity type annotation (`RootFirestoreModelIdentity<M, C>` or
15117
+ * `FirestoreModelIdentityWithParent<<ParentType>, M, C>`, whether written as a `TSTypeReference` or
15118
+ * the `import("…").X<…>` `TSImportType` shape the compiler emits in `.d.ts`) to its model name,
15119
+ * collection name, and — for the nested form — its parent's model name.
15120
+ *
15121
+ * @param typeNode - The type-annotation node.
15122
+ * @returns The resolved identity, or null when the type is not a recognized identity shape.
15123
+ */ function parseIdentityTypeAnnotation(typeNode) {
15124
+ var result = null;
15125
+ var name = referencedTypeName(typeNode);
15126
+ var args = typeReferenceTypeArguments(typeNode);
15127
+ if (name === ROOT_IDENTITY_TYPE_NAME && args && args.length >= 2) {
15128
+ var modelName = tsLiteralStringValue(args[0]);
15129
+ var collectionName = tsLiteralStringValue(args[1]);
15130
+ if (modelName != null && collectionName != null) {
15131
+ result = {
15132
+ modelName: modelName,
15133
+ collectionName: collectionName
15134
+ };
15135
+ }
15136
+ } else if (name === WITH_PARENT_IDENTITY_TYPE_NAME && args && args.length >= 3) {
15137
+ var modelName1 = tsLiteralStringValue(args[1]);
15138
+ var collectionName1 = tsLiteralStringValue(args[2]);
15139
+ var parentModelName = identityTypeAnnotationModelName(args[0]);
15140
+ if (modelName1 != null && collectionName1 != null) {
15141
+ result = _object_spread({
15142
+ modelName: modelName1,
15143
+ collectionName: collectionName1
15144
+ }, parentModelName != null ? {
15145
+ parentModelName: parentModelName
15146
+ } : {});
15147
+ }
15148
+ }
15149
+ return result;
15150
+ }
15151
+ /**
15152
+ * Resolves just the model name from an identity type annotation node (root or with-parent shape),
15153
+ * used to recover a parent identity's model name from its embedded type.
15154
+ *
15155
+ * @param typeNode - The type-annotation node.
15156
+ * @returns The model name, or null when the type is not a recognized identity shape.
15157
+ */ function identityTypeAnnotationModelName(typeNode) {
15158
+ var result = null;
15159
+ var name = referencedTypeName(typeNode);
15160
+ var args = typeReferenceTypeArguments(typeNode);
15161
+ if (name === ROOT_IDENTITY_TYPE_NAME && args && args.length >= 1) {
15162
+ result = tsLiteralStringValue(args[0]);
15163
+ } else if (name === WITH_PARENT_IDENTITY_TYPE_NAME && args && args.length >= 2) {
15164
+ result = tsLiteralStringValue(args[1]);
15165
+ }
15166
+ return result;
15167
+ }
15168
+ /**
15169
+ * Returns the string value of a `TSLiteralType` wrapping a string literal (e.g. the `"nu"` in
15170
+ * `RootFirestoreModelIdentity<"notificationUser", "nu">`).
15171
+ *
15172
+ * @param node - The type-argument node.
15173
+ * @returns The literal string, or null when the node is not a string-literal type.
15174
+ */ function tsLiteralStringValue(node) {
15175
+ var _node_literal;
15176
+ var result = null;
15177
+ if ((node === null || node === void 0 ? void 0 : node.type) === 'TSLiteralType' && ((_node_literal = node.literal) === null || _node_literal === void 0 ? void 0 : _node_literal.type) === 'Literal' && typeof node.literal.value === 'string') {
15178
+ result = node.literal.value;
15179
+ }
15180
+ return result;
15181
+ }
15182
+ /**
15183
+ * Links each type-annotation-discovered child identity to its parent's declaring variable by
15184
+ * matching the parent's model name (captured from the inline parent type) to an accumulated entry.
15185
+ * Entries already carrying a parent reference (e.g. from a call-expression scan) are left untouched.
15186
+ *
15187
+ * @param state - The scan state; its accumulator is mutated in place using the pending-parent map.
15188
+ */ function resolveTypeAnnotationParents(state) {
15189
+ var accumulator = state.accumulator, pendingParentModelNameByVariable = state.pendingParentModelNameByVariable;
15190
+ if (pendingParentModelNameByVariable.size === 0) return;
15191
+ var variableByModelName = new Map();
15192
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
15193
+ try {
15194
+ for(var _iterator = accumulator.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
15195
+ var entry = _step.value;
15196
+ if (!variableByModelName.has(entry.modelName)) {
15197
+ variableByModelName.set(entry.modelName, entry.identityVariableName);
15198
+ }
15199
+ }
15200
+ } catch (err) {
15201
+ _didIteratorError = true;
15202
+ _iteratorError = err;
15203
+ } finally{
15204
+ try {
15205
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
15206
+ _iterator.return();
15207
+ }
15208
+ } finally{
15209
+ if (_didIteratorError) {
15210
+ throw _iteratorError;
15211
+ }
15212
+ }
15213
+ }
15214
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
15215
+ try {
15216
+ for(var _iterator1 = pendingParentModelNameByVariable[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
15217
+ var _step_value = _sliced_to_array$1(_step1.value, 2), variableName = _step_value[0], parentModelName = _step_value[1];
15218
+ var entry1 = accumulator.get(variableName);
15219
+ if (!entry1 || entry1.parentIdentityVariableName) continue;
15220
+ var parentVariableName = variableByModelName.get(parentModelName);
15221
+ if (parentVariableName) {
15222
+ accumulator.set(variableName, _object_spread_props(_object_spread({}, entry1), {
15223
+ parentIdentityVariableName: parentVariableName
15224
+ }));
15225
+ }
15226
+ }
15227
+ } catch (err) {
15228
+ _didIteratorError1 = true;
15229
+ _iteratorError1 = err;
15230
+ } finally{
15231
+ try {
15232
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
15233
+ _iterator1.return();
15234
+ }
15235
+ } finally{
15236
+ if (_didIteratorError1) {
15237
+ throw _iteratorError1;
15238
+ }
15239
+ }
15240
+ }
15241
+ }
13624
15242
  /**
13625
15243
  * Collects every `VariableDeclarator` directly under the Program body, looking through
13626
15244
  * `ExportNamedDeclaration` wrappers.
@@ -13685,50 +15303,67 @@ function unwrapVariableDeclaration(statement) {
13685
15303
  return result;
13686
15304
  }
13687
15305
  /**
13688
- * Builds the workspace identity registry by globbing each search root and parsing each
13689
- * matched `.ts` file. Results are cached by the joined absolute-glob-pattern key.
15306
+ * Builds the workspace identity registry from two complementary discovery passes that feed one
15307
+ * accumulator.
15308
+ *
15309
+ * 1. The cwd-relative `searchRoots` globs — pick up `firestoreModelIdentity(...)` call expressions
15310
+ * in the in-repo source and in consumer-local `components/*` / `apps/*` model files.
15311
+ * 2. The installed `@dereekb/firebase` package's `src/lib/model` directory (resolved from `cwd` via
15312
+ * {@link resolveInstalledFirebaseModelDir}) — picks up framework identities downstream, where the
15313
+ * package ships `.d.ts` declarations (identity type-annotations) rather than scannable call
15314
+ * expressions. No-op inside the monorepo, where pass 1 already covers the framework source.
15315
+ *
15316
+ * Each file is parsed once and run through both the call-expression and type-annotation extractors;
15317
+ * the first writer per identity-variable name wins, so consumer-local declarations always take
15318
+ * precedence over framework ones. Results are cached by cwd + factory + roots + framework dir.
13690
15319
  *
13691
15320
  * @param cwd - ESLint working directory.
13692
15321
  * @param searchRoots - Relative glob patterns.
13693
15322
  * @param identityFactoryName - The call-expression name to match.
13694
15323
  * @returns The registry indexed by identity variable name and model name.
13695
15324
  */ function buildIdentityRegistry(cwd, searchRoots, identityFactoryName) {
13696
- var cacheKey = "".concat(cwd, "::").concat(identityFactoryName, "::").concat(searchRoots.join('|'));
15325
+ var frameworkModelDir = resolveInstalledFirebaseModelDir(cwd);
15326
+ var cacheKey = "".concat(cwd, "::").concat(identityFactoryName, "::").concat(searchRoots.join('|'), "::").concat(frameworkModelDir !== null && frameworkModelDir !== void 0 ? frameworkModelDir : '');
13697
15327
  var cached = identityRegistryCache.get(cacheKey);
13698
15328
  if (cached) {
13699
15329
  return cached;
13700
15330
  }
13701
- var accumulator = new Map();
15331
+ var state = {
15332
+ accumulator: new Map(),
15333
+ pendingParentModelNameByVariable: new Map()
15334
+ };
13702
15335
  var seenFiles = new Set();
13703
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
13704
- try {
13705
- for(var _iterator = searchRoots[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13706
- var pattern = _step.value;
13707
- var files = safeGlobSync(pattern, cwd);
13708
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
15336
+ var scanFiles = function scanFiles(relativeFiles, baseDir) {
15337
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
15338
+ try {
15339
+ for(var _iterator = relativeFiles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
15340
+ var relativeFile = _step.value;
15341
+ var absoluteFile = node_path.isAbsolute(relativeFile) ? relativeFile : node_path.resolve(baseDir, relativeFile);
15342
+ if (seenFiles.has(absoluteFile)) continue;
15343
+ seenFiles.add(absoluteFile);
15344
+ scanIdentityFile(absoluteFile, identityFactoryName, state);
15345
+ }
15346
+ } catch (err) {
15347
+ _didIteratorError = true;
15348
+ _iteratorError = err;
15349
+ } finally{
13709
15350
  try {
13710
- for(var _iterator1 = files[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
13711
- var relativeFile = _step1.value;
13712
- var absoluteFile = node_path.isAbsolute(relativeFile) ? relativeFile : node_path.resolve(cwd, relativeFile);
13713
- if (seenFiles.has(absoluteFile)) continue;
13714
- seenFiles.add(absoluteFile);
13715
- scanIdentityFile(absoluteFile, identityFactoryName, accumulator);
15351
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
15352
+ _iterator.return();
13716
15353
  }
13717
- } catch (err) {
13718
- _didIteratorError1 = true;
13719
- _iteratorError1 = err;
13720
15354
  } finally{
13721
- try {
13722
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
13723
- _iterator1.return();
13724
- }
13725
- } finally{
13726
- if (_didIteratorError1) {
13727
- throw _iteratorError1;
13728
- }
15355
+ if (_didIteratorError) {
15356
+ throw _iteratorError;
13729
15357
  }
13730
15358
  }
13731
15359
  }
15360
+ };
15361
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
15362
+ try {
15363
+ for(var _iterator = searchRoots[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
15364
+ var pattern = _step.value;
15365
+ scanFiles(safeGlobSync$1(pattern, cwd), cwd);
15366
+ }
13732
15367
  } catch (err) {
13733
15368
  _didIteratorError = true;
13734
15369
  _iteratorError = err;
@@ -13743,11 +15378,30 @@ function unwrapVariableDeclaration(statement) {
13743
15378
  }
13744
15379
  }
13745
15380
  }
13746
- var registry = finalizeIdentityRegistry(accumulator);
15381
+ if (frameworkModelDir) {
15382
+ scanFiles(safeGlobSync$1('**/*.ts', frameworkModelDir), frameworkModelDir);
15383
+ }
15384
+ resolveTypeAnnotationParents(state);
15385
+ var registry = finalizeIdentityRegistry(state.accumulator);
13747
15386
  identityRegistryCache.set(cacheKey, registry);
13748
15387
  return registry;
13749
15388
  }
13750
- function safeGlobSync(pattern, cwd) {
15389
+ /**
15390
+ * Converts a {@link VirtualModelIdentity} stub into a registry {@link IdentityEntry}, omitting
15391
+ * the optional parent reference when absent.
15392
+ *
15393
+ * @param virtual - The identity stub.
15394
+ * @returns The identity entry.
15395
+ */ function virtualModelIdentityToEntry(virtual) {
15396
+ return _object_spread({
15397
+ modelName: virtual.modelName,
15398
+ collectionName: virtual.collectionName,
15399
+ identityVariableName: virtual.identityVariableName
15400
+ }, virtual.parentIdentityVariableName ? {
15401
+ parentIdentityVariableName: virtual.parentIdentityVariableName
15402
+ } : {});
15403
+ }
15404
+ function safeGlobSync$1(pattern, cwd) {
13751
15405
  var result;
13752
15406
  try {
13753
15407
  result = node_fs.globSync(pattern, {
@@ -13758,10 +15412,13 @@ function safeGlobSync(pattern, cwd) {
13758
15412
  }
13759
15413
  return result;
13760
15414
  }
13761
- function scanIdentityFile(absoluteFile, identityFactoryName, accumulator) {
15415
+ function scanIdentityFile(absoluteFile, identityFactoryName, state) {
15416
+ if (absoluteFile.endsWith('.spec.ts') || absoluteFile.endsWith('.test.ts') || absoluteFile.endsWith('.id.ts')) {
15417
+ return;
15418
+ }
13762
15419
  try {
13763
15420
  var source = node_fs.readFileSync(absoluteFile, 'utf8');
13764
- if (source.includes(identityFactoryName)) {
15421
+ if (source.includes(identityFactoryName) || source.includes(IDENTITY_TYPE_SOURCE_MARKER)) {
13765
15422
  var programNode = parser.parse(source, {
13766
15423
  ecmaVersion: 2022,
13767
15424
  sourceType: 'module',
@@ -13769,7 +15426,8 @@ function scanIdentityFile(absoluteFile, identityFactoryName, accumulator) {
13769
15426
  range: false,
13770
15427
  jsx: false
13771
15428
  });
13772
- collectIdentityCallsFromProgram(programNode, identityFactoryName, accumulator);
15429
+ collectIdentityCallsFromProgram(programNode, identityFactoryName, state.accumulator);
15430
+ collectIdentityTypeAnnotationsFromProgram(programNode, state);
13773
15431
  }
13774
15432
  } catch (unused) {
13775
15433
  // Best-effort discovery — unparsable files are skipped silently so the rule does not
@@ -13823,13 +15481,7 @@ function scanIdentityFile(absoluteFile, identityFactoryName, accumulator) {
13823
15481
  try {
13824
15482
  for(var _iterator = virtualIdentities[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
13825
15483
  var virtual = _step.value;
13826
- accumulator.set(virtual.identityVariableName, _object_spread({
13827
- modelName: virtual.modelName,
13828
- collectionName: virtual.collectionName,
13829
- identityVariableName: virtual.identityVariableName
13830
- }, virtual.parentIdentityVariableName ? {
13831
- parentIdentityVariableName: virtual.parentIdentityVariableName
13832
- } : {}));
15484
+ accumulator.set(virtual.identityVariableName, virtualModelIdentityToEntry(virtual));
13833
15485
  }
13834
15486
  } catch (err) {
13835
15487
  _didIteratorError = true;
@@ -14612,13 +16264,17 @@ function _unsupported_iterable_to_array$1(o, minLen) {
14612
16264
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
14613
16265
  }
14614
16266
  /**
14615
- * Default glob patterns (relative to ESLint `cwd`) used to locate model + factory source files.
14616
- * Mirrors {@link require-firestore-rule-for-service-model}'s search roots so the orphan rule
14617
- * picks up factories declared anywhere a model interface might also live.
16267
+ * Default glob pattern (relative to ESLint `cwd`) used to locate `@dbxModelServiceFactory` source
16268
+ * files. A single layout-agnostic `**\/*.ts` scan finds a consumer's own factory declarations no
16269
+ * matter where they live, rather than assuming the dbx-components monorepo layout
16270
+ * (`components/*\/src/lib/model`, `apps/*\/src/app`) — which a downstream consumer of
16271
+ * `@dereekb/firebase` does not share. The walk prunes `node_modules`/build dirs
16272
+ * (see {@link discoveryGlobExcludeFilter}) and the cheap `text.includes('@'+factoryTag)` pre-filter
16273
+ * in {@link collectFactoryModelTypesFromFile} keeps it from parsing files that carry no tag, so the
16274
+ * broad glob stays fast even in a large consumer repo. In-repo this is a superset of the former
16275
+ * monorepo-specific roots, so the demo app's framework + local factories still resolve.
14618
16276
  */ var DEFAULT_FACTORY_SEARCH_ROOTS = [
14619
- 'packages/firebase/src/lib/model/**/*.ts',
14620
- 'components/*/src/lib/model/**/*.ts',
14621
- 'apps/*/src/app/**/*.ts'
16277
+ '**/*.ts'
14622
16278
  ];
14623
16279
  /**
14624
16280
  * Default name of the `@dbxModel` marker tag that triggers the orphan check.
@@ -14627,6 +16283,11 @@ function _unsupported_iterable_to_array$1(o, minLen) {
14627
16283
  * Default name of the `@dbxModelServiceFactory <modelType>` tag the rule cross-references.
14628
16284
  */ var DEFAULT_FACTORY_TAG = 'dbxModelServiceFactory';
14629
16285
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
16286
+ /**
16287
+ * Cache of discovered factory model-type sets keyed by `cwd + factoryTag + searchRoots`. ESLint
16288
+ * calls `create()` once per linted file; without this the broad `**\/*.ts` scan would re-run for
16289
+ * every file. The set is stable for the lifetime of a lint process.
16290
+ */ var factoryModelTypeSetCache = new Map();
14630
16291
  /**
14631
16292
  * ESLint rule that flags every `@dbxModel`-marked interface that has no matching
14632
16293
  * `@dbxModelServiceFactory <modelType>` declaration elsewhere in the workspace.
@@ -14692,16 +16353,18 @@ var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
14692
16353
  var _options_factorySearchRoots;
14693
16354
  if (options.virtualFactoryModelTypes) return new Set(options.virtualFactoryModelTypes);
14694
16355
  var roots = (_options_factorySearchRoots = options.factorySearchRoots) !== null && _options_factorySearchRoots !== void 0 ? _options_factorySearchRoots : DEFAULT_FACTORY_SEARCH_ROOTS;
16356
+ var cacheKey = "".concat(cwd, "::").concat(factoryTag, "::").concat(roots.join('|'));
16357
+ var cached = factoryModelTypeSetCache.get(cacheKey);
16358
+ if (cached) return cached;
14695
16359
  var out = new Set();
16360
+ var exclude = discoveryGlobExcludeFilter();
14696
16361
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
14697
16362
  try {
14698
16363
  for(var _iterator = roots[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
14699
16364
  var pattern = _step.value;
14700
16365
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
14701
16366
  try {
14702
- for(var _iterator1 = node_fs.globSync(pattern, {
14703
- cwd: cwd
14704
- })[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
16367
+ for(var _iterator1 = safeGlobSync(pattern, cwd, exclude)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
14705
16368
  var rel = _step1.value;
14706
16369
  collectFactoryModelTypesFromFile({
14707
16370
  rel: rel,
@@ -14739,6 +16402,7 @@ var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
14739
16402
  }
14740
16403
  }
14741
16404
  }
16405
+ factoryModelTypeSetCache.set(cacheKey, out);
14742
16406
  return out;
14743
16407
  }
14744
16408
  function visitInterface(node) {
@@ -14776,9 +16440,22 @@ var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
14776
16440
  function lowercaseFirstLetter(name) {
14777
16441
  return name.length === 0 ? name : name.charAt(0).toLowerCase() + name.slice(1);
14778
16442
  }
16443
+ function safeGlobSync(pattern, cwd, exclude) {
16444
+ var result;
16445
+ try {
16446
+ result = node_fs.globSync(pattern, {
16447
+ cwd: cwd,
16448
+ exclude: exclude
16449
+ });
16450
+ } catch (unused) {
16451
+ result = [];
16452
+ }
16453
+ return result;
16454
+ }
14779
16455
  function collectFactoryModelTypesFromFile(input) {
14780
16456
  var rel = input.rel, cwd = input.cwd, factoryTag = input.factoryTag, out = input.out;
14781
16457
  if (typeof rel !== 'string') return;
16458
+ if (rel.endsWith('.spec.ts') || rel.endsWith('.test.ts')) return;
14782
16459
  var abs = node_path.resolve(cwd, rel);
14783
16460
  var text;
14784
16461
  try {
@@ -15587,6 +17264,7 @@ exports.DEFAULT_API_DETAILS_FACTORY_NAME = DEFAULT_API_DETAILS_FACTORY_NAME;
15587
17264
  exports.DEFAULT_CONSTRAINT_FACTORY_NAMES = DEFAULT_CONSTRAINT_FACTORY_NAMES;
15588
17265
  exports.DEFAULT_CRUD_FUNCTION_TYPE_VERBS = DEFAULT_CRUD_FUNCTION_TYPE_VERBS;
15589
17266
  exports.DEFAULT_CRUD_VERB_NAMES = DEFAULT_CRUD_VERB_NAMES;
17267
+ exports.DEFAULT_DISCOVERY_EXCLUDED_DIRS = DEFAULT_DISCOVERY_EXCLUDED_DIRS;
15590
17268
  exports.DEFAULT_FACTORY_SEARCH_ROOTS = DEFAULT_FACTORY_SEARCH_ROOTS;
15591
17269
  exports.DEFAULT_FACTORY_TAG = DEFAULT_FACTORY_TAG;
15592
17270
  exports.DEFAULT_FIRESTORE_RULES_FILENAME = DEFAULT_FIRESTORE_RULES_FILENAME;
@@ -15619,6 +17297,7 @@ exports.INPUT_TYPE_PROPERTY_NAME = INPUT_TYPE_PROPERTY_NAME;
15619
17297
  exports.MIRRORS_POLICY_KEY_MARKER_REGEX = MIRRORS_POLICY_KEY_MARKER_REGEX;
15620
17298
  exports.MODEL_FIREBASE_CRUD_FUNCTION_CONFIG_MAP_TYPE_NAME = MODEL_FIREBASE_CRUD_FUNCTION_CONFIG_MAP_TYPE_NAME;
15621
17299
  exports.QUERY_SUFFIX = QUERY_SUFFIX;
17300
+ exports.discoveryGlobExcludeFilter = discoveryGlobExcludeFilter;
15622
17301
  exports.firebaseESLintPlugin = firebaseESLintPlugin;
15623
17302
  exports.parseFirestoreRules = parseFirestoreRules;
15624
17303
  exports.parseStorageRules = parseStorageRules;