@reliverse/relinka 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 (63) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +141 -0
  3. package/output/components/animate.d.ts +13 -0
  4. package/output/components/animate.js +55 -0
  5. package/output/components/any-key.d.ts +7 -0
  6. package/output/components/any-key.js +56 -0
  7. package/output/components/ascii-art.d.ts +6 -0
  8. package/output/components/ascii-art.js +12 -0
  9. package/output/components/confirm.d.ts +3 -0
  10. package/output/components/confirm.js +99 -0
  11. package/output/components/date.d.ts +6 -0
  12. package/output/components/date.js +125 -0
  13. package/output/components/end.d.ts +2 -0
  14. package/output/components/end.js +36 -0
  15. package/output/components/mono.d.ts +5 -0
  16. package/output/components/mono.js +64 -0
  17. package/output/components/next-steps.d.ts +2 -0
  18. package/output/components/next-steps.js +25 -0
  19. package/output/components/num-multi-select.d.ts +3 -0
  20. package/output/components/num-multi-select.js +108 -0
  21. package/output/components/num-select.d.ts +5 -0
  22. package/output/components/num-select.js +122 -0
  23. package/output/components/number.d.ts +3 -0
  24. package/output/components/number.js +92 -0
  25. package/output/components/password.d.ts +3 -0
  26. package/output/components/password.js +117 -0
  27. package/output/components/results.d.ts +10 -0
  28. package/output/components/results.js +34 -0
  29. package/output/components/select.d.ts +2 -0
  30. package/output/components/select.js +97 -0
  31. package/output/components/spinner.d.ts +15 -0
  32. package/output/components/spinner.js +110 -0
  33. package/output/components/start.d.ts +2 -0
  34. package/output/components/start.js +33 -0
  35. package/output/components/text.d.ts +3 -0
  36. package/output/components/text.js +88 -0
  37. package/output/hooks/useKeyPress.d.ts +4 -0
  38. package/output/hooks/useKeyPress.js +14 -0
  39. package/output/main.d.ts +16 -0
  40. package/output/main.js +16 -0
  41. package/output/types/prod.d.ts +83 -0
  42. package/output/types/prod.js +0 -0
  43. package/output/utils/colorize.d.ts +2 -0
  44. package/output/utils/colorize.js +129 -0
  45. package/output/utils/errors.d.ts +1 -0
  46. package/output/utils/errors.js +11 -0
  47. package/output/utils/mapping.d.ts +4 -0
  48. package/output/utils/mapping.js +49 -0
  49. package/output/utils/messages.d.ts +17 -0
  50. package/output/utils/messages.js +203 -0
  51. package/output/utils/platforms.d.ts +1 -0
  52. package/output/utils/platforms.js +22 -0
  53. package/output/utils/prompt-tmp.d.ts +13 -0
  54. package/output/utils/prompt-tmp.js +254 -0
  55. package/output/utils/prompt.d.ts +13 -0
  56. package/output/utils/prompt.js +254 -0
  57. package/output/utils/readline.d.ts +2 -0
  58. package/output/utils/readline.js +9 -0
  59. package/output/utils/terminal.d.ts +5 -0
  60. package/output/utils/terminal.js +33 -0
  61. package/output/utils/variants.d.ts +9 -0
  62. package/output/utils/variants.js +49 -0
  63. package/package.json +96 -0
@@ -0,0 +1,254 @@
1
+ import { stdin, stdout } from "node:process";
2
+ import readline from "node:readline";
3
+ import { WriteStream } from "node:tty";
4
+ import { cursor, erase } from "sisteransi";
5
+ import wrap from "wrap-ansi";
6
+ function diffLines(a, b) {
7
+ if (a === b) {
8
+ return;
9
+ }
10
+ const aLines = a.split("\n");
11
+ const bLines = b.split("\n");
12
+ const diff = [];
13
+ for (let i = 0; i < Math.max(aLines.length, bLines.length); i++) {
14
+ if (aLines[i] !== bLines[i]) {
15
+ diff.push(i);
16
+ }
17
+ }
18
+ return diff;
19
+ }
20
+ const cancel = Symbol("rp:cancel");
21
+ export function isCancel(value) {
22
+ return value === cancel;
23
+ }
24
+ function setRawMode(input, value) {
25
+ if (input.isTTY) {
26
+ input.setRawMode(value);
27
+ }
28
+ }
29
+ const aliases = /* @__PURE__ */ new Map([
30
+ ["k", "up"],
31
+ ["j", "down"],
32
+ ["h", "left"],
33
+ ["l", "right"]
34
+ ]);
35
+ const keys = /* @__PURE__ */ new Set(["up", "down", "left", "right", "space", "enter"]);
36
+ export function createPrompt({
37
+ render: renderFn,
38
+ input = stdin,
39
+ output = stdout,
40
+ ...opts
41
+ }, trackValue = true) {
42
+ const _input = input;
43
+ const _output = output;
44
+ let _rl;
45
+ const _opts = opts;
46
+ const _track = trackValue;
47
+ let _cursor = 0;
48
+ let state = "initial";
49
+ let value = _opts.initialValue ?? "";
50
+ let error = "";
51
+ const subscribers = /* @__PURE__ */ new Map();
52
+ let _prevFrame = "";
53
+ const self = {};
54
+ const _render = () => renderFn.call(self);
55
+ function prompt() {
56
+ const sink = new WriteStream(0);
57
+ sink._write = (chunk, encoding, done) => {
58
+ if (_track) {
59
+ value = _rl.line.replace(/\t/g, "");
60
+ _cursor = _rl.cursor;
61
+ emit("value", value);
62
+ }
63
+ done();
64
+ };
65
+ _input.pipe(sink);
66
+ _rl = readline.createInterface({
67
+ input: _input,
68
+ output: sink,
69
+ tabSize: 2,
70
+ prompt: "",
71
+ escapeCodeTimeout: 50
72
+ });
73
+ readline.emitKeypressEvents(_input, _rl);
74
+ _rl.prompt();
75
+ if (_opts.initialValue !== void 0 && _track) {
76
+ _rl.write(_opts.initialValue);
77
+ }
78
+ _input.on("keypress", onKeypress);
79
+ setRawMode(_input, true);
80
+ _output.on("resize", render);
81
+ render();
82
+ return new Promise((resolve) => {
83
+ once("submit", () => {
84
+ _output.write(cursor.show);
85
+ _output.off("resize", render);
86
+ setRawMode(_input, false);
87
+ resolve(value);
88
+ });
89
+ once("cancel", () => {
90
+ _output.write(cursor.show);
91
+ _output.off("resize", render);
92
+ setRawMode(_input, false);
93
+ resolve(cancel);
94
+ });
95
+ });
96
+ }
97
+ function on(event, cb) {
98
+ const arr = subscribers.get(event) ?? [];
99
+ arr.push({ cb });
100
+ subscribers.set(event, arr);
101
+ }
102
+ function once(event, cb) {
103
+ const arr = subscribers.get(event) ?? [];
104
+ arr.push({ cb, once: true });
105
+ subscribers.set(event, arr);
106
+ }
107
+ function emit(event, ...data) {
108
+ const cbs = subscribers.get(event) ?? [];
109
+ const cleanup = [];
110
+ for (const subscriber of cbs) {
111
+ subscriber.cb(...data);
112
+ if (subscriber.once) {
113
+ cleanup.push(() => cbs.splice(cbs.indexOf(subscriber), 1));
114
+ }
115
+ }
116
+ for (const cb of cleanup) {
117
+ cb();
118
+ }
119
+ }
120
+ function unsubscribe() {
121
+ subscribers.clear();
122
+ }
123
+ function onKeypress(char, key) {
124
+ if (state === "error") {
125
+ state = "active";
126
+ }
127
+ if (key?.name && !_track && aliases.has(key.name)) {
128
+ emit("cursor", aliases.get(key.name));
129
+ }
130
+ if (key?.name && keys.has(key.name)) {
131
+ emit("cursor", key.name);
132
+ }
133
+ if (char && (char.toLowerCase() === "y" || char.toLowerCase() === "n")) {
134
+ emit("confirm", char.toLowerCase() === "y");
135
+ }
136
+ if (char === " " && _opts.placeholder) {
137
+ if (!value) {
138
+ _rl.write(_opts.placeholder);
139
+ emit("value", _opts.placeholder);
140
+ }
141
+ }
142
+ if (char) {
143
+ emit("key", char.toLowerCase());
144
+ }
145
+ if (key?.name === "return") {
146
+ if (_opts.validate) {
147
+ const problem = _opts.validate(value);
148
+ if (problem) {
149
+ error = problem;
150
+ state = "error";
151
+ _rl.write(value);
152
+ }
153
+ }
154
+ if (state !== "error") {
155
+ state = "submit";
156
+ }
157
+ }
158
+ if (char === "") {
159
+ state = "cancel";
160
+ }
161
+ if (state === "submit" || state === "cancel") {
162
+ emit("finalize");
163
+ }
164
+ render();
165
+ if (state === "submit" || state === "cancel") {
166
+ close();
167
+ }
168
+ }
169
+ function close() {
170
+ _input.unpipe();
171
+ _input.removeListener("keypress", onKeypress);
172
+ _output.write("\n");
173
+ setRawMode(_input, false);
174
+ _rl.close();
175
+ emit(state, value);
176
+ unsubscribe();
177
+ }
178
+ function restoreCursor() {
179
+ const lines = wrap(_prevFrame, process.stdout.columns, { hard: true }).split("\n").length - 1;
180
+ _output.write(cursor.move(-999, lines * -1));
181
+ }
182
+ function render() {
183
+ const frame = wrap(_render() || "", process.stdout.columns, {
184
+ hard: true
185
+ });
186
+ if (frame === _prevFrame) {
187
+ return;
188
+ }
189
+ if (state === "initial") {
190
+ _output.write(cursor.hide);
191
+ } else {
192
+ const diff = diffLines(_prevFrame, frame);
193
+ restoreCursor();
194
+ if (diff && diff.length === 1) {
195
+ const diffLine = diff[0];
196
+ _output.write(cursor.move(0, diffLine));
197
+ _output.write(erase.lines(1));
198
+ const lines = frame.split("\n");
199
+ _output.write(lines[diffLine]);
200
+ _prevFrame = frame;
201
+ _output.write(cursor.move(0, lines.length - diffLine - 1));
202
+ return;
203
+ } else if (diff && diff.length > 1) {
204
+ const diffLine = diff[0];
205
+ _output.write(cursor.move(0, diffLine));
206
+ _output.write(erase.down());
207
+ const lines = frame.split("\n");
208
+ const newLines = lines.slice(diffLine);
209
+ _output.write(newLines.join("\n"));
210
+ _prevFrame = frame;
211
+ return;
212
+ }
213
+ _output.write(erase.down());
214
+ }
215
+ _output.write(frame);
216
+ if (state === "initial") {
217
+ state = "active";
218
+ }
219
+ _prevFrame = frame;
220
+ }
221
+ Object.assign(self, {
222
+ prompt,
223
+ on,
224
+ once,
225
+ emit,
226
+ close,
227
+ render,
228
+ get state() {
229
+ return state;
230
+ },
231
+ set state(val) {
232
+ state = val;
233
+ },
234
+ get value() {
235
+ return value;
236
+ },
237
+ set value(val) {
238
+ value = val;
239
+ },
240
+ get error() {
241
+ return error;
242
+ },
243
+ set error(val) {
244
+ error = val;
245
+ },
246
+ _cursor,
247
+ _track,
248
+ _input,
249
+ _output,
250
+ _rl,
251
+ _opts
252
+ });
253
+ return self;
254
+ }
@@ -0,0 +1,2 @@
1
+ export declare function resetCursorAndClear(stream: NodeJS.WritableStream, x: number, y?: number, callback?: () => void): void;
2
+ export declare function moveCursorAndClear(stream: NodeJS.WritableStream, dx: number, dy: number, callback?: () => void): void;
@@ -0,0 +1,9 @@
1
+ import readline from "node:readline";
2
+ export function resetCursorAndClear(stream, x, y, callback) {
3
+ readline.cursorTo(stream, x, y, callback);
4
+ readline.clearScreenDown(stream, callback);
5
+ }
6
+ export function moveCursorAndClear(stream, dx, dy, callback) {
7
+ readline.moveCursor(stream, dx, dy, callback);
8
+ readline.clearScreenDown(stream, callback);
9
+ }
@@ -0,0 +1,5 @@
1
+ export declare function removeCursor(): void;
2
+ export declare function restoreCursor(): void;
3
+ export declare function deleteLastLine(): void;
4
+ export declare function deleteLastLines(count: number): void;
5
+ export declare function countLines(text: string): number;
@@ -0,0 +1,33 @@
1
+ import ansiEscapes from "ansi-escapes";
2
+ import { cursor } from "sisteransi";
3
+ import wrapAnsi from "wrap-ansi";
4
+ import { msg } from "./messages.js";
5
+ export function removeCursor() {
6
+ process.stdout.write(cursor.hide);
7
+ }
8
+ export function restoreCursor() {
9
+ process.stdout.write(cursor.show);
10
+ }
11
+ export function deleteLastLine() {
12
+ process.stdout.write(ansiEscapes.cursorUp(1) + ansiEscapes.eraseLine);
13
+ }
14
+ export function deleteLastLines(count) {
15
+ if (count <= 0) {
16
+ msg({
17
+ type: "M_ERROR",
18
+ title: "Count is less than or equal to 0. Nothing to delete."
19
+ });
20
+ return;
21
+ }
22
+ process.stdout.write(ansiEscapes.eraseLines(count));
23
+ }
24
+ export function countLines(text) {
25
+ const terminalWidth = process.stdout.columns || 80;
26
+ const lines = text.split("\n");
27
+ let lineCount = 0;
28
+ for (const line of lines) {
29
+ const wrapped = wrapAnsi(line, terminalWidth, { hard: true });
30
+ lineCount += wrapped.split("\n").length;
31
+ }
32
+ return lineCount;
33
+ }
@@ -0,0 +1,9 @@
1
+ import type { ColorName, Variant } from "../types/prod";
2
+ export declare const variantMap: {
3
+ doubleBox: typeof createDoubleBox;
4
+ };
5
+ export declare function applyVariant(lines: string[] | string, variant?: Variant, options?: {
6
+ limit?: number;
7
+ }, borderColor?: ColorName): Promise<string>;
8
+ declare function createDoubleBox(lines: string[], limit?: number, borderColor?: ColorName): string;
9
+ export {};
@@ -0,0 +1,49 @@
1
+ import { colorMap } from "./mapping.js";
2
+ export const variantMap = {
3
+ // box: createBox,
4
+ doubleBox: createDoubleBox
5
+ // banner: createBanner,
6
+ // underline: createUnderline,
7
+ };
8
+ export async function applyVariant(lines, variant, options, borderColor) {
9
+ const linesArray = Array.isArray(lines) ? lines : [lines];
10
+ switch (variant) {
11
+ // case "box":
12
+ // return createBox(linesArray, options?.limit);
13
+ case "doubleBox":
14
+ return createDoubleBox(linesArray, options?.limit, borderColor);
15
+ // case "banner":
16
+ // return createBanner(linesArray);
17
+ // case "underline":
18
+ // return createUnderline(linesArray);
19
+ default:
20
+ return linesArray.join("\n");
21
+ }
22
+ }
23
+ function createDoubleBox(lines, limit, borderColor) {
24
+ const processedLines = processLines(lines, limit);
25
+ const maxLength = Math.max(...processedLines.map((line) => line.length));
26
+ const indentation = "";
27
+ if (borderColor === void 0) {
28
+ borderColor = "viceGradient";
29
+ }
30
+ const topBorder = borderColor ? colorMap[borderColor](`${"\u2550".repeat(maxLength)}\u2557`) : `${"\u2550".repeat(maxLength)}\u2557`;
31
+ const bottomBorder = borderColor ? colorMap[borderColor](`${indentation}\u255A${"\u2550".repeat(maxLength + 2)}\u255D`) : `${indentation}\u255A${"\u2550".repeat(maxLength + 2)}\u255D`;
32
+ const middle = processedLines.map((line, index) => {
33
+ const lineIndentation = index === 0 ? indentation : indentation + " ";
34
+ return `${lineIndentation}${borderColor ? colorMap[borderColor]("\u2551") : "\u2551"} ${colorMap[borderColor](line.padEnd(maxLength))} ${borderColor ? colorMap[borderColor]("\u2551") : "\u2551"}`;
35
+ }).join("\n");
36
+ return `${topBorder}
37
+ ${middle}
38
+ ${bottomBorder}`;
39
+ }
40
+ function processLines(lines, limit) {
41
+ const linesArray = Array.isArray(lines) ? lines : [lines];
42
+ return linesArray.map((line) => {
43
+ let truncatedLine = line;
44
+ if (limit && line.length > limit) {
45
+ truncatedLine = `${line.slice(0, limit - 3)}...`;
46
+ }
47
+ return truncatedLine.padEnd(limit || truncatedLine.length);
48
+ });
49
+ }
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@reliverse/relinka",
3
+ "version": "1.0.0",
4
+ "description": "@reliverse/relinka is a powerful library that enables seamless, typesafe, and resilient prompts for command-line applications. Crafted with simplicity and elegance, it provides developers with an intuitive and robust way to build interactive CLIs.",
5
+ "scripts": {
6
+ "appts": "bun typecheck && bun lint && bun format",
7
+ "build": "unbuild && bun build.optim.ts",
8
+ "bunp": "bun publish",
9
+ "pub": "redrun build bunp",
10
+ "lint": "eslint --cache --fix .",
11
+ "format": "biome check --write .",
12
+ "optimize": "putout output --fix",
13
+ "check": "bun test",
14
+ "attw": "attw --pack",
15
+ "tsc": "tshy",
16
+ "knip": "knip",
17
+ "dev": "bun examples/run-example.ts",
18
+ "dev:x": "tsx examples/run-example.ts"
19
+ },
20
+ "type": "module",
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/reliverse/prompts.git"
27
+ },
28
+ "main": "./output/main.js",
29
+ "types": "./output/main.d.ts",
30
+ "module": "./output/main.js",
31
+ "exports": {
32
+ "import": "./output/main.js",
33
+ "types": "./output/main.d.ts"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/reliverse/prompts/issues",
37
+ "email": "blefnk@gmail.com"
38
+ },
39
+ "files": ["package.json", "README.md", "LICENSE.md", "output"],
40
+ "homepage": "https://github.com/reliverse/prompts",
41
+ "keywords": ["cli", "reliverse"],
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@figliolia/chalk-animation": "^1.0.4",
45
+ "@sinclair/typebox": "^0.33.17",
46
+ "ansi-escapes": "^7.0.0",
47
+ "chalk": "^5.3.0",
48
+ "cli-spinners": "^3.2.0",
49
+ "cli-width": "^4.1.0",
50
+ "defu": "^6.1.4",
51
+ "detect-package-manager": "^3.0.2",
52
+ "figlet": "^1.8.0",
53
+ "fs-extra": "^11.2.0",
54
+ "get-pixels": "^3.3.3",
55
+ "gradient-string": "^3.0.0",
56
+ "log-update": "^6.1.0",
57
+ "mute-stream": "^2.0.0",
58
+ "node-emoji": "^2.1.3",
59
+ "nypm": "^0.3.12",
60
+ "ora": "^8.1.1",
61
+ "pathe": "^1.1.2",
62
+ "picocolors": "^1.1.1",
63
+ "sisteransi": "^1.0.5",
64
+ "wrap-ansi": "^9.0.0"
65
+ },
66
+ "devDependencies": {
67
+ "@arethetypeswrong/cli": "^0.16.4",
68
+ "@biomejs/biome": "1.9.4",
69
+ "@cspell/dict-npm": "^5.1.12",
70
+ "@eslint/js": "^9.14.0",
71
+ "@types/bun": "^1.1.13",
72
+ "@types/chalk-animation": "^1.6.3",
73
+ "@types/eslint__js": "^8.42.3",
74
+ "@types/figlet": "^1.7.0",
75
+ "@types/fs-extra": "^11.0.4",
76
+ "@types/mute-stream": "^0.0.4",
77
+ "@types/node": "^22.9.0",
78
+ "@types/sentencer": "^0.2.3",
79
+ "@types/tape": "^5.6.4",
80
+ "eslint": "^9.14.0",
81
+ "eslint-plugin-perfectionist": "^3.9.1",
82
+ "knip": "^5.36.2",
83
+ "mock-stdin": "^1.0.0",
84
+ "printj": "^1.3.1",
85
+ "putout": "^36.11.0",
86
+ "redrun": "^11.0.5",
87
+ "sentencer": "^0.2.1",
88
+ "tape": "^5.9.0",
89
+ "tshy": "^3.0.2",
90
+ "tsx": "^4.19.2",
91
+ "typescript": "^5.6.3",
92
+ "typescript-eslint": "^8.13.0",
93
+ "unbuild": "^2.0.0",
94
+ "vitest": "^2.1.4"
95
+ }
96
+ }