@jacobbubu/md-to-lark 1.4.11 → 1.5.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 CHANGED
@@ -112,6 +112,7 @@ Presets, Mermaid, and stage artifacts:
112
112
  npm run publish:md -- --input ./test-md/comp/comp.md --preset medium --dry-run
113
113
  npm run publish:md -- --input ./test-md/comp/comp.md --preset zh-format --dry-run
114
114
  npm run publish:md -- --input ./test-md/comp/comp.md --preset zh-format --preset ./my-preset.mjs --dry-run
115
+ npm run publish:md -- --input ./paper.md --single-dollar-text-math --dry-run
115
116
  npm run publish:md -- --input ./tmp/generated/article.md --resource-base-dir ./source-assets --dry-run
116
117
  npm run publish:md -- --input ./test-md/mermaid.md --mermaid-target board --dry-run
117
118
  npm run publish:md -- --input ./test-md/comp/comp.md --pipeline-cache-dir ./out/debug-cache --dry-run
@@ -175,6 +176,7 @@ Guardrails:
175
176
  - Local attachment and image detection with real upload
176
177
  - Remote image download and standalone URL preparation
177
178
  - Mermaid `text-drawing` and `board` output paths
179
+ - Opt-in single-dollar inline math parsing for LaTeX-heavy papers
178
180
  - Table width heuristics and numeric-column right alignment
179
181
  - Chinese Markdown formatting preset (`zh-format`)
180
182
  - Ordered preset composition from CLI and programmatic usage
@@ -1,6 +1,6 @@
1
1
  function usage() {
2
2
  return [
3
- 'Usage: npm run publish:md -- --input <file.md|dir> [--title <doc_title_or_prefix>] [--date-prefix|--no-date-prefix] [--preset <preset_name_or_module_path>]... [--document-base-url <base_url>] [--resource-base-dir <dir>] [--folder <folder_token>] [--doc <document_id>] [--download-remote-images|--no-download-remote-images] [--yt-dlp-path <path>] [--yt-dlp-cookies-path <path>] [--pipeline-cache-dir <dir>] [--mermaid-target <text-drawing|board>] [--mermaid-board-syntax-type <int>] [--mermaid-board-style-type <int>] [--mermaid-board-diagram-type <int>] [--dry-run] [--help|-h]',
3
+ 'Usage: npm run publish:md -- --input <file.md|dir> [--title <doc_title_or_prefix>] [--date-prefix|--no-date-prefix] [--preset <preset_name_or_module_path>]... [--document-base-url <base_url>] [--resource-base-dir <dir>] [--folder <folder_token>] [--doc <document_id>] [--download-remote-images|--no-download-remote-images] [--yt-dlp-path <path>] [--yt-dlp-cookies-path <path>] [--pipeline-cache-dir <dir>] [--single-dollar-text-math] [--mermaid-target <text-drawing|board>] [--mermaid-board-syntax-type <int>] [--mermaid-board-style-type <int>] [--mermaid-board-diagram-type <int>] [--dry-run] [--help|-h]',
4
4
  '',
5
5
  'Options:',
6
6
  ' --input Markdown file path, or directory path (publish all *.md recursively).',
@@ -17,6 +17,7 @@ function usage() {
17
17
  ' --yt-dlp-path Optional yt-dlp executable path for standalone URL extraction.',
18
18
  ' --yt-dlp-cookies-path Optional cookie file path passed to yt-dlp --cookies.',
19
19
  ' --pipeline-cache-dir Pipeline cache root directory. Default: ./out/pipeline-cache',
20
+ ' --single-dollar-text-math Opt in to parsing $...$ as inline math. Default: disabled to avoid currency false positives.',
20
21
  ' --mermaid-target Mermaid render target: text-drawing (default) or board.',
21
22
  ' --mermaid-board-syntax-type Optional integer syntax_type for board createPlantuml (default: 2).',
22
23
  ' --mermaid-board-style-type Optional integer style_type for board createPlantuml.',
@@ -63,6 +64,7 @@ export function parsePublishMdArgs(argv, env = process.env) {
63
64
  let ytDlpPath = '';
64
65
  let ytDlpCookiesPath = '';
65
66
  let pipelineCacheDir = '';
67
+ let singleDollarTextMath;
66
68
  let mermaidTarget;
67
69
  let mermaidBoardSyntaxType;
68
70
  let mermaidBoardStyleType;
@@ -175,6 +177,10 @@ export function parsePublishMdArgs(argv, env = process.env) {
175
177
  i += 1;
176
178
  continue;
177
179
  }
180
+ if (arg === '--single-dollar-text-math' || arg === '--single-dollar-math') {
181
+ singleDollarTextMath = true;
182
+ continue;
183
+ }
178
184
  if (arg === '--mermaid-target') {
179
185
  const value = argv[i + 1];
180
186
  if (!value)
@@ -245,6 +251,7 @@ export function parsePublishMdArgs(argv, env = process.env) {
245
251
  ...(ytDlpPath.trim() ? { ytDlpPath: ytDlpPath.trim() } : {}),
246
252
  ...(ytDlpCookiesPath.trim() ? { ytDlpCookiesPath: ytDlpCookiesPath.trim() } : {}),
247
253
  ...(pipelineCacheDir.trim() ? { pipelineCacheDir: pipelineCacheDir.trim() } : {}),
254
+ ...(singleDollarTextMath === undefined ? {} : { singleDollarTextMath }),
248
255
  ...(mermaidTarget ? { mermaidTarget } : {}),
249
256
  ...(mermaidBoardSyntaxType === undefined ? {} : { mermaidBoardSyntaxType }),
250
257
  ...(mermaidBoardStyleType === undefined ? {} : { mermaidBoardStyleType }),
@@ -73,9 +73,7 @@ export async function publishMdToLark(options, env = process.env) {
73
73
  const runtime = buildPublishRuntime(options, env, markdownPresets);
74
74
  logPublishRuntimeSummary(runtime, inputSet.markdownFiles.length, inputSet.mode);
75
75
  const normalizedDocumentId = options.documentId ? normalizeDocumentId(options.documentId) : undefined;
76
- const resolveTargetDocumentId = options.dryRun || normalizedDocumentId
77
- ? undefined
78
- : createFolderDocumentResolver(runtime, options);
76
+ const resolveTargetDocumentId = options.dryRun || normalizedDocumentId ? undefined : createFolderDocumentResolver(runtime, options);
79
77
  const results = [];
80
78
  for (let index = 0; index < inputSet.markdownFiles.length; index += 1) {
81
79
  const markdownPath = inputSet.markdownFiles[index];
@@ -1,4 +1,4 @@
1
1
  export { applyStandaloneAttachmentTransforms } from '../../publish/asset-adapter.js';
2
2
  export { patchBTTForMermaidAndAssets } from '../../publish/btt-patch.js';
3
3
  export { buildPipelineDocumentId } from '../../publish/ids.js';
4
- export { applyTableColumnWidthHeuristics, collectMermaidPatches, ensureLastBlockBttIds } from '../../publish/last-normalize.js';
4
+ export { applyTableColumnWidthHeuristics, collectMermaidPatches, ensureLastBlockBttIds, } from '../../publish/last-normalize.js';
@@ -1,4 +1,4 @@
1
- import { buildLASTIndexes, flattenTreeBlocks, fromRawBlockToLAST, } from './codec-btt-to-last.js';
1
+ import { buildLASTIndexes, flattenTreeBlocks, fromRawBlockToLAST } from './codec-btt-to-last.js';
2
2
  import { normalizeDocumentIdToLAST } from './codec-last-to-btt.js';
3
3
  export function convertBTTToLAST(bttDoc) {
4
4
  const rawBlocks = Object.keys(bttDoc.flatBlocks ?? {}).length
@@ -1,5 +1,5 @@
1
- import { createDocumentChildren, } from './ops.js';
2
- import { DEFAULT_MERMAID_RENDER_CONFIG, } from './render-types.js';
1
+ import { createDocumentChildren } from './ops.js';
2
+ import { DEFAULT_MERMAID_RENDER_CONFIG } from './render-types.js';
3
3
  import { applyCreatedBoardMermaid, applyCreatedFileBlock, applyCreatedImageBlock } from './render-post-process.js';
4
4
  import { renderCreatedTableNode } from './render-table.js';
5
5
  import { buildCreatePayloadFromRawBlock, createRenderBatchEntry, getSourceBlockId, toObjectRecord, } from './render-payload.js';
@@ -124,7 +124,8 @@ export function canUseElementsOnlyPatch(rawBlock) {
124
124
  if (effectiveEntries.length === 0)
125
125
  return true;
126
126
  for (const [key, value] of effectiveEntries) {
127
- if (key === 'align' && (value === 1 || value === 2 || value === 3 || value === 'left' || value === 'center' || value === 'right')) {
127
+ if (key === 'align' &&
128
+ (value === 1 || value === 2 || value === 3 || value === 'left' || value === 'center' || value === 'right')) {
128
129
  continue;
129
130
  }
130
131
  return false;
@@ -310,7 +311,12 @@ export function getSourceBlockId(node, rawBlockRecord) {
310
311
  : node.blockId;
311
312
  }
312
313
  function isBatchSafeBlockType(blockType) {
313
- if (blockType === 1 || blockType === 23 || blockType === 27 || blockType === 31 || blockType === 32 || blockType === 43) {
314
+ if (blockType === 1 ||
315
+ blockType === 23 ||
316
+ blockType === 27 ||
317
+ blockType === 31 ||
318
+ blockType === 32 ||
319
+ blockType === 43) {
314
320
  return false;
315
321
  }
316
322
  return true;
@@ -33,7 +33,9 @@ export async function applyCreatedImageBlock(client, documentId, createdBlockId,
33
33
  ...(typeof width === 'number' ? { width } : {}),
34
34
  ...(typeof proportionalHeight === 'number' ? { height: proportionalHeight } : {}),
35
35
  ...(image && typeof image.align === 'number' ? { align: image.align } : {}),
36
- ...(image && toObjectRecord(image.caption) ? { caption: toObjectRecord(image.caption) } : {}),
36
+ ...(image && toObjectRecord(image.caption)
37
+ ? { caption: toObjectRecord(image.caption) }
38
+ : {}),
37
39
  ...(image && typeof image.scale === 'number' ? { scale: image.scale } : {}),
38
40
  };
39
41
  let imageToken = await uploadBinaryToNode(client, 'docx_image', createdBlockId, localPath, authOptions, mediaLimiter);
@@ -145,7 +145,7 @@ function createDividerBlock(ctx, parentId) {
145
145
  });
146
146
  return blockId;
147
147
  }
148
- function createImageBlock(ctx, parentId, sourceUrl) {
148
+ function createImageBlock(ctx, parentId, sourceUrl, alt = null) {
149
149
  const blockId = nextBlockId(ctx);
150
150
  const parentBlock = ctx.blocks[parentId];
151
151
  const blockBase = {
@@ -155,8 +155,15 @@ function createImageBlock(ctx, parentId, sourceUrl) {
155
155
  children: [],
156
156
  payload: createDefaultImagePayload(parentBlock?.type),
157
157
  };
158
+ const selectorAttrs = {};
158
159
  if (sourceUrl) {
159
- blockBase.selector = { attrs: { sourceUrl } };
160
+ selectorAttrs.sourceUrl = sourceUrl;
161
+ }
162
+ if (alt) {
163
+ selectorAttrs.alt = alt;
164
+ }
165
+ if (Object.keys(selectorAttrs).length > 0) {
166
+ blockBase.selector = { attrs: selectorAttrs };
160
167
  }
161
168
  addBlock(ctx, blockBase);
162
169
  return blockId;
@@ -358,14 +365,31 @@ function isWhitespaceTextNode(node) {
358
365
  function getMeaningfulChildren(nodes) {
359
366
  return nodes.filter((child) => !isWhitespaceTextNode(child));
360
367
  }
361
- function findStandaloneImageSrcInParagraph(paragraph) {
368
+ function extractImageSourceFromElement(element) {
369
+ if (element.tagName === 'img') {
370
+ return {
371
+ sourceUrl: getStringProp(element, 'src'),
372
+ alt: getStringProp(element, 'alt'),
373
+ };
374
+ }
375
+ if (element.tagName !== 'a')
376
+ return null;
377
+ const meaningfulChildren = getMeaningfulChildren(getChildren(element));
378
+ if (meaningfulChildren.length !== 1)
379
+ return null;
380
+ const only = meaningfulChildren[0];
381
+ if (!only || !isElement(only))
382
+ return null;
383
+ return extractImageSourceFromElement(only);
384
+ }
385
+ function findStandaloneImageInParagraph(paragraph) {
362
386
  const meaningfulChildren = getMeaningfulChildren(getChildren(paragraph));
363
387
  if (meaningfulChildren.length !== 1)
364
388
  return null;
365
389
  const only = meaningfulChildren[0];
366
- if (!only || !isElement(only) || only.tagName !== 'img')
390
+ if (!only || !isElement(only))
367
391
  return null;
368
- return getStringProp(only, 'src');
392
+ return extractImageSourceFromElement(only);
369
393
  }
370
394
  function parseHttpUrl(url) {
371
395
  try {
@@ -472,10 +496,11 @@ function findStandaloneRichItemInTableCell(cell) {
472
496
  }
473
497
  if (!only || !isElement(only))
474
498
  return null;
475
- if (only.tagName === 'img') {
499
+ const imageSource = extractImageSourceFromElement(only);
500
+ if (imageSource) {
476
501
  return {
477
502
  kind: 'image',
478
- sourceUrl: getStringProp(only, 'src'),
503
+ ...imageSource,
479
504
  };
480
505
  }
481
506
  if (only.tagName !== 'a')
@@ -667,7 +692,7 @@ function convertTable(ctx, table, parentId) {
667
692
  const cellBlock = ctx.blocks[cellId];
668
693
  const richItem = cell ? findStandaloneRichItemInTableCell(cell) : null;
669
694
  if (cellBlock?.type === 'table_cell' && richItem?.kind === 'image') {
670
- const imageId = createImageBlock(ctx, cellId, richItem.sourceUrl);
695
+ const imageId = createImageBlock(ctx, cellId, richItem.sourceUrl, richItem.alt);
671
696
  cellBlock.children = [imageId];
672
697
  cells.push(cellId);
673
698
  continue;
@@ -733,6 +758,44 @@ function convertUnknownElement(ctx, element, parentId) {
733
758
  ]),
734
759
  ];
735
760
  }
761
+ function hasNonWhitespaceInline(inlines) {
762
+ return inlines.some((inline) => toSearchText(inline).text.trim().length > 0);
763
+ }
764
+ function convertParagraph(ctx, paragraph, parentId) {
765
+ const standaloneImage = findStandaloneImageInParagraph(paragraph);
766
+ if (standaloneImage?.sourceUrl) {
767
+ return [createImageBlock(ctx, parentId, standaloneImage.sourceUrl, standaloneImage.alt)];
768
+ }
769
+ const standaloneIframe = findStandaloneIframePayloadInParagraph(paragraph);
770
+ if (standaloneIframe) {
771
+ return [createIframeBlock(ctx, parentId, standaloneIframe.url, standaloneIframe.iframeType)];
772
+ }
773
+ const ids = [];
774
+ let pendingInlineNodes = [];
775
+ const flushText = () => {
776
+ if (pendingInlineNodes.length === 0)
777
+ return;
778
+ const inlines = parseInlineNodes(ctx, pendingInlineNodes);
779
+ pendingInlineNodes = [];
780
+ if (!hasNonWhitespaceInline(inlines))
781
+ return;
782
+ ids.push(createTextualBlock(ctx, 'text', parentId, inlines));
783
+ };
784
+ for (const child of getChildren(paragraph)) {
785
+ const image = isElement(child) ? extractImageSourceFromElement(child) : null;
786
+ if (image?.sourceUrl) {
787
+ flushText();
788
+ ids.push(createImageBlock(ctx, parentId, image.sourceUrl, image.alt));
789
+ continue;
790
+ }
791
+ pendingInlineNodes.push(child);
792
+ }
793
+ flushText();
794
+ if (ids.length > 0) {
795
+ return ids;
796
+ }
797
+ return [createTextualBlock(ctx, 'text', parentId, parseInlineNodes(ctx, getChildren(paragraph)))];
798
+ }
736
799
  function convertBlock(ctx, node, parentId) {
737
800
  if (isWhitespaceTextNode(node)) {
738
801
  return [];
@@ -753,17 +816,8 @@ function convertBlock(ctx, node, parentId) {
753
816
  return [];
754
817
  }
755
818
  switch (node.tagName) {
756
- case 'p': {
757
- const standaloneImageSrc = findStandaloneImageSrcInParagraph(node);
758
- if (standaloneImageSrc) {
759
- return [createImageBlock(ctx, parentId, standaloneImageSrc)];
760
- }
761
- const standaloneIframe = findStandaloneIframePayloadInParagraph(node);
762
- if (standaloneIframe) {
763
- return [createIframeBlock(ctx, parentId, standaloneIframe.url, standaloneIframe.iframeType)];
764
- }
765
- return [createTextualBlock(ctx, 'text', parentId, parseInlineNodes(ctx, getChildren(node)))];
766
- }
819
+ case 'p':
820
+ return convertParagraph(ctx, node, parentId);
767
821
  case 'h1':
768
822
  case 'h2':
769
823
  case 'h3':
@@ -789,7 +843,7 @@ function convertBlock(ctx, node, parentId) {
789
843
  case 'table':
790
844
  return convertTable(ctx, node, parentId);
791
845
  case 'img':
792
- return [createImageBlock(ctx, parentId, getStringProp(node, 'src'))];
846
+ return [createImageBlock(ctx, parentId, getStringProp(node, 'src'), getStringProp(node, 'alt'))];
793
847
  case 'br':
794
848
  return [
795
849
  createTextualBlock(ctx, 'text', parentId, [
@@ -4,12 +4,12 @@ import remarkGfm from 'remark-gfm';
4
4
  import remarkMath from 'remark-math';
5
5
  import remarkRehype from 'remark-rehype';
6
6
  import { normalizeMarkdownBeforeParse } from './normalize-markdown.js';
7
- export async function markdownToHast(markdown) {
7
+ export async function markdownToHast(markdown, options = {}) {
8
8
  const content = normalizeMarkdownBeforeParse(markdown);
9
9
  const processor = unified()
10
10
  .use(remarkParse)
11
11
  .use(remarkGfm)
12
- .use(remarkMath, { singleDollarTextMath: false })
12
+ .use(remarkMath, { singleDollarTextMath: options.singleDollarTextMath ?? false })
13
13
  .use(remarkRehype, { allowDangerousHtml: false });
14
14
  const mdast = processor.parse(content);
15
15
  const hast = await processor.run(mdast);
@@ -345,6 +345,7 @@ export function renderHASTToTerminal(root, options = {}) {
345
345
  return `${ctx.lines.join('\n')}\n`;
346
346
  }
347
347
  export async function renderMarkdownToTerminal(markdown, options = {}) {
348
- const hast = await markdownToHast(markdown);
348
+ const parseOptions = options.singleDollarTextMath === undefined ? {} : { singleDollarTextMath: options.singleDollarTextMath };
349
+ const hast = await markdownToHast(markdown, parseOptions);
349
350
  return renderHASTToTerminal(hast, options);
350
351
  }
@@ -44,7 +44,9 @@ function applyRawBlockPatch(rawBlock, blockId, mermaidByBlockId, assetByBlockId,
44
44
  file.media_kind = asset.mediaKind;
45
45
  }
46
46
  if (typeof file.view_type !== 'number') {
47
- file.view_type = shouldUsePreviewView(path.extname(asset.fileName).toLowerCase(), asset.mediaKind ?? 'file') ? 2 : 1;
47
+ file.view_type = shouldUsePreviewView(path.extname(asset.fileName).toLowerCase(), asset.mediaKind ?? 'file')
48
+ ? 2
49
+ : 1;
48
50
  }
49
51
  rawBlock.file = file;
50
52
  }
@@ -2,6 +2,6 @@ export { applyStandaloneAttachmentTransforms } from './asset-adapter.js';
2
2
  export { patchBTTForMermaidAndAssets } from './btt-patch.js';
3
3
  export { buildPipelineDocumentId } from './ids.js';
4
4
  export { applyTableColumnWidthHeuristics, collectMermaidPatches, ensureLastBlockBttIds } from './last-normalize.js';
5
- export { processSingleMarkdownFile } from './process-file.js';
6
- export { buildPublishRuntime, logPublishRuntimeSummary } from './runtime.js';
5
+ export { processSingleMarkdownFile, } from './process-file.js';
6
+ export { buildPublishRuntime, logPublishRuntimeSummary, } from './runtime.js';
7
7
  export { buildPipelineStagePaths, ensureDir, writeJson, writeSourceStage, writePrepareStage, writePrepareLogFile, writeHastStage, writeLastStage, writeBttStage, writePublishStageArtifact, } from './stage-cache.js';
@@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { convertLASTToBTT } from '../interop/index.js';
4
4
  import { clearDocumentContent, normalizeDocumentId } from '../lark/docx/ops.js';
5
- import { renderBTTToDocument, } from '../lark/docx/render-btt.js';
5
+ import { renderBTTToDocument } from '../lark/docx/render-btt.js';
6
6
  import { hastToLAST, markdownToHast, prepareMarkdownBeforePublish } from '../pipeline/index.js';
7
7
  import { applySingleH1TitleRule, buildTitleForMarkdown } from '../commands/publish-md/title-policy.js';
8
8
  import { applyStandaloneAttachmentTransforms } from './asset-adapter.js';
@@ -95,7 +95,7 @@ export async function processSingleMarkdownFile(params) {
95
95
  markdown = prepareResult.preparedContent;
96
96
  await writePrepareStage(stagePaths, markdown, prepareResult);
97
97
  console.error(`[prepare ${index + 1}/${inputSet.markdownFiles.length}] rewritten=${prepareResult.rewrittenCount} downloaded=${prepareResult.downloadedCount} failed=${prepareResult.failedCount} log=${prepareResult.logFilePath}`);
98
- const hast = await markdownToHast(markdown);
98
+ const hast = await markdownToHast(markdown, runtime.markdownParseConfig);
99
99
  await writeHastStage(stagePaths, hast);
100
100
  const h1RuleResult = options.title ? {} : applySingleH1TitleRule(hast);
101
101
  const title = buildTitleForMarkdown(markdownPath, inputSet, options.title, h1RuleResult.derivedTitle, {
@@ -99,6 +99,9 @@ export function buildPublishRuntime(options, env, markdownPresets) {
99
99
  ...(mermaidBoardDiagramType === undefined ? {} : { diagramType: mermaidBoardDiagramType }),
100
100
  },
101
101
  };
102
+ const markdownParseConfig = {
103
+ singleDollarTextMath: options.singleDollarTextMath ?? false,
104
+ };
102
105
  return {
103
106
  env,
104
107
  markdownPresets,
@@ -118,6 +121,7 @@ export function buildPublishRuntime(options, env, markdownPresets) {
118
121
  downloadRemoteImages,
119
122
  ...(ytDlpPath ? { ytDlpPath } : {}),
120
123
  mermaidRenderConfig,
124
+ markdownParseConfig,
121
125
  prepareConfig: {
122
126
  enabled: downloadRemoteImages,
123
127
  timeoutMs: prepareTimeoutMs,
@@ -138,6 +142,9 @@ export function logPublishRuntimeSummary(runtime, inputCount, inputMode) {
138
142
  console.error(runtime.mermaidRenderConfig.target === 'board'
139
143
  ? `Mermaid: target=board syntax_type=${String(runtime.mermaidRenderConfig.board.syntaxType)} style_type=${String(runtime.mermaidRenderConfig.board.styleType ?? '(default)')} diagram_type=${String(runtime.mermaidRenderConfig.board.diagramType ?? '(default)')}`
140
144
  : 'Mermaid: target=text-drawing');
145
+ if (runtime.markdownParseConfig.singleDollarTextMath) {
146
+ console.error('Markdown parse: single_dollar_text_math=true');
147
+ }
141
148
  console.error(`Document URL base: ${runtime.documentBaseUrl}`);
142
149
  if (runtime.resourceBaseDir) {
143
150
  console.error(`Local asset base override: ${runtime.resourceBaseDir}`);
@@ -1,9 +1,7 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
4
- const JPEG_SOF_MARKERS = new Set([
5
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf,
6
- ]);
4
+ const JPEG_SOF_MARKERS = new Set([0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf]);
7
5
  function isPositiveInteger(value) {
8
6
  return Number.isInteger(value) && value > 0;
9
7
  }
@@ -68,9 +66,7 @@ function readJpegDimensions(buffer) {
68
66
  return null;
69
67
  }
70
68
  function readWebpDimensions(buffer) {
71
- if (buffer.length < 30 ||
72
- buffer.toString('ascii', 0, 4) !== 'RIFF' ||
73
- buffer.toString('ascii', 8, 12) !== 'WEBP') {
69
+ if (buffer.length < 30 || buffer.toString('ascii', 0, 4) !== 'RIFF' || buffer.toString('ascii', 8, 12) !== 'WEBP') {
74
70
  return null;
75
71
  }
76
72
  const chunkType = buffer.toString('ascii', 12, 16);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacobbubu/md-to-lark",
3
- "version": "1.4.11",
3
+ "version": "1.5.1",
4
4
  "description": "Publish Markdown to Feishu docs with a stable pipeline.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",