Skip to content

Commit ff3182c

Browse files
Bashamegasaschanaz
andauthored
KDL Parser (#2064)
Co-authored-by: Kagami Sascha Rosylight <[email protected]>
1 parent 63642ab commit ff3182c

File tree

6 files changed

+229
-92
lines changed

6 files changed

+229
-92
lines changed

inputfiles/addedTypes.jsonc

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -373,98 +373,6 @@
373373
// Full support: https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API#browser_compatibility
374374
"storage-access"
375375
]
376-
},
377-
"AutoFillBase": {
378-
"name": "AutoFillBase",
379-
"value": [
380-
// Off
381-
"off",
382-
// Automatic
383-
"on",
384-
""
385-
]
386-
},
387-
"AutoFillAddressKind": {
388-
"name": "AutoFillAddressKind",
389-
"value": [
390-
"shipping",
391-
"billing"
392-
]
393-
},
394-
"AutoFillNormalField": {
395-
"name": "AutoFillNormalField",
396-
"value": [
397-
"name",
398-
"honorific-prefix",
399-
"given-name",
400-
"additional-name",
401-
"family-name",
402-
"honorific-suffix",
403-
404-
"username",
405-
"new-password",
406-
"current-password",
407-
// Supported in iOS Safari too even though WPT tests
408-
// for Safari currently fail as of 2023-06.
409-
"one-time-code",
410-
411-
"organization",
412-
"street-address",
413-
"address-line1",
414-
"address-line2",
415-
"address-line3",
416-
"address-level4",
417-
"address-level3",
418-
"address-level2",
419-
"address-level1",
420-
"country",
421-
"country-name",
422-
"postal-code",
423-
424-
"cc-name",
425-
"cc-given-name",
426-
"cc-family-name",
427-
"cc-number",
428-
"cc-exp",
429-
"cc-exp-month",
430-
"cc-exp-year",
431-
"cc-csc",
432-
"cc-type",
433-
"transaction-currency",
434-
"transaction-amount",
435-
436-
"bday-day",
437-
"bday-month",
438-
"bday-year"
439-
]
440-
},
441-
"AutoFillContactKind": {
442-
"name": "AutoFillContactKind",
443-
"value": [
444-
"home",
445-
"work",
446-
"mobile"
447-
]
448-
},
449-
"AutoFillContactField": {
450-
"name": "AutoFillContactField",
451-
"value": [
452-
"tel",
453-
"tel-country-code",
454-
"tel-national",
455-
"tel-area-code",
456-
"tel-local",
457-
"tel-local-prefix",
458-
"tel-local-suffix",
459-
"tel-extension",
460-
"email"
461-
]
462-
},
463-
"AutoFillCredentialField": {
464-
"name": "AutoFillCredentialField",
465-
"value": [
466-
"webauthn"
467-
]
468376
}
469377
}
470378
},

inputfiles/patches/autocomplete.kdl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
enum AutoFillBase {
2+
// Off
3+
off
4+
// Automatic
5+
on
6+
""
7+
}
8+
enum AutoFillAddressKind {
9+
shipping
10+
billing
11+
}
12+
enum AutoFillNormalField {
13+
name
14+
honorific-prefix
15+
given-name
16+
additional-name
17+
family-name
18+
honorific-suffix
19+
20+
username
21+
new-password
22+
current-password
23+
// Supported in iOS Safari too even though WPT tests
24+
// for Safari currently fail as of 2023-06.
25+
one-time-code
26+
27+
organization
28+
street-address
29+
address-line1
30+
address-line2
31+
address-line3
32+
address-level4
33+
address-level3
34+
address-level2
35+
address-level1
36+
country
37+
country-name
38+
postal-code
39+
40+
cc-name
41+
cc-given-name
42+
cc-family-name
43+
cc-number
44+
cc-exp
45+
cc-exp-month
46+
cc-exp-year
47+
cc-csc
48+
cc-type
49+
transaction-currency
50+
transaction-amount
51+
52+
bday-day
53+
bday-month
54+
bday-year
55+
}
56+
enum AutoFillContactKind {
57+
home
58+
work
59+
mobile
60+
}
61+
enum AutoFillContactField {
62+
tel
63+
tel-country-code
64+
tel-national
65+
tel-area-code
66+
tel-local
67+
tel-local-prefix
68+
tel-local-suffix
69+
tel-extension
70+
email
71+
}
72+
enum AutoFillCredentialField {
73+
webauthn
74+
}

package-lock.json

Lines changed: 77 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"eslint-plugin-prettier": "^5.1.3",
5959
"globals": "^16.0.0",
6060
"jsonc-parser": "^3.2.1",
61+
"kdljs": "^0.3.0",
6162
"node-fetch": "^3.3.2",
6263
"prettier": "^3.2.5",
6364
"print-diff": "^2.0.0",

src/build.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { getInterfaceToEventMap } from "./build/webref/events.js";
1414
import { getWebidls } from "./build/webref/idl.js";
1515
import jsonc from "jsonc-parser";
1616
import { generateDescriptions } from "./build/mdn-comments.js";
17+
import readPatches from "./build/patches.js";
1718

1819
function mergeNamesakes(filtered: Browser.WebIdl) {
1920
const targets = [
@@ -93,6 +94,7 @@ async function emitDom() {
9394

9495
const overriddenItems = await readInputJSON("overridingTypes.jsonc");
9596
const addedItems = await readInputJSON("addedTypes.jsonc");
97+
const patches = await readPatches();
9698
const comments = await readInputJSON("comments.json");
9799
const deprecatedInfo = await readInputJSON("deprecatedMessage.json");
98100
const documentationFromMDN = await generateDescriptions();
@@ -230,6 +232,7 @@ async function emitDom() {
230232
webidl = mergeApiDescriptions(webidl, documentationFromMDN);
231233
webidl = merge(webidl, addedItems);
232234
webidl = merge(webidl, overriddenItems);
235+
webidl = merge(webidl, patches);
233236
webidl = merge(webidl, comments);
234237
webidl = mergeDeprecatedMessage(webidl, deprecatedInfo);
235238
for (const name in webidl.interfaces!.interface) {

src/build/patches.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { parse } from "kdljs";
2+
import type { Enum } from "./types";
3+
import { readdir, readFile } from "fs/promises";
4+
import { merge } from "./helpers.js";
5+
6+
/**
7+
* Converts patch files in KDL to match the [types](types.d.ts).
8+
*/
9+
function parseKDL(kdlText: string) {
10+
const { output, errors } = parse(kdlText);
11+
12+
if (errors.length) {
13+
throw new Error("KDL parse errors", { cause: errors });
14+
}
15+
16+
const nodes = output!;
17+
const enums: Record<string, Enum> = {};
18+
19+
for (const node of nodes) {
20+
if (node.name === "enum") {
21+
handleEnum(node, enums);
22+
}
23+
}
24+
25+
return { enums: { enum: enums } };
26+
}
27+
28+
/**
29+
* Handles an enum node by extracting its name and values.
30+
* Throws an error if the enum name is missing or if the values are not in the correct format.
31+
* @param node The enum node to handle.
32+
* @param enums The record of enums to update.
33+
*/
34+
function handleEnum(node: any, enums: Record<string, Enum>) {
35+
const name = node.values[0];
36+
if (typeof name !== "string") {
37+
throw new Error("Missing enum name");
38+
}
39+
const values: string[] = [];
40+
41+
for (const child of node.children ?? []) {
42+
values.push(child.name);
43+
}
44+
45+
enums[name] = { name, value: values };
46+
}
47+
48+
/**
49+
* Collect all file URLs in a directory.
50+
*/
51+
async function getAllFileURLs(folder: URL): Promise<URL[]> {
52+
const entries = await readdir(folder, { withFileTypes: true });
53+
return entries.map((entry) => new URL(entry.name, folder));
54+
}
55+
56+
/**
57+
* Read and parse a single KDL file.
58+
*/
59+
export async function readPatch(fileUrl: URL): Promise<any> {
60+
const text = await readFile(fileUrl, "utf8");
61+
return parseKDL(text);
62+
}
63+
64+
/**
65+
* Read, parse, and merge all KDL files under the input folder.
66+
*/
67+
export default async function readPatches(): Promise<any> {
68+
const patchDirectory = new URL("../../inputfiles/patches/", import.meta.url);
69+
const fileUrls = await getAllFileURLs(patchDirectory);
70+
71+
const parsedContents = await Promise.all(fileUrls.map(readPatch));
72+
73+
return parsedContents.reduce((acc, current) => merge(acc, current), {});
74+
}

0 commit comments

Comments
 (0)