uidex 0.5.1 → 0.6.0

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.
@@ -88,6 +88,7 @@ interface ReportRecord {
88
88
  interface Registry {
89
89
  add(entity: Entity): void;
90
90
  get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
91
+ matchPattern<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
91
92
  list<K extends EntityKind>(kind: K): ReadonlyArray<EntityByKind<K>>;
92
93
  query(predicate: (entity: Entity) => boolean): Entity[];
93
94
  byScope(scope: Scope): Entity[];
@@ -88,6 +88,7 @@ interface ReportRecord {
88
88
  interface Registry {
89
89
  add(entity: Entity): void;
90
90
  get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
91
+ matchPattern<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
91
92
  list<K extends EntityKind>(kind: K): ReadonlyArray<EntityByKind<K>>;
92
93
  query(predicate: (entity: Entity) => boolean): Entity[];
93
94
  byScope(scope: Scope): Entity[];
@@ -1210,6 +1210,7 @@ function posAt(content, offset) {
1210
1210
 
1211
1211
  // src/scanner/scan/jsx-ancestry.ts
1212
1212
  var DATA_ATTR_RE = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
1213
+ var PATTERN_ATTR_RE = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*\{\s*`([^`$]+)\$\{/g;
1213
1214
  function parseDataAttrs(tagSource) {
1214
1215
  if (!tagSource.includes("data-uidex")) return [];
1215
1216
  const out2 = [];
@@ -1218,6 +1219,11 @@ function parseDataAttrs(tagSource) {
1218
1219
  const id = m[2] ?? m[3];
1219
1220
  if (id) out2.push({ kind, id });
1220
1221
  }
1222
+ for (const m of tagSource.matchAll(PATTERN_ATTR_RE)) {
1223
+ const kind = m[1] ?? "element";
1224
+ const prefix = m[2];
1225
+ if (prefix) out2.push({ kind, id: `${prefix}*` });
1226
+ }
1221
1227
  return out2;
1222
1228
  }
1223
1229
  function collectJSXAncestry(content) {
@@ -1567,6 +1573,7 @@ function freezeEntity(entity, flows) {
1567
1573
  function createRegistry() {
1568
1574
  const store = emptyStore();
1569
1575
  let flowsCache = null;
1576
+ const patternCache = /* @__PURE__ */ new Map();
1570
1577
  const getFlows = () => {
1571
1578
  if (flowsCache === null) flowsCache = Array.from(store.flow.values());
1572
1579
  return flowsCache;
@@ -1576,6 +1583,7 @@ function createRegistry() {
1576
1583
  const key = entityKey(entity);
1577
1584
  store[entity.kind].set(key, entity);
1578
1585
  flowsCache = null;
1586
+ patternCache.delete(entity.kind);
1579
1587
  };
1580
1588
  const get = (kind, id) => {
1581
1589
  assertEntityKind(kind);
@@ -1583,6 +1591,38 @@ function createRegistry() {
1583
1591
  if (raw === void 0) return void 0;
1584
1592
  return freezeEntity(raw, getFlows());
1585
1593
  };
1594
+ const getPatternsForKind = (kind) => {
1595
+ const cached = patternCache.get(kind);
1596
+ if (cached !== void 0)
1597
+ return cached;
1598
+ const patterns = [];
1599
+ for (const [key, entity] of store[kind]) {
1600
+ if (key.endsWith("*")) {
1601
+ patterns.push({
1602
+ prefix: key.slice(0, -1),
1603
+ entity
1604
+ });
1605
+ }
1606
+ }
1607
+ patternCache.set(
1608
+ kind,
1609
+ patterns
1610
+ );
1611
+ return patterns;
1612
+ };
1613
+ const matchPattern = (kind, id) => {
1614
+ assertEntityKind(kind);
1615
+ const patterns = getPatternsForKind(kind);
1616
+ if (patterns.length === 0) return void 0;
1617
+ let best;
1618
+ for (const entry of patterns) {
1619
+ if (id.startsWith(entry.prefix) && (best === void 0 || entry.prefix.length > best.prefix.length)) {
1620
+ best = entry;
1621
+ }
1622
+ }
1623
+ if (best === void 0) return void 0;
1624
+ return freezeEntity(best.entity, getFlows());
1625
+ };
1586
1626
  const list = (kind) => {
1587
1627
  assertEntityKind(kind);
1588
1628
  const flows = getFlows();
@@ -1633,6 +1673,7 @@ function createRegistry() {
1633
1673
  return {
1634
1674
  add,
1635
1675
  get,
1676
+ matchPattern,
1636
1677
  list,
1637
1678
  query,
1638
1679
  byScope,
@@ -2341,10 +2382,18 @@ function audit(opts) {
2341
2382
  }
2342
2383
  if (lint) {
2343
2384
  const dynamicAttrRe = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*\{/g;
2385
+ const templateWithPrefixRe = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*\{\s*`[^`$]+\$\{/g;
2344
2386
  for (const f of files) {
2387
+ const templatePrefixPositions = /* @__PURE__ */ new Set();
2388
+ templateWithPrefixRe.lastIndex = 0;
2389
+ let tm;
2390
+ while ((tm = templateWithPrefixRe.exec(f.content)) !== null) {
2391
+ templatePrefixPositions.add(tm.index);
2392
+ }
2345
2393
  let m;
2346
2394
  dynamicAttrRe.lastIndex = 0;
2347
2395
  while ((m = dynamicAttrRe.exec(f.content)) !== null) {
2396
+ if (templatePrefixPositions.has(m.index)) continue;
2348
2397
  const kind = m[1] ?? "element";
2349
2398
  let line = 1;
2350
2399
  for (let i = 0; i < m.index; i++) if (f.content[i] === "\n") line++;
@@ -2428,7 +2477,7 @@ function audit(opts) {
2428
2477
  if (lint && coverageEnabled) {
2429
2478
  for (const flow of registry.list("flow")) {
2430
2479
  for (const touchedId of flow.touches) {
2431
- const found = registry.get("element", touchedId) ?? registry.get("widget", touchedId) ?? registry.get("region", touchedId);
2480
+ const found = registry.get("element", touchedId) ?? registry.get("widget", touchedId) ?? registry.get("region", touchedId) ?? registry.matchPattern("element", touchedId) ?? registry.matchPattern("widget", touchedId) ?? registry.matchPattern("region", touchedId);
2432
2481
  if (!found) {
2433
2482
  diagnostics.push({
2434
2483
  code: "unknown-reference",