@knighted/jsx 1.5.1 → 1.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.
- package/README.md +1 -0
- package/dist/cjs/debug/diagnostics.cjs +57 -0
- package/dist/cjs/debug/diagnostics.d.cts +6 -0
- package/dist/cjs/debug/index.cjs +7 -0
- package/dist/cjs/debug/index.d.cts +2 -0
- package/dist/cjs/internal/attribute-resolution.cjs +55 -0
- package/dist/cjs/internal/attribute-resolution.d.cts +15 -0
- package/dist/cjs/internal/dev-environment.cjs +41 -0
- package/dist/cjs/internal/dev-environment.d.cts +4 -0
- package/dist/cjs/internal/event-bindings.cjs +93 -0
- package/dist/cjs/internal/event-bindings.d.cts +22 -0
- package/dist/cjs/internal/template-diagnostics.cjs +171 -0
- package/dist/cjs/internal/template-diagnostics.d.cts +13 -0
- package/dist/cjs/jsx.cjs +9 -110
- package/dist/cjs/loader/jsx.cjs +92 -20
- package/dist/cjs/loader/jsx.d.cts +6 -1
- package/dist/cjs/node/bootstrap.cjs +19 -19
- package/dist/cjs/node/bootstrap.d.cts +2 -1
- package/dist/cjs/node/debug/index.cjs +6 -0
- package/dist/cjs/node/debug/index.d.cts +2 -0
- package/dist/cjs/node/index.cjs +1 -1
- package/dist/cjs/react/react-jsx.cjs +1 -1
- package/dist/cjs/runtime/shared.cjs +41 -22
- package/dist/cjs/runtime/shared.d.cts +5 -2
- package/dist/debug/diagnostics.d.ts +6 -0
- package/dist/debug/diagnostics.js +52 -0
- package/dist/debug/index.d.ts +2 -0
- package/dist/debug/index.js +3 -0
- package/dist/internal/attribute-resolution.d.ts +15 -0
- package/dist/internal/attribute-resolution.js +50 -0
- package/dist/internal/dev-environment.d.ts +4 -0
- package/dist/internal/dev-environment.js +34 -0
- package/dist/internal/event-bindings.d.ts +22 -0
- package/dist/internal/event-bindings.js +87 -0
- package/dist/internal/template-diagnostics.d.ts +13 -0
- package/dist/internal/template-diagnostics.js +167 -0
- package/dist/jsx.js +9 -110
- package/dist/lite/debug/diagnostics.js +1 -0
- package/dist/lite/debug/index.js +8 -0
- package/dist/lite/index.js +8 -4
- package/dist/lite/node/debug/index.js +8 -0
- package/dist/lite/node/index.js +8 -4
- package/dist/lite/node/react/index.js +7 -3
- package/dist/lite/react/index.js +7 -3
- package/dist/loader/jsx.d.ts +6 -1
- package/dist/loader/jsx.js +92 -20
- package/dist/node/bootstrap.d.ts +2 -1
- package/dist/node/bootstrap.js +19 -19
- package/dist/node/debug/index.d.ts +2 -0
- package/dist/node/debug/index.js +6 -0
- package/dist/node/index.js +1 -1
- package/dist/react/react-jsx.js +2 -2
- package/dist/runtime/shared.d.ts +5 -2
- package/dist/runtime/shared.js +39 -21
- package/package.json +40 -8
package/dist/lite/node/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var
|
|
2
|
-
${t.
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {createRequire}from'module';import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var te=createRequire(import.meta.url),R=()=>te,M="<!doctype html><html><body></body></html>",re=["window","self","document","HTMLElement","Element","Node","DocumentFragment","customElements","Text","Comment","MutationObserver","navigator"],oe=()=>typeof document<"u"&&typeof document.createElement=="function",se=e=>{let t=globalThis,n=e;re.forEach(r=>{t[r]===void 0&&n[r]!==void 0&&(t[r]=n[r]);});},S=()=>{let{parseHTML:e}=R()("linkedom"),{window:t}=e(M);return t},w=()=>{let{JSDOM:e}=R()("jsdom"),{window:t}=new e(M);return t},ae=()=>{let e=typeof process<"u"&&process.env?.KNIGHTED_JSX_NODE_SHIM?process.env.KNIGHTED_JSX_NODE_SHIM.toLowerCase():void 0;return e==="linkedom"||e==="jsdom"?e:"auto"},ie=()=>{let e=ae();return e==="linkedom"?[S,w]:e==="jsdom"?[w,S]:[S,w]},pe=()=>{let e=[];for(let n of ie())try{return n()}catch(r){e.push(r);}let t='Unable to bootstrap a DOM-like environment. Install "linkedom" or "jsdom" (both optional peer dependencies) or set KNIGHTED_JSX_NODE_SHIM to pick one explicitly.';throw new AggregateError(e,t)},X=false,D=()=>{if(oe()||X)return;let e=pe();se(e),X=true;};var ce="oxc-parser",le=e=>{let t=e.raw??e,n=t[0]??"",r=[];for(let o=0;o<t.length-1;o++){let s="${expr#"+o+"}",i=n.length;n+=s;let p=n.length;r.push({index:o,templateStart:i,templateEnd:p,label:s}),n+=t[o+1]??"";}return {source:n,spans:r}},me=(e,t)=>{let n=new Map;return t.forEach(r=>{n.set(r.index,r);}),e.expressionRanges.map(r=>{let o=n.get(r.index);if(!o)return null;let s=Math.max(0,r.sourceEnd-r.sourceStart),i=Math.max(0,o.templateEnd-o.templateStart);return {sourceStart:r.sourceStart,sourceEnd:r.sourceEnd,templateStart:o.templateStart,templateEnd:o.templateEnd,delta:i-s}}).filter(r=>!!r).sort((r,o)=>r.sourceStart-o.sourceStart)},ue=(e,t,n)=>{if(!Number.isFinite(e)||e<=0)return 0;let r=0;for(let s of t){if(e<s.sourceStart)break;if(e<s.sourceEnd){let i=Math.max(0,e-s.sourceStart),p=Math.max(0,s.templateEnd-s.templateStart);if(p===0)return s.templateStart;let a=Math.min(i,Math.max(0,p-1));return s.templateStart+a}r+=s.delta;}let o=e+r;return o<=0?0:o>=n?n:o},L=(e,t)=>{let n=Math.max(0,Math.min(t,e.length)),r=1,o=1;for(let s=0;s<n;s++){if(e.charCodeAt(s)===10){r++,o=1;continue}o++;}return {line:r,column:o}},de=e=>{let t=[],n=0;return e.forEach((r,o)=>{t.push(n),n+=r.length,o<e.length-1&&(n+=1);}),t},fe=(e,t,n,r,o,s,i)=>{let p=n+t.length,a=Math.max(r,n),c=Math.min(o,p);if(c>a){let l=Math.max(0,a-n),u=Math.max(1,c-a);return " ".repeat(l)+"^".repeat(u)}if(t.length===0&&e>=s&&e<=i)return "^";if(e===s){let l=Math.max(0,r-n);return " ".repeat(Math.min(l,t.length))+"^"}return ""},ge=(e,t,n,r,o)=>{if(!e.length)return "";let s=e.split(`
|
|
2
|
+
`),i=de(s),p=Math.max(1,r-1),a=Math.min(s.length,o+1),c=String(a).length,l=[];for(let u=p;u<=a;u++){let d=s[u-1]??"",m=String(u).padStart(c," ");l.push(`${m} | ${d}`);let f=fe(u,d,i[u-1]??0,t,n,r,o);f&&l.push(`${" ".repeat(c)} | ${f}`);}return l.join(`
|
|
3
|
+
`)},T=(e,t,n,r,o)=>{let s=ce,i=`[${s}] ${r.message}`,p=r.labels?.[0];if(!p)return i;let{source:a,spans:c}=le(t),l=me(n,c),u=h=>ue(typeof h=="number"?h:0,l,a.length),d=u(p.start),m=u(p.end);m<=d&&(m=Math.min(a.length,d+1));let f=L(a,d),x=L(a,Math.max(d,m-1)),y=ge(a,d,m,f.line,x.line),g=`[${s}] ${r.message}`;return g+=`
|
|
4
|
+
--> ${e} template:${f.line}:${f.column}`,p.message&&(g+=`
|
|
5
|
+
${p.message}`),y&&(g+=`
|
|
6
|
+
${y}`),r.helpMessage&&(g+=`
|
|
7
|
+
${r.helpMessage}`),g};var xe=/<\s*$/,he=/<\/\s*$/,I="__KX_EXPR__",P=new RegExp(`${I}\\d+_\\d+__`,"g"),Ee=0;var j={lang:"jsx",sourceType:"module",range:true,preserveParens:true},O=e=>{for(let t of e.body)if(t.type==="ExpressionStatement"){let n=t.expression;if(n.type==="JSXElement"||n.type==="JSXFragment")return n}throw new Error("The jsx template must contain a single JSX element or fragment.")},b=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${b(e.object)}.${e.property.name}`;default:return ""}},J=(e,t)=>{if(!e||typeof e!="object")return;let n=e;typeof n.type=="string"&&(t(n),Object.values(n).forEach(r=>{if(r){if(Array.isArray(r)){r.forEach(o=>J(o,t));return}typeof r=="object"&&J(r,t);}}));},$=(e,t)=>{let n=e.replace(/\r/g,"").replace(/\n\s+/g," "),r=e.match(/^\s*/)?.[0]??"",o=e.match(/\s*$/)?.[0]??"",s=/\n/.test(r),i=/\n/.test(o),p=n;if(s&&(p=p.replace(/^\s+/,"")),i&&(p=p.replace(/\s+$/,"")),p.length===0||p.trim().length===0)return [];let a=[];P.lastIndex=0;let c=0,l;for(;l=P.exec(p);){let d=l.index,m=p.slice(c,d);m&&a.push(m);let f=l[0];t.has(f)?a.push(t.get(f)):a.push(f),c=d+f.length;}let u=p.slice(c);return u&&a.push(u),a},ye=(e,t)=>{let n=new Set;return J(e,r=>{r.type==="Identifier"&&t.placeholders.has(r.name)&&n.add(r.name);}),Array.from(n)},_=(e,t,n)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return n(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[r,o]=e.range,s=t.source.slice(r,o),i=ye(e,t);try{let p=new Function(...i,`"use strict"; return (${s});`),a=i.map(c=>t.placeholders.get(c));return p(...a)}catch(p){throw new Error(`Failed to evaluate expression ${s}: ${p.message}`)}},be=e=>{let t=e.replace(/[^a-zA-Z0-9_$]/g,"");return t?/[A-Za-z_$]/.test(t[0])?t:`Component${t}`:"Component"},Se=(e,t,n)=>{let r=n.get(e);if(r)return r;let o=e.displayName||e.name||`Component${t.length}`,s=be(o??""),i=s,p=1;for(;t.some(c=>c.name===i);)i=`${s}${p++}`;let a={name:i,value:e};return t.push(a),n.set(e,a),a},F=(e,t)=>{let n=e.raw??e,r=new Map,o=[],s=new Map,i=n[0]??"",p=Ee++,a=0,c=[];for(let l=0;l<t.length;l++){let u=n[l]??"",d=n[l+1]??"",m=t[l],f=xe.test(u)||he.test(u),x;if(f&&typeof m=="function")x=Se(m,o,s).name;else if(f&&typeof m=="string")x=m;else {let h=`${I}${p}_${a++}__`;r.set(h,m),x=h;}let y=i.length;i+=x;let g=i.length;c.push({index:l,sourceStart:y,sourceEnd:g}),i+=d;}return {source:i,placeholders:r,bindings:o,diagnostics:{expressionRanges:c}}};var W=e=>{let{getIdentifierName:t,evaluateExpressionWithNamespace:n}=e;return (r,o,s)=>{let i={},p=(a,c)=>{i[a]=c;};return r.forEach(a=>{if(a.type==="JSXSpreadAttribute"){let l=n(a.argument,o,s);l&&typeof l=="object"&&!Array.isArray(l)&&Object.assign(i,l);return}let c=t(a.name);if(!a.value){p(c,true);return}if(a.value.type==="Literal"){p(c,a.value.value);return}if(a.value.type==="JSXExpressionContainer"){if(a.value.expression.type==="JSXEmptyExpression")return;p(c,n(a.value.expression,o,s));}}),i}};var B="Capture",V=e=>e.endsWith(B)?{eventName:e.slice(0,-B.length),capture:true}:{eventName:e,capture:false},U=e=>{if(!e.startsWith("on"))return null;if(e.startsWith("on:")){let r=e.slice(3);if(!r)return null;let o=V(r);return o.eventName?o:null}let t=e.slice(2);if(!t)return null;let n=V(t);return n.eventName?{eventName:n.eventName.toLowerCase(),capture:n.capture}:null},q=e=>!e||typeof e!="object"?false:"handleEvent"in e&&typeof e.handleEvent=="function",Ce=e=>{if(!e||typeof e!="object"||!("handler"in e))return false;let t=e.handler;return typeof t=="function"?true:q(t)},K=(e,t)=>{if(typeof t=="function"||q(t))return {listener:t};if(!Ce(t))return null;let n=t,r=n.options?{...n.options}:void 0,o=(s,i)=>{i!=null&&(r||(r={}),r[s]=i);};return o("capture",n.capture),o("once",n.once),o("passive",n.passive),o("signal",n.signal??void 0),{listener:n.handler,options:r}};var Re=()=>{if(typeof document>"u"||typeof document.createElement!="function")throw new Error("The jsx template tag requires a DOM-like environment (document missing).")},Me=e=>typeof Node>"u"?false:e instanceof Node||e instanceof DocumentFragment,De=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",G=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",Le={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},Z=e=>{if(!(!e||e==="html"||e==="svg"))return Le[e]},Pe=e=>e==="svg"?svg:html,C=(e,t,n)=>{let r=Z(t.space),o=String(n);if(r){e.setAttributeNS(r,t.attribute,o);return}e.setAttribute(t.attribute,o);},z=(e,t)=>{let n=Z(t.space);if(n){e.removeAttributeNS(n,t.attribute);return}e.removeAttribute(t.attribute);},k=(e,t)=>Array.isArray(e)?e.filter(Boolean).join(t):e,Ie=(e,t,n)=>t==="svg"||!n.property||n.property.includes(":")?false:n.property in e,je=(e,t,n,r)=>{if(n==null)return;if(t==="dangerouslySetInnerHTML"&&typeof n=="object"&&n&&"__html"in n){e.innerHTML=String(n.__html??"");return}if(t==="ref"){if(typeof n=="function"){n(e);return}if(n&&typeof n=="object"){n.current=e;return}}if(t==="style"&&typeof n=="object"&&n!==null){let c=n,l=e.style;if(!l)return;let u=l;Object.entries(c).forEach(([d,m])=>{if(m!=null){if(d.startsWith("--")){l.setProperty(d,String(m));return}u[d]=m;}});return}let o=U(t);if(o){let c=K(t,n);if(c){let l=c.options?{...c.options}:void 0;o.capture&&(l?l.capture=true:l={capture:true}),e.addEventListener(o.eventName,c.listener,l);return}}let s=find(Pe(r),t),i=e,p=Ie(e,r,s);if(s.mustUseProperty){let c=s.boolean?!!n:n;i[s.property]=c;return}if(s.boolean){let c=!!n;p&&(i[s.property]=c),c?C(e,s,""):z(e,s);return}let a=n;if(s.spaceSeparated?a=k(n," "):s.commaSeparated?a=k(n,","):s.commaOrSpaceSeparated&&(a=k(n," ")),s.booleanish&&typeof a=="boolean"&&(a=a?"true":"false"),s.overloadedBoolean){if(a===false){z(e,s);return}if(a===true){C(e,s,"");return}}if(p){i[s.property]=a;return}a!==false&&C(e,s,a);},E=(e,t)=>{if(t!=null&&typeof t!="boolean"){if(G(t))throw new Error("Async values are not supported inside jsx template results.");if(Array.isArray(t)){t.forEach(n=>E(e,n));return}if(De(t)){for(let n of t)E(e,n);return}if(Me(t)){e.appendChild(t);return}e.appendChild(document.createTextNode(String(t)));}},N=(e,t,n)=>_(e,t,r=>v(r,t,n)),Y=W({getIdentifierName:b,evaluateExpressionWithNamespace:N}),Oe=(e,t,n,r)=>{let o=Y(t,n,r);Object.entries(o).forEach(([s,i])=>{if(s!=="key"){if(s==="children"){E(e,i);return}je(e,s,i,r);}});},A=(e,t,n)=>{let r=[];return e.forEach(o=>{switch(o.type){case "JSXText":{$(o.value,t.placeholders).forEach(i=>{r.push(i);});break}case "JSXExpressionContainer":{if(o.expression.type==="JSXEmptyExpression")break;r.push(N(o.expression,t,n));break}case "JSXSpreadChild":{let s=N(o.expression,t,n);s!=null&&r.push(s);break}case "JSXElement":case "JSXFragment":{r.push(v(o,t,n));break}}}),r},$e=(e,t,n,r)=>{let o=Y(e.openingElement.attributes,t,r),s=A(e.children,t,r);s.length===1?o.children=s[0]:s.length>1&&(o.children=s);let i=n(o);if(G(i))throw new Error("Async jsx components are not supported.");return i},_e=(e,t,n)=>{let r=e.openingElement,o=b(r.name),s=t.components.get(o);if(s)return $e(e,t,s,n);if(/[A-Z]/.test(o[0]??""))throw new Error(`Unknown component "${o}". Did you interpolate it with the template literal?`);let i=o==="svg"?"svg":n,p=o==="foreignObject"?null:i,a=i==="svg"?document.createElementNS("http://www.w3.org/2000/svg",o):document.createElement(o);return Oe(a,r.attributes,t,i),A(e.children,t,p).forEach(l=>E(a,l)),a},v=(e,t,n)=>{if(e.type==="JSXFragment"){let r=document.createDocumentFragment();return A(e.children,t,n).forEach(s=>E(r,s)),r}return _e(e,t,n)},Q=(e,...t)=>{Re();let n=F(e,t),r=parseSync("inline.jsx",n.source,j);if(r.errors.length>0)throw new Error(T("jsx",e,n.diagnostics,r.errors[0]));let o=O(r.program),s={source:n.source,placeholders:n.placeholders,components:new Map(n.bindings.map(i=>[i.name,i.value]))};return v(o,s,null)};D();var rt=Q;
|
|
8
|
+
export{rt as jsx};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';import {createElement,Fragment}from'react';var
|
|
2
|
-
${t.
|
|
3
|
-
|
|
1
|
+
import {parseSync}from'oxc-parser';import {createElement,Fragment}from'react';var _="oxc-parser",O=e=>{let n=e.raw??e,r=n[0]??"",t=[];for(let o=0;o<n.length-1;o++){let s="${expr#"+o+"}",a=r.length;r+=s;let p=r.length;t.push({index:o,templateStart:a,templateEnd:p,label:s}),r+=n[o+1]??"";}return {source:r,spans:t}},j=(e,n)=>{let r=new Map;return n.forEach(t=>{r.set(t.index,t);}),e.expressionRanges.map(t=>{let o=r.get(t.index);if(!o)return null;let s=Math.max(0,t.sourceEnd-t.sourceStart),a=Math.max(0,o.templateEnd-o.templateStart);return {sourceStart:t.sourceStart,sourceEnd:t.sourceEnd,templateStart:o.templateStart,templateEnd:o.templateEnd,delta:a-s}}).filter(t=>!!t).sort((t,o)=>t.sourceStart-o.sourceStart)},L=(e,n,r)=>{if(!Number.isFinite(e)||e<=0)return 0;let t=0;for(let s of n){if(e<s.sourceStart)break;if(e<s.sourceEnd){let a=Math.max(0,e-s.sourceStart),p=Math.max(0,s.templateEnd-s.templateStart);if(p===0)return s.templateStart;let i=Math.min(a,Math.max(0,p-1));return s.templateStart+i}t+=s.delta;}let o=e+t;return o<=0?0:o>=r?r:o},w=(e,n)=>{let r=Math.max(0,Math.min(n,e.length)),t=1,o=1;for(let s=0;s<r;s++){if(e.charCodeAt(s)===10){t++,o=1;continue}o++;}return {line:t,column:o}},D=e=>{let n=[],r=0;return e.forEach((t,o)=>{n.push(r),r+=t.length,o<e.length-1&&(r+=1);}),n},B=(e,n,r,t,o,s,a)=>{let p=r+n.length,i=Math.max(t,r),c=Math.min(o,p);if(c>i){let m=Math.max(0,i-r),l=Math.max(1,c-i);return " ".repeat(m)+"^".repeat(l)}if(n.length===0&&e>=s&&e<=a)return "^";if(e===s){let m=Math.max(0,t-r);return " ".repeat(Math.min(m,n.length))+"^"}return ""},v=(e,n,r,t,o)=>{if(!e.length)return "";let s=e.split(`
|
|
2
|
+
`),a=D(s),p=Math.max(1,t-1),i=Math.min(s.length,o+1),c=String(i).length,m=[];for(let l=p;l<=i;l++){let d=s[l-1]??"",u=String(l).padStart(c," ");m.push(`${u} | ${d}`);let g=B(l,d,a[l-1]??0,n,r,t,o);g&&m.push(`${" ".repeat(c)} | ${g}`);}return m.join(`
|
|
3
|
+
`)},b=(e,n,r,t,o)=>{let s=_,a=`[${s}] ${t.message}`,p=t.labels?.[0];if(!p)return a;let{source:i,spans:c}=O(n),m=j(r,c),l=h=>L(typeof h=="number"?h:0,m,i.length),d=l(p.start),u=l(p.end);u<=d&&(u=Math.min(i.length,d+1));let g=w(i,d),f=w(i,Math.max(d,u-1)),E=v(i,d,u,g.line,f.line),x=`[${s}] ${t.message}`;return x+=`
|
|
4
|
+
--> ${e} template:${g.line}:${g.column}`,p.message&&(x+=`
|
|
5
|
+
${p.message}`),E&&(x+=`
|
|
6
|
+
${E}`),t.helpMessage&&(x+=`
|
|
7
|
+
${t.helpMessage}`),x};var z=/<\s*$/,W=/<\/\s*$/,X="__KX_EXPR__",R=new RegExp(`${X}\\d+_\\d+__`,"g"),U=0;var $={lang:"jsx",sourceType:"module",range:true,preserveParens:true},A=e=>{for(let n of e.body)if(n.type==="ExpressionStatement"){let r=n.expression;if(r.type==="JSXElement"||r.type==="JSXFragment")return r}throw new Error("The jsx template must contain a single JSX element or fragment.")},S=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${S(e.object)}.${e.property.name}`;default:return ""}},C=(e,n)=>{if(!e||typeof e!="object")return;let r=e;typeof r.type=="string"&&(n(r),Object.values(r).forEach(t=>{if(t){if(Array.isArray(t)){t.forEach(o=>C(o,n));return}typeof t=="object"&&C(t,n);}}));},k=(e,n)=>{let r=e.replace(/\r/g,"").replace(/\n\s+/g," "),t=e.match(/^\s*/)?.[0]??"",o=e.match(/\s*$/)?.[0]??"",s=/\n/.test(t),a=/\n/.test(o),p=r;if(s&&(p=p.replace(/^\s+/,"")),a&&(p=p.replace(/\s+$/,"")),p.length===0||p.trim().length===0)return [];let i=[];R.lastIndex=0;let c=0,m;for(;m=R.exec(p);){let d=m.index,u=p.slice(c,d);u&&i.push(u);let g=m[0];n.has(g)?i.push(n.get(g)):i.push(g),c=d+g.length;}let l=p.slice(c);return l&&i.push(l),i},V=(e,n)=>{let r=new Set;return C(e,t=>{t.type==="Identifier"&&n.placeholders.has(t.name)&&r.add(t.name);}),Array.from(r)},M=(e,n,r)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return r(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[t,o]=e.range,s=n.source.slice(t,o),a=V(e,n);try{let p=new Function(...a,`"use strict"; return (${s});`),i=a.map(c=>n.placeholders.get(c));return p(...i)}catch(p){throw new Error(`Failed to evaluate expression ${s}: ${p.message}`)}},Z=e=>{let n=e.replace(/[^a-zA-Z0-9_$]/g,"");return n?/[A-Za-z_$]/.test(n[0])?n:`Component${n}`:"Component"},G=(e,n,r)=>{let t=r.get(e);if(t)return t;let o=e.displayName||e.name||`Component${n.length}`,s=Z(o??""),a=s,p=1;for(;n.some(c=>c.name===a);)a=`${s}${p++}`;let i={name:a,value:e};return n.push(i),r.set(e,i),i},N=(e,n)=>{let r=e.raw??e,t=new Map,o=[],s=new Map,a=r[0]??"",p=U++,i=0,c=[];for(let m=0;m<n.length;m++){let l=r[m]??"",d=r[m+1]??"",u=n[m],g=z.test(l)||W.test(l),f;if(g&&typeof u=="function")f=G(u,o,s).name;else if(g&&typeof u=="string")f=u;else {let h=`${X}${p}_${i++}__`;t.set(h,u),f=h;}let E=a.length;a+=f;let x=a.length;c.push({index:m,sourceStart:E,sourceEnd:x}),a+=d;}return {source:a,placeholders:t,bindings:o,diagnostics:{expressionRanges:c}}};var q=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",Q=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",y=(e,n)=>{if(n!=null&&typeof n!="boolean"){if(Q(n))throw new Error("Async values are not supported inside reactJsx template results.");if(Array.isArray(n)){n.forEach(r=>y(e,r));return}if(q(n)){for(let r of n)y(e,r);return}e.push(n);}},T=(e,n)=>M(e,n,r=>J(r,n)),Y=(e,n)=>{let r={};return e.forEach(t=>{if(t.type==="JSXSpreadAttribute"){let s=T(t.argument,n);s&&typeof s=="object"&&!Array.isArray(s)&&Object.assign(r,s);return}let o=S(t.name);if(!t.value){r[o]=true;return}if(t.value.type==="Literal"){r[o]=t.value.value;return}if(t.value.type==="JSXExpressionContainer"){if(t.value.expression.type==="JSXEmptyExpression")return;r[o]=T(t.value.expression,n);}}),r},I=(e,n)=>{let r=[];return e.forEach(t=>{switch(t.type){case "JSXText":{k(t.value,n.placeholders).forEach(s=>y(r,s));break}case "JSXExpressionContainer":{if(t.expression.type==="JSXEmptyExpression")break;y(r,T(t.expression,n));break}case "JSXSpreadChild":{let o=T(t.expression,n);o!=null&&y(r,o);break}case "JSXElement":case "JSXFragment":{r.push(J(t,n));break}}}),r},F=(e,n,r)=>createElement(e,n,...r),ee=(e,n)=>{let r=e.openingElement,t=S(r.name),o=n.components.get(t),s=Y(r.attributes,n),a=I(e.children,n);if(o)return F(o,s,a);if(/[A-Z]/.test(t[0]??""))throw new Error(`Unknown component "${t}". Did you interpolate it with the template literal?`);return F(t,s,a)},J=(e,n)=>{if(e.type==="JSXFragment"){let r=I(e.children,n);return createElement(Fragment,null,...r)}return ee(e,n)},te=(e,...n)=>{let r=N(e,n),t=parseSync("inline.jsx",r.source,$);if(t.errors.length>0)throw new Error(b("reactJsx",e,r.diagnostics,t.errors[0]));let o=A(t.program),s={source:r.source,placeholders:r.placeholders,components:new Map(r.bindings.map(a=>[a.name,a.value]))};return J(o,s)};export{te as reactJsx};
|
package/dist/lite/react/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';import {createElement,Fragment}from'react';var
|
|
2
|
-
${t.
|
|
3
|
-
|
|
1
|
+
import {parseSync}from'oxc-parser';import {createElement,Fragment}from'react';var _="oxc-parser",O=e=>{let n=e.raw??e,r=n[0]??"",t=[];for(let o=0;o<n.length-1;o++){let s="${expr#"+o+"}",a=r.length;r+=s;let p=r.length;t.push({index:o,templateStart:a,templateEnd:p,label:s}),r+=n[o+1]??"";}return {source:r,spans:t}},j=(e,n)=>{let r=new Map;return n.forEach(t=>{r.set(t.index,t);}),e.expressionRanges.map(t=>{let o=r.get(t.index);if(!o)return null;let s=Math.max(0,t.sourceEnd-t.sourceStart),a=Math.max(0,o.templateEnd-o.templateStart);return {sourceStart:t.sourceStart,sourceEnd:t.sourceEnd,templateStart:o.templateStart,templateEnd:o.templateEnd,delta:a-s}}).filter(t=>!!t).sort((t,o)=>t.sourceStart-o.sourceStart)},L=(e,n,r)=>{if(!Number.isFinite(e)||e<=0)return 0;let t=0;for(let s of n){if(e<s.sourceStart)break;if(e<s.sourceEnd){let a=Math.max(0,e-s.sourceStart),p=Math.max(0,s.templateEnd-s.templateStart);if(p===0)return s.templateStart;let i=Math.min(a,Math.max(0,p-1));return s.templateStart+i}t+=s.delta;}let o=e+t;return o<=0?0:o>=r?r:o},w=(e,n)=>{let r=Math.max(0,Math.min(n,e.length)),t=1,o=1;for(let s=0;s<r;s++){if(e.charCodeAt(s)===10){t++,o=1;continue}o++;}return {line:t,column:o}},D=e=>{let n=[],r=0;return e.forEach((t,o)=>{n.push(r),r+=t.length,o<e.length-1&&(r+=1);}),n},B=(e,n,r,t,o,s,a)=>{let p=r+n.length,i=Math.max(t,r),c=Math.min(o,p);if(c>i){let m=Math.max(0,i-r),l=Math.max(1,c-i);return " ".repeat(m)+"^".repeat(l)}if(n.length===0&&e>=s&&e<=a)return "^";if(e===s){let m=Math.max(0,t-r);return " ".repeat(Math.min(m,n.length))+"^"}return ""},v=(e,n,r,t,o)=>{if(!e.length)return "";let s=e.split(`
|
|
2
|
+
`),a=D(s),p=Math.max(1,t-1),i=Math.min(s.length,o+1),c=String(i).length,m=[];for(let l=p;l<=i;l++){let d=s[l-1]??"",u=String(l).padStart(c," ");m.push(`${u} | ${d}`);let g=B(l,d,a[l-1]??0,n,r,t,o);g&&m.push(`${" ".repeat(c)} | ${g}`);}return m.join(`
|
|
3
|
+
`)},b=(e,n,r,t,o)=>{let s=_,a=`[${s}] ${t.message}`,p=t.labels?.[0];if(!p)return a;let{source:i,spans:c}=O(n),m=j(r,c),l=h=>L(typeof h=="number"?h:0,m,i.length),d=l(p.start),u=l(p.end);u<=d&&(u=Math.min(i.length,d+1));let g=w(i,d),f=w(i,Math.max(d,u-1)),E=v(i,d,u,g.line,f.line),x=`[${s}] ${t.message}`;return x+=`
|
|
4
|
+
--> ${e} template:${g.line}:${g.column}`,p.message&&(x+=`
|
|
5
|
+
${p.message}`),E&&(x+=`
|
|
6
|
+
${E}`),t.helpMessage&&(x+=`
|
|
7
|
+
${t.helpMessage}`),x};var z=/<\s*$/,W=/<\/\s*$/,X="__KX_EXPR__",R=new RegExp(`${X}\\d+_\\d+__`,"g"),U=0;var $={lang:"jsx",sourceType:"module",range:true,preserveParens:true},A=e=>{for(let n of e.body)if(n.type==="ExpressionStatement"){let r=n.expression;if(r.type==="JSXElement"||r.type==="JSXFragment")return r}throw new Error("The jsx template must contain a single JSX element or fragment.")},S=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${S(e.object)}.${e.property.name}`;default:return ""}},C=(e,n)=>{if(!e||typeof e!="object")return;let r=e;typeof r.type=="string"&&(n(r),Object.values(r).forEach(t=>{if(t){if(Array.isArray(t)){t.forEach(o=>C(o,n));return}typeof t=="object"&&C(t,n);}}));},k=(e,n)=>{let r=e.replace(/\r/g,"").replace(/\n\s+/g," "),t=e.match(/^\s*/)?.[0]??"",o=e.match(/\s*$/)?.[0]??"",s=/\n/.test(t),a=/\n/.test(o),p=r;if(s&&(p=p.replace(/^\s+/,"")),a&&(p=p.replace(/\s+$/,"")),p.length===0||p.trim().length===0)return [];let i=[];R.lastIndex=0;let c=0,m;for(;m=R.exec(p);){let d=m.index,u=p.slice(c,d);u&&i.push(u);let g=m[0];n.has(g)?i.push(n.get(g)):i.push(g),c=d+g.length;}let l=p.slice(c);return l&&i.push(l),i},V=(e,n)=>{let r=new Set;return C(e,t=>{t.type==="Identifier"&&n.placeholders.has(t.name)&&r.add(t.name);}),Array.from(r)},M=(e,n,r)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return r(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[t,o]=e.range,s=n.source.slice(t,o),a=V(e,n);try{let p=new Function(...a,`"use strict"; return (${s});`),i=a.map(c=>n.placeholders.get(c));return p(...i)}catch(p){throw new Error(`Failed to evaluate expression ${s}: ${p.message}`)}},Z=e=>{let n=e.replace(/[^a-zA-Z0-9_$]/g,"");return n?/[A-Za-z_$]/.test(n[0])?n:`Component${n}`:"Component"},G=(e,n,r)=>{let t=r.get(e);if(t)return t;let o=e.displayName||e.name||`Component${n.length}`,s=Z(o??""),a=s,p=1;for(;n.some(c=>c.name===a);)a=`${s}${p++}`;let i={name:a,value:e};return n.push(i),r.set(e,i),i},N=(e,n)=>{let r=e.raw??e,t=new Map,o=[],s=new Map,a=r[0]??"",p=U++,i=0,c=[];for(let m=0;m<n.length;m++){let l=r[m]??"",d=r[m+1]??"",u=n[m],g=z.test(l)||W.test(l),f;if(g&&typeof u=="function")f=G(u,o,s).name;else if(g&&typeof u=="string")f=u;else {let h=`${X}${p}_${i++}__`;t.set(h,u),f=h;}let E=a.length;a+=f;let x=a.length;c.push({index:m,sourceStart:E,sourceEnd:x}),a+=d;}return {source:a,placeholders:t,bindings:o,diagnostics:{expressionRanges:c}}};var q=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",Q=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",y=(e,n)=>{if(n!=null&&typeof n!="boolean"){if(Q(n))throw new Error("Async values are not supported inside reactJsx template results.");if(Array.isArray(n)){n.forEach(r=>y(e,r));return}if(q(n)){for(let r of n)y(e,r);return}e.push(n);}},T=(e,n)=>M(e,n,r=>J(r,n)),Y=(e,n)=>{let r={};return e.forEach(t=>{if(t.type==="JSXSpreadAttribute"){let s=T(t.argument,n);s&&typeof s=="object"&&!Array.isArray(s)&&Object.assign(r,s);return}let o=S(t.name);if(!t.value){r[o]=true;return}if(t.value.type==="Literal"){r[o]=t.value.value;return}if(t.value.type==="JSXExpressionContainer"){if(t.value.expression.type==="JSXEmptyExpression")return;r[o]=T(t.value.expression,n);}}),r},I=(e,n)=>{let r=[];return e.forEach(t=>{switch(t.type){case "JSXText":{k(t.value,n.placeholders).forEach(s=>y(r,s));break}case "JSXExpressionContainer":{if(t.expression.type==="JSXEmptyExpression")break;y(r,T(t.expression,n));break}case "JSXSpreadChild":{let o=T(t.expression,n);o!=null&&y(r,o);break}case "JSXElement":case "JSXFragment":{r.push(J(t,n));break}}}),r},F=(e,n,r)=>createElement(e,n,...r),ee=(e,n)=>{let r=e.openingElement,t=S(r.name),o=n.components.get(t),s=Y(r.attributes,n),a=I(e.children,n);if(o)return F(o,s,a);if(/[A-Z]/.test(t[0]??""))throw new Error(`Unknown component "${t}". Did you interpolate it with the template literal?`);return F(t,s,a)},J=(e,n)=>{if(e.type==="JSXFragment"){let r=I(e.children,n);return createElement(Fragment,null,...r)}return ee(e,n)},te=(e,...n)=>{let r=N(e,n),t=parseSync("inline.jsx",r.source,$);if(t.errors.length>0)throw new Error(b("reactJsx",e,r.diagnostics,t.errors[0]));let o=A(t.program),s={source:r.source,placeholders:r.placeholders,components:new Map(r.bindings.map(a=>[a.name,a.value]))};return J(o,s)};export{te as reactJsx};
|
package/dist/loader/jsx.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { type SourceMap } from 'magic-string';
|
|
2
|
+
type LoaderCallback = (error: Error | null, content?: string, map?: SourceMap | null) => void;
|
|
2
3
|
type LoaderContext<TOptions> = {
|
|
3
4
|
resourcePath: string;
|
|
4
5
|
async(): LoaderCallback;
|
|
@@ -24,6 +25,10 @@ type LoaderOptions = {
|
|
|
24
25
|
* Optional per-tag override of the transformation mode. Keys map to tag names.
|
|
25
26
|
*/
|
|
26
27
|
tagModes?: Record<string, LoaderMode | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* When true, generate inline source maps for mutated files.
|
|
30
|
+
*/
|
|
31
|
+
sourceMap?: boolean;
|
|
27
32
|
};
|
|
28
33
|
export default function jsxLoader(this: LoaderContext<LoaderOptions>, input: string | Buffer): void;
|
|
29
34
|
export {};
|
package/dist/loader/jsx.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
2
|
import { parseSync } from 'oxc-parser';
|
|
3
|
+
import { formatTaggedTemplateParserError, } from '../internal/template-diagnostics.js';
|
|
3
4
|
const createPlaceholderMap = (placeholders) => new Map(placeholders.map(entry => [entry.marker, entry.code]));
|
|
4
5
|
class ReactTemplateBuilder {
|
|
5
6
|
placeholderMap;
|
|
@@ -159,6 +160,9 @@ class ReactTemplateBuilder {
|
|
|
159
160
|
throw new Error('[jsx-loader] Unable to inline complex expressions in react mode.');
|
|
160
161
|
}
|
|
161
162
|
/* c8 ignore next */
|
|
163
|
+
/* v8 ignore next */
|
|
164
|
+
/* istanbul ignore next */
|
|
165
|
+
// Should never happen because OXC always annotates expression ranges.
|
|
162
166
|
throw new Error('[jsx-loader] Unable to compile expression for react mode.');
|
|
163
167
|
}
|
|
164
168
|
buildCreateElement(type, props, children) {
|
|
@@ -270,11 +274,15 @@ const shouldInterpolateName = (name) => /^[A-Z]/.test(name.name);
|
|
|
270
274
|
const addSlot = (slots, source, range) => {
|
|
271
275
|
if (!range) {
|
|
272
276
|
/* c8 ignore next */
|
|
277
|
+
/* v8 ignore next */
|
|
278
|
+
// OXC always provides ranges; guard defends against malformed AST nodes.
|
|
273
279
|
return;
|
|
274
280
|
}
|
|
275
281
|
const [start, end] = range;
|
|
276
282
|
if (start === end) {
|
|
277
283
|
/* c8 ignore next */
|
|
284
|
+
/* v8 ignore next */
|
|
285
|
+
// Zero-length ranges indicate parser bugs and would emit empty slices.
|
|
278
286
|
return;
|
|
279
287
|
}
|
|
280
288
|
slots.push({
|
|
@@ -287,6 +295,9 @@ const collectSlots = (program, source) => {
|
|
|
287
295
|
const slots = [];
|
|
288
296
|
const recordComponentName = (name) => {
|
|
289
297
|
if (!name) {
|
|
298
|
+
/* c8 ignore next */
|
|
299
|
+
/* v8 ignore next */
|
|
300
|
+
// JSX elements emitted by OXC always carry a name; this is defensive.
|
|
290
301
|
return;
|
|
291
302
|
}
|
|
292
303
|
switch (name.type) {
|
|
@@ -356,6 +367,8 @@ const renderTemplateWithSlots = (source, slots) => {
|
|
|
356
367
|
slots.forEach(slot => {
|
|
357
368
|
if (slot.start < cursor) {
|
|
358
369
|
/* c8 ignore next */
|
|
370
|
+
/* v8 ignore next */
|
|
371
|
+
// Slots are generated from non-overlapping JSX ranges; this protects against parser regressions.
|
|
359
372
|
throw new Error('Overlapping JSX expressions detected inside template literal.');
|
|
360
373
|
}
|
|
361
374
|
output += escapeTemplateChunk(source.slice(cursor, slot.start));
|
|
@@ -365,10 +378,12 @@ const renderTemplateWithSlots = (source, slots) => {
|
|
|
365
378
|
output += escapeTemplateChunk(source.slice(cursor));
|
|
366
379
|
return { code: output, changed: slots.length > 0 };
|
|
367
380
|
};
|
|
368
|
-
const transformTemplateLiteral = (templateSource, resourcePath) => {
|
|
381
|
+
const transformTemplateLiteral = (templateSource, resourcePath, tagName, templates, diagnostics) => {
|
|
369
382
|
const result = parseSync(`${resourcePath}?jsx-template`, templateSource, TEMPLATE_PARSER_OPTIONS);
|
|
370
383
|
if (result.errors.length > 0) {
|
|
371
|
-
throw new Error(
|
|
384
|
+
throw new Error(formatTaggedTemplateParserError(tagName, templates, diagnostics, result.errors[0], {
|
|
385
|
+
label: 'jsx-loader',
|
|
386
|
+
}));
|
|
372
387
|
}
|
|
373
388
|
const slots = collectSlots(result.program, templateSource);
|
|
374
389
|
return renderTemplateWithSlots(templateSource, slots);
|
|
@@ -437,6 +452,25 @@ const normalizeJsxTextSegments = (value, placeholders) => {
|
|
|
437
452
|
return segments;
|
|
438
453
|
};
|
|
439
454
|
const TAG_PLACEHOLDER_PREFIX = '__JSX_LOADER_TAG_EXPR_';
|
|
455
|
+
const materializeTemplateStrings = (quasis) => {
|
|
456
|
+
const cooked = [];
|
|
457
|
+
const raw = [];
|
|
458
|
+
quasis.forEach(quasi => {
|
|
459
|
+
const value = quasi.value;
|
|
460
|
+
const cookedChunk = typeof value.cooked === 'string' ? value.cooked : (value.raw ?? '');
|
|
461
|
+
const rawChunk = typeof value.raw === 'string' ? value.raw : cookedChunk;
|
|
462
|
+
cooked.push(cookedChunk);
|
|
463
|
+
raw.push(rawChunk);
|
|
464
|
+
});
|
|
465
|
+
const templates = cooked;
|
|
466
|
+
Object.defineProperty(templates, 'raw', {
|
|
467
|
+
value: raw,
|
|
468
|
+
writable: false,
|
|
469
|
+
configurable: false,
|
|
470
|
+
enumerable: false,
|
|
471
|
+
});
|
|
472
|
+
return templates;
|
|
473
|
+
};
|
|
440
474
|
const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
441
475
|
const placeholderMap = new Map();
|
|
442
476
|
const tagPlaceholderMap = new Map();
|
|
@@ -444,6 +478,7 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
444
478
|
let placeholderIndex = 0;
|
|
445
479
|
let trimStartNext = 0;
|
|
446
480
|
let mutated = false;
|
|
481
|
+
const expressionRanges = [];
|
|
447
482
|
const registerMarker = (code, isTag) => {
|
|
448
483
|
if (isTag) {
|
|
449
484
|
const existing = tagPlaceholderMap.get(code);
|
|
@@ -459,10 +494,18 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
459
494
|
placeholderMap.set(marker, code);
|
|
460
495
|
return marker;
|
|
461
496
|
};
|
|
497
|
+
const appendInsertion = (expressionIndex, insertion) => {
|
|
498
|
+
const start = template.length;
|
|
499
|
+
template += insertion;
|
|
500
|
+
const end = template.length;
|
|
501
|
+
expressionRanges.push({ index: expressionIndex, sourceStart: start, sourceEnd: end });
|
|
502
|
+
};
|
|
462
503
|
quasis.forEach((quasi, index) => {
|
|
463
504
|
let chunk = quasi.value.cooked;
|
|
464
505
|
if (typeof chunk !== 'string') {
|
|
465
506
|
/* c8 ignore next */
|
|
507
|
+
/* v8 ignore next */
|
|
508
|
+
// Cooked text is always available for valid templates; fall back shields invalid escape sequences.
|
|
466
509
|
chunk = quasi.value.raw ?? '';
|
|
467
510
|
}
|
|
468
511
|
if (trimStartNext > 0) {
|
|
@@ -474,10 +517,13 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
474
517
|
if (!expression) {
|
|
475
518
|
return;
|
|
476
519
|
}
|
|
520
|
+
const expressionIndex = index;
|
|
477
521
|
const start = expression.start ?? null;
|
|
478
522
|
const end = expression.end ?? null;
|
|
479
523
|
if (start === null || end === null) {
|
|
480
524
|
/* c8 ignore next */
|
|
525
|
+
/* v8 ignore next */
|
|
526
|
+
// Expressions parsed from tagged templates always include start/end ranges.
|
|
481
527
|
throw new Error('Unable to read template expression source range.');
|
|
482
528
|
}
|
|
483
529
|
const nextChunk = quasis[index + 1];
|
|
@@ -487,7 +533,8 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
487
533
|
const code = source.slice(start, end);
|
|
488
534
|
const marker = registerMarker(code, context.type === 'tag');
|
|
489
535
|
const appendMarker = (wrapper) => {
|
|
490
|
-
|
|
536
|
+
const insertion = wrapper ? wrapper(marker) : marker;
|
|
537
|
+
appendInsertion(expressionIndex, insertion);
|
|
491
538
|
};
|
|
492
539
|
switch (context.type) {
|
|
493
540
|
case 'tag':
|
|
@@ -529,15 +576,22 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
529
576
|
marker,
|
|
530
577
|
code,
|
|
531
578
|
})),
|
|
579
|
+
diagnostics: { expressionRanges },
|
|
532
580
|
};
|
|
533
581
|
};
|
|
534
582
|
const restoreTemplatePlaceholders = (code, placeholders) => placeholders.reduce((result, placeholder) => {
|
|
535
583
|
return result.split(placeholder.marker).join(`\${${placeholder.code}}`);
|
|
536
584
|
}, code);
|
|
537
|
-
const
|
|
585
|
+
const createInlineSourceMapComment = (map) => {
|
|
586
|
+
const payload = Buffer.from(JSON.stringify(map), 'utf8').toString('base64');
|
|
587
|
+
return `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${payload}`;
|
|
588
|
+
};
|
|
589
|
+
const compileReactTemplate = (templateSource, placeholders, resourcePath, tagName, templates, diagnostics) => {
|
|
538
590
|
const parsed = parseSync(`${resourcePath}?jsx-react-template`, templateSource, TEMPLATE_PARSER_OPTIONS);
|
|
539
591
|
if (parsed.errors.length > 0) {
|
|
540
|
-
throw new Error(
|
|
592
|
+
throw new Error(formatTaggedTemplateParserError(tagName, templates, diagnostics, parsed.errors[0], {
|
|
593
|
+
label: 'jsx-loader',
|
|
594
|
+
}));
|
|
541
595
|
}
|
|
542
596
|
const root = extractJsxRoot(parsed.program);
|
|
543
597
|
const builder = new ReactTemplateBuilder(placeholders);
|
|
@@ -548,12 +602,14 @@ const isLoaderPlaceholderIdentifier = (node) => {
|
|
|
548
602
|
(node.type !== 'Identifier' && node.type !== 'JSXIdentifier') ||
|
|
549
603
|
typeof node.name !== 'string') {
|
|
550
604
|
/* c8 ignore next */
|
|
605
|
+
/* v8 ignore next */
|
|
606
|
+
// Visitor only calls this helper with identifier-like nodes; guard prevents crashes on malformed ASTs.
|
|
551
607
|
return false;
|
|
552
608
|
}
|
|
553
609
|
return (node.name.startsWith(TEMPLATE_EXPR_PLACEHOLDER_PREFIX) ||
|
|
554
610
|
node.name.startsWith(TAG_PLACEHOLDER_PREFIX));
|
|
555
611
|
};
|
|
556
|
-
const transformSource = (source, config) => {
|
|
612
|
+
const transformSource = (source, config, options) => {
|
|
557
613
|
const ast = parseSync(config.resourcePath, source, MODULE_PARSER_OPTIONS);
|
|
558
614
|
if (ast.errors.length > 0) {
|
|
559
615
|
throw new Error(formatParserError(ast.errors[0]));
|
|
@@ -566,7 +622,7 @@ const transformSource = (source, config) => {
|
|
|
566
622
|
}
|
|
567
623
|
});
|
|
568
624
|
if (!taggedTemplates.length) {
|
|
569
|
-
return { code: source,
|
|
625
|
+
return { code: source, mutated: false };
|
|
570
626
|
}
|
|
571
627
|
const magic = new MagicString(source);
|
|
572
628
|
let mutated = false;
|
|
@@ -578,8 +634,9 @@ const transformSource = (source, config) => {
|
|
|
578
634
|
const mode = config.tagModes.get(tagName) ?? DEFAULT_MODE;
|
|
579
635
|
const quasi = node.quasi;
|
|
580
636
|
const templateSource = buildTemplateSource(quasi.quasis, quasi.expressions, source, tagName);
|
|
637
|
+
const templateStrings = materializeTemplateStrings(quasi.quasis);
|
|
581
638
|
if (mode === 'runtime') {
|
|
582
|
-
const { code, changed } = transformTemplateLiteral(templateSource.source, config.resourcePath);
|
|
639
|
+
const { code, changed } = transformTemplateLiteral(templateSource.source, config.resourcePath, tagName, templateStrings, templateSource.diagnostics);
|
|
583
640
|
const restored = restoreTemplatePlaceholders(code, templateSource.placeholders);
|
|
584
641
|
const templateChanged = changed || templateSource.mutated;
|
|
585
642
|
if (!templateChanged) {
|
|
@@ -592,20 +649,37 @@ const transformSource = (source, config) => {
|
|
|
592
649
|
return;
|
|
593
650
|
}
|
|
594
651
|
if (mode === 'react') {
|
|
595
|
-
const compiled = compileReactTemplate(templateSource.source, templateSource.placeholders, config.resourcePath);
|
|
652
|
+
const compiled = compileReactTemplate(templateSource.source, templateSource.placeholders, config.resourcePath, tagName, templateStrings, templateSource.diagnostics);
|
|
596
653
|
helperKinds.add('react');
|
|
597
654
|
magic.overwrite(node.start, node.end, compiled);
|
|
598
655
|
mutated = true;
|
|
599
656
|
return;
|
|
600
657
|
}
|
|
601
658
|
/* c8 ignore next */
|
|
659
|
+
/* v8 ignore next */
|
|
660
|
+
// Modes are validated during option parsing; this fallback guards future extensions.
|
|
602
661
|
throw new Error(`[jsx-loader] Transformation mode "${mode}" not implemented yet for tag "${tagName}".`);
|
|
603
662
|
});
|
|
663
|
+
const helperSource = Array.from(helperKinds)
|
|
664
|
+
.map(kind => HELPER_SNIPPETS[kind])
|
|
665
|
+
.filter(Boolean)
|
|
666
|
+
.join('\n');
|
|
667
|
+
if (helperSource) {
|
|
668
|
+
magic.append(`\n${helperSource}`);
|
|
669
|
+
mutated = true;
|
|
670
|
+
}
|
|
671
|
+
const code = mutated ? magic.toString() : source;
|
|
672
|
+
const map = options?.sourceMap && mutated
|
|
673
|
+
? magic.generateMap({
|
|
674
|
+
hires: true,
|
|
675
|
+
source: config.resourcePath,
|
|
676
|
+
includeContent: true,
|
|
677
|
+
})
|
|
678
|
+
: undefined;
|
|
604
679
|
return {
|
|
605
|
-
code
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
.filter(Boolean),
|
|
680
|
+
code,
|
|
681
|
+
map,
|
|
682
|
+
mutated,
|
|
609
683
|
};
|
|
610
684
|
};
|
|
611
685
|
export default function jsxLoader(input) {
|
|
@@ -642,16 +716,14 @@ export default function jsxLoader(input) {
|
|
|
642
716
|
}
|
|
643
717
|
});
|
|
644
718
|
const source = typeof input === 'string' ? input : input.toString('utf8');
|
|
645
|
-
const
|
|
719
|
+
const enableSourceMap = options.sourceMap === true;
|
|
720
|
+
const { code, map } = transformSource(source, {
|
|
646
721
|
resourcePath: this.resourcePath,
|
|
647
722
|
tags,
|
|
648
723
|
tagModes,
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
callback(null, code);
|
|
724
|
+
}, { sourceMap: enableSourceMap });
|
|
725
|
+
const output = map && enableSourceMap ? `${code}\n${createInlineSourceMapComment(map)}` : code;
|
|
726
|
+
callback(null, output, map);
|
|
655
727
|
}
|
|
656
728
|
catch (error) {
|
|
657
729
|
callback(error);
|
package/dist/node/bootstrap.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare const ensureNodeDom: () =>
|
|
1
|
+
export declare const ensureNodeDom: () => void;
|
|
2
|
+
export declare const __setNodeRequireForTesting: (mockRequire: NodeJS.Require | null) => void;
|
package/dist/node/bootstrap.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const nodeRequire = createRequire(import.meta.url);
|
|
3
|
+
let requireOverride = null;
|
|
4
|
+
const resolveRequire = () => requireOverride ?? nodeRequire;
|
|
1
5
|
const DOM_TEMPLATE = '<!doctype html><html><body></body></html>';
|
|
2
6
|
const GLOBAL_KEYS = [
|
|
3
7
|
'window',
|
|
@@ -23,13 +27,13 @@ const assignGlobalTargets = (windowObj) => {
|
|
|
23
27
|
}
|
|
24
28
|
});
|
|
25
29
|
};
|
|
26
|
-
const loadLinkedom =
|
|
27
|
-
const { parseHTML } =
|
|
30
|
+
const loadLinkedom = () => {
|
|
31
|
+
const { parseHTML } = resolveRequire()('linkedom');
|
|
28
32
|
const { window } = parseHTML(DOM_TEMPLATE);
|
|
29
33
|
return window;
|
|
30
34
|
};
|
|
31
|
-
const loadJsdom =
|
|
32
|
-
const { JSDOM } =
|
|
35
|
+
const loadJsdom = () => {
|
|
36
|
+
const { JSDOM } = resolveRequire()('jsdom');
|
|
33
37
|
const { window } = new JSDOM(DOM_TEMPLATE);
|
|
34
38
|
return window;
|
|
35
39
|
};
|
|
@@ -52,11 +56,11 @@ const selectLoaders = () => {
|
|
|
52
56
|
}
|
|
53
57
|
return [loadLinkedom, loadJsdom];
|
|
54
58
|
};
|
|
55
|
-
const createShimWindow =
|
|
59
|
+
const createShimWindow = () => {
|
|
56
60
|
const errors = [];
|
|
57
61
|
for (const loader of selectLoaders()) {
|
|
58
62
|
try {
|
|
59
|
-
return
|
|
63
|
+
return loader();
|
|
60
64
|
}
|
|
61
65
|
catch (error) {
|
|
62
66
|
errors.push(error);
|
|
@@ -65,19 +69,15 @@ const createShimWindow = async () => {
|
|
|
65
69
|
const help = 'Unable to bootstrap a DOM-like environment. Install "linkedom" or "jsdom" (both optional peer dependencies) or set KNIGHTED_JSX_NODE_SHIM to pick one explicitly.';
|
|
66
70
|
throw new AggregateError(errors, help);
|
|
67
71
|
};
|
|
68
|
-
let
|
|
69
|
-
export const ensureNodeDom =
|
|
70
|
-
if (hasDom()) {
|
|
72
|
+
let bootstrapped = false;
|
|
73
|
+
export const ensureNodeDom = () => {
|
|
74
|
+
if (hasDom() || bootstrapped) {
|
|
71
75
|
return;
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throw error;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return bootstrapPromise;
|
|
77
|
+
const windowObj = createShimWindow();
|
|
78
|
+
assignGlobalTargets(windowObj);
|
|
79
|
+
bootstrapped = true;
|
|
80
|
+
};
|
|
81
|
+
export const __setNodeRequireForTesting = (mockRequire) => {
|
|
82
|
+
requireOverride = mockRequire;
|
|
83
83
|
};
|
package/dist/node/index.js
CHANGED
package/dist/react/react-jsx.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseSync } from 'oxc-parser';
|
|
2
|
-
import { buildTemplate, evaluateExpression, extractRootNode,
|
|
2
|
+
import { buildTemplate, evaluateExpression, extractRootNode, formatTaggedTemplateParserError, getIdentifierName, normalizeJsxTextSegments, parserOptions, } from '../runtime/shared.js';
|
|
3
3
|
import { Fragment, createElement, } from 'react';
|
|
4
4
|
const isIterable = (value) => {
|
|
5
5
|
if (!value || typeof value === 'string') {
|
|
@@ -124,7 +124,7 @@ export const reactJsx = (templates, ...values) => {
|
|
|
124
124
|
const build = buildTemplate(templates, values);
|
|
125
125
|
const result = parseSync('inline.jsx', build.source, parserOptions);
|
|
126
126
|
if (result.errors.length > 0) {
|
|
127
|
-
throw new Error(
|
|
127
|
+
throw new Error(formatTaggedTemplateParserError('reactJsx', templates, build.diagnostics, result.errors[0]));
|
|
128
128
|
}
|
|
129
129
|
const root = extractRootNode(result.program);
|
|
130
130
|
const ctx = {
|
package/dist/runtime/shared.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { Expression, JSXElement, JSXFragment, JSXIdentifier, JSXMemberExpression, JSXNamespacedName, Program } from '@oxc-project/types';
|
|
2
2
|
import type { OxcError, ParserOptions } from 'oxc-parser';
|
|
3
|
+
import type { TemplateDiagnostics } from '../internal/template-diagnostics.js';
|
|
4
|
+
export { formatTaggedTemplateParserError } from '../internal/template-diagnostics.js';
|
|
5
|
+
export type { TemplateDiagnostics, TemplateExpressionRange, } from '../internal/template-diagnostics.js';
|
|
3
6
|
export declare const PLACEHOLDER_PREFIX = "__KX_EXPR__";
|
|
4
7
|
export declare const placeholderPattern: RegExp;
|
|
8
|
+
export declare const formatParserError: (error: OxcError) => string;
|
|
5
9
|
type AnyTemplateFunction = (...args: any[]) => unknown;
|
|
6
10
|
type AnyTemplateConstructor = abstract new (...args: any[]) => unknown;
|
|
7
11
|
export type TemplateComponent = (AnyTemplateFunction | AnyTemplateConstructor) & {
|
|
@@ -16,6 +20,7 @@ export type TemplateBuildResult<TComponent extends TemplateComponent> = {
|
|
|
16
20
|
source: string;
|
|
17
21
|
placeholders: Map<string, unknown>;
|
|
18
22
|
bindings: BindingEntry<TComponent>[];
|
|
23
|
+
diagnostics: TemplateDiagnostics;
|
|
19
24
|
};
|
|
20
25
|
export type TemplateContext<TComponent extends TemplateComponent> = {
|
|
21
26
|
source: string;
|
|
@@ -23,7 +28,6 @@ export type TemplateContext<TComponent extends TemplateComponent> = {
|
|
|
23
28
|
components: Map<string, TComponent>;
|
|
24
29
|
};
|
|
25
30
|
export declare const parserOptions: ParserOptions;
|
|
26
|
-
export declare const formatParserError: (error: OxcError) => string;
|
|
27
31
|
export declare const extractRootNode: (program: Program) => JSXElement | JSXFragment;
|
|
28
32
|
export declare const getIdentifierName: (identifier: JSXIdentifier | JSXNamespacedName | JSXMemberExpression) => string;
|
|
29
33
|
type AnyOxcNode = {
|
|
@@ -37,4 +41,3 @@ export declare const evaluateExpression: <TComponent extends TemplateComponent>(
|
|
|
37
41
|
export declare const sanitizeIdentifier: (value: string) => string;
|
|
38
42
|
export declare const ensureBinding: <TComponent extends TemplateComponent>(value: TComponent, bindings: BindingEntry<TComponent>[], bindingLookup: Map<TComponent, BindingEntry<TComponent>>) => BindingEntry<TComponent>;
|
|
39
43
|
export declare const buildTemplate: <TComponent extends TemplateComponent>(strings: TemplateStringsArray, values: unknown[]) => TemplateBuildResult<TComponent>;
|
|
40
|
-
export {};
|