@hardlydifficult/text 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.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @hardlydifficult/text
2
+
3
+ Text utilities for error formatting, template replacement, and chunking.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @hardlydifficult/text
9
+ ```
10
+
11
+ ## API
12
+
13
+ ### `getErrorMessage(err: unknown): string`
14
+
15
+ Extract a message string from an unknown error. Returns `err.message` for `Error` instances, `String(err)` otherwise.
16
+
17
+ ```typescript
18
+ import { getErrorMessage } from "@hardlydifficult/text";
19
+
20
+ try {
21
+ await riskyOperation();
22
+ } catch (err) {
23
+ console.error(getErrorMessage(err));
24
+ }
25
+ ```
26
+
27
+ ### `formatError(err: unknown, context?: string): string`
28
+
29
+ Format an error for user-facing output. Prepends an optional context prefix.
30
+
31
+ ```typescript
32
+ import { formatError } from "@hardlydifficult/text";
33
+
34
+ formatError(new Error("not found"), "User lookup"); // "User lookup: not found"
35
+ formatError(new Error("not found")); // "not found"
36
+ ```
37
+
38
+ ### `formatErrorForLog(err: unknown): string`
39
+
40
+ Format an error for logging. Returns the message for `Error` instances, `String(err)` otherwise.
41
+
42
+ ### `replaceTemplate(template: string, values: Record<string, string>): string`
43
+
44
+ Replace `{{variable}}` placeholders with provided values. Unmatched placeholders are left as-is.
45
+
46
+ ```typescript
47
+ import { replaceTemplate } from "@hardlydifficult/text";
48
+
49
+ replaceTemplate("Hello {{name}}, welcome to {{place}}!", {
50
+ name: "Alice",
51
+ place: "Wonderland",
52
+ });
53
+ // "Hello Alice, welcome to Wonderland!"
54
+ ```
55
+
56
+ ### `extractPlaceholders(template: string): string[]`
57
+
58
+ Extract all unique placeholder names from a template.
59
+
60
+ ```typescript
61
+ import { extractPlaceholders } from "@hardlydifficult/text";
62
+
63
+ extractPlaceholders("{{name}} is in {{place}}"); // ["name", "place"]
64
+ ```
65
+
66
+ ### `chunkText(text: string, maxLength: number): string[]`
67
+
68
+ Split text into chunks of at most `maxLength` characters. Prefers breaking on newlines, then spaces, and falls back to hard breaks.
69
+
70
+ ```typescript
71
+ import { chunkText } from "@hardlydifficult/text";
72
+
73
+ const chunks = chunkText(longMessage, 2000);
74
+ for (const chunk of chunks) {
75
+ await channel.send(chunk);
76
+ }
77
+ ```
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Split text into chunks that respect a maximum length.
3
+ * Prefers breaking on newlines, then spaces, and falls back to hard breaks.
4
+ */
5
+ /**
6
+ * Split text into chunks of at most `maxLength` characters.
7
+ *
8
+ * @param text - The text to split
9
+ * @param maxLength - Maximum length of each chunk
10
+ * @returns Array of text chunks
11
+ */
12
+ export declare function chunkText(text: string, maxLength: number): string[];
13
+ //# sourceMappingURL=chunkText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunkText.d.ts","sourceRoot":"","sources":["../src/chunkText.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBnE"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Split text into chunks that respect a maximum length.
4
+ * Prefers breaking on newlines, then spaces, and falls back to hard breaks.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.chunkText = chunkText;
8
+ /**
9
+ * Split text into chunks of at most `maxLength` characters.
10
+ *
11
+ * @param text - The text to split
12
+ * @param maxLength - Maximum length of each chunk
13
+ * @returns Array of text chunks
14
+ */
15
+ function chunkText(text, maxLength) {
16
+ const chunks = [];
17
+ let remaining = text;
18
+ while (remaining.length > 0) {
19
+ if (remaining.length <= maxLength) {
20
+ chunks.push(remaining);
21
+ break;
22
+ }
23
+ // Find a good break point (newline or space)
24
+ let breakPoint = remaining.lastIndexOf("\n", maxLength);
25
+ if (breakPoint === -1 || breakPoint < maxLength / 2) {
26
+ breakPoint = remaining.lastIndexOf(" ", maxLength);
27
+ }
28
+ if (breakPoint === -1 || breakPoint < maxLength / 2) {
29
+ breakPoint = maxLength;
30
+ }
31
+ chunks.push(remaining.slice(0, breakPoint));
32
+ remaining = remaining.slice(breakPoint).trimStart();
33
+ }
34
+ return chunks;
35
+ }
36
+ //# sourceMappingURL=chunkText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunkText.js","sourceRoot":"","sources":["../src/chunkText.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AASH,8BAwBC;AA/BD;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,SAAiB;IACvD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM;QACR,CAAC;QAED,6CAA6C;QAC7C,IAAI,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YACpD,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,UAAU,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YACpD,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;QAC5C,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAC;IACtD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Error utilities - consistent error handling across the codebase
3
+ */
4
+ /**
5
+ * Extract a message string from an unknown error
6
+ */
7
+ export declare function getErrorMessage(err: unknown): string;
8
+ /**
9
+ * Format an error for user-facing output
10
+ */
11
+ export declare function formatError(err: unknown, context?: string): string;
12
+ /**
13
+ * Format an error for logging (includes more detail for non-Error types)
14
+ */
15
+ export declare function formatErrorForLog(err: unknown): string;
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKtD"}
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * Error utilities - consistent error handling across the codebase
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getErrorMessage = getErrorMessage;
7
+ exports.formatError = formatError;
8
+ exports.formatErrorForLog = formatErrorForLog;
9
+ /**
10
+ * Extract a message string from an unknown error
11
+ */
12
+ function getErrorMessage(err) {
13
+ if (err instanceof Error) {
14
+ return err.message;
15
+ }
16
+ return String(err);
17
+ }
18
+ /**
19
+ * Format an error for user-facing output
20
+ */
21
+ function formatError(err, context) {
22
+ const message = getErrorMessage(err);
23
+ if (context !== undefined && context !== "") {
24
+ return `${context}: ${message}`;
25
+ }
26
+ return message;
27
+ }
28
+ /**
29
+ * Format an error for logging (includes more detail for non-Error types)
30
+ */
31
+ function formatErrorForLog(err) {
32
+ if (err instanceof Error) {
33
+ return err.message;
34
+ }
35
+ return String(err);
36
+ }
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAKH,0CAKC;AAKD,kCAMC;AAKD,8CAKC;AA7BD;;GAEG;AACH,SAAgB,eAAe,CAAC,GAAY;IAC1C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,GAAY,EAAE,OAAgB;IACxD,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QAC5C,OAAO,GAAG,OAAO,KAAK,OAAO,EAAE,CAAC;IAClC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,GAAY;IAC5C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { getErrorMessage, formatError, formatErrorForLog } from "./errors.js";
2
+ export { replaceTemplate, extractPlaceholders } from "./template.js";
3
+ export { chunkText } from "./chunkText.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.chunkText = exports.extractPlaceholders = exports.replaceTemplate = exports.formatErrorForLog = exports.formatError = exports.getErrorMessage = void 0;
4
+ var errors_js_1 = require("./errors.js");
5
+ Object.defineProperty(exports, "getErrorMessage", { enumerable: true, get: function () { return errors_js_1.getErrorMessage; } });
6
+ Object.defineProperty(exports, "formatError", { enumerable: true, get: function () { return errors_js_1.formatError; } });
7
+ Object.defineProperty(exports, "formatErrorForLog", { enumerable: true, get: function () { return errors_js_1.formatErrorForLog; } });
8
+ var template_js_1 = require("./template.js");
9
+ Object.defineProperty(exports, "replaceTemplate", { enumerable: true, get: function () { return template_js_1.replaceTemplate; } });
10
+ Object.defineProperty(exports, "extractPlaceholders", { enumerable: true, get: function () { return template_js_1.extractPlaceholders; } });
11
+ var chunkText_js_1 = require("./chunkText.js");
12
+ Object.defineProperty(exports, "chunkText", { enumerable: true, get: function () { return chunkText_js_1.chunkText; } });
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA8E;AAArE,4GAAA,eAAe,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AACxD,6CAAqE;AAA5D,8GAAA,eAAe,OAAA;AAAE,kHAAA,mBAAmB,OAAA;AAC7C,+CAA2C;AAAlC,yGAAA,SAAS,OAAA"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Simple template utility for placeholder replacement.
3
+ * Replaces {{variable}} placeholders with provided values.
4
+ */
5
+ /**
6
+ * Replace template placeholders with values
7
+ *
8
+ * @param template - The template string with {{variable}} placeholders
9
+ * @param values - Object mapping variable names to their values
10
+ * @returns The template with placeholders replaced
11
+ */
12
+ export declare function replaceTemplate(template: string, values: Record<string, string>): string;
13
+ /**
14
+ * Extract all placeholder names from a template
15
+ *
16
+ * @param template - The template string with {{variable}} placeholders
17
+ * @returns Array of unique placeholder names
18
+ */
19
+ export declare function extractPlaceholders(template: string): string[];
20
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAW9D"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Simple template utility for placeholder replacement.
4
+ * Replaces {{variable}} placeholders with provided values.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.replaceTemplate = replaceTemplate;
8
+ exports.extractPlaceholders = extractPlaceholders;
9
+ /**
10
+ * Replace template placeholders with values
11
+ *
12
+ * @param template - The template string with {{variable}} placeholders
13
+ * @param values - Object mapping variable names to their values
14
+ * @returns The template with placeholders replaced
15
+ */
16
+ function replaceTemplate(template, values) {
17
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
18
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
19
+ return values[key] ?? match;
20
+ }
21
+ return match;
22
+ });
23
+ }
24
+ /**
25
+ * Extract all placeholder names from a template
26
+ *
27
+ * @param template - The template string with {{variable}} placeholders
28
+ * @returns Array of unique placeholder names
29
+ */
30
+ function extractPlaceholders(template) {
31
+ const matches = template.matchAll(/\{\{(\w+)\}\}/g);
32
+ const placeholders = new Set();
33
+ for (const match of matches) {
34
+ if (match[1]) {
35
+ placeholders.add(match[1]);
36
+ }
37
+ }
38
+ return Array.from(placeholders);
39
+ }
40
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AASH,0CAUC;AAQD,kDAWC;AApCD;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,QAAgB,EAChB,MAA8B;IAE9B,OAAO,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC/D,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YACtD,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;QAC9B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,QAAgB;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@hardlydifficult/text",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.js",
5
+ "types": "./dist/index.d.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "test:coverage": "vitest run --coverage",
14
+ "lint": "tsc --noEmit",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "20.19.31",
19
+ "typescript": "5.8.3",
20
+ "vitest": "1.6.1"
21
+ },
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ }
25
+ }