Skip to content

Instantly share code, notes, and snippets.

@developit
Last active July 25, 2023 12:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save developit/5b54337adbdbf401742a06e5af801c67 to your computer and use it in GitHub Desktop.
Save developit/5b54337adbdbf401742a06e5af801c67 to your computer and use it in GitHub Desktop.

Horrible JSX Transform

import { jsx } from './jsx.js';

const out = jsx(`
  const App = props => (
    <div class="app">
      <h1>Hello {"World"}</h1>
      <ul>{['a','b','c'].map(item => <li>{item}</li>)}</ul>
    </div>
  );
`);

console.log(out);
/*
  const App = props => (
    html`<div class="app">
      <h1>Hello ${"World"}</h1>
      <ul>${['a','b','c'].map(item => html`<li>${item}</li>`)}</ul>
    </div>`
  );
*/

To run the code, prepend an import of html. You can import{html}from'htm/preact', or set up the binding manually:

const HTM = `
import htm from'https://unpkg.com/htm/dist/htm.mjs';
function html(){return (html=self.html||(self.html=htm.bind(h))).apply(this,arguments)}
`;
code = HTM + jsx(code);

Polka/Express Middleware

import polka from 'polka';
import sirv from 'sirv';
import { jsx } from './jsx.js';

const app = polka();
app.use(jsxMiddleware());
app.use(sirv({ dev: true }));
app.listen();

function jsxMiddleware() {
  return (req, res, next) => {
    if (!/\.m?jsx?$/i.test(req.path)) return next();
    let buf = '', { end, write, setHeader, writeHead } = res;
    res.write = chunk => buf += chunk;
    res.setHeader = (k, v) => /^content-length$/i.test(k) || setHeader.call(res, k, v);
    res.writeHead = (status, headers, h) => {
      for (let k in (h={},headers)) if (!/^content-length$/i.test(k)) h[k] = headers[k];
      return writeHead.call(res, status, h);
    };
    res.end = chunk => end.call(res, jsx(buf + (chunk || '')));
    next();
  };
}
export function jsx(code) {
const tokenizer = /(^|)(?:<\/([a-z$_][a-z0-9_.-:]*)>|<([a-z$_][a-z0-9_.-:]*)(\s+[a-z0-9._-]+(?:=(?:".*?"|'.*?'|\{.+?\}))?)*(\s*\/\s*)?>|<(\/?)>)/gi;
let out='', index=0, token;
let depth = 0;
let stacks = [];
let shouldPop = false;
while (token = tokenizer.exec(code)) {
const [, before, end, start, attrs, selfClosing, fragment] = token;
let leading = code.substring(index, token.index) + before;
if (depth || shouldPop) leading = leading.replace(/{/g, '${');
if (leading.match(/\$\{[^}]*$/) && depth) {
stacks.push(depth);
depth = 0;
}
out += leading;
if (!start && depth===0 && shouldPop) {
depth = stacks.pop() || 0;
shouldPop = false;
}
let rep;
if (start) {
if (/(^[A-Z]|\.$)/.test(start)) {
rep = start;
}
if (depth++ === 0) {
out += 'html`';
shouldPop = false;
}
}
else if (/(^[A-Z]|\.$)/.test(end)) {
rep = end;
}
index = tokenizer.lastIndex;
if (fragment!=null) {
out += fragment || (depth++) ? '' : 'html`';
}
else {
let f = code.substring(token.index + before.length, index);
if (rep) f = f.replace(rep, '${' + rep + '}');
f = f.replace(/(\.\.\.|=){/g, '$1${');
out += f;
}
if (end || selfClosing || fragment==='/') {
if (--depth === 0) {
out += '`';
shouldPop = true;
}
}
}
out += code.substring(index);
return out;
}
export function jsx(e){const t=/(^|)(?:<\/([a-z$_][a-z0-9_.-:]*)>|<([a-z$_][a-z0-9_.-:]*)(\s+[a-z0-9._-]+(?:=(?:".*?"|'.*?'|\{.+?\}))?)*(\s*\/\s*)?>|<(\/?)>)/gi;let s,l="",n=0,a=0,r=[],$=!1;for(;s=t.exec(e);){const[,c,i,g,p,u,o]=s;let x,h=e.substring(n,s.index)+c;if((a||$)&&(h=h.replace(/{/g,"${")),h.match(/\$\{[^}]*$/)&&a&&(r.push(a),a=0),l+=h,!g&&0===a&&$&&(a=r.pop()||0,$=!1),g?(/(^[A-Z]|\.$)/.test(g)&&(x=g),0==a++&&(l+="html`",$=!1)):/(^[A-Z]|\.$)/.test(i)&&(x=i),n=t.lastIndex,null!=o)l+=o||a++?"":"html`";else{let t=e.substring(s.index+c.length,n);x&&(t=t.replace(x,"${"+x+"}")),t=t.replace(/(\.\.\.|=){/g,"$1${"),l+=t}(i||u||"/"===o)&&0==--a&&(l+="`",$=!0)}return l+=e.substring(n),l}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment