UNPKG

@dhiwise/component-tagger

Version:

Automatically annotate JSX components and HTML elements with data attributes

5 lines (4 loc) 8.24 kB
import{createUnplugin as K}from"unplugin";import*as S from"path";import{parse as V}from"@babel/parser";import{traverse as q}from"@babel/core";import W from"magic-string";import u from"chalk";import H from"picomatch";var L=new Set(["Fragment","Suspense","StrictMode","Profiler","React.Fragment"]),J=["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"],A=["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(r){let e=new Set;for(let t of r.program.body)if(t.type==="ImportDeclaration"){let o=t,i=o.source.value;if(J.some(n=>i===n||i.startsWith(n+"/")))for(let n of o.specifiers)n.type==="ImportSpecifier"||n.type==="ImportDefaultSpecifier"?e.add(n.local.name):n.type==="ImportNamespaceSpecifier"&&e.add(`${n.local.name}.*`)}return e}var M=new Map;function N(r){let e=r.sort().join(",");if(!M.has(e)){let t=r.map(i=>`**/*${i}`),o=H(t);M.set(e,o)}return M.get(e)}function x(r,e){let t=e.extensions||[".jsx",".tsx",".js",".ts"];return N(t)(r)?![".test.",".spec.","__tests__","__mocks__"].some(n=>r.includes(n)):!1}function _(r,e,t){return e.includeElements&&e.includeElements.length>0?e.includeElements.includes(r):e.shouldTag?e.shouldTag(r):!(e.excludeElements&&e.excludeElements.includes(r)||L.has(r)||t&&k(r,t))}function k(r,e){if(e.has(r)||A.includes(r))return!0;for(let t of e)if(t.endsWith(".*")){let o=t.slice(0,-2);if(r.startsWith(`${o}.`))return!0}return!1}function j(r){if(r){if(r.type==="StringLiteral")return r.value;if(r.type==="JSXExpressionContainer"){let e=r.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 t=e.left.type==="StringLiteral"?e.left.value:"",o=e.right.type==="StringLiteral"?e.right.value:"";return t+o}if(e.type==="Identifier")return`[var:${e.name}]`}}}function $(r,e,t){let o={},i=["className","id","src","alt","href","type","name","value"],a=new Set([...i,...e.extractAttributes||[]]);for(let s of r.attributes)if(s.type==="JSXAttribute"&&s.name.type==="JSXIdentifier"){let f=s.name.name;if(!a.has(f))continue;if(s.value){let m=j(s.value);m!==void 0&&(o[f]=m)}else o[f]="true"}else s.type==="JSXSpreadAttribute"&&(o["[spread]"]="true");let n="";return t&&t.children&&(n=t.children.map(s=>s.type==="JSXText"?s.value.trim():s.type==="JSXExpressionContainer"&&s.expression.type==="StringLiteral"?s.expression.value:"").filter(Boolean).join(" ").trim()),n&&(o.textContent=n),o}function I(r){let e=r.name;return e.type==="JSXIdentifier"?e.name:e.type==="JSXMemberExpression"?U(e):"Unknown"}function U(r){return`${r.object.name}.${r.property.name}`}function g(r){return r.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&#39;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function O(r,e,t){return`${r}:${e}:${t}`}function c(r,e){if(!e.verbose)return;let t=r;r.includes("Error")||r.includes("error")?t=u.red(r):r.includes("Tagged")||r.includes("Summary")?t=u.green(r):r.includes("Processing")||r.includes("started")?t=u.blue(r):t=u.yellow(r),console.log(`[component-tagger] ${t}`)}function v(r){return u.green(`Component Tagger Summary: - Total files scanned: ${u.cyan(r.totalFiles)} - Files processed: ${u.cyan(r.processedFiles)} - Elements tagged: ${u.cyan(r.totalElements)}`)}async function X(r,e,t){if(!x(e,t)||e.includes("node_modules")&&!t.processNodeModules||t.excludeDirectories&&t.excludeDirectories.some(n=>e.includes(n)))return null;let o=process.cwd(),i=S.relative(o,e),a=S.basename(e);c(`Processing file: ${i}`,t);try{let s=V(r,{sourceType:"module",plugins:["jsx","typescript"]}),f=B(s),m=new W(r),b=0,h=null;return q(s,{JSXElement:E=>{h=E.node},JSXOpeningElement:E=>{if(!h)return;let d=E.node,T=I(d);if(!_(T,t,f))return;let R=$(d,t,h),G={elementName:T};Object.entries(R).forEach(([C,p])=>{G[C]=p});let y=d.loc?.start?.line??0,P=d.loc?.start?.column??0,w=h?.loc?.end?.line??y,D=t.generateComponentId?t.generateComponentId(i,y,P):O(i,y,P),l=` ${t.attributePrefix}-id="${g(D)}"`;if(t.includeLegacyAttributes&&(l+=` ${t.attributePrefix}-path="${g(i)}"`,l+=` ${t.attributePrefix}-line="${y}"`,l+=` ${t.attributePrefix}-end-line="${w}"`,l+=` ${t.attributePrefix}-file="${g(a)}"`,l+=` ${t.attributePrefix}-name="${g(T)}"`),t.includeContentAttribute){let C=JSON.stringify(G),p=encodeURIComponent(C);t.maxContentLength&&p.length>t.maxContentLength&&(p=p.substring(0,t.maxContentLength)+"..."),l+=` ${t.attributePrefix}-content="${p}"`}m.appendLeft(d.name.end??0,l),c(l.toString(),t),b++}}),b>0?(c(`Tagged ${b} components in ${i}`,t),{code:m.toString(),map:t.sourceMaps?m.generateMap({hires:!0}):null}):null}catch(n){return console.error(`Error processing file ${i}:`,n),null}}var F=K((r={})=>{let e={extensions:[".jsx",".tsx",".js",".ts"],verbose:!1,attributePrefix:"data-component",includeContentAttribute:!0,maxContentLength:1e3,includeLegacyAttributes:!0,sourceMaps:!0,excludeDirectories:[],processNodeModules:!1,...r},t={totalFiles:0,processedFiles:0,totalElements:0};return{name:"component-tagger",transformInclude(o){return x(o,e)},async transform(o,i){if(i.includes("node_modules")&&!e.processNodeModules||e.excludeDirectories&&e.excludeDirectories.some(n=>i.includes(n)))return null;t.totalFiles++;let a=await X(o,i,e);if(a){t.processedFiles++;let n=(a.code.match(new RegExp(`${e.attributePrefix}-id="`,"g"))||[]).length;t.totalElements+=n}else t.processedFiles++;return a},buildStart(){c("Component tagger plugin started",e),t.totalFiles=0,t.processedFiles=0,t.totalElements=0},buildEnd(){c(v(t),e)}}});function z(r={}){let e=F.vite(r);return{...Array.isArray(e)?e[0]:e,enforce:"pre"}}var fe=z;export{z as createVitePlugin,fe as default};