react-render-detective 0.2.0 → 0.3.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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/babel.cjs +2 -2
  3. package/dist/babel.js +1 -1
  4. package/dist/{chunk-6YPJQ7M5.cjs → chunk-DZ3BZ654.cjs} +88 -4
  5. package/dist/chunk-DZ3BZ654.cjs.map +1 -0
  6. package/dist/{chunk-LSIXHWQD.js → chunk-HOTY7J3X.js} +14 -4
  7. package/dist/chunk-HOTY7J3X.js.map +1 -0
  8. package/dist/{chunk-QQ4VARSD.cjs → chunk-JD4IJ4MN.cjs} +14 -4
  9. package/dist/chunk-JD4IJ4MN.cjs.map +1 -0
  10. package/dist/{chunk-PSCFSJ65.js → chunk-MCIQMYNR.js} +12 -5
  11. package/dist/chunk-MCIQMYNR.js.map +1 -0
  12. package/dist/{chunk-BPNLNIHU.cjs → chunk-PHYYA67T.cjs} +12 -5
  13. package/dist/chunk-PHYYA67T.cjs.map +1 -0
  14. package/dist/{chunk-MSISKPST.js → chunk-QOGTEVBP.js} +88 -4
  15. package/dist/chunk-QOGTEVBP.js.map +1 -0
  16. package/dist/core.cjs +18 -18
  17. package/dist/core.d.cts +38 -2
  18. package/dist/core.d.ts +38 -2
  19. package/dist/core.js +1 -1
  20. package/dist/index.cjs +40 -31
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +13 -3
  23. package/dist/index.d.ts +13 -3
  24. package/dist/index.js +14 -5
  25. package/dist/index.js.map +1 -1
  26. package/dist/overlay.cjs +6 -6
  27. package/dist/overlay.cjs.map +1 -1
  28. package/dist/overlay.js +4 -4
  29. package/dist/overlay.js.map +1 -1
  30. package/dist/{types-BWVaQPHb.d.cts → types-gl13xwmN.d.cts} +5 -0
  31. package/dist/{types-BWVaQPHb.d.ts → types-gl13xwmN.d.ts} +5 -0
  32. package/dist/vite.cjs +9 -6
  33. package/dist/vite.cjs.map +1 -1
  34. package/dist/vite.js +8 -5
  35. package/dist/vite.js.map +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunk-6YPJQ7M5.cjs.map +0 -1
  38. package/dist/chunk-BPNLNIHU.cjs.map +0 -1
  39. package/dist/chunk-LSIXHWQD.js.map +0 -1
  40. package/dist/chunk-MSISKPST.js.map +0 -1
  41. package/dist/chunk-PSCFSJ65.js.map +0 -1
  42. package/dist/chunk-QQ4VARSD.cjs.map +0 -1
@@ -4,6 +4,7 @@ var SELF_PATTERN = /[/\\]react-render-detective[/\\](src|dist)[/\\]/;
4
4
  var HOC_NAMES = /* @__PURE__ */ new Set(["memo", "forwardRef"]);
5
5
  function renderDetectiveBabelPlugin(api) {
6
6
  const t = api.types;
7
+ const processed = /* @__PURE__ */ new WeakSet();
7
8
  api.assertVersion?.("^7.0.0-0 || ^8.0.0-0");
8
9
  const isComponentName = (name) => !!name && /^[A-Z]/.test(name);
9
10
  function returnsJsx(path) {
@@ -57,6 +58,9 @@ function renderDetectiveBabelPlugin(api) {
57
58
  ];
58
59
  const source = locationOf(node, state);
59
60
  if (source) properties.push(t.objectProperty(t.identifier("source"), t.stringLiteral(source)));
61
+ if (path.getFunctionParent()) {
62
+ properties.push(t.objectProperty(t.identifier("declaredInRender"), t.booleanLiteral(true)));
63
+ }
60
64
  state.rrdTouched = true;
61
65
  return t.callExpression(ensureImport(path, state), [fn, t.objectExpression(properties)]);
62
66
  }
@@ -90,6 +94,8 @@ function renderDetectiveBabelPlugin(api) {
90
94
  const id = path.node.id;
91
95
  if (!id || !isComponentName(id.name)) return;
92
96
  if (!returnsJsx(path)) return;
97
+ if (processed.has(path.node)) return;
98
+ processed.add(path.node);
93
99
  const wrapped = wrap(t.cloneNode(id), id.name, path.node, path, state);
94
100
  const assignment = t.expressionStatement(t.assignmentExpression("=", t.cloneNode(id), wrapped));
95
101
  assignment._rrdGenerated = true;
@@ -99,7 +105,6 @@ function renderDetectiveBabelPlugin(api) {
99
105
  } else {
100
106
  path.insertAfter(assignment);
101
107
  }
102
- path.skip();
103
108
  },
104
109
  /** `const Foo = () => <div />` and `const Foo = memo(() => <div />)` */
105
110
  VariableDeclarator(path, state) {
@@ -118,8 +123,9 @@ function renderDetectiveBabelPlugin(api) {
118
123
  if (!target.isArrowFunctionExpression() && !target.isFunctionExpression()) return;
119
124
  if (isAlreadyWrapped(target)) return;
120
125
  if (!returnsJsx(target)) return;
126
+ if (processed.has(path.node)) return;
127
+ processed.add(path.node);
121
128
  target.replaceWith(wrap(target.node, id.name, path.node, path, state));
122
- path.skip();
123
129
  },
124
130
  /** `export default function () { return <div /> }` */
125
131
  ExportDefaultDeclaration(path, state) {
@@ -134,8 +140,9 @@ function renderDetectiveBabelPlugin(api) {
134
140
  declaration.node.generator,
135
141
  declaration.node.async
136
142
  );
143
+ if (processed.has(path.node)) return;
144
+ processed.add(path.node);
137
145
  path.replaceWith(t.exportDefaultDeclaration(wrap(expression, name, declaration.node, path, state)));
138
- path.skip();
139
146
  }
140
147
  }
141
148
  };
@@ -156,5 +163,5 @@ function componentNameFromFile(path) {
156
163
  }
157
164
 
158
165
  export { renderDetectiveBabelPlugin };
159
- //# sourceMappingURL=chunk-PSCFSJ65.js.map
160
- //# sourceMappingURL=chunk-PSCFSJ65.js.map
166
+ //# sourceMappingURL=chunk-MCIQMYNR.js.map
167
+ //# sourceMappingURL=chunk-MCIQMYNR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/babel/index.ts"],"names":[],"mappings":";AAuCA,IAAM,qBAAA,GAAwB,wBAAA;AAW9B,IAAM,YAAA,GAAe,iDAAA;AACrB,IAAM,4BAAY,IAAI,GAAA,CAAI,CAAC,MAAA,EAAQ,YAAY,CAAC,CAAA;AAEjC,SAAR,2BACL,GAAA,EACc;AACd,EAAA,MAAM,IAAI,GAAA,CAAI,KAAA;AAOd,EAAA,MAAM,SAAA,uBAAgB,OAAA,EAAyB;AAG/C,EAAA,GAAA,CAAI,gBAAgB,sBAAsB,CAAA;AAS1C,EAAA,MAAM,eAAA,GAAkB,CAAC,IAAA,KAA6C,CAAC,CAAC,IAAA,IAAQ,QAAA,CAAS,KAAK,IAAI,CAAA;AAElG,EAAA,SAAS,WAAW,IAAA,EAA8C;AAChE,IAAA,IAAI,KAAA,GAAQ,KAAA;AACZ,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAG5B,IAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,IAAI,KAAK,CAAC,IAAA,CAAK,kBAAiB,EAAG;AACpD,MAAA,MAAM,OAAQ,IAAA,CAAkB,IAAA;AAChC,MAAA,OAAO,YAAY,IAAI,CAAA;AAAA,IACzB;AAEA,IAAA,IAAA,CAAK,QAAA,CAAS;AAAA,MACZ,SAAS,KAAA,EAAO;AACd,QAAA,KAAA,CAAM,IAAA,EAAK;AAAA,MACb,CAAA;AAAA,MACA,gBAAgB,GAAA,EAAK;AACnB,QAAA,IAAI,GAAA,CAAI,KAAK,QAAA,IAAY,WAAA,CAAY,IAAI,IAAA,CAAK,QAAQ,GAAG,KAAA,GAAQ,IAAA;AAAA,MACnE;AAAA,KACD,CAAA;AACD,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,SAAS,YAAY,IAAA,EAAmD;AACtE,IAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,IAAA,IAAI,CAAA,CAAE,aAAa,IAAI,CAAA,IAAK,EAAE,aAAA,CAAc,IAAI,GAAG,OAAO,IAAA;AAC1D,IAAA,IAAI,CAAA,CAAE,uBAAA,CAAwB,IAAI,CAAA,EAAG,OAAO,WAAA,CAAY,IAAA,CAAK,UAAU,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,SAAS,CAAA;AACtG,IAAA,IAAI,CAAA,CAAE,mBAAA,CAAoB,IAAI,CAAA,EAAG,OAAO,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA,IAAK,WAAA,CAAY,IAAA,CAAK,KAAK,CAAA;AACxF,IAAA,IAAI,EAAE,yBAAA,CAA0B,IAAI,GAAG,OAAO,WAAA,CAAY,KAAK,UAAU,CAAA;AACzE,IAAA,IAAI,CAAA,CAAE,gBAAA,CAAiB,IAAI,CAAA,EAAG;AAE5B,MAAA,OAAO,KAAK,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,KAAM,WAAA,CAAY,CAAoB,CAAC,CAAA;AAAA,IACrE;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,SAAS,YAAA,CAAa,MAAgB,KAAA,EAAqC;AACzE,IAAA,IAAI,KAAA,CAAM,QAAA,EAAU,OAAO,KAAA,CAAM,QAAA;AACjC,IAAA,MAAM,UAAU,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,CAAA;AACpD,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,qBAAA,CAAsB,UAAU,CAAA;AAC5D,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,YAAA,IAAgB,qBAAA;AAC1C,IAAA,OAAA,CAAQ,gBAAA;AAAA,MACN,MAAA;AAAA,MACA,CAAA,CAAE,iBAAA,CAAkB,CAAC,CAAA,CAAE,gBAAgB,KAAA,EAAO,CAAA,CAAE,UAAA,CAAW,qBAAqB,CAAC,CAAC,CAAA,EAAG,CAAA,CAAE,aAAA,CAAc,MAAM,CAAC;AAAA,KAC9G;AACA,IAAA,KAAA,CAAM,QAAA,GAAW,KAAA;AACjB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,SAAS,UAAA,CAAW,MAAuB,KAAA,EAAkC;AAC3E,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,EAAK,KAAA,CAAM,IAAA;AAC7B,IAAA,IAAI,IAAA,KAAS,MAAA,IAAa,CAAC,KAAA,CAAM,iBAAiB,OAAO,MAAA;AACzD,IAAA,OAAO,CAAA,EAAG,KAAA,CAAM,eAAe,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAA,CAAK,IAAA,CAAK,GAAA,EAAK,KAAA,CAAM,MAAA,IAAU,CAAA,IAAK,CAAC,CAAA,CAAA;AAAA,EAC9E;AAGA,EAAA,SAAS,IAAA,CACP,EAAA,EACA,IAAA,EACA,IAAA,EACA,MACA,KAAA,EAC2B;AAC3B,IAAA,MAAM,UAAA,GAA0C;AAAA,MAC9C,CAAA,CAAE,eAAe,CAAA,CAAE,UAAA,CAAW,MAAM,CAAA,EAAG,CAAA,CAAE,aAAA,CAAc,IAAI,CAAC;AAAA,KAC9D;AACA,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,IAAA,EAAM,KAAK,CAAA;AACrC,IAAA,IAAI,MAAA,EAAQ,UAAA,CAAW,IAAA,CAAK,CAAA,CAAE,cAAA,CAAe,CAAA,CAAE,UAAA,CAAW,QAAQ,CAAA,EAAG,CAAA,CAAE,aAAA,CAAc,MAAM,CAAC,CAAC,CAAA;AAQ7F,IAAA,IAAI,IAAA,CAAK,mBAAkB,EAAG;AAC5B,MAAA,UAAA,CAAW,IAAA,CAAK,CAAA,CAAE,cAAA,CAAe,CAAA,CAAE,UAAA,CAAW,kBAAkB,CAAA,EAAG,CAAA,CAAE,cAAA,CAAe,IAAI,CAAC,CAAC,CAAA;AAAA,IAC5F;AACA,IAAA,KAAA,CAAM,UAAA,GAAa,IAAA;AACnB,IAAA,OAAO,CAAA,CAAE,cAAA,CAAe,YAAA,CAAa,IAAA,EAAM,KAAK,CAAA,EAAG,CAAC,EAAA,EAAI,CAAA,CAAE,gBAAA,CAAiB,UAAU,CAAC,CAAC,CAAA;AAAA,EACzF;AAGA,EAAA,SAAS,iBAAiB,IAAA,EAAyB;AACjD,IAAA,MAAM,SAAS,IAAA,CAAK,UAAA;AACpB,IAAA,IAAI,CAAC,MAAA,EAAQ,gBAAA,EAAiB,EAAG,OAAO,KAAA;AACxC,IAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,MAAA;AAC3B,IAAA,IAAI,CAAA,CAAE,aAAa,MAAM,CAAA,IAAK,+BAA+B,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,EAAG,OAAO,IAAA;AACvF,IAAA,IAAI,CAAA,CAAE,kBAAA,CAAmB,MAAM,CAAA,IAAK,CAAA,CAAE,YAAA,CAAa,MAAA,CAAO,QAAA,EAAU,EAAE,IAAA,EAAM,qBAAA,EAAuB,GAAG,OAAO,IAAA;AAC7G,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,wBAAA;AAAA,IAEN,IAAiB,IAAA,EAAoE;AACnF,MAAA,MAAM,KAAA,GAAQ,IAAA;AACd,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,IAAA,CAAK,QAAA,IAAY,EAAA;AACvC,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,IAAA,IAAQ,KAAK,IAAA,CAAK,IAAA,IAAQ,QAAQ,GAAA,EAAI;AAC9D,MAAA,KAAA,CAAM,eAAA,GAAkB,QAAA,CAAS,UAAA,CAAW,IAAI,CAAA,GAAI,QAAA,CAAS,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,CAAE,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA,GAAI,QAAA;AAAA,IAC1G,CAAA;AAAA,IAEA,OAAA,EAAS;AAAA,MACP,OAAA,EAAS;AAAA,QACP,KAAA,CAAM,MAAoC,KAAA,EAAc;AACtD,UAAA,MAAM,UAAU,KAAA,CAAM,IAAA,CAAK,OAAA,IAAW,OAAA,CAAQ,IAAI,QAAA,KAAa,YAAA;AAC/D,UAAA,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAA,IAAY,EAAA;AAE7C,UAAA,MAAM,IAAA,GACJ,CAAC,OAAA,IACD,CAAC,YACD,cAAA,CAAe,IAAA,CAAK,QAAQ,CAAA,IAC5B,aAAa,IAAA,CAAK,QAAQ,CAAA,IAC1B,CAAC,QAAQ,QAAA,EAAU,KAAA,CAAM,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA,IAC3C,OAAA,CAAQ,QAAA,EAAU,KAAA,CAAM,KAAK,OAAA,EAAS,KAAK,CAAA,IAC1C,KAAA,CAAM,KAAK,UAAA,KAAe,IAAA,IAAQ,CAAC,YAAA,CAAa,KAAK,IAAI,CAAA;AAE5D,UAAA,IAAI,IAAA,OAAW,IAAA,EAAK;AAAA,QACtB;AAAA,OACF;AAAA;AAAA,MAGA,mBAAA,CAAoB,MAAgD,KAAA,EAAc;AAChF,QAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,EAAA;AACrB,QAAA,IAAI,CAAC,EAAA,IAAM,CAAC,eAAA,CAAgB,EAAA,CAAG,IAAI,CAAA,EAAG;AACtC,QAAA,IAAI,CAAC,UAAA,CAAW,IAAqC,CAAA,EAAG;AASxD,QAAA,IAAI,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,QAAA,SAAA,CAAU,GAAA,CAAI,KAAK,IAAI,CAAA;AAEvB,QAAA,MAAM,OAAA,GAAU,IAAA,CAAK,CAAA,CAAE,SAAA,CAAU,EAAE,CAAA,EAAG,EAAA,CAAG,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AACrE,QAAA,MAAM,UAAA,GAAa,CAAA,CAAE,mBAAA,CAAoB,CAAA,CAAE,oBAAA,CAAqB,GAAA,EAAK,CAAA,CAAE,SAAA,CAAU,EAAE,CAAA,EAAG,OAAO,CAAC,CAAA;AAC9F,QAAC,WAA2C,aAAA,GAAgB,IAAA;AAE5D,QAAA,MAAM,eAAA,GAAkB,KAAK,kBAAA,EAAmB;AAChD,QAAA,IAAI,KAAK,UAAA,CAAW,0BAAA,MAAgC,IAAA,CAAK,UAAA,CAAW,0BAAyB,EAAG;AAC9F,UAAA,eAAA,EAAiB,YAAY,UAAU,CAAA;AAAA,QACzC,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,YAAY,UAAU,CAAA;AAAA,QAC7B;AAAA,MACF,CAAA;AAAA;AAAA,MAGA,kBAAA,CAAmB,MAA+C,KAAA,EAAc;AAC9E,QAAA,MAAM,EAAA,GAAK,KAAK,IAAA,CAAK,EAAA;AACrB,QAAA,MAAM,IAAA,GAAO,KAAK,IAAA,CAAK,IAAA;AACvB,QAAA,IAAI,CAAC,CAAA,CAAE,YAAA,CAAa,EAAE,CAAA,IAAK,CAAC,IAAA,IAAQ,CAAC,eAAA,CAAgB,EAAA,CAAG,IAAI,CAAA,EAAG;AAI/D,QAAA,IAAI,MAAA,GAAmB,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AACtC,QAAA,IAAI,MAAA,CAAO,kBAAiB,EAAG;AAC7B,UAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,MAAA;AAC3B,UAAA,MAAM,KAAA,GACH,EAAE,YAAA,CAAa,MAAM,KAAK,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,IACnD,CAAA,CAAE,mBAAmB,MAAM,CAAA,IAAK,CAAA,CAAE,YAAA,CAAa,MAAA,CAAO,QAAQ,KAAK,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA;AACxG,UAAA,IAAI,CAAC,KAAA,EAAO;AACZ,UAAA,MAAM,KAAA,GAAS,MAAA,CAAO,GAAA,CAAI,WAAW,EAAiB,CAAC,CAAA;AACvD,UAAA,IAAI,CAAC,KAAA,EAAO;AACZ,UAAA,MAAA,GAAS,KAAA;AAAA,QACX;AAEA,QAAA,IAAI,CAAC,MAAA,CAAO,yBAAA,MAA+B,CAAC,MAAA,CAAO,sBAAqB,EAAG;AAC3E,QAAA,IAAI,gBAAA,CAAiB,MAAM,CAAA,EAAG;AAC9B,QAAA,IAAI,CAAC,UAAA,CAAW,MAAuC,CAAA,EAAG;AAE1D,QAAA,IAAI,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,QAAA,SAAA,CAAU,GAAA,CAAI,KAAK,IAAI,CAAA;AACvB,QAAA,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,IAAA,EAA+B,EAAA,CAAG,MAAM,IAAA,CAAK,IAAA,EAAM,IAAA,EAAM,KAAK,CAAC,CAAA;AAAA,MAChG,CAAA;AAAA;AAAA,MAGA,wBAAA,CAAyB,MAAqD,KAAA,EAAc;AAC1F,QAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,aAAa,CAAA;AAC1C,QAAA,IAAI,CAAC,WAAA,CAAY,qBAAA,EAAsB,IAAK,WAAA,CAAY,KAAK,EAAA,EAAI;AACjE,QAAA,IAAI,CAAC,UAAA,CAAW,WAA4C,CAAA,EAAG;AAE/D,QAAA,MAAM,IAAA,GAAO,qBAAA,CAAsB,KAAA,CAAM,eAAA,IAAmB,SAAS,CAAA;AACrE,QAAA,MAAM,aAAa,CAAA,CAAE,kBAAA;AAAA,UACnB,IAAA;AAAA,UACA,YAAY,IAAA,CAAK,MAAA;AAAA,UACjB,YAAY,IAAA,CAAK,IAAA;AAAA,UACjB,YAAY,IAAA,CAAK,SAAA;AAAA,UACjB,YAAY,IAAA,CAAK;AAAA,SACnB;AACA,QAAA,IAAI,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AAC9B,QAAA,SAAA,CAAU,GAAA,CAAI,KAAK,IAAI,CAAA;AACvB,QAAA,IAAA,CAAK,WAAA,CAAY,CAAA,CAAE,wBAAA,CAAyB,IAAA,CAAK,UAAA,EAAY,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,IAAA,EAAM,KAAK,CAAC,CAAC,CAAA;AAAA,MACpG;AAAA;AACF,GACF;AACF;AAEA,SAAS,OAAA,CAAQ,QAAA,EAAkB,QAAA,EAA8C,SAAA,EAA6B;AAC5G,EAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAA,KAAW,GAAG,OAAO,SAAA;AAC/C,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAO,OAAO,CAAA,KAAM,QAAA,GAAW,QAAA,CAAS,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAE,CAAA;AAC/F;AAEA,SAAS,aAAa,OAAA,EAAsC;AAC1D,EAAA,OAAO,OAAA,CAAQ,WAAW,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,CAAM,UAAU,YAAY,CAAA;AACtE;AAGA,SAAS,sBAAsB,IAAA,EAAsB;AACnD,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,CAAE,KAAI,IAAK,SAAA;AAC1C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAc,EAAE,CAAA;AAC1C,EAAA,MAAM,OAAA,GAAU,IAAA,KAAS,OAAA,GAAW,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA,CAAE,KAAA,CAAM,EAAE,CAAA,CAAE,CAAC,CAAA,IAAK,SAAA,GAAa,IAAA;AACrF,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,gBAAA,EAAkB,CAAC,GAAG,EAAA,EAAI,CAAA,KAAc,CAAA,CAAE,WAAA,EAAa,CAAA;AACtF,EAAA,OAAO,SAAS,IAAA,CAAK,MAAM,CAAA,GAAI,MAAA,GAAS,YAAY,MAAM,CAAA,CAAA;AAC5D","file":"chunk-MCIQMYNR.js","sourcesContent":["/**\n * Babel plugin: instrument every React component in a file at build time.\n *\n * Why this exists: without it you only learn about components you already\n * suspected, because you have to wrap them by hand. With it, the tool reports\n * on the whole tree — and it can attach a real source location, which React\n * itself no longer exposes at runtime (`_debugSource` was removed in React 19).\n *\n * Build-time only. It must never run in a production build, and it removes\n * itself when `NODE_ENV` is production unless explicitly forced.\n */\nimport type { NodePath, PluginObject, PluginPass, types as BabelTypes } from \"@babel/core\";\n\nexport interface RenderDetectivePluginOptions {\n /** Defaults to `NODE_ENV !== \"production\"`. */\n enabled?: boolean;\n /** Only instrument files whose path matches. Empty = all files. */\n include?: Array<string | RegExp>;\n /** Skip files whose path matches. Applied after `include`. */\n exclude?: Array<string | RegExp>;\n /**\n * Skip files with no `\"use client\"` directive. Turn this on for the Next.js\n * app router: server components never render on the client, and wrapping one\n * in a hook-using HOC would break the build.\n */\n clientOnly?: boolean;\n /** Import specifier for the runtime. Overridable for testing and monorepos. */\n importSource?: string;\n /** Root used to make source locations relative. Defaults to `process.cwd()`. */\n root?: string;\n}\n\ninterface State extends PluginPass {\n opts: RenderDetectivePluginOptions;\n rrdLocal?: BabelTypes.Identifier;\n rrdTouched?: boolean;\n rrdRelativePath?: string;\n}\n\nconst DEFAULT_IMPORT_SOURCE = \"react-render-detective\";\n\n/*\n * Never instrument the detective's own runtime. Its HOC returns a component\n * that renders the component it was given; instrumenting that makes it render\n * itself, and the app dies with a stack overflow before the first paint.\n *\n * node_modules covers the normal install. This covers a source alias — how the\n * bundled example consumes the package, and how anyone working on it locally\n * would too.\n */\nconst SELF_PATTERN = /[/\\\\]react-render-detective[/\\\\](src|dist)[/\\\\]/;\nconst HOC_NAMES = new Set([\"memo\", \"forwardRef\"]);\n\nexport default function renderDetectiveBabelPlugin(\n api: { types: typeof BabelTypes; assertVersion?: (v: number | string) => void },\n): PluginObject {\n const t = api.types;\n /*\n * Guards against re-processing a node we just rewrote. Using `path.skip()`\n * for that was a mistake: it skips the entire subtree, so components declared\n * *inside* another component were never instrumented — exactly the case the\n * remount diagnosis exists to catch.\n */\n const processed = new WeakSet<BabelTypes.Node>();\n // Babel 7 and 8 both work: only `types`, `NodePath` and the visitor shape are\n // used, all stable across the major.\n api.assertVersion?.(\"^7.0.0-0 || ^8.0.0-0\");\n\n /**\n * A component is an uppercase-named function that returns JSX.\n *\n * No all-caps exclusion: it was rejecting `const A = () => <i />`, a perfectly\n * ordinary component, to guard against constants that in practice are values\n * rather than functions returning JSX — and the JSX check already covers that.\n */\n const isComponentName = (name: string | undefined | null): boolean => !!name && /^[A-Z]/.test(name);\n\n function returnsJsx(path: NodePath<BabelTypes.Function>): boolean {\n let found = false;\n const body = path.get(\"body\");\n\n // Concise arrow body: `() => <div />` or `() => cond ? <a/> : <b/>`\n if (!Array.isArray(body) && !body.isBlockStatement()) {\n const node = (body as NodePath).node;\n return containsJsx(node);\n }\n\n path.traverse({\n Function(inner) {\n inner.skip(); // JSX in a nested closure belongs to that closure\n },\n ReturnStatement(ret) {\n if (ret.node.argument && containsJsx(ret.node.argument)) found = true;\n },\n });\n return found;\n }\n\n function containsJsx(node: BabelTypes.Node | null | undefined): boolean {\n if (!node) return false;\n if (t.isJSXElement(node) || t.isJSXFragment(node)) return true;\n if (t.isConditionalExpression(node)) return containsJsx(node.consequent) || containsJsx(node.alternate);\n if (t.isLogicalExpression(node)) return containsJsx(node.left) || containsJsx(node.right);\n if (t.isParenthesizedExpression(node)) return containsJsx(node.expression);\n if (t.isCallExpression(node)) {\n // `memo(() => <div />)` and friends\n return node.arguments.some((a) => containsJsx(a as BabelTypes.Node));\n }\n return false;\n }\n\n function ensureImport(path: NodePath, state: State): BabelTypes.Identifier {\n if (state.rrdLocal) return state.rrdLocal;\n const program = path.findParent((p) => p.isProgram()) as NodePath<BabelTypes.Program>;\n const local = program.scope.generateUidIdentifier(\"rrdTrack\");\n const source = state.opts.importSource ?? DEFAULT_IMPORT_SOURCE;\n program.unshiftContainer(\n \"body\",\n t.importDeclaration([t.importSpecifier(local, t.identifier(\"withRenderDetective\"))], t.stringLiteral(source)),\n );\n state.rrdLocal = local;\n return local;\n }\n\n function locationOf(node: BabelTypes.Node, state: State): string | undefined {\n const line = node.loc?.start.line;\n if (line === undefined || !state.rrdRelativePath) return undefined;\n return `${state.rrdRelativePath}:${line}:${(node.loc?.start.column ?? 0) + 1}`;\n }\n\n /** `__rrdTrack(fn, { name, source })` */\n function wrap(\n fn: BabelTypes.Expression,\n name: string,\n node: BabelTypes.Node,\n path: NodePath,\n state: State,\n ): BabelTypes.CallExpression {\n const properties: BabelTypes.ObjectProperty[] = [\n t.objectProperty(t.identifier(\"name\"), t.stringLiteral(name)),\n ];\n const source = locationOf(node, state);\n if (source) properties.push(t.objectProperty(t.identifier(\"source\"), t.stringLiteral(source)));\n\n /*\n * Whether a component is declared inside another function is a *static*\n * fact, and the compiler is standing right here. The runtime previously\n * guessed at it by timing repeated definitions, which failed the moment a\n * user clicked more than five seconds apart.\n */\n if (path.getFunctionParent()) {\n properties.push(t.objectProperty(t.identifier(\"declaredInRender\"), t.booleanLiteral(true)));\n }\n state.rrdTouched = true;\n return t.callExpression(ensureImport(path, state), [fn, t.objectExpression(properties)]);\n }\n\n /** Already wrapped, by hand or by a previous pass. */\n function isAlreadyWrapped(path: NodePath): boolean {\n const parent = path.parentPath;\n if (!parent?.isCallExpression()) return false;\n const callee = parent.node.callee;\n if (t.isIdentifier(callee) && /rrdTrack|withRenderDetective/.test(callee.name)) return true;\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: \"withRenderDetective\" })) return true;\n return false;\n }\n\n return {\n name: \"react-render-detective\",\n\n pre(this: State, file: { opts: { filename?: string | null; root?: string | null } }) {\n const state = this;\n const filename = file.opts.filename ?? \"\";\n const root = state.opts.root ?? file.opts.root ?? process.cwd();\n state.rrdRelativePath = filename.startsWith(root) ? filename.slice(root.length).replace(/^[/\\\\]/, \"\") : filename;\n },\n\n visitor: {\n Program: {\n enter(path: NodePath<BabelTypes.Program>, state: State) {\n const enabled = state.opts.enabled ?? process.env.NODE_ENV !== \"production\";\n const filename = state.file.opts.filename ?? \"\";\n\n const skip =\n !enabled ||\n !filename ||\n /node_modules/.test(filename) ||\n SELF_PATTERN.test(filename) ||\n !matches(filename, state.opts.include, true) ||\n matches(filename, state.opts.exclude, false) ||\n (state.opts.clientOnly === true && !hasUseClient(path.node));\n\n if (skip) path.skip();\n },\n },\n\n /** `function Foo() { return <div /> }` */\n FunctionDeclaration(path: NodePath<BabelTypes.FunctionDeclaration>, state: State) {\n const id = path.node.id;\n if (!id || !isComponentName(id.name)) return;\n if (!returnsJsx(path as NodePath<BabelTypes.Function>)) return;\n\n /*\n * Reassign rather than rewrite the declaration: function declarations\n * hoist, and components are routinely used above their definition. A\n * `const` would turn that into a temporal dead zone error at runtime.\n * ESM export bindings are live, so `export function Foo` still exports\n * the wrapper.\n */\n if (processed.has(path.node)) return;\n processed.add(path.node);\n\n const wrapped = wrap(t.cloneNode(id), id.name, path.node, path, state);\n const assignment = t.expressionStatement(t.assignmentExpression(\"=\", t.cloneNode(id), wrapped));\n (assignment as { _rrdGenerated?: boolean })._rrdGenerated = true;\n\n const statementParent = path.getStatementParent();\n if (path.parentPath.isExportDefaultDeclaration() || path.parentPath.isExportNamedDeclaration()) {\n statementParent?.insertAfter(assignment);\n } else {\n path.insertAfter(assignment);\n }\n },\n\n /** `const Foo = () => <div />` and `const Foo = memo(() => <div />)` */\n VariableDeclarator(path: NodePath<BabelTypes.VariableDeclarator>, state: State) {\n const id = path.node.id;\n const init = path.node.init;\n if (!t.isIdentifier(id) || !init || !isComponentName(id.name)) return;\n\n // Unwrap one level of memo()/forwardRef() so the instrumentation sits\n // inside them: memo compares props before our wrapper ever renders.\n let target: NodePath = path.get(\"init\") as NodePath;\n if (target.isCallExpression()) {\n const callee = target.node.callee;\n const isHoc =\n (t.isIdentifier(callee) && HOC_NAMES.has(callee.name)) ||\n (t.isMemberExpression(callee) && t.isIdentifier(callee.property) && HOC_NAMES.has(callee.property.name));\n if (!isHoc) return;\n const first = (target.get(\"arguments\") as NodePath[])[0];\n if (!first) return;\n target = first;\n }\n\n if (!target.isArrowFunctionExpression() && !target.isFunctionExpression()) return;\n if (isAlreadyWrapped(target)) return;\n if (!returnsJsx(target as NodePath<BabelTypes.Function>)) return;\n\n if (processed.has(path.node)) return;\n processed.add(path.node);\n target.replaceWith(wrap(target.node as BabelTypes.Expression, id.name, path.node, path, state));\n },\n\n /** `export default function () { return <div /> }` */\n ExportDefaultDeclaration(path: NodePath<BabelTypes.ExportDefaultDeclaration>, state: State) {\n const declaration = path.get(\"declaration\");\n if (!declaration.isFunctionDeclaration() || declaration.node.id) return; // named ones are handled above\n if (!returnsJsx(declaration as NodePath<BabelTypes.Function>)) return;\n\n const name = componentNameFromFile(state.rrdRelativePath ?? \"Default\");\n const expression = t.functionExpression(\n null,\n declaration.node.params as BabelTypes.Identifier[],\n declaration.node.body,\n declaration.node.generator,\n declaration.node.async,\n );\n if (processed.has(path.node)) return;\n processed.add(path.node);\n path.replaceWith(t.exportDefaultDeclaration(wrap(expression, name, declaration.node, path, state)));\n },\n },\n };\n}\n\nfunction matches(filename: string, patterns: Array<string | RegExp> | undefined, whenEmpty: boolean): boolean {\n if (!patterns || patterns.length === 0) return whenEmpty;\n return patterns.some((p) => (typeof p === \"string\" ? filename.includes(p) : p.test(filename)));\n}\n\nfunction hasUseClient(program: BabelTypes.Program): boolean {\n return program.directives.some((d) => d.value.value === \"use client\");\n}\n\n/** `src/components/UserCard.tsx` → `UserCard` */\nfunction componentNameFromFile(path: string): string {\n const base = path.split(/[/\\\\]/).pop() ?? \"Default\";\n const stem = base.replace(/\\.[jt]sx?$/, \"\");\n const cleaned = stem === \"index\" ? (path.split(/[/\\\\]/).slice(-2)[0] ?? \"Default\") : stem;\n const pascal = cleaned.replace(/(^|[-_.])(\\w)/g, (_, __, c: string) => c.toUpperCase());\n return /^[A-Z]/.test(pascal) ? pascal : `Component${pascal}`;\n}\n"]}
@@ -6,6 +6,7 @@ var SELF_PATTERN = /[/\\]react-render-detective[/\\](src|dist)[/\\]/;
6
6
  var HOC_NAMES = /* @__PURE__ */ new Set(["memo", "forwardRef"]);
7
7
  function renderDetectiveBabelPlugin(api) {
8
8
  const t = api.types;
9
+ const processed = /* @__PURE__ */ new WeakSet();
9
10
  api.assertVersion?.("^7.0.0-0 || ^8.0.0-0");
10
11
  const isComponentName = (name) => !!name && /^[A-Z]/.test(name);
11
12
  function returnsJsx(path) {
@@ -59,6 +60,9 @@ function renderDetectiveBabelPlugin(api) {
59
60
  ];
60
61
  const source = locationOf(node, state);
61
62
  if (source) properties.push(t.objectProperty(t.identifier("source"), t.stringLiteral(source)));
63
+ if (path.getFunctionParent()) {
64
+ properties.push(t.objectProperty(t.identifier("declaredInRender"), t.booleanLiteral(true)));
65
+ }
62
66
  state.rrdTouched = true;
63
67
  return t.callExpression(ensureImport(path, state), [fn, t.objectExpression(properties)]);
64
68
  }
@@ -92,6 +96,8 @@ function renderDetectiveBabelPlugin(api) {
92
96
  const id = path.node.id;
93
97
  if (!id || !isComponentName(id.name)) return;
94
98
  if (!returnsJsx(path)) return;
99
+ if (processed.has(path.node)) return;
100
+ processed.add(path.node);
95
101
  const wrapped = wrap(t.cloneNode(id), id.name, path.node, path, state);
96
102
  const assignment = t.expressionStatement(t.assignmentExpression("=", t.cloneNode(id), wrapped));
97
103
  assignment._rrdGenerated = true;
@@ -101,7 +107,6 @@ function renderDetectiveBabelPlugin(api) {
101
107
  } else {
102
108
  path.insertAfter(assignment);
103
109
  }
104
- path.skip();
105
110
  },
106
111
  /** `const Foo = () => <div />` and `const Foo = memo(() => <div />)` */
107
112
  VariableDeclarator(path, state) {
@@ -120,8 +125,9 @@ function renderDetectiveBabelPlugin(api) {
120
125
  if (!target.isArrowFunctionExpression() && !target.isFunctionExpression()) return;
121
126
  if (isAlreadyWrapped(target)) return;
122
127
  if (!returnsJsx(target)) return;
128
+ if (processed.has(path.node)) return;
129
+ processed.add(path.node);
123
130
  target.replaceWith(wrap(target.node, id.name, path.node, path, state));
124
- path.skip();
125
131
  },
126
132
  /** `export default function () { return <div /> }` */
127
133
  ExportDefaultDeclaration(path, state) {
@@ -136,8 +142,9 @@ function renderDetectiveBabelPlugin(api) {
136
142
  declaration.node.generator,
137
143
  declaration.node.async
138
144
  );
145
+ if (processed.has(path.node)) return;
146
+ processed.add(path.node);
139
147
  path.replaceWith(t.exportDefaultDeclaration(wrap(expression, name, declaration.node, path, state)));
140
- path.skip();
141
148
  }
142
149
  }
143
150
  };
@@ -158,5 +165,5 @@ function componentNameFromFile(path) {
158
165
  }
159
166
 
160
167
  exports.renderDetectiveBabelPlugin = renderDetectiveBabelPlugin;
161
- //# sourceMappingURL=chunk-BPNLNIHU.cjs.map
162
- //# sourceMappingURL=chunk-BPNLNIHU.cjs.map
168
+ //# sourceMappingURL=chunk-PHYYA67T.cjs.map
169
+ //# sourceMappingURL=chunk-PHYYA67T.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/babel/index.ts"],"names":[],"mappings":"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","file":"chunk-PHYYA67T.cjs","sourcesContent":["/**\n * Babel plugin: instrument every React component in a file at build time.\n *\n * Why this exists: without it you only learn about components you already\n * suspected, because you have to wrap them by hand. With it, the tool reports\n * on the whole tree — and it can attach a real source location, which React\n * itself no longer exposes at runtime (`_debugSource` was removed in React 19).\n *\n * Build-time only. It must never run in a production build, and it removes\n * itself when `NODE_ENV` is production unless explicitly forced.\n */\nimport type { NodePath, PluginObject, PluginPass, types as BabelTypes } from \"@babel/core\";\n\nexport interface RenderDetectivePluginOptions {\n /** Defaults to `NODE_ENV !== \"production\"`. */\n enabled?: boolean;\n /** Only instrument files whose path matches. Empty = all files. */\n include?: Array<string | RegExp>;\n /** Skip files whose path matches. Applied after `include`. */\n exclude?: Array<string | RegExp>;\n /**\n * Skip files with no `\"use client\"` directive. Turn this on for the Next.js\n * app router: server components never render on the client, and wrapping one\n * in a hook-using HOC would break the build.\n */\n clientOnly?: boolean;\n /** Import specifier for the runtime. Overridable for testing and monorepos. */\n importSource?: string;\n /** Root used to make source locations relative. Defaults to `process.cwd()`. */\n root?: string;\n}\n\ninterface State extends PluginPass {\n opts: RenderDetectivePluginOptions;\n rrdLocal?: BabelTypes.Identifier;\n rrdTouched?: boolean;\n rrdRelativePath?: string;\n}\n\nconst DEFAULT_IMPORT_SOURCE = \"react-render-detective\";\n\n/*\n * Never instrument the detective's own runtime. Its HOC returns a component\n * that renders the component it was given; instrumenting that makes it render\n * itself, and the app dies with a stack overflow before the first paint.\n *\n * node_modules covers the normal install. This covers a source alias — how the\n * bundled example consumes the package, and how anyone working on it locally\n * would too.\n */\nconst SELF_PATTERN = /[/\\\\]react-render-detective[/\\\\](src|dist)[/\\\\]/;\nconst HOC_NAMES = new Set([\"memo\", \"forwardRef\"]);\n\nexport default function renderDetectiveBabelPlugin(\n api: { types: typeof BabelTypes; assertVersion?: (v: number | string) => void },\n): PluginObject {\n const t = api.types;\n /*\n * Guards against re-processing a node we just rewrote. Using `path.skip()`\n * for that was a mistake: it skips the entire subtree, so components declared\n * *inside* another component were never instrumented — exactly the case the\n * remount diagnosis exists to catch.\n */\n const processed = new WeakSet<BabelTypes.Node>();\n // Babel 7 and 8 both work: only `types`, `NodePath` and the visitor shape are\n // used, all stable across the major.\n api.assertVersion?.(\"^7.0.0-0 || ^8.0.0-0\");\n\n /**\n * A component is an uppercase-named function that returns JSX.\n *\n * No all-caps exclusion: it was rejecting `const A = () => <i />`, a perfectly\n * ordinary component, to guard against constants that in practice are values\n * rather than functions returning JSX — and the JSX check already covers that.\n */\n const isComponentName = (name: string | undefined | null): boolean => !!name && /^[A-Z]/.test(name);\n\n function returnsJsx(path: NodePath<BabelTypes.Function>): boolean {\n let found = false;\n const body = path.get(\"body\");\n\n // Concise arrow body: `() => <div />` or `() => cond ? <a/> : <b/>`\n if (!Array.isArray(body) && !body.isBlockStatement()) {\n const node = (body as NodePath).node;\n return containsJsx(node);\n }\n\n path.traverse({\n Function(inner) {\n inner.skip(); // JSX in a nested closure belongs to that closure\n },\n ReturnStatement(ret) {\n if (ret.node.argument && containsJsx(ret.node.argument)) found = true;\n },\n });\n return found;\n }\n\n function containsJsx(node: BabelTypes.Node | null | undefined): boolean {\n if (!node) return false;\n if (t.isJSXElement(node) || t.isJSXFragment(node)) return true;\n if (t.isConditionalExpression(node)) return containsJsx(node.consequent) || containsJsx(node.alternate);\n if (t.isLogicalExpression(node)) return containsJsx(node.left) || containsJsx(node.right);\n if (t.isParenthesizedExpression(node)) return containsJsx(node.expression);\n if (t.isCallExpression(node)) {\n // `memo(() => <div />)` and friends\n return node.arguments.some((a) => containsJsx(a as BabelTypes.Node));\n }\n return false;\n }\n\n function ensureImport(path: NodePath, state: State): BabelTypes.Identifier {\n if (state.rrdLocal) return state.rrdLocal;\n const program = path.findParent((p) => p.isProgram()) as NodePath<BabelTypes.Program>;\n const local = program.scope.generateUidIdentifier(\"rrdTrack\");\n const source = state.opts.importSource ?? DEFAULT_IMPORT_SOURCE;\n program.unshiftContainer(\n \"body\",\n t.importDeclaration([t.importSpecifier(local, t.identifier(\"withRenderDetective\"))], t.stringLiteral(source)),\n );\n state.rrdLocal = local;\n return local;\n }\n\n function locationOf(node: BabelTypes.Node, state: State): string | undefined {\n const line = node.loc?.start.line;\n if (line === undefined || !state.rrdRelativePath) return undefined;\n return `${state.rrdRelativePath}:${line}:${(node.loc?.start.column ?? 0) + 1}`;\n }\n\n /** `__rrdTrack(fn, { name, source })` */\n function wrap(\n fn: BabelTypes.Expression,\n name: string,\n node: BabelTypes.Node,\n path: NodePath,\n state: State,\n ): BabelTypes.CallExpression {\n const properties: BabelTypes.ObjectProperty[] = [\n t.objectProperty(t.identifier(\"name\"), t.stringLiteral(name)),\n ];\n const source = locationOf(node, state);\n if (source) properties.push(t.objectProperty(t.identifier(\"source\"), t.stringLiteral(source)));\n\n /*\n * Whether a component is declared inside another function is a *static*\n * fact, and the compiler is standing right here. The runtime previously\n * guessed at it by timing repeated definitions, which failed the moment a\n * user clicked more than five seconds apart.\n */\n if (path.getFunctionParent()) {\n properties.push(t.objectProperty(t.identifier(\"declaredInRender\"), t.booleanLiteral(true)));\n }\n state.rrdTouched = true;\n return t.callExpression(ensureImport(path, state), [fn, t.objectExpression(properties)]);\n }\n\n /** Already wrapped, by hand or by a previous pass. */\n function isAlreadyWrapped(path: NodePath): boolean {\n const parent = path.parentPath;\n if (!parent?.isCallExpression()) return false;\n const callee = parent.node.callee;\n if (t.isIdentifier(callee) && /rrdTrack|withRenderDetective/.test(callee.name)) return true;\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: \"withRenderDetective\" })) return true;\n return false;\n }\n\n return {\n name: \"react-render-detective\",\n\n pre(this: State, file: { opts: { filename?: string | null; root?: string | null } }) {\n const state = this;\n const filename = file.opts.filename ?? \"\";\n const root = state.opts.root ?? file.opts.root ?? process.cwd();\n state.rrdRelativePath = filename.startsWith(root) ? filename.slice(root.length).replace(/^[/\\\\]/, \"\") : filename;\n },\n\n visitor: {\n Program: {\n enter(path: NodePath<BabelTypes.Program>, state: State) {\n const enabled = state.opts.enabled ?? process.env.NODE_ENV !== \"production\";\n const filename = state.file.opts.filename ?? \"\";\n\n const skip =\n !enabled ||\n !filename ||\n /node_modules/.test(filename) ||\n SELF_PATTERN.test(filename) ||\n !matches(filename, state.opts.include, true) ||\n matches(filename, state.opts.exclude, false) ||\n (state.opts.clientOnly === true && !hasUseClient(path.node));\n\n if (skip) path.skip();\n },\n },\n\n /** `function Foo() { return <div /> }` */\n FunctionDeclaration(path: NodePath<BabelTypes.FunctionDeclaration>, state: State) {\n const id = path.node.id;\n if (!id || !isComponentName(id.name)) return;\n if (!returnsJsx(path as NodePath<BabelTypes.Function>)) return;\n\n /*\n * Reassign rather than rewrite the declaration: function declarations\n * hoist, and components are routinely used above their definition. A\n * `const` would turn that into a temporal dead zone error at runtime.\n * ESM export bindings are live, so `export function Foo` still exports\n * the wrapper.\n */\n if (processed.has(path.node)) return;\n processed.add(path.node);\n\n const wrapped = wrap(t.cloneNode(id), id.name, path.node, path, state);\n const assignment = t.expressionStatement(t.assignmentExpression(\"=\", t.cloneNode(id), wrapped));\n (assignment as { _rrdGenerated?: boolean })._rrdGenerated = true;\n\n const statementParent = path.getStatementParent();\n if (path.parentPath.isExportDefaultDeclaration() || path.parentPath.isExportNamedDeclaration()) {\n statementParent?.insertAfter(assignment);\n } else {\n path.insertAfter(assignment);\n }\n },\n\n /** `const Foo = () => <div />` and `const Foo = memo(() => <div />)` */\n VariableDeclarator(path: NodePath<BabelTypes.VariableDeclarator>, state: State) {\n const id = path.node.id;\n const init = path.node.init;\n if (!t.isIdentifier(id) || !init || !isComponentName(id.name)) return;\n\n // Unwrap one level of memo()/forwardRef() so the instrumentation sits\n // inside them: memo compares props before our wrapper ever renders.\n let target: NodePath = path.get(\"init\") as NodePath;\n if (target.isCallExpression()) {\n const callee = target.node.callee;\n const isHoc =\n (t.isIdentifier(callee) && HOC_NAMES.has(callee.name)) ||\n (t.isMemberExpression(callee) && t.isIdentifier(callee.property) && HOC_NAMES.has(callee.property.name));\n if (!isHoc) return;\n const first = (target.get(\"arguments\") as NodePath[])[0];\n if (!first) return;\n target = first;\n }\n\n if (!target.isArrowFunctionExpression() && !target.isFunctionExpression()) return;\n if (isAlreadyWrapped(target)) return;\n if (!returnsJsx(target as NodePath<BabelTypes.Function>)) return;\n\n if (processed.has(path.node)) return;\n processed.add(path.node);\n target.replaceWith(wrap(target.node as BabelTypes.Expression, id.name, path.node, path, state));\n },\n\n /** `export default function () { return <div /> }` */\n ExportDefaultDeclaration(path: NodePath<BabelTypes.ExportDefaultDeclaration>, state: State) {\n const declaration = path.get(\"declaration\");\n if (!declaration.isFunctionDeclaration() || declaration.node.id) return; // named ones are handled above\n if (!returnsJsx(declaration as NodePath<BabelTypes.Function>)) return;\n\n const name = componentNameFromFile(state.rrdRelativePath ?? \"Default\");\n const expression = t.functionExpression(\n null,\n declaration.node.params as BabelTypes.Identifier[],\n declaration.node.body,\n declaration.node.generator,\n declaration.node.async,\n );\n if (processed.has(path.node)) return;\n processed.add(path.node);\n path.replaceWith(t.exportDefaultDeclaration(wrap(expression, name, declaration.node, path, state)));\n },\n },\n };\n}\n\nfunction matches(filename: string, patterns: Array<string | RegExp> | undefined, whenEmpty: boolean): boolean {\n if (!patterns || patterns.length === 0) return whenEmpty;\n return patterns.some((p) => (typeof p === \"string\" ? filename.includes(p) : p.test(filename)));\n}\n\nfunction hasUseClient(program: BabelTypes.Program): boolean {\n return program.directives.some((d) => d.value.value === \"use client\");\n}\n\n/** `src/components/UserCard.tsx` → `UserCard` */\nfunction componentNameFromFile(path: string): string {\n const base = path.split(/[/\\\\]/).pop() ?? \"Default\";\n const stem = base.replace(/\\.[jt]sx?$/, \"\");\n const cleaned = stem === \"index\" ? (path.split(/[/\\\\]/).slice(-2)[0] ?? \"Default\") : stem;\n const pascal = cleaned.replace(/(^|[-_.])(\\w)/g, (_, __, c: string) => c.toUpperCase());\n return /^[A-Z]/.test(pascal) ? pascal : `Component${pascal}`;\n}\n"]}
@@ -324,6 +324,21 @@ function diagnose(input, thresholds) {
324
324
  function classify(input) {
325
325
  const { changedProps, contextChanges, parentRendered, parentUnknown, parentName } = input;
326
326
  if (input.phase === "mount") {
327
+ if (input.remounts >= 2) {
328
+ const inline = input.inlineDefinitionSuspected;
329
+ return make(
330
+ "mount",
331
+ inline ? "high" : "medium",
332
+ `${input.componentName} was rebuilt, not re-rendered \u2014 this is remount ${input.remounts + 1}.`,
333
+ [
334
+ `This component has been unmounted and mounted again ${input.remounts}\xD7 \u2014 its DOM and all of its state were discarded each time.`,
335
+ inline ? "Its definition is being re-created repeatedly in a short window, which means it is declared *inside* another component's render body. React sees a new component type on every parent render and cannot reuse anything." : "Its definition is stable, so the remounts come from the element identity changing \u2014 usually a changing `key`, or the component moving between branches of a conditional.",
336
+ "A remount is much more expensive than a re-render, and it resets state."
337
+ ],
338
+ true,
339
+ inline ? `Move ${input.componentName} out of its parent's render body to module scope. Defining a component inside another component makes React discard and rebuild the whole subtree on every parent render.` : `Check the \`key\` given to ${input.componentName}, and whether it is being rendered from a different branch each time.`
340
+ );
341
+ }
327
342
  return make("mount", "high", `${input.componentName} mounted.`, ["First render of this instance."], false);
328
343
  }
329
344
  if (input.trackedState.length > 0) {
@@ -570,6 +585,8 @@ var RingBuffer = class {
570
585
 
571
586
  // src/core/store.ts
572
587
  var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
588
+ var INLINE_DEFINITION_WINDOW_MS = 5e3;
589
+ var timestamp = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
573
590
  var EMPTY_STATE = [];
574
591
  var DURATION_SAMPLE = 200;
575
592
  var SWEEP_DELAY_MS = 250;
@@ -593,6 +610,10 @@ var Detective = class {
593
610
  this.seq = 0;
594
611
  this.flushScheduled = false;
595
612
  this.nextId = 0;
613
+ /** Mount/unmount history per component name, for remount detection. */
614
+ this.lifecycles = /* @__PURE__ */ new Map();
615
+ /** How often each component *definition* has been wrapped. */
616
+ this.definitions = /* @__PURE__ */ new Map();
596
617
  /** Nodes created by `useRenderDiagnostics`, where props/state cannot be separated. */
597
618
  this.hookModeNodes = /* @__PURE__ */ new WeakSet();
598
619
  this.initialized = false;
@@ -666,9 +687,66 @@ var Detective = class {
666
687
  }
667
688
  attach(node) {
668
689
  this.nodes.set(node.id, node);
690
+ if (node.detached) {
691
+ node.detached = false;
692
+ const existing = this.lifecycles.get(node.name);
693
+ if (existing) existing.unmounts--;
694
+ return;
695
+ }
696
+ if (node.everAttached) return;
697
+ node.everAttached = true;
698
+ const life = this.lifecycleFor(node.name);
699
+ life.mounts++;
700
+ if (life.unmounts > 0) life.remounts++;
669
701
  }
670
702
  detach(node) {
671
703
  this.nodes.delete(node.id);
704
+ if (node.everAttached && !node.detached) {
705
+ node.detached = true;
706
+ this.lifecycleFor(node.name).unmounts++;
707
+ }
708
+ }
709
+ lifecycleFor(name) {
710
+ let life = this.lifecycles.get(name);
711
+ if (!life) this.lifecycles.set(name, life = { mounts: 0, unmounts: 0, remounts: 0 });
712
+ return life;
713
+ }
714
+ /**
715
+ * Called once per `withRenderDetective` call. A component declared at module
716
+ * scope is wrapped once; one declared *inside* a render body is wrapped again
717
+ * on every render of its parent — which also forces React to throw away and
718
+ * rebuild its entire subtree. That is the signal.
719
+ */
720
+ noteDefinition(name, source, declaredInRender = false) {
721
+ const key = source ?? name;
722
+ const now2 = timestamp();
723
+ const record = this.definitions.get(key);
724
+ if (!record) {
725
+ this.definitions.set(key, { name, count: 1, firstSeen: now2, lastSeen: now2, declaredInRender });
726
+ return;
727
+ }
728
+ record.count++;
729
+ record.lastSeen = now2;
730
+ if (declaredInRender) record.declaredInRender = true;
731
+ }
732
+ /**
733
+ * Is this component declared inside another component's render body?
734
+ *
735
+ * The build plugin answers this statically and exactly. Without it we fall
736
+ * back to a rate heuristic — repeated definitions of the same component in a
737
+ * short window — which is weaker: hot reload also re-defines components, and
738
+ * a user clicking slowly stretches the window. Hence the plugin's answer wins.
739
+ */
740
+ inlineDefinitionSuspected(name) {
741
+ for (const record of this.definitions.values()) {
742
+ if (record.name !== name) continue;
743
+ if (record.declaredInRender) return true;
744
+ if (record.count >= 3 && record.lastSeen - record.firstSeen < INLINE_DEFINITION_WINDOW_MS) return true;
745
+ }
746
+ return false;
747
+ }
748
+ lifecycleOf(name) {
749
+ return this.lifecycles.get(name) ?? { mounts: 0, unmounts: 0, remounts: 0 };
672
750
  }
673
751
  /** Hot path. Must stay allocation-free and O(1). */
674
752
  recordAttempt(node, props) {
@@ -825,6 +903,8 @@ var Detective = class {
825
903
  attempts: rec.attempts,
826
904
  committed: true,
827
905
  trackedState,
906
+ remounts: this.lifecycleOf(node.name).remounts,
907
+ inlineDefinitionSuspected: this.inlineDefinitionSuspected(node.name),
828
908
  priorAvoidableRenders: node.stats.potentiallyAvoidableRenders
829
909
  },
830
910
  this.config.thresholds
@@ -906,7 +986,7 @@ var Detective = class {
906
986
  for (const node of this.nodes.values()) {
907
987
  if (name && node.name !== name) continue;
908
988
  if (node.stats.renderCount === 0 && node.stats.uncommittedAttempts === 0) continue;
909
- out.push(toStats(node));
989
+ out.push(toStats(node, this.lifecycleOf(node.name)));
910
990
  }
911
991
  return out;
912
992
  }
@@ -954,6 +1034,8 @@ var Detective = class {
954
1034
  reset() {
955
1035
  this.clear();
956
1036
  this.nodes.clear();
1037
+ this.lifecycles.clear();
1038
+ this.definitions.clear();
957
1039
  this.listeners.clear();
958
1040
  if (this.sweepHandle !== void 0) clearTimeout(this.sweepHandle);
959
1041
  this.sweepHandle = void 0;
@@ -967,7 +1049,7 @@ function percentile(sorted, p) {
967
1049
  const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p / 100 * sorted.length) - 1));
968
1050
  return sorted[idx];
969
1051
  }
970
- function toStats(node) {
1052
+ function toStats(node, lifecycle) {
971
1053
  const sorted = [...node.durations].sort((a, b) => a - b);
972
1054
  const s = node.stats;
973
1055
  return {
@@ -976,6 +1058,7 @@ function toStats(node) {
976
1058
  source: node.source,
977
1059
  renderCount: s.renderCount,
978
1060
  mountCount: s.mountCount,
1061
+ remountCount: lifecycle.remounts,
979
1062
  uncommittedAttempts: s.uncommittedAttempts,
980
1063
  devReplays: s.devReplays,
981
1064
  totalSelfDuration: s.totalSelfDuration,
@@ -1000,6 +1083,7 @@ function mergeStats(a, b) {
1000
1083
  source: a.source ?? b.source,
1001
1084
  renderCount,
1002
1085
  mountCount: a.mountCount + b.mountCount,
1086
+ remountCount: Math.max(a.remountCount, b.remountCount),
1003
1087
  uncommittedAttempts: a.uncommittedAttempts + b.uncommittedAttempts,
1004
1088
  devReplays: a.devReplays + b.devReplays,
1005
1089
  totalSelfDuration: total,
@@ -1021,5 +1105,5 @@ function getDetective() {
1021
1105
  }
1022
1106
 
1023
1107
  export { Detective, RingBuffer, defaultConfig, detectDev, diagnose, diffProps, formatInspected, getDetective, inspect, isPlainObject, isReactElement, matches, mergeConfig, severityFor, shallowEqual, shouldInstrument, valueType };
1024
- //# sourceMappingURL=chunk-MSISKPST.js.map
1025
- //# sourceMappingURL=chunk-MSISKPST.js.map
1108
+ //# sourceMappingURL=chunk-QOGTEVBP.js.map
1109
+ //# sourceMappingURL=chunk-QOGTEVBP.js.map