@hardlydifficult/text 1.0.17 → 1.0.19

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 (2) hide show
  1. package/README.md +212 -243
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -11,154 +11,199 @@ npm install @hardlydifficult/text
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import * as text from "@hardlydifficult/text";
14
+ import {
15
+ replaceTemplate,
16
+ chunkText,
17
+ slugify,
18
+ formatDuration,
19
+ buildFileTree,
20
+ convertFormat,
21
+ createLinker,
22
+ } from "@hardlydifficult/text";
15
23
 
16
24
  // Template replacement
17
- const greeting = text.replaceTemplate("Hello {{name}}!", { name: "World" });
18
- console.log(greeting); // "Hello World!"
25
+ const greeting = replaceTemplate("Hello {{name}}!", { name: "Alice" });
26
+ // "Hello Alice!"
19
27
 
20
- // Text chunking
21
- const chunks = text.chunkText("Line 1\nLine 2\nLong line", 15);
22
- console.log(chunks); // ["Line 1\nLine 2", "Long line"]
28
+ // Split long text into chunks
29
+ const chunks = chunkText("Line 1\nLine 2\nLine 3", 10);
30
+ // ["Line 1\nLine 2", "Line 3"]
23
31
 
24
- // Slugification
25
- console.log(text.slugify("My Feature Name!")); // "my-feature-name"
32
+ // Convert to URL-safe slug
33
+ const slug = slugify("My Feature Name!", 10);
34
+ // "my-feature"
26
35
 
27
- // Duration formatting
28
- console.log(text.formatDuration(125_000)); // "2m 5s"
29
- ```
30
-
31
- ## Error Handling
32
-
33
- ### `getErrorMessage(err: unknown): string`
36
+ // Format duration in ms
37
+ const formatted = formatDuration(125_000);
38
+ // "2m 5s"
34
39
 
35
- Extract a message string from an unknown error.
36
-
37
- ```typescript
38
- import { getErrorMessage } from "@hardlydifficult/text";
40
+ // Build a file tree
41
+ const tree = buildFileTree(["src/index.ts", "src/utils.ts", "README.md"]);
42
+ // src/
43
+ // index.ts
44
+ // utils.ts
45
+ //
46
+ // README.md
39
47
 
40
- try {
41
- throw new Error("Something went wrong");
42
- } catch (err) {
43
- console.error(getErrorMessage(err)); // "Something went wrong"
44
- }
48
+ // Convert between JSON/YAML
49
+ const yaml = convertFormat('{"name":"Alice"}', "yaml");
50
+ // name: Alice
45
51
  ```
46
52
 
47
- ### `formatError(err: unknown, context?: string): string`
53
+ ## Error Handling
48
54
 
49
- Format an error with an optional context prefix.
55
+ Consistent error extraction and formatting utilities.
50
56
 
51
57
  ```typescript
52
- import { formatError } from "@hardlydifficult/text";
53
-
54
- formatError(new Error("not found"), "User lookup"); // "User lookup: not found"
55
- formatError(new Error("not found")); // "not found"
56
- ```
58
+ import { getErrorMessage, formatError, formatErrorForLog } from "@hardlydifficult/text";
57
59
 
58
- ### `formatErrorForLog(err: unknown): string`
60
+ const err = new Error("disk full");
59
61
 
60
- Format an error for logging. Returns `err.message` for `Error` instances, `String(err)` otherwise.
62
+ getErrorMessage(err); // "disk full"
63
+ formatError(err, "Failed to save"); // "Failed to save: disk full"
64
+ formatErrorForLog(err); // "disk full"
65
+ ```
61
66
 
62
- ```typescript
63
- import { formatErrorForLog } from "@hardlydifficult/text";
67
+ ### Functions
64
68
 
65
- formatErrorForLog(new Error("Database error")); // "Database error"
66
- ```
69
+ | Function | Description |
70
+ |----------|-------------|
71
+ | `getErrorMessage(err)` | Extract message string from unknown error |
72
+ | `formatError(err, context?)` | Format error with optional context prefix |
73
+ | `formatErrorForLog(err)` | Format error for logging (non-Error → string) |
67
74
 
68
75
  ## Template Replacement
69
76
 
70
- ### `replaceTemplate(template: string, values: Record<string, string>): string`
71
-
72
- Replace `{{variable}}` placeholders with provided values.
77
+ Simple string interpolation using `{{variable}}` syntax.
73
78
 
74
79
  ```typescript
75
- import { replaceTemplate } from "@hardlydifficult/text";
80
+ import { replaceTemplate, extractPlaceholders } from "@hardlydifficult/text";
76
81
 
77
- replaceTemplate("Hello {{name}}, welcome to {{place}}!", {
82
+ const text = replaceTemplate("Hello {{name}}! You are {{age}}.", {
78
83
  name: "Alice",
79
- place: "Wonderland",
84
+ age: "30",
80
85
  });
81
- // "Hello Alice, welcome to Wonderland!"
82
- ```
83
-
84
- ### `extractPlaceholders(template: string): string[]`
85
-
86
- Extract all unique placeholder names from a template string.
86
+ // "Hello Alice! You are 30."
87
87
 
88
- ```typescript
89
- import { extractPlaceholders } from "@hardlydifficult/text";
90
-
91
- extractPlaceholders("{{name}} is in {{place}}"); // ["name", "place"]
88
+ const vars = extractPlaceholders("{{greeting}}, {{name}}!");
89
+ // ["greeting", "name"]
92
90
  ```
93
91
 
94
- ## Text Processing
92
+ ### Functions
95
93
 
96
- ### `chunkText(text: string, maxLength: number): string[]`
94
+ | Function | Description |
95
+ |----------|-------------|
96
+ | `replaceTemplate(template, values)` | Replace all `{{variable}}` placeholders |
97
+ | `extractPlaceholders(template)` | Return unique placeholder names |
97
98
 
98
- Split text into chunks of at most `maxLength` characters, preferring line breaks and spaces for natural breaks.
99
+ ## Text Chunking
100
+
101
+ Split long text into manageable chunks respecting natural breaks.
99
102
 
100
103
  ```typescript
101
104
  import { chunkText } from "@hardlydifficult/text";
102
105
 
103
- const text = "Line 1\nLine 2\nThis is a very long line that needs to be chunked.";
104
- const chunks = chunkText(text, 20);
105
- // ["Line 1\nLine 2", "This is a very", "long line that", "needs to be", "chunked."]
106
+ const text = "line one\nline two\nline three";
107
+ chunkText(text, 18);
108
+ // ["line one\nline two", "line three"]
106
109
  ```
107
110
 
108
- ### `slugify(input: string, maxLength?: number): string`
111
+ ### Behavior
112
+
113
+ - Breaks on newlines first, then spaces
114
+ - Falls back to hard breaks when no natural break point exists
115
+ - Trims leading whitespace from subsequent chunks
109
116
 
110
- Convert a string to a URL/filename-safe slug by lowercasing, replacing non-alphanumeric characters with hyphens, and optionally truncating at hyphen boundaries.
117
+ ## Slugification
118
+
119
+ Convert strings to URL/filename-safe slugs.
111
120
 
112
121
  ```typescript
113
122
  import { slugify } from "@hardlydifficult/text";
114
123
 
115
124
  slugify("My Feature Name!"); // "my-feature-name"
116
125
  slugify("My Feature Name!", 10); // "my-feature"
117
- slugify(" spaces & symbols! "); // "spaces-symbols"
118
126
  ```
119
127
 
120
- ### `formatWithLineNumbers(content: string, startLine?: number): string`
128
+ ### Features
121
129
 
122
- Format text content with right-aligned line numbers.
130
+ - Lowercases and replaces non-alphanumeric runs with single hyphens
131
+ - Trims leading/trailing hyphens
132
+ - Optional `maxLength` truncates at hyphen boundary when possible
123
133
 
124
- ```typescript
125
- import { formatWithLineNumbers } from "@hardlydifficult/text";
134
+ ## Duration Formatting
126
135
 
127
- formatWithLineNumbers("foo\nbar\nbaz");
128
- // " 1: foo\n 2: bar\n 3: baz"
136
+ Format milliseconds as human-readable duration strings.
129
137
 
130
- formatWithLineNumbers("hello\nworld", 10);
131
- // "10: hello\n11: world"
138
+ ```typescript
139
+ import { formatDuration } from "@hardlydifficult/text";
140
+
141
+ formatDuration(125_000); // "2m 5s"
142
+ formatDuration(3_600_000); // "1h"
143
+ formatDuration(500); // "<1s"
132
144
  ```
133
145
 
134
- ### `formatDuration(ms: number): string`
146
+ ### Format Rules
135
147
 
136
- Format milliseconds as a human-readable duration string, showing up to two units and using "<1s" for sub-second values.
148
+ | Duration | Output |
149
+ |----------|--------|
150
+ | < 1000ms | `<1s` |
151
+ | 1–59 seconds | `<seconds>s` |
152
+ | 1–59 minutes | `<minutes>m` or `<minutes>m <seconds>s` |
153
+ | 1–23 hours | `<hours>h` or `<hours>h <minutes>m` |
154
+ | ≥ 1 day | `<days>d` or `<days>d <hours>h` |
155
+
156
+ ## File Tree Rendering
157
+
158
+ Build and render hierarchical file trees with depth-based truncation and annotations.
137
159
 
138
160
  ```typescript
139
- import { formatDuration } from "@hardlydifficult/text";
161
+ import { buildFileTree, FILE_TREE_DEFAULTS } from "@hardlydifficult/text";
162
+ import type { BuildTreeOptions } from "@hardlydifficult/text";
140
163
 
141
- formatDuration(125_000); // "2m 5s"
142
- formatDuration(3_600_000); // "1h"
143
- formatDuration(500); // "<1s"
144
- formatDuration(90_000_000); // "1d 1h"
164
+ const paths = [
165
+ "src/index.ts",
166
+ "test/unit/a.test.ts",
167
+ "test/unit/b.test.ts",
168
+ ];
169
+
170
+ const options: BuildTreeOptions = {
171
+ maxLevel2: 2,
172
+ annotations: new Map([["src/index.ts", "Entry point"]]),
173
+ collapseDirs: ["test"],
174
+ };
175
+
176
+ buildFileTree(paths, options);
177
+ // src/
178
+ // index.ts — Entry point
179
+ //
180
+ // test/
181
+ // (2 files across 1 dir)
145
182
  ```
146
183
 
147
- ## Format Conversion
184
+ ### Options
185
+
186
+ | Option | Type | Default | Description |
187
+ |--------|------|---------|-------------|
188
+ | `maxLevel2` | `number` | 10 | Max children to show at depth 2 (top-level dirs) |
189
+ | `maxLevel3` | `number` | 3 | Max children to show at depth 3 (files/dirs inside top dirs) |
190
+ | `annotations` | `Map<string, string>` | `undefined` | File/dir descriptions |
191
+ | `details` | `Map<string, string[]>` | `undefined` | Extra lines to show under file entries |
192
+ | `collapseDirs` | `string[]` | `undefined` | Directory names to collapse and summarize |
148
193
 
149
- ### `convertFormat(content: string, to: "json" | "yaml"): string`
194
+ ## Format Conversion
150
195
 
151
- Convert between JSON and YAML string formats with automatic input format detection.
196
+ Convert text between JSON and YAML with auto-detection.
152
197
 
153
198
  ```typescript
154
199
  import { convertFormat } from "@hardlydifficult/text";
200
+ import type { TextFormat } from "@hardlydifficult/text";
155
201
 
156
202
  // JSON to YAML
157
- convertFormat('{"name": "Alice", "age": 30}', "yaml");
203
+ convertFormat('{"name":"Alice"}', "yaml");
158
204
  // name: Alice
159
- // age: 30
160
205
 
161
- // YAML to JSON
206
+ // YAML to JSON (pretty-printed with 2-space indent)
162
207
  convertFormat("name: Alice\nage: 30", "json");
163
208
  // {
164
209
  // "name": "Alice",
@@ -166,212 +211,136 @@ convertFormat("name: Alice\nage: 30", "json");
166
211
  // }
167
212
  ```
168
213
 
169
- ### `formatYaml(data: unknown): string`
214
+ ### Functions
170
215
 
171
- Serialize data to clean YAML, using block literals for long strings containing colons.
216
+ | Function | Description |
217
+ |----------|-------------|
218
+ | `convertFormat(content, to)` | Parse input and re-serialize to `json` or `yaml` |
172
219
 
173
- ```typescript
174
- import { formatYaml } from "@hardlydifficult/text";
220
+ ## YAML Formatting
175
221
 
176
- formatYaml({ message: "Hello: World" });
177
- // "message: >\n Hello: World"
178
- ```
179
-
180
- ### `healYaml(dirtyYaml: string): string`
181
-
182
- Clean malformed YAML by stripping markdown code fences and quoting problematic scalar values containing colons.
222
+ Serialize data to clean YAML, using block literals for long strings containing `: `.
183
223
 
184
224
  ```typescript
185
- import { healYaml } from "@hardlydifficult/text";
225
+ import { formatYaml } from "@hardlydifficult/text";
186
226
 
187
- healYaml('```yaml\nmessage: Hello: World\n```');
188
- // "message: >\n Hello: World"
227
+ formatYaml({
228
+ purpose:
229
+ "Core AI SDK: LLM integrations (Anthropic, Ollama) and streaming support.",
230
+ });
231
+ // purpose: |
232
+ // Core AI SDK: LLM integrations (Anthropic, Ollama) and streaming support.
189
233
  ```
190
234
 
191
- ## Link Generation
235
+ ### Behavior
192
236
 
193
- ### `createLinker(initialRules?: LinkRule[]): Linker`
237
+ - Long strings (`>60 chars`) containing `: ` render as block literals (`|`)
238
+ - Short strings and safe scalars remain plain or quoted as needed
239
+ - Preserves round-trip parseability
194
240
 
195
- Create a configurable linker to transform text patterns into platform-specific links. The linker is idempotent by default, skips code spans and existing links, and resolves overlapping matches deterministically.
241
+ ## YAML Healing
242
+
243
+ Sanitize malformed YAML from LLMs by stripping code fences and quoting scalar values containing colons.
196
244
 
197
245
  ```typescript
198
- import { createLinker } from "@hardlydifficult/text";
246
+ import { healYaml } from "@hardlydifficult/text";
247
+ import { parse } from "yaml";
199
248
 
200
- const linker = createLinker()
201
- .linear("fairmint")
202
- .githubPr("Fairmint/api");
249
+ const badYaml = `\`\`\`yaml
250
+ purpose: |
251
+ Core AI: LLM integrations (Anthropic, Ollama)
252
+ description: Main deps: Node, TypeScript, Vitest.
253
+ \`\`\``;
203
254
 
204
- linker.linkText("Fix ENG-533 and PR#42", { format: "slack" });
205
- // "Fix <https://linear.app/fairmint/issue/ENG-533|ENG-533> and <https://github.com/Fairmint/api/pull/42|PR#42>"
255
+ const cleaned = healYaml(badYaml);
256
+ // purpose: |
257
+ // Core AI: LLM integrations (Anthropic, Ollama)
258
+ // description: "Main deps: Node, TypeScript, Vitest."
206
259
 
207
- linker.linkText("Fix ENG-533 and PR#42", { format: "markdown" });
208
- // "[ENG-533](https://linear.app/fairmint/issue/ENG-533) and [PR#42](https://github.com/Fairmint/api/pull/42)"
260
+ parse(cleaned); // Parses successfully
209
261
  ```
210
262
 
211
- #### Linker Methods
263
+ ### Fixes Applied
212
264
 
213
- **`.linear(workspace: string, options?: { name?: string; priority?: number }): Linker`**
265
+ - Strips markdown code fences (` ```yaml ` or ` ``` `)
266
+ - Quotes plain scalar values containing `: ` to avoid parse errors
214
267
 
215
- Add a rule for Linear issue references (e.g., `ENG-533`).
268
+ ## Linkification
216
269
 
217
- ```typescript
218
- const linker = createLinker().linear("fairmint");
219
- linker.linkText("Fix ENG-533", { format: "markdown" });
220
- // "[ENG-533](https://linear.app/fairmint/issue/ENG-533)"
221
- ```
222
-
223
- **`.githubPr(repository: string, options?: { name?: string; priority?: number }): Linker`**
224
-
225
- Add a rule for GitHub pull request references (e.g., `PR#42`).
270
+ Transform text with issue/PR references into formatted links.
226
271
 
227
272
  ```typescript
228
- const linker = createLinker().githubPr("Fairmint/api");
229
- linker.linkText("Merge PR#42", { format: "markdown" });
230
- // "[PR#42](https://github.com/Fairmint/api/pull/42)"
231
- ```
232
-
233
- **`.custom(pattern: RegExp, toHref: string | LinkHrefBuilder, options?: { name?: string; priority?: number }): Linker`**
273
+ import { createLinker } from "@hardlydifficult/text";
234
274
 
235
- Add a custom rule with a regex pattern and URL template or callback.
275
+ const linker = createLinker()
276
+ .linear("fairmint")
277
+ .githubPr("Fairmint/api");
236
278
 
237
- ```typescript
238
- const linker = createLinker().custom(
239
- /\bINC-\d+\b/g,
240
- ({ match }) => `https://incident.io/${match}`
241
- );
242
- linker.linkText("Resolve INC-99", { format: "markdown" });
243
- // "[INC-99](https://incident.io/INC-99)"
279
+ const output = linker.apply("Fix ENG-533 and PR#42", { platform: "slack" });
280
+ // Fix <https://linear.app/fairmint/issue/ENG-533|ENG-533> <https://github.com/Fairmint/api/pull/42|PR#42>
244
281
  ```
245
282
 
246
- **`.linkText(input: string, options?: LinkerApplyOptions): string`**
283
+ ### Platforms
247
284
 
248
- Apply all configured rules to the input text and return formatted links.
285
+ | Platform | Output Format |
286
+ |----------|---------------|
287
+ | `slack` | `<href\|text>` |
288
+ | `discord` | `[text](href)` |
289
+ | `markdown` | `[text](href)` |
290
+ | `plaintext` | `href` (raw URL) |
249
291
 
250
- **`.apply(input: string, options?: LinkerApplyOptions): string`**
292
+ ### Linker Methods
251
293
 
252
- Alias for `linkText()`.
294
+ | Method | Description |
295
+ |--------|-------------|
296
+ | `custom(pattern, toHref, options)` | Register a new rule with regex pattern and href builder |
297
+ | `linear(workspace, options)` | Match `PROJECT-123` and link to Linear |
298
+ | `githubPr(repository, options)` | Match `PR#123` and link to GitHub Pull Request |
299
+ | `apply(text, options)` | Transform text with configured rules |
253
300
 
254
- #### Link Options
301
+ ### Options
255
302
 
256
303
  | Option | Type | Default | Description |
257
304
  |--------|------|---------|-------------|
258
- | `format` | `"slack" \| "discord" \| "markdown" \| "plaintext"` | `"markdown"` | Target output format |
259
- | `platform` | `"slack" \| "discord" \| "markdown" \| "plaintext"` | `"markdown"` | Alias for `format` |
260
- | `skipCode` | `boolean` | `true` | Skip linkification inside code spans (backticks and fenced blocks) |
261
- | `skipExistingLinks` | `boolean` | `true` | Skip linkification inside existing links (Slack, Markdown, and plain URLs) |
262
-
263
- #### URL Template Syntax
264
-
265
- When using a string template for `href` or `toHref`, the following substitutions are available:
266
-
267
- - `$0` or `$&` — Full regex match
268
- - `$1`, `$2`, etc. — Capture groups
269
- - `$$` — Literal `$`
305
+ | `format` / `platform` | `LinkerPlatform` | `"markdown"` | Output format |
306
+ | `skipCode` | `boolean` | `true` | Skip linkification inside code blocks/inline code |
307
+ | `skipExistingLinks` | `boolean` | `true` | Skip linkification inside existing links |
270
308
 
271
- ```typescript
272
- const linker = createLinker().custom(
273
- /\b([A-Z]{2,6})-(\d+)\b/g,
274
- "https://example.com/issues/$1/$2"
275
- );
276
- linker.linkText("ENG-533", { format: "markdown" });
277
- // "[ENG-533](https://example.com/issues/ENG/533)"
278
- ```
309
+ ### LinkRule Options
279
310
 
280
- ## File Tree Rendering
311
+ | Property | Type | Description |
312
+ |----------|------|-------------|
313
+ | `pattern` | `RegExp` | Match pattern (global matching enforced) |
314
+ | `href` / `toHref` | `string` or `LinkHrefBuilder` | URL template (supports `$0`/`$&`, `$1`..`$N`) or callback |
315
+ | `priority` | `number` | `0` | Higher priority wins overlapping matches |
281
316
 
282
- ### `buildFileTree(files: string[], options?: BuildTreeOptions): string`
317
+ ## Text with Line Numbers
283
318
 
284
- Build and render a hierarchical file tree with depth-based truncation and optional annotations.
319
+ Format text content with right-aligned line numbers.
285
320
 
286
321
  ```typescript
287
- import { buildFileTree } from "@hardlydifficult/text";
288
-
289
- const files = [
290
- "src/index.ts",
291
- "src/utils.ts",
292
- "src/components/Button.tsx",
293
- "README.md",
294
- ];
295
-
296
- buildFileTree(files);
297
- // src/
298
- // index.ts
299
- // utils.ts
300
- // components/
301
- // Button.tsx
302
- //
303
- // README.md
304
- ```
305
-
306
- #### Tree Options
307
-
308
- | Option | Type | Default | Description |
309
- |--------|------|---------|-------------|
310
- | `maxLevel2` | `number` | `10` | Maximum children to show at depth 2 |
311
- | `maxLevel3` | `number` | `3` | Maximum children to show at depth 3+ |
312
- | `annotations` | `Map<string, string>` | — | Descriptions to append to entries (e.g., `"src/index.ts" → "Main entry point"`) |
313
- | `details` | `Map<string, string[]>` | — | Extra indented lines to show under file entries (e.g., key sections) |
314
- | `collapseDirs` | `string[]` | — | Directory names to collapse with a summary instead of expanding |
322
+ import { formatWithLineNumbers } from "@hardlydifficult/text";
315
323
 
316
- #### Annotations Example
324
+ formatWithLineNumbers("foo\nbar\nbaz");
325
+ // 1: foo
326
+ // 2: bar
327
+ // 3: baz
317
328
 
318
- ```typescript
319
- const annotations = new Map([
320
- ["src", "Source code"],
321
- ["src/index.ts", "Main entry point"],
322
- ]);
323
-
324
- buildFileTree(["src/index.ts", "src/utils.ts"], { annotations });
325
- // src/ — Source code
326
- // index.ts — Main entry point
327
- // utils.ts
329
+ formatWithLineNumbers("hello\nworld", 10);
330
+ // 10: hello
331
+ // 11: world
328
332
  ```
329
333
 
330
- #### Details Example
331
-
332
- ```typescript
333
- const details = new Map([
334
- [
335
- "src/index.ts",
336
- [
337
- "> main (5-20): App entry point.",
338
- "> shutdown (22-35): Cleanup handler.",
339
- ],
340
- ],
341
- ]);
342
-
343
- buildFileTree(["src/index.ts"], { details });
344
- // src/
345
- // index.ts
346
- // > main (5-20): App entry point.
347
- // > shutdown (22-35): Cleanup handler.
348
- ```
334
+ ## Markdown Fence Escaping
349
335
 
350
- #### Collapsed Directories Example
336
+ Escape content by wrapping with more backticks than contained in the content.
351
337
 
352
338
  ```typescript
353
- buildFileTree(
354
- [
355
- "node_modules/package-a/index.js",
356
- "node_modules/package-b/index.js",
357
- "src/index.ts",
358
- ],
359
- { collapseDirs: ["node_modules"] }
360
- );
361
- // node_modules/
362
- // (2 files across 2 dirs)
363
- //
364
- // src/
365
- // index.ts
366
- ```
339
+ import { escapeFence } from "@hardlydifficult/text";
367
340
 
368
- ### `FILE_TREE_DEFAULTS`
369
-
370
- Default truncation limits for file tree rendering.
371
-
372
- ```typescript
373
- import { FILE_TREE_DEFAULTS } from "@hardlydifficult/text";
341
+ const result = escapeFence("content with ``` triple backticks");
342
+ // { fence: "````", content: "content with ``` triple backticks" }
374
343
 
375
- console.log(FILE_TREE_DEFAULTS.maxLevel2); // 10
376
- console.log(FILE_TREE_DEFAULTS.maxLevel3); // 3
344
+ // Use as:
345
+ // ${result.fence}${result.content}${result.fence}
377
346
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/text",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [