@hardlydifficult/document-generator 1.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.
- package/README.md +130 -0
- package/dist/Document.d.ts +17 -0
- package/dist/Document.d.ts.map +1 -0
- package/dist/Document.js +90 -0
- package/dist/Document.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/markdownConverter.d.ts +17 -0
- package/dist/markdownConverter.d.ts.map +1 -0
- package/dist/markdownConverter.js +85 -0
- package/dist/markdownConverter.js.map +1 -0
- package/dist/outputters/index.d.ts +3 -0
- package/dist/outputters/index.d.ts.map +1 -0
- package/dist/outputters/index.js +8 -0
- package/dist/outputters/index.js.map +1 -0
- package/dist/outputters/markdown.d.ts +3 -0
- package/dist/outputters/markdown.d.ts.map +1 -0
- package/dist/outputters/markdown.js +35 -0
- package/dist/outputters/markdown.js.map +1 -0
- package/dist/outputters/plainText.d.ts +3 -0
- package/dist/outputters/plainText.d.ts.map +1 -0
- package/dist/outputters/plainText.js +33 -0
- package/dist/outputters/plainText.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# @hardlydifficult/document-generator
|
|
2
|
+
|
|
3
|
+
Platform-agnostic document builder with chainable API. Build rich documents once, output to multiple formats.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hardlydifficult/document-generator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { doc, toMarkdown, toPlainText } from '@hardlydifficult/document-generator';
|
|
15
|
+
|
|
16
|
+
const document = doc()
|
|
17
|
+
.header("Weekly Report")
|
|
18
|
+
.text("Summary of this week's **key highlights**.")
|
|
19
|
+
.list(["Completed feature A", "Fixed bug B", "Started project C"])
|
|
20
|
+
.divider()
|
|
21
|
+
.link("View details", "https://example.com")
|
|
22
|
+
.context("Generated on 2025-01-15");
|
|
23
|
+
|
|
24
|
+
// Output as markdown
|
|
25
|
+
console.log(toMarkdown(document.getBlocks()));
|
|
26
|
+
|
|
27
|
+
// Output as plain text
|
|
28
|
+
console.log(toPlainText(document.getBlocks()));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## API
|
|
32
|
+
|
|
33
|
+
### `doc()` / `new Document()`
|
|
34
|
+
|
|
35
|
+
Create a new document builder. All methods are chainable.
|
|
36
|
+
|
|
37
|
+
### Chainable Methods
|
|
38
|
+
|
|
39
|
+
| Method | Description |
|
|
40
|
+
|--------|-------------|
|
|
41
|
+
| `.header(text)` | Add a header/title |
|
|
42
|
+
| `.text(content)` | Add text paragraph (supports **bold**, *italic*, ~~strike~~) |
|
|
43
|
+
| `.list(items)` | Add a bulleted list |
|
|
44
|
+
| `.divider()` | Add a horizontal divider |
|
|
45
|
+
| `.context(text)` | Add footer/context text |
|
|
46
|
+
| `.link(text, url)` | Add a hyperlink |
|
|
47
|
+
| `.code(content)` | Add code (auto-detects inline vs multiline) |
|
|
48
|
+
| `.image(url, alt?)` | Add an image |
|
|
49
|
+
|
|
50
|
+
### `document.getBlocks(): Block[]`
|
|
51
|
+
|
|
52
|
+
Get the internal block representation for custom processing.
|
|
53
|
+
|
|
54
|
+
## Inline Markdown Support
|
|
55
|
+
|
|
56
|
+
Text blocks support standard inline markdown that gets auto-converted per platform:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
doc().text('This has **bold**, *italic*, and ~~strikethrough~~ text.');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- Standard markdown: `**bold**`, `*italic*`, `~~strike~~`
|
|
63
|
+
- Slack: Converted to `*bold*`, `_italic_`, `~strike~`
|
|
64
|
+
- Discord: Uses standard markdown (no conversion needed)
|
|
65
|
+
- Plain text: Formatting stripped
|
|
66
|
+
|
|
67
|
+
**Note:** Use `.code()` and `.link()` methods for code and links—not markdown syntax.
|
|
68
|
+
|
|
69
|
+
## Code Blocks
|
|
70
|
+
|
|
71
|
+
The `.code()` method auto-detects format:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Single line → inline code
|
|
75
|
+
doc().code('const x = 1'); // → `const x = 1`
|
|
76
|
+
|
|
77
|
+
// Multiline → code block
|
|
78
|
+
doc().code('const x = 1;\nconst y = 2;');
|
|
79
|
+
// → ```
|
|
80
|
+
// const x = 1;
|
|
81
|
+
// const y = 2;
|
|
82
|
+
// ```
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Outputters
|
|
86
|
+
|
|
87
|
+
### `toMarkdown(blocks): string`
|
|
88
|
+
|
|
89
|
+
Convert to standard markdown format.
|
|
90
|
+
|
|
91
|
+
### `toPlainText(blocks): string`
|
|
92
|
+
|
|
93
|
+
Convert to plain text, stripping all formatting.
|
|
94
|
+
|
|
95
|
+
## Block Types
|
|
96
|
+
|
|
97
|
+
Internal block types for custom processing:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
type Block =
|
|
101
|
+
| { type: 'header'; text: string }
|
|
102
|
+
| { type: 'text'; content: string }
|
|
103
|
+
| { type: 'list'; items: string[] }
|
|
104
|
+
| { type: 'divider' }
|
|
105
|
+
| { type: 'context'; text: string }
|
|
106
|
+
| { type: 'link'; text: string; url: string }
|
|
107
|
+
| { type: 'code'; content: string; multiline: boolean }
|
|
108
|
+
| { type: 'image'; url: string; alt?: string };
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Integration with @hardlydifficult/chat
|
|
112
|
+
|
|
113
|
+
Documents integrate seamlessly with the chat package for Slack and Discord:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { doc } from '@hardlydifficult/document-generator';
|
|
117
|
+
import { createChatClient } from '@hardlydifficult/chat';
|
|
118
|
+
|
|
119
|
+
const client = createChatClient({ type: 'slack' });
|
|
120
|
+
const channel = await client.connect(channelId);
|
|
121
|
+
|
|
122
|
+
const report = doc()
|
|
123
|
+
.header("Daily Metrics")
|
|
124
|
+
.text("Here are today's **key numbers**:")
|
|
125
|
+
.list(["Users: 1,234", "Revenue: $5,678", "Errors: 0"])
|
|
126
|
+
.context("Generated automatically");
|
|
127
|
+
|
|
128
|
+
// Automatically converted to Slack Block Kit
|
|
129
|
+
await channel.postMessage(report);
|
|
130
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Block } from './types.js';
|
|
2
|
+
export declare class Document {
|
|
3
|
+
private blocks;
|
|
4
|
+
header(text: string): this;
|
|
5
|
+
text(content: string): this;
|
|
6
|
+
list(items: string[]): this;
|
|
7
|
+
divider(): this;
|
|
8
|
+
context(text: string): this;
|
|
9
|
+
link(text: string, url: string): this;
|
|
10
|
+
code(content: string): this;
|
|
11
|
+
image(url: string, alt?: string): this;
|
|
12
|
+
getBlocks(): Block[];
|
|
13
|
+
toMarkdown(): string;
|
|
14
|
+
toPlainText(): string;
|
|
15
|
+
}
|
|
16
|
+
export declare function doc(): Document;
|
|
17
|
+
//# sourceMappingURL=Document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Document.d.ts","sourceRoot":"","sources":["../src/Document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EASN,MAAM,YAAY,CAAC;AAIpB,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAe;IAE7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAS1B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS3B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAS3B,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAS3B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAUrC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAW3B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAUtC,SAAS,IAAI,KAAK,EAAE;IAIpB,UAAU,IAAI,MAAM;IAIpB,WAAW,IAAI,MAAM;CAGtB;AAED,wBAAgB,GAAG,IAAI,QAAQ,CAE9B"}
|
package/dist/Document.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Document = void 0;
|
|
4
|
+
exports.doc = doc;
|
|
5
|
+
const markdown_js_1 = require("./outputters/markdown.js");
|
|
6
|
+
const plainText_js_1 = require("./outputters/plainText.js");
|
|
7
|
+
class Document {
|
|
8
|
+
blocks = [];
|
|
9
|
+
header(text) {
|
|
10
|
+
const block = {
|
|
11
|
+
type: 'header',
|
|
12
|
+
text,
|
|
13
|
+
};
|
|
14
|
+
this.blocks.push(block);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
text(content) {
|
|
18
|
+
const block = {
|
|
19
|
+
type: 'text',
|
|
20
|
+
content,
|
|
21
|
+
};
|
|
22
|
+
this.blocks.push(block);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
list(items) {
|
|
26
|
+
const block = {
|
|
27
|
+
type: 'list',
|
|
28
|
+
items,
|
|
29
|
+
};
|
|
30
|
+
this.blocks.push(block);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
divider() {
|
|
34
|
+
const block = {
|
|
35
|
+
type: 'divider',
|
|
36
|
+
};
|
|
37
|
+
this.blocks.push(block);
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
context(text) {
|
|
41
|
+
const block = {
|
|
42
|
+
type: 'context',
|
|
43
|
+
text,
|
|
44
|
+
};
|
|
45
|
+
this.blocks.push(block);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
link(text, url) {
|
|
49
|
+
const block = {
|
|
50
|
+
type: 'link',
|
|
51
|
+
text,
|
|
52
|
+
url,
|
|
53
|
+
};
|
|
54
|
+
this.blocks.push(block);
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
code(content) {
|
|
58
|
+
const multiline = content.includes('\n');
|
|
59
|
+
const block = {
|
|
60
|
+
type: 'code',
|
|
61
|
+
content,
|
|
62
|
+
multiline,
|
|
63
|
+
};
|
|
64
|
+
this.blocks.push(block);
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
image(url, alt) {
|
|
68
|
+
const block = {
|
|
69
|
+
type: 'image',
|
|
70
|
+
url,
|
|
71
|
+
alt,
|
|
72
|
+
};
|
|
73
|
+
this.blocks.push(block);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
getBlocks() {
|
|
77
|
+
return this.blocks;
|
|
78
|
+
}
|
|
79
|
+
toMarkdown() {
|
|
80
|
+
return (0, markdown_js_1.toMarkdown)(this.blocks);
|
|
81
|
+
}
|
|
82
|
+
toPlainText() {
|
|
83
|
+
return (0, plainText_js_1.toPlainText)(this.blocks);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.Document = Document;
|
|
87
|
+
function doc() {
|
|
88
|
+
return new Document();
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=Document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Document.js","sourceRoot":"","sources":["../src/Document.ts"],"names":[],"mappings":";;;AAyGA,kBAEC;AAhGD,0DAAwE;AACxE,4DAA2E;AAE3E,MAAa,QAAQ;IACX,MAAM,GAAY,EAAE,CAAC;IAE7B,MAAM,CAAC,IAAY;QACjB,MAAM,KAAK,GAAgB;YACzB,IAAI,EAAE,QAAQ;YACd,IAAI;SACL,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,MAAM,KAAK,GAAc;YACvB,IAAI,EAAE,MAAM;YACZ,OAAO;SACR,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,KAAe;QAClB,MAAM,KAAK,GAAc;YACvB,IAAI,EAAE,MAAM;YACZ,KAAK;SACN,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,MAAM,KAAK,GAAiB;YAC1B,IAAI,EAAE,SAAS;SAChB,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,MAAM,KAAK,GAAiB;YAC1B,IAAI,EAAE,SAAS;YACf,IAAI;SACL,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,IAAY,EAAE,GAAW;QAC5B,MAAM,KAAK,GAAc;YACvB,IAAI,EAAE,MAAM;YACZ,IAAI;YACJ,GAAG;SACJ,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,KAAK,GAAc;YACvB,IAAI,EAAE,MAAM;YACZ,OAAO;YACP,SAAS;SACV,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,GAAY;QAC7B,MAAM,KAAK,GAAe;YACxB,IAAI,EAAE,OAAO;YACb,GAAG;YACH,GAAG;SACJ,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,UAAU;QACR,OAAO,IAAA,wBAAc,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,WAAW;QACT,OAAO,IAAA,0BAAe,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;CACF;AAzFD,4BAyFC;AAED,SAAgB,GAAG;IACjB,OAAO,IAAI,QAAQ,EAAE,CAAC;AACxB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Document, doc } from './Document.js';
|
|
2
|
+
export type { Block, HeaderBlock, TextBlock, ListBlock, DividerBlock, ContextBlock, LinkBlock, CodeBlock, ImageBlock, Platform, } from './types.js';
|
|
3
|
+
export { toMarkdown } from './outputters/markdown.js';
|
|
4
|
+
export { toPlainText } from './outputters/plainText.js';
|
|
5
|
+
export { convertMarkdown, stripMarkdown } from './markdownConverter.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAG9C,YAAY,EACV,KAAK,EACL,WAAW,EACX,SAAS,EACT,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACV,QAAQ,GACT,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stripMarkdown = exports.convertMarkdown = exports.toPlainText = exports.toMarkdown = exports.doc = exports.Document = void 0;
|
|
4
|
+
// Main classes and factory
|
|
5
|
+
var Document_js_1 = require("./Document.js");
|
|
6
|
+
Object.defineProperty(exports, "Document", { enumerable: true, get: function () { return Document_js_1.Document; } });
|
|
7
|
+
Object.defineProperty(exports, "doc", { enumerable: true, get: function () { return Document_js_1.doc; } });
|
|
8
|
+
// Outputters (for direct use)
|
|
9
|
+
var markdown_js_1 = require("./outputters/markdown.js");
|
|
10
|
+
Object.defineProperty(exports, "toMarkdown", { enumerable: true, get: function () { return markdown_js_1.toMarkdown; } });
|
|
11
|
+
var plainText_js_1 = require("./outputters/plainText.js");
|
|
12
|
+
Object.defineProperty(exports, "toPlainText", { enumerable: true, get: function () { return plainText_js_1.toPlainText; } });
|
|
13
|
+
// Markdown converter (for custom outputters)
|
|
14
|
+
var markdownConverter_js_1 = require("./markdownConverter.js");
|
|
15
|
+
Object.defineProperty(exports, "convertMarkdown", { enumerable: true, get: function () { return markdownConverter_js_1.convertMarkdown; } });
|
|
16
|
+
Object.defineProperty(exports, "stripMarkdown", { enumerable: true, get: function () { return markdownConverter_js_1.stripMarkdown; } });
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2BAA2B;AAC3B,6CAA8C;AAArC,uGAAA,QAAQ,OAAA;AAAE,kGAAA,GAAG,OAAA;AAgBtB,8BAA8B;AAC9B,wDAAsD;AAA7C,yGAAA,UAAU,OAAA;AACnB,0DAAwD;AAA/C,2GAAA,WAAW,OAAA;AAEpB,6CAA6C;AAC7C,+DAAwE;AAA/D,uHAAA,eAAe,OAAA;AAAE,qHAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Platform } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Converts inline markdown formatting to the target platform format.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Bold: `**text**` → platform-specific bold
|
|
7
|
+
* - Italic: `*text*` → platform-specific italic
|
|
8
|
+
* - Strikethrough: `~~text~~` → platform-specific strike
|
|
9
|
+
*
|
|
10
|
+
* Processing order: bold → italic → strikethrough (to avoid matching `**` as italic)
|
|
11
|
+
*/
|
|
12
|
+
export declare function convertMarkdown(text: string, platform: Platform): string;
|
|
13
|
+
/**
|
|
14
|
+
* Removes all markdown formatting from text, returning plain text.
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripMarkdown(text: string): string;
|
|
17
|
+
//# sourceMappingURL=markdownConverter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownConverter.d.ts","sourceRoot":"","sources":["../src/markdownConverter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA8DxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAalD"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertMarkdown = convertMarkdown;
|
|
4
|
+
exports.stripMarkdown = stripMarkdown;
|
|
5
|
+
/**
|
|
6
|
+
* Converts inline markdown formatting to the target platform format.
|
|
7
|
+
*
|
|
8
|
+
* Handles:
|
|
9
|
+
* - Bold: `**text**` → platform-specific bold
|
|
10
|
+
* - Italic: `*text*` → platform-specific italic
|
|
11
|
+
* - Strikethrough: `~~text~~` → platform-specific strike
|
|
12
|
+
*
|
|
13
|
+
* Processing order: bold → italic → strikethrough (to avoid matching `**` as italic)
|
|
14
|
+
*/
|
|
15
|
+
function convertMarkdown(text, platform) {
|
|
16
|
+
if (platform === 'plaintext') {
|
|
17
|
+
return stripMarkdown(text);
|
|
18
|
+
}
|
|
19
|
+
let result = text;
|
|
20
|
+
const placeholders = new Map();
|
|
21
|
+
let placeholderIndex = 0;
|
|
22
|
+
// Process bold first: **text** (before italic to avoid matching ** as italic)
|
|
23
|
+
// Use placeholder to prevent italic regex from matching converted bold
|
|
24
|
+
result = result.replace(/\*\*(.+?)\*\*/g, (_match, content) => {
|
|
25
|
+
const placeholder = `__BOLD_PLACEHOLDER_${String(placeholderIndex++)}__`;
|
|
26
|
+
let replacement;
|
|
27
|
+
switch (platform) {
|
|
28
|
+
case 'markdown':
|
|
29
|
+
case 'discord':
|
|
30
|
+
replacement = `**${content}**`;
|
|
31
|
+
break;
|
|
32
|
+
case 'slack':
|
|
33
|
+
replacement = `*${content}*`;
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
replacement = content;
|
|
37
|
+
}
|
|
38
|
+
placeholders.set(placeholder, replacement);
|
|
39
|
+
return placeholder;
|
|
40
|
+
});
|
|
41
|
+
// Process italic: *text* (but not **text**)
|
|
42
|
+
// Use negative lookbehind/lookahead to ensure single asterisk
|
|
43
|
+
result = result.replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, (_match, content) => {
|
|
44
|
+
switch (platform) {
|
|
45
|
+
case 'markdown':
|
|
46
|
+
case 'discord':
|
|
47
|
+
return `*${content}*`;
|
|
48
|
+
case 'slack':
|
|
49
|
+
return `_${content}_`;
|
|
50
|
+
default:
|
|
51
|
+
return content;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// Process strikethrough: ~~text~~
|
|
55
|
+
result = result.replace(/~~(.+?)~~/g, (_match, content) => {
|
|
56
|
+
switch (platform) {
|
|
57
|
+
case 'markdown':
|
|
58
|
+
case 'discord':
|
|
59
|
+
return `~~${content}~~`;
|
|
60
|
+
case 'slack':
|
|
61
|
+
return `~${content}~`;
|
|
62
|
+
default:
|
|
63
|
+
return content;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// Replace placeholders with final bold format
|
|
67
|
+
for (const [placeholder, replacement] of placeholders) {
|
|
68
|
+
result = result.replace(placeholder, replacement);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Removes all markdown formatting from text, returning plain text.
|
|
74
|
+
*/
|
|
75
|
+
function stripMarkdown(text) {
|
|
76
|
+
let result = text;
|
|
77
|
+
// Remove bold: **text** → text
|
|
78
|
+
result = result.replace(/\*\*(.+?)\*\*/g, '$1');
|
|
79
|
+
// Remove italic: *text* → text (but not **text**)
|
|
80
|
+
result = result.replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, '$1');
|
|
81
|
+
// Remove strikethrough: ~~text~~ → text
|
|
82
|
+
result = result.replace(/~~(.+?)~~/g, '$1');
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=markdownConverter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownConverter.js","sourceRoot":"","sources":["../src/markdownConverter.ts"],"names":[],"mappings":";;AAYA,0CA8DC;AAKD,sCAaC;AA1FD;;;;;;;;;GASG;AACH,SAAgB,eAAe,CAAC,IAAY,EAAE,QAAkB;IAC9D,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC7B,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAEzB,8EAA8E;IAC9E,uEAAuE;IACvE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAe,EAAE,EAAE;QACpE,MAAM,WAAW,GAAG,sBAAsB,MAAM,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;QACzE,IAAI,WAAmB,CAAC;QACxB,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,SAAS;gBACZ,WAAW,GAAG,KAAK,OAAO,IAAI,CAAC;gBAC/B,MAAM;YACR,KAAK,OAAO;gBACV,WAAW,GAAG,IAAI,OAAO,GAAG,CAAC;gBAC7B,MAAM;YACR;gBACE,WAAW,GAAG,OAAO,CAAC;QAC1B,CAAC;QACD,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAC3C,OAAO,WAAW,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,8DAA8D;IAC9D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,4BAA4B,EAAE,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QACxF,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,SAAS;gBACZ,OAAO,IAAI,OAAO,GAAG,CAAC;YACxB,KAAK,OAAO;gBACV,OAAO,IAAI,OAAO,GAAG,CAAC;YACxB;gBACE,OAAO,OAAO,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,kCAAkC;IAClC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;QACxE,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,SAAS;gBACZ,OAAO,KAAK,OAAO,IAAI,CAAC;YAC1B,KAAK,OAAO;gBACV,OAAO,IAAI,OAAO,GAAG,CAAC;YACxB;gBACE,OAAO,OAAO,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,8CAA8C;IAC9C,KAAK,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,IAAI,YAAY,EAAE,CAAC;QACtD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,IAAY;IACxC,IAAI,MAAM,GAAG,IAAI,CAAC;IAElB,+BAA+B;IAC/B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAEhD,kDAAkD;IAClD,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,4BAA4B,EAAE,IAAI,CAAC,CAAC;IAE5D,wCAAwC;IACxC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/outputters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toPlainText = exports.toMarkdown = void 0;
|
|
4
|
+
var markdown_js_1 = require("./markdown.js");
|
|
5
|
+
Object.defineProperty(exports, "toMarkdown", { enumerable: true, get: function () { return markdown_js_1.toMarkdown; } });
|
|
6
|
+
var plainText_js_1 = require("./plainText.js");
|
|
7
|
+
Object.defineProperty(exports, "toPlainText", { enumerable: true, get: function () { return plainText_js_1.toPlainText; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/outputters/index.ts"],"names":[],"mappings":";;;AAAA,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AACnB,+CAA6C;AAApC,2GAAA,WAAW,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/outputters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAsClD"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toMarkdown = toMarkdown;
|
|
4
|
+
function toMarkdown(blocks) {
|
|
5
|
+
return blocks
|
|
6
|
+
.map((block) => {
|
|
7
|
+
switch (block.type) {
|
|
8
|
+
case 'header':
|
|
9
|
+
return `# ${block.text}\n\n`;
|
|
10
|
+
case 'text':
|
|
11
|
+
return `${block.content}\n\n`;
|
|
12
|
+
case 'list':
|
|
13
|
+
return `${block.items.map((item) => `- ${item}`).join('\n')}\n\n`;
|
|
14
|
+
case 'divider':
|
|
15
|
+
return `---\n\n`;
|
|
16
|
+
case 'context':
|
|
17
|
+
return `*${block.text}*\n\n`;
|
|
18
|
+
case 'link':
|
|
19
|
+
return `[${block.text}](${block.url})\n\n`;
|
|
20
|
+
case 'code':
|
|
21
|
+
if (block.multiline) {
|
|
22
|
+
return `\`\`\`\n${block.content}\n\`\`\`\n\n`;
|
|
23
|
+
}
|
|
24
|
+
return `\`${block.content}\`\n\n`;
|
|
25
|
+
case 'image': {
|
|
26
|
+
const alt = block.alt ?? block.url;
|
|
27
|
+
return `\n\n`;
|
|
28
|
+
}
|
|
29
|
+
default:
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.join('');
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/outputters/markdown.ts"],"names":[],"mappings":";;AAEA,gCAsCC;AAtCD,SAAgB,UAAU,CAAC,MAAe;IACxC,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,QAAQ;gBACX,OAAO,KAAK,KAAK,CAAC,IAAI,MAAM,CAAC;YAE/B,KAAK,MAAM;gBACT,OAAO,GAAG,KAAK,CAAC,OAAO,MAAM,CAAC;YAEhC,KAAK,MAAM;gBACT,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAEpE,KAAK,SAAS;gBACZ,OAAO,SAAS,CAAC;YAEnB,KAAK,SAAS;gBACZ,OAAO,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC;YAE/B,KAAK,MAAM;gBACT,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC;YAE7C,KAAK,MAAM;gBACT,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;oBACpB,OAAO,WAAW,KAAK,CAAC,OAAO,cAAc,CAAC;gBAChD,CAAC;gBACD,OAAO,KAAK,KAAK,CAAC,OAAO,QAAQ,CAAC;YAEpC,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;gBACnC,OAAO,KAAK,GAAG,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC;YACvC,CAAC;YAED;gBACE,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plainText.d.ts","sourceRoot":"","sources":["../../src/outputters/plainText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAmCnD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toPlainText = toPlainText;
|
|
4
|
+
const markdownConverter_js_1 = require("../markdownConverter.js");
|
|
5
|
+
function toPlainText(blocks) {
|
|
6
|
+
return blocks
|
|
7
|
+
.map((block) => {
|
|
8
|
+
switch (block.type) {
|
|
9
|
+
case 'header':
|
|
10
|
+
return `${block.text.toUpperCase()}\n\n`;
|
|
11
|
+
case 'text':
|
|
12
|
+
return `${(0, markdownConverter_js_1.stripMarkdown)(block.content)}\n\n`;
|
|
13
|
+
case 'list':
|
|
14
|
+
return `${block.items.map((item) => `• ${(0, markdownConverter_js_1.stripMarkdown)(item)}`).join('\n')}\n\n`;
|
|
15
|
+
case 'divider':
|
|
16
|
+
return `────────────────\n\n`;
|
|
17
|
+
case 'context':
|
|
18
|
+
return `${(0, markdownConverter_js_1.stripMarkdown)(block.text)}\n\n`;
|
|
19
|
+
case 'link':
|
|
20
|
+
return `${block.text} (${block.url})\n\n`;
|
|
21
|
+
case 'code':
|
|
22
|
+
return `${block.content}\n\n`;
|
|
23
|
+
case 'image': {
|
|
24
|
+
const alt = block.alt ?? block.url;
|
|
25
|
+
return `[Image: ${alt}]\n\n`;
|
|
26
|
+
}
|
|
27
|
+
default:
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.join('');
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=plainText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plainText.js","sourceRoot":"","sources":["../../src/outputters/plainText.ts"],"names":[],"mappings":";;AAGA,kCAmCC;AArCD,kEAAwD;AAExD,SAAgB,WAAW,CAAC,MAAe;IACzC,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,QAAQ;gBACX,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;YAE3C,KAAK,MAAM;gBACT,OAAO,GAAG,IAAA,oCAAa,EAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAE/C,KAAK,MAAM;gBACT,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAA,oCAAa,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;YAEnF,KAAK,SAAS;gBACZ,OAAO,sBAAsB,CAAC;YAEhC,KAAK,SAAS;gBACZ,OAAO,GAAG,IAAA,oCAAa,EAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;YAE5C,KAAK,MAAM;gBACT,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC;YAE5C,KAAK,MAAM;gBACT,OAAO,GAAG,KAAK,CAAC,OAAO,MAAM,CAAC;YAEhC,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;gBACnC,OAAO,WAAW,GAAG,OAAO,CAAC;YAC/B,CAAC;YAED;gBACE,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type Platform = 'markdown' | 'slack' | 'discord' | 'plaintext';
|
|
2
|
+
export type Block = HeaderBlock | TextBlock | ListBlock | DividerBlock | ContextBlock | LinkBlock | CodeBlock | ImageBlock;
|
|
3
|
+
export interface HeaderBlock {
|
|
4
|
+
type: 'header';
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TextBlock {
|
|
8
|
+
type: 'text';
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ListBlock {
|
|
12
|
+
type: 'list';
|
|
13
|
+
items: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface DividerBlock {
|
|
16
|
+
type: 'divider';
|
|
17
|
+
}
|
|
18
|
+
export interface ContextBlock {
|
|
19
|
+
type: 'context';
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
export interface LinkBlock {
|
|
23
|
+
type: 'link';
|
|
24
|
+
text: string;
|
|
25
|
+
url: string;
|
|
26
|
+
}
|
|
27
|
+
export interface CodeBlock {
|
|
28
|
+
type: 'code';
|
|
29
|
+
content: string;
|
|
30
|
+
multiline: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface ImageBlock {
|
|
33
|
+
type: 'image';
|
|
34
|
+
url: string;
|
|
35
|
+
alt?: string;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,KAAK,GACb,WAAW,GACX,SAAS,GACT,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,SAAS,GACT,UAAU,CAAC;AAEf,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hardlydifficult/document-generator",
|
|
3
|
+
"version": "1.0.1",
|
|
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
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"lint": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"typescript": "5.8.3",
|
|
18
|
+
"@types/node": "20.19.31",
|
|
19
|
+
"vitest": "1.6.1"
|
|
20
|
+
}
|
|
21
|
+
}
|