@dev-workflow/skill 0.1.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/LICENSE +21 -0
- package/README.md +80 -0
- package/bin/cli.mjs +9 -0
- package/package.json +39 -0
- package/skills/artifact/README.md +23 -0
- package/skills/execution/devFlow/SKILL.md +341 -0
- package/skills/execution/devFlow/agents/openai.yaml +7 -0
- package/skills/execution/devFlow/domains/backend/references/api-tech.md +173 -0
- package/skills/execution/devFlow/domains/backend/scripts/check_api_tech_doc.mjs +170 -0
- package/skills/execution/devFlow/domains/backend/scripts/check_api_tech_doc.test.mjs +89 -0
- package/skills/execution/devFlow/domains/backend/templates/api-tech.md +164 -0
- package/skills/execution/devFlow/domains/frontend/references/contract-check.md +270 -0
- package/skills/execution/devFlow/domains/frontend/references/foundation-freeze.md +92 -0
- package/skills/execution/devFlow/domains/frontend/references/lightweight-flow.md +55 -0
- package/skills/execution/devFlow/domains/frontend/references/page-build.md +268 -0
- package/skills/execution/devFlow/domains/frontend/references/page-tech.md +414 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/field-common.md +69 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-complex.md +105 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-id-code.md +44 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-number-date.md +106 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-relation.md +144 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-selectors.md +102 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/fields-text.md +130 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/index.md +42 -0
- package/skills/execution/devFlow/domains/frontend/references/product-design-specs/interaction.md +61 -0
- package/skills/execution/devFlow/domains/frontend/scripts/check_page_tech_doc.mjs +82 -0
- package/skills/execution/devFlow/domains/frontend/scripts/contract_check_static.mjs +145 -0
- package/skills/execution/devFlow/domains/frontend/scripts/generate_foundation_summary.mjs +224 -0
- package/skills/execution/devFlow/domains/frontend/templates/contract-report.md +66 -0
- package/skills/execution/devFlow/domains/frontend/templates/mini-plan-l0.md +7 -0
- package/skills/execution/devFlow/domains/frontend/templates/mini-plan-l1.md +9 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/component.tsx.tpl +8 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/constants.ts.tpl +5 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/index.ts.tpl +1 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/route.tsx.tpl +11 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/service.ts.tpl +17 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-build/types.ts.tpl +11 -0
- package/skills/execution/devFlow/domains/frontend/templates/page-tech.md +103 -0
- package/skills/execution/devFlow/domains/requirement/references/prd-review.md +129 -0
- package/skills/execution/devFlow/domains/requirement/templates/prd-review.md +57 -0
- package/skills/execution/figmaSync/SKILL.md +349 -0
- package/skills/execution/figmaSync/chapters/apply.md +177 -0
- package/skills/execution/figmaSync/chapters/plan.md +359 -0
- package/skills/execution/figmaSync/chapters/prepare.md +47 -0
- package/skills/execution/figmaSync/examples/native-css.md +129 -0
- package/skills/execution/figmaSync/examples/plan-doc-sample.md +39 -0
- package/skills/execution/figmaSync/scripts/_shared/session-log.mjs +82 -0
- package/skills/execution/figmaSync/scripts/_shared/token-resolver.mjs +132 -0
- package/skills/execution/figmaSync/scripts/_shared/token-source.mjs +145 -0
- package/skills/execution/figmaSync/scripts/figma-sync-report.mjs +448 -0
- package/skills/execution/figmaSync/scripts/icon-inventory.mjs +165 -0
- package/skills/execution/figmaSync/scripts/lookup-var.mjs +184 -0
- package/skills/execution/figmaSync/scripts/match-token.mjs +210 -0
- package/skills/execution/figmaSync/scripts/prepare-check.mjs +290 -0
- package/skills/execution/figmaSync/scripts/verify-plan.mjs +458 -0
- package/skills/execution/figmaSync/snapshots/README.md +13 -0
- package/skills/execution/figmaSync/snapshots/last-sync.md +1538 -0
- package/skills/execution/figmaSync/templates/PLAN.md.tpl +227 -0
- package/skills/review/consistency-checker/SKILL.md +112 -0
- package/skills/review/consistency-checker/rules/README.md +16 -0
- package/src/cli/agents.mjs +16 -0
- package/src/cli/copy.mjs +95 -0
- package/src/cli/install.mjs +131 -0
- package/src/cli/prompts.mjs +66 -0
- package/tools/lark/README.md +78 -0
- package/tools/lark/references/lark-doc.md +156 -0
- package/tools/lark/references/lark-read.md +235 -0
- package/tools/lark/references/prepare.md +147 -0
- package/tools/lark/scripts/lark_api.mjs +404 -0
- package/tools/lark/scripts/lark_api.test.mjs +63 -0
- package/tools/lark/scripts/lark_check_permissions.mjs +52 -0
- package/tools/lark/scripts/lark_publish_doc.mjs +299 -0
- package/tools/lark/scripts/lark_read_docx.mjs +328 -0
- package/tools/lark/scripts/markdown_to_lark_blocks.mjs +397 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
|
|
3
|
+
import { parseArgs, printJson } from './lark_api.mjs'
|
|
4
|
+
|
|
5
|
+
const MAX_TEXT_LENGTH = 1800
|
|
6
|
+
const MAX_TABLE_CELLS = 45
|
|
7
|
+
// 飞书 docx 单次创建表格 row_size 上限为 9,超过返回 1770001 invalid param。
|
|
8
|
+
const MAX_TABLE_ROWS = 9
|
|
9
|
+
const CODE_LANGUAGE_MAP = {
|
|
10
|
+
javascript: 3,
|
|
11
|
+
js: 3,
|
|
12
|
+
typescript: 3,
|
|
13
|
+
ts: 3,
|
|
14
|
+
json: 19,
|
|
15
|
+
bash: 14,
|
|
16
|
+
sh: 14,
|
|
17
|
+
shell: 14
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function splitLongText(text) {
|
|
21
|
+
if (text.length <= MAX_TEXT_LENGTH) return [text]
|
|
22
|
+
|
|
23
|
+
const chunks = []
|
|
24
|
+
let rest = text
|
|
25
|
+
|
|
26
|
+
while (rest.length > MAX_TEXT_LENGTH) {
|
|
27
|
+
let cut = rest.lastIndexOf('\n', MAX_TEXT_LENGTH)
|
|
28
|
+
if (cut < MAX_TEXT_LENGTH * 0.5) cut = rest.lastIndexOf('。', MAX_TEXT_LENGTH)
|
|
29
|
+
if (cut < MAX_TEXT_LENGTH * 0.5) cut = MAX_TEXT_LENGTH
|
|
30
|
+
|
|
31
|
+
chunks.push(rest.slice(0, cut).trim())
|
|
32
|
+
rest = rest.slice(cut).trim()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (rest) chunks.push(rest)
|
|
36
|
+
return chunks
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function createTextBlock(text) {
|
|
40
|
+
return {
|
|
41
|
+
block_type: 2,
|
|
42
|
+
text: {
|
|
43
|
+
elements: createTextElements(text)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function createBulletBlock(text) {
|
|
49
|
+
return {
|
|
50
|
+
block_type: 12,
|
|
51
|
+
bullet: {
|
|
52
|
+
elements: createTextElements(text)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function createOrderedBlock(text, sequence) {
|
|
58
|
+
return {
|
|
59
|
+
block_type: 13,
|
|
60
|
+
ordered: {
|
|
61
|
+
elements: createTextElements(text),
|
|
62
|
+
style: {
|
|
63
|
+
sequence: String(sequence)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createCalloutBlock(text, emoji) {
|
|
70
|
+
const block = {
|
|
71
|
+
block_type: 19,
|
|
72
|
+
callout: { background_color: 1, border_color: 1, emoji_id: emoji || 'memo' }
|
|
73
|
+
}
|
|
74
|
+
// 文本作为子块由 writeBlocks 经 descendant API 写入,避免污染 JSON 序列化。
|
|
75
|
+
Object.defineProperty(block, '__calloutText', { value: text })
|
|
76
|
+
return block
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function createQuoteBlock(text) {
|
|
80
|
+
const block = { block_type: 34, quote_container: {} }
|
|
81
|
+
Object.defineProperty(block, '__quoteText', { value: text })
|
|
82
|
+
return block
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function createHeadingBlock(level, text) {
|
|
86
|
+
const blockType = level === 1 ? 3 : level === 2 ? 4 : 5
|
|
87
|
+
const key = level === 1 ? 'heading1' : level === 2 ? 'heading2' : 'heading3'
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
block_type: blockType,
|
|
91
|
+
[key]: {
|
|
92
|
+
elements: createTextElements(text)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createTextElements(text) {
|
|
98
|
+
const elements = []
|
|
99
|
+
// 同时识别行内代码 `code` 与粗体 **bold**。
|
|
100
|
+
const pattern = /(`[^`\n]+`)|(\*\*[^*\n]+\*\*)/g
|
|
101
|
+
let lastIndex = 0
|
|
102
|
+
let match
|
|
103
|
+
|
|
104
|
+
while ((match = pattern.exec(text))) {
|
|
105
|
+
if (match.index > lastIndex) {
|
|
106
|
+
elements.push({ text_run: { content: text.slice(lastIndex, match.index) } })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const token = match[0]
|
|
110
|
+
if (token.startsWith('`')) {
|
|
111
|
+
elements.push({
|
|
112
|
+
text_run: { content: token.slice(1, -1), text_element_style: { inline_code: true } }
|
|
113
|
+
})
|
|
114
|
+
} else {
|
|
115
|
+
elements.push({
|
|
116
|
+
text_run: { content: token.slice(2, -2), text_element_style: { bold: true } }
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
lastIndex = pattern.lastIndex
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (lastIndex < text.length) {
|
|
124
|
+
elements.push({ text_run: { content: text.slice(lastIndex) } })
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return elements.length ? elements : [{ text_run: { content: '' } }]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function normalizeLanguage(language) {
|
|
131
|
+
const key = language.trim().toLowerCase()
|
|
132
|
+
return CODE_LANGUAGE_MAP[key] || CODE_LANGUAGE_MAP.text
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function createCodeBlock(language, code) {
|
|
136
|
+
const block = {
|
|
137
|
+
block_type: 14,
|
|
138
|
+
code: {
|
|
139
|
+
elements: [{ text_run: { content: code } }]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const languageCode = normalizeLanguage(language)
|
|
143
|
+
|
|
144
|
+
if (languageCode) {
|
|
145
|
+
block.code.style = { language: languageCode }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return block
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function splitTableRow(line) {
|
|
152
|
+
const trimmed = line.trim().replace(/^\|/, '').replace(/\|$/, '')
|
|
153
|
+
// 仅按未转义的 | 切分单元格,再把 \| 还原为字面 |(支持单元格内的联合类型如 'A' \| 'B')。
|
|
154
|
+
return trimmed.split(/(?<!\\)\|/).map((cell) => cell.trim().replace(/\\\|/g, '|'))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isTableSeparator(line) {
|
|
158
|
+
const cells = splitTableRow(line)
|
|
159
|
+
return cells.length > 1 && cells.every((cell) => /^:?-{3,}:?$/.test(cell))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function isTableStart(lines, index) {
|
|
163
|
+
return (
|
|
164
|
+
index + 1 < lines.length && lines[index].includes('|') && isTableSeparator(lines[index + 1])
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function collectTable(lines, startIndex) {
|
|
169
|
+
const rows = [splitTableRow(lines[startIndex])]
|
|
170
|
+
let index = startIndex + 2
|
|
171
|
+
|
|
172
|
+
while (index < lines.length && lines[index].trim() && lines[index].includes('|')) {
|
|
173
|
+
rows.push(splitTableRow(lines[index]))
|
|
174
|
+
index += 1
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { rows, nextIndex: index }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function createTableBlocks(rows) {
|
|
181
|
+
const columnSize = Math.max(...rows.map((row) => row.length))
|
|
182
|
+
const normalizedRows = rows.map((row) => [
|
|
183
|
+
...row,
|
|
184
|
+
...Array.from({ length: columnSize - row.length }, () => '')
|
|
185
|
+
])
|
|
186
|
+
const maxRows = Math.max(
|
|
187
|
+
2,
|
|
188
|
+
Math.min(MAX_TABLE_ROWS, Math.floor(MAX_TABLE_CELLS / columnSize))
|
|
189
|
+
)
|
|
190
|
+
const tables = []
|
|
191
|
+
const header = normalizedRows[0]
|
|
192
|
+
const bodyRows = normalizedRows.slice(1)
|
|
193
|
+
const chunks = []
|
|
194
|
+
|
|
195
|
+
if (normalizedRows.length <= maxRows) {
|
|
196
|
+
chunks.push(normalizedRows)
|
|
197
|
+
} else {
|
|
198
|
+
const bodyChunkSize = Math.max(1, maxRows - 1)
|
|
199
|
+
|
|
200
|
+
for (let index = 0; index < bodyRows.length; index += bodyChunkSize) {
|
|
201
|
+
chunks.push([header, ...bodyRows.slice(index, index + bodyChunkSize)])
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (const chunk of chunks) {
|
|
206
|
+
tables.push(createTableBlock(chunk, columnSize))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return tables
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const TABLE_TOTAL_WIDTH = 760
|
|
213
|
+
const TABLE_MIN_COL_WIDTH = 56
|
|
214
|
+
|
|
215
|
+
function displayWidth(text) {
|
|
216
|
+
let width = 0
|
|
217
|
+
for (const ch of String(text)) {
|
|
218
|
+
width += /[一-鿿 -〿-]/.test(ch) ? 2 : 1
|
|
219
|
+
}
|
|
220
|
+
return width
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function computeColumnWidths(rows, columnSize) {
|
|
224
|
+
// 满宽自适应:按每列最长内容(中文计 2 宽)分配,归一到 ~760,长枚举名少换行、行更矮。
|
|
225
|
+
const weights = Array.from({ length: columnSize }, (_, col) =>
|
|
226
|
+
Math.max(2, ...rows.map((row) => displayWidth(row[col] ?? '')))
|
|
227
|
+
)
|
|
228
|
+
const sum = weights.reduce((acc, value) => acc + value, 0) || columnSize
|
|
229
|
+
const widths = weights.map((weight) =>
|
|
230
|
+
Math.max(TABLE_MIN_COL_WIDTH, Math.round((TABLE_TOTAL_WIDTH * weight) / sum))
|
|
231
|
+
)
|
|
232
|
+
const diff = TABLE_TOTAL_WIDTH - widths.reduce((acc, value) => acc + value, 0)
|
|
233
|
+
widths[columnSize - 1] = Math.max(TABLE_MIN_COL_WIDTH, widths[columnSize - 1] + diff)
|
|
234
|
+
return widths
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function createTableBlock(rows, columnSize) {
|
|
238
|
+
const block = {
|
|
239
|
+
block_type: 31,
|
|
240
|
+
table: {
|
|
241
|
+
property: {
|
|
242
|
+
row_size: rows.length,
|
|
243
|
+
column_size: columnSize
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Object.defineProperty(block, '__tableRows', {
|
|
249
|
+
value: rows
|
|
250
|
+
})
|
|
251
|
+
// 表头底色与列宽建表时不被接受,由 writeBlocks 在建表后 PATCH 设置。
|
|
252
|
+
Object.defineProperty(block, '__columnWidth', {
|
|
253
|
+
value: computeColumnWidths(rows, columnSize)
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
return block
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function markdownToLarkBlocks(markdown) {
|
|
260
|
+
const lines = markdown.replace(/\r\n/g, '\n').split('\n')
|
|
261
|
+
const blocks = []
|
|
262
|
+
let paragraph = []
|
|
263
|
+
let codeFence = null
|
|
264
|
+
let codeLines = []
|
|
265
|
+
let orderedSequence = 1
|
|
266
|
+
|
|
267
|
+
const flushParagraph = () => {
|
|
268
|
+
const text = paragraph.join('\n').trim()
|
|
269
|
+
paragraph = []
|
|
270
|
+
|
|
271
|
+
if (!text) return
|
|
272
|
+
|
|
273
|
+
for (const chunk of splitLongText(text)) {
|
|
274
|
+
blocks.push(createTextBlock(chunk))
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const flushCode = () => {
|
|
279
|
+
const language = codeFence ? codeFence.replace(/^```/, '').trim() : ''
|
|
280
|
+
const body = codeLines.join('\n')
|
|
281
|
+
codeFence = null
|
|
282
|
+
codeLines = []
|
|
283
|
+
|
|
284
|
+
for (const chunk of splitLongText(body)) {
|
|
285
|
+
blocks.push(createCodeBlock(language, chunk))
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
290
|
+
const line = lines[index]
|
|
291
|
+
|
|
292
|
+
if (line.startsWith('```')) {
|
|
293
|
+
if (codeFence) {
|
|
294
|
+
flushCode()
|
|
295
|
+
} else {
|
|
296
|
+
flushParagraph()
|
|
297
|
+
codeFence = line
|
|
298
|
+
codeLines = []
|
|
299
|
+
}
|
|
300
|
+
continue
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (isTableStart(lines, index)) {
|
|
304
|
+
flushParagraph()
|
|
305
|
+
orderedSequence = 1
|
|
306
|
+
const table = collectTable(lines, index)
|
|
307
|
+
blocks.push(...createTableBlocks(table.rows))
|
|
308
|
+
index = table.nextIndex - 1
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (codeFence) {
|
|
313
|
+
codeLines.push(line)
|
|
314
|
+
continue
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const heading = /^(#{1,3})\s+(.+)$/.exec(line)
|
|
318
|
+
if (heading) {
|
|
319
|
+
flushParagraph()
|
|
320
|
+
blocks.push(createHeadingBlock(heading[1].length, heading[2].trim()))
|
|
321
|
+
continue
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 高亮块 callout:`> [!TIP] 文本` / `> [!NOTE] ...` / `> [!WARNING] ...`。
|
|
325
|
+
const calloutMatch = /^>\s*\[!(\w+)\]\s*(.*)$/.exec(line)
|
|
326
|
+
if (calloutMatch) {
|
|
327
|
+
flushParagraph()
|
|
328
|
+
orderedSequence = 1
|
|
329
|
+
const type = calloutMatch[1].toUpperCase()
|
|
330
|
+
const emoji = type === 'WARNING' || type === 'WARN' ? 'warning' : type === 'TIP' ? 'bulb' : 'memo'
|
|
331
|
+
blocks.push(createCalloutBlock(calloutMatch[2].trim(), emoji))
|
|
332
|
+
continue
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// 引用块:`> 文本` → 飞书 quote_container(引用样式),由 writeBlocks 经 descendant API 写入。
|
|
336
|
+
const quote = /^>\s?(.*)$/.exec(line)
|
|
337
|
+
if (quote) {
|
|
338
|
+
flushParagraph()
|
|
339
|
+
orderedSequence = 1
|
|
340
|
+
const text = quote[1].trim()
|
|
341
|
+
if (text) blocks.push(createQuoteBlock(text))
|
|
342
|
+
continue
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (line.trim() === '') {
|
|
346
|
+
flushParagraph()
|
|
347
|
+
orderedSequence = 1
|
|
348
|
+
continue
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// 分割线:独立的 --- / *** / ___(非表格分隔行)→ 飞书 divider 块。
|
|
352
|
+
if (/^(-{3,}|\*{3,}|_{3,})$/.test(line.trim())) {
|
|
353
|
+
flushParagraph()
|
|
354
|
+
orderedSequence = 1
|
|
355
|
+
blocks.push({ block_type: 22, divider: {} })
|
|
356
|
+
continue
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const bullet = /^\s*[-*]\s+(.+)$/.exec(line)
|
|
360
|
+
if (bullet) {
|
|
361
|
+
flushParagraph()
|
|
362
|
+
orderedSequence = 1
|
|
363
|
+
blocks.push(createBulletBlock(bullet[1].trim()))
|
|
364
|
+
continue
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const ordered = /^\s*\d+[.)]\s+(.+)$/.exec(line)
|
|
368
|
+
if (ordered) {
|
|
369
|
+
flushParagraph()
|
|
370
|
+
blocks.push(createOrderedBlock(ordered[1].trim(), orderedSequence))
|
|
371
|
+
orderedSequence += 1
|
|
372
|
+
continue
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
orderedSequence = 1
|
|
376
|
+
paragraph.push(line)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (codeFence) flushCode()
|
|
380
|
+
flushParagraph()
|
|
381
|
+
|
|
382
|
+
return blocks
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async function main() {
|
|
386
|
+
const args = parseArgs()
|
|
387
|
+
const file = args.file
|
|
388
|
+
const markdown = file ? readFileSync(file, 'utf8') : readFileSync(0, 'utf8')
|
|
389
|
+
printJson({ blocks: markdownToLarkBlocks(markdown) })
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
393
|
+
main().catch((error) => {
|
|
394
|
+
console.error(error.message)
|
|
395
|
+
process.exit(1)
|
|
396
|
+
})
|
|
397
|
+
}
|