@dhiwise/component-tagger
Version:
Automatically annotate JSX components and HTML elements with data attributes
2 lines (1 loc) • 7.39 kB
JavaScript
import*as x from"path";import{parse as j}from"@babel/parser";import{traverse as q}from"@babel/core";import U from"magic-string";import h from"chalk";import D from"picomatch";var L=new Set(["Fragment","Suspense","StrictMode","Profiler","React.Fragment"]),P=["three","@react-three/fiber","@react-three/drei","@react-three/rapier","@react-three/a11y","@react-three/csg","@react-three/flex","@react-three/gpu-pathtracer","@react-three/postprocessing","@react-three/cannon","@react-three/xr","@react-three/test-renderer","three/addons","three/examples"],J=["object3D","audioListener","positionalAudio","mesh","batchedMesh","instancedMesh","scene","sprite","lOD","skinnedMesh","skeleton","bone","lineSegments","lineLoop","points","group","camera","perspectiveCamera","orthographicCamera","cubeCamera","arrayCamera","instancedBufferGeometry","bufferGeometry","boxBufferGeometry","circleBufferGeometry","coneBufferGeometry","cylinderBufferGeometry","dodecahedronBufferGeometry","extrudeBufferGeometry","icosahedronBufferGeometry","latheBufferGeometry","octahedronBufferGeometry","planeBufferGeometry","polyhedronBufferGeometry","ringBufferGeometry","shapeBufferGeometry","sphereBufferGeometry","tetrahedronBufferGeometry","torusBufferGeometry","torusKnotBufferGeometry","tubeBufferGeometry","wireframeGeometry","tetrahedronGeometry","octahedronGeometry","icosahedronGeometry","dodecahedronGeometry","polyhedronGeometry","tubeGeometry","torusKnotGeometry","torusGeometry","sphereGeometry","ringGeometry","planeGeometry","latheGeometry","shapeGeometry","extrudeGeometry","edgesGeometry","coneGeometry","cylinderGeometry","circleGeometry","boxGeometry","capsuleGeometry","material","shadowMaterial","spriteMaterial","rawShaderMaterial","shaderMaterial","pointsMaterial","meshPhysicalMaterial","meshStandardMaterial","meshPhongMaterial","meshToonMaterial","meshNormalMaterial","meshLambertMaterial","meshDepthMaterial","meshDistanceMaterial","meshBasicMaterial","meshMatcapMaterial","lineDashedMaterial","lineBasicMaterial","primitive","light","spotLightShadow","spotLight","pointLight","rectAreaLight","hemisphereLight","directionalLightShadow","directionalLight","ambientLight","lightShadow","ambientLightProbe","hemisphereLightProbe","lightProbe","spotLightHelper","skeletonHelper","pointLightHelper","hemisphereLightHelper","gridHelper","polarGridHelper","directionalLightHelper","cameraHelper","boxHelper","box3Helper","planeHelper","arrowHelper","axesHelper","texture","videoTexture","dataTexture","dataTexture3D","compressedTexture","cubeTexture","canvasTexture","depthTexture","raycaster","vector2","vector3","vector4","euler","matrix3","matrix4","quaternion","bufferAttribute","float16BufferAttribute","float32BufferAttribute","float64BufferAttribute","int8BufferAttribute","int16BufferAttribute","int32BufferAttribute","uint8BufferAttribute","uint16BufferAttribute","uint32BufferAttribute","instancedBufferAttribute","color","fog","fogExp2","shape","colorShiftMaterial"];function B(t){let e=new Set;for(let r of t.program.body)if(r.type==="ImportDeclaration"){let n=r,a=n.source.value;if(P.some(o=>a===o||a.startsWith(o+"/")))for(let o of n.specifiers)o.type==="ImportSpecifier"||o.type==="ImportDefaultSpecifier"?e.add(o.local.name):o.type==="ImportNamespaceSpecifier"&&e.add(`${o.local.name}.*`)}return e}var C=new Map;function F(t){let e=t.sort().join(",");if(!C.has(e)){let r=t.map(a=>`**/*${a}`),n=D(r);C.set(e,n)}return C.get(e)}function A(t,e){let r=e.extensions||[".jsx",".tsx",".js",".ts"];return F(r)(t)?![".test.",".spec.","__tests__","__mocks__"].some(o=>t.includes(o)):!1}function _(t,e,r){return e.includeElements&&e.includeElements.length>0?e.includeElements.includes(t):e.shouldTag?e.shouldTag(t):!(e.excludeElements&&e.excludeElements.includes(t)||L.has(t)||r&&H(t,r))}function H(t,e){if(e.has(t)||J.includes(t))return!0;for(let r of e)if(r.endsWith(".*")){let n=r.slice(0,-2);if(t.startsWith(`${n}.`))return!0}return!1}function N(t){if(t){if(t.type==="StringLiteral")return t.value;if(t.type==="JSXExpressionContainer"){let e=t.expression;if(e.type==="StringLiteral")return e.value;if(e.type==="TemplateLiteral"&&e.quasis.length===1)return e.quasis[0].value.raw;if(e.type==="BinaryExpression"&&e.operator==="+"){let r=e.left.type==="StringLiteral"?e.left.value:"",n=e.right.type==="StringLiteral"?e.right.value:"";return r+n}if(e.type==="Identifier")return`[var:${e.name}]`}}}function $(t,e,r){let n={},a=["className","id","src","alt","href","type","name","value"],c=new Set([...a,...e.extractAttributes||[]]);for(let i of t.attributes)if(i.type==="JSXAttribute"&&i.name.type==="JSXIdentifier"){let m=i.name.name;if(!c.has(m))continue;if(i.value){let l=N(i.value);l!==void 0&&(n[m]=l)}else n[m]="true"}else i.type==="JSXSpreadAttribute"&&(n["[spread]"]="true");let o="";return r&&r.children&&(o=r.children.map(i=>i.type==="JSXText"?i.value.trim():i.type==="JSXExpressionContainer"&&i.expression.type==="StringLiteral"?i.expression.value:"").filter(Boolean).join(" ").trim()),o&&(n.textContent=o),n}function I(t){let e=t.name;return e.type==="JSXIdentifier"?e.name:e.type==="JSXMemberExpression"?k(e):"Unknown"}function k(t){return`${t.object.name}.${t.property.name}`}function p(t){return t.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}function O(t,e,r){return`${t}:${e}:${r}`}function y(t,e){if(!e.verbose)return;let r=t;t.includes("Error")||t.includes("error")?r=h.red(t):t.includes("Tagged")||t.includes("Summary")?r=h.green(t):t.includes("Processing")||t.includes("started")?r=h.blue(t):r=h.yellow(t),console.log(`[component-tagger] ${r}`)}async function X(t,e,r){if(!A(e,r)||e.includes("node_modules")&&!r.processNodeModules||r.excludeDirectories&&r.excludeDirectories.some(o=>e.includes(o)))return null;let n=process.cwd(),a=x.relative(n,e),c=x.basename(e);y(`Processing file: ${a}`,r);try{let i=j(t,{sourceType:"module",plugins:["jsx","typescript"]}),m=B(i),l=new U(t),b=0,d=null;return q(i,{JSXElement:S=>{d=S.node},JSXOpeningElement:S=>{if(!d)return;let f=S.node,E=I(f);if(!_(E,r,m))return;let v=$(f,r,d),M={elementName:E};Object.entries(v).forEach(([T,u])=>{M[T]=u});let g=f.loc?.start?.line??0,G=f.loc?.start?.column??0,R=d?.loc?.end?.line??g,w=r.generateComponentId?r.generateComponentId(a,g,G):O(a,g,G),s=` ${r.attributePrefix}-id="${p(w)}"`;if(r.includeLegacyAttributes&&(s+=` ${r.attributePrefix}-path="${p(a)}"`,s+=` ${r.attributePrefix}-line="${g}"`,s+=` ${r.attributePrefix}-end-line="${R}"`,s+=` ${r.attributePrefix}-file="${p(c)}"`,s+=` ${r.attributePrefix}-name="${p(E)}"`),r.includeContentAttribute){let T=JSON.stringify(M),u=encodeURIComponent(T);r.maxContentLength&&u.length>r.maxContentLength&&(u=u.substring(0,r.maxContentLength)+"..."),s+=` ${r.attributePrefix}-content="${u}"`}l.appendLeft(f.name.end??0,s),y(s.toString(),r),b++}}),b>0?(y(`Tagged ${b} components in ${a}`,r),{code:l.toString(),map:r.sourceMaps?l.generateMap({hires:!0}):null}):null}catch(o){return console.error(`Error processing file ${a}:`,o),null}}async function V(t){let e=this.resourcePath,r={extensions:[".jsx",".tsx",".js",".ts"],verbose:!1,attributePrefix:"data-component",includeContentAttribute:!0,maxContentLength:1e3,includeLegacyAttributes:!0,sourceMaps:!0,excludeDirectories:[],processNodeModules:!1,...this.query};try{let n=await X(t,e,r);return n?n.code:t}catch{return t}}var ae=V;export{ae as default};