@theholocron/cli 1.0.0

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.
Files changed (95) hide show
  1. package/.alexignore +3 -0
  2. package/.editorconfig +24 -0
  3. package/.editorconfig-checker.json +20 -0
  4. package/.env +3 -0
  5. package/.gitattributes +12 -0
  6. package/.github/CODEOWNERS +1 -0
  7. package/.github/dependabot.yml +6 -0
  8. package/.github/labeler.yml +21 -0
  9. package/.github/workflows/bookkeeping-pr.yml +32 -0
  10. package/.github/workflows/greetings.yml +32 -0
  11. package/.github/workflows/lint.yml +96 -0
  12. package/.github/workflows/publish.yml +71 -0
  13. package/.github/workflows/review.yml +72 -0
  14. package/.github/workflows/stale.yml +25 -0
  15. package/.husky/commit-msg +1 -0
  16. package/.husky/pre-commit +13 -0
  17. package/.husky/prepare-commit-msg +18 -0
  18. package/LICENSE +674 -0
  19. package/README.md +17 -0
  20. package/commitlint.config.js +9 -0
  21. package/eslint.config.js +9 -0
  22. package/media/README.md +11 -0
  23. package/media/error.mp3 +0 -0
  24. package/media/success.mp3 +0 -0
  25. package/media/warning.mp3 +0 -0
  26. package/package.json +71 -0
  27. package/prettier.config.js +11 -0
  28. package/src/cli.ts +65 -0
  29. package/src/commands/README.md +13 -0
  30. package/src/commands/bootstrap.ts +102 -0
  31. package/src/commands/conf/README.md +45 -0
  32. package/src/commands/conf/add.ts +49 -0
  33. package/src/commands/conf/edit.ts +12 -0
  34. package/src/commands/conf/view.ts +40 -0
  35. package/src/commands/conf.ts +10 -0
  36. package/src/commands/log.ts +91 -0
  37. package/src/const.ts +19 -0
  38. package/src/tasks/README.md +33 -0
  39. package/src/tasks/find/README.md +49 -0
  40. package/src/tasks/find/find-project.example.ts +23 -0
  41. package/src/tasks/find/find-project.ts +76 -0
  42. package/src/tasks/find/index.ts +1 -0
  43. package/src/tasks/index.ts +2 -0
  44. package/src/tasks/replace/README.md +61 -0
  45. package/src/tasks/replace/index.ts +1 -0
  46. package/src/tasks/replace/replace.example.ts +31 -0
  47. package/src/tasks/replace/replace.ts +95 -0
  48. package/src/ui/README.md +8 -0
  49. package/src/ui/index.ts +2 -0
  50. package/src/ui/open/README.md +58 -0
  51. package/src/ui/open/index.ts +7 -0
  52. package/src/ui/open/open-browser.ts +25 -0
  53. package/src/ui/open/open-editor.example.ts +14 -0
  54. package/src/ui/open/open-editor.ts +30 -0
  55. package/src/ui/prompts/README.md +36 -0
  56. package/src/ui/prompts/autocomplete.prompt.ts +18 -0
  57. package/src/ui/prompts/confirm.prompt.ts +21 -0
  58. package/src/ui/prompts/index.ts +17 -0
  59. package/src/ui/prompts/input.prompt.ts +15 -0
  60. package/src/ui/prompts/search.prompt.ts +33 -0
  61. package/src/ui/prompts/select.prompt.ts +17 -0
  62. package/src/ui/prompts/types.ts +8 -0
  63. package/src/ui/prompts/utils.ts +11 -0
  64. package/src/utils/$/README.md +87 -0
  65. package/src/utils/$/command.test.ts +48 -0
  66. package/src/utils/$/command.ts +21 -0
  67. package/src/utils/$/directory.ts +108 -0
  68. package/src/utils/$/file.ts +98 -0
  69. package/src/utils/$/index.example.ts +37 -0
  70. package/src/utils/$/index.ts +22 -0
  71. package/src/utils/$/path.ts +13 -0
  72. package/src/utils/$/remove.ts +47 -0
  73. package/src/utils/$/spawn.ts +26 -0
  74. package/src/utils/$/utils.ts +21 -0
  75. package/src/utils/README.md +15 -0
  76. package/src/utils/config/README.md +41 -0
  77. package/src/utils/config/config.ts +26 -0
  78. package/src/utils/config/index.ts +1 -0
  79. package/src/utils/config/preferences.conf.ts +45 -0
  80. package/src/utils/env/README.md +52 -0
  81. package/src/utils/env/env.example.ts +21 -0
  82. package/src/utils/env/env.ts +57 -0
  83. package/src/utils/env/index.ts +1 -0
  84. package/src/utils/index.ts +5 -0
  85. package/src/utils/log/README.md +117 -0
  86. package/src/utils/log/index.ts +2 -0
  87. package/src/utils/log/log.example.ts +13 -0
  88. package/src/utils/log/log.ts +58 -0
  89. package/src/utils/log/logger.ts +28 -0
  90. package/src/utils/log/sound.ts +35 -0
  91. package/src/utils/node/README.md +23 -0
  92. package/src/utils/node/index.ts +5 -0
  93. package/src/utils/node/package.ts +12 -0
  94. package/tsconfig.json +15 -0
  95. package/yamllint.config.yml +20 -0
@@ -0,0 +1,52 @@
1
+ # Environment Variables
2
+
3
+ A wrapper around [`dotenv`](https://github.com/motdotla/dotenv) that provides a configuration file for storing environment variables.
4
+
5
+ The configuration will pull from a `.env` file within the repository and place all of that data onto the `process.env` for instant access.
6
+
7
+ ## Usage
8
+
9
+ ```javascript
10
+ import { env } from "@/utils";
11
+
12
+ // grab every value within the configuration file
13
+ const [readErr, readData] = env.read();
14
+
15
+ // grab a specific variable
16
+ const [readAllErr, readAllData] = env.read("SOME_ENV_VAR");
17
+
18
+ // set a specific variable
19
+ const [writeErr, writeData] = env.write({ mockKey: "mockValue" });
20
+ ```
21
+
22
+ ### When to use `env` methods or `process.env`
23
+
24
+ #### Use `process.env` for accessing environment variables
25
+
26
+ The point of `dotenv` is to allow you to put environment variables within a file in order to have them show up on `process.env`. So if you need access to any environment variable, rather than running it on the command-line, you can add it to the `.env` and it will be present.
27
+
28
+ #### Use `env.read()` for interfacing with the configuration file
29
+
30
+ Whenever you want the application to read the configuration file or values on it, then use `env.read()`. Common use cases would be to read the configuration before changing it, or reading the values to use it for setting something else such as a file name.
31
+
32
+ #### Use `env.write()` for writing to or updating the configuration file
33
+
34
+ Whenever you want the application to change the configuration file or values on it, then use `env.write()`. This will set permanent changes to the configuration file.
35
+
36
+ ## API
37
+
38
+ ### `.read(key?: string)`
39
+
40
+ Returns the value of the key specified or the entire environment variables object if no key is present.
41
+
42
+ #### key
43
+
44
+ Type: `string`
45
+
46
+ ### `.write(obj: Record<string, string>)`
47
+
48
+ Returns `true` if writing to the environment variables file was successful, or `false` if there was an error.
49
+
50
+ #### obj
51
+
52
+ Type: `Record<string, string>`
@@ -0,0 +1,21 @@
1
+ import { env } from "@/utils";
2
+
3
+ const [err, data] = env.read();
4
+
5
+ if (err) {
6
+ console.error(err);
7
+ process.exit(1);
8
+ }
9
+
10
+ console.log("Complete env");
11
+ console.log(data);
12
+
13
+ const [singleErr, singleData] = env.read("VERBOSE");
14
+
15
+ if (singleErr) {
16
+ console.error(singleErr);
17
+ process.exit(1);
18
+ }
19
+
20
+ console.log("Single key env");
21
+ console.log(singleData);
@@ -0,0 +1,57 @@
1
+ import fs from "node:fs";
2
+ import dotenv from "dotenv";
3
+
4
+ const ENV_CONF = `${process.cwd()}/.env`;
5
+
6
+ /**
7
+ * Reads environment variables from the .env file.
8
+ */
9
+ type ReadEnvReturn<T> = [Error | null, T];
10
+
11
+ const readEnv = <T = Record<string, string>>(key?: string): ReadEnvReturn<T> => {
12
+ try {
13
+ const result = dotenv.config();
14
+
15
+ if (result.error) {
16
+ return [result.error, {} as T];
17
+ }
18
+
19
+ const parsedData = result.parsed || {};
20
+
21
+ if (key && parsedData.hasOwnProperty(key)) {
22
+ return [null, parsedData[key] as T];
23
+ }
24
+
25
+ return [null, parsedData as T];
26
+ } catch (error) {
27
+ return [error as Error, {} as T];
28
+ }
29
+ };
30
+
31
+ /**
32
+ * Writes environment variables to the .env file.
33
+ */
34
+ const writeEnv = (obj: Record<string, string>): [Error | null, boolean] => {
35
+ try {
36
+ const [_, conf] = readEnv();
37
+
38
+ const newConf = {
39
+ ...conf,
40
+ ...obj,
41
+ };
42
+
43
+ const content = Object.entries(newConf)
44
+ .map(([key, value]) => `${key}=${value}`)
45
+ .join("\n");
46
+
47
+ fs.writeFileSync(ENV_CONF, content, { flag: "w+" });
48
+ return [null, true];
49
+ } catch (err) {
50
+ return [err as Error, false];
51
+ }
52
+ };
53
+
54
+ export const env = {
55
+ read: readEnv,
56
+ write: writeEnv,
57
+ };
@@ -0,0 +1 @@
1
+ export * from "./env";
@@ -0,0 +1,5 @@
1
+ export * from "./$";
2
+ export * from "./config";
3
+ export * from "./env";
4
+ export * from "./log";
5
+ export * from "./node";
@@ -0,0 +1,117 @@
1
+ # Log
2
+
3
+ A logger with different levels and formatting options.
4
+
5
+ This provides functions for logging messages with different log levels (error, info, success, warning). Each log level has its own formatting for better readability.
6
+
7
+ ## Usage
8
+
9
+ ```javascript
10
+ import { log } from "@/utils";
11
+
12
+ const FN = "func";
13
+ const options = { debug: true };
14
+
15
+ console.log(log.style.bold("this message is bold"));
16
+
17
+ log.data(FN, "key", { test: "value"}, options);
18
+ log.error(FN, "This is an error message", options);
19
+ log.info(FN, "This is an info message", options);
20
+ log.process(FN, "this is a processing message", options);
21
+ log.success(FN, "This is a success message", options);
22
+ log.warning(FN, "This is a warning message", options);
23
+ ```
24
+
25
+ ## API
26
+
27
+ All functions take `CLIOptions` as the last argument, which allow you to pass in an object with `debug` as a boolean to allow you to print to the console and `sound` as a boolean to allow sound as feedback.
28
+
29
+ ### `.data(prefix: string, key: string, message: any, options: CLIOptions)`
30
+
31
+ Logs data with a function prefix.
32
+
33
+ #### prefix
34
+
35
+ The function name to be identified in the logs.
36
+
37
+ Type: `string`
38
+
39
+ #### key
40
+
41
+ A name for the data.
42
+
43
+ Type: `string`
44
+
45
+ #### message
46
+
47
+ Type: `any`
48
+
49
+ ### `.error(prefix: string, message: string)`
50
+
51
+ Logs an error message with a function prefix.
52
+
53
+ #### prefix
54
+
55
+ The function name to be identified in the logs.
56
+
57
+ Type: `string`
58
+
59
+ #### message
60
+
61
+ Type: `string`
62
+
63
+ ### `.info(prefix: string, message: string)`
64
+
65
+ Logs an info message with a function prefix.
66
+
67
+ #### prefix
68
+
69
+ The function name to be identified in the logs.
70
+
71
+ Type: `string`
72
+
73
+ #### message
74
+
75
+ Type: `string`
76
+
77
+ ### `.process(prefix: string, message: string)`
78
+
79
+ Logs a message for a running process with a function prefix.
80
+
81
+ #### prefix
82
+
83
+ The function name to be identified in the logs.
84
+
85
+ Type: `string`
86
+
87
+ #### message
88
+
89
+ Type: `string`
90
+
91
+ ### `.success(prefix: string, message: string)`
92
+
93
+ Logs a success message with a function prefix.
94
+
95
+ #### prefix
96
+
97
+ The function name to be identified in the logs.
98
+
99
+ Type: `string`
100
+
101
+ #### message
102
+
103
+ Type: `string`
104
+
105
+ ### `.warning(prefix: string, message: string)`
106
+
107
+ Logs a warning message with a function prefix.
108
+
109
+ #### prefix
110
+
111
+ The function name to be identified in the logs.
112
+
113
+ Type: `string`
114
+
115
+ #### message
116
+
117
+ Type: `string`
@@ -0,0 +1,2 @@
1
+ export * from "./log";
2
+ export { type LogLevel } from "./logger";
@@ -0,0 +1,13 @@
1
+ import { log } from "@/utils";
2
+
3
+ const FN = "func";
4
+ const options = { debug: true };
5
+
6
+ console.log(log.style.bold("this message is bold"));
7
+
8
+ log.data(FN, "key", { test: "value" }, options);
9
+ log.error(FN, "This is an error message", options);
10
+ log.info(FN, "This is an info message", options);
11
+ log.process(FN, "this is a processing message", options);
12
+ log.success(FN, "This is a success message", options);
13
+ log.warning(FN, "This is a warning message", options);
@@ -0,0 +1,58 @@
1
+ import chalk from "chalk";
2
+ import { type CLIOptions } from "@/cli";
3
+ import { logger } from "./logger";
4
+ import { sound } from "./sound";
5
+
6
+ type LoggerFunction = (prefix: string, message: string, options?: CLIOptions) => void;
7
+
8
+ const bold = (str: string) => chalk.magenta.bold(str);
9
+
10
+ const data = (prefix: string, key: string, message: any, options: CLIOptions) => {
11
+ options?.debug && console.log(chalk.cyan(`[${prefix}]:`), chalk.bgWhiteBright(`${key}:`), message);
12
+ };
13
+
14
+ const error: LoggerFunction = (prefix, message, options) => {
15
+ logger.error(`[${prefix}] error: ${message}`);
16
+
17
+ console.log(chalk.red.bold(message));
18
+ options?.sound && sound.error();
19
+ };
20
+
21
+ const info: LoggerFunction = (prefix, message, options) => {
22
+ logger.info(`[${prefix}] info: ${message}`);
23
+
24
+ options?.debug && console.log(chalk.cyan(`[${prefix}]:`), message);
25
+ };
26
+
27
+ const processing: LoggerFunction = (prefix, message, options) => {
28
+ logger.info(`[${prefix}] processing: ${message}`);
29
+
30
+ options?.debug && console.log(chalk.magenta(`[${prefix}]:`), message);
31
+ };
32
+
33
+ const success: LoggerFunction = (prefix, message, options) => {
34
+ logger.info(`[${prefix}] success: ${message}`);
35
+
36
+ console.log(chalk.green.bold(message));
37
+ options?.sound && sound.success();
38
+ };
39
+
40
+ const warning: LoggerFunction = (prefix, message, options) => {
41
+ logger.warn(`[${prefix}] warning: ${message}`);
42
+
43
+ console.log(chalk.yellow.bold(message));
44
+ options?.sound && sound.warning();
45
+ };
46
+
47
+ export const log = {
48
+ bold,
49
+ data,
50
+ error,
51
+ info,
52
+ process: processing,
53
+ success,
54
+ style: {
55
+ bold,
56
+ },
57
+ warning,
58
+ };
@@ -0,0 +1,28 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import winston from "winston";
4
+ import { config } from "@/utils";
5
+
6
+ const LOGS = config.get("preferences.logs");
7
+
8
+ if (!fs.existsSync(LOGS)) {
9
+ fs.mkdirSync(LOGS, { recursive: true });
10
+ }
11
+
12
+ export type LogLevel = "error" | "warn" | "info" | "verbose" | "debug" | "all";
13
+
14
+ export const logger = winston.createLogger({
15
+ level: "info" as LogLevel,
16
+ format: winston.format.combine(
17
+ winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
18
+ winston.format.printf(({ timestamp, level, message }) => `${timestamp} ${level}: ${message}`)
19
+ ),
20
+ transports: [
21
+ new winston.transports.File({ filename: path.join(LOGS, "error.log"), level: "error" as LogLevel }),
22
+ new winston.transports.File({ filename: path.join(LOGS, "warn.log"), level: "warn" as LogLevel }),
23
+ new winston.transports.File({ filename: path.join(LOGS, "info.log"), level: "info" as LogLevel }),
24
+ new winston.transports.File({ filename: path.join(LOGS, "verbose.log"), level: "verbose" as LogLevel }),
25
+ new winston.transports.File({ filename: path.join(LOGS, "debug.log"), level: "debug" as LogLevel }),
26
+ new winston.transports.File({ filename: path.join(LOGS, "log") }), // General log file
27
+ ],
28
+ });
@@ -0,0 +1,35 @@
1
+ import play from "play-sound";
2
+
3
+ const player = play();
4
+
5
+ async function playSound(soundPath: string): Promise<void> {
6
+ return new Promise((resolve, reject) => {
7
+ player.play(soundPath, (err: Error | null) => {
8
+ if (err) {
9
+ reject(err);
10
+ } else {
11
+ resolve();
12
+ }
13
+ });
14
+ });
15
+ }
16
+
17
+ type FeedbackFunction = () => Promise<void>;
18
+
19
+ const error: FeedbackFunction = async () => {
20
+ await playSound("./media/error.mp3");
21
+ };
22
+
23
+ const success: FeedbackFunction = async () => {
24
+ await playSound("./media/success.mp3");
25
+ };
26
+
27
+ const warning: FeedbackFunction = async () => {
28
+ await playSound("./media/warning.mp3");
29
+ };
30
+
31
+ export const sound = {
32
+ error,
33
+ success,
34
+ warning,
35
+ };
@@ -0,0 +1,23 @@
1
+ # Node
2
+
3
+ Interact with node packages.
4
+
5
+ ## Usage
6
+
7
+ ```javascript
8
+ import { node } from "@/utils";
9
+
10
+ const name = node.pkg("~/code/foo");
11
+ ```
12
+
13
+ ## API
14
+
15
+ ### `.pkg(dirPath: string)`
16
+
17
+ Grabs the data from the package in parsed JSON.
18
+
19
+ #### dirPath
20
+
21
+ The pathway to the `package.json`.
22
+
23
+ Type: `string`
@@ -0,0 +1,5 @@
1
+ import { getPackage } from "./package";
2
+
3
+ export const node = {
4
+ pkg: getPackage,
5
+ };
@@ -0,0 +1,12 @@
1
+ import { promises as fs } from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ export async function getPackage(dirPath: string): Promise<string | null> {
5
+ try {
6
+ const pkg = await fs.readFile(path.join(dirPath, "package.json"), "utf-8");
7
+
8
+ return [null, JSON.parse(pkg)];
9
+ } catch (error) {
10
+ return [error];
11
+ }
12
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "display": "Holocron CLI",
3
+ "extends": "@tsconfig/node-lts/tsconfig.json",
4
+ "compilerOptions": {
5
+ "baseUrl": "./",
6
+ "outDir": "./dist",
7
+ "paths": {
8
+ "@/media": ["./media/*"],
9
+ "@/package": ["./package.json"],
10
+ "@/*": ["./src/*"]
11
+ }
12
+ },
13
+ "include": ["**/*.ts"],
14
+ "exclude": ["./node_modules"]
15
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+
3
+ extends: default
4
+
5
+ rules:
6
+ comments:
7
+ min-spaces-from-content: 1
8
+ require-starting-space: true
9
+
10
+ comments-indentation: {}
11
+
12
+ document-start:
13
+ ignore: |
14
+ .github/*.yml
15
+
16
+ indentation:
17
+ spaces: consistent
18
+ indent-sequences: consistent
19
+
20
+ line-length: disable