@pretextbook/remark-pretext 0.0.1 → 0.0.3

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.
@@ -0,0 +1,22 @@
1
+ import { BlockContent, DefinitionContent, PhrasingContent } from 'mdast';
2
+ export interface VisitContext {
3
+ /** Parent node, if any. */
4
+ parent?: BlockContent | DefinitionContent | PhrasingContent;
5
+ /** All ancestor nodes in traversal order. */
6
+ ancestors: (BlockContent | DefinitionContent | PhrasingContent)[];
7
+ /** Nesting depth. */
8
+ depth: number;
9
+ /** Accumulated error/warning messages. */
10
+ messages?: ConversionMessage[];
11
+ /** Raw source markdown (optional, used for delimiter detection). */
12
+ source?: string;
13
+ }
14
+ export interface ConversionMessage {
15
+ type: 'warning' | 'error';
16
+ reason: string;
17
+ category: string;
18
+ position?: {
19
+ line?: number;
20
+ column?: number;
21
+ };
22
+ }
@@ -0,0 +1,24 @@
1
+ import { BlockContent, DefinitionContent } from 'mdast';
2
+ import { ContainerDirective } from 'mdast-util-directive';
3
+ import { Element } from 'xast';
4
+ import { DirectiveSpec } from './directive-map.js';
5
+ import { VisitContext } from './context.js';
6
+ /**
7
+ * Generic factory function: applies semantic rules from spec.
8
+ *
9
+ * Handles:
10
+ * - Statement wrapping for theorem-like elements
11
+ * - Task nesting with introduction wrapping (exercise/project/task)
12
+ * - Proof/solution sibling extraction
13
+ *
14
+ * @param spec Semantic specification for this directive type
15
+ * @param attrs HTML/XML attributes for the element
16
+ * @param titleEl Optional <title> element (extracted from first paragraph if present)
17
+ * @param children Body content of the directive
18
+ * @param ctx Visitor context
19
+ * @param convertBlock Callback to recursively convert block children
20
+ * @param convertDirective Callback to recursively convert nested directives
21
+ *
22
+ * @returns XAST element for this directive
23
+ */
24
+ export declare function buildDirectiveWithSpec(spec: DirectiveSpec, attrs: Record<string, string> | undefined, titleEl: Element | null, children: Array<BlockContent | DefinitionContent>, ctx: VisitContext, convertBlock: (child: BlockContent | DefinitionContent, ctx: VisitContext) => Element | null, convertDirective: (node: ContainerDirective, ctx: VisitContext) => Element | null): Element;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Maps directive names (from remark-directive's `:::name`) to their
3
+ * corresponding xast element names and semantic specifications.
4
+ *
5
+ * Architecture (Phase 2 refactor):
6
+ * - Separated semantic specs (requiresStatement) from routing logic
7
+ * - Factories apply spec-driven semantic rules uniformly
8
+ * - Adding new directives requires only configuration change, not new functions
9
+ */
10
+ export type DirectiveCategory = 'theorem-like' | 'proof-like' | 'definition-like' | 'axiom-like' | 'remark-like' | 'example-like' | 'project-like' | 'exercise-like' | 'solution-like';
11
+ /**
12
+ * Semantic specification for how a directive type should be converted.
13
+ * This pattern mirrors unified-latex-to-pretext's factory specifications.
14
+ */
15
+ export interface DirectiveSpec {
16
+ /** The PreTeXt XML element name (= xast `name` field). */
17
+ type: string;
18
+ /** Routing category for handler selection. */
19
+ category: DirectiveCategory;
20
+ /**
21
+ * If true, the directive's body content is wrapped in a <statement> element,
22
+ * and proof/solution siblings are extracted as siblings of the statement
23
+ * (not children of it). This matches PreTeXt semantics where theorems have:
24
+ * <theorem><title/><statement>...</statement><proof/></theorem>
25
+ *
26
+ * If false, content is added directly without statement wrapping.
27
+ */
28
+ requiresStatement: boolean;
29
+ /**
30
+ * If true, this directive can have nested task children.
31
+ * Content before the first task becomes an <introduction> wrapper.
32
+ * Example:
33
+ * <exercise><introduction>...</introduction><task>...</task><task>...</task></exercise>
34
+ *
35
+ * Only applies if nested tasks are actually present in the body.
36
+ * If no tasks are found, requiresStatement still applies.
37
+ */
38
+ hasNestedTasks?: boolean;
39
+ }
40
+ /**
41
+ * Backwards-compatible type for code that only needs type+category.
42
+ * @deprecated Use DirectiveSpec instead for new code.
43
+ */
44
+ export interface DirectiveInfo {
45
+ type: string;
46
+ category: DirectiveCategory;
47
+ }
48
+ /**
49
+ * Semantic specification table: directive name → spec.
50
+ *
51
+ * Pattern mirrors unified-latex-to-pretext's environment specification approach:
52
+ * Declarative table + factory functions apply rules uniformly.
53
+ * To add a new directive: just add an entry here.
54
+ */
55
+ export declare const DIRECTIVE_SPEC_TABLE: Readonly<Record<string, DirectiveSpec>>;
56
+ /**
57
+ * @deprecated Use DIRECTIVE_SPEC_TABLE directly or via getDirectiveSpec().
58
+ * Kept for backwards compatibility. Returns spec as old DirectiveInfo type.
59
+ */
60
+ export declare const DIRECTIVE_MAP: Readonly<Record<string, DirectiveInfo>>;
61
+ /** Get directive spec, or undefined if not found. */
62
+ export declare function getDirectiveSpec(name: string): DirectiveSpec | undefined;
63
+ /** Set of directive names that are proof/solution-like (used when separating statement siblings). */
64
+ export declare const PROOF_SOLUTION_NAMES: Set<string>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Directive Normalizer (Two-Pass Algorithm)
3
+ *
4
+ * Transforms user-friendly flexible colon syntax into standard remark-directive format.
5
+ *
6
+ * INPUT (flexible):
7
+ * :::exercise
8
+ * Intro
9
+ * :::task
10
+ * Content
11
+ * :::
12
+ * :::task
13
+ * More
14
+ * :::
15
+ * :::
16
+ *
17
+ * OUTPUT (normalized for remark-directive):
18
+ * ::::exercise
19
+ * Intro
20
+ * :::task
21
+ * Content
22
+ * :::
23
+ * :::task
24
+ * More
25
+ * :::
26
+ * ::::
27
+ *
28
+ * Algorithm (Two-Pass):
29
+ * - Pass 1: Parse markers, build nesting tree with parent references
30
+ * - Pass 2: Traverse tree bottom-up, compute final colon counts
31
+ * (each parent = max(children) + 1, ensuring proper nesting)
32
+ * - Pass 3: Re-emit with adjusted markers
33
+ */
34
+ /**
35
+ * Main normalization function
36
+ */
37
+ export declare function normalizeDirectiveColons(markdown: string): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Indentation-Based Directive Normalizer
3
+ *
4
+ * Transforms Python-like indentation-based directive syntax into colon syntax.
5
+ *
6
+ * INPUT (indentation-based):
7
+ * Theorem[Pythagorean]{#thm}:
8
+ * Statement text here.
9
+ *
10
+ * Proof:
11
+ * Proof content.
12
+ *
13
+ * Plain text (outdented).
14
+ *
15
+ * OUTPUT (colon-based):
16
+ * :::theorem[Pythagorean]{#thm}
17
+ * Statement text here.
18
+ *
19
+ * ::::proof
20
+ * Proof content.
21
+ * ::::
22
+ * :::
23
+ *
24
+ * Plain text (outdented).
25
+ *
26
+ * Algorithm:
27
+ * 1. Track fenced code blocks (``` and ~~~) and skip directive detection inside them
28
+ * 2. Parse each line to detect directive markers (Keyword[...]{...}:)
29
+ * 3. Track indentation stack: when indent increases, open a block; when decreases, close block(s)
30
+ * 4. Convert to colon syntax with proper nesting depth (validated against DIRECTIVE_SPEC_TABLE)
31
+ * 5. Preserve all non-directive content and indentation outside directives and code fences
32
+ */
33
+ /**
34
+ * Normalize indentation-based syntax to colon-based syntax
35
+ */
36
+ export declare function normalizeIndentationDirectives(markdown: string): string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Convert a markdown string (with PreTeXt directive extensions) to a PreTeXt
3
+ * XML string.
4
+ *
5
+ * The output contains the converted XML fragment — the children of the root
6
+ * node serialized as a string — suitable for embedding in a PreTeXt document.
7
+ *
8
+ * @param markdown - The markdown source to convert.
9
+ * @returns A PreTeXt XML string.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { markdownToPretext } from '@pretextbook/remark-pretext';
14
+ *
15
+ * const xml = markdownToPretext('# Hello\n\nThis is a paragraph.');
16
+ * // → '<section>\n <title>Hello</title>\n <p>This is a paragraph.</p>\n</section>'
17
+ * ```
18
+ */
19
+ export declare function markdownToPretext(markdown: string): string;
@@ -0,0 +1,31 @@
1
+ import { Plugin } from 'unified';
2
+ import { Root, Text } from 'mdast';
3
+ export interface Math {
4
+ type: 'math';
5
+ value: string;
6
+ meta?: string;
7
+ }
8
+ declare module 'mdast' {
9
+ interface PhrasingContentMap {
10
+ math: Math;
11
+ }
12
+ }
13
+ export interface MathTokenizationResult {
14
+ markdown: string;
15
+ tokens: Map<string, Math>;
16
+ }
17
+ export declare function tokenizeMathInMarkdown(markdown: string): MathTokenizationResult;
18
+ /**
19
+ * Find math in a string and split into text and math nodes.
20
+ * Returns array of alternating Text and Math nodes.
21
+ *
22
+ * Order matters: we check longer/more specific delimiters first.
23
+ */
24
+ export declare function splitTextWithMath(text: string): (Text | Math)[];
25
+ /**
26
+ * Remark plugin that detects and parses math delimiters in text nodes.
27
+ */
28
+ export declare function applyMathDelimiters(tree: Root): void;
29
+ export declare function applyMathTokens(tree: Root, tokens: Map<string, Math>): void;
30
+ declare const remarkMath: Plugin<[], Root>;
31
+ export default remarkMath;
@@ -0,0 +1,13 @@
1
+ import { Root as MdastRoot } from 'mdast';
2
+ import { Root } from 'xast';
3
+ import { ConversionMessage } from './context.js';
4
+ /** Result type for conversion: tree + diagnostic messages. */
5
+ export interface ConversionResult {
6
+ tree: Root;
7
+ messages: ConversionMessage[];
8
+ }
9
+ /** Transform an mdast Root node into an xast Root node (backwards compatible). */
10
+ export declare function mdastToPtxast(tree: MdastRoot, source?: string): Root;
11
+ export { mdastToPtxast as mdastToXast };
12
+ /** Transform an mdast Root node, returning tree + diagnostic messages. */
13
+ export declare function mdastToPtxastWithDiagnostics(tree: MdastRoot, source?: string): ConversionResult;
@@ -0,0 +1,11 @@
1
+ import { Plugin } from 'unified';
2
+ import { Root as MdastRoot } from 'mdast';
3
+ import { Root } from 'xast';
4
+ /** Options for the remark-pretext plugin (currently none, reserved for future use). */
5
+ export interface RemarkPretextOptions {
6
+ }
7
+ declare const remarkPretext: Plugin<[RemarkPretextOptions?], MdastRoot, Root>;
8
+ export default remarkPretext;
9
+ export { mdastToPtxast } from './mdast-to-ptxast.js';
10
+ export { DIRECTIVE_MAP, PROOF_SOLUTION_NAMES } from './directive-map.js';
11
+ export type { DirectiveInfo, DirectiveCategory } from './directive-map.js';
package/index.cjs CHANGED
@@ -1 +1 @@
1
- module.exports = require('../../dist/packages/remark-pretext/index.cjs');
1
+ module.exports = require('./dist/index.cjs');
package/index.d.ts CHANGED
@@ -1 +1 @@
1
- export * from '../../dist/packages/remark-pretext/index.d.ts';
1
+ export * from "./dist/index.d.ts";
package/index.js CHANGED
@@ -1 +1 @@
1
- export * from '../../dist/packages/remark-pretext/index.js';
1
+ export * from './dist/index.js';
package/package.json CHANGED
@@ -1,53 +1,54 @@
1
- {
2
- "name": "@pretextbook/remark-pretext",
3
- "version": "0.0.1",
4
- "description": "remark plugin to transform markdown-style PreTeXt directives into ptxast",
5
- "author": "Oscar Levin",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/pretextbook/pretext-tools.git"
10
- },
11
- "bugs": {
12
- "url": "https://github.com/pretextbook/pretext-tools/issues"
13
- },
14
- "homepage": "https://github.com/pretextbook/pretext-tools/packages/remark-pretext#readme",
15
- "private": false,
16
- "type": "module",
17
- "main": "./index.cjs",
18
- "module": "./index.js",
19
- "types": "./index.d.ts",
20
- "exports": {
21
- ".": {
22
- "types": "./index.d.ts",
23
- "import": "./index.js",
24
- "require": "./index.cjs",
25
- "default": "./index.js"
26
- }
27
- },
28
- "sideEffects": false,
29
- "files": [
30
- "*.js",
31
- "*.cjs",
32
- "*.d.ts",
33
- "*.d.cts",
34
- "lib",
35
- "types"
36
- ],
37
- "scripts": {
38
- "build": "vite build",
39
- "test": "vitest run"
40
- },
41
- "dependencies": {
42
- "@pretextbook/ptxast": "^0.0.1",
43
- "@types/mdast": "^4.0.0",
44
- "mdast-util-directive": "^3.0.0",
45
- "remark-directive": "^4.0.0",
46
- "remark-parse": "^11.0.0",
47
- "unified": "^11.0.0",
48
- "unist-util-visit": "^5.0.0"
49
- },
50
- "publishConfig": {
51
- "access": "public"
52
- }
53
- }
1
+ {
2
+ "name": "@pretextbook/remark-pretext",
3
+ "version": "0.0.3",
4
+ "description": "remark plugin to transform markdown-style PreTeXt directives into ptxast",
5
+ "author": "Oscar Levin",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/PreTeXtBook/pretext-tools.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/PreTeXtBook/pretext-tools/issues"
13
+ },
14
+ "homepage": "https://github.com/PreTeXtBook/pretext-tools/packages/remark-pretext#readme",
15
+ "private": false,
16
+ "type": "module",
17
+ "main": "./index.cjs",
18
+ "module": "./index.js",
19
+ "types": "./index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./index.d.ts",
23
+ "import": "./index.js",
24
+ "require": "./index.cjs",
25
+ "default": "./index.js"
26
+ }
27
+ },
28
+ "sideEffects": false,
29
+ "files": [
30
+ "*.js",
31
+ "*.cjs",
32
+ "*.d.ts",
33
+ "*.d.cts",
34
+ "dist",
35
+ "types"
36
+ ],
37
+ "scripts": {
38
+ "build": "vite build",
39
+ "test": "vitest run"
40
+ },
41
+ "dependencies": {
42
+ "@pretextbook/ptxast": "^0.0.3",
43
+ "@types/mdast": "^4.0.0",
44
+ "mdast-util-directive": "^3.0.0",
45
+ "remark-directive": "^4.0.0",
46
+ "remark-parse": "^11.0.0",
47
+ "unified": "^11.0.0",
48
+ "unist-util-visit": "^5.0.0",
49
+ "xast-util-to-xml": "^4.0.0"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ }
54
+ }