TypeScript Markdown parser and HTML renderer. Published to GitHub Packages as @lazyalienserver/alienmark. Consumed by apps/frontend (workspace) and apps/alienmark (workspace, HTTP service). Syntax docs live in docs/alienmark/.
This is a published library: the public API surface is a stability contract.
From src/index.ts:
// High-level
export function renderMarkdown(markdown: string, options?: ParseOptions): string;
export function parseMarkdown(markdown: string, options?: ParseOptions): DocumentNode;
// Lower-level
export { parse, renderHtml };
export type * from "./ast/nodes.js"; // DocumentNode, ParseOptions, and all AST node typesrenderMarkdown=renderHtml(parse(markdown, options)).parseMarkdownreturns the structured AST (DocumentNode).parseandrenderHtmlare the lower-level entrypoints, also exported.- All AST node types are re-exported from
src/ast/nodes.ts.
Treat anything exported from
src/index.tsas the public surface. Don't rename, reorder, or change signatures of these exports without bumping the package version and coordinating downstream (apps/frontend,apps/alienmark, and external consumers via GitHub Packages).
AlienMark is not full CommonMark. It intentionally supports only what AlienCommons needs:
- Headings
#through####. - Paragraphs.
- Strong emphasis
**text**/__text__; emphasis*text*/_text_. - Inline code with backticks.
- Links
[label](url); images. - Fenced code blocks (triple backticks).
- Blockquotes (
>). - Single-level ordered and unordered lists.
- Horizontal rules (
---,***,___).
When adding syntax, extend the AST in src/ast/nodes.ts, parse it in src/parser/, render it in src/renderer/, document it in docs/alienmark/docs/syntax.{en,zh}.md, and add tests in test/.
src/
├── index.ts Public re-exports.
├── ast/nodes.ts AST node types + ParseOptions + DocumentNode.
├── parser/
│ ├── parse.ts Block parser entrypoint.
│ └── inline.ts Inline parser (emphasis, code, links, images).
└── renderer/
└── render-html.ts AST → HTML.
test/
└── alienmark.test.ts Vitest tests (run via `vp test run`).
- Build:
vp pack→ ESMdist/index.mjs+dist/index.d.mts. - Tests: Vitest (
vp test run). - Typecheck:
tsc --noEmitundertsconfig.json— note strict flags:strict,noUncheckedIndexedAccess,exactOptionalPropertyTypes,verbatimModuleSyntax,isolatedModules. - Module:
NodeNext. Target:ESNext. Use real ESM imports with.jsspecifiers (e.g../parser/parse.js) —verbatimModuleSyntaxrequiresimport typefor type-only imports.
| Action | Command |
|---|---|
| Build (lib) | pnpm turbo run build --filter=alienmark |
| Dev (watch) | pnpm --filter alienmark dev |
| Tests | pnpm turbo run test --filter=alienmark (vp test run) |
| Full check | pnpm turbo run check --filter=alienmark |
| Typecheck | pnpm turbo run typecheck --filter=alienmark (tsc --noEmit) |
| Lint | pnpm turbo run lint:check --filter=alienmark |
| Format check | pnpm turbo run fmt:check --filter=alienmark |
- Public API is stable. Bump
versioninpackage.json(currently0.1.x) on any breaking change; coordinate withapps/frontendandapps/alienmarkand external consumers. - No
any.exactOptionalPropertyTypesis on — model optional fields precisely; don't smuggleundefinedinto required positions. .jsimport specifiers are mandatory (NodeNext +verbatimModuleSyntax). Type-only imports must useimport type.- Always update both
test/anddocs/alienmark/docs/syntax.{en,zh}.mdwhen supported syntax changes (seedocs/AGENTS.mdon keeping EN/ZH in sync). - Don't commit
dist/. - Match existing parser/renderer conventions; don't introduce a CommonMark-compliant reimplementation unless that's the explicit task.
pnpm turbo run test --filter=alienmark # Vitest
pnpm turbo run check --filter=alienmark # vp check (lint + format + type-aware)
pnpm turbo run typecheck --filter=alienmark # tsc --noEmitCI publishes this package from the main branch via .github/workflows/alienmark-package-publish.yml. Don't change the publish workflow's package name, registry, or version source without coordinating.