@cluerise/tools 3.0.1 → 4.0.1

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.
@@ -1,10 +1,105 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+ var _packageName, _CoreConfig_static, rootDirectory_get, _command, _ConsoleStatusLogger_static, createResultMessage_fn, _config, _CommitLinter_instances, isValidEnumValue_fn, isValidType_fn, isValidScope_fn, _CommitLinter_static, parseSemanticCommitMessage_fn, _options, _eslint, _eslintFixer, _FileLinter_static, preparePrettierLintResult_fn, _FileLinter_instances, prettierLint_fn, prepareESLintLintResult_fn, eslintLint_fn;
10
+ import Path from "node:path";
1
11
  import { z, ZodError } from "zod";
2
- import ChildProcess from "child_process";
12
+ import ChildProcess from "node:child_process";
13
+ import loadCommitlintConfig from "@commitlint/load";
14
+ import FileSystem from "node:fs/promises";
15
+ import OS from "node:os";
3
16
  import { ESLint } from "eslint";
4
- import FileSystem from "fs/promises";
5
17
  import { glob } from "glob";
6
18
  import * as Prettier from "prettier";
7
- import "@commitlint/load";
19
+ class CoreConfig {
20
+ /**
21
+ * Determines if the application is running in production mode.
22
+ *
23
+ * This is based on the environment variable `import.meta.env.PROD`.
24
+ *
25
+ * @returns True if in production mode, false otherwise.
26
+ */
27
+ static get isProd() {
28
+ return true;
29
+ }
30
+ /**
31
+ * Returns the package and its path to the configuration files.
32
+ *
33
+ * This is used to load configurations from the package in production mode.
34
+ *
35
+ * @returns The path to the configuration files in the package.
36
+ */
37
+ static get configPackage() {
38
+ return `${__privateGet(this, _packageName)}/dist/configs`;
39
+ }
40
+ /**
41
+ * Returns the directory where configuration files are stored.
42
+ *
43
+ * In production mode, this points to the `dist/configs` directory within the package.
44
+ * In development mode, it points to the root directory.
45
+ *
46
+ * @returns The path to the configuration directory.
47
+ */
48
+ static get configDirectory() {
49
+ return this.isProd ? `${__privateGet(this, _CoreConfig_static, rootDirectory_get)}/dist/configs` : __privateGet(this, _CoreConfig_static, rootDirectory_get);
50
+ }
51
+ }
52
+ _packageName = new WeakMap();
53
+ _CoreConfig_static = new WeakSet();
54
+ rootDirectory_get = function() {
55
+ return this.isProd ? `./node_modules/${__privateGet(this, _packageName)}` : ".";
56
+ };
57
+ __privateAdd(CoreConfig, _CoreConfig_static);
58
+ __privateAdd(CoreConfig, _packageName, "@cluerise/tools");
59
+ const _ConsoleStatusLogger = class _ConsoleStatusLogger {
60
+ constructor(command) {
61
+ __privateAdd(this, _command);
62
+ __privateSet(this, _command, command);
63
+ }
64
+ /**
65
+ * Begins logging for a command with the specified argument.
66
+ *
67
+ * @param argument - The argument for the command.
68
+ *
69
+ * @example
70
+ * const logger = new ConsoleStatusLogger('Linting');
71
+ * logger.begin('src/index.ts'); // Logs: "Linting src/index.ts..."
72
+ */
73
+ begin(argument) {
74
+ console.info(`${__privateGet(this, _command)} ${argument}...`);
75
+ }
76
+ /**
77
+ * Ends logging for a command with the specified argument and exit code.
78
+ *
79
+ * @param argument - The argument for the command.
80
+ * @param exitCode - The exit code of the command execution. If null, it indicates completion without an error.
81
+ *
82
+ * @example
83
+ * const logger = new ConsoleStatusLogger('Linting');
84
+ * logger.end('src/index.ts'); // Logs: "Linting src/index.ts... Done"
85
+ * logger.end('src/index.ts', 0); // Logs: "Linting src/index.ts... OK"
86
+ * logger.end('src/index.ts', 1); // Logs: "Linting src/index.ts... Failed"
87
+ */
88
+ end(argument, exitCode = null) {
89
+ var _a;
90
+ console.info(`${__privateGet(this, _command)} ${argument}... ${__privateMethod(_a = _ConsoleStatusLogger, _ConsoleStatusLogger_static, createResultMessage_fn).call(_a, exitCode)}`);
91
+ }
92
+ };
93
+ _command = new WeakMap();
94
+ _ConsoleStatusLogger_static = new WeakSet();
95
+ createResultMessage_fn = function(exitCode) {
96
+ if (exitCode === null) {
97
+ return "Done";
98
+ }
99
+ return exitCode === 0 ? "OK" : "Failed";
100
+ };
101
+ __privateAdd(_ConsoleStatusLogger, _ConsoleStatusLogger_static);
102
+ let ConsoleStatusLogger = _ConsoleStatusLogger;
8
103
  const enginesSchema = z.object({
9
104
  node: z.string()
10
105
  });
@@ -22,139 +117,347 @@ z.object({
22
117
  repository: repositorySchema.optional()
23
118
  });
24
119
  const runMain = (main2) => {
25
- main2(process.argv.slice(2)).then((exitCode) => {
120
+ Promise.resolve().then(() => main2(process.argv.slice(2))).then((exitCode) => {
26
121
  process.exit(exitCode);
27
122
  }).catch((error) => {
28
- console.error(error);
123
+ console.error("Error:", error);
29
124
  process.exit(1);
30
125
  });
31
126
  };
32
- const createResultMessage = (exitCode) => {
33
- if (exitCode === null) {
34
- return "Done";
127
+ class StringUtils {
128
+ /**
129
+ * Capitalizes the first letter of a given string.
130
+ *
131
+ * @param value - The string to capitalize.
132
+ * @returns The string with the first letter capitalized.
133
+ */
134
+ static capitalize(value) {
135
+ const [firstLetter] = value;
136
+ if (!firstLetter) {
137
+ return value;
138
+ }
139
+ return `${firstLetter.toUpperCase()}${value.slice(1)}`;
140
+ }
141
+ }
142
+ const _CommitLinter = class _CommitLinter {
143
+ constructor(config) {
144
+ __privateAdd(this, _CommitLinter_instances);
145
+ __privateAdd(this, _config);
146
+ __privateSet(this, _config, config);
147
+ }
148
+ /**
149
+ * Initializes the CommitLinter with the loaded commitlint configuration.
150
+ *
151
+ * @returns A Promise that resolves to an instance of CommitLinter.
152
+ */
153
+ static async init() {
154
+ const config = await loadCommitlintConfig();
155
+ return new _CommitLinter(config);
156
+ }
157
+ /**
158
+ * Lints commit messages using commitlint.
159
+ *
160
+ * @param args - An array of arguments to pass to commitlint.
161
+ * @returns The exit status of the commitlint command.
162
+ */
163
+ static lint(args) {
164
+ const { status } = ChildProcess.spawnSync("commitlint", args, { stdio: "inherit" });
165
+ return status ?? 0;
166
+ }
167
+ /**
168
+ * Parses a semantic branch name into its type and scope.
169
+ *
170
+ * @param name - The branch name to parse.
171
+ * @returns An object containing the type and scope of the commit message.
172
+ * @throws An error if the branch name is invalid.
173
+ */
174
+ parseSemanticBranchName(name) {
175
+ const [typeValue, scopeValue] = name.split("-");
176
+ if (!typeValue || !__privateMethod(this, _CommitLinter_instances, isValidType_fn).call(this, typeValue)) {
177
+ throw new Error("Invalid commit type in branch name");
178
+ }
179
+ const type = typeValue.toLowerCase();
180
+ const scope = scopeValue && __privateMethod(this, _CommitLinter_instances, isValidScope_fn).call(this, scopeValue) ? scopeValue.toLowerCase() : null;
181
+ return {
182
+ type,
183
+ scope
184
+ };
185
+ }
186
+ /**
187
+ * Returns the prefix of a semantic commit message as a string.
188
+ *
189
+ * This prefix consists of the type and scope of the commit message.
190
+ * If the scope is not provided, it will only return the type.
191
+ * @param prefix - An object containing the type and scope of the commit message.
192
+ * @returns
193
+ */
194
+ static stringifySemanticCommitMessagePrefix({ type, scope }) {
195
+ return `${type}${scope ? `(${scope})` : ""}`;
196
+ }
197
+ /**
198
+ * Formats a semantic commit message by capitalizing the content after the prefix.
199
+ *
200
+ * @param message - The commit message to format.
201
+ * @returns The formatted commit message.
202
+ */
203
+ static formatSemanticCommitMessage(message) {
204
+ const { prefix, content } = __privateMethod(this, _CommitLinter_static, parseSemanticCommitMessage_fn).call(this, message);
205
+ if (!prefix || !content) {
206
+ return message;
207
+ }
208
+ return `${prefix}: ${StringUtils.capitalize(content)}`;
209
+ }
210
+ /**
211
+ * Creates a semantic commit message from a prefix and a message.
212
+ *
213
+ * @param prefix - The prefix of the commit message, containing type and scope.
214
+ * @param message - The content of the commit message.
215
+ * @returns The formatted semantic commit message.
216
+ */
217
+ static createSemanticCommitMessage(prefix, message) {
218
+ const [subject, ...comments] = message.split("\n#");
219
+ let commitMessage = this.stringifySemanticCommitMessagePrefix(prefix) + ": ";
220
+ if (subject) {
221
+ commitMessage += StringUtils.capitalize(subject);
222
+ }
223
+ if (comments.length > 0) {
224
+ commitMessage += "\n\n#" + comments.join("\n#");
225
+ }
226
+ return commitMessage;
35
227
  }
36
- return exitCode === 0 ? "OK" : "Failed";
37
228
  };
38
- const createStatusConsole = (command) => ({
39
- printBegin: (arg) => console.info(`${command} ${arg}...`),
40
- printEnd: (arg, exitCode = null) => console.info(`${command} ${arg}... ${createResultMessage(exitCode)}`)
41
- });
42
- const lintCommit = (args) => {
43
- const { status } = ChildProcess.spawnSync("commitlint", args, { stdio: "inherit" });
44
- return status ?? 0;
229
+ _config = new WeakMap();
230
+ _CommitLinter_instances = new WeakSet();
231
+ isValidEnumValue_fn = function(ruleName, value) {
232
+ const rule = __privateGet(this, _config).rules[ruleName];
233
+ if (!rule) {
234
+ return true;
235
+ }
236
+ const [_severity, _condition, values] = rule;
237
+ if (!values) {
238
+ return true;
239
+ }
240
+ return values.includes(value);
241
+ };
242
+ isValidType_fn = function(type) {
243
+ return __privateMethod(this, _CommitLinter_instances, isValidEnumValue_fn).call(this, "type-enum", type);
45
244
  };
46
- const lintFilesScopeShortcutSchema = z.union([z.literal("all"), z.literal("code")]);
47
- const scopePatterns = {
48
- all: ["**"],
49
- code: ["src/**"]
245
+ isValidScope_fn = function(scope) {
246
+ return __privateMethod(this, _CommitLinter_instances, isValidEnumValue_fn).call(this, "scope-enum", scope);
50
247
  };
51
- const scopeShortcuts = Object.keys(scopePatterns);
52
- const isScopeShortcut = (scope) => scopeShortcuts.includes(scope);
53
- const resolveScope = (scope) => {
54
- if (Array.isArray(scope)) {
55
- return scope;
248
+ _CommitLinter_static = new WeakSet();
249
+ parseSemanticCommitMessage_fn = function(message) {
250
+ const firstColonPosition = message.search(":");
251
+ const prefix = message.slice(0, firstColonPosition).trim();
252
+ const content = message.slice(firstColonPosition + 1).trim();
253
+ return { prefix, content };
254
+ };
255
+ __privateAdd(_CommitLinter, _CommitLinter_static);
256
+ let CommitLinter = _CommitLinter;
257
+ const _FileLinter = class _FileLinter {
258
+ constructor(options) {
259
+ __privateAdd(this, _FileLinter_instances);
260
+ __privateAdd(this, _options);
261
+ __privateAdd(this, _eslint);
262
+ __privateAdd(this, _eslintFixer, null);
263
+ __privateSet(this, _options, options ?? null);
264
+ __privateSet(this, _eslint, new ESLint({
265
+ overrideConfigFile: options == null ? void 0 : options.configPath
266
+ }));
267
+ if (options == null ? void 0 : options.fix) {
268
+ __privateSet(this, _eslintFixer, new ESLint({
269
+ fix: options.fix,
270
+ overrideConfigFile: options == null ? void 0 : options.configPath
271
+ }));
272
+ }
56
273
  }
57
- if (isScopeShortcut(scope)) {
58
- return scopePatterns[scope];
274
+ /**
275
+ * Lints files using `lint-staged` with the provided arguments.
276
+ *
277
+ * @param args - An array of arguments to pass to `lint-staged`.
278
+ * @returns The exit status of the `lint-staged` command.
279
+ */
280
+ static lintStaged(args) {
281
+ const { status } = ChildProcess.spawnSync("lint-staged", args, { stdio: "inherit" });
282
+ return status ?? 0;
283
+ }
284
+ /**
285
+ * Lints files matching the provided patterns using ESLint and Prettier.
286
+ *
287
+ * @param patterns - An array of glob patterns to match files against. Defaults to ['**'] which matches all files.
288
+ * @returns A promise that resolves to a LintFilesResult indicating the success or failure of the linting process.
289
+ */
290
+ async lint(patterns = ["**"]) {
291
+ var _a;
292
+ const prettierResults = await __privateMethod(this, _FileLinter_instances, prettierLint_fn).call(this, patterns);
293
+ const eslintResults = await __privateMethod(this, _FileLinter_instances, eslintLint_fn).call(this, patterns);
294
+ const eslintResult = await __privateMethod(this, _FileLinter_instances, prepareESLintLintResult_fn).call(this, eslintResults);
295
+ if (eslintResult.status === "failure") {
296
+ return eslintResult;
297
+ }
298
+ const prettierResult = __privateMethod(_a = _FileLinter, _FileLinter_static, preparePrettierLintResult_fn).call(_a, prettierResults);
299
+ if (prettierResult.status === "failure") {
300
+ return prettierResult;
301
+ }
302
+ return {
303
+ status: "success"
304
+ };
59
305
  }
60
- return [scope];
61
306
  };
62
- const formatWithPrettier = async (patterns) => {
63
- const eslint = new ESLint();
307
+ _options = new WeakMap();
308
+ _eslint = new WeakMap();
309
+ _eslintFixer = new WeakMap();
310
+ _FileLinter_static = new WeakSet();
311
+ preparePrettierLintResult_fn = function(results) {
312
+ if (results.length === 0) {
313
+ return { status: "success" };
314
+ }
315
+ const title = `Linting with Prettier failed with ${results.length} problem${results.length === 1 ? "" : "s"}
316
+ `;
317
+ let message = "Prettier failed with the following files:\n";
318
+ message += results.map((result) => `- ${result.path}`).join("\n");
319
+ message += OS.EOL;
320
+ return {
321
+ status: "failure",
322
+ title,
323
+ message,
324
+ problemCount: results.length
325
+ };
326
+ };
327
+ _FileLinter_instances = new WeakSet();
328
+ prettierLint_fn = async function(patterns) {
64
329
  const configPath = await Prettier.resolveConfigFile();
65
330
  if (!configPath) {
66
- return false;
331
+ return [];
67
332
  }
68
333
  const config = await Prettier.resolveConfig(configPath);
69
334
  if (!config) {
70
- return false;
335
+ return [];
71
336
  }
72
337
  const paths = await glob(patterns, {
73
338
  nodir: true,
74
339
  ignore: "node_modules/**"
75
340
  });
76
- await Promise.all(
341
+ const results = await Promise.all(
77
342
  paths.map(async (path) => {
78
- if (await eslint.isPathIgnored(path)) {
79
- return;
343
+ var _a;
344
+ if (await __privateGet(this, _eslint).isPathIgnored(path)) {
345
+ return null;
346
+ }
347
+ const contentBuffer = await FileSystem.readFile(path);
348
+ const content = contentBuffer.toString();
349
+ if ((_a = __privateGet(this, _options)) == null ? void 0 : _a.fix) {
350
+ const nextContent = await Prettier.format(content, {
351
+ ...config,
352
+ filepath: path
353
+ });
354
+ await FileSystem.writeFile(path, nextContent);
355
+ return null;
80
356
  }
81
- const prevContent = (await FileSystem.readFile(path)).toString();
82
- const nextContent = await Prettier.format(prevContent, {
357
+ const result = await Prettier.check(content, {
83
358
  ...config,
84
359
  filepath: path
85
360
  });
86
- await FileSystem.writeFile(path, nextContent);
361
+ return result ? null : { path };
87
362
  })
88
363
  );
364
+ return results.filter((result) => result !== null);
89
365
  };
90
- const lintFiles = async (scope, options) => {
91
- const patterns = resolveScope(scope);
92
- if (options == null ? void 0 : options.fix) {
93
- await formatWithPrettier(patterns);
94
- }
95
- const eslint = new ESLint({
96
- fix: options == null ? void 0 : options.fix
97
- });
98
- const results = await eslint.lintFiles(patterns);
99
- const problemCount = results.reduce((sum, result) => sum + result.errorCount + result.warningCount, 0);
100
- if (options == null ? void 0 : options.fix) {
101
- await ESLint.outputFixes(results);
102
- }
103
- if (problemCount > 0) {
104
- const formatter = await eslint.loadFormatter("stylish");
105
- const resultText = formatter.format(results);
106
- console.error(resultText);
107
- const errorMessage = `Linting failed with ${problemCount} problem${problemCount === 1 ? "" : "s"}.`;
108
- throw new Error(errorMessage);
366
+ prepareESLintLintResult_fn = async function(results) {
367
+ const problemCount = results.reduce(
368
+ (sum, result) => {
369
+ var _a;
370
+ return sum + result.errorCount + result.warningCount + (((_a = __privateGet(this, _options)) == null ? void 0 : _a.fix) ? -(result.fixableErrorCount + result.fixableWarningCount) : 0);
371
+ },
372
+ 0
373
+ );
374
+ if (problemCount === 0) {
375
+ return { status: "success" };
109
376
  }
377
+ const title = `ESLint failed with ${problemCount} problem${problemCount === 1 ? "" : "s"}`;
378
+ const formatter = await __privateGet(this, _eslint).loadFormatter("stylish");
379
+ const message = await formatter.format(results);
380
+ return {
381
+ status: "failure",
382
+ title,
383
+ message,
384
+ problemCount
385
+ };
110
386
  };
111
- const lintStaged = (args) => {
112
- const { status } = ChildProcess.spawnSync("lint-staged", args, { stdio: "inherit" });
113
- return status ?? 0;
114
- };
115
- const LintCommands = {
116
- lintFiles,
117
- lintCommit,
118
- lintStaged
387
+ eslintLint_fn = async function(patterns) {
388
+ const results = await __privateGet(this, _eslint).lintFiles(patterns);
389
+ const errorResults = ESLint.getErrorResults(results);
390
+ if (__privateGet(this, _eslintFixer) && errorResults.length > 0) {
391
+ await ESLint.outputFixes(await __privateGet(this, _eslintFixer).lintFiles(patterns));
392
+ }
393
+ return results;
119
394
  };
120
- const lintScopeArgSchema = z.union([lintFilesScopeShortcutSchema, z.literal("commit"), z.literal("staged")]);
395
+ __privateAdd(_FileLinter, _FileLinter_static);
396
+ let FileLinter = _FileLinter;
397
+ const lintScopeArgSchema = z.union([z.literal("all"), z.literal("fix"), z.literal("commit"), z.literal("staged")]);
121
398
  const parseLintArgs = ([scopeArg]) => {
122
399
  const scope = lintScopeArgSchema.parse(scopeArg);
123
400
  return {
124
401
  scope
125
402
  };
126
403
  };
127
- const lintingConsole = createStatusConsole("Linting");
128
404
  const main = async (args) => {
129
405
  try {
130
406
  const { scope } = parseLintArgs(args);
131
- lintingConsole.printBegin(scope);
407
+ const statusLogger = new ConsoleStatusLogger("Linting");
408
+ statusLogger.begin(scope);
132
409
  if (scope === "commit") {
133
- const exitCode = LintCommands.lintCommit(args.slice(1));
134
- lintingConsole.printEnd(scope, exitCode);
410
+ const exitCode = CommitLinter.lint(args.slice(1));
411
+ statusLogger.end(scope, exitCode);
135
412
  return exitCode;
136
413
  }
137
414
  if (scope === "staged") {
138
- const exitCode = LintCommands.lintStaged(args.slice(1));
139
- lintingConsole.printEnd(scope, exitCode);
415
+ const exitCode = FileLinter.lintStaged(args.slice(1));
416
+ statusLogger.end(scope, exitCode);
140
417
  return exitCode;
141
418
  }
142
- await LintCommands.lintFiles(scope);
143
- lintingConsole.printEnd(scope);
419
+ const fix = scope === "fix";
420
+ const fileLinter = new FileLinter({ fix });
421
+ const lintStatus = await fileLinter.lint();
422
+ if (lintStatus.status === "failure") {
423
+ console.error(lintStatus.title);
424
+ console.error(lintStatus.message);
425
+ statusLogger.end(scope, 1);
426
+ return 1;
427
+ }
428
+ const markdownLinter = new FileLinter({
429
+ configPath: Path.join(CoreConfig.configDirectory, "eslint-markdown.config.js"),
430
+ fix
431
+ });
432
+ try {
433
+ const markdownLintStatus = await markdownLinter.lint(["**/*.md"]);
434
+ if (markdownLintStatus.status === "failure") {
435
+ console.error(markdownLintStatus.title);
436
+ console.error(markdownLintStatus.message);
437
+ statusLogger.end(scope, 1);
438
+ return 1;
439
+ }
440
+ } catch (error) {
441
+ const allFilesIgnoredError = error instanceof Error && "messageTemplate" in error && error.messageTemplate === "all-matched-files-ignored";
442
+ if (!allFilesIgnoredError) {
443
+ throw error;
444
+ }
445
+ }
446
+ statusLogger.end(scope);
144
447
  return 0;
145
448
  } catch (error) {
146
449
  if (error instanceof ZodError) {
147
450
  const firstIssue = error.issues[0];
148
451
  if ((firstIssue == null ? void 0 : firstIssue.code) === "invalid_union") {
149
- console.error("Invalid scope");
452
+ console.error("Error: Invalid scope");
150
453
  return 1;
151
454
  }
152
455
  }
153
456
  if (error instanceof Error) {
154
- console.error(error.message);
155
- return 1;
457
+ console.error("Error:", error.message);
458
+ } else {
459
+ console.error("Error:", error);
156
460
  }
157
- console.error(error);
158
461
  return 1;
159
462
  }
160
463
  };