@brnshkr/config 0.0.1-beta.3 → 0.0.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -226
- package/conf/.gitignore.dist +15 -0
- package/conf/Makefile +3778 -0
- package/conf/Makefile.dist +13 -0
- package/conf/bunfig.dist.toml +5 -0
- package/conf/commitlint.dist.mjs +1 -0
- package/conf/editorconfig.dist +19 -0
- package/conf/launch.dist.json +31 -0
- package/conf/markdownlint.dist.mjs +1 -0
- package/conf/spelling/defaults.json +185 -0
- package/conf/tsconfig.dist.json +3 -0
- package/conf/tsconfig.json +31 -27
- package/conf/vitest.dist.mjs +1 -0
- package/conf/vscode-css-custom-data.dist.json +95 -0
- package/conf/vscode-extensions.dist.json +21 -0
- package/conf/vscode-settings.dist.jsonc +338 -0
- package/dist/commitlint/index.d.mts +72 -0
- package/dist/commitlint/index.mjs +239 -0
- package/dist/eslint/index.d.mts +3890 -1387
- package/dist/eslint/index.mjs +2662 -471
- package/dist/markdownlint/index.d.mts +2304 -0
- package/dist/markdownlint/index.mjs +440 -0
- package/dist/shared.mjs +406 -64
- package/dist/spelling/index.d.mts +30 -0
- package/dist/spelling/index.mjs +2 -0
- package/dist/spelling/spelling.test.d.mts +1 -0
- package/dist/spelling/spelling.test.mjs +12 -0
- package/dist/stylelint/index.d.mts +47 -9
- package/dist/stylelint/index.mjs +145 -47
- package/dist/vitest/index.d.mts +73 -0
- package/dist/vitest/index.mjs +181 -0
- package/package.json +192 -105
- package/conf/tsconfig.json.example +0 -3
- package/dist/scripts/eslint.mjs +0 -16
- package/dist/scripts/stylelint.mjs +0 -31
- /package/conf/{eslint.config.mjs.example → eslint.dist.mjs} +0 -0
- /package/conf/{stylelint.config.mjs.example → stylelint.dist.mjs} +0 -0
package/dist/shared.mjs
CHANGED
|
@@ -1,36 +1,52 @@
|
|
|
1
1
|
import { isPackageExists } from "local-pkg";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { execFileSync } from "node:child_process";
|
|
2
5
|
//#region ../package.json
|
|
3
6
|
var name = "@brnshkr/config";
|
|
4
|
-
var version = "0.0.1-beta.
|
|
7
|
+
var version = "0.0.1-beta.4";
|
|
5
8
|
//#endregion
|
|
6
9
|
//#region ../src/js/shared/utils/package-json.ts
|
|
7
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @internal @brnshkr/config
|
|
12
|
+
*/
|
|
13
|
+
const packageOrganizationInternal = name.split("/", 1).at(0)?.replace(/^@/v, "");
|
|
8
14
|
if (packageOrganizationInternal === void 0 || packageOrganizationInternal.length === 0) throw new Error("Failed to read package organization from package.json file.");
|
|
9
15
|
const packageOrganization = packageOrganizationInternal;
|
|
10
16
|
const packageOrganizationUpper = packageOrganizationInternal.toUpperCase();
|
|
11
17
|
//#endregion
|
|
12
18
|
//#region ../src/js/shared/utils/log.ts
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @internal @brnshkr/config
|
|
21
|
+
*/
|
|
22
|
+
const log = (message) => {
|
|
23
|
+
console.error(`[${name}] ${message}`);
|
|
16
24
|
};
|
|
17
25
|
//#endregion
|
|
18
26
|
//#region ../src/js/shared/utils/object.ts
|
|
27
|
+
const objectKeys = (object) => Object.keys(object);
|
|
28
|
+
const objectValues = (object) => Object.values(object);
|
|
19
29
|
const objectEntries = (object) => Object.entries(object);
|
|
20
30
|
const objectFromEntries = (entries) => Object.fromEntries(entries);
|
|
21
31
|
const objectAssign = (target, source) => Object.assign(target, source);
|
|
32
|
+
const isPlainObject = (value) => {
|
|
33
|
+
if (typeof value !== "object" || !value) return false;
|
|
34
|
+
return (Object.getPrototypeOf(value) ?? Object.prototype) === Object.prototype;
|
|
35
|
+
};
|
|
22
36
|
//#endregion
|
|
23
37
|
//#region ../src/js/shared/utils/interop-import.ts
|
|
24
38
|
const interopImport = async (thePackage) => {
|
|
25
39
|
const resolved = await thePackage;
|
|
26
|
-
return typeof resolved === "object" && resolved
|
|
40
|
+
return typeof resolved === "object" && resolved && "default" in resolved ? resolved.default : resolved;
|
|
27
41
|
};
|
|
28
42
|
//#endregion
|
|
29
43
|
//#region ../src/js/shared/utils/package-resolvers.ts
|
|
44
|
+
/**
|
|
45
|
+
* @internal @brnshkr/config
|
|
46
|
+
*/
|
|
30
47
|
const ESLINT_PACKAGES = {
|
|
31
48
|
ESLINT_CSS: "@eslint/css",
|
|
32
|
-
|
|
33
|
-
ESLINT_IMPORT_RESOVLER_TYPESCRIPT: "eslint-import-resolver-typescript",
|
|
49
|
+
ESLINT_IMPORT_RESOLVER_TYPESCRIPT: "eslint-import-resolver-typescript",
|
|
34
50
|
ESLINT_JSON: "@eslint/json",
|
|
35
51
|
ESLINT_MARKDOWN: "@eslint/markdown",
|
|
36
52
|
ESLINT_MERGE_PROCESSORS: "eslint-merge-processors",
|
|
@@ -50,47 +66,74 @@ const ESLINT_PACKAGES = {
|
|
|
50
66
|
ESLINT_PLUGIN_UNUSED_IMPORTS: "eslint-plugin-unused-imports",
|
|
51
67
|
ESLINT_PLUGIN_YML: "eslint-plugin-yml",
|
|
52
68
|
SVELTE: "svelte",
|
|
69
|
+
TAILWINDCSS: "tailwindcss",
|
|
53
70
|
TYPESCRIPT: "typescript",
|
|
54
71
|
TYPESCRIPT_ESLINT: "typescript-eslint",
|
|
55
72
|
VITEST_ESLINT_PLUGIN: "@vitest/eslint-plugin"
|
|
56
73
|
};
|
|
57
74
|
const ESLINT_PACKAGE_RESOLVERS = {
|
|
58
|
-
[ESLINT_PACKAGES.ESLINT_CSS]: async () =>
|
|
59
|
-
[ESLINT_PACKAGES.
|
|
60
|
-
[ESLINT_PACKAGES.
|
|
61
|
-
[ESLINT_PACKAGES.
|
|
62
|
-
[ESLINT_PACKAGES.
|
|
63
|
-
[ESLINT_PACKAGES.
|
|
64
|
-
[ESLINT_PACKAGES.
|
|
65
|
-
[ESLINT_PACKAGES.
|
|
66
|
-
[ESLINT_PACKAGES.
|
|
67
|
-
[ESLINT_PACKAGES.
|
|
68
|
-
[ESLINT_PACKAGES.
|
|
69
|
-
[ESLINT_PACKAGES.
|
|
70
|
-
[ESLINT_PACKAGES.
|
|
71
|
-
[ESLINT_PACKAGES.
|
|
72
|
-
[ESLINT_PACKAGES.
|
|
73
|
-
[ESLINT_PACKAGES.
|
|
74
|
-
[ESLINT_PACKAGES.
|
|
75
|
-
[ESLINT_PACKAGES.
|
|
76
|
-
[ESLINT_PACKAGES.
|
|
77
|
-
[ESLINT_PACKAGES.
|
|
78
|
-
[ESLINT_PACKAGES.ESLINT_PLUGIN_YML]: async () => await interopImport(import("eslint-plugin-yml")),
|
|
75
|
+
[ESLINT_PACKAGES.ESLINT_CSS]: async () => interopImport(import("@eslint/css")),
|
|
76
|
+
[ESLINT_PACKAGES.ESLINT_JSON]: async () => interopImport(import("@eslint/json")),
|
|
77
|
+
[ESLINT_PACKAGES.ESLINT_IMPORT_RESOLVER_TYPESCRIPT]: async () => interopImport(import("eslint-import-resolver-typescript")),
|
|
78
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_ANTFU]: async () => interopImport(import("eslint-plugin-antfu")),
|
|
79
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_ESLINT_COMMENTS]: async () => interopImport(import("@eslint-community/eslint-plugin-eslint-comments")),
|
|
80
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_IMPORT_X]: async () => interopImport(import("eslint-plugin-import-x")),
|
|
81
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_JSDOC]: async () => interopImport(import("eslint-plugin-jsdoc")),
|
|
82
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_JSONC]: async () => interopImport(import("eslint-plugin-jsonc")),
|
|
83
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_JSDOC_PROCESSOR]: async () => interopImport(import("eslint-plugin-jsdoc/getJsdocProcessorPlugin.js")),
|
|
84
|
+
[ESLINT_PACKAGES.ESLINT_MARKDOWN]: async () => interopImport(import("@eslint/markdown")),
|
|
85
|
+
[ESLINT_PACKAGES.ESLINT_MERGE_PROCESSORS]: async () => interopImport(import("eslint-merge-processors")),
|
|
86
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_N]: async () => interopImport(import("eslint-plugin-n")),
|
|
87
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_PERFECTIONIST]: async () => interopImport(import("eslint-plugin-perfectionist")),
|
|
88
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_REGEXP]: async () => interopImport(import("eslint-plugin-regexp")),
|
|
89
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_STYLISTIC]: async () => interopImport(import("@stylistic/eslint-plugin")),
|
|
90
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_SVELTE]: async () => interopImport(import("eslint-plugin-svelte")),
|
|
91
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_TOML]: async () => interopImport(import("eslint-plugin-toml")),
|
|
92
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_UNICORN]: async () => interopImport(import("eslint-plugin-unicorn")),
|
|
93
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_UNUSED_IMPORTS]: async () => interopImport(import("eslint-plugin-unused-imports")),
|
|
94
|
+
[ESLINT_PACKAGES.ESLINT_PLUGIN_YML]: async () => interopImport(import("eslint-plugin-yml")),
|
|
79
95
|
[ESLINT_PACKAGES.SVELTE]: () => isPackageExists(ESLINT_PACKAGES.SVELTE),
|
|
96
|
+
[ESLINT_PACKAGES.TAILWINDCSS]: () => isPackageExists(ESLINT_PACKAGES.TAILWINDCSS),
|
|
80
97
|
[ESLINT_PACKAGES.TYPESCRIPT]: () => isPackageExists(ESLINT_PACKAGES.TYPESCRIPT),
|
|
81
|
-
[ESLINT_PACKAGES.TYPESCRIPT_ESLINT]: async () =>
|
|
82
|
-
[ESLINT_PACKAGES.VITEST_ESLINT_PLUGIN]: async () =>
|
|
98
|
+
[ESLINT_PACKAGES.TYPESCRIPT_ESLINT]: async () => interopImport(import("typescript-eslint")),
|
|
99
|
+
[ESLINT_PACKAGES.VITEST_ESLINT_PLUGIN]: async () => interopImport(import("@vitest/eslint-plugin"))
|
|
100
|
+
};
|
|
101
|
+
const COMMITLINT_PACKAGES = {
|
|
102
|
+
COMMITLINT_CONFIG_CONVENTIONAL: "@commitlint/config-conventional",
|
|
103
|
+
COMMITLINT_PLUGIN_FUNCTION_RULES: "commitlint-plugin-function-rules",
|
|
104
|
+
COMMITLINT_PLUGIN_TENSE: "commitlint-plugin-tense"
|
|
105
|
+
};
|
|
106
|
+
const COMMITLINT_PACKAGE_RESOLVERS = {
|
|
107
|
+
[COMMITLINT_PACKAGES.COMMITLINT_CONFIG_CONVENTIONAL]: () => isPackageExists(COMMITLINT_PACKAGES.COMMITLINT_CONFIG_CONVENTIONAL),
|
|
108
|
+
[COMMITLINT_PACKAGES.COMMITLINT_PLUGIN_FUNCTION_RULES]: () => isPackageExists(COMMITLINT_PACKAGES.COMMITLINT_PLUGIN_FUNCTION_RULES),
|
|
109
|
+
[COMMITLINT_PACKAGES.COMMITLINT_PLUGIN_TENSE]: () => isPackageExists(COMMITLINT_PACKAGES.COMMITLINT_PLUGIN_TENSE)
|
|
110
|
+
};
|
|
111
|
+
const MARKDOWNLINT_PACKAGES = {
|
|
112
|
+
MARKDOWNLINT_GITHUB: "@github/markdownlint-github",
|
|
113
|
+
MARKDOWNLINT_RULES: "@hongminhee/markdownlint-rules",
|
|
114
|
+
MARKDOWNLINT_RULE_NO_TRAILING_SLASH_IN_LINKS: "markdownlint-rule-no-trailing-slash-in-links",
|
|
115
|
+
MARKDOWNLINT_RULE_RELATIVE_LINKS: "markdownlint-rule-relative-links",
|
|
116
|
+
MARKDOWNLINT_RULE_SEARCH_REPLACE: "markdownlint-rule-search-replace",
|
|
117
|
+
MARKDOWNLINT_RULE_TABLE_FORMAT: "markdownlint-rule-table-format"
|
|
118
|
+
};
|
|
119
|
+
const MARKDOWNLINT_PACKAGE_RESOLVERS = {
|
|
120
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_GITHUB]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_GITHUB),
|
|
121
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULES]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULES),
|
|
122
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_NO_TRAILING_SLASH_IN_LINKS]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_NO_TRAILING_SLASH_IN_LINKS),
|
|
123
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_RELATIVE_LINKS]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_RELATIVE_LINKS),
|
|
124
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_SEARCH_REPLACE]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_SEARCH_REPLACE),
|
|
125
|
+
[MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_TABLE_FORMAT]: () => isPackageExists(MARKDOWNLINT_PACKAGES.MARKDOWNLINT_RULE_TABLE_FORMAT)
|
|
83
126
|
};
|
|
84
127
|
const STYLELINT_PACKAGES = {
|
|
85
128
|
POSTCSS_HTML: "postcss-html",
|
|
86
129
|
STYLELINT_CONFIG_CSS_MODULES: "stylelint-config-css-modules",
|
|
87
130
|
STYLELINT_CONFIG_HTML: "stylelint-config-html",
|
|
88
131
|
STYLELINT_CONFIG_RECESS_ORDER: "stylelint-config-recess-order",
|
|
132
|
+
STYLELINT_CONFIG_STANDARD_LESS: "stylelint-config-standard-less",
|
|
89
133
|
STYLELINT_CONFIG_STANDARD_SCSS: "stylelint-config-standard-scss",
|
|
90
134
|
STYLELINT_DECLARATION_STRICT_VALUE: "stylelint-declaration-strict-value",
|
|
91
135
|
STYLELINT_ORDER: "stylelint-order",
|
|
92
136
|
STYLELINT_PLUGIN_DEFENSIVE_CSS: "stylelint-plugin-defensive-css",
|
|
93
|
-
STYLELINT_PLUGIN_LOGICAL_CSS: "stylelint-plugin-logical-css",
|
|
94
137
|
STYLELINT_PLUGIN_USE_BASELINE: "stylelint-plugin-use-baseline",
|
|
95
138
|
STYLELINT_USE_NESTING: "stylelint-use-nesting",
|
|
96
139
|
STYLISTIC_STYLELINT_CONFIG: "@stylistic/stylelint-config"
|
|
@@ -100,51 +143,98 @@ const STYLELINT_PACKAGE_RESOLVERS = {
|
|
|
100
143
|
[STYLELINT_PACKAGES.STYLELINT_CONFIG_CSS_MODULES]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_CONFIG_CSS_MODULES),
|
|
101
144
|
[STYLELINT_PACKAGES.STYLELINT_CONFIG_HTML]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_CONFIG_HTML),
|
|
102
145
|
[STYLELINT_PACKAGES.STYLELINT_CONFIG_RECESS_ORDER]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_CONFIG_RECESS_ORDER),
|
|
146
|
+
[STYLELINT_PACKAGES.STYLELINT_CONFIG_STANDARD_LESS]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_CONFIG_STANDARD_LESS),
|
|
103
147
|
[STYLELINT_PACKAGES.STYLELINT_CONFIG_STANDARD_SCSS]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_CONFIG_STANDARD_SCSS),
|
|
104
148
|
[STYLELINT_PACKAGES.STYLELINT_DECLARATION_STRICT_VALUE]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_DECLARATION_STRICT_VALUE),
|
|
105
149
|
[STYLELINT_PACKAGES.STYLELINT_ORDER]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_ORDER),
|
|
106
150
|
[STYLELINT_PACKAGES.STYLELINT_PLUGIN_DEFENSIVE_CSS]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_PLUGIN_DEFENSIVE_CSS),
|
|
107
|
-
[STYLELINT_PACKAGES.STYLELINT_PLUGIN_LOGICAL_CSS]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_PLUGIN_LOGICAL_CSS),
|
|
108
151
|
[STYLELINT_PACKAGES.STYLELINT_PLUGIN_USE_BASELINE]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_PLUGIN_USE_BASELINE),
|
|
109
152
|
[STYLELINT_PACKAGES.STYLELINT_USE_NESTING]: () => isPackageExists(STYLELINT_PACKAGES.STYLELINT_USE_NESTING),
|
|
110
153
|
[STYLELINT_PACKAGES.STYLISTIC_STYLELINT_CONFIG]: () => isPackageExists(STYLELINT_PACKAGES.STYLISTIC_STYLELINT_CONFIG)
|
|
111
154
|
};
|
|
155
|
+
const VITEST_PACKAGES = {
|
|
156
|
+
HAPPY_DOM: "happy-dom",
|
|
157
|
+
JSDOM: "jsdom",
|
|
158
|
+
VITEST_UI: "@vitest/ui"
|
|
159
|
+
};
|
|
160
|
+
const VITEST_PACKAGE_RESOLVERS = {
|
|
161
|
+
[VITEST_PACKAGES.HAPPY_DOM]: () => isPackageExists(VITEST_PACKAGES.HAPPY_DOM),
|
|
162
|
+
[VITEST_PACKAGES.JSDOM]: () => isPackageExists(VITEST_PACKAGES.JSDOM),
|
|
163
|
+
[VITEST_PACKAGES.VITEST_UI]: () => isPackageExists(VITEST_PACKAGES.VITEST_UI)
|
|
164
|
+
};
|
|
112
165
|
//#endregion
|
|
113
166
|
//#region ../src/js/shared/utils/string.ts
|
|
167
|
+
/**
|
|
168
|
+
* @internal @brnshkr/config
|
|
169
|
+
*/
|
|
114
170
|
const joinAsQuotedList = (strings, type = "conjunction") => strings.length > 1 ? `"${strings.slice(0, -1).join("\", \"")}" ${type === "conjunction" ? "and" : "or"} "${strings.slice(-1).join("")}"` : {
|
|
115
171
|
0: "",
|
|
116
172
|
1: `"${strings[0] ?? ""}"`
|
|
117
173
|
}[strings.length] ?? "";
|
|
118
174
|
//#endregion
|
|
119
175
|
//#region ../src/js/shared/utils/module.ts
|
|
176
|
+
/**
|
|
177
|
+
* @internal @brnshkr/config
|
|
178
|
+
*/
|
|
120
179
|
const PACKAGE_RESOLVERS = {
|
|
180
|
+
...COMMITLINT_PACKAGE_RESOLVERS,
|
|
121
181
|
...ESLINT_PACKAGE_RESOLVERS,
|
|
122
|
-
...
|
|
182
|
+
...MARKDOWNLINT_PACKAGE_RESOLVERS,
|
|
183
|
+
...STYLELINT_PACKAGE_RESOLVERS,
|
|
184
|
+
...VITEST_PACKAGE_RESOLVERS
|
|
123
185
|
};
|
|
124
186
|
const warnMissingPackages = (moduleInfo, packages, type) => {
|
|
125
|
-
log(
|
|
126
|
-
log(
|
|
187
|
+
log(`Failed resolving required dependencies for module "${moduleInfo.name}". Please install ${joinAsQuotedList([...packages], type === "requiredAny" ? "disjunction" : "conjunction")} or disable the ${moduleInfo.name} module in the config.`);
|
|
188
|
+
log(`Run \`bun a -D -E ${packages.join(" ")}\` to install.`);
|
|
127
189
|
};
|
|
128
190
|
const packageCache = {};
|
|
191
|
+
const loadPackageAsynchronously = async (thePackage) => {
|
|
192
|
+
try {
|
|
193
|
+
return await PACKAGE_RESOLVERS[thePackage]();
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const loadPackageSynchronously = (thePackage) => {
|
|
199
|
+
try {
|
|
200
|
+
return PACKAGE_RESOLVERS[thePackage]();
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const collectPackagesAsynchronously = async (moduleInfo, type, packages) => {
|
|
206
|
+
const collectedPackages = [];
|
|
207
|
+
for (const thePackage of packages) {
|
|
208
|
+
const resolvedPackage = packageCache[thePackage] ?? await loadPackageAsynchronously(thePackage);
|
|
209
|
+
packageCache[thePackage] ??= resolvedPackage;
|
|
210
|
+
if (type === "requiredAll" && resolvedPackage === false) {
|
|
211
|
+
warnMissingPackages(moduleInfo, packages, type);
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
collectedPackages.push(resolvedPackage === false ? void 0 : resolvedPackage);
|
|
215
|
+
}
|
|
216
|
+
return collectedPackages;
|
|
217
|
+
};
|
|
218
|
+
const collectPackagesSynchronously = (moduleInfo, type, packages) => {
|
|
219
|
+
const collectedPackages = [];
|
|
220
|
+
for (const thePackage of packages) {
|
|
221
|
+
const resolvedPackage = packageCache[thePackage] ?? loadPackageSynchronously(thePackage);
|
|
222
|
+
packageCache[thePackage] ??= resolvedPackage;
|
|
223
|
+
if (type === "requiredAll" && resolvedPackage === false) {
|
|
224
|
+
warnMissingPackages(moduleInfo, packages, type);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
collectedPackages.push(resolvedPackage === false ? void 0 : resolvedPackage);
|
|
228
|
+
}
|
|
229
|
+
return collectedPackages;
|
|
230
|
+
};
|
|
129
231
|
const resolvePackagesSharedAsynchronously = async (moduleInfo, type) => {
|
|
130
232
|
if (moduleInfo.packages === void 0) return {};
|
|
131
233
|
const resolvedPackages = {};
|
|
132
234
|
const packages = type === void 0 ? moduleInfo.packages : { [type]: moduleInfo.packages[type] };
|
|
133
235
|
for (const [currentType, currentPackages] of objectEntries(packages)) {
|
|
134
236
|
if (!currentPackages || currentPackages.length === 0) continue;
|
|
135
|
-
resolvedPackages[currentType]
|
|
136
|
-
for (const currentPackage of currentPackages) try {
|
|
137
|
-
const resolvedPackage = packageCache[currentPackage] ?? await PACKAGE_RESOLVERS[currentPackage]();
|
|
138
|
-
packageCache[currentPackage] ??= resolvedPackage;
|
|
139
|
-
if (resolvedPackage === false) throw new Error("Skip to catch block.");
|
|
140
|
-
resolvedPackages[currentType].push(resolvedPackage);
|
|
141
|
-
} catch {
|
|
142
|
-
if (currentType === "requiredAll") {
|
|
143
|
-
warnMissingPackages(moduleInfo, currentPackages, currentType);
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
resolvedPackages[currentType].push(void 0);
|
|
147
|
-
}
|
|
237
|
+
resolvedPackages[currentType] = await collectPackagesAsynchronously(moduleInfo, currentType, currentPackages);
|
|
148
238
|
if (currentType === "requiredAny" && resolvedPackages[currentType].filter((thePackage) => thePackage !== void 0).length === 0) warnMissingPackages(moduleInfo, currentPackages, currentType);
|
|
149
239
|
}
|
|
150
240
|
return type === void 0 ? resolvedPackages : resolvedPackages[type] ?? [];
|
|
@@ -155,19 +245,7 @@ const resolvePackagesSharedSynchronously = (moduleInfo, type) => {
|
|
|
155
245
|
const packages = type === void 0 ? moduleInfo.packages : { [type]: moduleInfo.packages[type] };
|
|
156
246
|
for (const [currentType, currentPackages] of objectEntries(packages)) {
|
|
157
247
|
if (!currentPackages || currentPackages.length === 0) continue;
|
|
158
|
-
resolvedPackages[currentType]
|
|
159
|
-
for (const currentPackage of currentPackages) try {
|
|
160
|
-
const resolvedPackage = packageCache[currentPackage] ?? PACKAGE_RESOLVERS[currentPackage]();
|
|
161
|
-
packageCache[currentPackage] ??= resolvedPackage;
|
|
162
|
-
if (resolvedPackage === false) throw new Error("Skip to catch block.");
|
|
163
|
-
resolvedPackages[currentType].push(resolvedPackage);
|
|
164
|
-
} catch {
|
|
165
|
-
if (currentType === "requiredAll") {
|
|
166
|
-
warnMissingPackages(moduleInfo, currentPackages, currentType);
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
resolvedPackages[currentType].push(void 0);
|
|
170
|
-
}
|
|
248
|
+
resolvedPackages[currentType] = collectPackagesSynchronously(moduleInfo, currentType, currentPackages);
|
|
171
249
|
if (currentType === "requiredAny" && resolvedPackages[currentType].filter((thePackage) => thePackage !== void 0).length === 0) warnMissingPackages(moduleInfo, currentPackages, currentType);
|
|
172
250
|
}
|
|
173
251
|
return type === void 0 ? resolvedPackages : resolvedPackages[type] ?? [];
|
|
@@ -180,13 +258,31 @@ const isModuleEnabledByDefault = (moduleInfo) => {
|
|
|
180
258
|
let isEnabled = false;
|
|
181
259
|
for (const [currentType, currentPackages] of objectEntries(packages)) {
|
|
182
260
|
if (currentType === "optional") continue;
|
|
183
|
-
if (currentPackages && currentPackages.length > 0) isEnabled = currentType === "requiredAll" ? doAllPackagesExist
|
|
261
|
+
if (currentPackages && currentPackages.length > 0) isEnabled = (currentType === "requiredAll" ? doAllPackagesExist : doesAnyPackageExist)(currentPackages);
|
|
184
262
|
if (isEnabled) break;
|
|
185
263
|
}
|
|
186
264
|
return isEnabled;
|
|
187
265
|
};
|
|
266
|
+
const createModuleState = () => {
|
|
267
|
+
const enabledStates = {};
|
|
268
|
+
return {
|
|
269
|
+
isModuleEnabled: (moduleInfo) => enabledStates[moduleInfo.name] ?? isModuleEnabledByDefault(moduleInfo),
|
|
270
|
+
setModuleEnabled: (moduleInfo, isEnabled) => {
|
|
271
|
+
enabledStates[moduleInfo.name] = isEnabled;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
};
|
|
188
275
|
//#endregion
|
|
189
276
|
//#region ../src/js/shared/utils/globs.ts
|
|
277
|
+
/**
|
|
278
|
+
* @internal @brnshkr/config
|
|
279
|
+
*/
|
|
280
|
+
const GLOB_TEST_FILES = [
|
|
281
|
+
"**/__tests__/**/*.?(c|m)[jt]s?(x)",
|
|
282
|
+
"**/*.spec.?(c|m)[jt]s?(x)",
|
|
283
|
+
"**/*.test.?(c|m)[jt]s?(x)"
|
|
284
|
+
];
|
|
285
|
+
const GLOB_BENCHMARK_FILES = ["**/*.bench.?(c|m)[jt]s?(x)", "**/*.benchmark.?(c|m)[jt]s?(x)"];
|
|
190
286
|
const GLOB_IGNORES = [
|
|
191
287
|
"**/.cache/**",
|
|
192
288
|
"**/.changeset/**",
|
|
@@ -195,6 +291,7 @@ const GLOB_IGNORES = [
|
|
|
195
291
|
"**/.hg/store/**",
|
|
196
292
|
"**/.history/**",
|
|
197
293
|
"**/.idea/**",
|
|
294
|
+
"**/.local/**",
|
|
198
295
|
"**/.next/**",
|
|
199
296
|
"**/.nuxt/**",
|
|
200
297
|
"**/.output/**",
|
|
@@ -204,7 +301,9 @@ const GLOB_IGNORES = [
|
|
|
204
301
|
"**/.vercel/**",
|
|
205
302
|
"**/.vite-inspect/**",
|
|
206
303
|
"**/.vitepress/cache/**",
|
|
304
|
+
"**/.vitest/**",
|
|
207
305
|
"**/.yarn/**",
|
|
306
|
+
"**/__generated__/**",
|
|
208
307
|
"**/__snapshots__/**",
|
|
209
308
|
"**/*.code-search",
|
|
210
309
|
"**/*.example",
|
|
@@ -219,13 +318,256 @@ const GLOB_IGNORES = [
|
|
|
219
318
|
"**/package-lock.json",
|
|
220
319
|
"**/pnpm-lock.yaml",
|
|
221
320
|
"**/temp/**",
|
|
321
|
+
"**/tests/**/[Ff]ixture?(s)/**",
|
|
222
322
|
"**/tmp/**",
|
|
223
323
|
"**/vendor/**",
|
|
224
324
|
"**/vite.config.*.timestamp-*",
|
|
225
325
|
"**/yarn.lock"
|
|
226
326
|
];
|
|
227
327
|
//#endregion
|
|
328
|
+
//#region ../src/js/shared/utils/filesystem.ts
|
|
329
|
+
/**
|
|
330
|
+
* @internal @brnshkr/config
|
|
331
|
+
*/
|
|
332
|
+
const toPosix = (value) => value.replaceAll("\\", "/");
|
|
333
|
+
const doesFileExist = (filePath) => {
|
|
334
|
+
try {
|
|
335
|
+
fs.accessSync(filePath, fs.constants.R_OK);
|
|
336
|
+
return true;
|
|
337
|
+
} catch {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
const getMtime = (filePath) => {
|
|
342
|
+
try {
|
|
343
|
+
return fs.statSync(filePath).mtimeMs;
|
|
344
|
+
} catch {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
const readTextFile = (filePath) => {
|
|
349
|
+
try {
|
|
350
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
351
|
+
} catch {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
const readJsonFile = (filePath) => {
|
|
356
|
+
const content = readTextFile(filePath);
|
|
357
|
+
if (content === void 0) return;
|
|
358
|
+
try {
|
|
359
|
+
return JSON.parse(content);
|
|
360
|
+
} catch {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const readJsonObjectFile = (filePath) => {
|
|
365
|
+
const parsedContent = readJsonFile(filePath);
|
|
366
|
+
return isPlainObject(parsedContent) ? parsedContent : void 0;
|
|
367
|
+
};
|
|
368
|
+
const findNearestPackageJson = (startDirectory) => {
|
|
369
|
+
let current = path.resolve(startDirectory);
|
|
370
|
+
let parent = path.dirname(current);
|
|
371
|
+
while (current !== parent) {
|
|
372
|
+
const candidate = path.join(current, "package.json");
|
|
373
|
+
if (doesFileExist(candidate)) return candidate;
|
|
374
|
+
current = parent;
|
|
375
|
+
parent = path.dirname(current);
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
//#endregion
|
|
228
379
|
//#region ../src/js/shared/utils/constants.ts
|
|
229
380
|
const QUOTES = "single";
|
|
230
381
|
//#endregion
|
|
231
|
-
|
|
382
|
+
//#region ../src/js/spelling/utils/files.ts
|
|
383
|
+
/**
|
|
384
|
+
* @internal @brnshkr/config/spelling
|
|
385
|
+
*/
|
|
386
|
+
const COMMAND_TIMEOUT_MILLISECONDS = 6e4;
|
|
387
|
+
const listTrackedFiles = (rootDirectory) => {
|
|
388
|
+
return execFileSync("git", ["ls-files", "-z"], {
|
|
389
|
+
cwd: rootDirectory,
|
|
390
|
+
encoding: "utf-8",
|
|
391
|
+
maxBuffer: Infinity,
|
|
392
|
+
timeout: COMMAND_TIMEOUT_MILLISECONDS
|
|
393
|
+
}).split("\0").filter((filePath) => filePath !== "");
|
|
394
|
+
};
|
|
395
|
+
const isScannedPath = (filePath, scannedExtensions, scannedNames, ignoreExpressions) => {
|
|
396
|
+
if (ignoreExpressions.some((ignoreExpression) => ignoreExpression.test(filePath))) return false;
|
|
397
|
+
return scannedNames.has(path.basename(filePath)) || scannedExtensions.has(path.extname(filePath));
|
|
398
|
+
};
|
|
399
|
+
const collectFilePaths = (rootDirectory, settings) => {
|
|
400
|
+
const scannedExtensions = new Set(settings.fileExtensions);
|
|
401
|
+
const scannedNames = new Set(settings.fileNames);
|
|
402
|
+
const ignoreExpressions = settings.ignorePatterns.map((ignorePattern) => new RegExp(ignorePattern, "u"));
|
|
403
|
+
return listTrackedFiles(rootDirectory).filter((filePath) => isScannedPath(filePath, scannedExtensions, scannedNames, ignoreExpressions)).filter((filePath) => doesFileExist(path.join(rootDirectory, filePath)));
|
|
404
|
+
};
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region ../src/js/spelling/utils/patterns.ts
|
|
407
|
+
/**
|
|
408
|
+
* @internal @brnshkr/config/spelling
|
|
409
|
+
*/
|
|
410
|
+
const buildPatterns = (settings) => {
|
|
411
|
+
const stemSuffixGroup = `(?:${settings.stemSuffixes.join("|")})`;
|
|
412
|
+
return [...objectEntries(settings.britishSpellings).map(([britishSpelling, americanSpelling]) => ({
|
|
413
|
+
pattern: new RegExp(String.raw`\b${britishSpelling}\w*`, "giv"),
|
|
414
|
+
toAmericanSpelling: (word) => americanSpelling + word.slice(britishSpelling.length)
|
|
415
|
+
})), ...settings.britishStems.map((britishStem) => ({
|
|
416
|
+
pattern: new RegExp(String.raw`\b${britishStem}${stemSuffixGroup}\b`, "giv"),
|
|
417
|
+
toAmericanSpelling: (word) => `${britishStem.slice(0, -1)}z${word.slice(britishStem.length)}`
|
|
418
|
+
}))];
|
|
419
|
+
};
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region ../src/js/spelling/utils/settings.ts
|
|
422
|
+
/**
|
|
423
|
+
* @internal @brnshkr/config/spelling
|
|
424
|
+
*/
|
|
425
|
+
const EVERY_PATH$1 = "*";
|
|
426
|
+
const DEFAULTS_FILE = "defaults.json";
|
|
427
|
+
const LINE_SUFFIX_PATTERN = /^(?<text>.*):(?<lineNumbers>\d+(?:,\d+)*)$/v;
|
|
428
|
+
const findShippedDirectory = () => {
|
|
429
|
+
const packageJsonPath = findNearestPackageJson(import.meta.dirname);
|
|
430
|
+
if (packageJsonPath === void 0) throw new Error("Unable to locate the shipped defaults of \"@brnshkr/config\".");
|
|
431
|
+
return path.join(path.dirname(packageJsonPath), "conf", "spelling");
|
|
432
|
+
};
|
|
433
|
+
const readSettingsFile = (filePath) => {
|
|
434
|
+
const settings = readJsonObjectFile(filePath);
|
|
435
|
+
if (settings === void 0) throw new Error(`Unable to read "${filePath}".`);
|
|
436
|
+
return settings;
|
|
437
|
+
};
|
|
438
|
+
const readStringList = (settings, settingName) => {
|
|
439
|
+
const declaredSetting = settings[settingName];
|
|
440
|
+
return Array.isArray(declaredSetting) ? declaredSetting.filter((entry) => typeof entry === "string") : [];
|
|
441
|
+
};
|
|
442
|
+
const readStringMap = (settings, settingName) => {
|
|
443
|
+
const declaredSetting = settings[settingName];
|
|
444
|
+
const stringMap = {};
|
|
445
|
+
if (!isPlainObject(declaredSetting)) return stringMap;
|
|
446
|
+
for (const [settingKey, entry] of objectEntries(declaredSetting)) if (typeof entry === "string") stringMap[settingKey] = entry;
|
|
447
|
+
return stringMap;
|
|
448
|
+
};
|
|
449
|
+
const readStringListMap = (settings, settingName) => {
|
|
450
|
+
const declaredSetting = settings[settingName];
|
|
451
|
+
const stringListMap = {};
|
|
452
|
+
if (!isPlainObject(declaredSetting)) return stringListMap;
|
|
453
|
+
for (const settingKey of objectKeys(declaredSetting)) stringListMap[settingKey] = readStringList(declaredSetting, settingKey);
|
|
454
|
+
return stringListMap;
|
|
455
|
+
};
|
|
456
|
+
const toSettings = (settings) => ({
|
|
457
|
+
fileExtensions: readStringList(settings, "fileExtensions"),
|
|
458
|
+
fileNames: readStringList(settings, "fileNames"),
|
|
459
|
+
ignorePatterns: readStringList(settings, "ignorePatterns"),
|
|
460
|
+
britishSpellings: readStringMap(settings, "britishSpellings"),
|
|
461
|
+
britishStems: readStringList(settings, "britishStems"),
|
|
462
|
+
stemSuffixes: readStringList(settings, "stemSuffixes"),
|
|
463
|
+
allowlist: readStringListMap(settings, "allowlist")
|
|
464
|
+
});
|
|
465
|
+
const mergeLists = (shippedEntries, declaredEntries) => [.../* @__PURE__ */ new Set([...shippedEntries, ...declaredEntries])];
|
|
466
|
+
const mergeSettings = (shippedSettings, declaredSettings) => ({
|
|
467
|
+
fileExtensions: mergeLists(shippedSettings.fileExtensions, declaredSettings.fileExtensions),
|
|
468
|
+
fileNames: mergeLists(shippedSettings.fileNames, declaredSettings.fileNames),
|
|
469
|
+
ignorePatterns: mergeLists(shippedSettings.ignorePatterns, declaredSettings.ignorePatterns),
|
|
470
|
+
britishSpellings: {
|
|
471
|
+
...shippedSettings.britishSpellings,
|
|
472
|
+
...declaredSettings.britishSpellings
|
|
473
|
+
},
|
|
474
|
+
britishStems: mergeLists(shippedSettings.britishStems, declaredSettings.britishStems),
|
|
475
|
+
stemSuffixes: mergeLists(shippedSettings.stemSuffixes, declaredSettings.stemSuffixes),
|
|
476
|
+
allowlist: {
|
|
477
|
+
...shippedSettings.allowlist,
|
|
478
|
+
...declaredSettings.allowlist
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
const readSettings = (rootDirectory, configPath) => {
|
|
482
|
+
const shippedPath = path.join(findShippedDirectory(), DEFAULTS_FILE);
|
|
483
|
+
const shippedSettings = toSettings(readSettingsFile(shippedPath));
|
|
484
|
+
const settingsPath = path.resolve(rootDirectory, configPath);
|
|
485
|
+
return doesFileExist(settingsPath) ? mergeSettings(shippedSettings, toSettings(readSettingsFile(settingsPath))) : shippedSettings;
|
|
486
|
+
};
|
|
487
|
+
const parseAllowedLiterals = (declaredLiterals) => declaredLiterals.map((declaredLiteral) => {
|
|
488
|
+
const matchedGroups = LINE_SUFFIX_PATTERN.exec(declaredLiteral)?.groups;
|
|
489
|
+
return {
|
|
490
|
+
text: matchedGroups?.["text"] ?? declaredLiteral,
|
|
491
|
+
lineNumbers: matchedGroups === void 0 ? void 0 : (matchedGroups["lineNumbers"] ?? "").split(",").map(Number)
|
|
492
|
+
};
|
|
493
|
+
});
|
|
494
|
+
const isCoveredBy = (coveringCandidate, allowedLiteral) => {
|
|
495
|
+
if (coveringCandidate.text.toLowerCase() !== allowedLiteral.text.toLowerCase()) return false;
|
|
496
|
+
if (coveringCandidate.lineNumbers === void 0) return true;
|
|
497
|
+
return allowedLiteral.lineNumbers?.every((lineNumber) => coveringCandidate.lineNumbers?.includes(lineNumber) === true) ?? false;
|
|
498
|
+
};
|
|
499
|
+
const formatAllowedLiteral = ({ text, lineNumbers }) => lineNumbers === void 0 ? text : `${text}:${lineNumbers.join(",")}`;
|
|
500
|
+
const rejectCoveredLiterals = (allowlist) => {
|
|
501
|
+
const literalsAllowedEverywhere = allowlist[EVERY_PATH$1] ?? [];
|
|
502
|
+
for (const [allowedPath, allowedLiterals] of objectEntries(allowlist)) for (const [index, allowedLiteral] of allowedLiterals.entries()) {
|
|
503
|
+
const coveringLiteral = [...allowedPath === EVERY_PATH$1 ? [] : literalsAllowedEverywhere, ...allowedLiterals.slice(0, index)].find((coveringCandidate) => isCoveredBy(coveringCandidate, allowedLiteral));
|
|
504
|
+
if (coveringLiteral !== void 0) throw new Error(`Allowed word "${formatAllowedLiteral(allowedLiteral)}" under "${allowedPath}" is already covered by "${formatAllowedLiteral(coveringLiteral)}".`);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
const readAllowlist = (settings) => {
|
|
508
|
+
const allowlist = {};
|
|
509
|
+
const allowlistEntries = objectEntries(settings.allowlist ?? {});
|
|
510
|
+
for (const [allowedPath, declaredLiterals] of allowlistEntries) allowlist[allowedPath] = parseAllowedLiterals(declaredLiterals);
|
|
511
|
+
rejectCoveredLiterals(allowlist);
|
|
512
|
+
return allowlist;
|
|
513
|
+
};
|
|
514
|
+
//#endregion
|
|
515
|
+
//#region ../src/js/spelling/index.ts
|
|
516
|
+
const EVERY_PATH = "*";
|
|
517
|
+
const DEFAULT_CONFIG_PATH = "conf/spelling.json";
|
|
518
|
+
const REGEX_METACHARACTERS = /[$\(\)*+.?\[\\\]^\{\|\}]/gv;
|
|
519
|
+
const escapeRegexLiteral = (value) => value.replaceAll(REGEX_METACHARACTERS, String.raw`\$&`);
|
|
520
|
+
const maskAllowedLiterals = (line, allowedLiterals, lineNumber) => {
|
|
521
|
+
let maskedLine = line;
|
|
522
|
+
for (const { text, lineNumbers } of allowedLiterals) if (lineNumbers === void 0 || lineNumbers.includes(lineNumber)) maskedLine = maskedLine.replaceAll(new RegExp(escapeRegexLiteral(text), "giu"), (matchedText) => ".".repeat(matchedText.length));
|
|
523
|
+
return maskedLine;
|
|
524
|
+
};
|
|
525
|
+
const compareCaseInsensitively = (firstValue, secondValue) => {
|
|
526
|
+
const firstLowercased = firstValue.toLowerCase();
|
|
527
|
+
const secondLowercased = secondValue.toLowerCase();
|
|
528
|
+
if (firstLowercased !== secondLowercased) return firstLowercased < secondLowercased ? -1 : 1;
|
|
529
|
+
return firstValue < secondValue ? -1 : Number(firstValue > secondValue);
|
|
530
|
+
};
|
|
531
|
+
const compareFindings = (firstFinding, secondFinding) => {
|
|
532
|
+
const pathOrder = compareCaseInsensitively(firstFinding.path, secondFinding.path);
|
|
533
|
+
if (pathOrder !== 0) return pathOrder;
|
|
534
|
+
return firstFinding.line === secondFinding.line ? compareCaseInsensitively(firstFinding.word, secondFinding.word) : firstFinding.line - secondFinding.line;
|
|
535
|
+
};
|
|
536
|
+
const findInFile = (fileContents, filePath, patterns, allowlist) => {
|
|
537
|
+
const allowedLiterals = [...allowlist[EVERY_PATH] ?? [], ...allowlist[filePath] ?? []];
|
|
538
|
+
const findings = [];
|
|
539
|
+
for (const [index, line] of fileContents.split("\n").entries()) {
|
|
540
|
+
const lineNumber = index + 1;
|
|
541
|
+
const maskedLine = maskAllowedLiterals(line, allowedLiterals, lineNumber);
|
|
542
|
+
for (const { pattern, toAmericanSpelling } of patterns) for (const [word] of maskedLine.matchAll(pattern)) findings.push({
|
|
543
|
+
path: filePath,
|
|
544
|
+
line: lineNumber,
|
|
545
|
+
word,
|
|
546
|
+
suggestion: toAmericanSpelling(word)
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
return findings;
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Report every British spelling in a repository's tracked prose, docblocks and identifiers.
|
|
553
|
+
*
|
|
554
|
+
* @api
|
|
555
|
+
*
|
|
556
|
+
* @param options where to scan, which settings to read, and which files to look at
|
|
557
|
+
*
|
|
558
|
+
* @returns every finding, sorted by path, line and word
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```js
|
|
562
|
+
* scan({ rootDirectory: process.cwd() });
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
const scan = (options) => {
|
|
566
|
+
const { rootDirectory = process.cwd(), configPath = DEFAULT_CONFIG_PATH, paths } = options ?? {};
|
|
567
|
+
const settings = readSettings(rootDirectory, configPath);
|
|
568
|
+
const allowlist = readAllowlist(settings);
|
|
569
|
+
const patterns = buildPatterns(settings);
|
|
570
|
+
return (paths ?? collectFilePaths(rootDirectory, settings)).map((filePath) => findInFile(readTextFile(path.join(rootDirectory, filePath)) ?? "", filePath, patterns, allowlist)).flat().toSorted(compareFindings);
|
|
571
|
+
};
|
|
572
|
+
//#endregion
|
|
573
|
+
export { name as A, objectAssign as C, objectValues as D, objectKeys as E, packageOrganization as O, isPlainObject as S, objectFromEntries as T, COMMITLINT_PACKAGES as _, getMtime as a, STYLELINT_PACKAGES as b, toPosix as c, GLOB_TEST_FILES as d, createModuleState as f, resolvePackagesSharedSynchronously as g, resolvePackagesSharedAsynchronously as h, findNearestPackageJson as i, version as j, packageOrganizationUpper as k, GLOB_BENCHMARK_FILES as l, isModuleEnabledByDefault as m, QUOTES as n, readJsonObjectFile as o, doAllPackagesExist as p, doesFileExist as r, readTextFile as s, scan as t, GLOB_IGNORES as u, ESLINT_PACKAGES as v, objectEntries as w, VITEST_PACKAGES as x, MARKDOWNLINT_PACKAGES as y };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region ../src/js/spelling/types/options.d.ts
|
|
2
|
+
interface SpellingOptions {
|
|
3
|
+
rootDirectory?: string;
|
|
4
|
+
configPath?: string;
|
|
5
|
+
paths?: string[];
|
|
6
|
+
}
|
|
7
|
+
interface SpellingFinding {
|
|
8
|
+
path: string;
|
|
9
|
+
line: number;
|
|
10
|
+
word: string;
|
|
11
|
+
suggestion: string;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region ../src/js/spelling/index.d.ts
|
|
15
|
+
/**
|
|
16
|
+
* Report every British spelling in a repository's tracked prose, docblocks and identifiers.
|
|
17
|
+
*
|
|
18
|
+
* @api
|
|
19
|
+
*
|
|
20
|
+
* @param options where to scan, which settings to read, and which files to look at
|
|
21
|
+
*
|
|
22
|
+
* @returns every finding, sorted by path, line and word
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```js
|
|
26
|
+
* scan({ rootDirectory: process.cwd() });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const scan: (options?: Partial<SpellingOptions>) => SpellingFinding[];
|
|
30
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as scan } from "../shared.mjs";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
//#region ../src/js/spelling/spelling.test.ts
|
|
4
|
+
/**
|
|
5
|
+
* @internal @brnshkr/config/spelling
|
|
6
|
+
*/
|
|
7
|
+
test("every tracked file is written in american english", () => {
|
|
8
|
+
const findings = scan().map(({ path, line, word, suggestion }) => `${path}:${String(line)} — "${word}", use "${suggestion}"`);
|
|
9
|
+
expect(findings).toStrictEqual([]);
|
|
10
|
+
});
|
|
11
|
+
//#endregion
|
|
12
|
+
export {};
|