├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── README.md ├── astro.config.mts ├── astro ├── assets │ ├── logo-dark.svg │ └── logo-light.svg ├── components │ ├── Benchmarks.astro │ ├── SiteTitle.astro │ └── playground │ │ ├── Playground.astro │ │ ├── form.tsx │ │ ├── result.tsx │ │ ├── styles │ │ ├── form.module.css │ │ ├── result.module.css │ │ └── toast.module.css │ │ └── ui │ │ ├── toast.tsx │ │ ├── toaster.tsx │ │ └── use-toast.ts ├── content │ ├── config.ts │ └── docs │ │ ├── cli │ │ ├── index.md │ │ └── performance.md │ │ ├── clients │ │ ├── cpp.mdx │ │ ├── d.md │ │ ├── go.mdx │ │ ├── luajit.md │ │ ├── python.mdx │ │ └── rust.md │ │ ├── index.mdx │ │ ├── installation.mdx │ │ ├── introduction.md │ │ ├── performance.mdx │ │ └── playground.mdx ├── custom.css └── env.d.ts ├── biome.jsonc ├── lib └── wasm │ ├── wasm.js │ └── wasm.wasm ├── package.json ├── pnpm-lock.yaml ├── public ├── ada.png ├── ada.svg ├── android-chrome-192x192.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── fonts │ └── Inter-SemiBold.woff ├── mstile-150x150.png ├── safari-pinned-tab.svg └── site.webmanifest ├── tailwind.config.js └── tsconfig.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | enable-beta-ecosystems: true 3 | updates: 4 | - package-ecosystem: npm 5 | directory: "/" 6 | open-pull-requests-limit: 10 7 | schedule: 8 | interval: monthly 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: linter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | # This allows a subsequently queued workflow run to interrupt previous runs 12 | concurrency: 13 | group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}" 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: read 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | persist-credentials: false 25 | 26 | - name: Setup Biome 27 | uses: biomejs/setup-biome@v2 28 | 29 | - name: Lint 30 | run: biome ci . 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | 37 | .contentlayer 38 | 39 | # Astro 40 | /.astro 41 | /dist 42 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Ref: https://pnpm.io/npmrc#manage-package-manager-versions 2 | # When enabled, pnpm will automatically download and run the version of pnpm 3 | # specified in the packageManager field of package.json. 4 | manage-package-manager-versions = true 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Getting started 2 | 3 | `ada-url.com` requires Node.js 20 with [pnpm](https://pnpm.io) to install dependencies. 4 | 5 | - To install `pnpm` follow the steps in https://pnpm.io/installation. 6 | - To build locally, run `pnpm install` in the root repository and navigate to `http://localhost:3000` 7 | - To run the linter, run `pnpm run lint-fix` 8 | 9 | ## Documentation 10 | 11 | All documentation lives inside `contents/docs` folder 12 | 13 | ## Credits 14 | 15 | - Components of this website is developed by `ui.shadcn.com` 16 | -------------------------------------------------------------------------------- /astro.config.mts: -------------------------------------------------------------------------------- 1 | import starlight from '@astrojs/starlight' 2 | import { defineConfig } from 'astro/config' 3 | 4 | import react from '@astrojs/react' 5 | 6 | import tailwind from '@astrojs/tailwind' 7 | 8 | // https://astro.build/config 9 | export default defineConfig({ 10 | srcDir: './astro', 11 | site: 'https://www.ada-url.com', 12 | vite: { 13 | build: { 14 | rollupOptions: { 15 | // For some reason, the build crashes without this 16 | external: ['sharp'], 17 | }, 18 | }, 19 | }, 20 | integrations: [ 21 | starlight({ 22 | // https://starlight.astro.build/reference/configuration 23 | title: 'Ada URL', 24 | social: { 25 | github: 'https://github.com/ada-url/ada', 26 | }, 27 | sidebar: [ 28 | { 29 | label: 'Getting Started', 30 | items: ['introduction', 'installation'], 31 | }, 32 | { 33 | label: 'CLI', 34 | items: [ 35 | { 36 | label: 'Introduction', 37 | slug: 'cli', 38 | }, 39 | { 40 | label: 'Performance', 41 | slug: 'cli/performance', 42 | }, 43 | ], 44 | }, 45 | { 46 | label: 'Supported Languages', 47 | items: [ 48 | { 49 | label: 'C++ client', 50 | slug: 'clients/cpp', 51 | }, 52 | { 53 | label: 'Rust client', 54 | slug: 'clients/rust', 55 | }, 56 | { 57 | label: 'Python client', 58 | slug: 'clients/python', 59 | }, 60 | { 61 | label: 'Go client', 62 | slug: 'clients/go', 63 | }, 64 | { 65 | label: 'LuaJIT client', 66 | slug: 'clients/luajit', 67 | }, 68 | { 69 | label: 'D client', 70 | slug: 'clients/d', 71 | }, 72 | ], 73 | }, 74 | ], 75 | components: { 76 | SiteTitle: './astro/components/SiteTitle.astro', 77 | }, 78 | favicon: './favicon-32x32.png', 79 | logo: { 80 | light: './astro/assets/logo-light.svg', 81 | dark: './astro/assets/logo-dark.svg', 82 | replacesTitle: true, 83 | }, 84 | customCss: [ 85 | // Relative path to your custom CSS file 86 | './astro/custom.css', 87 | ], 88 | editLink: { 89 | baseUrl: 'https://github.com/ada-url/website/edit/main', 90 | }, 91 | titleDelimiter: '-', 92 | credits: false, 93 | }), 94 | react(), 95 | tailwind(), 96 | ], 97 | }) 98 | -------------------------------------------------------------------------------- /astro/assets/logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /astro/assets/logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /astro/components/Benchmarks.astro: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Ada is fast

4 |

5 | On a benchmark where we need to validate and normalize{" "} 6 | 9 | thousands of URLs found on popular websites 10 | {" "} we find that ada can be several times faster than popular competitors. 11 |

12 |
13 |
14 |
15 | 16 |
17 |
18 |
19 | 20 | 94 | 95 | -------------------------------------------------------------------------------- /astro/components/SiteTitle.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import AstrolightSiteTitle from '@astrojs/starlight/components/SiteTitle.astro' 3 | import type { Props } from '@astrojs/starlight/props' 4 | 5 | const menuItems = [ 6 | { name: 'Docs', href: '/introduction' }, 7 | { name: 'Performance', href: '/performance' }, 8 | { name: 'Playground', href: '/playground' }, 9 | ] 10 | 11 | function pathsMatch(lhs: string, rhs: string): boolean { 12 | return rhs.includes(lhs) 13 | } 14 | --- 15 | 16 |
17 | 18 | 19 |
20 | 21 | 35 |
36 | 37 | 77 | -------------------------------------------------------------------------------- /astro/components/playground/Playground.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import PlaygroundForm from './form' 3 | import { Toaster } from './ui/toaster' 4 | --- 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /astro/components/playground/form.tsx: -------------------------------------------------------------------------------- 1 | import WASM from '@/lib/wasm/wasm.js' 2 | import { ChevronDown, Loader2 } from 'lucide-react' 3 | import { useCallback, useEffect, useState } from 'react' 4 | import { useForm } from 'react-hook-form' 5 | import ParsingResult, { type WASMResponse } from './result' 6 | import styles from './styles/form.module.css' 7 | import { useToast } from './ui/use-toast' 8 | 9 | let wasm: { 10 | parse: (url: string) => WASMResponse & { delete: VoidFunction } 11 | } 12 | 13 | const versions = ['2.9.2', '2.9.1', '2.9.0', '2.8.0'] 14 | 15 | function toJS(obj: Record): any { 16 | const result: Record = {} 17 | for (const key in obj.__proto__) { 18 | result[key] = typeof obj[key] === 'object' ? toJS(obj[key]) : obj[key] 19 | } 20 | return result 21 | } 22 | 23 | export default function PlaygroundForm() { 24 | const { toast } = useToast() 25 | const { handleSubmit, register, formState } = useForm<{ url: string; version: string }>() 26 | const [output, setOutput] = useState() 27 | 28 | const [defaultValue, setDefaultValue] = useState() 29 | const onSubmit = useCallback( 30 | async (data: { url: string; version: string }) => { 31 | try { 32 | wasm ??= await WASM() 33 | const result = wasm.parse(data.url) 34 | setOutput(toJS(result)) 35 | result.delete() 36 | history.replaceState({}, '', `/playground?url=${encodeURIComponent(data.url)}`) 37 | } catch (error) { 38 | if (error instanceof Error) { 39 | toast({ 40 | title: 'An error occurred', 41 | description: error.message, 42 | }) 43 | } 44 | setOutput(undefined) 45 | } 46 | }, 47 | [toast], 48 | ) 49 | 50 | // This function only runs on mounting/refresh to set initial default value 51 | useEffect(() => { 52 | const searchParams = new URLSearchParams(window.location.search) 53 | const search = searchParams.get('url') 54 | const value = search ? decodeURI(search) : window.location.href 55 | setDefaultValue(value) 56 | onSubmit({ url: value, version: versions.at(0) ?? '' }) 57 | }, [onSubmit]) 58 | 59 | return ( 60 |
61 |
62 | 72 | 73 |
74 | 82 | 83 | 87 |
88 |
89 | 90 | {output !== undefined ? : null} 91 |
92 | ) 93 | } 94 | -------------------------------------------------------------------------------- /astro/components/playground/result.tsx: -------------------------------------------------------------------------------- 1 | import * as Tabs from '@radix-ui/react-tabs' 2 | import { Terminal } from 'lucide-react' 3 | import styles from './styles/result.module.css' 4 | 5 | export type WASMResponse = 6 | | { 7 | components: { 8 | hash_start: number 9 | host_end: number 10 | host_start: number 11 | pathname_start: number 12 | port: number 13 | protocol_end: number 14 | search_start: number 15 | username_end: number 16 | } 17 | href: string 18 | result: 'success' 19 | type: number 20 | } 21 | | { 22 | result: 'fail' 23 | } 24 | 25 | function getDiagram(props: WASMResponse) { 26 | if (props.result === 'fail') { 27 | return null 28 | } 29 | 30 | const { components } = props 31 | 32 | const omitted = 4294967295 33 | const lines: string[][] = [props.href.split(''), new Array(props.href.length).fill(' ')] 34 | 35 | const omittable_values = [components.hash_start, components.search_start] 36 | 37 | for (const value of omittable_values) { 38 | if (value !== omitted) { 39 | lines[1][value] = '|' 40 | } 41 | } 42 | 43 | const non_omittable_values = [ 44 | components.pathname_start, 45 | components.host_end, 46 | components.host_start, 47 | components.username_end, 48 | components.protocol_end, 49 | ] 50 | 51 | for (const value of non_omittable_values) { 52 | if (value !== props.href.length) { 53 | lines[1][value] = '|' 54 | } 55 | } 56 | 57 | const line2 = lines[1].slice() 58 | if (components.hash_start !== omitted) { 59 | line2[components.hash_start] = '`' 60 | 61 | for (let i = components.hash_start + 1; i < line2.length; i++) { 62 | line2[i] = '-' 63 | } 64 | line2.push(` hash_start ${components.hash_start}`) 65 | lines.push(line2) 66 | } 67 | 68 | const line3 = lines[1].slice() 69 | if (components.search_start !== omitted) { 70 | line3[components.search_start] = '`' 71 | 72 | for (let i = components.search_start + 1; i < line3.length; i++) { 73 | line3[i] = '-' 74 | } 75 | line3.push(` search_start ${components.search_start}`) 76 | lines.push(line3) 77 | } 78 | 79 | const line4 = lines[1].slice() 80 | if (components.pathname_start !== props.href.length) { 81 | line4[components.pathname_start] = '`' 82 | for (let i = components.pathname_start + 1; i < line4.length; i++) { 83 | line4[i] = '-' 84 | } 85 | line4.push(` pathname_start ${components.pathname_start}`) 86 | lines.push(line4) 87 | } 88 | 89 | const line5 = lines[1].slice() 90 | if (components.host_end !== props.href.length) { 91 | line5[components.host_end] = '`' 92 | 93 | for (let i = components.host_end + 1; i < line5.length; i++) { 94 | line5[i] = '-' 95 | } 96 | line5.push(` host_end ${components.host_end}`) 97 | lines.push(line5) 98 | } 99 | 100 | const line6 = lines[1].slice() 101 | if (components.host_start !== props.href.length) { 102 | line6[components.host_start] = '`' 103 | 104 | for (let i = components.host_start + 1; i < line6.length; i++) { 105 | line6[i] = '-' 106 | } 107 | 108 | line6.push(` host_start ${components.host_start}`) 109 | lines.push(line6) 110 | } 111 | 112 | const line7: string[] = lines[1].slice() 113 | if (components.username_end !== props.href.length) { 114 | line7[components.username_end] = '`' 115 | 116 | for (let i = components.username_end + 1; i < line7.length; i++) { 117 | line7[i] = '-' 118 | } 119 | line7.push(` username_end ${components.username_end}`) 120 | lines.push(line7) 121 | } 122 | 123 | const line8 = lines[1].slice() 124 | if (components.protocol_end !== props.href.length) { 125 | line8[components.protocol_end] = '`' 126 | 127 | for (let i = components.protocol_end + 1; i < line8.length; i++) { 128 | line8[i] = '-' 129 | } 130 | line8.push(` protocol_end ${components.protocol_end}`) 131 | lines.push(line8) 132 | } 133 | return lines.map((line) => line.join('')).join('\n') 134 | } 135 | 136 | export default function ParsingResult(props: WASMResponse) { 137 | const alert = ( 138 |
139 | 140 |
141 | {props.result === 'success' ? 'Parsing successful!' : 'Parsing failed!'} 142 |
143 |

144 | {props.result === 'success' 145 | ? `Input resolved into "${props.href}"` 146 | : 'We could not parse this input. It is invalid.'} 147 |

148 |
149 | ) 150 | 151 | if (props.result !== 'success') { 152 | return alert 153 | } 154 | 155 | return ( 156 | <> 157 | {alert} 158 | 159 | 160 | 161 | 162 | Diagram 163 | 164 | 165 | Raw Output 166 | 167 | 168 | 169 |
{getDiagram(props)}
170 |
171 | 172 |
{JSON.stringify(props, null, 2)}
173 |
174 |
175 | 176 | ) 177 | } 178 | -------------------------------------------------------------------------------- /astro/components/playground/styles/form.module.css: -------------------------------------------------------------------------------- 1 | .formContainer { 2 | display: flex; 3 | flex-direction: column; 4 | row-gap: 1rem; 5 | } 6 | 7 | form { 8 | display: flex; 9 | flex-direction: column; 10 | row-gap: 1rem; 11 | } 12 | 13 | form > div { 14 | display: flex; 15 | flex-direction: row; 16 | column-gap: 1rem; 17 | } 18 | 19 | .loader { 20 | margin-right: 0.5rem; 21 | width: 1rem; 22 | height: 1rem; 23 | animation: spin 1s linear infinite; 24 | } 25 | 26 | .Button { 27 | display: inline-flex; 28 | align-items: center; 29 | justify-content: center; 30 | border-radius: 0.5rem; 31 | font-size: var(--sl-text-sm); 32 | font-weight: 600; 33 | background-color: var(--sl-color-gray-1); 34 | color: var(--sl-color-black); 35 | height: 2.5rem; 36 | width: fit-content; 37 | padding-inline: 1rem; 38 | outline-offset: 0.25rem; 39 | border-width: 0; 40 | } 41 | 42 | .Button:hover { 43 | cursor: pointer; 44 | } 45 | 46 | .Button:disabled { 47 | pointer-events: none; 48 | opacity: 0.5; 49 | } 50 | 51 | .Input { 52 | display: flex; 53 | width: 100%; 54 | height: 2.5rem; 55 | border-radius: 0.5rem; 56 | border: 1px solid var(--sl-color-gray-5); 57 | background-color: var(--sl-color-black); 58 | padding-block: 0.5rem; 59 | font-size: var(--sl-text-base); 60 | color: var(--sl-color-gray-2); 61 | padding-left: 0.5rem; 62 | } 63 | 64 | .Input:hover { 65 | border: 1px solid var(--sl-color-white); 66 | } 67 | 68 | .Input:disabled { 69 | cursor: not-allowed; 70 | opacity: 0.5; 71 | } 72 | 73 | .Label { 74 | position: relative; 75 | display: flex; 76 | justify-content: flex-end; 77 | align-items: center; 78 | gap: 0.25rem; 79 | color: var(--sl-color-gray-1); 80 | } 81 | 82 | .Icon { 83 | position: absolute; 84 | top: 50%; 85 | transform: translateY(-50%); 86 | pointer-events: none; 87 | } 88 | 89 | .Caret { 90 | width: 1rem; 91 | height: 1rem; 92 | inset-inline-end: 0; 93 | } 94 | 95 | .Select { 96 | align-self: self-end; 97 | background-color: transparent; 98 | text-overflow: ellipsis; 99 | color: inherit; 100 | cursor: pointer; 101 | appearance: none; 102 | font-size: var(--sl-text-sm); 103 | border: 0; 104 | padding-inline: 1.25rem; 105 | } 106 | 107 | .Option { 108 | background-color: var(--sl-color-bg-nav); 109 | color: var(--sl-color-gray-1); 110 | } 111 | 112 | @media (min-width: 50rem) { 113 | .Button { 114 | width: 8rem; 115 | } 116 | } 117 | @keyframes spin { 118 | from { 119 | transform: rotate(0deg); 120 | } 121 | to { 122 | transform: rotate(360deg); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /astro/components/playground/styles/result.module.css: -------------------------------------------------------------------------------- 1 | .Terminal { 2 | width: 1rem; 3 | height: 1rem; 4 | } 5 | 6 | .Alert { 7 | position: relative; 8 | padding: 1rem; 9 | border-radius: 0.5rem; 10 | width: 100%; 11 | font-size: var(--sl-text-base); 12 | border: 1px solid var(--sl-color-gray-5); 13 | background-color: var(--sl-color-black); 14 | } 15 | 16 | .Alert > svg { 17 | position: absolute; 18 | left: 1rem; 19 | top: 1rem; 20 | } 21 | 22 | .AlertTitle { 23 | font-size: var(--sl-text-h5); 24 | margin-bottom: 0.25rem; 25 | font-weight: 500; 26 | line-height: 1; 27 | padding-left: 1.75rem; 28 | } 29 | 30 | .AlertDescription { 31 | line-height: var(--sl-line-height); 32 | padding-left: 1.75rem; 33 | } 34 | 35 | .Root { 36 | width: 100%; 37 | padding: 0.25rem 0rem; 38 | } 39 | 40 | .TabsList { 41 | display: flex; 42 | height: 2.5rem; 43 | border-bottom: 2px solid var(--sl-color-gray-5); 44 | } 45 | 46 | .TabsTrigger { 47 | display: flex; 48 | appearance: none; 49 | align-items: center; 50 | margin-bottom: -2px; 51 | padding: 0 1.25rem; 52 | border-width: 0 0 2px 0; 53 | border-bottom: solid var(--sl-color-gray-5); 54 | color: var(--sl-color-gray-3); 55 | outline-offset: var(--sl-outline-offset-inside); 56 | background-color: var(--sl-color-bg); 57 | } 58 | 59 | .TabsTrigger:disabled { 60 | pointer-events: none; 61 | opacity: 0.5; 62 | } 63 | 64 | .TabsTrigger[data-state="active"] { 65 | color: var(--sl-color-white); 66 | border-color: var(--sl-color-text-accent); 67 | font-weight: 600; 68 | } 69 | 70 | .TabsContent { 71 | margin-top: 0.5rem; 72 | outline-offset: 0.25rem; 73 | border: 1px solid var(--sl-color-gray-5); 74 | background-color: var(--sl-color-bg-inline-code); 75 | } 76 | 77 | .TabsContent pre { 78 | border-radius: 0.5rem; 79 | padding: 1rem; 80 | color: var(--sl-color-white); 81 | font-family: var(--sl-font-system-mono); 82 | overflow-x: auto; 83 | } 84 | -------------------------------------------------------------------------------- /astro/components/playground/styles/toast.module.css: -------------------------------------------------------------------------------- 1 | .Viewport { 2 | --viewport-padding: 25px; 3 | position: fixed; 4 | bottom: 0; 5 | right: 0; 6 | display: flex; 7 | flex-direction: column; 8 | padding: var(--viewport-padding); 9 | gap: 10px; 10 | width: 390px; 11 | max-width: 100vw; 12 | margin: 0; 13 | list-style: none; 14 | z-index: 2147483647; 15 | outline: none; 16 | } 17 | 18 | .Root { 19 | position: relative; 20 | color: white; 21 | font-size: var(--sl-text-sm); 22 | background-color: var(--sl-color-toast-red); 23 | border-radius: 0.5rem; 24 | padding: 15px; 25 | display: grid; 26 | grid-template-areas: "title action" "description action"; 27 | grid-template-columns: auto max-content; 28 | column-gap: 15px; 29 | align-items: center; 30 | &[data-state="open"] { 31 | animation: slideIn 150ms cubic-bezier(0.16, 1, 0.3, 1); 32 | } 33 | &[data-state="closed"] { 34 | animation: hide 100ms ease-in; 35 | } 36 | &[data-swipe="move"] { 37 | transform: translateX(var(--radix-toast-swipe-move-x)); 38 | } 39 | &[data-swipe="cancel"] { 40 | transform: translateX(0); 41 | transition: transform 200ms ease-out; 42 | } 43 | &[data-swipe="end"] { 44 | animation: swipeOut 100ms ease-out; 45 | } 46 | } 47 | 48 | @keyframes hide { 49 | from { 50 | opacity: 1; 51 | } 52 | to { 53 | opacity: 0; 54 | } 55 | } 56 | 57 | @keyframes slideIn { 58 | from { 59 | transform: translateX(calc(100% + var(--viewport-padding))); 60 | } 61 | to { 62 | transform: translateX(0); 63 | } 64 | } 65 | 66 | @keyframes swipeOut { 67 | from { 68 | transform: translateX(var(--radix-toast-swipe-end-x)); 69 | } 70 | to { 71 | transform: translateX(calc(100% + var(--viewport-padding))); 72 | } 73 | } 74 | 75 | .Title { 76 | grid-area: title; 77 | font-weight: 500; 78 | } 79 | 80 | .Description { 81 | grid-area: description; 82 | margin: 0; 83 | opacity: 0.9; 84 | } 85 | 86 | .Action { 87 | grid-area: action; 88 | } 89 | 90 | .Close { 91 | position: absolute; 92 | top: 0.5rem; 93 | right: 0.5rem; 94 | background-color: var(--sl-color-toast-red); 95 | border: 0; 96 | padding: 0.25rem 0.5rem; 97 | } 98 | 99 | .X { 100 | height: 1rem; 101 | width: 1rem; 102 | } 103 | -------------------------------------------------------------------------------- /astro/components/playground/ui/toast.tsx: -------------------------------------------------------------------------------- 1 | import * as ToastPrimitives from '@radix-ui/react-toast' 2 | import { X } from 'lucide-react' 3 | import * as React from 'react' 4 | import styles from '../styles/toast.module.css' 5 | 6 | const ToastProvider = ToastPrimitives.Provider 7 | 8 | const ToastViewport = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ ...props }, ref) => ( 12 | 13 | )) 14 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName 15 | 16 | const Toast = React.forwardRef< 17 | React.ElementRef, 18 | React.ComponentPropsWithoutRef 19 | >(({ className, ...props }, ref) => { 20 | return 21 | }) 22 | Toast.displayName = ToastPrimitives.Root.displayName 23 | 24 | const ToastAction = React.forwardRef< 25 | React.ElementRef, 26 | React.ComponentPropsWithoutRef 27 | >(({ ...props }, ref) => ) 28 | ToastAction.displayName = ToastPrimitives.Action.displayName 29 | 30 | const ToastClose = React.forwardRef< 31 | React.ElementRef, 32 | React.ComponentPropsWithoutRef 33 | >(({ ...props }, ref) => ( 34 | 35 | 36 | 37 | )) 38 | ToastClose.displayName = ToastPrimitives.Close.displayName 39 | 40 | const ToastTitle = React.forwardRef< 41 | React.ElementRef, 42 | React.ComponentPropsWithoutRef 43 | >(({ ...props }, ref) => ) 44 | ToastTitle.displayName = ToastPrimitives.Title.displayName 45 | 46 | const ToastDescription = React.forwardRef< 47 | React.ElementRef, 48 | React.ComponentPropsWithoutRef 49 | >(({ ...props }, ref) => ( 50 | 51 | )) 52 | ToastDescription.displayName = ToastPrimitives.Description.displayName 53 | 54 | type ToastProps = React.ComponentPropsWithoutRef 55 | 56 | type ToastActionElement = React.ReactElement 57 | 58 | export { 59 | type ToastProps, 60 | type ToastActionElement, 61 | ToastProvider, 62 | ToastViewport, 63 | Toast, 64 | ToastTitle, 65 | ToastDescription, 66 | ToastClose, 67 | ToastAction, 68 | } 69 | -------------------------------------------------------------------------------- /astro/components/playground/ui/toaster.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Toast, 3 | ToastClose, 4 | ToastDescription, 5 | ToastProvider, 6 | ToastTitle, 7 | ToastViewport, 8 | } from './toast' 9 | import { useToast } from './use-toast' 10 | 11 | export function Toaster() { 12 | const { toasts } = useToast() 13 | 14 | return ( 15 | 16 | {toasts.map(({ id, title, description, ...props }) => ( 17 | 18 | {title && {title}} 19 | {description && {description}} 20 | 21 | 22 | ))} 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /astro/components/playground/ui/use-toast.ts: -------------------------------------------------------------------------------- 1 | // Inspired by react-hot-toast library 2 | import * as React from 'react' 3 | 4 | import type { ToastActionElement, ToastProps } from './toast' 5 | 6 | const TOAST_LIMIT = 1 7 | const TOAST_REMOVE_DELAY = 1000000 8 | 9 | type ToasterToast = ToastProps & { 10 | id: string 11 | title?: React.ReactNode 12 | description?: React.ReactNode 13 | action?: ToastActionElement 14 | } 15 | 16 | const actionTypes = { 17 | ADD_TOAST: 'ADD_TOAST', 18 | UPDATE_TOAST: 'UPDATE_TOAST', 19 | DISMISS_TOAST: 'DISMISS_TOAST', 20 | REMOVE_TOAST: 'REMOVE_TOAST', 21 | } as const 22 | 23 | let count = 0 24 | 25 | function genId() { 26 | count = (count + 1) % Number.MAX_VALUE 27 | return count.toString() 28 | } 29 | 30 | type ActionType = typeof actionTypes 31 | 32 | type Action = 33 | | { 34 | type: ActionType['ADD_TOAST'] 35 | toast: ToasterToast 36 | } 37 | | { 38 | type: ActionType['UPDATE_TOAST'] 39 | toast: Partial 40 | } 41 | | { 42 | type: ActionType['DISMISS_TOAST'] 43 | toastId?: ToasterToast['id'] 44 | } 45 | | { 46 | type: ActionType['REMOVE_TOAST'] 47 | toastId?: ToasterToast['id'] 48 | } 49 | 50 | interface State { 51 | toasts: ToasterToast[] 52 | } 53 | 54 | const toastTimeouts = new Map>() 55 | 56 | const addToRemoveQueue = (toastId: string) => { 57 | if (toastTimeouts.has(toastId)) { 58 | return 59 | } 60 | 61 | const timeout = setTimeout(() => { 62 | toastTimeouts.delete(toastId) 63 | dispatch({ 64 | type: 'REMOVE_TOAST', 65 | toastId: toastId, 66 | }) 67 | }, TOAST_REMOVE_DELAY) 68 | 69 | toastTimeouts.set(toastId, timeout) 70 | } 71 | 72 | export const reducer = (state: State, action: Action): State => { 73 | switch (action.type) { 74 | case 'ADD_TOAST': 75 | return { 76 | ...state, 77 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 78 | } 79 | 80 | case 'UPDATE_TOAST': 81 | return { 82 | ...state, 83 | toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)), 84 | } 85 | 86 | case 'DISMISS_TOAST': { 87 | const { toastId } = action 88 | 89 | // ! Side effects ! - This could be extracted into a dismissToast() action, 90 | // but I'll keep it here for simplicity 91 | if (toastId) { 92 | addToRemoveQueue(toastId) 93 | } else { 94 | state.toasts.forEach((toast) => { 95 | addToRemoveQueue(toast.id) 96 | }) 97 | } 98 | 99 | return { 100 | ...state, 101 | toasts: state.toasts.map((t) => 102 | t.id === toastId || toastId === undefined 103 | ? { 104 | ...t, 105 | open: false, 106 | } 107 | : t, 108 | ), 109 | } 110 | } 111 | case 'REMOVE_TOAST': 112 | if (action.toastId === undefined) { 113 | return { 114 | ...state, 115 | toasts: [], 116 | } 117 | } 118 | return { 119 | ...state, 120 | toasts: state.toasts.filter((t) => t.id !== action.toastId), 121 | } 122 | } 123 | } 124 | 125 | const listeners: Array<(state: State) => void> = [] 126 | 127 | let memoryState: State = { toasts: [] } 128 | 129 | function dispatch(action: Action) { 130 | memoryState = reducer(memoryState, action) 131 | listeners.forEach((listener) => { 132 | listener(memoryState) 133 | }) 134 | } 135 | 136 | type Toast = Omit 137 | 138 | function toast({ ...props }: Toast) { 139 | const id = genId() 140 | 141 | const update = (props: ToasterToast) => 142 | dispatch({ 143 | type: 'UPDATE_TOAST', 144 | toast: { ...props, id }, 145 | }) 146 | const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }) 147 | 148 | dispatch({ 149 | type: 'ADD_TOAST', 150 | toast: { 151 | ...props, 152 | id, 153 | open: true, 154 | onOpenChange: (open) => { 155 | if (!open) dismiss() 156 | }, 157 | }, 158 | }) 159 | 160 | return { 161 | id: id, 162 | dismiss, 163 | update, 164 | } 165 | } 166 | 167 | function useToast() { 168 | const [state, setState] = React.useState(memoryState) 169 | 170 | // biome-ignore lint/correctness/useExhaustiveDependencies: Ignore for now. 171 | React.useEffect(() => { 172 | listeners.push(setState) 173 | return () => { 174 | const index = listeners.indexOf(setState) 175 | if (index > -1) { 176 | listeners.splice(index, 1) 177 | } 178 | } 179 | }, [state]) 180 | 181 | return { 182 | ...state, 183 | toast, 184 | dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), 185 | } 186 | } 187 | 188 | export { useToast, toast } 189 | -------------------------------------------------------------------------------- /astro/content/config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection } from 'astro:content' 2 | import { docsSchema } from '@astrojs/starlight/schema' 3 | 4 | export const collections = { 5 | docs: defineCollection({ schema: docsSchema() }), 6 | } 7 | -------------------------------------------------------------------------------- /astro/content/docs/cli/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Command line interface 3 | description: How to use adaparse CLI 4 | --- 5 | 6 | The adaparse command tool takes URL strings (ASCII/UTF-8) and it validates, normalizes and queries them efficiently. 7 | 8 | ## Options 9 | 10 | - `-d`, `--diagram`: Print a diagram of the result 11 | - `-u`, `--url`: URL Parameter (required) 12 | - `-h`, `--help`: Print usage 13 | - `-g`, `--get`: Get a specific part of the URL (e.g., 'origin', 'host', etc. as mentioned in the examples above) 14 | - `-b`, `--benchmark`: Run benchmark for piped file functions 15 | - `-p`, `--path`: Process all the URLs in a given file 16 | - `-o`, `--output`: Output the results of the parsing to a file 17 | 18 | ## Usage/Examples 19 | 20 | ### Well-formatted URL 21 | 22 | ```bash 23 | adaparse "http://www.google.com" 24 | ``` 25 | 26 | **Output:** 27 | 28 | ```text 29 | http://www.google.com 30 | ``` 31 | 32 | ### Diagram 33 | 34 | ```bash 35 | adaparse -d http://www.google.com/bal\?a\=\=11\#fddfds 36 | ``` 37 | 38 | **Output:** 39 | 40 | ```text 41 | http://www.google.com/bal?a==11#fddfds [38 bytes] 42 | | | | | | 43 | | | | | `------ hash_start 44 | | | | `------------ search_start 25 45 | | | `---------------- pathname_start 21 46 | | | `---------------- host_end 21 47 | | `------------------------------ host_start 7 48 | | `------------------------------ username_end 7 49 | `-------------------------------- protocol_end 5 50 | ``` 51 | 52 | ### Pipe Operator 53 | 54 | Ada can process URLs from piped input, making it easy to integrate with other command-line tools 55 | that produce ASCII or UTF-8 outputs. Here's an example of how to pipe the output of another command into Ada. 56 | Given a list of URLs, one by line, we may query the normalized URL string (`href`) and detect any malformed URL: 57 | 58 | ```bash 59 | cat dragonball_url.txt | adaparse --get href 60 | ``` 61 | 62 | **Output:** 63 | 64 | ```text 65 | http://www.goku.com 66 | http://www.vegeta.com 67 | http://www.gohan.com 68 | ``` 69 | 70 | Our tool supports the passing of arguments to each URL in said file so 71 | that you can query for the hash, the host, the protocol, the port, 72 | the origin, the search, the password, the username, the pathname 73 | or the hostname: 74 | 75 | ```bash 76 | cat dragonball_url.txt | adaparse -g host 77 | ``` 78 | 79 | **Output:** 80 | 81 | ```text 82 | www.goku.com 83 | www.vegeta.com 84 | www.gohan.com 85 | ``` 86 | 87 | If you omit `-g`, it will only provide a list of invalid URLs. This might be 88 | useful if you want to valid quickly a list of URLs. 89 | 90 | ### Benchmark Runner 91 | 92 | The benchmark flag can be used to output the time it takes to process piped input: 93 | 94 | ```bash 95 | cat wikipedia_100k.txt | adaparse -b 96 | ``` 97 | 98 | **Output:** 99 | 100 | ```text 101 | Invalid URL: 1968:_Die_Kinder_der_Diktatur 102 | Invalid URL: 58957:_The_Bluegrass_Guitar_Collection 103 | Invalid URL: 650luc:_Gangsta_Grillz 104 | Invalid URL: Q4%3A57 105 | Invalid URL: Q10%3A47 106 | Invalid URL: Q5%3A45 107 | Invalid URL: Q40%3A28 108 | Invalid URL: 1:1_scale 109 | Invalid URL: 1893:_A_World's_Fair_Mystery 110 | Invalid URL: 12:51_(Krissy_%26_Ericka_song) 111 | Invalid URL: 111:_A_Nelson_Number 112 | Invalid URL: 7:00AM-8%3A00AM_(24_season_5) 113 | Invalid URL: Q53%3A31 114 | read 5209265 bytes in 32819917 ns using 100000 lines, used 160 loads 115 | 0.1587226744053009 GB/s 116 | ``` 117 | 118 | ### Saving result to file system 119 | 120 | There is an option to output to a file on disk: 121 | 122 | ```bash 123 | cat wikipedia_100k.txt | adaparse -o wiki_output.txt 124 | ``` 125 | 126 | As well as read in from a file on disk without going through cat: 127 | 128 | ```bash 129 | adaparse -p wikipedia_top_100_txt 130 | ``` 131 | 132 | #### Advanced Usage 133 | 134 | You may also combine different flags together. E.g. Say one wishes to extract only the host from URLs stored in wikipedia.txt and output it to the test_write.txt file: 135 | 136 | ```bash 137 | adaparse -p wikipedia_top100.txt -o test_write.txt -g host -b 138 | ``` 139 | 140 | **Output:** 141 | 142 | ```text 143 | read 5209265 bytes in 26737131 ns using 100000 lines, total_bytes is 5209265 used 160 loads 144 | 0.19483260937757307 GB/s(base) 145 | ``` 146 | 147 | Content of test_write.txt: 148 | 149 | ```text 150 | (---snip---) 151 | en.wikipedia.org 152 | en.wikipedia.org 153 | en.wikipedia.org 154 | en.wikipedia.org 155 | en.wikipedia.org 156 | en.wikipedia.org 157 | en.wikipedia.org 158 | en.wikipedia.org 159 | en.wikipedia.org 160 | en.wikipedia.org 161 | (---snip---) 162 | ``` -------------------------------------------------------------------------------- /astro/content/docs/cli/performance.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CLI Performance 3 | description: How is the performance of Ada and adaparse CLI? 4 | --- 5 | 6 | Our `adaparse` tool may outperform other popular alternatives. We offer a [collection of 7 | sets of URLs](https://github.com/ada-url/url-various-datasets) for benchmarking purposes. 8 | The following results are on a MacBook Air 2022 (M2 processor) using LLVM 14. We 9 | compare against [trurl](https://github.com/curl/trurl) version 0.6 (libcurl/7.87.0). 10 | 11 | ### Benchmarks 12 | 13 |
14 | 15 | wikipedia_100k dataset, adaparse can parse URLs three times faster than trurl. 16 | 17 | 18 | ```bash 19 | time cat url-various-datasets/wikipedia/wikipedia_100k.txt| trurl --url-file - &> /dev/null 1 20 | cat url-various-datasets/wikipedia/wikipedia_100k.txt 0,00s user 0,01s system 3% cpu 0,179 total 21 | trurl --url-file - &> /dev/null 0,14s user 0,03s system 98% cpu 0,180 total 22 | 23 | 24 | time cat url-various-datasets/wikipedia/wikipedia_100k.txt| ./build/tools/cli/adaparse -g href &> /dev/null 25 | cat url-various-datasets/wikipedia/wikipedia_100k.txt 0,00s user 0,00s system 10% cpu 0,056 total 26 | ./build/tools/cli/adaparse -g href &> /dev/null 0,05s user 0,00s system 93% cpu 0,055 total 27 | ``` 28 |
29 |
30 | 31 | Using top100 dataset, adaparse is twice as fast as the trurl. 32 | 33 | 34 | ```bash 35 | time cat url-various-datasets/top100/top100.txt| trurl --url-file - &> /dev/null 1 36 | cat url-various-datasets/top100/top100.txt 0,00s user 0,00s system 4% cpu 0,115 total 37 | trurl --url-file - &> /dev/null 0,09s user 0,02s system 97% cpu 0,113 total 38 | 39 | time cat url-various-datasets/top100/top100.txt| ./build/tools/cli/adaparse -g href &> /dev/null 40 | cat url-various-datasets/top100/top100.txt 0,00s user 0,01s system 11% cpu 0,062 total 41 | ./build/tools/cli/adaparse -g href &> /dev/null 0,05s user 0,00s system 94% cpu 0,061 total 42 | ``` 43 |
44 | 45 | ### Results 46 | 47 | The results will vary depending on your system. We invite you to run your own benchmarks. 48 | 49 | #### Parsing 100,000 Wikipedia URLs 50 | 51 | ```bash 52 | ada ▏ 55 ms ███████▋ 53 | trurl ▏ 180 ms █████████████████████████ 54 | ``` 55 | 56 | #### Parsing 100,000 URLs from TOP 100 websites 57 | 58 | ```bash 59 | ada ▏ 61 ms █████████████▍ 60 | trurl ▏ 113 ms █████████████████████████ 61 | ``` -------------------------------------------------------------------------------- /astro/content/docs/clients/cpp.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: C++ 3 | description: How to install and use Ada in a C++ project 4 | --- 5 | import { Steps } from '@astrojs/starlight/components'; 6 | 7 | More information about the API can be found from [C++ API Reference](https://cpp-api.ada-url.com). 8 | 9 | ## Requirements 10 | 11 | The project is self-contained and has no dependency. 12 | A recent C++ compiler supporting C++17. We test GCC 9 or better, LLVM 10 or better and Microsoft Visual Studio 2022. 13 | 14 | ## Building 15 | 16 | Ada uses **cmake** as a build system. It's recommended to have cmake available in your system. 17 | Run the following commands to compile and build Ada locally. 18 | 19 | 20 | 21 | 1. **Prepare** 22 | 23 | ```bash 24 | cmake -B build 25 | ``` 26 | 27 | 2. **Build** 28 | 29 | ```bash 30 | cmake --build build 31 | ``` 32 | 33 | 34 | 35 | ## Usage 36 | 37 | Use the following code to run and test Ada. 38 | 39 | ```cpp 40 | #include "ada.h" 41 | #include 42 | 43 | int main(int , char *[]) { 44 | ada::result url = ada::parse("https://www.google.com"); 45 | url->set_protocol("http"); 46 | std::cout << url->get_protocol() << std::endl; 47 | std::cout << url->get_host() << std::endl; 48 | return EXIT_SUCCESS; 49 | } 50 | ``` 51 | 52 | ### Parsing & Validation 53 | 54 | Parse and validate a URL from an ASCII or UTF-8 string 55 | 56 | ```cpp 57 | ada::result url = 58 | ada::parse("https://www.google.com"); 59 | if (url) { /* URL is valid */ } 60 | ``` 61 | 62 | After calling **parse** function, you *must* check that the result is valid before 63 | accessing it when you are not sure that it will succeed. The following 64 | code is unsafe: 65 | 66 | ```cpp 67 | ada::result url = 68 | ada::parse("some bad url"); 69 | url->get_href(); 70 | ``` 71 | 72 | You should do... 73 | 74 | ```cpp 75 | ada::result url = 76 | ada::parse("some bad url"); 77 | if(url) { 78 | // next line is now safe: 79 | url->get_href(); 80 | } else { 81 | // report a parsing failure 82 | } 83 | ``` 84 | 85 | For simplicity, in the examples below, we skip the check because 86 | we know that parsing succeeds. 87 | 88 | ## Examples 89 | 90 | ### Credentials 91 | 92 | ```cpp 93 | auto url = ada::parse("https://www.google.com"); 94 | url->set_username("username"); 95 | url->set_password("password"); 96 | // ada->get_href() will return "https://username:password@www.google.com/" 97 | ``` 98 | 99 | ### Protocol 100 | 101 | ```cpp 102 | auto url = ada::parse("https://www.google.com"); 103 | url->set_protocol("wss"); 104 | // url->get_protocol() will return "wss:" 105 | // url->get_href() will return "wss://www.google.com/" 106 | ``` 107 | 108 | ### Host 109 | 110 | ```cpp 111 | auto url = ada::parse("https://www.google.com"); 112 | url->set_host("github.com"); 113 | // url->get_host() will return "github.com" 114 | // you can use `url.set_hostname` depending on your usage. 115 | ``` 116 | 117 | ### Port 118 | 119 | ```cpp 120 | auto url = ada::parse("https://www.google.com"); 121 | url->set_port("8080"); 122 | // url->get_port() will return "8080" 123 | ``` 124 | 125 | ### Pathname 126 | 127 | ```cpp 128 | auto url = ada::parse("https://www.google.com"); 129 | url->set_pathname("/my-super-long-path") 130 | // url->get_pathname() will return "/my-super-long-path" 131 | ``` 132 | 133 | ### Search/Query 134 | 135 | ```cpp 136 | auto url = ada::parse("https://www.google.com"); 137 | url->set_search("target=self"); 138 | // url->get_search() will return "?target=self" 139 | ``` 140 | 141 | ### Hash/Fragment 142 | 143 | ```cpp 144 | auto url = ada::parse("https://www.google.com"); 145 | url->set_hash("is-this-the-real-life"); 146 | // url->get_hash() will return "#is-this-the-real-life" 147 | ``` -------------------------------------------------------------------------------- /astro/content/docs/clients/d.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: D 3 | description: How to install and use Ada in a D project 4 | --- 5 | 6 | Ada has a D client available on [Github][source-code] and 7 | also on [dub.pm][dub-registry]. 8 | 9 | ## Installation 10 | 11 | Add the following as a dependency to your project (`dub.json` or `dub.sdl`): 12 | 13 | ```bash 14 | # dub add ada-d from dub-registry 15 | $ dub add ada-d 16 | ``` 17 | 18 | Modules hierarchy: 19 | 20 | ```bash 21 | . 22 | └── source 23 | └── ada 24 | ├── c 25 | │   ├── ada.d # low-level C bindings - @nogc, nothrow, @safe and betterC compatible 26 | │   └── wrapper.d # D (mangled) RAII - @nogc, nothrow, @safe and betterC compatible 27 | └── url 28 | └── package.d # by default set public wrapper.d in 'import ada.url' 29 | # (for low-level C bindings use 'import ada.c.ada') 30 | ``` 31 | 32 | ## Usage 33 | 34 | Here is an example illustrating a common usage: 35 | 36 | ```d 37 | import ada.url : AdaUrl, ParseOptions; // @safe, nothrow and betterC compatible 38 | import std.stdio : writeln; // need GC and throw exception 39 | 40 | void main() @safe { 41 | auto u = AdaUrl(ParseOptions("http://www.google:8080/love#drug")); 42 | writeln("port: ", u.getPort); 43 | writeln("hash: ", u.getHash); 44 | writeln("pathname: ", u.getPathname); 45 | writeln("href: ", u.getHref()); 46 | u.setPort("9999"); 47 | writeln("href: ", u.getHref); // empty '()' is optional 48 | } 49 | ``` 50 | 51 | full example: [here](https://github.com/kassane/ada-d/tree/main/example) 52 | 53 | ## Resources 54 | 55 | - [Source code][source-code] 56 | - [Dub - dub.pm][dub-registry] 57 | - [Documentation - dpldocs.info][documentation] 58 | 59 | 60 | [dub-registry]: http://ada-d.dub.pm 61 | [documentation]: https://ada-d.dpldocs.info 62 | [source-code]: https://github.com/kassane/ada-d -------------------------------------------------------------------------------- /astro/content/docs/clients/go.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Go 3 | description: How to install and use Ada in a Go project 4 | --- 5 | 6 | Ada has a Go client available on [Github](https://github.com/ada-url/goada). -------------------------------------------------------------------------------- /astro/content/docs/clients/luajit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: LuaJIT 3 | description: How to install and use Ada in a LuaJIT or OpenResty project 4 | --- 5 | 6 | Ada has a LuaJIT / OpenResty client available on [Github][source-code], 7 | and also on [luarocks.org][rock] and [https://opm.openresty.org/][opm]. 8 | 9 | ## Installation 10 | 11 | ### Using LuaRocks 12 | 13 | ```bash 14 | luarocks install lua-resty-ada 15 | ``` 16 | 17 | LuaRocks repository for `lua-resty-ada` is located at 18 | [luarocks.org/modules/bungle/lua-resty-ada](https://luarocks.org/modules/bungle/lua-resty-session). 19 | 20 | ### Using OpenResty Package Manager 21 | 22 | ```bash 23 | opm get bungle/lua-resty-ada 24 | ``` 25 | 26 | OPM repository for `lua-resty-ada` is located at 27 | [opm.openresty.org/package/bungle/lua-resty-ada](https://opm.openresty.org/package/bungle/lua-resty-ada/). 28 | 29 | ## Usage 30 | 31 | Please consult the [API documentation][documentation] for a more detailed information. 32 | 33 | ### URL class 34 | 35 | The `resty.ada` can parse URL and return an instance of URL: 36 | 37 | ```lua 38 | local ada_url = require("resty.ada") 39 | local url = ada_url.parse("https://example.org/path/file.txt") 40 | local protocol = url:get_protocol() 41 | url:free() -- explicit free (garbage collector would do it implicitly) 42 | print(protocol) -- "https:" 43 | ``` 44 | 45 | ### Static functions 46 | 47 | The library can also be used without creating instances: 48 | 49 | ```lua 50 | local ada_url = require("resty.ada") 51 | local protocol = ada_url.get_protocol("https://example.org/path/file.txt") 52 | print(protocol) -- "https:" 53 | ``` 54 | 55 | ## Resources 56 | 57 | - [Source code][source-code] 58 | - [LuaRocks][rock] 59 | - [OpenResty Package Manager][opm] 60 | - [Documentation][documentation] 61 | 62 | [rock]: https://luarocks.org/modules/bungle/lua-resty-ada 63 | [opm]: https://opm.openresty.org/package/bungle/lua-resty-ada/ 64 | [documentation]: https://bungle.github.io/lua-resty-ada/ 65 | [source-code]: https://github.com/bungle/lua-resty-ada -------------------------------------------------------------------------------- /astro/content/docs/clients/python.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Python 3 | description: How to install and use Ada in a Python project 4 | --- 5 | import { Steps } from '@astrojs/starlight/components'; 6 | 7 | Ada has a Python client available on [Github](https://github.com/ada-url/ada-python). 8 | For more details on the `ada_url` API, see the documentation at [Read the Docs](https://ada-url.readthedocs.io/en/latest/). 9 | 10 | ## Installation 11 | 12 | ### Installing pre-built binary wheels 13 | 14 | The easiest way to get started is to install `ada-url` from [PyPI](https://pypi.org/project/ada-url/). 15 | 16 | From within your virtual environment, run: 17 | 18 | ```bash 19 | python3 -m pip install ada-url 20 | ``` 21 | 22 | ### Installing from source 23 | 24 | The `Makefile` in the [project root](https://github.com/ada-url/ada-python) will build a package for installation on your own machine. 25 | 26 | From within your virtual environment, run: 27 | 28 | 29 | 30 | 1. **Prepare** 31 | 32 | ```bash 33 | make requirements package 34 | ``` 35 | 36 | 2. **Install** 37 | 38 | ```bash 39 | python3 -m install -e . 40 | ``` 41 | 42 | 43 | 44 | ## Usage 45 | 46 | ### URL class 47 | 48 | The `ada_url` package defines a `URL` class that can parse URLs: 49 | 50 | ```py 51 | >>> import ada_url 52 | >>> urlobj = ada_url.URL('https://example.org/path/file.txt') 53 | >>> urlobj.protocol 54 | 'https:' 55 | >>> urlobj.pathname 56 | '/path/file.txt' 57 | ``` 58 | 59 | ### High-level functions 60 | 61 | It also exposes some higher level functions for analyzing and manipulating URLs: 62 | 63 | #### parse_url 64 | 65 | ```py 66 | >>> import ada_url 67 | >>> ada_url.parse_url('https://user:pass@example.org:80/api?q=1#2') 68 | { 69 | 'href': 'https://user:pass@example.org:80/api?q=1#2', 70 | 'username': 'user', 71 | 'password': 'pass', 72 | 'protocol': 'https:', 73 | 'host': 'example.org:80', 74 | 'port': '80', 75 | 'hostname': 'example.org', 76 | 'pathname': '/api', 77 | 'search': '?q=1', 78 | 'hash': '#2' 79 | } 80 | ``` 81 | 82 | #### join_url 83 | 84 | ```py 85 | >>> import ada_url 86 | >>> ada_url.join_url( 87 | 'https://example.org/dir/child.txt', '../parent.txt' 88 | ) 89 | ``` -------------------------------------------------------------------------------- /astro/content/docs/clients/rust.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rust 3 | description: How to install and use Ada in a Rust project 4 | --- 5 | 6 | Ada has a Rust client available on [Github][source-code] and 7 | also on [crates.io][crate]. 8 | 9 | ## Installation 10 | 11 | Add the following as a dependency to your project (`Cargo.toml`): 12 | 13 | ```toml 14 | [dependencies] 15 | ada-url = "1" 16 | ``` 17 | 18 | ## Usage 19 | 20 | Here is an example illustrating a common usage: 21 | 22 | ```rust 23 | use ada_url::Url; 24 | fn main() { 25 | let mut u = Url::parse("http://www.google:8080/love#drug", None) 26 | .expect("bad url"); 27 | println!("port: {:?}", u.port()); 28 | println!("hash: {:?}", u.hash()); 29 | println!("pathname: {:?}", u.pathname()); 30 | println!("href: {:?}", u.href()); 31 | u.set_port("9999"); 32 | println!("href: {:?}", u.href()); 33 | } 34 | ``` 35 | 36 | ## Resources 37 | 38 | - [Source code][source-code] 39 | - [Crate - crates.io][crate] 40 | - [Documentation - docs.rs][documentation] 41 | 42 | 43 | [crate]: https://crates.io/crates/ada-url 44 | [documentation]: https://docs.rs/ada-url/1.0.2/ada_url/ 45 | [source-code]: https://github.com/ada-url/rust -------------------------------------------------------------------------------- /astro/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fast WHATWG Compliant URL parser" 3 | description: WHATWG Compliant URL parser written with focus on compliance, performance and security across multiple platforms and languages. 4 | template: splash 5 | hero: 6 | tagline: Parse millions of URLs per second 7 | image: 8 | dark: ../../assets/logo-dark.svg 9 | light: ../../assets/logo-light.svg 10 | actions: 11 | - text: Get Started 12 | link: /introduction/ 13 | icon: right-arrow 14 | variant: primary 15 | - text: GitHub 16 | link: https://github.com/ada-url/ada 17 | icon: external 18 | variant: secondary 19 | next: false 20 | --- 21 | 22 | import Benchmarks from '../../components/Benchmarks.astro' 23 | 24 | 25 | -------------------------------------------------------------------------------- /astro/content/docs/installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: How to install Ada and add as a dependency 4 | --- 5 | import { Steps } from '@astrojs/starlight/components'; 6 | 7 | :::note 8 | Ada is available on different programming languages such as **C++**, **Python**, **Go**, **Rust** or **LuaJIT**. 9 | ::: 10 | 11 | ## Homebrew 12 | 13 | Ada is available through [Homebrew](https://formulae.brew.sh/formula/ada-url#default). 14 | Homebrew is kept up to date with the recent releases of Ada. 15 | 16 | Run the following command to install Ada to your macOS computer: 17 | 18 | ```bash 19 | brew install ada-url 20 | ``` 21 | 22 | ## Build from source 23 | 24 | ### Requirements 25 | 26 | The project is self-contained and has no dependency. 27 | A recent C++ compiler supporting C++17. We test GCC 9 or better, LLVM 10 or better and Microsoft Visual Studio 2022. 28 | 29 | ### Compiling 30 | 31 | :::note 32 | Ada uses **cmake** as a build system. It's recommended to have cmake available in your system. 33 | ::: 34 | 35 | Run the following commands to compile and build Ada locally. 36 | 37 | 38 | 39 | 1. **Prepare build** 40 | 41 | The following command prepares the build. 42 | 43 | ```bash 44 | cmake -B build 45 | ``` 46 | 47 | 2. **Build** 48 | 49 | Run the following command to build Ada on your system. 50 | 51 | ```bash 52 | cmake --build build 53 | ``` 54 | 55 | 3. **Run tests** 56 | 57 | Run the following `ctest` command to validate your build. 58 | 59 | ```bash 60 | ctest --output-on-failure --test-dir build 61 | ``` 62 | 63 | 64 | ### Windows 65 | 66 | Windows users need additional flags to specify the build configuration, e.g. `--config Release`. 67 | 68 | ### Docker 69 | 70 | The project can also be built via docker using default docker file of repository with following commands. 71 | 72 | 73 | 74 | 1. **Build** 75 | 76 | Build and prepare the docker file 77 | 78 | ```bash 79 | docker build -t ada-builder 80 | ``` 81 | 82 | 2. **Run** 83 | 84 | Run the tests 85 | 86 | ```bash 87 | docker run --rm -it -v ${PWD}:/repo ada-builder 88 | ``` 89 | 90 | 91 | 92 | ### Amalgamation 93 | 94 | You may amalgamate all source files into only two files (`ada.h` and `ada.cpp`) by typing executing the Python 95 | 3 script `singleheader/amalgamate.py`. By default, the files are created in the `singleheader` directory. 96 | 97 | ```bash 98 | ./singleheader/amalgamate.py 99 | ``` -------------------------------------------------------------------------------- /astro/content/docs/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | description: WHATWG specification compliant URL parser 4 | --- 5 | 6 | Ada is a fast and spec-compliant URL parser written in C++. 7 | 8 | * It's widely tested by both Web Platform Tests and Google OSS Fuzzer. 9 | * It is **extremely fast**. 10 | * It's the default URL parser of Node.js since Node 18.16.0. 11 | * It supports Unicode Technical Standard. 12 | 13 | The Ada library passes the full range of tests from the specification, across a wide range of platforms (e.g., Windows, Linux, macOS). 14 | 15 | ## FAQ 16 | 17 |
18 | What is WHATWG? 19 | 20 | The term WHATWG stands for **Web Hypertext Application Technology Working Group**. 21 | 22 | It is a community-driven organization that focuses on developing and maintaining web standards. 23 | The WHATWG was initially formed in response to the divergence between the World Wide Web Consortium (W3C) and the browser vendors at the time, who felt that the W3C process was too slow to address the evolving needs of web developers. 24 |
25 |
26 | Who uses Ada? It is battle-tested? 27 | 28 | Ada is adopted by Node.js and used by millions of developers since Node.js 18.16.0. 29 |
30 |
31 | Can I use this in my project? 32 | 33 | Yes. Free to use for personal and commercial projects. Ada is available under MIT and Apache License 2.0. 34 |
35 | 36 | ## License 37 | 38 | This code is made available under the Apache License 2.0 as well as the MIT license. 39 | 40 | Our tests include third-party code and data. The benchmarking code includes third-party code: it is provided for research purposes only and not part of the library. -------------------------------------------------------------------------------- /astro/content/docs/performance.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Performance 3 | description: How's the performance of Ada? 4 | --- 5 | 6 | On a benchmark where we need to validate and normalize [thousands URLs found 7 | on popular websites](https://github.com/ada-url/url-various-datasets/tree/main/top100), 8 | we find that ada can be several times faster than popular competitors (system: Apple MacBook 2022 9 | with LLVM 14). 10 | 11 | ```bash 12 | Ada ▏ 188 ns/URL ███▏ 13 | servo-url ▏ 664 ns/URL ███████████▎ 14 | cURL ▏ 1471 ns/URL █████████████████████████ 15 | ``` 16 | 17 | Ada has improved the performance of the popular JavaScript environment Node.js: 18 | 19 | :::note 20 | Since Node.js 18, a new URL parser dependency was added to Node.js — Ada. This addition bumped the Node.js performance when parsing URLs to a new level. Some results could reach up to an improvement of **400%**. ([State of Node.js Performance 2023](https://blog.rafaelgss.dev/state-of-nodejs-performance-2023)) 21 | ::: 22 | ## Available datasets 23 | 24 | ### [ada-url/url-various-datasets](https://github.com/ada-url/url-various-datasets) 25 | 26 | These are collections of URLs for benchmarking purposes. Disclaimer: This repository is developed and released for research purposes only. 27 | 28 | - `files/node_files.txt`: 29 | - Contains all source files from a given Node.js snapshot as URLs (43415 URLs). 30 | - `files/linux_files.txt`: 31 | - Contains all files from a Linux systems as URLs (169312 URLs). 32 | - `wikipedia/wikipedia_100k.txt`: 33 | - Contains 100k URLs from a snapshot of all Wikipedia articles as URLs (March 6th 2023) 34 | - `others/kasztp.txt`: 35 | - Contains test URLs from [URL_Shortener](https://github.com/kasztp/URL_Shortener) (MIT License) (48009 URLs). 36 | - `others/userbait.txt`: 37 | - Contains test URLs from [phishing_sites_detector](https://github.com/userbait/phishing_sites_detector) (unknown copyright) (11430 URLs). 38 | - `top100/top100.txt` 39 | - Contains crawl of the top visited 100 websites and extracts unique URLs (98000 URLs) 40 | 41 | ### [ada-url/url-dataset](https://github.com/ada-url/url-dataset) 42 | 43 | This repository crawls the top visited 100 websites and extracts unique URLs to be used for generating a dataset of unique real-world URL examples. 44 | The script creates a out.txt file with each line containing a different URL. 45 | 46 | ## Resources 47 | 48 | ### [ada_analysis](https://github.com/ada-url/ada_analysis) 49 | 50 | #### Introduction 51 | 52 | Repository to do data analysis 53 | 54 | The file follow the CSV format. For each URL in a set, on a given system, we include the number of cycles and instructions needed to process the URL as well as many other attributes of the URL, including its protocol type, length of the path and so forth. You can open CSV files in a spreadsheet tool. 55 | 56 | The big_url_set is our default (github//ada-url/url-dataset/out.txt). 57 | 58 | We process each URL 30 times, but not in sequence. We record the time needed to generate the normalized URL (href). 59 | 60 | The benchmark done using model_bench. It only works under Linux because only under Linux can we get the fine grained precision we need to benchmark individual URL. 61 | 62 | We do not need report the timings (ns) for precision reasons. Only the number of cycles and the number of instructions are reported. 63 | 64 | ### [js_url_benchmark](https://github.com/ada-url/js_url_benchmark) 65 | 66 | #### Introduction 67 | 68 | Runs the same benchmark in latest Bun, Deno as well as Node.js v16, v17, v18 and v20. 69 | 70 | ## Benchmarks 71 | 72 | ### JavaScript URLs 73 | 74 | Benchmarks and results are available through [js_url_benchmark](https://github.com/ada-url/js_url_benchmark) 75 | repository in `ada-url` organization. 76 | 77 | #### Deno 1.32.5 78 | 79 | ```bash 80 | cpu: AMD EPYC 7262 8-Core Processor 81 | runtime: deno 1.32.5 (x86_64-unknown-linux-gnu) 82 | 83 | benchmark time (avg) (min … max) p75 p99 p995 84 | ------------------------------------------------------------------- ----------------------------- 85 | fixtures/linux_files.txt 184.46 ms/iter (183.7 ms … 185.67 ms) 184.54 ms 185.67 ms 185.67 ms 86 | fixtures/kasztp.txt 59.97 ms/iter (59.72 ms … 60.31 ms) 60.06 ms 60.31 ms 60.31 ms 87 | fixtures/userbait.txt 21.03 ms/iter (20.8 ms … 21.54 ms) 21.06 ms 21.54 ms 21.54 ms 88 | fixtures/top100.txt 158.16 ms/iter (157.51 ms … 158.72 ms) 158.62 ms 158.72 ms 158.72 ms 89 | fixtures/wikipedia_100k.txt 110.1 ms/iter (109.66 ms … 110.55 ms) 110.36 ms 110.55 ms 110.55 ms 90 | Average URL size: 62 bytes 91 | Ratio of bad URLs: 0.02% 92 | ``` 93 | 94 | #### Bun 0.5.9 95 | 96 | ```bash 97 | cpu: AMD EPYC 7262 8-Core Processor 98 | runtime: bun 0.5.9 (x64-linux) 99 | 100 | benchmark time (avg) (min … max) p75 p99 p995 101 | ------------------------------------------------------------------- ----------------------------- 102 | fixtures/linux_files.txt 101.06 ms/iter (93.72 ms … 112.09 ms) 103.01 ms 112.09 ms 112.09 ms 103 | fixtures/kasztp.txt 45.11 ms/iter (43.38 ms … 62.19 ms) 44.78 ms 62.19 ms 62.19 ms 104 | fixtures/userbait.txt 13.46 ms/iter (12.77 ms … 27.97 ms) 13.26 ms 27.97 ms 27.97 ms 105 | fixtures/top100.txt 122.87 ms/iter (120.98 ms … 134.54 ms) 122.85 ms 134.54 ms 134.54 ms 106 | fixtures/wikipedia_100k.txt 69.06 ms/iter (62.78 ms … 87 ms) 73.06 ms 87 ms 87 ms 107 | Average URL size: 61 bytes 108 | Ratio of bad URLs: 0.02% 109 | ``` 110 | 111 | #### Node.js v20.0.0 112 | 113 | 114 | ```bash 115 | cpu: AMD EPYC 7262 8-Core Processor 116 | runtime: node v20.0.0 (x64-linux) 117 | 118 | benchmark time (avg) (min … max) p75 p99 p995 119 | ------------------------------------------------------------------- ----------------------------- 120 | fixtures/linux_files.txt 92.01 ms/iter (91.27 ms … 92.66 ms) 92.35 ms 92.66 ms 92.66 ms 121 | fixtures/kasztp.txt 30 ms/iter (29.68 ms … 30.36 ms) 30.16 ms 30.36 ms 30.36 ms 122 | fixtures/userbait.txt 8.33 ms/iter (8.17 ms … 9.79 ms) 8.36 ms 9.79 ms 9.79 ms 123 | fixtures/top100.txt 67.44 ms/iter (67 ms … 68.93 ms) 67.54 ms 68.93 ms 68.93 ms 124 | fixtures/wikipedia_100k.txt 56.98 ms/iter (56.65 ms … 57.65 ms) 57.14 ms 57.65 ms 57.65 ms 125 | Average URL size: 62 bytes 126 | Ratio of bad URLs: 0.03% 127 | ``` -------------------------------------------------------------------------------- /astro/content/docs/playground.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Playground" 3 | description: 'A playground to test and run Ada URL parser: a WHATWG Compliant and fast URL parser' 4 | template: splash 5 | --- 6 | 7 | import Playground from '../../components/playground/Playground.astro' 8 | 9 | 10 | -------------------------------------------------------------------------------- /astro/custom.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sl-color-toast-red: #991b1b; 3 | } 4 | 5 | :root[data-theme="light"] { 6 | --sl-color-toast-red: #dc2626; 7 | } 8 | -------------------------------------------------------------------------------- /astro/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "organizeImports": { 4 | "enabled": true 5 | }, 6 | "linter": { 7 | "enabled": true, 8 | "rules": { 9 | "recommended": true, 10 | "a11y": { 11 | "recommended": true 12 | }, 13 | "performance": { 14 | "recommended": true 15 | }, 16 | "suspicious": { 17 | "noExplicitAny": "off" 18 | }, 19 | "complexity": { 20 | "noForEach": "off" 21 | }, 22 | "correctness": { 23 | "useExhaustiveDependencies": "warn" 24 | } 25 | } 26 | }, 27 | "formatter": { 28 | "enabled": true, 29 | "indentWidth": 2, 30 | "indentStyle": "space", 31 | "lineWidth": 100 32 | }, 33 | "files": { 34 | "ignore": [ 35 | "node_modules", 36 | "public", 37 | ".next", 38 | ".contentlayer", 39 | "lib/wasm", 40 | ".vercel", 41 | ".astro", 42 | "dist" 43 | ] 44 | }, 45 | "javascript": { 46 | "formatter": { 47 | "quoteStyle": "single", 48 | "quoteProperties": "asNeeded", 49 | "jsxQuoteStyle": "single", 50 | "trailingCommas": "all", 51 | "semicolons": "asNeeded" 52 | } 53 | }, 54 | "css": { 55 | "formatter": { 56 | "enabled": true 57 | } 58 | }, 59 | "json": { 60 | "formatter": { 61 | "enabled": true 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/wasm/wasm.js: -------------------------------------------------------------------------------- 1 | 2 | var loadWASM = (() => { 3 | var _scriptDir = import.meta.url; 4 | 5 | return ( 6 | function(loadWASM = {}) { 7 | 8 | var Module=typeof loadWASM!="undefined"?loadWASM:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}var wasmBinaryFile;if(Module["locateFile"]){wasmBinaryFile="wasm.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}}else{wasmBinaryFile=new URL("wasm.wasm",import.meta.url).href}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}catch(err){abort(err)}}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinary(binaryFile))}}return Promise.resolve().then(()=>getBinary(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>{return WebAssembly.instantiate(binary,imports)}).then(instance=>{return instance}).then(receiver,reason=>{err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}else{return instantiateArrayBuffer(binaryFile,imports,callback)}}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["q"];updateMemoryViews();wasmTable=Module["asm"]["t"];addOnInit(Module["asm"]["r"]);removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}function callRuntimeCallbacks(callbacks){while(callbacks.length>0){callbacks.shift()(Module)}}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError(`Unknown type size: ${size}`)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return{[name]:function(){return body.apply(this,arguments)}}[name]}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}var finalizationRegistry=false;function detachFinalizer(handle){}function runDestructor($$){if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function releaseClassHandle($$){$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}var registeredPointers={};function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}var delayFunction=undefined;function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record}}))}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function attachFinalizer(handle){if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$:$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${arguments.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(function(){clonedHandle["delete"]()}));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAP32[pointer>>2])}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function dynCallLegacy(sig,ptr,args){var f=Module["dynCall_"+sig];return args&&args.length?f.apply(null,[ptr].concat(args)):f.call(null,ptr)}function getWasmTableEntry(funcPtr){return wasmTable.get(funcPtr)}function dynCall(sig,ptr,args){if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr).apply(null,args);return rtn}function getDynCaller(sig,ptr){var argCache=[];return function(){argCache.length=0;Object.assign(argCache,arguments);return dynCall(sig,ptr,argCache)}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp}var UnboundTypeError=undefined;function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function throwUnboundTypeError(message,types){var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))}function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);if(upcast){upcast=embind__requireFunction(upcastSignature,upcast)}if(downcast){downcast=embind__requireFunction(downcastSignature,downcast)}rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],function(base){base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(legalFunctionName,function(){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[arguments.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,arguments)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){if(registeredClass.baseClass.__derivedClasses===undefined){registeredClass.baseClass.__derivedClasses=[]}registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function validateThis(this_,classType,humanName){if(!(this_ instanceof Object)){throwBindingError(`${humanName} with invalid "this": ${this_}`)}if(!(this_ instanceof classType.registeredClass.constructor)){throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`)}if(!this_.$$.ptr){throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`)}return upcastPointer(this_.$$.ptr,this_.$$.ptrType.registeredClass,classType.registeredClass)}function __embind_register_class_property(classType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext){fieldName=readLatin1String(fieldName);getter=embind__requireFunction(getterSignature,getter);whenDependentTypesAreResolved([],[classType],function(classType){classType=classType[0];var humanName=`${classType.name}.${fieldName}`;var desc={get:function(){throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])},enumerable:true,configurable:true};if(setter){desc.set=()=>{throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])}}else{desc.set=v=>{throwBindingError(humanName+" is a read-only property")}}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);whenDependentTypesAreResolved([],setter?[getterReturnType,setterArgumentType]:[getterReturnType],function(types){var getterReturnType=types[0];var desc={get:function(){var ptr=validateThis(this,classType,humanName+" getter");return getterReturnType["fromWireType"](getter(getterContext,ptr))},enumerable:true};if(setter){setter=embind__requireFunction(setterSignature,setter);var setterArgumentType=types[1];desc.set=function(v){var ptr=validateThis(this,classType,humanName+" setter");var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,v));runDestructors(destructors)}}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);return[]});return[]})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[];this.get=function(id){return this.allocated[id]};this.has=function(id){return this.allocated[id]!==undefined};this.allocate=function(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id};this.free=function(id){this.allocated[id]=undefined;this.freelist.push(id)}}var emval_handles=new HandleAllocator;function __emval_decref(handle){if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}}function count_emval_handles(){var count=0;for(var i=emval_handles.reserved;i{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":function(destructors,value){return Emval.toHandle(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function embindRepr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function newFunc(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError(`new_ called with constructor type ${typeof constructor} which is not a function`)}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc,isAsync){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns||isAsync?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i>2])}return array}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>HEAPU16;shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>HEAPU32;shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function _abort(){abort("")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;abortOnCannotGrowMemory(requestedSize)}embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_ClassHandle();init_embind();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var wasmImports={"d":___cxa_throw,"l":__embind_register_bigint,"i":__embind_register_bool,"h":__embind_register_class,"b":__embind_register_class_property,"p":__embind_register_emval,"g":__embind_register_float,"k":__embind_register_function,"c":__embind_register_integer,"a":__embind_register_memory_view,"f":__embind_register_std_string,"e":__embind_register_std_wstring,"j":__embind_register_void,"m":_abort,"o":_emscripten_memcpy_big,"n":_emscripten_resize_heap};var asm=createWasm();var ___wasm_call_ctors=function(){return(___wasm_call_ctors=Module["asm"]["r"]).apply(null,arguments)};var _malloc=function(){return(_malloc=Module["asm"]["s"]).apply(null,arguments)};var ___getTypeName=function(){return(___getTypeName=Module["asm"]["u"]).apply(null,arguments)};var __embind_initialize_bindings=Module["__embind_initialize_bindings"]=function(){return(__embind_initialize_bindings=Module["__embind_initialize_bindings"]=Module["asm"]["v"]).apply(null,arguments)};var ___errno_location=function(){return(___errno_location=Module["asm"]["__errno_location"]).apply(null,arguments)};var _free=function(){return(_free=Module["asm"]["w"]).apply(null,arguments)};var ___cxa_is_pointer_type=function(){return(___cxa_is_pointer_type=Module["asm"]["x"]).apply(null,arguments)};var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); 9 | 10 | 11 | return loadWASM.ready 12 | } 13 | 14 | ); 15 | })(); 16 | export default loadWASM; -------------------------------------------------------------------------------- /lib/wasm/wasm.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/lib/wasm/wasm.wasm -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ada-url.com", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "astro dev", 7 | "build": "astro sync && astro build", 8 | "start": "astro dev", 9 | "lint": "biome check .", 10 | "lint-fix": "biome check . --write" 11 | }, 12 | "dependencies": { 13 | "@astrojs/react": "^3.6.2", 14 | "@astrojs/starlight": "^0.29.0", 15 | "@astrojs/tailwind": "^5.1.2", 16 | "@radix-ui/react-tabs": "^1.1.1", 17 | "@radix-ui/react-toast": "^1.2.2", 18 | "@tailwindcss/nesting": "0.0.0-insiders.565cd3e", 19 | "@types/react": "18.2.24", 20 | "@types/react-dom": "18.2.8", 21 | "astro": "^4.16.10", 22 | "autoprefixer": "10.4.20", 23 | "chart.js": "^4.4.3", 24 | "lucide-react": "0.279.0", 25 | "postcss": "8.4.49", 26 | "react": "18.2.0", 27 | "react-dom": "18.2.0", 28 | "react-hook-form": "^7.45.4", 29 | "sharp": "^0.33.5", 30 | "tailwindcss": "3.4.14", 31 | "tailwindcss-animate": "^1.0.7", 32 | "typescript": "5.6.3" 33 | }, 34 | "devDependencies": { 35 | "@biomejs/biome": "^1.9.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/ada.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/ada.png -------------------------------------------------------------------------------- /public/ada.svg: -------------------------------------------------------------------------------- 1 | 2 | 93 | 94 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/fonts/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/fonts/Inter-SemiBold.woff -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ada-url/website/ebbb16ad9de9b11d90918abd01d212de0ba9a3e9/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 34 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "theme_color": "#ffffff", 12 | "background_color": "#ffffff", 13 | "display": "standalone" 14 | } 15 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | darkMode: ['class'], 4 | content: ['./pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}', './app/**/*.{ts,tsx}'], 5 | theme: { 6 | container: { 7 | center: true, 8 | padding: '2rem', 9 | screens: { 10 | '2xl': '1400px', 11 | }, 12 | }, 13 | extend: { 14 | colors: { 15 | border: 'hsl(var(--border))', 16 | input: 'hsl(var(--input))', 17 | ring: 'hsl(var(--ring))', 18 | background: 'hsl(var(--background))', 19 | foreground: 'hsl(var(--foreground))', 20 | primary: { 21 | DEFAULT: 'hsl(var(--primary))', 22 | foreground: 'hsl(var(--primary-foreground))', 23 | }, 24 | secondary: { 25 | DEFAULT: 'hsl(var(--secondary))', 26 | foreground: 'hsl(var(--secondary-foreground))', 27 | }, 28 | destructive: { 29 | DEFAULT: 'hsl(var(--destructive))', 30 | foreground: 'hsl(var(--destructive-foreground))', 31 | }, 32 | muted: { 33 | DEFAULT: 'hsl(var(--muted))', 34 | foreground: 'hsl(var(--muted-foreground))', 35 | }, 36 | accent: { 37 | DEFAULT: 'hsl(var(--accent))', 38 | foreground: 'hsl(var(--accent-foreground))', 39 | }, 40 | popover: { 41 | DEFAULT: 'hsl(var(--popover))', 42 | foreground: 'hsl(var(--popover-foreground))', 43 | }, 44 | card: { 45 | DEFAULT: 'hsl(var(--card))', 46 | foreground: 'hsl(var(--card-foreground))', 47 | }, 48 | }, 49 | borderRadius: { 50 | lg: 'var(--radius)', 51 | md: 'calc(var(--radius) - 2px)', 52 | sm: 'calc(var(--radius) - 4px)', 53 | }, 54 | keyframes: { 55 | 'accordion-down': { 56 | from: { height: 0 }, 57 | to: { height: 'var(--radix-accordion-content-height)' }, 58 | }, 59 | 'accordion-up': { 60 | from: { height: 'var(--radix-accordion-content-height)' }, 61 | to: { height: 0 }, 62 | }, 63 | }, 64 | animation: { 65 | 'accordion-down': 'accordion-down 0.2s ease-out', 66 | 'accordion-up': 'accordion-up 0.2s ease-out', 67 | }, 68 | }, 69 | }, 70 | plugins: [ 71 | require('@tailwindcss/nesting'), 72 | require('tailwindcss-animate'), 73 | require('tailwindcss'), 74 | require('autoprefixer'), 75 | ], 76 | } 77 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "Bundler", // allow following "exports" in package.json. This is also fine as the code isn't compiled by `tsc` but by Next / Astro 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": ".", 18 | "plugins": [ 19 | { 20 | "name": "next" 21 | } 22 | ], 23 | "paths": { 24 | "@/*": ["./*"], 25 | "contentlayer/generated": ["./.contentlayer/generated"] 26 | } 27 | }, 28 | "include": [ 29 | "next-env.d.ts", 30 | "**/*.ts", 31 | "**/*.tsx", 32 | ".next/types/**/*.ts", 33 | ".contentlayer/generated" 34 | ], 35 | "exclude": ["node_modules"] 36 | } 37 | --------------------------------------------------------------------------------