Comparing version 0.1.5 to 0.1.6
208
hjsx.js
@@ -1,207 +0,1 @@ | ||
// util/normalize-attribute-name.ts | ||
function normalizeAttributeName(attribute) { | ||
if (attributes.html.includes(attribute)) { | ||
return toHtmlAttribute(attribute); | ||
} | ||
if (attributes.svg.includes(attribute)) { | ||
return toSvgAttribute(attribute); | ||
} | ||
return attribute; | ||
} | ||
var toHtmlAttribute = function(attribute) { | ||
if (exceptions.html[attribute]) { | ||
return exceptions.html[attribute]; | ||
} | ||
return attribute.toLowerCase(); | ||
}; | ||
var toSvgAttribute = function(attribute) { | ||
if (exceptions.svg[attribute]) { | ||
return exceptions.svg[attribute]; | ||
} | ||
return attribute.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`); | ||
}; | ||
var attributes = { | ||
html: "accept acceptCharset accessKey action allowFullScreen alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge charSet checked cite classID className colSpan cols content contentEditable contextMenu controls controlsList coords crossOrigin data dateTime default defer dir disabled download draggable encType form formAction formEncType formMethod formNoValidate formTarget frameBorder headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media mediaGroup method min minLength multiple muted name noValidate nonce open optimum pattern placeholder poster preload profile radioGroup readOnly rel required reversed role rowSpan rows sandbox scope scoped scrolling seamless selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step style summary tabIndex target title type useMap value width wmode wrap", | ||
svg: "accentHeight accumulate additive alignmentBaseline allowReorder alphabetic amplitude arabicForm ascent attributeName attributeType autoReverse azimuth baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight clip clipPath clipPathUnits clipRule colorInterpolation colorInterpolationFilters colorProfile colorRendering contentScriptType contentStyleType cursor cx cy d decelerate descent diffuseConstant direction display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground end exponent externalResourcesRequired fill fillOpacity fillRule filter filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor limitingConeAngle local markerEnd markerHeight markerMid markerStart markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode numOctaves offset opacity operator order orient orientation origin overflow overlinePosition overlineThickness paintOrder panose1 pathLength patternContentUnits patternTransform patternUnits pointerEvents points pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions requiredFeatures restart result rotate rx ry scale seed shapeRendering slope spacing specularConstant specularExponent speed spreadMethod startOffset stdDeviation stemh stemv stitchTiles stopColor stopOpacity strikethroughPosition strikethroughThickness string stroke strokeDasharray strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor textDecoration textLength textRendering to transform u1 u2 underlinePosition underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic vHanging vIdeographic vMathematical values vectorEffect version vertAdvY vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlns xmlnsXlink xmlBase xmlLang xmlSpace y y1 y2 yChannelSelector z zoomAndPan" | ||
}; | ||
var exceptions = { | ||
html: { | ||
acceptCharset: "accept-charset", | ||
className: "class", | ||
htmlFor: "for", | ||
httpEquiv: "http-equiv", | ||
defaultChecked: "checked" | ||
}, | ||
svg: { | ||
panose1: "panose-1", | ||
xlinkActuate: "xlink:actuate", | ||
xlinkArcrole: "xlink:arcrole", | ||
xlinkHref: "xlink:href", | ||
xlinkRole: "xlink:role", | ||
xlinkShow: "xlink:show", | ||
xlinkTitle: "xlink:title", | ||
xlinkType: "xlink:type", | ||
xmlBase: "xml:base", | ||
xmlLang: "xml:lang", | ||
xmlSpace: "xml:space", | ||
xmlnsXlink: "xmlns:xlink", | ||
xmlns: "xmlns", | ||
zoomAndPan: "zoomAndPan" | ||
} | ||
}; | ||
// util/index.ts | ||
function escapeHtml(str) { | ||
let html = ""; | ||
let matchIndex; | ||
let lastIndex = 0; | ||
let char; | ||
while (true) { | ||
matchIndex = regex.exec(str)?.index; | ||
if (matchIndex === undefined) | ||
break; | ||
html += str.slice(lastIndex, matchIndex); | ||
char = str[matchIndex]; | ||
html += escapeMap[char]; | ||
lastIndex = matchIndex + 1; | ||
} | ||
html += str.slice(lastIndex); | ||
return html; | ||
} | ||
function isPrimitive(value) { | ||
return typeof value === "string" || typeof value === "number" || typeof value === "boolean"; | ||
} | ||
function isNullish(value) { | ||
return value === null || value === undefined; | ||
} | ||
function isIterable(value) { | ||
return Symbol.iterator in Object(value) && typeof value !== "string"; | ||
} | ||
function isObject(value) { | ||
return typeof value === "object" && value !== null; | ||
} | ||
function isClassConstructor(fn) { | ||
return typeof fn === "function" && fn.toString().trim().startsWith("class"); | ||
} | ||
function dangerouslySetInnerHTML(value) { | ||
if (typeof value !== "object" || value === null) { | ||
throw new Error("dangerouslySetInnerHTML must be an object"); | ||
} | ||
if (!("__html" in value)) { | ||
throw new Error("dangerouslySetInnerHTML must have an __html property"); | ||
} | ||
return String(value.__html); | ||
} | ||
function handleStyle(value) { | ||
if (typeof value !== "object" || value === null) { | ||
throw new Error("style must be an object"); | ||
} | ||
return Object.entries(value).map(([key, value2]) => `${toKebabCase(key)}: ${value2}`).join("; "); | ||
} | ||
var toKebabCase = function(str) { | ||
return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`); | ||
}; | ||
var escapeMap = { | ||
"&": "&", | ||
"<": "<", | ||
">": ">", | ||
'"': """, | ||
"'": "'" | ||
}; | ||
var regex = new RegExp(`[${Object.keys(escapeMap).join("")}]`, "g"); | ||
var SELF_CLOSING_TAGS = [ | ||
"area", | ||
"base", | ||
"br", | ||
"col", | ||
"command", | ||
"embed", | ||
"hr", | ||
"img", | ||
"input", | ||
"keygen", | ||
"link", | ||
"meta", | ||
"param", | ||
"source", | ||
"track", | ||
"wbr" | ||
]; | ||
// hjsx.ts | ||
function hjsx(type, props, children) { | ||
return { | ||
type, | ||
props, | ||
children, | ||
render() { | ||
return renderToString(this); | ||
}, | ||
$$typeof: Symbol.for("hjsx.element"), | ||
key: null, | ||
ref: null, | ||
_owner: null | ||
}; | ||
} | ||
function fragment({ children }) { | ||
return children; | ||
} | ||
var validateElement = function(element) { | ||
if (!isObject(element)) { | ||
throw new Error("Element must be an object"); | ||
} | ||
if (!("type" in element)) { | ||
throw new Error("Element must have a type"); | ||
} | ||
if (!("props" in element)) { | ||
throw new Error("Element must have props"); | ||
} | ||
}; | ||
var renderToString = (component) => { | ||
if (isPrimitive(component)) | ||
return escapeHtml(String(component)); | ||
if (isNullish(component)) | ||
return ""; | ||
if (isIterable(component)) | ||
return renderChildren({ children: component }); | ||
if (!isObject(component)) | ||
return ""; | ||
if (!("children" in component)) | ||
return renderChildren({ children: component }); | ||
validateElement(component); | ||
let { type, props, children } = component; | ||
props = props ?? {}; | ||
if (typeof type === "function") { | ||
const componentInstance = isClassConstructor(type) ? new type({ ...props, children }) : type({ ...props, children }); | ||
return renderToString(componentInstance); | ||
} | ||
const innerHTML = props.dangerouslySetInnerHTML ? dangerouslySetInnerHTML(props.dangerouslySetInnerHTML) : null; | ||
const propsString = Object.entries(props).filter(([key, value]) => key !== "u.dangerouslySetInnerHTML" && value !== false && value != null).map(([key, value]) => { | ||
const normalizedKey = normalizeAttributeName(key); | ||
const normalizedValue = escapeHtml(String(key === "style" ? handleStyle(value) : value)); | ||
return value === true ? normalizedKey : `${normalizedKey}="${normalizedValue}"`; | ||
}).join(" "); | ||
const childrenString = innerHTML ?? renderChildren({ children }); | ||
if (typeof type !== "string") { | ||
return renderToString({ type, props, children }); | ||
} | ||
return SELF_CLOSING_TAGS.includes(type) ? `<${type} ${propsString} />` : `<${type} ${propsString}>${childrenString}</${type}>`; | ||
}; | ||
var renderChildren = (args) => { | ||
if (isNullish(args)) | ||
return ""; | ||
if (isPrimitive(args)) | ||
return escapeHtml(String(args)); | ||
if (!isObject(args)) | ||
return ""; | ||
const { children } = args; | ||
const childrenArray = Array.isArray(children) ? children : [children]; | ||
return childrenArray.filter((child) => !isNullish(child)).map(renderToString).join(""); | ||
}; | ||
globalThis.hjsx = hjsx; | ||
globalThis.fragment = fragment; | ||
export { | ||
renderToString, | ||
hjsx, | ||
fragment | ||
}; | ||
function J(R){if(W.html.includes(R))return C(R);if(W.svg.includes(R))return M(R);return R}var C=function(R){if(A.html[R])return A.html[R];return R.toLowerCase()},M=function(R){if(A.svg[R])return A.svg[R];return R.replace(/([A-Z])/g,(F)=>`-${F[0].toLowerCase()}`)},W={html:"accept acceptCharset accessKey action allowFullScreen alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge charSet checked cite classID className colSpan cols content contentEditable contextMenu controls controlsList coords crossOrigin data dateTime default defer dir disabled download draggable encType form formAction formEncType formMethod formNoValidate formTarget frameBorder headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media mediaGroup method min minLength multiple muted name noValidate nonce open optimum pattern placeholder poster preload profile radioGroup readOnly rel required reversed role rowSpan rows sandbox scope scoped scrolling seamless selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step style summary tabIndex target title type useMap value width wmode wrap",svg:"accentHeight accumulate additive alignmentBaseline allowReorder alphabetic amplitude arabicForm ascent attributeName attributeType autoReverse azimuth baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight clip clipPath clipPathUnits clipRule colorInterpolation colorInterpolationFilters colorProfile colorRendering contentScriptType contentStyleType cursor cx cy d decelerate descent diffuseConstant direction display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground end exponent externalResourcesRequired fill fillOpacity fillRule filter filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor limitingConeAngle local markerEnd markerHeight markerMid markerStart markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode numOctaves offset opacity operator order orient orientation origin overflow overlinePosition overlineThickness paintOrder panose1 pathLength patternContentUnits patternTransform patternUnits pointerEvents points pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions requiredFeatures restart result rotate rx ry scale seed shapeRendering slope spacing specularConstant specularExponent speed spreadMethod startOffset stdDeviation stemh stemv stitchTiles stopColor stopOpacity strikethroughPosition strikethroughThickness string stroke strokeDasharray strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor textDecoration textLength textRendering to transform u1 u2 underlinePosition underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic vHanging vIdeographic vMathematical values vectorEffect version vertAdvY vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlns xmlnsXlink xmlBase xmlLang xmlSpace y y1 y2 yChannelSelector z zoomAndPan"},A={html:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv",defaultChecked:"checked"},svg:{panose1:"panose-1",xlinkActuate:"xlink:actuate",xlinkArcrole:"xlink:arcrole",xlinkHref:"xlink:href",xlinkRole:"xlink:role",xlinkShow:"xlink:show",xlinkTitle:"xlink:title",xlinkType:"xlink:type",xmlBase:"xml:base",xmlLang:"xml:lang",xmlSpace:"xml:space",xmlnsXlink:"xmlns:xlink",xmlns:"xmlns",zoomAndPan:"zoomAndPan"}};function B(R){let F="",N,Z=0,w;while(!0){if(N=K.exec(R)?.index,N===void 0)break;F+=R.slice(Z,N),w=R[N],F+=X[w],Z=N+1}return F+=R.slice(Z),F}function O(R){return typeof R==="string"||typeof R==="number"||typeof R==="boolean"}function D(R){return R===null||R===void 0}function Y(R){return Symbol.iterator in Object(R)&&typeof R!=="string"}function E(R){return typeof R==="object"&&R!==null}function $(R){return typeof R==="function"&&R.toString().trim().startsWith("class")}function j(R){if(typeof R!=="object"||R===null)throw new Error("dangerouslySetInnerHTML must be an object");if(!("__html"in R))throw new Error("dangerouslySetInnerHTML must have an __html property");return String(R.__html)}function H(R){if(typeof R!=="object"||R===null)throw new Error("style must be an object");return Object.entries(R).map(([F,N])=>`${k(F)}: ${N}`).join("; ")}var k=function(R){return R.replace(/([A-Z])/g,(F)=>`-${F[0].toLowerCase()}`)},X={"&":"&","<":"<",">":">",'"':""","'":"'"},K=new RegExp(`[${Object.keys(X).join("")}]`,"g"),L=["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"];function _(R,F,N){return{type:R,props:F,children:N,render(){return G(this)},$$typeof:Symbol.for("hjsx.element"),key:null,ref:null,_owner:null}}function I({children:R}){return R}var S=function(R){if(!E(R))throw new Error("Element must be an object");if(!("type"in R))throw new Error("Element must have a type");if(!("props"in R))throw new Error("Element must have props")},G=(R)=>{if(O(R))return B(String(R));if(D(R))return"";if(Y(R))return P({children:R});if(!E(R))return"";if(!("children"in R))return P({children:R});S(R);let{type:F,props:N,children:Z}=R;if(N=N??{},typeof F==="function"){const f=$(F)?new F({...N,children:Z}):F({...N,children:Z});return G(f)}const w=N.dangerouslySetInnerHTML?j(N.dangerouslySetInnerHTML):null,Q=Object.entries(N).filter(([f,q])=>f!=="u.dangerouslySetInnerHTML"&&q!==!1&&q!=null).map(([f,q])=>{const U=J(f),z=B(String(f==="style"?H(q):q));return q===!0?U:`${U}="${z}"`}).join(" "),V=w??P({children:Z});if(typeof F!=="string")return G({type:F,props:N,children:Z});return L.includes(F)?`<${F} ${Q} />`:`<${F} ${Q}>${V}</${F}>`},P=(R)=>{if(D(R))return"";if(O(R))return B(String(R));if(!E(R))return"";const{children:F}=R;return(Array.isArray(F)?F:[F]).filter((Z)=>!D(Z)).map(G).join("")};globalThis.hjsx=_;globalThis.fragment=I;export{G as renderToString,_ as hjsx,I as fragment}; |
{ | ||
"name": "hjsx", | ||
"version": "0.1.5", | ||
"version": "0.1.6", | ||
"module": "hjsx.ts", | ||
@@ -9,3 +9,3 @@ "main": "hjsx.js", | ||
"scripts": { | ||
"build": "bun build hjsx.ts --outfile hjsx.js --target node", | ||
"build": "bun build hjsx.ts --outfile hjsx.js --target node --minify", | ||
"prepare": "bun run build && bun run util/update-version.ts" | ||
@@ -12,0 +12,0 @@ }, |
89630
1779