char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somport URL extension to typescriptbf382b3

main
3.2 KiB109 linesraw
1import {
2  ObjectCreate,
3  ObjectDefineProperty,
4  TypeError,
5  WeakMapPrototypeSet as weakSet,
6} from "ext:core/primordials";
7import { required, state, usv } from "ext:web/idl.js";
8import { op_url_parse, op_url_set } from "ext:core/ops";
9import { URLSearchParams } from "./search_params.js";
10import { params, queryList, urls } from "./state.js";
11import type { URLComponent, URLParts } from "ext:core/ops";
12
13function parse(rawInput: unknown, rawBase: unknown, count: number): URLParts | null {
14  required(count, 1);
15  const input = usv(rawInput);
16  const base = rawBase === undefined ? null : usv(rawBase);
17  return op_url_parse([input, base]);
18}
19function initializeURL(receiver: URL, parts: URLParts): URL {
20  const searchParams: URLSearchParams = ObjectCreate(URLSearchParams.prototype);
21  const url = { parts, searchParams };
22  weakSet(params, searchParams, { list: queryList(parts), url });
23  weakSet(urls, receiver, url);
24  return receiver;
25}
26// Component accessors are installed from the table below, without instance fields.
27interface URL extends Record<URLComponent, string> {
28  readonly origin: string;
29}
30class URL {
31  constructor(input: unknown, base: unknown = undefined) {
32    const parts = parse(input, base, arguments.length);
33    if (parts === null) throw new TypeError("Invalid URL");
34    initializeURL(this, parts);
35  }
36  static canParse(input: unknown, base: unknown = undefined): boolean {
37    return parse(input, base, arguments.length) !== null;
38  }
39  static parse(input: unknown, base: unknown = undefined): URL | null {
40    const parts = parse(input, base, arguments.length);
41    return parts === null
42      ? null
43      : initializeURL(ObjectCreate(URL.prototype), parts);
44  }
45  get searchParams(): URLSearchParams {
46    return state(urls, this).searchParams;
47  }
48  toString(): string {
49    return state(urls, this).parts[0];
50  }
51  toJSON(): string {
52    return state(urls, this).parts[0];
53  }
54}
55const components = [
56  "href",
57  "origin",
58  "protocol",
59  "username",
60  "password",
61  "host",
62  "hostname",
63  "port",
64  "pathname",
65  "search",
66  "hash",
67] as const;
68for (let index = 0; index < components.length; index++) {
69  const name = components[index];
70  const descriptor: {
71    get(this: URL): string;
72    set?: (this: URL, value: unknown) => void;
73    enumerable: boolean;
74    configurable: boolean;
75  } = {
76    get(this: URL) {
77      return state(urls, this).parts[index];
78    },
79    enumerable: true,
80    configurable: true,
81  };
82  if (name !== "origin") {
83    descriptor.set = {
84      set(this: URL, rawValue: unknown) {
85        const data = state(urls, this);
86        const value = usv(rawValue);
87        const parts = op_url_set([data.parts[0], name, value]);
88        if (parts === null) throw new TypeError("Invalid URL");
89        data.parts = parts;
90        if (name === "href" || name === "search") {
91          state(params, data.searchParams).list = queryList(parts);
92        }
93      },
94    }.set;
95  }
96  ObjectDefineProperty(descriptor.get, "name", {
97    value: `get ${name}`,
98    configurable: true,
99  });
100  if (descriptor.set) {
101    ObjectDefineProperty(descriptor.set, "name", {
102      value: `set ${name}`,
103      configurable: true,
104    });
105  }
106  ObjectDefineProperty(URL.prototype, name, descriptor);
107}
108
109export { URL };