├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── LICENSE ├── README.md ├── bun.lockb ├── examples ├── components.tsx └── serve.ts ├── hjsx.ts ├── package.json ├── publish.ts ├── tsconfig.json ├── types.d.ts └── util ├── index.test.ts ├── index.ts ├── normalize-attribute-name.ts └── rm-comments.ts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [trvswgnr] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | hjsx.js 4 | 5 | # Logs 6 | 7 | logs 8 | _.log 9 | npm-debug.log_ 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | .pnpm-debug.log* 14 | 15 | # Caches 16 | 17 | .cache 18 | 19 | # Diagnostic reports (https://nodejs.org/api/report.html) 20 | 21 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 22 | 23 | # Runtime data 24 | 25 | pids 26 | _.pid 27 | _.seed 28 | *.pid.lock 29 | 30 | # Directory for instrumented libs generated by jscoverage/JSCover 31 | 32 | lib-cov 33 | 34 | # Coverage directory used by tools like istanbul 35 | 36 | coverage 37 | *.lcov 38 | 39 | # nyc test coverage 40 | 41 | .nyc_output 42 | 43 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 44 | 45 | .grunt 46 | 47 | # Bower dependency directory (https://bower.io/) 48 | 49 | bower_components 50 | 51 | # node-waf configuration 52 | 53 | .lock-wscript 54 | 55 | # Compiled binary addons (https://nodejs.org/api/addons.html) 56 | 57 | build/Release 58 | 59 | # Dependency directories 60 | 61 | node_modules/ 62 | jspm_packages/ 63 | 64 | # Snowpack dependency directory (https://snowpack.dev/) 65 | 66 | web_modules/ 67 | 68 | # TypeScript cache 69 | 70 | *.tsbuildinfo 71 | 72 | # Optional npm cache directory 73 | 74 | .npm 75 | 76 | # Optional eslint cache 77 | 78 | .eslintcache 79 | 80 | # Optional stylelint cache 81 | 82 | .stylelintcache 83 | 84 | # Microbundle cache 85 | 86 | .rpt2_cache/ 87 | .rts2_cache_cjs/ 88 | .rts2_cache_es/ 89 | .rts2_cache_umd/ 90 | 91 | # Optional REPL history 92 | 93 | .node_repl_history 94 | 95 | # Output of 'npm pack' 96 | 97 | *.tgz 98 | 99 | # Yarn Integrity file 100 | 101 | .yarn-integrity 102 | 103 | # dotenv environment variable files 104 | 105 | .env 106 | .env.development.local 107 | .env.test.local 108 | .env.production.local 109 | .env.local 110 | 111 | # parcel-bundler cache (https://parceljs.org/) 112 | 113 | .parcel-cache 114 | 115 | # Next.js build output 116 | 117 | .next 118 | out 119 | 120 | # Nuxt.js build / generate output 121 | 122 | .nuxt 123 | dist 124 | 125 | # Gatsby files 126 | 127 | # Comment in the public line in if your project uses Gatsby and not Next.js 128 | 129 | # https://nextjs.org/blog/next-9-1#public-directory-support 130 | 131 | # public 132 | 133 | # vuepress build output 134 | 135 | .vuepress/dist 136 | 137 | # vuepress v2.x temp and cache directory 138 | 139 | .temp 140 | 141 | # Docusaurus cache and generated files 142 | 143 | .docusaurus 144 | 145 | # Serverless directories 146 | 147 | .serverless/ 148 | 149 | # FuseBox cache 150 | 151 | .fusebox/ 152 | 153 | # DynamoDB Local files 154 | 155 | .dynamodb/ 156 | 157 | # TernJS port file 158 | 159 | .tern-port 160 | 161 | # Stores VSCode versions used for testing VSCode extensions 162 | 163 | .vscode-test 164 | 165 | # yarn v2 166 | 167 | .yarn/cache 168 | .yarn/unplugged 169 | .yarn/build-state.yml 170 | .yarn/install-state.gz 171 | .pnp.* 172 | 173 | # IntelliJ based IDEs 174 | .idea 175 | 176 | # Finder (MacOS) folder config 177 | .DS_Store 178 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "tabWidth": 4, 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Travis Aaron Wagner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hjsx 2 | 3 | ![npm](https://img.shields.io/npm/v/hjsx?style=for-the-badge) 4 | ![tests](https://img.shields.io/badge/tests-passing-green?style=for-the-badge) 5 | 6 | > [!WARNING] 7 | > This project is still in early development and is not ready for use. 8 | 9 | JSX is great for templating, but pulling in React can be overkill, and even when just using the types it can be confusing. **hjsx** (Hypertext + JavaScript Extensible Markup Language) aims to provide a simple way to use JSX on the server by rendering it to HTML. 10 | 11 | It includes modified types for the JSX elements, with all event handlers removed, and a `render` method that returns a string. 12 | 13 | It _is_ currently available on [`npm`](https://www.npmjs.com/package/hjsx), but I wouldn't recommend using it yet. 14 | 15 | ## Usage 16 | 17 | First, install the package: 18 | 19 | ```bash 20 | bun i hjsx 21 | ``` 22 | 23 | Then you'll need to update your tsconfig.json to use the `react-jsx` compiler option, and set the `jsxFactory` and `jsxFragmentFactory` options to `hjsx` and `hjsx.fragment` respectively: 24 | 25 | ```json 26 | { 27 | "compilerOptions": { 28 | "jsx": "react-jsx", 29 | "jsxFactory": "hjsx", 30 | "jsxFragmentFactory": "hjsx.fragment" 31 | } 32 | } 33 | ``` 34 | 35 | Now you can use JSX: 36 | 37 | ```tsx 38 | import { type hjsx } from "hjsx"; 39 | type MyComponentProps = hjsx.Attributes & {}; 40 | export function MyComponent(props: MyComponentProps) { 41 | return ( 42 | <> 43 |
44 |

c00l b34nz

45 |
46 | 47 | ); 48 | } 49 | ``` 50 | 51 | Check out the demo: 52 | 53 | ```bash 54 | bun install 55 | bun run examples/serve.ts 56 | ``` 57 | 58 | ## Contributing 59 | 60 | Contributions are welcome! Please help me. This is a cry for help. 61 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trvswgnr/hjsx/bb910e66e0d2c6e990abcda68b85e2c7f0799d75/bun.lockb -------------------------------------------------------------------------------- /examples/components.tsx: -------------------------------------------------------------------------------- 1 | import "../hjsx"; 2 | 3 | type Props = hjsx.PropsWithChildren 4 | 5 | export function Button({ children, ...props }: Props) { 6 | return ( 7 | <> 8 | 9 | 10 | ); 11 | } 12 | 13 | export const Page = ( 14 |
15 | 16 |
17 | ); 18 | -------------------------------------------------------------------------------- /examples/serve.ts: -------------------------------------------------------------------------------- 1 | import { Page } from "./components"; 2 | 3 | const server = Bun.serve({ 4 | port: 3000, 5 | async fetch(req) { 6 | const body = Page.render(); 7 | return new Response(body, { 8 | headers: { 9 | "content-type": "text/html; charset=utf-8", 10 | }, 11 | }); 12 | } 13 | }); 14 | 15 | console.log(`Listening on ${server.url}`); 16 | -------------------------------------------------------------------------------- /hjsx.ts: -------------------------------------------------------------------------------- 1 | import * as u from "./util"; 2 | 3 | export function hjsx( 4 | type: hjsx.Element["type"], 5 | props?: Record, 6 | children?: hjsx.Node, 7 | ) { 8 | return { 9 | type, 10 | props, 11 | children, 12 | render() { 13 | return renderToString(this); 14 | }, 15 | $$typeof: Symbol.for("hjsx.element"), 16 | key: null, 17 | ref: null, 18 | _owner: null, 19 | }; 20 | } 21 | 22 | export function fragment({ children }: hjsx.RenderProps) { 23 | return children; 24 | } 25 | 26 | export const renderToString = (component?: unknown): string => { 27 | if (u.isPrimitive(component)) return u.escapeHtml(String(component)); 28 | if (u.isNullish(component)) return ""; 29 | if (u.isIterable(component)) return renderChildren({ children: component }); 30 | if (!u.isObject(component)) return ""; 31 | if (!("children" in component)) return renderChildren({ children: component }); 32 | validateElement(component); 33 | 34 | let { type, props, children } = component; 35 | props = props ?? {}; 36 | if (typeof type === "function") { 37 | const componentInstance = u.isClassConstructor(type) 38 | ? new type({ ...props, children }) 39 | : type({ ...props, children }); 40 | return renderToString(componentInstance); 41 | } 42 | 43 | const innerHTML = props.dangerouslySetInnerHTML 44 | ? u.dangerouslySetInnerHTML(props.dangerouslySetInnerHTML) 45 | : null; 46 | const propsString = Object.entries(props) 47 | .filter( 48 | ([key, value]) => 49 | key !== "u.dangerouslySetInnerHTML" && value !== false && value != null, 50 | ) 51 | .map(([key, value]) => { 52 | const normalizedKey = u.normalizeAttributeName(key); 53 | const normalizedValue = u.escapeHtml( 54 | String(key === "style" ? u.handleStyle(value) : value), 55 | ); 56 | return value === true ? normalizedKey : `${normalizedKey}="${normalizedValue}"`; 57 | }) 58 | .join(" "); 59 | 60 | const childrenString = innerHTML ?? renderChildren({ children }); 61 | 62 | if (typeof type !== "string") { 63 | return renderToString({ type, props, children }); 64 | } 65 | 66 | return u.SELF_CLOSING_TAGS.includes(type) 67 | ? `<${type} ${propsString} />` 68 | : `<${type} ${propsString}>${childrenString}`; 69 | }; 70 | 71 | const renderChildren = (args: unknown): string => { 72 | if (u.isNullish(args)) return ""; 73 | if (u.isPrimitive(args)) return u.escapeHtml(String(args)); 74 | if (!u.isObject(args)) return ""; 75 | const { children } = args; 76 | const childrenArray = Array.isArray(children) ? children : [children]; 77 | return childrenArray 78 | .filter((child) => !u.isNullish(child)) 79 | .map(renderToString) 80 | .join(""); 81 | }; 82 | 83 | function validateElement( 84 | element: unknown, 85 | ): asserts element is hjsx.PropsWithChildren { 86 | if (!u.isObject(element)) { 87 | throw new Error("Element must be an object"); 88 | } 89 | if (!("type" in element)) { 90 | throw new Error("Element must have a type"); 91 | } 92 | if (!("props" in element)) { 93 | throw new Error("Element must have props"); 94 | } 95 | } 96 | 97 | // set globals 98 | globalThis.hjsx = Object.assign(hjsx, { fragment }); 99 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hjsx", 3 | "version": "0.1.19", 4 | "module": "hjsx.ts", 5 | "main": "hjsx.js", 6 | "type": "module", 7 | "types": "types.d.ts", 8 | "scripts": { 9 | "build": "bun build hjsx.ts --outfile hjsx.js --target node --minify" 10 | }, 11 | "devDependencies": { 12 | "@types/bun": "latest" 13 | }, 14 | "peerDependencies": { 15 | "typescript": "^5.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /publish.ts: -------------------------------------------------------------------------------- 1 | import { colors } from "./util"; 2 | import { parseArgs } from "node:util"; 3 | 4 | const { config, quietSpawnOptions } = getConfig(); 5 | await main(); 6 | 7 | /** 8 | * this script is used to do the following: 9 | * 10 | * 1. build the project 11 | * 2. update the version in package.json 12 | * 3. run tests 13 | * 4. update the tests badge in README.md 14 | * 5. commit and push changes to github 15 | * 6. publish to npm 16 | * 17 | * ## usage: 18 | * 19 | * patch version: 20 | * ```sh 21 | * bun publish.ts --patch 22 | * # or 23 | * bun publish.ts -p 24 | * ``` 25 | * 26 | * minor version: 27 | * ```sh 28 | * bun publish.ts --minor 29 | * # or 30 | * bun publish.ts -m 31 | * ``` 32 | * 33 | * major version: 34 | * ```sh 35 | * # major version 36 | * bun publish.ts --major 37 | * # or 38 | * bun publish.ts -M 39 | *``` 40 | * 41 | * no version change (still runs tests and pushes to github): 42 | * ```sh 43 | * bun publish.ts # no args 44 | * ``` 45 | */ 46 | async function main() { 47 | const promiseResults = await Promise.all([build(), updatePkgVersion(), runTests()]); 48 | const [buildSuccessful, [oldVersion, newVersion], testsPassed] = promiseResults; 49 | const readmeUpdated = await updateReadmeTestsBadge(testsPassed); 50 | const changedFiles = await getChangedFiles(); 51 | await commitAndPush(changedFiles); 52 | await publish(oldVersion, newVersion); 53 | } 54 | 55 | async function getChangedFiles(): Promise { 56 | console.log("getting changed files..."); 57 | const process = Bun.spawn(["git", "diff", "--name-only"], quietSpawnOptions); 58 | const stdout = await Bun.readableStreamToText(process.stdout); 59 | const changed = stdout.split("\n").filter(Boolean); 60 | if (changed.length) { 61 | console.log("changed files:"); 62 | changed.forEach((file) => console.log(`- ${file}`)); 63 | } 64 | return changed; 65 | } 66 | 67 | async function build(): Promise { 68 | console.log("building..."); 69 | const { exited } = Bun.spawn(["bun", "run", "build"], quietSpawnOptions); 70 | const exitCode = await exited; 71 | const success = exitCode === 0; 72 | const message = success ? colors.green("build successful!") : colors.red("build failed!"); 73 | console.log(message); 74 | return success; 75 | } 76 | 77 | async function publish(oldVersion: SemVer, newVersion: SemVer) { 78 | if (oldVersion === newVersion) { 79 | console.log( 80 | `${colors.yellow("not publishing to npm")} ${colors.gray( 81 | `(v${newVersion} is the same as npm)`, 82 | )}`, 83 | ); 84 | return; 85 | } 86 | console.log("publishing to npm..."); 87 | const process = Bun.spawn(["npm", "publish"], quietSpawnOptions); 88 | const exitCode = await process.exited; 89 | if (exitCode !== 0) { 90 | const stderr = await Bun.readableStreamToText(process.stderr); 91 | throw new Error(`npm publish failed: ${stderr}`); 92 | } 93 | console.log( 94 | `${colors.green("published to npm!")} 🎉 ${colors.gray(oldVersion)} → ${colors.gray( 95 | newVersion, 96 | )}`, 97 | ); 98 | } 99 | 100 | async function commitAndPush(changedFiles: string[]): Promise { 101 | if (!changedFiles.length) { 102 | console.log("no changes to commit"); 103 | return; 104 | } 105 | console.log("committing and pushing..."); 106 | let process = Bun.spawn(["git", "add", "."], quietSpawnOptions); 107 | let exitCode = await process.exited; 108 | if (exitCode !== 0) { 109 | const stderr = await Bun.readableStreamToText(process.stderr); 110 | throw new Error(`git add failed: ${stderr}`); 111 | } 112 | process = Bun.spawn(["git", "commit", "-m", "'updated, tested'"], quietSpawnOptions); 113 | exitCode = await process.exited; 114 | if (exitCode !== 0) { 115 | const stderr = await Bun.readableStreamToText(process.stderr); 116 | throw new Error(`git commit failed: ${stderr}`); 117 | } 118 | process = Bun.spawn(["git", "push"], quietSpawnOptions); 119 | exitCode = await process.exited; 120 | if (exitCode !== 0) { 121 | const stderr = await Bun.readableStreamToText(process.stderr); 122 | throw new Error(`git push failed: ${stderr}`); 123 | } 124 | console.log("committed and pushed to github"); 125 | } 126 | 127 | async function updatePkgVersion(): Promise<[SemVer, SemVer]> { 128 | console.log("updating version..."); 129 | const parsed = parseArgs(config); 130 | const file = Bun.file("package.json"); 131 | const pkg = await file.json(); 132 | const version = pkg.version; 133 | const newVersion = getNewVersion(version, parsed.values); 134 | pkg.version = newVersion; 135 | const writer = file.writer(); 136 | writer.write(JSON.stringify(pkg, null, 4)); 137 | await writer.end(); 138 | if (version === newVersion) { 139 | console.log("package version is already up to date"); 140 | return [version, newVersion]; 141 | } 142 | console.log( 143 | `${colors.green("updated version")} ${colors.gray(version)} → ${colors.gray(newVersion)}`, 144 | ); 145 | return [version, newVersion]; 146 | } 147 | 148 | function getNewVersion(version: SemVer, args: ParsedArgs["values"]): SemVer { 149 | const [major, minor, patch] = version.split(".").map(Number); 150 | if (args.major) return `${major + 1}.0.0`; 151 | if (args.minor) return `${major}.${minor + 1}.0`; 152 | if (args.patch) return `${major}.${minor}.${patch + 1}`; 153 | return version; 154 | } 155 | 156 | async function runTests(): Promise { 157 | console.log("running tests..."); 158 | const process = Bun.spawn("bun test".split(" "), quietSpawnOptions); 159 | const exitCode = await process.exited; 160 | const passed = exitCode === 0; 161 | let message = passed ? colors.green("tests passed!") : colors.red("tests failed!"); 162 | console.log(message); 163 | return passed; 164 | } 165 | 166 | async function updateReadmeTestsBadge(testsPassed: boolean): Promise { 167 | const color = testsPassed ? "green" : "red"; 168 | const text = testsPassed ? "passing" : "failing"; 169 | console.log("updating README.md tests badge..."); 170 | const link = `![tests](https://img.shields.io/badge/tests-${text}-${color}?style=for-the-badge)`; 171 | const file = Bun.file("README.md"); 172 | const contents = await file.text(); 173 | const updated = contents.replace(/!\[tests\].+/, link); 174 | if (contents === updated) { 175 | console.log("README.md tests badge is already up to date"); 176 | return false; 177 | } 178 | const writer = file.writer(); 179 | writer.write(updated); 180 | await writer.end(); 181 | return true; 182 | } 183 | function getConfig() { 184 | const options = { 185 | patch: { 186 | type: "boolean", 187 | short: "p", 188 | }, 189 | minor: { 190 | type: "boolean", 191 | short: "m", 192 | }, 193 | major: { 194 | type: "boolean", 195 | short: "M", 196 | }, 197 | } as const; 198 | const args = process.argv.slice(2); 199 | const config = { args, options }; 200 | const quietSpawnOptions = { 201 | stdout: "pipe", 202 | stderr: "pipe", 203 | } as const; 204 | return { config, quietSpawnOptions }; 205 | } 206 | 207 | type Package = { 208 | name: string; 209 | version: SemVer; 210 | module: string; 211 | main: string; 212 | type: string; 213 | types: string; 214 | scripts: JsonRecord; 215 | devDependencies: JsonRecord; 216 | peerDependencies: JsonRecord; 217 | }; 218 | 219 | type SemVer = `${number}.${number}.${number}`; 220 | type JsonRecord = Record; 221 | type ParsedArgs = ReturnType>; 222 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "moduleDetection": "force", 7 | "jsx": "react", 8 | "jsxFactory": "hjsx", 9 | "jsxFragmentFactory": "hjsx.fragment", 10 | "allowJs": true, 11 | 12 | /* Bundler mode */ 13 | "moduleResolution": "bundler", 14 | "allowImportingTsExtensions": true, 15 | "verbatimModuleSyntax": true, 16 | "noEmit": true, 17 | 18 | /* Linting */ 19 | "skipLibCheck": false, 20 | "strict": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "forceConsistentCasingInFileNames": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | declare function fragment(props: hjsx.RenderProps): hjsx.Node; 2 | declare global { 3 | export type hjsx = typeof hjsx & { 4 | fragment: typeof fragment; 5 | }; 6 | export function hjsx( 7 | type: hjsx.Element["type"], 8 | props?: hjsx.Element["props"], 9 | children?: hjsx.Node, 10 | ): hjsx.Element; 11 | export namespace hjsx { 12 | type RenderProps = { 13 | type: hjsx.Element["type"]; 14 | props?: hjsx.Element["props"]; 15 | children?: hjsx.Node; 16 | }; 17 | type FunctionComponent

= ( 18 | props?: P & { children?: Node }, 19 | ) => Node & { render: () => string }; 20 | type PropsWithChildren

= P & { children?: Node | undefined }; 21 | interface SVGLineElementAttributes extends SVGProps {} 22 | interface SVGTextElementAttributes extends SVGProps {} 23 | interface SVGProps extends SVGAttributes, ClassAttributes {} 24 | type CrossOrigin = "anonymous" | "use-credentials" | "" | undefined; 25 | interface AllHTMLAttributes extends HTMLAttributes { 26 | accept?: string | undefined; 27 | acceptCharset?: string | undefined; 28 | action?: string | undefined; 29 | allowFullScreen?: boolean | undefined; 30 | allowTransparency?: boolean | undefined; 31 | alt?: string | undefined; 32 | as?: string | undefined; 33 | async?: boolean | undefined; 34 | autoComplete?: string | undefined; 35 | autoPlay?: boolean | undefined; 36 | capture?: boolean | "user" | "environment" | undefined; 37 | cellPadding?: number | string | undefined; 38 | cellSpacing?: number | string | undefined; 39 | charSet?: string | undefined; 40 | challenge?: string | undefined; 41 | checked?: boolean | undefined; 42 | cite?: string | undefined; 43 | classID?: string | undefined; 44 | cols?: number | undefined; 45 | colSpan?: number | undefined; 46 | controls?: boolean | undefined; 47 | coords?: string | undefined; 48 | crossOrigin?: CrossOrigin; 49 | data?: string | undefined; 50 | dateTime?: string | undefined; 51 | default?: boolean | undefined; 52 | defer?: boolean | undefined; 53 | disabled?: boolean | undefined; 54 | download?: any; 55 | encType?: string | undefined; 56 | form?: string | undefined; 57 | formAction?: string | undefined; 58 | formEncType?: string | undefined; 59 | formMethod?: string | undefined; 60 | formNoValidate?: boolean | undefined; 61 | formTarget?: string | undefined; 62 | frameBorder?: number | string | undefined; 63 | headers?: string | undefined; 64 | height?: number | string | undefined; 65 | high?: number | undefined; 66 | href?: string | undefined; 67 | hrefLang?: string | undefined; 68 | htmlFor?: string | undefined; 69 | httpEquiv?: string | undefined; 70 | integrity?: string | undefined; 71 | keyParams?: string | undefined; 72 | keyType?: string | undefined; 73 | kind?: string | undefined; 74 | label?: string | undefined; 75 | list?: string | undefined; 76 | loop?: boolean | undefined; 77 | low?: number | undefined; 78 | manifest?: string | undefined; 79 | marginHeight?: number | undefined; 80 | marginWidth?: number | undefined; 81 | max?: number | string | undefined; 82 | maxLength?: number | undefined; 83 | media?: string | undefined; 84 | mediaGroup?: string | undefined; 85 | method?: string | undefined; 86 | min?: number | string | undefined; 87 | minLength?: number | undefined; 88 | multiple?: boolean | undefined; 89 | muted?: boolean | undefined; 90 | name?: string | undefined; 91 | noValidate?: boolean | undefined; 92 | open?: boolean | undefined; 93 | optimum?: number | undefined; 94 | pattern?: string | undefined; 95 | placeholder?: string | undefined; 96 | playsInline?: boolean | undefined; 97 | poster?: string | undefined; 98 | preload?: string | undefined; 99 | readOnly?: boolean | undefined; 100 | required?: boolean | undefined; 101 | reversed?: boolean | undefined; 102 | rows?: number | undefined; 103 | rowSpan?: number | undefined; 104 | sandbox?: string | undefined; 105 | scope?: string | undefined; 106 | scoped?: boolean | undefined; 107 | scrolling?: string | undefined; 108 | seamless?: boolean | undefined; 109 | selected?: boolean | undefined; 110 | shape?: string | undefined; 111 | size?: number | undefined; 112 | sizes?: string | undefined; 113 | span?: number | undefined; 114 | src?: string | undefined; 115 | srcDoc?: string | undefined; 116 | srcLang?: string | undefined; 117 | srcSet?: string | undefined; 118 | start?: number | undefined; 119 | step?: number | string | undefined; 120 | summary?: string | undefined; 121 | target?: string | undefined; 122 | type?: string | undefined; 123 | useMap?: string | undefined; 124 | value?: string | readonly string[] | number | undefined; 125 | width?: number | string | undefined; 126 | wmode?: string | undefined; 127 | wrap?: string | undefined; 128 | } 129 | type HTMLAttributeReferrerPolicy = 130 | | "" 131 | | "no-referrer" 132 | | "no-referrer-when-downgrade" 133 | | "origin" 134 | | "origin-when-cross-origin" 135 | | "same-origin" 136 | | "strict-origin" 137 | | "strict-origin-when-cross-origin" 138 | | "unsafe-url"; 139 | type HTMLAttributeAnchorTarget = "_self" | "_blank" | "_parent" | "_top" | (string & {}); 140 | interface AnchorHTMLAttributes extends HTMLAttributes { 141 | download?: any; 142 | href?: string | undefined; 143 | hrefLang?: string | undefined; 144 | media?: string | undefined; 145 | ping?: string | undefined; 146 | target?: HTMLAttributeAnchorTarget | undefined; 147 | type?: string | undefined; 148 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 149 | } 150 | interface AudioHTMLAttributes extends MediaHTMLAttributes {} 151 | interface AreaHTMLAttributes extends HTMLAttributes { 152 | alt?: string | undefined; 153 | coords?: string | undefined; 154 | download?: any; 155 | href?: string | undefined; 156 | hrefLang?: string | undefined; 157 | media?: string | undefined; 158 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 159 | shape?: string | undefined; 160 | target?: string | undefined; 161 | } 162 | interface BaseHTMLAttributes extends HTMLAttributes { 163 | href?: string | undefined; 164 | target?: string | undefined; 165 | } 166 | interface BlockquoteHTMLAttributes extends HTMLAttributes { 167 | cite?: string | undefined; 168 | } 169 | interface ButtonHTMLAttributes extends HTMLAttributes { 170 | disabled?: boolean | undefined; 171 | form?: string | undefined; 172 | formAction?: string | undefined; 173 | formEncType?: string | undefined; 174 | formMethod?: string | undefined; 175 | formNoValidate?: boolean | undefined; 176 | formTarget?: string | undefined; 177 | name?: string | undefined; 178 | type?: "submit" | "reset" | "button" | undefined; 179 | value?: string | readonly string[] | number | undefined; 180 | } 181 | interface CanvasHTMLAttributes extends HTMLAttributes { 182 | height?: number | string | undefined; 183 | width?: number | string | undefined; 184 | } 185 | interface ColHTMLAttributes extends HTMLAttributes { 186 | span?: number | undefined; 187 | width?: number | string | undefined; 188 | } 189 | interface ColgroupHTMLAttributes extends HTMLAttributes { 190 | span?: number | undefined; 191 | } 192 | interface DataHTMLAttributes extends HTMLAttributes { 193 | value?: string | readonly string[] | number | undefined; 194 | } 195 | interface DetailsHTMLAttributes extends HTMLAttributes { 196 | open?: boolean | undefined; 197 | name?: string | undefined; 198 | } 199 | interface DelHTMLAttributes extends HTMLAttributes { 200 | cite?: string | undefined; 201 | dateTime?: string | undefined; 202 | } 203 | interface DialogHTMLAttributes extends HTMLAttributes { 204 | open?: boolean | undefined; 205 | } 206 | interface EmbedHTMLAttributes extends HTMLAttributes { 207 | height?: number | string | undefined; 208 | src?: string | undefined; 209 | type?: string | undefined; 210 | width?: number | string | undefined; 211 | } 212 | interface FieldsetHTMLAttributes extends HTMLAttributes { 213 | disabled?: boolean | undefined; 214 | form?: string | undefined; 215 | name?: string | undefined; 216 | } 217 | interface FormHTMLAttributes extends HTMLAttributes { 218 | acceptCharset?: string | undefined; 219 | action?: string | undefined; 220 | autoComplete?: string | undefined; 221 | encType?: string | undefined; 222 | method?: string | undefined; 223 | name?: string | undefined; 224 | noValidate?: boolean | undefined; 225 | target?: string | undefined; 226 | } 227 | interface HtmlHTMLAttributes extends HTMLAttributes { 228 | manifest?: string | undefined; 229 | } 230 | interface IframeHTMLAttributes extends HTMLAttributes { 231 | allow?: string | undefined; 232 | allowFullScreen?: boolean | undefined; 233 | allowTransparency?: boolean | undefined; 234 | frameBorder?: number | string | undefined; 235 | height?: number | string | undefined; 236 | loading?: "eager" | "lazy" | undefined; 237 | marginHeight?: number | undefined; 238 | marginWidth?: number | undefined; 239 | name?: string | undefined; 240 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 241 | sandbox?: string | undefined; 242 | scrolling?: string | undefined; 243 | seamless?: boolean | undefined; 244 | src?: string | undefined; 245 | srcDoc?: string | undefined; 246 | width?: number | string | undefined; 247 | } 248 | interface ImgHTMLAttributes extends HTMLAttributes { 249 | alt?: string | undefined; 250 | crossOrigin?: CrossOrigin; 251 | decoding?: "async" | "auto" | "sync" | undefined; 252 | height?: number | string | undefined; 253 | loading?: "eager" | "lazy" | undefined; 254 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 255 | sizes?: string | undefined; 256 | src?: string | undefined; 257 | srcSet?: string | undefined; 258 | useMap?: string | undefined; 259 | width?: number | string | undefined; 260 | } 261 | interface InsHTMLAttributes extends HTMLAttributes { 262 | cite?: string | undefined; 263 | dateTime?: string | undefined; 264 | } 265 | type HTMLInputTypeAttribute = 266 | | "button" 267 | | "checkbox" 268 | | "color" 269 | | "date" 270 | | "datetime-local" 271 | | "email" 272 | | "file" 273 | | "hidden" 274 | | "image" 275 | | "month" 276 | | "number" 277 | | "password" 278 | | "radio" 279 | | "range" 280 | | "reset" 281 | | "search" 282 | | "submit" 283 | | "tel" 284 | | "text" 285 | | "time" 286 | | "url" 287 | | "week" 288 | | (string & {}); 289 | interface InputHTMLAttributes extends HTMLAttributes { 290 | accept?: string | undefined; 291 | alt?: string | undefined; 292 | autoComplete?: string | undefined; 293 | capture?: boolean | "user" | "environment" | undefined; 294 | checked?: boolean | undefined; 295 | disabled?: boolean | undefined; 296 | enterKeyHint?: 297 | | "enter" 298 | | "done" 299 | | "go" 300 | | "next" 301 | | "previous" 302 | | "search" 303 | | "send" 304 | | undefined; 305 | form?: string | undefined; 306 | formAction?: string | undefined; 307 | formEncType?: string | undefined; 308 | formMethod?: string | undefined; 309 | formNoValidate?: boolean | undefined; 310 | formTarget?: string | undefined; 311 | height?: number | string | undefined; 312 | list?: string | undefined; 313 | max?: number | string | undefined; 314 | maxLength?: number | undefined; 315 | min?: number | string | undefined; 316 | minLength?: number | undefined; 317 | multiple?: boolean | undefined; 318 | name?: string | undefined; 319 | pattern?: string | undefined; 320 | placeholder?: string | undefined; 321 | readOnly?: boolean | undefined; 322 | required?: boolean | undefined; 323 | size?: number | undefined; 324 | src?: string | undefined; 325 | step?: number | string | undefined; 326 | type?: HTMLInputTypeAttribute | undefined; 327 | value?: string | readonly string[] | number | undefined; 328 | width?: number | string | undefined; 329 | } 330 | interface KeygenHTMLAttributes extends HTMLAttributes { 331 | challenge?: string | undefined; 332 | disabled?: boolean | undefined; 333 | form?: string | undefined; 334 | keyType?: string | undefined; 335 | keyParams?: string | undefined; 336 | name?: string | undefined; 337 | } 338 | interface LabelHTMLAttributes extends HTMLAttributes { 339 | form?: string | undefined; 340 | htmlFor?: string | undefined; 341 | } 342 | interface LiHTMLAttributes extends HTMLAttributes { 343 | value?: string | readonly string[] | number | undefined; 344 | } 345 | interface LinkHTMLAttributes extends HTMLAttributes { 346 | as?: string | undefined; 347 | crossOrigin?: CrossOrigin; 348 | fetchPriority?: "high" | "low" | "auto"; 349 | href?: string | undefined; 350 | hrefLang?: string | undefined; 351 | integrity?: string | undefined; 352 | media?: string | undefined; 353 | imageSrcSet?: string | undefined; 354 | imageSizes?: string | undefined; 355 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 356 | sizes?: string | undefined; 357 | type?: string | undefined; 358 | charSet?: string | undefined; 359 | } 360 | interface MapHTMLAttributes extends HTMLAttributes { 361 | name?: string | undefined; 362 | } 363 | interface MenuHTMLAttributes extends HTMLAttributes { 364 | type?: string | undefined; 365 | } 366 | interface MediaHTMLAttributes extends HTMLAttributes { 367 | autoPlay?: boolean | undefined; 368 | controls?: boolean | undefined; 369 | controlsList?: string | undefined; 370 | crossOrigin?: CrossOrigin; 371 | loop?: boolean | undefined; 372 | mediaGroup?: string | undefined; 373 | muted?: boolean | undefined; 374 | playsInline?: boolean | undefined; 375 | preload?: string | undefined; 376 | src?: string | undefined; 377 | } 378 | interface MetaHTMLAttributes extends HTMLAttributes { 379 | charSet?: string | undefined; 380 | httpEquiv?: string | undefined; 381 | name?: string | undefined; 382 | media?: string | undefined; 383 | content?: string | undefined; 384 | } 385 | interface MeterHTMLAttributes extends HTMLAttributes { 386 | form?: string | undefined; 387 | high?: number | undefined; 388 | low?: number | undefined; 389 | max?: number | string | undefined; 390 | min?: number | string | undefined; 391 | optimum?: number | undefined; 392 | value?: string | readonly string[] | number | undefined; 393 | } 394 | interface QuoteHTMLAttributes extends HTMLAttributes { 395 | cite?: string | undefined; 396 | } 397 | interface ObjectHTMLAttributes extends HTMLAttributes { 398 | classID?: string | undefined; 399 | data?: string | undefined; 400 | form?: string | undefined; 401 | height?: number | string | undefined; 402 | name?: string | undefined; 403 | type?: string | undefined; 404 | useMap?: string | undefined; 405 | width?: number | string | undefined; 406 | wmode?: string | undefined; 407 | } 408 | interface OlHTMLAttributes extends HTMLAttributes { 409 | reversed?: boolean | undefined; 410 | start?: number | undefined; 411 | type?: "1" | "a" | "A" | "i" | "I" | undefined; 412 | } 413 | interface OptgroupHTMLAttributes extends HTMLAttributes { 414 | disabled?: boolean | undefined; 415 | label?: string | undefined; 416 | } 417 | interface OptionHTMLAttributes extends HTMLAttributes { 418 | disabled?: boolean | undefined; 419 | label?: string | undefined; 420 | selected?: boolean | undefined; 421 | value?: string | readonly string[] | number | undefined; 422 | } 423 | interface OutputHTMLAttributes extends HTMLAttributes { 424 | form?: string | undefined; 425 | htmlFor?: string | undefined; 426 | name?: string | undefined; 427 | } 428 | interface ParamHTMLAttributes extends HTMLAttributes { 429 | name?: string | undefined; 430 | value?: string | readonly string[] | number | undefined; 431 | } 432 | interface ProgressHTMLAttributes extends HTMLAttributes { 433 | max?: number | string | undefined; 434 | value?: string | readonly string[] | number | undefined; 435 | } 436 | interface SlotHTMLAttributes extends HTMLAttributes { 437 | name?: string | undefined; 438 | } 439 | interface ScriptHTMLAttributes extends HTMLAttributes { 440 | async?: boolean | undefined; 441 | charSet?: string | undefined; 442 | crossOrigin?: CrossOrigin; 443 | defer?: boolean | undefined; 444 | integrity?: string | undefined; 445 | noModule?: boolean | undefined; 446 | referrerPolicy?: HTMLAttributeReferrerPolicy | undefined; 447 | src?: string | undefined; 448 | type?: string | undefined; 449 | } 450 | interface SelectHTMLAttributes extends HTMLAttributes { 451 | autoComplete?: string | undefined; 452 | disabled?: boolean | undefined; 453 | form?: string | undefined; 454 | multiple?: boolean | undefined; 455 | name?: string | undefined; 456 | required?: boolean | undefined; 457 | size?: number | undefined; 458 | value?: string | readonly string[] | number | undefined; 459 | } 460 | interface SourceHTMLAttributes extends HTMLAttributes { 461 | height?: number | string | undefined; 462 | media?: string | undefined; 463 | sizes?: string | undefined; 464 | src?: string | undefined; 465 | srcSet?: string | undefined; 466 | type?: string | undefined; 467 | width?: number | string | undefined; 468 | } 469 | interface StyleHTMLAttributes extends HTMLAttributes { 470 | media?: string | undefined; 471 | scoped?: boolean | undefined; 472 | type?: string | undefined; 473 | } 474 | interface TableHTMLAttributes extends HTMLAttributes { 475 | align?: "left" | "center" | "right" | undefined; 476 | bgcolor?: string | undefined; 477 | border?: number | undefined; 478 | cellPadding?: number | string | undefined; 479 | cellSpacing?: number | string | undefined; 480 | frame?: boolean | undefined; 481 | rules?: "none" | "groups" | "rows" | "columns" | "all" | undefined; 482 | summary?: string | undefined; 483 | width?: number | string | undefined; 484 | } 485 | interface TextareaHTMLAttributes extends HTMLAttributes { 486 | autoComplete?: string | undefined; 487 | cols?: number | undefined; 488 | dirName?: string | undefined; 489 | disabled?: boolean | undefined; 490 | form?: string | undefined; 491 | maxLength?: number | undefined; 492 | minLength?: number | undefined; 493 | name?: string | undefined; 494 | placeholder?: string | undefined; 495 | readOnly?: boolean | undefined; 496 | required?: boolean | undefined; 497 | rows?: number | undefined; 498 | value?: string | readonly string[] | number | undefined; 499 | wrap?: string | undefined; 500 | } 501 | interface TdHTMLAttributes extends HTMLAttributes { 502 | align?: "left" | "center" | "right" | "justify" | "char" | undefined; 503 | colSpan?: number | undefined; 504 | headers?: string | undefined; 505 | rowSpan?: number | undefined; 506 | scope?: string | undefined; 507 | abbr?: string | undefined; 508 | height?: number | string | undefined; 509 | width?: number | string | undefined; 510 | valign?: "top" | "middle" | "bottom" | "baseline" | undefined; 511 | } 512 | interface ThHTMLAttributes extends HTMLAttributes { 513 | align?: "left" | "center" | "right" | "justify" | "char" | undefined; 514 | colSpan?: number | undefined; 515 | headers?: string | undefined; 516 | rowSpan?: number | undefined; 517 | scope?: string | undefined; 518 | abbr?: string | undefined; 519 | } 520 | interface TimeHTMLAttributes extends HTMLAttributes { 521 | dateTime?: string | undefined; 522 | } 523 | interface TrackHTMLAttributes extends HTMLAttributes { 524 | default?: boolean | undefined; 525 | kind?: string | undefined; 526 | label?: string | undefined; 527 | src?: string | undefined; 528 | srcLang?: string | undefined; 529 | } 530 | interface VideoHTMLAttributes extends MediaHTMLAttributes { 531 | height?: number | string | undefined; 532 | playsInline?: boolean | undefined; 533 | poster?: string | undefined; 534 | width?: number | string | undefined; 535 | disablePictureInPicture?: boolean | undefined; 536 | disableRemotePlayback?: boolean | undefined; 537 | } 538 | interface SVGAttributes extends AriaAttributes, DOMAttributes { 539 | suppressHydrationWarning?: boolean | undefined; 540 | className?: string | undefined; 541 | color?: string | undefined; 542 | height?: number | string | undefined; 543 | id?: string | undefined; 544 | lang?: string | undefined; 545 | max?: number | string | undefined; 546 | media?: string | undefined; 547 | method?: string | undefined; 548 | min?: number | string | undefined; 549 | name?: string | undefined; 550 | style?: CSSProperties | undefined; 551 | target?: string | undefined; 552 | type?: string | undefined; 553 | width?: number | string | undefined; 554 | role?: AriaRole | undefined; 555 | tabIndex?: number | undefined; 556 | crossOrigin?: CrossOrigin; 557 | accentHeight?: number | string | undefined; 558 | accumulate?: "none" | "sum" | undefined; 559 | additive?: "replace" | "sum" | undefined; 560 | alignmentBaseline?: 561 | | "auto" 562 | | "baseline" 563 | | "before-edge" 564 | | "text-before-edge" 565 | | "middle" 566 | | "central" 567 | | "after-edge" 568 | | "text-after-edge" 569 | | "ideographic" 570 | | "alphabetic" 571 | | "hanging" 572 | | "mathematical" 573 | | "inherit" 574 | | undefined; 575 | allowReorder?: "no" | "yes" | undefined; 576 | alphabetic?: number | string | undefined; 577 | amplitude?: number | string | undefined; 578 | arabicForm?: "initial" | "medial" | "terminal" | "isolated" | undefined; 579 | ascent?: number | string | undefined; 580 | attributeName?: string | undefined; 581 | attributeType?: string | undefined; 582 | autoReverse?: Booleanish | undefined; 583 | azimuth?: number | string | undefined; 584 | baseFrequency?: number | string | undefined; 585 | baselineShift?: number | string | undefined; 586 | baseProfile?: number | string | undefined; 587 | bbox?: number | string | undefined; 588 | begin?: number | string | undefined; 589 | bias?: number | string | undefined; 590 | by?: number | string | undefined; 591 | calcMode?: number | string | undefined; 592 | capHeight?: number | string | undefined; 593 | clip?: number | string | undefined; 594 | clipPath?: string | undefined; 595 | clipPathUnits?: number | string | undefined; 596 | clipRule?: number | string | undefined; 597 | colorInterpolation?: number | string | undefined; 598 | colorInterpolationFilters?: "auto" | "sRGB" | "linearRGB" | "inherit" | undefined; 599 | colorProfile?: number | string | undefined; 600 | colorRendering?: number | string | undefined; 601 | contentScriptType?: number | string | undefined; 602 | contentStyleType?: number | string | undefined; 603 | cursor?: number | string | undefined; 604 | cx?: number | string | undefined; 605 | cy?: number | string | undefined; 606 | d?: string | undefined; 607 | decelerate?: number | string | undefined; 608 | descent?: number | string | undefined; 609 | diffuseConstant?: number | string | undefined; 610 | direction?: number | string | undefined; 611 | display?: number | string | undefined; 612 | divisor?: number | string | undefined; 613 | dominantBaseline?: number | string | undefined; 614 | dur?: number | string | undefined; 615 | dx?: number | string | undefined; 616 | dy?: number | string | undefined; 617 | edgeMode?: number | string | undefined; 618 | elevation?: number | string | undefined; 619 | enableBackground?: number | string | undefined; 620 | end?: number | string | undefined; 621 | exponent?: number | string | undefined; 622 | externalResourcesRequired?: Booleanish | undefined; 623 | fill?: string | undefined; 624 | fillOpacity?: number | string | undefined; 625 | fillRule?: "nonzero" | "evenodd" | "inherit" | undefined; 626 | filter?: string | undefined; 627 | filterRes?: number | string | undefined; 628 | filterUnits?: number | string | undefined; 629 | floodColor?: number | string | undefined; 630 | floodOpacity?: number | string | undefined; 631 | focusable?: Booleanish | "auto" | undefined; 632 | fontFamily?: string | undefined; 633 | fontSize?: number | string | undefined; 634 | fontSizeAdjust?: number | string | undefined; 635 | fontStretch?: number | string | undefined; 636 | fontStyle?: number | string | undefined; 637 | fontVariant?: number | string | undefined; 638 | fontWeight?: number | string | undefined; 639 | format?: number | string | undefined; 640 | fr?: number | string | undefined; 641 | from?: number | string | undefined; 642 | fx?: number | string | undefined; 643 | fy?: number | string | undefined; 644 | g1?: number | string | undefined; 645 | g2?: number | string | undefined; 646 | glyphName?: number | string | undefined; 647 | glyphOrientationHorizontal?: number | string | undefined; 648 | glyphOrientationVertical?: number | string | undefined; 649 | glyphRef?: number | string | undefined; 650 | gradientTransform?: string | undefined; 651 | gradientUnits?: string | undefined; 652 | hanging?: number | string | undefined; 653 | horizAdvX?: number | string | undefined; 654 | horizOriginX?: number | string | undefined; 655 | href?: string | undefined; 656 | ideographic?: number | string | undefined; 657 | imageRendering?: number | string | undefined; 658 | in2?: number | string | undefined; 659 | in?: string | undefined; 660 | intercept?: number | string | undefined; 661 | k1?: number | string | undefined; 662 | k2?: number | string | undefined; 663 | k3?: number | string | undefined; 664 | k4?: number | string | undefined; 665 | k?: number | string | undefined; 666 | kernelMatrix?: number | string | undefined; 667 | kernelUnitLength?: number | string | undefined; 668 | kerning?: number | string | undefined; 669 | keyPoints?: number | string | undefined; 670 | keySplines?: number | string | undefined; 671 | keyTimes?: number | string | undefined; 672 | lengthAdjust?: number | string | undefined; 673 | letterSpacing?: number | string | undefined; 674 | lightingColor?: number | string | undefined; 675 | limitingConeAngle?: number | string | undefined; 676 | local?: number | string | undefined; 677 | markerEnd?: string | undefined; 678 | markerHeight?: number | string | undefined; 679 | markerMid?: string | undefined; 680 | markerStart?: string | undefined; 681 | markerUnits?: number | string | undefined; 682 | markerWidth?: number | string | undefined; 683 | mask?: string | undefined; 684 | maskContentUnits?: number | string | undefined; 685 | maskUnits?: number | string | undefined; 686 | mathematical?: number | string | undefined; 687 | mode?: number | string | undefined; 688 | numOctaves?: number | string | undefined; 689 | offset?: number | string | undefined; 690 | opacity?: number | string | undefined; 691 | operator?: number | string | undefined; 692 | order?: number | string | undefined; 693 | orient?: number | string | undefined; 694 | orientation?: number | string | undefined; 695 | origin?: number | string | undefined; 696 | overflow?: number | string | undefined; 697 | overlinePosition?: number | string | undefined; 698 | overlineThickness?: number | string | undefined; 699 | paintOrder?: number | string | undefined; 700 | panose1?: number | string | undefined; 701 | path?: string | undefined; 702 | pathLength?: number | string | undefined; 703 | patternContentUnits?: string | undefined; 704 | patternTransform?: number | string | undefined; 705 | patternUnits?: string | undefined; 706 | pointerEvents?: number | string | undefined; 707 | points?: string | undefined; 708 | pointsAtX?: number | string | undefined; 709 | pointsAtY?: number | string | undefined; 710 | pointsAtZ?: number | string | undefined; 711 | preserveAlpha?: Booleanish | undefined; 712 | preserveAspectRatio?: string | undefined; 713 | primitiveUnits?: number | string | undefined; 714 | r?: number | string | undefined; 715 | radius?: number | string | undefined; 716 | refX?: number | string | undefined; 717 | refY?: number | string | undefined; 718 | renderingIntent?: number | string | undefined; 719 | repeatCount?: number | string | undefined; 720 | repeatDur?: number | string | undefined; 721 | requiredExtensions?: number | string | undefined; 722 | requiredFeatures?: number | string | undefined; 723 | restart?: number | string | undefined; 724 | result?: string | undefined; 725 | rotate?: number | string | undefined; 726 | rx?: number | string | undefined; 727 | ry?: number | string | undefined; 728 | scale?: number | string | undefined; 729 | seed?: number | string | undefined; 730 | shapeRendering?: number | string | undefined; 731 | slope?: number | string | undefined; 732 | spacing?: number | string | undefined; 733 | specularConstant?: number | string | undefined; 734 | specularExponent?: number | string | undefined; 735 | speed?: number | string | undefined; 736 | spreadMethod?: string | undefined; 737 | startOffset?: number | string | undefined; 738 | stdDeviation?: number | string | undefined; 739 | stemh?: number | string | undefined; 740 | stemv?: number | string | undefined; 741 | stitchTiles?: number | string | undefined; 742 | stopColor?: string | undefined; 743 | stopOpacity?: number | string | undefined; 744 | strikethroughPosition?: number | string | undefined; 745 | strikethroughThickness?: number | string | undefined; 746 | string?: number | string | undefined; 747 | stroke?: string | undefined; 748 | strokeDasharray?: string | number | undefined; 749 | strokeDashoffset?: string | number | undefined; 750 | strokeLinecap?: "butt" | "round" | "square" | "inherit" | undefined; 751 | strokeLinejoin?: "miter" | "round" | "bevel" | "inherit" | undefined; 752 | strokeMiterlimit?: number | string | undefined; 753 | strokeOpacity?: number | string | undefined; 754 | strokeWidth?: number | string | undefined; 755 | surfaceScale?: number | string | undefined; 756 | systemLanguage?: number | string | undefined; 757 | tableValues?: number | string | undefined; 758 | targetX?: number | string | undefined; 759 | targetY?: number | string | undefined; 760 | textAnchor?: string | undefined; 761 | textDecoration?: number | string | undefined; 762 | textLength?: number | string | undefined; 763 | textRendering?: number | string | undefined; 764 | to?: number | string | undefined; 765 | transform?: string | undefined; 766 | u1?: number | string | undefined; 767 | u2?: number | string | undefined; 768 | underlinePosition?: number | string | undefined; 769 | underlineThickness?: number | string | undefined; 770 | unicode?: number | string | undefined; 771 | unicodeBidi?: number | string | undefined; 772 | unicodeRange?: number | string | undefined; 773 | unitsPerEm?: number | string | undefined; 774 | vAlphabetic?: number | string | undefined; 775 | values?: string | undefined; 776 | vectorEffect?: number | string | undefined; 777 | version?: string | undefined; 778 | vertAdvY?: number | string | undefined; 779 | vertOriginX?: number | string | undefined; 780 | vertOriginY?: number | string | undefined; 781 | vHanging?: number | string | undefined; 782 | vIdeographic?: number | string | undefined; 783 | viewBox?: string | undefined; 784 | viewTarget?: number | string | undefined; 785 | visibility?: number | string | undefined; 786 | vMathematical?: number | string | undefined; 787 | widths?: number | string | undefined; 788 | wordSpacing?: number | string | undefined; 789 | writingMode?: number | string | undefined; 790 | x1?: number | string | undefined; 791 | x2?: number | string | undefined; 792 | x?: number | string | undefined; 793 | xChannelSelector?: string | undefined; 794 | xHeight?: number | string | undefined; 795 | xlinkActuate?: string | undefined; 796 | xlinkArcrole?: string | undefined; 797 | xlinkHref?: string | undefined; 798 | xlinkRole?: string | undefined; 799 | xlinkShow?: string | undefined; 800 | xlinkTitle?: string | undefined; 801 | xlinkType?: string | undefined; 802 | xmlBase?: string | undefined; 803 | xmlLang?: string | undefined; 804 | xmlns?: string | undefined; 805 | xmlnsXlink?: string | undefined; 806 | xmlSpace?: string | undefined; 807 | y1?: number | string | undefined; 808 | y2?: number | string | undefined; 809 | y?: number | string | undefined; 810 | yChannelSelector?: string | undefined; 811 | z?: number | string | undefined; 812 | zoomAndPan?: string | undefined; 813 | } 814 | interface WebViewHTMLAttributes extends HTMLAttributes { 815 | allowFullScreen?: boolean | undefined; 816 | allowpopups?: boolean | undefined; 817 | autosize?: boolean | undefined; 818 | blinkfeatures?: string | undefined; 819 | disableblinkfeatures?: string | undefined; 820 | disableguestresize?: boolean | undefined; 821 | disablewebsecurity?: boolean | undefined; 822 | guestinstance?: string | undefined; 823 | httpreferrer?: string | undefined; 824 | nodeintegration?: boolean | undefined; 825 | partition?: string | undefined; 826 | plugins?: boolean | undefined; 827 | preload?: string | undefined; 828 | src?: string | undefined; 829 | useragent?: string | undefined; 830 | webpreferences?: string | undefined; 831 | } 832 | interface AriaAttributes { 833 | "aria-activedescendant"?: string | undefined; 834 | "aria-atomic"?: Booleanish | undefined; 835 | "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined; 836 | "aria-braillelabel"?: string | undefined; 837 | "aria-brailleroledescription"?: string | undefined; 838 | "aria-busy"?: Booleanish | undefined; 839 | "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined; 840 | "aria-colcount"?: number | undefined; 841 | "aria-colindex"?: number | undefined; 842 | "aria-colindextext"?: string | undefined; 843 | "aria-colspan"?: number | undefined; 844 | "aria-controls"?: string | undefined; 845 | "aria-current"?: 846 | | boolean 847 | | "false" 848 | | "true" 849 | | "page" 850 | | "step" 851 | | "location" 852 | | "date" 853 | | "time" 854 | | undefined; 855 | "aria-describedby"?: string | undefined; 856 | "aria-description"?: string | undefined; 857 | "aria-details"?: string | undefined; 858 | "aria-disabled"?: Booleanish | undefined; 859 | "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined; 860 | "aria-errormessage"?: string | undefined; 861 | "aria-expanded"?: Booleanish | undefined; 862 | "aria-flowto"?: string | undefined; 863 | "aria-grabbed"?: Booleanish | undefined; 864 | "aria-haspopup"?: 865 | | boolean 866 | | "false" 867 | | "true" 868 | | "menu" 869 | | "listbox" 870 | | "tree" 871 | | "grid" 872 | | "dialog" 873 | | undefined; 874 | "aria-hidden"?: Booleanish | undefined; 875 | "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined; 876 | "aria-keyshortcuts"?: string | undefined; 877 | "aria-label"?: string | undefined; 878 | "aria-labelledby"?: string | undefined; 879 | "aria-level"?: number | undefined; 880 | "aria-live"?: "off" | "assertive" | "polite" | undefined; 881 | "aria-modal"?: Booleanish | undefined; 882 | "aria-multiline"?: Booleanish | undefined; 883 | "aria-multiselectable"?: Booleanish | undefined; 884 | "aria-orientation"?: "horizontal" | "vertical" | undefined; 885 | "aria-owns"?: string | undefined; 886 | "aria-placeholder"?: string | undefined; 887 | "aria-posinset"?: number | undefined; 888 | "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined; 889 | "aria-readonly"?: Booleanish | undefined; 890 | "aria-relevant"?: 891 | | "additions" 892 | | "additions removals" 893 | | "additions text" 894 | | "all" 895 | | "removals" 896 | | "removals additions" 897 | | "removals text" 898 | | "text" 899 | | "text additions" 900 | | "text removals" 901 | | undefined; 902 | "aria-required"?: Booleanish | undefined; 903 | "aria-roledescription"?: string | undefined; 904 | "aria-rowcount"?: number | undefined; 905 | "aria-rowindex"?: number | undefined; 906 | "aria-rowindextext"?: string | undefined; 907 | "aria-rowspan"?: number | undefined; 908 | "aria-selected"?: Booleanish | undefined; 909 | "aria-setsize"?: number | undefined; 910 | "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined; 911 | "aria-valuemax"?: number | undefined; 912 | "aria-valuemin"?: number | undefined; 913 | "aria-valuenow"?: number | undefined; 914 | "aria-valuetext"?: string | undefined; 915 | } 916 | type Booleanish = boolean | "true" | "false"; 917 | interface HTMLAttributes extends AriaAttributes, DOMAttributes { 918 | defaultChecked?: boolean | undefined; 919 | defaultValue?: string | number | readonly string[] | undefined; 920 | suppressContentEditableWarning?: boolean | undefined; 921 | suppressHydrationWarning?: boolean | undefined; 922 | accessKey?: string | undefined; 923 | autoFocus?: boolean | undefined; 924 | className?: string | undefined; 925 | contentEditable?: Booleanish | "inherit" | "plaintext-only" | undefined; 926 | contextMenu?: string | undefined; 927 | dir?: string | undefined; 928 | draggable?: Booleanish | undefined; 929 | hidden?: boolean | undefined; 930 | id?: string | undefined; 931 | lang?: string | undefined; 932 | nonce?: string | undefined; 933 | slot?: string | undefined; 934 | spellCheck?: Booleanish | undefined; 935 | style?: CSSProperties | undefined; 936 | tabIndex?: number | undefined; 937 | title?: string | undefined; 938 | translate?: "yes" | "no" | undefined; 939 | radioGroup?: string | undefined; 940 | role?: AriaRole | undefined; 941 | about?: string | undefined; 942 | content?: string | undefined; 943 | datatype?: string | undefined; 944 | inlist?: any; 945 | prefix?: string | undefined; 946 | property?: string | undefined; 947 | rel?: string | undefined; 948 | resource?: string | undefined; 949 | rev?: string | undefined; 950 | typeof?: string | undefined; 951 | vocab?: string | undefined; 952 | autoCapitalize?: string | undefined; 953 | autoCorrect?: string | undefined; 954 | autoSave?: string | undefined; 955 | color?: string | undefined; 956 | itemProp?: string | undefined; 957 | itemScope?: boolean | undefined; 958 | itemType?: string | undefined; 959 | itemID?: string | undefined; 960 | itemRef?: string | undefined; 961 | results?: number | undefined; 962 | security?: string | undefined; 963 | unselectable?: "on" | "off" | undefined; 964 | inputMode?: 965 | | "none" 966 | | "text" 967 | | "tel" 968 | | "url" 969 | | "email" 970 | | "numeric" 971 | | "decimal" 972 | | "search" 973 | | undefined; 974 | is?: string | undefined; 975 | } 976 | type AriaRole = 977 | | "alert" 978 | | "alertdialog" 979 | | "application" 980 | | "article" 981 | | "banner" 982 | | "button" 983 | | "cell" 984 | | "checkbox" 985 | | "columnheader" 986 | | "combobox" 987 | | "complementary" 988 | | "contentinfo" 989 | | "definition" 990 | | "dialog" 991 | | "directory" 992 | | "document" 993 | | "feed" 994 | | "figure" 995 | | "form" 996 | | "grid" 997 | | "gridcell" 998 | | "group" 999 | | "heading" 1000 | | "img" 1001 | | "link" 1002 | | "list" 1003 | | "listbox" 1004 | | "listitem" 1005 | | "log" 1006 | | "main" 1007 | | "marquee" 1008 | | "math" 1009 | | "menu" 1010 | | "menubar" 1011 | | "menuitem" 1012 | | "menuitemcheckbox" 1013 | | "menuitemradio" 1014 | | "navigation" 1015 | | "none" 1016 | | "note" 1017 | | "option" 1018 | | "presentation" 1019 | | "progressbar" 1020 | | "radio" 1021 | | "radiogroup" 1022 | | "region" 1023 | | "row" 1024 | | "rowgroup" 1025 | | "rowheader" 1026 | | "scrollbar" 1027 | | "search" 1028 | | "searchbox" 1029 | | "separator" 1030 | | "slider" 1031 | | "spinbutton" 1032 | | "status" 1033 | | "switch" 1034 | | "tab" 1035 | | "table" 1036 | | "tablist" 1037 | | "tabpanel" 1038 | | "term" 1039 | | "textbox" 1040 | | "timer" 1041 | | "toolbar" 1042 | | "tooltip" 1043 | | "tree" 1044 | | "treegrid" 1045 | | "treeitem" 1046 | | (string & {}); 1047 | export interface CSSProperties extends CSS.Properties<(string & {}) | number> {} 1048 | interface TrustedHTML {} 1049 | interface DOMAttributes { 1050 | children?: hjsx.Node | undefined; 1051 | dangerouslySetInnerHTML?: 1052 | | { 1053 | __html: string | TrustedHTML; 1054 | } 1055 | | undefined; 1056 | } 1057 | type Node = 1058 | | Element 1059 | | string 1060 | | number 1061 | | Iterable 1062 | | Portal 1063 | | boolean 1064 | | null 1065 | | undefined; 1066 | interface Portal extends Element { 1067 | children: Node; 1068 | } 1069 | interface Element< 1070 | P = any, 1071 | T extends string | JSXElementConstructor = string | JSXElementConstructor, 1072 | > { 1073 | type: T; 1074 | props: P; 1075 | key: string | null; 1076 | } 1077 | type JSXElementConstructor

= 1078 | | ((props: P, deprecatedLegacyContext?: any) => Node) 1079 | | (new (props: P, deprecatedLegacyContext?: any) => Component); 1080 | interface Component

extends String { 1081 | [x: string]: any; 1082 | } 1083 | type DetailedHTMLProps = Attributes & E; 1084 | interface ClassAttributes extends Attributes { 1085 | ref?: LegacyRef | undefined; 1086 | } 1087 | type LegacyRef = string | Ref; 1088 | interface Attributes { 1089 | key?: Key | null | undefined; 1090 | } 1091 | type Key = string | number | bigint; 1092 | interface RefObject { 1093 | readonly current: T | null; 1094 | } 1095 | type RefCallback = { 1096 | bivarianceHack(instance: T | null): void; 1097 | }["bivarianceHack"]; 1098 | type Ref = RefCallback | RefObject | null; 1099 | } 1100 | export namespace JSX { 1101 | interface IntrinsicElements { 1102 | a: hjsx.DetailedHTMLProps; 1103 | abbr: hjsx.DetailedHTMLProps; 1104 | address: hjsx.DetailedHTMLProps; 1105 | area: hjsx.DetailedHTMLProps; 1106 | article: hjsx.DetailedHTMLProps; 1107 | aside: hjsx.DetailedHTMLProps; 1108 | audio: hjsx.DetailedHTMLProps; 1109 | b: hjsx.DetailedHTMLProps; 1110 | base: hjsx.DetailedHTMLProps; 1111 | bdi: hjsx.DetailedHTMLProps; 1112 | bdo: hjsx.DetailedHTMLProps; 1113 | big: hjsx.DetailedHTMLProps; 1114 | blockquote: hjsx.DetailedHTMLProps; 1115 | body: hjsx.DetailedHTMLProps; 1116 | br: hjsx.DetailedHTMLProps; 1117 | button: hjsx.DetailedHTMLProps; 1118 | canvas: hjsx.DetailedHTMLProps; 1119 | caption: hjsx.DetailedHTMLProps; 1120 | center: hjsx.DetailedHTMLProps; 1121 | cite: hjsx.DetailedHTMLProps; 1122 | code: hjsx.DetailedHTMLProps; 1123 | col: hjsx.DetailedHTMLProps; 1124 | colgroup: hjsx.DetailedHTMLProps; 1125 | data: hjsx.DetailedHTMLProps; 1126 | datalist: hjsx.DetailedHTMLProps; 1127 | dd: hjsx.DetailedHTMLProps; 1128 | del: hjsx.DetailedHTMLProps; 1129 | details: hjsx.DetailedHTMLProps; 1130 | dfn: hjsx.DetailedHTMLProps; 1131 | dialog: hjsx.DetailedHTMLProps; 1132 | div: hjsx.DetailedHTMLProps; 1133 | dl: hjsx.DetailedHTMLProps; 1134 | dt: hjsx.DetailedHTMLProps; 1135 | em: hjsx.DetailedHTMLProps; 1136 | embed: hjsx.DetailedHTMLProps; 1137 | fieldset: hjsx.DetailedHTMLProps; 1138 | figcaption: hjsx.DetailedHTMLProps; 1139 | figure: hjsx.DetailedHTMLProps; 1140 | footer: hjsx.DetailedHTMLProps; 1141 | form: hjsx.DetailedHTMLProps; 1142 | h1: hjsx.DetailedHTMLProps; 1143 | h2: hjsx.DetailedHTMLProps; 1144 | h3: hjsx.DetailedHTMLProps; 1145 | h4: hjsx.DetailedHTMLProps; 1146 | h5: hjsx.DetailedHTMLProps; 1147 | h6: hjsx.DetailedHTMLProps; 1148 | head: hjsx.DetailedHTMLProps; 1149 | header: hjsx.DetailedHTMLProps; 1150 | hgroup: hjsx.DetailedHTMLProps; 1151 | hr: hjsx.DetailedHTMLProps; 1152 | html: hjsx.DetailedHTMLProps; 1153 | i: hjsx.DetailedHTMLProps; 1154 | iframe: hjsx.DetailedHTMLProps; 1155 | img: hjsx.DetailedHTMLProps; 1156 | input: hjsx.DetailedHTMLProps; 1157 | ins: hjsx.DetailedHTMLProps; 1158 | kbd: hjsx.DetailedHTMLProps; 1159 | keygen: hjsx.DetailedHTMLProps; 1160 | label: hjsx.DetailedHTMLProps; 1161 | legend: hjsx.DetailedHTMLProps; 1162 | li: hjsx.DetailedHTMLProps; 1163 | link: hjsx.DetailedHTMLProps; 1164 | main: hjsx.DetailedHTMLProps; 1165 | map: hjsx.DetailedHTMLProps; 1166 | mark: hjsx.DetailedHTMLProps; 1167 | menu: hjsx.DetailedHTMLProps; 1168 | menuitem: hjsx.DetailedHTMLProps; 1169 | meta: hjsx.DetailedHTMLProps; 1170 | meter: hjsx.DetailedHTMLProps; 1171 | nav: hjsx.DetailedHTMLProps; 1172 | noindex: hjsx.DetailedHTMLProps; 1173 | noscript: hjsx.DetailedHTMLProps; 1174 | object: hjsx.DetailedHTMLProps; 1175 | ol: hjsx.DetailedHTMLProps; 1176 | optgroup: hjsx.DetailedHTMLProps; 1177 | option: hjsx.DetailedHTMLProps; 1178 | output: hjsx.DetailedHTMLProps; 1179 | p: hjsx.DetailedHTMLProps; 1180 | param: hjsx.DetailedHTMLProps; 1181 | picture: hjsx.DetailedHTMLProps; 1182 | pre: hjsx.DetailedHTMLProps; 1183 | progress: hjsx.DetailedHTMLProps; 1184 | q: hjsx.DetailedHTMLProps; 1185 | rp: hjsx.DetailedHTMLProps; 1186 | rt: hjsx.DetailedHTMLProps; 1187 | ruby: hjsx.DetailedHTMLProps; 1188 | s: hjsx.DetailedHTMLProps; 1189 | samp: hjsx.DetailedHTMLProps; 1190 | search: hjsx.DetailedHTMLProps; 1191 | slot: hjsx.DetailedHTMLProps; 1192 | script: hjsx.DetailedHTMLProps; 1193 | section: hjsx.DetailedHTMLProps; 1194 | select: hjsx.DetailedHTMLProps; 1195 | small: hjsx.DetailedHTMLProps; 1196 | source: hjsx.DetailedHTMLProps; 1197 | span: hjsx.DetailedHTMLProps; 1198 | strong: hjsx.DetailedHTMLProps; 1199 | style: hjsx.DetailedHTMLProps; 1200 | sub: hjsx.DetailedHTMLProps; 1201 | summary: hjsx.DetailedHTMLProps; 1202 | sup: hjsx.DetailedHTMLProps; 1203 | table: hjsx.DetailedHTMLProps; 1204 | template: hjsx.DetailedHTMLProps; 1205 | tbody: hjsx.DetailedHTMLProps; 1206 | td: hjsx.DetailedHTMLProps; 1207 | textarea: hjsx.DetailedHTMLProps; 1208 | tfoot: hjsx.DetailedHTMLProps; 1209 | th: hjsx.DetailedHTMLProps; 1210 | thead: hjsx.DetailedHTMLProps; 1211 | time: hjsx.DetailedHTMLProps; 1212 | title: hjsx.DetailedHTMLProps; 1213 | tr: hjsx.DetailedHTMLProps; 1214 | track: hjsx.DetailedHTMLProps; 1215 | u: hjsx.DetailedHTMLProps; 1216 | ul: hjsx.DetailedHTMLProps; 1217 | var: hjsx.DetailedHTMLProps; 1218 | video: hjsx.DetailedHTMLProps; 1219 | wbr: hjsx.DetailedHTMLProps; 1220 | webview: hjsx.DetailedHTMLProps; 1221 | svg: hjsx.SVGProps; 1222 | animate: hjsx.SVGProps; 1223 | animateMotion: hjsx.SVGProps; 1224 | animateTransform: hjsx.SVGProps; 1225 | circle: hjsx.SVGProps; 1226 | clipPath: hjsx.SVGProps; 1227 | defs: hjsx.SVGProps; 1228 | desc: hjsx.SVGProps; 1229 | ellipse: hjsx.SVGProps; 1230 | feBlend: hjsx.SVGProps; 1231 | feColorMatrix: hjsx.SVGProps; 1232 | feComponentTransfer: hjsx.SVGProps; 1233 | feComposite: hjsx.SVGProps; 1234 | feConvolveMatrix: hjsx.SVGProps; 1235 | feDiffuseLighting: hjsx.SVGProps; 1236 | feDisplacementMap: hjsx.SVGProps; 1237 | feDistantLight: hjsx.SVGProps; 1238 | feDropShadow: hjsx.SVGProps; 1239 | feFlood: hjsx.SVGProps; 1240 | feFuncA: hjsx.SVGProps; 1241 | feFuncB: hjsx.SVGProps; 1242 | feFuncG: hjsx.SVGProps; 1243 | feFuncR: hjsx.SVGProps; 1244 | feGaussianBlur: hjsx.SVGProps; 1245 | feImage: hjsx.SVGProps; 1246 | feMerge: hjsx.SVGProps; 1247 | feMergeNode: hjsx.SVGProps; 1248 | feMorphology: hjsx.SVGProps; 1249 | feOffset: hjsx.SVGProps; 1250 | fePointLight: hjsx.SVGProps; 1251 | feSpecularLighting: hjsx.SVGProps; 1252 | feSpotLight: hjsx.SVGProps; 1253 | feTile: hjsx.SVGProps; 1254 | feTurbulence: hjsx.SVGProps; 1255 | filter: hjsx.SVGProps; 1256 | foreignObject: hjsx.SVGProps; 1257 | g: hjsx.SVGProps; 1258 | image: hjsx.SVGProps; 1259 | line: hjsx.SVGLineElementAttributes; 1260 | linearGradient: hjsx.SVGProps; 1261 | marker: hjsx.SVGProps; 1262 | mask: hjsx.SVGProps; 1263 | metadata: hjsx.SVGProps; 1264 | mpath: hjsx.SVGProps; 1265 | path: hjsx.SVGProps; 1266 | pattern: hjsx.SVGProps; 1267 | polygon: hjsx.SVGProps; 1268 | polyline: hjsx.SVGProps; 1269 | radialGradient: hjsx.SVGProps; 1270 | rect: hjsx.SVGProps; 1271 | stop: hjsx.SVGProps; 1272 | switch: hjsx.SVGProps; 1273 | symbol: hjsx.SVGProps; 1274 | text: hjsx.SVGTextElementAttributes; 1275 | textPath: hjsx.SVGProps; 1276 | tspan: hjsx.SVGProps; 1277 | use: hjsx.SVGProps; 1278 | view: hjsx.SVGProps; 1279 | } 1280 | } 1281 | interface Element {} 1282 | interface DocumentFragment {} 1283 | interface HTMLElement extends Element {} 1284 | interface HTMLAnchorElement extends HTMLElement {} 1285 | interface HTMLAreaElement extends HTMLElement {} 1286 | interface HTMLAudioElement extends HTMLElement {} 1287 | interface HTMLBaseElement extends HTMLElement {} 1288 | interface HTMLBodyElement extends HTMLElement {} 1289 | interface HTMLBRElement extends HTMLElement {} 1290 | interface HTMLButtonElement extends HTMLElement {} 1291 | interface HTMLCanvasElement extends HTMLElement {} 1292 | interface HTMLDataElement extends HTMLElement {} 1293 | interface HTMLDataListElement extends HTMLElement {} 1294 | interface HTMLDetailsElement extends HTMLElement {} 1295 | interface HTMLDialogElement extends HTMLElement {} 1296 | interface HTMLDivElement extends HTMLElement {} 1297 | interface HTMLDListElement extends HTMLElement {} 1298 | interface HTMLEmbedElement extends HTMLElement {} 1299 | interface HTMLFieldSetElement extends HTMLElement {} 1300 | interface HTMLFormElement extends HTMLElement {} 1301 | interface HTMLHeadingElement extends HTMLElement {} 1302 | interface HTMLHeadElement extends HTMLElement {} 1303 | interface HTMLHRElement extends HTMLElement {} 1304 | interface HTMLHtmlElement extends HTMLElement {} 1305 | interface HTMLIFrameElement extends HTMLElement {} 1306 | interface HTMLImageElement extends HTMLElement {} 1307 | interface HTMLInputElement extends HTMLElement {} 1308 | interface HTMLModElement extends HTMLElement {} 1309 | interface HTMLLabelElement extends HTMLElement {} 1310 | interface HTMLLegendElement extends HTMLElement {} 1311 | interface HTMLLIElement extends HTMLElement {} 1312 | interface HTMLLinkElement extends HTMLElement {} 1313 | interface HTMLMapElement extends HTMLElement {} 1314 | interface HTMLMetaElement extends HTMLElement {} 1315 | interface HTMLMeterElement extends HTMLElement {} 1316 | interface HTMLObjectElement extends HTMLElement {} 1317 | interface HTMLOListElement extends HTMLElement {} 1318 | interface HTMLOptGroupElement extends HTMLElement {} 1319 | interface HTMLOptionElement extends HTMLElement {} 1320 | interface HTMLOutputElement extends HTMLElement {} 1321 | interface HTMLParagraphElement extends HTMLElement {} 1322 | interface HTMLParamElement extends HTMLElement {} 1323 | interface HTMLPreElement extends HTMLElement {} 1324 | interface HTMLProgressElement extends HTMLElement {} 1325 | interface HTMLQuoteElement extends HTMLElement {} 1326 | interface HTMLSlotElement extends HTMLElement {} 1327 | interface HTMLScriptElement extends HTMLElement {} 1328 | interface HTMLSelectElement extends HTMLElement {} 1329 | interface HTMLSourceElement extends HTMLElement {} 1330 | interface HTMLSpanElement extends HTMLElement {} 1331 | interface HTMLStyleElement extends HTMLElement {} 1332 | interface HTMLTableElement extends HTMLElement {} 1333 | interface HTMLTableColElement extends HTMLElement {} 1334 | interface HTMLTableDataCellElement extends HTMLElement {} 1335 | interface HTMLTableHeaderCellElement extends HTMLElement {} 1336 | interface HTMLTableRowElement extends HTMLElement {} 1337 | interface HTMLTableSectionElement extends HTMLElement {} 1338 | interface HTMLTemplateElement extends HTMLElement {} 1339 | interface HTMLTextAreaElement extends HTMLElement {} 1340 | interface HTMLTimeElement extends HTMLElement {} 1341 | interface HTMLTitleElement extends HTMLElement {} 1342 | interface HTMLTrackElement extends HTMLElement {} 1343 | interface HTMLUListElement extends HTMLElement {} 1344 | interface HTMLVideoElement extends HTMLElement {} 1345 | interface HTMLWebViewElement extends HTMLElement {} 1346 | interface SVGElement extends Element {} 1347 | interface SVGSVGElement extends SVGElement {} 1348 | interface SVGCircleElement extends SVGElement {} 1349 | interface SVGClipPathElement extends SVGElement {} 1350 | interface SVGDefsElement extends SVGElement {} 1351 | interface SVGDescElement extends SVGElement {} 1352 | interface SVGEllipseElement extends SVGElement {} 1353 | interface SVGFEBlendElement extends SVGElement {} 1354 | interface SVGFEColorMatrixElement extends SVGElement {} 1355 | interface SVGFEComponentTransferElement extends SVGElement {} 1356 | interface SVGFECompositeElement extends SVGElement {} 1357 | interface SVGFEConvolveMatrixElement extends SVGElement {} 1358 | interface SVGFEDiffuseLightingElement extends SVGElement {} 1359 | interface SVGFEDisplacementMapElement extends SVGElement {} 1360 | interface SVGFEDistantLightElement extends SVGElement {} 1361 | interface SVGFEDropShadowElement extends SVGElement {} 1362 | interface SVGFEFloodElement extends SVGElement {} 1363 | interface SVGFEFuncAElement extends SVGElement {} 1364 | interface SVGFEFuncBElement extends SVGElement {} 1365 | interface SVGFEFuncGElement extends SVGElement {} 1366 | interface SVGFEFuncRElement extends SVGElement {} 1367 | interface SVGFEGaussianBlurElement extends SVGElement {} 1368 | interface SVGFEImageElement extends SVGElement {} 1369 | interface SVGFEMergeElement extends SVGElement {} 1370 | interface SVGFEMergeNodeElement extends SVGElement {} 1371 | interface SVGFEMorphologyElement extends SVGElement {} 1372 | interface SVGFEOffsetElement extends SVGElement {} 1373 | interface SVGFEPointLightElement extends SVGElement {} 1374 | interface SVGFESpecularLightingElement extends SVGElement {} 1375 | interface SVGFESpotLightElement extends SVGElement {} 1376 | interface SVGFETileElement extends SVGElement {} 1377 | interface SVGFETurbulenceElement extends SVGElement {} 1378 | interface SVGFilterElement extends SVGElement {} 1379 | interface SVGForeignObjectElement extends SVGElement {} 1380 | interface SVGGElement extends SVGElement {} 1381 | interface SVGImageElement extends SVGElement {} 1382 | interface SVGLineElement extends SVGElement {} 1383 | interface SVGLinearGradientElement extends SVGElement {} 1384 | interface SVGMarkerElement extends SVGElement {} 1385 | interface SVGMaskElement extends SVGElement {} 1386 | interface SVGMetadataElement extends SVGElement {} 1387 | interface SVGPathElement extends SVGElement {} 1388 | interface SVGPatternElement extends SVGElement {} 1389 | interface SVGPolygonElement extends SVGElement {} 1390 | interface SVGPolylineElement extends SVGElement {} 1391 | interface SVGRadialGradientElement extends SVGElement {} 1392 | interface SVGRectElement extends SVGElement {} 1393 | interface SVGStopElement extends SVGElement {} 1394 | interface SVGSwitchElement extends SVGElement {} 1395 | interface SVGSymbolElement extends SVGElement {} 1396 | interface SVGTextElement extends SVGElement {} 1397 | interface SVGTextPathElement extends SVGElement {} 1398 | interface SVGTSpanElement extends SVGElement {} 1399 | interface SVGUseElement extends SVGElement {} 1400 | interface SVGViewElement extends SVGElement {} 1401 | export namespace CSS { 1402 | export interface Properties { 1403 | [key: string]: string | number | TLength | TTime | null | undefined; 1404 | } 1405 | } 1406 | } 1407 | 1408 | export { hjsx, fragment }; 1409 | -------------------------------------------------------------------------------- /util/index.test.ts: -------------------------------------------------------------------------------- 1 | import { escapeHtml } from '.'; 2 | import { describe, expect, it } from 'bun:test'; 3 | 4 | describe('escapeHtml', () => { 5 | it('should escape special HTML characters', () => { 6 | expect(escapeHtml('Hello, & "everyone"!')).toBe('Hello, <world> & "everyone"!'); 7 | expect(escapeHtml('1 < 2 & 3 > 4')).toBe('1 < 2 & 3 > 4'); 8 | expect(escapeHtml('Use "quotes" and \'apostrophes\' wisely')).toBe('Use "quotes" and 'apostrophes' wisely'); 9 | }); 10 | 11 | it('should not escape already escaped HTML entities', () => { 12 | expect(escapeHtml('Hello, <world> & "everyone"!')).toBe('Hello, &lt;world&gt; &amp; &quot;everyone&quot;!'); 13 | }); 14 | 15 | it('should handle empty strings', () => { 16 | expect(escapeHtml('')).toBe(''); 17 | }); 18 | 19 | it('should handle strings without special characters', () => { 20 | expect(escapeHtml('Hello, world!')).toBe('Hello, world!'); 21 | }); 22 | 23 | it('should handle strings with only special characters', () => { 24 | expect(escapeHtml('<>&"\'')).toBe('<>&"''); 25 | }); 26 | }); -------------------------------------------------------------------------------- /util/index.ts: -------------------------------------------------------------------------------- 1 | export { normalizeAttributeName } from "./normalize-attribute-name.ts"; 2 | 3 | const escapeMap: Record = { 4 | "&": "&", 5 | "<": "<", 6 | ">": ">", 7 | '"': """, 8 | "'": "'", 9 | }; 10 | 11 | const regex = new RegExp(`[${Object.keys(escapeMap).join("")}]`, "g"); 12 | 13 | export function escapeHtml(str: string) { 14 | let html = ""; 15 | let matchIndex: number | undefined; 16 | let lastIndex = 0; 17 | let char: string; 18 | while (true) { 19 | matchIndex = regex.exec(str)?.index; 20 | if (matchIndex === undefined) break; 21 | html += str.slice(lastIndex, matchIndex); 22 | char = str[matchIndex]; 23 | html += escapeMap[char]; 24 | lastIndex = matchIndex + 1; 25 | } 26 | html += str.slice(lastIndex); 27 | return html; 28 | } 29 | 30 | export function uuid(): string { 31 | const parts = [ 32 | random_alphanumeric(8), 33 | random_alphanumeric(4), 34 | random_alphanumeric(4), 35 | random_alphanumeric(4), 36 | random_alphanumeric(12), 37 | ]; 38 | return parts.join("-"); 39 | } 40 | 41 | function random_alphanumeric(len: number): string { 42 | let str = ""; 43 | for (let i = 0; i < len; i++) { 44 | str += Math.floor(Math.random() * 36).toString(36); 45 | } 46 | return str; 47 | } 48 | 49 | export function isPrimitive(value: unknown): value is string | number | boolean { 50 | return typeof value === "string" || typeof value === "number" || typeof value === "boolean"; 51 | } 52 | 53 | export function isNullish(value: unknown): value is null | undefined { 54 | return value === null || value === undefined; 55 | } 56 | 57 | export function isIterable(value: unknown): value is Iterable { 58 | return Symbol.iterator in Object(value) && typeof value !== "string"; 59 | } 60 | 61 | export function isObject(value: unknown): value is Record { 62 | return typeof value === "object" && value !== null; 63 | } 64 | 65 | export function isClassConstructor(fn: unknown): fn is new (...args: any[]) => any { 66 | return typeof fn === "function" && fn.toString().trim().startsWith("class"); 67 | } 68 | 69 | export function dangerouslySetInnerHTML(value: unknown): string { 70 | if (typeof value !== "object" || value === null) { 71 | throw new Error("dangerouslySetInnerHTML must be an object"); 72 | } 73 | if (!("__html" in value)) { 74 | throw new Error("dangerouslySetInnerHTML must have an __html property"); 75 | } 76 | return String(value.__html); 77 | } 78 | 79 | export function handleStyle(value: unknown): string { 80 | if (typeof value !== "object" || value === null) { 81 | throw new Error("style must be an object"); 82 | } 83 | return Object.entries(value) 84 | .map(([key, value]) => `${toKebabCase(key)}: ${value}`) 85 | .join("; "); 86 | } 87 | 88 | function toKebabCase(str: string) { 89 | return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`); 90 | } 91 | 92 | export const SELF_CLOSING_TAGS = [ 93 | "area", 94 | "base", 95 | "br", 96 | "col", 97 | "command", 98 | "embed", 99 | "hr", 100 | "img", 101 | "input", 102 | "keygen", 103 | "link", 104 | "meta", 105 | "param", 106 | "source", 107 | "track", 108 | "wbr", 109 | ]; 110 | 111 | export const colors = { 112 | green(text: string) { 113 | return `\x1b[32m${text}\x1b[0m`; 114 | }, 115 | red(text: string) { 116 | return `\x1b[31m${text}\x1b[0m`; 117 | }, 118 | yellow(text: string) { 119 | return `\x1b[33m${text}\x1b[0m`; 120 | }, 121 | gray(text: string) { 122 | return `\x1b[90m${text}\x1b[0m`; 123 | }, 124 | } as const; 125 | -------------------------------------------------------------------------------- /util/normalize-attribute-name.ts: -------------------------------------------------------------------------------- 1 | export function normalizeAttributeName(attribute: string) { 2 | if (attributes.html.includes(attribute)) { 3 | return toHtmlAttribute(attribute); 4 | } 5 | if (attributes.svg.includes(attribute)) { 6 | return toSvgAttribute(attribute); 7 | } 8 | return attribute; 9 | } 10 | 11 | const attributes = { 12 | 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" as const, 13 | 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" as const, 14 | }; 15 | 16 | const exceptions: { html: Record; svg: Record } = { 17 | html: { 18 | acceptCharset: "accept-charset", 19 | className: "class", 20 | htmlFor: "for", 21 | httpEquiv: "http-equiv", 22 | defaultChecked: "checked", 23 | }, 24 | svg: { 25 | panose1: "panose-1", 26 | xlinkActuate: "xlink:actuate", 27 | xlinkArcrole: "xlink:arcrole", 28 | xlinkHref: "xlink:href", 29 | xlinkRole: "xlink:role", 30 | xlinkShow: "xlink:show", 31 | xlinkTitle: "xlink:title", 32 | xlinkType: "xlink:type", 33 | xmlBase: "xml:base", 34 | xmlLang: "xml:lang", 35 | xmlSpace: "xml:space", 36 | xmlnsXlink: "xmlns:xlink", 37 | xmlns: "xmlns", 38 | zoomAndPan: "zoomAndPan", 39 | }, 40 | }; 41 | 42 | function toHtmlAttribute(attribute: string) { 43 | if (exceptions.html[attribute]) { 44 | return exceptions.html[attribute]; 45 | } 46 | return attribute.toLowerCase(); 47 | } 48 | 49 | function toSvgAttribute(attribute: string) { 50 | if (exceptions.svg[attribute]) { 51 | return exceptions.svg[attribute]; 52 | } 53 | return attribute.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`); 54 | } 55 | -------------------------------------------------------------------------------- /util/rm-comments.ts: -------------------------------------------------------------------------------- 1 | const file = Bun.file("./react.d.ts"); 2 | console.log(`Input size: ${file.size} bytes`); 3 | const content = await file.text(); 4 | const output = [content] 5 | .map(removeBlockComments) 6 | .map(removeLineComments) 7 | .map(removeEmptyLines) 8 | .join(""); 9 | const bytesWritten = await Bun.write("./types.d.ts", output); 10 | console.log(`Output size: ${bytesWritten} bytes`); 11 | 12 | function removeBlockComments(input: string): string { 13 | const multiLineCommentPattern = /\/\*\*?[\s\S]*?\*\//gm; 14 | return input.replace(multiLineCommentPattern, ""); 15 | } 16 | 17 | function removeLineComments(input: string): string { 18 | const lineCommentPattern = /\/\/.*/gm; 19 | return input.replace(lineCommentPattern, ""); 20 | } 21 | 22 | function removeEmptyLines(input: string): string { 23 | const emptyLinePattern = /^\s*[\r\n]/gm; 24 | return input.replace(emptyLinePattern, ""); 25 | } 26 | --------------------------------------------------------------------------------