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