Skip to content

Refactor code structure for improved readability and maintainability #142

Refactor code structure for improved readability and maintainability

Refactor code structure for improved readability and maintainability #142

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: [20, 22]
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Production dependency audit
if: matrix.node == 20
run: pnpm run audit:prod
- name: Lint
if: matrix.node == 20
run: pnpm run lint
- name: Typecheck
run: pnpm run typecheck
- name: Type smoke
if: matrix.node == 20
run: pnpm run test:types
- name: Test
run: pnpm test -- --run
env:
CI: true
- name: Plugin compatibility matrix
if: matrix.node == 20
run: pnpm run test:plugins
env:
CI: true
- name: Slow stream correctness test
if: matrix.node == 20
run: pnpm run test:stream:slow
env:
CI: true
- name: Parser performance threshold
if: matrix.node == 20
run: pnpm run test:perf-threshold
env:
CI: true
- name: Build
if: matrix.node == 20
run: pnpm run build
- name: Package export/type lint
if: matrix.node == 20
run: pnpm run test:package-lint
- name: Pack package
if: matrix.node == 20
run: |
mkdir -p /tmp/markdown-it-ts-pack
pnpm pack --pack-destination /tmp/markdown-it-ts-pack
- name: Smoke test packed package
if: matrix.node == 20
run: |
PKG="$(ls /tmp/markdown-it-ts-pack/markdown-it-ts-*.tgz)"
mkdir -p /tmp/markdown-it-ts-smoke
cd /tmp/markdown-it-ts-smoke
printf '{"type":"module"}\n' > package.json
pnpm add "$PKG"
cat > smoke.mjs <<'EOF'
import MarkdownIt, {
Token as RootToken,
parse as rootParse,
parseInline as rootParseInline,
withRenderer as rootWithRenderer,
} from 'markdown-it-ts'
import { withRenderer } from 'markdown-it-ts/plugins/with-renderer'
import Renderer from 'markdown-it-ts/render/renderer'
import { StreamBuffer as StreamBufferSubpath } from 'markdown-it-ts/stream/buffer'
import { chunkedParse as chunkedParseSubpath } from 'markdown-it-ts/stream/chunked'
import {
DebouncedStreamParser,
ThrottledStreamParser,
} from 'markdown-it-ts/stream/debounced'
import {
recommendFullChunkStrategy,
recommendStreamChunkStrategy,
} from 'markdown-it-ts/support/chunk_recommend'
import {
ParserCore,
Token as CoreToken,
} from 'markdown-it-ts/core'
import {
EditableBuffer as ExperimentalEditableBuffer,
PieceTable as ExperimentalPieceTable,
StreamBuffer as ExperimentalStreamBuffer,
UnboundedBuffer as ExperimentalUnboundedBuffer,
parseAsyncIterable as experimentalParseAsyncIterable,
parseAsyncIterableToSink as experimentalParseAsyncIterableToSink,
parseIterable as experimentalParseIterable,
parseIterableToSink as experimentalParseIterableToSink,
chunkedParse as experimentalChunkedParse,
} from 'markdown-it-ts/experimental'
import { Token } from 'markdown-it-ts/common/token'
import { countLines, escapeHtml } from 'markdown-it-ts/common/utils'
const md = MarkdownIt()
const html = md.render('# ok')
const rootExports = await import('markdown-it-ts')
if (html !== '<h1>ok</h1>\n')
throw new Error(`unexpected render output: ${html}`)
for (const name of [
'chunkedParse',
'StreamBuffer',
'UnboundedBuffer',
'EditableBuffer',
'PieceTable',
'parseIterable',
'parseAsyncIterable',
'parseIterableToSink',
'parseAsyncIterableToSink',
'recommendFullChunkStrategy',
'recommendStreamChunkStrategy',
'DebouncedStreamParser',
'ThrottledStreamParser',
'getParseDiagnostics',
]) {
if (name in rootExports)
throw new Error(`${name} should be imported from markdown-it-ts/experimental or a subpath`)
}
if (typeof Renderer !== 'function')
throw new Error('Renderer default export is not a function')
if (typeof RootToken !== 'function')
throw new Error('root Token export is not a function')
if (typeof rootParse !== 'function')
throw new Error('root parse export is not a function')
if (typeof rootParseInline !== 'function')
throw new Error('root parseInline export is not a function')
if (typeof rootWithRenderer !== 'function')
throw new Error('root withRenderer export is not a function')
if (typeof withRenderer !== 'function')
throw new Error('withRenderer subpath export is not a function')
if (typeof StreamBufferSubpath !== 'function')
throw new Error('stream/buffer subpath export is not a function')
if (typeof chunkedParseSubpath !== 'function')
throw new Error('stream/chunked subpath export is not a function')
if (typeof DebouncedStreamParser !== 'function')
throw new Error('DebouncedStreamParser subpath export is not a function')
if (typeof ThrottledStreamParser !== 'function')
throw new Error('ThrottledStreamParser subpath export is not a function')
if (typeof recommendFullChunkStrategy !== 'function')
throw new Error('recommendFullChunkStrategy subpath export is not a function')
if (typeof recommendStreamChunkStrategy !== 'function')
throw new Error('recommendStreamChunkStrategy subpath export is not a function')
if (typeof ParserCore !== 'function')
throw new Error('core ParserCore export is not a function')
if (typeof CoreToken !== 'function')
throw new Error('core Token export is not a function')
if (typeof experimentalChunkedParse !== 'function')
throw new Error('experimental chunkedParse export is not a function')
if (typeof ExperimentalStreamBuffer !== 'function')
throw new Error('experimental StreamBuffer export is not a function')
if (typeof ExperimentalEditableBuffer !== 'function')
throw new Error('experimental EditableBuffer export is not a function')
if (typeof ExperimentalPieceTable !== 'function')
throw new Error('experimental PieceTable export is not a function')
if (typeof ExperimentalUnboundedBuffer !== 'function')
throw new Error('experimental UnboundedBuffer export is not a function')
if (typeof experimentalParseIterable !== 'function')
throw new Error('experimental parseIterable export is not a function')
if (typeof experimentalParseAsyncIterable !== 'function')
throw new Error('experimental parseAsyncIterable export is not a function')
if (typeof experimentalParseIterableToSink !== 'function')
throw new Error('experimental parseIterableToSink export is not a function')
if (typeof experimentalParseAsyncIterableToSink !== 'function')
throw new Error('experimental parseAsyncIterableToSink export is not a function')
if (typeof Token !== 'function')
throw new Error('Token export is not a function')
if (escapeHtml('<>&"') !== '&lt;&gt;&amp;&quot;')
throw new Error('common/utils escapeHtml subpath export returned unexpected output')
if (countLines('a\nb\nc') !== 2)
throw new Error('common/utils countLines subpath export returned unexpected output')
EOF
node smoke.mjs
node "$GITHUB_WORKSPACE/scripts/package-type-smoke.mjs" "$PKG"
- name: Bundler smoke packed package
if: matrix.node == 20
run: |
PKG="$(ls /tmp/markdown-it-ts-pack/markdown-it-ts-*.tgz)"
MDTS_PACKAGE_SPEC="$PKG" node scripts/bundler-smoke.mjs
- name: Upload packed package
if: matrix.node == 20
uses: actions/upload-artifact@v4
with:
name: markdown-it-ts-pack
path: /tmp/markdown-it-ts-pack/*.tgz
if-no-files-found: error
runtime-smoke:
needs: quality
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: [18, 20, 22]
steps:
- name: Download packed package
uses: actions/download-artifact@v4
with:
name: markdown-it-ts-pack
path: /tmp/markdown-it-ts-pack
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Runtime smoke test
run: |
PKG="$(ls /tmp/markdown-it-ts-pack/markdown-it-ts-*.tgz)"
mkdir -p /tmp/markdown-it-ts-runtime-smoke
cd /tmp/markdown-it-ts-runtime-smoke
npm init -y
npm pkg set type=module
npm install "$PKG"
cat > smoke.mjs <<'EOF'
import MarkdownIt, {
Token as RootToken,
parse as rootParse,
parseInline as rootParseInline,
withRenderer as rootWithRenderer,
} from 'markdown-it-ts'
import { withRenderer } from 'markdown-it-ts/plugins/with-renderer'
import Renderer from 'markdown-it-ts/render/renderer'
import { StreamBuffer as StreamBufferSubpath } from 'markdown-it-ts/stream/buffer'
import { chunkedParse as chunkedParseSubpath } from 'markdown-it-ts/stream/chunked'
import {
DebouncedStreamParser,
ThrottledStreamParser,
} from 'markdown-it-ts/stream/debounced'
import {
recommendFullChunkStrategy,
recommendStreamChunkStrategy,
} from 'markdown-it-ts/support/chunk_recommend'
import {
ParserCore,
Token as CoreToken,
} from 'markdown-it-ts/core'
import {
EditableBuffer as ExperimentalEditableBuffer,
PieceTable as ExperimentalPieceTable,
StreamBuffer as ExperimentalStreamBuffer,
UnboundedBuffer as ExperimentalUnboundedBuffer,
parseIterable as experimentalParseIterable,
chunkedParse as experimentalChunkedParse,
} from 'markdown-it-ts/experimental'
import { Token } from 'markdown-it-ts/common/token'
import { countLines, escapeHtml } from 'markdown-it-ts/common/utils'
const md = MarkdownIt()
const html = md.render('# ok')
const rootExports = await import('markdown-it-ts')
if (html !== '<h1>ok</h1>\n')
throw new Error(`unexpected render output: ${html}`)
for (const name of [
'chunkedParse',
'StreamBuffer',
'UnboundedBuffer',
'EditableBuffer',
'PieceTable',
'parseIterable',
'parseAsyncIterable',
'parseIterableToSink',
'parseAsyncIterableToSink',
'recommendFullChunkStrategy',
'recommendStreamChunkStrategy',
'DebouncedStreamParser',
'ThrottledStreamParser',
'getParseDiagnostics',
]) {
if (name in rootExports)
throw new Error(`${name} should be imported from markdown-it-ts/experimental or a subpath`)
}
if (typeof Renderer !== 'function')
throw new Error('Renderer default export is not a function')
if (typeof RootToken !== 'function')
throw new Error('root Token export is not a function')
if (typeof rootParse !== 'function')
throw new Error('root parse export is not a function')
if (typeof rootParseInline !== 'function')
throw new Error('root parseInline export is not a function')
if (typeof rootWithRenderer !== 'function')
throw new Error('root withRenderer export is not a function')
if (typeof withRenderer !== 'function')
throw new Error('withRenderer subpath export is not a function')
if (typeof StreamBufferSubpath !== 'function')
throw new Error('stream/buffer subpath export is not a function')
if (typeof chunkedParseSubpath !== 'function')
throw new Error('stream/chunked subpath export is not a function')
if (typeof DebouncedStreamParser !== 'function')
throw new Error('DebouncedStreamParser subpath export is not a function')
if (typeof ThrottledStreamParser !== 'function')
throw new Error('ThrottledStreamParser subpath export is not a function')
if (typeof recommendFullChunkStrategy !== 'function')
throw new Error('recommendFullChunkStrategy subpath export is not a function')
if (typeof recommendStreamChunkStrategy !== 'function')
throw new Error('recommendStreamChunkStrategy subpath export is not a function')
if (typeof ParserCore !== 'function')
throw new Error('core ParserCore export is not a function')
if (typeof CoreToken !== 'function')
throw new Error('core Token export is not a function')
if (typeof experimentalChunkedParse !== 'function')
throw new Error('experimental chunkedParse export is not a function')
if (typeof ExperimentalStreamBuffer !== 'function')
throw new Error('experimental StreamBuffer export is not a function')
if (typeof ExperimentalEditableBuffer !== 'function')
throw new Error('experimental EditableBuffer export is not a function')
if (typeof ExperimentalPieceTable !== 'function')
throw new Error('experimental PieceTable export is not a function')
if (typeof ExperimentalUnboundedBuffer !== 'function')
throw new Error('experimental UnboundedBuffer export is not a function')
if (typeof experimentalParseIterable !== 'function')
throw new Error('experimental parseIterable export is not a function')
if (typeof Token !== 'function')
throw new Error('Token export is not a function')
if (escapeHtml('<') !== '&lt;')
throw new Error('common/utils escapeHtml subpath export returned unexpected output')
if (countLines('a\nb') !== 1)
throw new Error('common/utils countLines subpath export returned unexpected output')
EOF
node smoke.mjs