├── .gitignore ├── README.md ├── generic-jsx-babel-plugin ├── generic-jsx-babel-plugin.js ├── package-lock.json └── package.json ├── generic-jsx-examples ├── binary-tree.js ├── immutable-map.js ├── package.json ├── react.js └── reduce.js └── generic-jsx ├── generic-jsx.js ├── package-lock.json ├── package.json └── runkitExample.js /.gitignore: -------------------------------------------------------------------------------- 1 | lithograph/test-worker/test-environment-preload.bundle.js 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Apple 11 | .DS_Store 12 | 13 | #petrified 14 | _site 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Typescript v1 declaration files 48 | typings/ 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | 68 | # next.js build output 69 | .next -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | You can find a full explanation of the ideas behind this [here](http://tolmasky.com/2016/03/24/generalizing-jsx/). 3 | 4 | Or, try it on [RunKit](https://runkit.com/npm/generic-jsx)! 5 | 6 | # Generic JSX 7 | 8 | This is a version of JSX for general purpose programming. Why would you want that? Well, it gives 9 | us the ability to have curried named parameters in JavaScript. 10 | 11 | # How Do I use It? 12 | 13 | If you are using Babel, then all you should need to do is the following: 14 | 15 | ```JavaScript 16 | /* @jsx curry(_=>eval(_)) */ 17 | var { curry } = require("generic-jsx"); 18 | ``` 19 | 20 | Now you'll be able make functions with named parameters that you can curry: 21 | 22 | ```JavaScript 23 | var fs = require("fs"); 24 | var readFileSync = ({ name, encoding }) => fs.readFileSync(name, encoding); 25 | 26 | // ... 27 | var readString = ; 28 | 29 | (); 30 | ``` 31 | 32 | Or, use with data structures! 33 | 34 | ```JavaScript 35 | /* @jsx (curry(_=>eval(_))) */ 36 | var { curry, from } = require("generic-jsx"); 37 | var BinaryTree = require("generic-jsx/binary-tree"); 38 | 39 | // This represents 5 / ( 4 + 6) 40 | 41 | 42 | 43 | 44 | 45 | 46 | () 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /generic-jsx-babel-plugin/generic-jsx-babel-plugin.js: -------------------------------------------------------------------------------- 1 | const fail = message => { throw Error(message) }; 2 | 3 | const toBoundAttributes = (t, attributes, children) => 4 | t.ObjectExpression(attributes 5 | .map(JSXAttributeToObjectProperty(t))); 6 | 7 | const toChildrenArray = (t, children) => 8 | t.ArrayExpression(children 9 | .map(child => toChildValue(t, child)) 10 | .filter(child => !t.isJSXEmptyExpression(child))); 11 | 12 | const toExpression = (t, node) => 13 | t.isJSXIdentifier(node) ? 14 | t.Identifier(node.name) : 15 | t.isJSXMemberExpression(node) ? 16 | t.MemberExpression( 17 | toExpression(t, node.object), 18 | toExpression(t, node.property)) : 19 | t.isJSXExpressionContainer(node) ? 20 | node.expression : 21 | fail(`Unexpected ${node.type} in JSX element`); 22 | 23 | const toChildValue = (t, child) => 24 | t.isJSXText(child) ? t.StringLiteral(child.extra.raw) : 25 | t.isJSXExpressionContainer(child) ? child.expression : 26 | child; 27 | 28 | const JSXAttributeToObjectProperty = t => node => 29 | t.isJSXSpreadAttribute(node) ? 30 | t.SpreadElement(node.argument) : 31 | t.ObjectProperty( 32 | t.Identifier(node.name.name), 33 | toAttributeValue(t, node.value)); 34 | 35 | const toAttributeValue = (t, value) => 36 | value === null ? t.BooleanLiteral(true) : 37 | t.isStringLiteral(value) ? value : 38 | t.isJSXExpressionContainer(value) ? value.expression : 39 | fail(`Unexpected ${value.type} in JSX element`); 40 | 41 | const toBoundFunction = (t, bind, { openingElement, children }) => 42 | t.CallExpression((bind.used = true) && bind, 43 | [ 44 | toExpression(t, openingElement.name), 45 | toBoundAttributes(t, openingElement.attributes, children), 46 | openingElement.selfClosing ? 47 | t.BooleanLiteral(false) : 48 | toChildrenArray(t, children) 49 | ]); 50 | 51 | const toImportStatement = (t, as, source) => 52 | t.VariableDeclaration("const", 53 | [ 54 | t.VariableDeclarator( 55 | as, 56 | t.MemberExpression( 57 | t.CallExpression( 58 | t.Identifier("require"), 59 | [t.StringLiteral(source)]), 60 | t.Identifier("bind"))), 61 | ]); 62 | 63 | const get = (state, name) => 64 | state.get(`@generic-jsx/plugin-generic-jsx/${name}`); 65 | const set = (state, name, value) => 66 | (state.set(`@generic-jsx/plugin-generic-jsx/${name}`, value), value); 67 | 68 | module.exports = ({ types: t }) => 69 | ({ 70 | manipulateOptions: (_, parserOptions) => 71 | parserOptions.plugins.push("jsx"), 72 | 73 | visitor: 74 | { 75 | JSXElement: (path, state) => void(path 76 | .replaceWith(toBoundFunction( 77 | t, 78 | get(state, "bind-identifier"), 79 | path.node))), 80 | 81 | Program: 82 | { 83 | enter: (path, state) => void( 84 | !get(state, "bind-identifier") && 85 | path.replaceWith(t.Program( 86 | [ 87 | toImportStatement( 88 | t, 89 | set( 90 | state, 91 | "bind-identifier", 92 | path.scope.generateUidIdentifier("bind")), 93 | state.opts.importSource || "generic-jsx"), 94 | ...path.node.body 95 | ]))), 96 | 97 | exit: (path, state) => void( 98 | !get(state, "bind-identifier").used && 99 | !get(state, "bind-removed") && 100 | set(state, "bind-removed", true) && 101 | path.replaceWith(t.Program(path.node.body.slice(1)))) 102 | } 103 | } 104 | }); -------------------------------------------------------------------------------- /generic-jsx-babel-plugin/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@generic-jsx/babel-plugin", 3 | "version": "24.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@generic-jsx/babel-plugin", 9 | "version": "24.0.0", 10 | "license": "MIT", 11 | "engines": { 12 | "node": ">=4.x.x" 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /generic-jsx-babel-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@generic-jsx/babel-plugin", 3 | "version": "24.0.0", 4 | "description": "Generalized JSX supporting curried named parameters. For full explanation see http://tolmasky.com/2016/03/24/generalizing-jsx", 5 | "main": "generic-jsx-babel-plugin.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/tolmasky/generic-jsx" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Francisco Ryan Tolmasky I (https://tolmasky.com/)", 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">=4.x.x" 17 | }, 18 | "runkitExampleFilename": "runkitExample.js" 19 | } 20 | -------------------------------------------------------------------------------- /generic-jsx-examples/binary-tree.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | 4 | module.exports = function BinaryTree(value, ...[left, right]) 5 | { 6 | if (!(this instanceof BinaryTree)) 7 | return new BinaryTree(value, left, right); 8 | 9 | this.value = value; 10 | 11 | if (left) 12 | this.left = typeof left === "function" ? left() : left; 13 | 14 | if (right) 15 | this.right = typeof right === "function" ? right() : right; 16 | } 17 | -------------------------------------------------------------------------------- /generic-jsx-examples/immutable-map.js: -------------------------------------------------------------------------------- 1 | const I = require("immutable"); 2 | 3 | 4 | function Map(...entries) 5 | { 6 | return new I.Map(entries.map(child => child())); 7 | } 8 | 9 | Map.Entry = function(key, value) 10 | { 11 | return [key, value]; 12 | } 13 | 14 | module.exports = Map; 15 | -------------------------------------------------------------------------------- /generic-jsx-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@generic-jsx/examples", 3 | "version": "24.0.0", 4 | "description": "Generalized JSX supporting curried named parameters. For full explanation see http://tolmasky.com/2016/03/24/generalizing-jsx", 5 | "main": "", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/tolmasky/generic-jsx" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Francisco Ryan Tolmasky I (https://tolmasky.com/)", 14 | "license": "MIT", 15 | "dependencies": { 16 | }, 17 | "engines": { 18 | "node": ">=4.x.x" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /generic-jsx-examples/react.js: -------------------------------------------------------------------------------- 1 | const doublequote = string => `"${string.replace(/"/g, `\\"`)}"`; 2 | const CSSToString = style => doublequote(Object 3 | .entries(style) 4 | .map(([key, value]) => `${key}: ${value}`) 5 | .join("; ")); 6 | 7 | exports.CSSToString = CSSToString; 8 | 9 | const element = name => (style, ...children) => 10 | `<${name}${ style ? ` style = ${CSSToString(style)} ` : "" }>` + 11 | children.map(render).join("") + 12 | ``; 13 | 14 | exports.div = element("div"); 15 | exports.h1 = element("h1"); 16 | exports.p = element("p"); 17 | 18 | const render = element => 19 | typeof element === "string" ? 20 | element : 21 | render(element()); 22 | 23 | exports.render = render; 24 | -------------------------------------------------------------------------------- /generic-jsx-examples/reduce.js: -------------------------------------------------------------------------------- 1 | module.exports = function reduce(options) 2 | { 3 | var array = options.array; 4 | var initial = options.initial; 5 | var result = initial; 6 | var func = options.func; 7 | 8 | var index = 0; 9 | var count = array.length; 10 | 11 | for (; index < count; ++index) 12 | result = func(result, array[index]); 13 | 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /generic-jsx/generic-jsx.js: -------------------------------------------------------------------------------- 1 | const given = f => f(); 2 | 3 | const 4 | { 5 | isArrayPattern, 6 | isAssignmentPattern, 7 | isIdentifier, 8 | isObjectPattern, 9 | isObjectProperty, 10 | isRestElement 11 | } = require("@babel/types"); 12 | const { parseExpression } = require("@babel/parser"); 13 | 14 | const ArrayIsArray = Array.isArray; 15 | const ArrayMerge = (...args) => ObjectAssign([], ...args); 16 | 17 | const FunctionPrototypeToString = Function.prototype.toString; 18 | 19 | const ObjectAssign = Object.assign; 20 | const ObjectGetOwnPropertyNames = Object.getOwnPropertyNames; 21 | const ObjectFromEntries = Object.fromEntries; 22 | const ObjectHasOwn = Object.hasOwn; 23 | 24 | const ObjectMerge = (...args) => ObjectAssign({ }, ...args); 25 | const ObjectDefinePropertyValue = 26 | (object, key, value) => Object.defineProperty(object, key, { value }); 27 | 28 | const fNamed = (name, f) => ObjectDefinePropertyValue(f, "name", name); 29 | 30 | const isPrimitive = value => 31 | value === null || typeof value !== "object" && typeof value !== "function"; 32 | 33 | const fCached = f => given(( 34 | cache = new WeakMap(), 35 | set = (arguments, value) => (cache.set(arguments[0], value), value), 36 | getset = (arguments, deferred) => cache.has(arguments[0]) ? 37 | cache.get(arguments[0]) : 38 | set(arguments, deferred(...arguments))) => 39 | fNamed(`${f.name}-cached`, (...arguments) => isPrimitive(arguments[0]) ? 40 | f(arguments) : 41 | getset(arguments, f))); 42 | 43 | const BindingOfs = new WeakMap(); 44 | 45 | const FunctionGetBindingOf = f => BindingOfs.get(f) || false; 46 | const FunctionGetBaseBindingOf = (f, fPrevious = f) => 47 | f ? FunctionGetBaseBindingOf(FunctionGetBindingOf(f), f) : fPrevious; 48 | 49 | Function.getBindingOf = FunctionGetBindingOf; 50 | 51 | module.exports.getBindingOf = FunctionGetBindingOf; 52 | 53 | const fParseBindingOf = f => given(( 54 | bindingOf = FunctionGetBindingOf(f)) => 55 | bindingOf ? fParse(bindingOf) : fParseBindingOf(bindingOf)); 56 | 57 | const fParse = fCached(f => given(( 58 | fString = FunctionPrototypeToString.call(f), 59 | { type, params } = parseExpression(`(${fString})`), 60 | lastParameter = params.length > 0 && params[params.length - 1], 61 | restParameter = lastParameter && isRestElement(lastParameter) && lastParameter) => 62 | ({ 63 | stringified: fString, 64 | toBoundArguments: toToArguments(params), 65 | isArrowFunction: type === "ArrowFunctionExpression", 66 | length: restParameter ? params.length - 1 : params.length 67 | }))); 68 | 69 | const MISSING = { missing: true }; 70 | 71 | const toToArguments = node => 72 | !node ? 73 | () => void(0) : 74 | ArrayIsArray(node) ? 75 | given(( 76 | last = node.length >= 1 && node[node.length - 1], 77 | rest = last && isRestElement(last) && last, 78 | nonRest = rest ? node.slice(0, -1) : node, 79 | toRestArguments = rest ? toToArguments(rest) : () => [], 80 | toNonRestArguments = nonRest.map(toToArguments)) => 81 | named => toNonRestArguments 82 | .map(f => f(named)) 83 | .concat(toRestArguments(named, []))) : 84 | isArrayPattern(node) ? 85 | toToArguments(node.elements) : 86 | isObjectPattern(node) ? 87 | given((toArguments = toToArguments(node.properties)) => 88 | named => ObjectAssign({}, ...toArguments(named))) : 89 | isObjectProperty(node) ? 90 | given(( 91 | { key, value } = node, 92 | computedKey = isIdentifier(key) ? key.name : key.value, 93 | toArguments = toToArguments(node.value)) => 94 | named => given((value = toArguments(named, MISSING)) => 95 | value !== MISSING && ({ [computedKey]: value }))) : 96 | isIdentifier(node) ? 97 | given(({ name } = node) => 98 | (named, fallback) => 99 | ObjectHasOwn(named, name) ? named[name] : fallback) : 100 | isAssignmentPattern(node) ? 101 | toToArguments(node.left) : 102 | isRestElement(node) ? 103 | toToArguments(node.argument) : 104 | () => void(0); 105 | 106 | const RestEntries = Symbol("RestEntries"); 107 | 108 | function bind(f, attributes, children) 109 | { 110 | if (children.length === 0 && 111 | ObjectGetOwnPropertyNames(attributes).length === 0) 112 | return f; 113 | 114 | const baseBindingOf = FunctionGetBaseBindingOf(f); 115 | const 116 | { 117 | stringified, 118 | toBoundArguments, 119 | isArrowFunction, 120 | length 121 | } = fParse(baseBindingOf); 122 | 123 | const mergedAttributes = ObjectMerge( 124 | f.attributes, 125 | attributes, 126 | children && 127 | { 128 | [RestEntries]: ObjectFromEntries(children 129 | .map((value, index) => [index + length, value])) 130 | }); 131 | 132 | const toArguments = callArguments => ArrayMerge( 133 | toBoundArguments(mergedAttributes), 134 | mergedAttributes[RestEntries], 135 | callArguments); 136 | 137 | const fBound = isArrowFunction ? 138 | (...arguments) => baseBindingOf(...toArguments(arguments)) : 139 | function (...arguments) 140 | { 141 | return baseBindingOf.apply(this, toArguments(arguments)); 142 | }; 143 | 144 | BindingOfs.set(fBound, f); 145 | 146 | return ObjectAssign(fNamed(baseBindingOf.name, fBound), 147 | { 148 | attributes: mergedAttributes, 149 | toString() { return stringified; } 150 | }); 151 | } 152 | 153 | module.exports.bind = bind; 154 | 155 | module.exports.JSXPragma = function JSXPragma(evalInScope) 156 | { 157 | return function JSXPragma(f, attributes, ...children) 158 | { 159 | return bind( 160 | typeof f === "string" ? evalInScope(f) : f, 161 | attributes, 162 | children); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /generic-jsx/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generic-jsx", 3 | "version": "24.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "generic-jsx", 9 | "version": "24.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@babel/parser": "^7.18.11", 13 | "@babel/types": "^7.18.10" 14 | }, 15 | "engines": { 16 | "node": ">=4.x.x" 17 | } 18 | }, 19 | "node_modules/@babel/helper-string-parser": { 20 | "version": "7.18.10", 21 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", 22 | "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", 23 | "engines": { 24 | "node": ">=6.9.0" 25 | } 26 | }, 27 | "node_modules/@babel/helper-validator-identifier": { 28 | "version": "7.18.6", 29 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", 30 | "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", 31 | "engines": { 32 | "node": ">=6.9.0" 33 | } 34 | }, 35 | "node_modules/@babel/parser": { 36 | "version": "7.18.11", 37 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", 38 | "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==", 39 | "bin": { 40 | "parser": "bin/babel-parser.js" 41 | }, 42 | "engines": { 43 | "node": ">=6.0.0" 44 | } 45 | }, 46 | "node_modules/@babel/types": { 47 | "version": "7.18.10", 48 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", 49 | "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", 50 | "dependencies": { 51 | "@babel/helper-string-parser": "^7.18.10", 52 | "@babel/helper-validator-identifier": "^7.18.6", 53 | "to-fast-properties": "^2.0.0" 54 | }, 55 | "engines": { 56 | "node": ">=6.9.0" 57 | } 58 | }, 59 | "node_modules/to-fast-properties": { 60 | "version": "2.0.0", 61 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 62 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 63 | "engines": { 64 | "node": ">=4" 65 | } 66 | } 67 | }, 68 | "dependencies": { 69 | "@babel/helper-string-parser": { 70 | "version": "7.18.10", 71 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", 72 | "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" 73 | }, 74 | "@babel/helper-validator-identifier": { 75 | "version": "7.18.6", 76 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", 77 | "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" 78 | }, 79 | "@babel/parser": { 80 | "version": "7.18.11", 81 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", 82 | "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==" 83 | }, 84 | "@babel/types": { 85 | "version": "7.18.10", 86 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", 87 | "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", 88 | "requires": { 89 | "@babel/helper-string-parser": "^7.18.10", 90 | "@babel/helper-validator-identifier": "^7.18.6", 91 | "to-fast-properties": "^2.0.0" 92 | } 93 | }, 94 | "to-fast-properties": { 95 | "version": "2.0.0", 96 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 97 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /generic-jsx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generic-jsx", 3 | "version": "24.0.0", 4 | "description": "Generalized JSX supporting curried named parameters. For full explanation see http://tolmasky.com/2016/03/24/generalizing-jsx", 5 | "main": "./generic-jsx", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/tolmasky/generic-jsx" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Francisco Ryan Tolmasky I (https://tolmasky.com/)", 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">=4.x.x" 17 | }, 18 | "runkitExampleFilename": "runkitExample.js", 19 | "dependencies": { 20 | "@babel/parser": "^7.18.11", 21 | "@babel/types": "^7.18.10" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /generic-jsx/runkitExample.js: -------------------------------------------------------------------------------- 1 | /* @jsx (JSXPragma(_=>eval(_))) */ 2 | 3 | const { JSXPragma } = require("generic-jsx"); 4 | const BinaryTree = require("@generic-jsx/examples/binary-tree"); 5 | 6 | // BinaryTree is an ES6 class that we can curry using JSX: 7 | const Division = ; 8 | const Addition = ; 9 | const Number = BinaryTree; 10 | 11 | 12 | 13 | { Number(5) } 14 | 15 | { Number(4) } 16 | { Number(6) } 17 | 18 | () 19 | --------------------------------------------------------------------------------