@squiggle.sh/babel-plugin 0.1.0 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -12,9 +12,30 @@ type BabelTypes = {
12
12
  variableDeclaration(kind: string, declarations: unknown[]): unknown;
13
13
  variableDeclarator(id: unknown, init: unknown): unknown;
14
14
  callExpression(callee: unknown, args: unknown[]): unknown;
15
+ jsxExpressionContainer(expr: unknown): unknown;
16
+ arrayExpression(elements: unknown[]): unknown;
17
+ };
18
+ type BabelTemplate = {
19
+ statements: {
20
+ ast(code: string): unknown[];
21
+ };
22
+ };
23
+ type PluginApi = {
24
+ types: BabelTypes;
25
+ template?: BabelTemplate;
26
+ caller?<T>(cb: (caller: {
27
+ isDev?: boolean;
28
+ } | undefined) => T): T;
15
29
  };
16
30
  type BabelNode = {
17
31
  type: string;
32
+ name?: unknown;
33
+ property?: {
34
+ name?: string;
35
+ };
36
+ openingElement?: {
37
+ name: BabelNode;
38
+ };
18
39
  id?: {
19
40
  name?: string;
20
41
  } | null;
@@ -51,7 +72,7 @@ type Scope = {
51
72
  generateUidIdentifier(name: string): {
52
73
  name: string;
53
74
  };
54
- getProgramParent(): {
75
+ getProgramParent(): Scope & {
55
76
  path: ProgramPath;
56
77
  };
57
78
  };
@@ -63,6 +84,10 @@ type NodePath = {
63
84
  parentPath?: NodePath | null;
64
85
  scope: Scope;
65
86
  insertAfter(node: unknown): void;
87
+ replaceWith(node: unknown): void;
88
+ get(key: 'body'): NodePath[];
89
+ traverse(visitor: Record<string, unknown>): void;
90
+ skip(): void;
66
91
  };
67
92
  type ImportNodePath = {
68
93
  node: ImportDeclarationNode;
@@ -73,22 +98,35 @@ type BabelState = {
73
98
  filename?: string;
74
99
  squiggleHelperLocals?: Record<string, string>;
75
100
  squiggleFileLocal?: string;
101
+ squiggleSites?: {
102
+ line: number;
103
+ col: number;
104
+ }[];
105
+ squiggleTagLocal?: string;
106
+ squiggleSitesLocal?: string;
107
+ squiggleSitesInit?: string;
76
108
  };
77
109
  interface SquiggleBabelOptions {
78
110
  instrumentZustand?: boolean;
79
111
  instrumentMmkv?: boolean;
80
112
  instrumentAsyncStorage?: boolean;
81
113
  instrumentSqlite?: boolean;
114
+ instrumentLegendState?: boolean;
82
115
  helperModule?: string;
83
116
  zustandHelperModule?: string;
84
117
  rootDir?: string;
118
+ callSites?: boolean;
85
119
  stripInProduction?: boolean;
86
120
  }
87
- declare function squiggleBabelPlugin(_api: {
88
- types: BabelTypes;
89
- }, options?: SquiggleBabelOptions): {
121
+ declare function squiggleBabelPlugin(_api: PluginApi, options?: SquiggleBabelOptions): {
90
122
  name: string;
91
123
  visitor: {
124
+ Program: {
125
+ exit(path: NodePath, state: BabelState): void;
126
+ };
127
+ JSXElement: {
128
+ exit(path: NodePath, state: BabelState): void;
129
+ };
92
130
  ImportDeclaration(path: ImportNodePath, state: BabelState): void;
93
131
  FunctionDeclaration(path: NodePath, state: BabelState): void;
94
132
  VariableDeclarator(path: NodePath, state: BabelState): void;
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- var{defineProperty:H,getOwnPropertyNames:A,getOwnPropertyDescriptor:f}=Object,T=Object.prototype.hasOwnProperty;function y(q){return this[q]}var L=(q)=>{var k=(P??=new WeakMap).get(q),j;if(k)return k;if(k=H({},"__esModule",{value:!0}),q&&typeof q==="object"||typeof q==="function"){for(var K of A(q))if(!T.call(k,K))H(k,K,{get:y.bind(q,K),enumerable:!(j=f(q,K))||j.enumerable})}return P.set(q,k),k},P;var b=(q)=>q;function g(q,k){this[q]=b.bind(null,k)}var m=(q,k)=>{for(var j in k)H(q,j,{get:k[j],enumerable:!0,configurable:!0,set:g.bind(k,j)})};var i={};m(i,{default:()=>C});module.exports=L(i);var F=require("node:path"),c="@squiggle.sh/react-native",h={modules:new Set(["zustand","zustand/vanilla","zustand/react"]),names:new Set(["create","createStore"]),helper:"__squiggleInstrumentZustandFactory"},d={modules:new Set(["react-native-mmkv"]),names:new Set(["createMMKV","useMMKV"]),helper:"__squiggleInstrumentMmkvFactory"},r={modules:new Set(["@react-native-async-storage/async-storage"]),names:new Set,defaultExport:!0,helper:"__squiggleInstrumentAsyncStorage"},n={modules:new Set(["@op-engineering/op-sqlite"]),names:new Set(["open"]),helper:"__squiggleInstrumentOpSqliteFactory"},l={modules:new Set(["expo-sqlite"]),names:new Set(["openDatabaseAsync","openDatabaseSync","useSQLiteContext"]),helper:"__squiggleInstrumentExpoSqliteFactory"};function D(q){return/^[A-Z]/.test(q)}function G(q){if(!q)return!1;return q.some((k)=>{let j=k;return j?.type==="ReturnStatement"&&(j.argument?.type==="JSXElement"||j.argument?.type==="JSXFragment")})}function I(q){let k=q?.[0];if(k?.type!=="VariableDeclaration")return!1;return k.declarations?.some((j)=>j.init?.callee?.name==="_c")??!1}function S(q){if(q.type==="ArrowFunctionExpression"){let k=q.body;if(!k)return!1;if(k.type==="JSXElement"||k.type==="JSXFragment")return!0;if(k.type==="BlockStatement"){let j=k.body;return G(j)||I(j)}return!1}if(q.type==="FunctionExpression"||q.type==="FunctionDeclaration"){let k=q.body;return G(k?.body)||I(k?.body)}return!1}function C(q,k={}){let j=q.types,K=[];if(k.instrumentZustand!==!1)K.push(h);if(k.instrumentMmkv!==!1)K.push(d);if(k.instrumentAsyncStorage!==!1)K.push(r);if(k.instrumentSqlite!==!1)K.push(n,l);let N=k.helperModule??k.zustandHelperModule??c,u=k.rootDir??process.cwd(),U=k.stripInProduction===!0&&!0;function R(z){if(!F.isAbsolute(z))return z;return F.relative(u,z).split("\\").join("/")}function V(z,W){let B=W.squiggleFileLocal;if(!B){B=z.scope.generateUidIdentifier("sqFile").name,W.squiggleFileLocal=B;let $=R(W.filename??"<unknown>");z.scope.getProgramParent().path.unshiftContainer("body",j.variableDeclaration("const",[j.variableDeclarator(j.identifier(B),j.stringLiteral($))]))}return B}function _(z,W,B){let $=z.node;if($.type!=="ImportDeclaration")return;if(!B.modules.has($.source.value))return;let Y=[];for(let X of $.specifiers){if(X.type==="ImportDefaultSpecifier"){if(!B.defaultExport)continue}else if(X.type==="ImportSpecifier"){let M=X.imported,O=M?.type==="Identifier"?M.name:void 0;if(!O||!B.names.has(O))continue}else continue;let v=X.local.name,J=z.scope.generateUidIdentifier(v).name;X.local=j.identifier(J),Y.push({localName:v,uid:J})}if(Y.length===0)return;let Q=W.squiggleHelperLocals??={},Z=Q[B.helper];if(!Z){Z=z.scope.generateUidIdentifier("squiggleInstrument").name,Q[B.helper]=Z;let X=j.importDeclaration([j.importSpecifier(j.identifier(Z),j.identifier(B.helper))],j.stringLiteral(N));z.scope.getProgramParent().path.unshiftContainer("body",X)}let E=Y.map(({localName:X,uid:v})=>j.variableDeclarator(j.identifier(X),j.callExpression(j.identifier(Z),[j.identifier(v)])));z.insertAfter(j.variableDeclaration("const",E))}function w(z,W,B,$){return j.expressionStatement(j.assignmentExpression("=",j.memberExpression(j.identifier(z),j.identifier("__squiggleSrc")),j.objectExpression([j.objectProperty(j.identifier("file"),j.identifier(W)),j.objectProperty(j.identifier("line"),j.numericLiteral(B)),j.objectProperty(j.identifier("col"),j.numericLiteral($))])))}function x(z){let W=z.node.loc?.start;return{line:W?.line??0,col:W?.column??0}}return{name:"squiggle",visitor:{ImportDeclaration(z,W){for(let B of K)try{_(z,W,B)}catch{}},FunctionDeclaration(z,W){if(U)return;try{let B=z.node.id?.name;if(!B||!D(B))return;if(!S(z.node))return;let{line:$,col:Y}=x(z);z.insertAfter(w(B,V(z,W),$,Y))}catch{}},VariableDeclarator(z,W){if(U)return;try{let B=z.node.id;if(!B||B.type!=="Identifier")return;let $=B.name;if(!$||!D($))return;let Y=z.node.init;if(!Y)return;if(!S(Y))return;let{line:Q,col:Z}=x(z);z.parentPath?.insertAfter(w($,V(z,W),Q,Z))}catch{}}}}}
1
+ var{defineProperty:I,getOwnPropertyNames:h,getOwnPropertyDescriptor:m}=Object,r=Object.prototype.hasOwnProperty;function c(q){return this[q]}var p=(q)=>{var j=(N??=new WeakMap).get(q),z;if(j)return j;if(j=I({},"__esModule",{value:!0}),q&&typeof q==="object"||typeof q==="function"){for(var Y of h(q))if(!r.call(j,Y))I(j,Y,{get:c.bind(q,Y),enumerable:!(z=m(q,Y))||z.enumerable})}return N.set(q,j),j},N;var n=(q)=>q;function i(q,j){this[q]=n.bind(null,j)}var o=(q,j)=>{for(var z in j)I(q,z,{get:j[z],enumerable:!0,configurable:!0,set:i.bind(j,z)})};var xj={};o(xj,{default:()=>_});module.exports=p(xj);var v=require("node:path"),s="@squiggle.sh/react-native",k="node_modules/";function l(q){let j=q.lastIndexOf(k);return j===-1?q:k+q.slice(j+k.length)}var e={modules:new Set(["zustand","zustand/vanilla","zustand/react"]),names:new Set(["create","createStore"]),helper:"__squiggleInstrumentZustandFactory"},a={modules:new Set(["react-native-mmkv"]),names:new Set(["createMMKV","useMMKV"]),helper:"__squiggleInstrumentMmkvFactory"},t={modules:new Set(["@react-native-async-storage/async-storage"]),names:new Set,defaultExport:!0,helper:"__squiggleInstrumentAsyncStorage"},jj={modules:new Set(["@op-engineering/op-sqlite"]),names:new Set(["open"]),helper:"__squiggleInstrumentOpSqliteFactory"},qj={modules:new Set(["expo-sqlite"]),names:new Set(["openDatabaseAsync","openDatabaseSync","useSQLiteContext"]),helper:"__squiggleInstrumentExpoSqliteFactory"},zj={modules:new Set(["@legendapp/state"]),names:new Set(["observable"]),helper:"__squiggleInstrumentLegendStateFactory"},Wj={modules:new Set(["@legendapp/state/react"]),names:new Set(["useObservable"]),helper:"__squiggleInstrumentLegendStateFactory"};function M(q){return/^[A-Z]/.test(q)}function b(q){if(!q)return!1;return q.some((j)=>{let z=j;return z?.type==="ReturnStatement"&&(z.argument?.type==="JSXElement"||z.argument?.type==="JSXFragment")})}function E(q){let j=q?.[0];if(j?.type!=="VariableDeclaration")return!1;return j.declarations?.some((z)=>z.init?.callee?.name==="_c")??!1}function T(q){if(q.type==="ArrowFunctionExpression"){let j=q.body;if(!j)return!1;if(j.type==="JSXElement"||j.type==="JSXFragment")return!0;if(j.type==="BlockStatement"){let z=j.body;return b(z)||E(z)}return!1}if(q.type==="FunctionExpression"||q.type==="FunctionDeclaration"){let j=q.body;return b(j?.body)||E(j?.body)}return!1}function $j(q){let j=()=>(process.env.BABEL_ENV??"production")==="development";if(typeof q.caller!=="function")return j();return q.caller((z)=>z?.isDev??j())===!0}function Bj(q){if(!q)return!1;if(q.type==="JSXIdentifier"){let j=typeof q.name==="string"?q.name:"";return M(j)&&j!=="Fragment"}if(q.type==="JSXMemberExpression")return q.property?.name!=="Fragment";return!1}function Xj(q,j,z,Y){let X=JSON.stringify(j),Q=z.map((V)=>`{ file: ${X}, line: ${V.line}, col: ${V.col} }`).join(", ");return[`function ${q.tag}(e, i) {`," if (e != null && typeof e === 'object' && e.props) {"," var m = globalThis.__squiggleSites || (globalThis.__squiggleSites = new WeakMap());",` m.set(e.props, (${q.sites} || ${q.init}())[i]);`," }"," return e;","}",`var ${q.sites};`,`function ${q.init}() {`,` globalThis.__squiggleSourceRoot || (globalThis.__squiggleSourceRoot = ${JSON.stringify(Y)});`,` return (${q.sites} = [${Q}]);`,"}"].join(`
2
+ `)}function Yj(q){let j=q.callee;if(!j)return;if(j.type==="Identifier"&&typeof j.name==="string")return O(j.name)?{hook:j.name,expr:j.name}:void 0;if(j.type==="MemberExpression"&&!j.computed&&j.object?.type==="Identifier"&&j.property?.type==="Identifier"&&typeof j.property.name==="string"&&O(j.property.name))return{hook:j.property.name,expr:`${j.object.name}.${j.property.name}`};return}function O(q){return q==="use"||/^use[A-Z0-9]/.test(q)}var Zj=new Set(["TSAsExpression","TSNonNullExpression","TSSatisfiesExpression","TypeCastExpression","ParenthesizedExpression"]);function Kj(q){let{node:j,parentPath:z}=q;while(z&&Zj.has(z.node.type))j=z.node,z=z.parentPath;let Y=z?.node;if(Y?.type!=="VariableDeclarator"||Y.init!==j)return;let X=Y.id;if(!X)return;if(X.type==="Identifier")return X.name;if(X.type==="ArrayPattern"){let Q=X.elements?.[0];return Q?.type==="Identifier"?Q.name:void 0}if(X.type==="ObjectPattern"){let Q=(X.properties??[]).map((V)=>V.type==="ObjectProperty"?V.key?.name:void 0).filter((V)=>typeof V==="string");return Q.length>0?`{ ${Q.join(", ")} }`:void 0}return}var Qj=new Set(["use","useState","useReducer","useRef","useMemo","useCallback","useEffect","useLayoutEffect","useInsertionEffect","useImperativeHandle","useContext","useId","useTransition","useDeferredValue","useSyncExternalStore","useDebugValue","useOptimistic","useActionState","useFormState","useFormStatus","useEffectEvent"]);function Fj(q){let j=[];return q.traverse({Function(z){z.skip()},CallExpression:{exit(z){let Y=Yj(z.node);if(!Y)return;let X={hook:Y.hook},Q=Kj(z);if(Q!==void 0)X.name=Q;if(!Qj.has(Y.hook))X.ref=Y.expr;j.push(X)}}}),j}function Vj(q,j){let z=j.map((Y)=>{let X=[`hook: ${JSON.stringify(Y.hook)}`];if(Y.name!==void 0)X.push(`name: ${JSON.stringify(Y.name)}`);if(Y.ref!==void 0)X.push(`ref: function () { return ${Y.ref}; }`);return`{ ${X.join(", ")} }`});return`${q}.__squiggleHooks = [${z.join(", ")}];`}function Jj(q){let j=q.parentPath?.node.type;return j==="Program"||j==="ExportNamedDeclaration"||j==="ExportDefaultDeclaration"}function _(q,j={}){let z=q.types,Y=j.callSites??$j(q),X=[];if(j.instrumentZustand!==!1)X.push(e);if(j.instrumentMmkv!==!1)X.push(a);if(j.instrumentAsyncStorage!==!1)X.push(t);if(j.instrumentSqlite!==!1)X.push(jj,qj);if(j.instrumentLegendState!==!1)X.push(zj,Wj);let Q=j.helperModule??j.zustandHelperModule??s,V=j.rootDir??process.cwd(),u=j.stripInProduction===!0&&!0;function y(W){let B=v.isAbsolute(W)?v.relative(V,W).split("\\").join("/"):W;return l(B)}function D(W,B){let $=B.squiggleFileLocal;if(!$){$=W.scope.generateUidIdentifier("sqFile").name,B.squiggleFileLocal=$;let Z=y(B.filename??"<unknown>");W.scope.getProgramParent().path.unshiftContainer("body",z.variableDeclaration("const",[z.variableDeclarator(z.identifier($),z.stringLiteral(Z))]))}return $}function g(W,B,$){let Z=W.node;if(Z.type!=="ImportDeclaration")return;if(!$.modules.has(Z.source.value))return;let K=[];for(let F of Z.specifiers){if(F.type==="ImportDefaultSpecifier"){if(!$.defaultExport)continue}else if(F.type==="ImportSpecifier"){let L=F.imported,S=L?.type==="Identifier"?L.name:void 0;if(!S||!$.names.has(S))continue}else continue;let x=F.local.name,w=W.scope.generateUidIdentifier(x).name;F.local=z.identifier(w),K.push({localName:x,uid:w})}if(K.length===0)return;let U=B.squiggleHelperLocals??={},J=U[$.helper];if(!J){J=W.scope.generateUidIdentifier("squiggleInstrument").name,U[$.helper]=J;let F=z.importDeclaration([z.importSpecifier(z.identifier(J),z.identifier($.helper))],z.stringLiteral(Q));W.scope.getProgramParent().path.unshiftContainer("body",F)}let H=K.map(({localName:F,uid:x})=>z.variableDeclarator(z.identifier(F),z.callExpression(z.identifier(J),[z.identifier(x)])));W.insertAfter(z.variableDeclaration("const",H))}function R(W,B,$,Z){return z.expressionStatement(z.assignmentExpression("=",z.memberExpression(z.identifier(W),z.identifier("__squiggleSrc")),z.objectExpression([z.objectProperty(z.identifier("file"),z.identifier(B)),z.objectProperty(z.identifier("line"),z.numericLiteral($)),z.objectProperty(z.identifier("col"),z.numericLiteral(Z))])))}function C(W){let B=W.node.loc?.start;return{line:B?.line??0,col:B?.column??0}}let P=new WeakSet;function f(W,B){let $=W.node;if(P.has($))return;if(!Bj($.openingElement?.name))return;let Z=$.loc?.start;if(!Z||typeof Z.line!=="number")return;let K=W.scope.getProgramParent(),U=B.squiggleSites??=[],J=B.squiggleTagLocal??=K.generateUidIdentifier("sqTag").name;B.squiggleSitesLocal??=K.generateUidIdentifier("sqSites").name,B.squiggleSitesInit??=K.generateUidIdentifier("sqSitesInit").name;let H=U.length;U.push({line:Z.line,col:Z.column??0}),P.add($);let F=z.callExpression(z.identifier(J),[$,z.numericLiteral(H)]),x=W.parentPath?.node.type,w=x==="JSXElement"||x==="JSXFragment"||x==="JSXAttribute";W.replaceWith(w?z.jsxExpressionContainer(F):F)}function d(W,B){let $=B.squiggleSites;if(!$||$.length===0)return;if(!q.template)return;W.scope.getProgramParent().path.unshiftContainer("body",q.template.statements.ast(Xj({tag:B.squiggleTagLocal,sites:B.squiggleSitesLocal,init:B.squiggleSitesInit},y(B.filename??"<unknown>"),$,V)))}function G(W){return Y&&!(W.filename??"").includes("/node_modules/")}function A(W,B,$,Z){if(!G(Z)||!q.template)return;if(!M(B)&&!O(B))return;if(!Jj($))return;let K=Fj(W);if(K.length===0)return;$.insertAfter(q.template.statements.ast(Vj(B,K)))}return{name:"squiggle",visitor:{Program:{exit(W,B){if(!G(B))return;try{d(W,B)}catch{}}},JSXElement:{exit(W,B){if(!G(B))return;try{f(W,B)}catch{}}},ImportDeclaration(W,B){for(let $ of X)try{g(W,B,$)}catch{}},FunctionDeclaration(W,B){try{let $=W.node.id?.name;if($)A(W,$,W,B)}catch{}if(u)return;try{let $=W.node.id?.name;if(!$||!M($))return;if(!T(W.node))return;let{line:Z,col:K}=C(W);W.insertAfter(R($,D(W,B),Z,K))}catch{}},VariableDeclarator(W,B){try{let $=W.node.id,Z=W.node.init;if($?.type==="Identifier"&&$.name&&W.parentPath&&(Z?.type==="ArrowFunctionExpression"||Z?.type==="FunctionExpression"))A(W.get("init"),$.name,W.parentPath,B)}catch{}if(u)return;try{let $=W.node.id;if(!$||$.type!=="Identifier")return;let Z=$.name;if(!Z||!M(Z))return;let K=W.node.init;if(!K)return;if(!T(K))return;let{line:U,col:J}=C(W);W.parentPath?.insertAfter(R(Z,D(W,B),U,J))}catch{}}}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@squiggle.sh/babel-plugin",
3
- "version": "0.1.0",
4
- "description": "Squiggle Babel plugin: injects stable component source location (file/line/col) into React components",
3
+ "version": "0.2.0",
4
+ "description": "Squiggle Babel plugin: injects stable component source locations (definition and, in dev, each element's call site) into React components",
5
5
  "keywords": [
6
6
  "babel-plugin",
7
7
  "devtools",
@@ -36,7 +36,7 @@
36
36
  "sideEffects": true,
37
37
  "peerDependencies": {
38
38
  "@babel/core": ">=7",
39
- "@squiggle.sh/react-native": "0.1.0"
39
+ "@squiggle.sh/react-native": "0.2.0"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@squiggle.sh/react-native": {