forked from catppuccin/userstyles
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.ts
More file actions
110 lines (99 loc) 路 3.35 KB
/
Copy pathutils.ts
File metadata and controls
110 lines (99 loc) 路 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import Ajv, { Schema } from "ajv";
import { parse } from "@std/yaml";
import { join } from "@std/path";
import { SetRequired } from "type-fest/source/set-required.d.ts";
import { REPO_ROOT, userStylesSchema } from "@/deps.ts";
import { UserstylesSchema } from "@/types/userstyles.d.ts";
import { log } from "@/lint/logger.ts";
import { sprintf } from "@std/fmt/printf";
/**
* @param content A string of YAML content
* @param schema A JSON schema
* @returns A promise that resolves to the parsed YAML content, verified against the schema. Rejects if the content is invalid.
*/
export const validateYaml = <T>(
content: string,
schema: Schema,
): T => {
const ajv = new Ajv.default();
const validate = ajv.compile<T>(schema);
const data = parse(content);
if (!validate(data)) {
console.log(
"Found schema errors in scripts/userstyles.yml: " +
validate.errors?.map((err) =>
sprintf(
"%s %s%s",
err.instancePath.slice(1).replaceAll("/", "."),
err.message,
err.params.allowedValues
? ` (${JSON.stringify(err.params.allowedValues, undefined)})`
: "",
)
).join(" and "),
);
Deno.exit(1);
}
return data as T;
};
/**
* Utility function that calls {@link validateYaml} on the userstyles.yml file.
* Fails when data.userstyles is undefined.
*/
export const getUserstylesData = (): Userstyles => {
const content = Deno.readTextFileSync(
join(REPO_ROOT, "scripts/userstyles.yml"),
);
try {
const data = validateYaml<UserstylesSchema>(
content,
userStylesSchema,
);
if (data.userstyles === undefined || data.collaborators === undefined) {
console.log("userstyles.yml is missing required fields");
Deno.exit(1);
}
return data as Userstyles;
} catch (err) {
if (err.name === "YAMLError") {
const groups =
/(?<message>.*) at line (?<line>\d+), column (?<column>\d+):[\S\s]*/
.exec(err.message)?.groups;
log(
groups!.message,
{
file: "scripts/userstyles.yml",
startLine: Number(groups!.line),
content: content,
},
"error",
);
} else {
console.log(err);
}
Deno.exit(1);
}
};
/**
* Utility function that formats a list of items into the "x, y, ..., and z" format.
* @example
* formatListOfItems(['x']); // 'x'
* @example
* formatListOfItems(['x', 'y']); // 'x and y'
* @example
* formatListOfItems(['x', 'y', 'z']); // 'x, y, and z'
*/
export const formatListOfItems = (items: unknown[]): string => {
// If there are two items, connect them with an "and".
if (items.length === 2) return items.join(" and ");
// Otherwise, there is either just one item or more than two items.
return items.reduce((prev, curr, idx, arr) => {
// If this is the first item of the items we are looping through, set our initial string to it.
if (idx === 0) return curr;
// If this is the last one, add a comma (Oxford commas are amazing) followed by "and" and the item to the string.
if (curr === arr.at(-1)) return prev + `, and ${curr}`;
// Otherwise, it is some item in the middle of the list and we can just add it as a comma followed by the item to the string.
return prev + `, ${curr}`;
}) as string;
};
type Userstyles = SetRequired<UserstylesSchema, "userstyles" | "collaborators">;