@pyreon/document-primitives 0.24.5 → 0.25.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/lib/index.d.ts +7 -7
- package/package.json +18 -20
- package/src/DocumentPreview.ts +0 -48
- package/src/__tests__/document-primitives.browser.test.ts +0 -253
- package/src/__tests__/manifest-snapshot.test.ts +0 -45
- package/src/__tests__/primitives-attrs.test.ts +0 -517
- package/src/__tests__/primitives.test.ts +0 -104
- package/src/__tests__/reactivity.test.ts +0 -415
- package/src/__tests__/useDocumentExport.test.ts +0 -366
- package/src/index.ts +0 -37
- package/src/manifest.ts +0 -388
- package/src/primitives/DocButton.ts +0 -37
- package/src/primitives/DocCode.ts +0 -18
- package/src/primitives/DocColumn.ts +0 -11
- package/src/primitives/DocDivider.ts +0 -21
- package/src/primitives/DocDocument.ts +0 -69
- package/src/primitives/DocHeading.ts +0 -33
- package/src/primitives/DocImage.ts +0 -23
- package/src/primitives/DocLink.ts +0 -15
- package/src/primitives/DocList.ts +0 -15
- package/src/primitives/DocListItem.ts +0 -15
- package/src/primitives/DocPage.ts +0 -21
- package/src/primitives/DocPageBreak.ts +0 -11
- package/src/primitives/DocQuote.ts +0 -17
- package/src/primitives/DocRow.ts +0 -19
- package/src/primitives/DocSection.ts +0 -23
- package/src/primitives/DocSpacer.ts +0 -11
- package/src/primitives/DocTable.ts +0 -57
- package/src/primitives/DocText.ts +0 -31
- package/src/theme.ts +0 -37
- package/src/useDocumentExport.ts +0 -84
package/lib/index.d.ts
CHANGED
|
@@ -77,10 +77,10 @@ declare const DocButton: import("@pyreon/rocketstyle").RocketStyleComponent<Part
|
|
|
77
77
|
}> & import("@pyreon/core").PyreonHTMLAttributes<HTMLElement>, {
|
|
78
78
|
href?: string;
|
|
79
79
|
}, {}, {
|
|
80
|
+
padding: string;
|
|
80
81
|
borderRadius: number;
|
|
81
82
|
fontSize: number;
|
|
82
83
|
fontWeight: string;
|
|
83
|
-
padding: string;
|
|
84
84
|
textAlign: string;
|
|
85
85
|
textDecoration: string;
|
|
86
86
|
}, {
|
|
@@ -114,10 +114,10 @@ declare const DocCode: import("@pyreon/rocketstyle").RocketStyleComponent<Partia
|
|
|
114
114
|
language?: string;
|
|
115
115
|
}, {}, {
|
|
116
116
|
backgroundColor: string;
|
|
117
|
+
padding: string;
|
|
117
118
|
borderRadius: number;
|
|
118
119
|
fontFamily: string;
|
|
119
120
|
fontSize: number;
|
|
120
|
-
padding: string;
|
|
121
121
|
}, {
|
|
122
122
|
_documentType: "code";
|
|
123
123
|
}, {}, {
|
|
@@ -419,9 +419,9 @@ declare const DocImage: import("@pyreon/rocketstyle").RocketStyleComponent<Parti
|
|
|
419
419
|
beforeContentCss: import("@pyreon/elements").ExtendCss;
|
|
420
420
|
afterContentCss: import("@pyreon/elements").ExtendCss;
|
|
421
421
|
}> & import("@pyreon/core").PyreonHTMLAttributes<HTMLElement>, {
|
|
422
|
-
height?: number | string;
|
|
423
|
-
width?: number | string;
|
|
424
422
|
caption?: string;
|
|
423
|
+
width?: number | string;
|
|
424
|
+
height?: number | string;
|
|
425
425
|
src?: string;
|
|
426
426
|
alt?: string;
|
|
427
427
|
}, {}, {}, {
|
|
@@ -698,8 +698,8 @@ declare const DocQuote: import("@pyreon/rocketstyle").RocketStyleComponent<Parti
|
|
|
698
698
|
}, {}, {
|
|
699
699
|
borderColor: string;
|
|
700
700
|
color: string;
|
|
701
|
-
fontStyle: string;
|
|
702
701
|
padding: string;
|
|
702
|
+
fontStyle: string;
|
|
703
703
|
}, {
|
|
704
704
|
_documentType: "quote";
|
|
705
705
|
}, {}, {
|
|
@@ -757,8 +757,8 @@ declare const DocRow: import("@pyreon/rocketstyle").RocketStyleComponent<Partial
|
|
|
757
757
|
afterContentCss: import("@pyreon/elements").ExtendCss;
|
|
758
758
|
}> & import("@pyreon/core").PyreonHTMLAttributes<HTMLElement>, {
|
|
759
759
|
tag: string;
|
|
760
|
-
direction: "inline";
|
|
761
760
|
gap: number;
|
|
761
|
+
direction: "inline";
|
|
762
762
|
_documentProps: {};
|
|
763
763
|
}, {}, {}, {
|
|
764
764
|
_documentType: "row";
|
|
@@ -928,9 +928,9 @@ declare const DocTable: import("@pyreon/rocketstyle").RocketStyleComponent<Parti
|
|
|
928
928
|
beforeContentCss: import("@pyreon/elements").ExtendCss;
|
|
929
929
|
afterContentCss: import("@pyreon/elements").ExtendCss;
|
|
930
930
|
}> & import("@pyreon/core").PyreonHTMLAttributes<HTMLElement>, {
|
|
931
|
-
columns?: unknown[];
|
|
932
931
|
caption?: string;
|
|
933
932
|
rows?: unknown[];
|
|
933
|
+
columns?: unknown[];
|
|
934
934
|
headerStyle?: Record<string, unknown>;
|
|
935
935
|
striped?: boolean;
|
|
936
936
|
bordered?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/document-primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Rocketstyle document components — render in browser, export to 18 formats",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
"!lib/**/*.map",
|
|
14
14
|
"!lib/analysis",
|
|
15
15
|
"README.md",
|
|
16
|
-
"LICENSE"
|
|
17
|
-
"src"
|
|
16
|
+
"LICENSE"
|
|
18
17
|
],
|
|
19
18
|
"type": "module",
|
|
20
19
|
"sideEffects": false,
|
|
@@ -22,7 +21,6 @@
|
|
|
22
21
|
"types": "./lib/index.d.ts",
|
|
23
22
|
"exports": {
|
|
24
23
|
".": {
|
|
25
|
-
"bun": "./src/index.ts",
|
|
26
24
|
"import": "./lib/index.js",
|
|
27
25
|
"types": "./lib/index.d.ts"
|
|
28
26
|
}
|
|
@@ -42,25 +40,25 @@
|
|
|
42
40
|
"typecheck": "tsc --noEmit"
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
|
-
"@pyreon/connector-document": "^0.
|
|
46
|
-
"@pyreon/core": "^0.
|
|
47
|
-
"@pyreon/document": "^0.
|
|
48
|
-
"@pyreon/elements": "^0.
|
|
49
|
-
"@pyreon/rocketstyle": "^0.
|
|
50
|
-
"@pyreon/styler": "^0.
|
|
51
|
-
"@pyreon/ui-core": "^0.
|
|
43
|
+
"@pyreon/connector-document": "^0.25.0",
|
|
44
|
+
"@pyreon/core": "^0.25.0",
|
|
45
|
+
"@pyreon/document": "^0.25.0",
|
|
46
|
+
"@pyreon/elements": "^0.25.0",
|
|
47
|
+
"@pyreon/rocketstyle": "^0.25.0",
|
|
48
|
+
"@pyreon/styler": "^0.25.0",
|
|
49
|
+
"@pyreon/ui-core": "^0.25.0"
|
|
52
50
|
},
|
|
53
51
|
"devDependencies": {
|
|
54
|
-
"@pyreon/core": "^0.
|
|
55
|
-
"@pyreon/elements": "^0.
|
|
52
|
+
"@pyreon/core": "^0.25.0",
|
|
53
|
+
"@pyreon/elements": "^0.25.0",
|
|
56
54
|
"@pyreon/manifest": "0.13.1",
|
|
57
|
-
"@pyreon/reactivity": "^0.
|
|
58
|
-
"@pyreon/rocketstyle": "^0.
|
|
59
|
-
"@pyreon/runtime-dom": "^0.
|
|
60
|
-
"@pyreon/styler": "^0.
|
|
61
|
-
"@pyreon/test-utils": "^0.13.
|
|
62
|
-
"@pyreon/typescript": "^0.
|
|
63
|
-
"@pyreon/ui-core": "^0.
|
|
55
|
+
"@pyreon/reactivity": "^0.25.0",
|
|
56
|
+
"@pyreon/rocketstyle": "^0.25.0",
|
|
57
|
+
"@pyreon/runtime-dom": "^0.25.0",
|
|
58
|
+
"@pyreon/styler": "^0.25.0",
|
|
59
|
+
"@pyreon/test-utils": "^0.13.12",
|
|
60
|
+
"@pyreon/typescript": "^0.25.0",
|
|
61
|
+
"@pyreon/ui-core": "^0.25.0",
|
|
64
62
|
"@vitest/browser-playwright": "^4.1.4",
|
|
65
63
|
"@vitus-labs/tools-rolldown": "^2.4.0"
|
|
66
64
|
},
|
package/src/DocumentPreview.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Element } from '@pyreon/elements'
|
|
2
|
-
import rocketstyle from '@pyreon/rocketstyle'
|
|
3
|
-
|
|
4
|
-
const DocumentPreview = rocketstyle({
|
|
5
|
-
dimensions: {
|
|
6
|
-
sizes: 'size',
|
|
7
|
-
},
|
|
8
|
-
useBooleans: true,
|
|
9
|
-
})({ name: 'DocumentPreview', component: Element })
|
|
10
|
-
.theme({
|
|
11
|
-
backgroundColor: '#f5f5f5',
|
|
12
|
-
padding: 40,
|
|
13
|
-
})
|
|
14
|
-
.sizes({
|
|
15
|
-
A4: { width: '210mm', minHeight: '297mm' },
|
|
16
|
-
A3: { width: '297mm', minHeight: '420mm' },
|
|
17
|
-
A5: { width: '148mm', minHeight: '210mm' },
|
|
18
|
-
letter: { width: '8.5in', minHeight: '11in' },
|
|
19
|
-
legal: { width: '8.5in', minHeight: '14in' },
|
|
20
|
-
})
|
|
21
|
-
.styles(
|
|
22
|
-
(css: any) => css`
|
|
23
|
-
display: flex;
|
|
24
|
-
flex-direction: column;
|
|
25
|
-
align-items: center;
|
|
26
|
-
min-height: 100vh;
|
|
27
|
-
|
|
28
|
-
& > * {
|
|
29
|
-
background: white;
|
|
30
|
-
padding: 25mm;
|
|
31
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
32
|
-
margin: 20px 0;
|
|
33
|
-
}
|
|
34
|
-
`,
|
|
35
|
-
)
|
|
36
|
-
.statics({ _documentType: 'document' as const })
|
|
37
|
-
.attrs<{
|
|
38
|
-
size?: string
|
|
39
|
-
showPageBreaks?: boolean
|
|
40
|
-
}>((props) => ({
|
|
41
|
-
tag: 'div',
|
|
42
|
-
_documentProps: {
|
|
43
|
-
...(props.size ? { size: props.size } : { size: 'A4' }),
|
|
44
|
-
...(props.showPageBreaks ? { showPageBreaks: props.showPageBreaks } : {}),
|
|
45
|
-
},
|
|
46
|
-
}))
|
|
47
|
-
|
|
48
|
-
export default DocumentPreview
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { h } from '@pyreon/core'
|
|
2
|
-
import { extractDocumentTree } from '@pyreon/connector-document'
|
|
3
|
-
import { signal } from '@pyreon/reactivity'
|
|
4
|
-
import { mountInBrowser } from '@pyreon/test-utils/browser'
|
|
5
|
-
import { afterEach, describe, expect, it } from 'vitest'
|
|
6
|
-
import DocCode from '../primitives/DocCode'
|
|
7
|
-
import DocDocument from '../primitives/DocDocument'
|
|
8
|
-
import DocHeading from '../primitives/DocHeading'
|
|
9
|
-
import DocImage from '../primitives/DocImage'
|
|
10
|
-
import DocLink from '../primitives/DocLink'
|
|
11
|
-
import DocList from '../primitives/DocList'
|
|
12
|
-
import DocListItem from '../primitives/DocListItem'
|
|
13
|
-
import DocSection from '../primitives/DocSection'
|
|
14
|
-
import DocTable from '../primitives/DocTable'
|
|
15
|
-
import DocText from '../primitives/DocText'
|
|
16
|
-
|
|
17
|
-
// Real-browser smoke suite for @pyreon/document-primitives.
|
|
18
|
-
//
|
|
19
|
-
// The contract under test here is the one PR #197 fixed: when you pass a real
|
|
20
|
-
// rocketstyle-wrapped primitive (not a hand-constructed mock vnode) through
|
|
21
|
-
// `extractDocumentTree`, the extractor must invoke the component to reach the
|
|
22
|
-
// post-attrs vnode where `_documentProps` actually lives. Before PR #197,
|
|
23
|
-
// every real primitive silently dropped its metadata during export.
|
|
24
|
-
//
|
|
25
|
-
// The existing unit tests in `connector-document/src/__tests__/` use a
|
|
26
|
-
// hand-constructed `DocDocLike` function. This suite closes the gap by
|
|
27
|
-
// using the ACTUAL `DocDocument` primitive with real rocketstyle runtime,
|
|
28
|
-
// in a real browser.
|
|
29
|
-
|
|
30
|
-
describe('document-primitives in real browser', () => {
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
// Each test cleans up its own mount; extract-only tests have nothing to do.
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('extracts title + author from a real DocDocument vnode (PR #197 regression)', () => {
|
|
36
|
-
const vnode = h(DocDocument, { title: 'Resume', author: 'Alice' })
|
|
37
|
-
const tree = extractDocumentTree(vnode)
|
|
38
|
-
|
|
39
|
-
expect(tree.type).toBe('document')
|
|
40
|
-
expect(tree.props.title).toBe('Resume')
|
|
41
|
-
expect(tree.props.author).toBe('Alice')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('resolves reactive accessor props at extraction time (live signal reads)', () => {
|
|
45
|
-
const name = signal('Alice')
|
|
46
|
-
const vnode = h(DocDocument, {
|
|
47
|
-
title: () => `${name()} — Resume`,
|
|
48
|
-
author: () => name(),
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const first = extractDocumentTree(vnode)
|
|
52
|
-
expect(first.props.title).toBe('Alice — Resume')
|
|
53
|
-
expect(first.props.author).toBe('Alice')
|
|
54
|
-
|
|
55
|
-
name.set('Bob')
|
|
56
|
-
const second = extractDocumentTree(vnode)
|
|
57
|
-
expect(second.props.title).toBe('Bob — Resume')
|
|
58
|
-
expect(second.props.author).toBe('Bob')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('renders a nested DocDocument tree to real DOM and extracts the same tree', () => {
|
|
62
|
-
const vnode = h(
|
|
63
|
-
DocDocument,
|
|
64
|
-
{ title: 'Report' },
|
|
65
|
-
h(DocHeading, { level: 'h1' }, 'Q1 Results'),
|
|
66
|
-
h(DocText, null, 'Revenue grew 12%.'),
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
const { container, unmount } = mountInBrowser(vnode)
|
|
70
|
-
// Real browser renders the rocketstyle-wrapped elements.
|
|
71
|
-
expect(container.textContent).toContain('Q1 Results')
|
|
72
|
-
expect(container.textContent).toContain('Revenue grew 12%.')
|
|
73
|
-
|
|
74
|
-
// Same vnode drives the export path.
|
|
75
|
-
const tree = extractDocumentTree(vnode)
|
|
76
|
-
expect(tree.type).toBe('document')
|
|
77
|
-
expect(tree.props.title).toBe('Report')
|
|
78
|
-
expect(tree.children.length).toBeGreaterThanOrEqual(2)
|
|
79
|
-
const nodeChildren = tree.children.filter(
|
|
80
|
-
(c): c is Exclude<typeof c, string> => typeof c !== 'string',
|
|
81
|
-
)
|
|
82
|
-
expect(nodeChildren.some((c) => c.type === 'heading')).toBe(true)
|
|
83
|
-
expect(nodeChildren.some((c) => c.type === 'text')).toBe(true)
|
|
84
|
-
|
|
85
|
-
unmount()
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('extracts heading level from real DocHeading primitive', () => {
|
|
89
|
-
const tree = extractDocumentTree(
|
|
90
|
-
h(DocDocument, { title: 't' }, h(DocHeading, { level: 'h2' }, 'Section')),
|
|
91
|
-
)
|
|
92
|
-
const heading = (tree.children.find((c) => typeof c !== 'string' && c.type === 'heading') ??
|
|
93
|
-
null) as { type: string; props: { level?: number } } | null
|
|
94
|
-
expect(heading).not.toBeNull()
|
|
95
|
-
// DocHeading converts the 'h2' level prop into a numeric `level: 2`.
|
|
96
|
-
expect(heading?.props.level).toBe(2)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('extracts href from real DocLink primitive', () => {
|
|
100
|
-
const tree = extractDocumentTree(
|
|
101
|
-
h(
|
|
102
|
-
DocDocument,
|
|
103
|
-
{ title: 't' },
|
|
104
|
-
h(DocLink, { href: 'https://example.com' }, 'click me'),
|
|
105
|
-
),
|
|
106
|
-
)
|
|
107
|
-
const link = (tree.children.find((c) => typeof c !== 'string' && c.type === 'link') ??
|
|
108
|
-
null) as { type: string; props: { href?: string } } | null
|
|
109
|
-
expect(link).not.toBeNull()
|
|
110
|
-
expect(link?.props.href).toBe('https://example.com')
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('extracts ordered flag from real DocList primitive', () => {
|
|
114
|
-
const tree = extractDocumentTree(
|
|
115
|
-
h(
|
|
116
|
-
DocDocument,
|
|
117
|
-
{ title: 't' },
|
|
118
|
-
h(
|
|
119
|
-
DocList,
|
|
120
|
-
{ ordered: true },
|
|
121
|
-
h(DocListItem, null, 'one'),
|
|
122
|
-
h(DocListItem, null, 'two'),
|
|
123
|
-
),
|
|
124
|
-
),
|
|
125
|
-
)
|
|
126
|
-
const list = (tree.children.find((c) => typeof c !== 'string' && c.type === 'list') ??
|
|
127
|
-
null) as { type: string; props: { ordered?: boolean }; children: unknown[] } | null
|
|
128
|
-
expect(list).not.toBeNull()
|
|
129
|
-
expect(list?.props.ordered).toBe(true)
|
|
130
|
-
expect(list?.children.length).toBe(2)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('extracts language from real DocCode primitive', () => {
|
|
134
|
-
const tree = extractDocumentTree(
|
|
135
|
-
h(
|
|
136
|
-
DocDocument,
|
|
137
|
-
{ title: 't' },
|
|
138
|
-
h(DocCode, { language: 'typescript' }, 'const x = 1'),
|
|
139
|
-
),
|
|
140
|
-
)
|
|
141
|
-
const code = (tree.children.find((c) => typeof c !== 'string' && c.type === 'code') ??
|
|
142
|
-
null) as { type: string; props: { language?: string } } | null
|
|
143
|
-
expect(code).not.toBeNull()
|
|
144
|
-
expect(code?.props.language).toBe('typescript')
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
it('extracts src + alt from real DocImage primitive (no DOM forwarding crash)', () => {
|
|
148
|
-
// Image element has read-only `naturalWidth`/`naturalHeight` properties —
|
|
149
|
-
// a clean test that DocImage doesn't try to set them via property assignment.
|
|
150
|
-
const tree = extractDocumentTree(
|
|
151
|
-
h(
|
|
152
|
-
DocDocument,
|
|
153
|
-
{ title: 't' },
|
|
154
|
-
h(DocImage, { src: 'https://example.com/x.png', alt: 'logo' }),
|
|
155
|
-
),
|
|
156
|
-
)
|
|
157
|
-
const img = (tree.children.find((c) => typeof c !== 'string' && c.type === 'image') ??
|
|
158
|
-
null) as { type: string; props: { src?: string; alt?: string } } | null
|
|
159
|
-
expect(img).not.toBeNull()
|
|
160
|
-
expect(img?.props.src).toBe('https://example.com/x.png')
|
|
161
|
-
expect(img?.props.alt).toBe('logo')
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
it('extracts table rows + columns without read-only-property crash', () => {
|
|
165
|
-
// DocTable uses `.attrs(callback, { filter: ['rows', 'columns', ...] })`
|
|
166
|
-
// to strip export-only props before they reach the DOM, because
|
|
167
|
-
// HTMLTableElement.rows is a read-only HTMLCollection getter — assigning
|
|
168
|
-
// to it would crash. This test exercises that filter path.
|
|
169
|
-
const tree = extractDocumentTree(
|
|
170
|
-
h(
|
|
171
|
-
DocDocument,
|
|
172
|
-
{ title: 't' },
|
|
173
|
-
h(DocTable, {
|
|
174
|
-
rows: [
|
|
175
|
-
['a1', 'b1'],
|
|
176
|
-
['a2', 'b2'],
|
|
177
|
-
],
|
|
178
|
-
columns: ['col-a', 'col-b'],
|
|
179
|
-
}),
|
|
180
|
-
),
|
|
181
|
-
)
|
|
182
|
-
const table = (tree.children.find((c) => typeof c !== 'string' && c.type === 'table') ??
|
|
183
|
-
null) as
|
|
184
|
-
| {
|
|
185
|
-
type: string
|
|
186
|
-
props: {
|
|
187
|
-
rows?: unknown[]
|
|
188
|
-
columns?: unknown[]
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
| null
|
|
192
|
-
expect(table).not.toBeNull()
|
|
193
|
-
expect(Array.isArray(table?.props.rows)).toBe(true)
|
|
194
|
-
expect(table?.props.rows).toHaveLength(2)
|
|
195
|
-
expect(table?.props.columns).toEqual(['col-a', 'col-b'])
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it('extracts deeply nested tree (DocSection wrapping multiple primitives)', () => {
|
|
199
|
-
const tree = extractDocumentTree(
|
|
200
|
-
h(
|
|
201
|
-
DocDocument,
|
|
202
|
-
{ title: 'Report' },
|
|
203
|
-
h(
|
|
204
|
-
DocSection,
|
|
205
|
-
null,
|
|
206
|
-
h(DocHeading, { level: 'h1' }, 'Intro'),
|
|
207
|
-
h(DocText, null, 'paragraph'),
|
|
208
|
-
h(DocSection, null, h(DocText, null, 'nested-paragraph')),
|
|
209
|
-
),
|
|
210
|
-
),
|
|
211
|
-
)
|
|
212
|
-
expect(tree.type).toBe('document')
|
|
213
|
-
|
|
214
|
-
// The traversal into nested sections should preserve depth.
|
|
215
|
-
const findByType = (node: unknown, type: string): unknown => {
|
|
216
|
-
if (typeof node !== 'object' || !node) return null
|
|
217
|
-
const n = node as { type?: string; children?: unknown[] }
|
|
218
|
-
if (n.type === type) return n
|
|
219
|
-
for (const c of n.children ?? []) {
|
|
220
|
-
const found = findByType(c, type)
|
|
221
|
-
if (found) return found
|
|
222
|
-
}
|
|
223
|
-
return null
|
|
224
|
-
}
|
|
225
|
-
const heading = findByType(tree, 'heading')
|
|
226
|
-
expect(heading).not.toBeNull()
|
|
227
|
-
// 'nested-paragraph' should appear as a text node anywhere in the tree.
|
|
228
|
-
const treeStr = JSON.stringify(tree)
|
|
229
|
-
expect(treeStr).toContain('nested-paragraph')
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('handles primitives that have NO _documentProps cleanly (DocText)', () => {
|
|
233
|
-
// DocText has `_documentProps: {}` — empty object. Confirms the
|
|
234
|
-
// extractor doesn't choke on absent metadata.
|
|
235
|
-
const tree = extractDocumentTree(
|
|
236
|
-
h(DocDocument, { title: 't' }, h(DocText, null, 'just text')),
|
|
237
|
-
)
|
|
238
|
-
const text = (tree.children.find((c) => typeof c !== 'string' && c.type === 'text') ??
|
|
239
|
-
null) as { type: string; children?: unknown[] } | null
|
|
240
|
-
expect(text).not.toBeNull()
|
|
241
|
-
expect(JSON.stringify(text)).toContain('just text')
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
it('handles undefined / nullish optional metadata (omits, does not emit `key: undefined`)', () => {
|
|
245
|
-
// DocDocument explicitly only sets keys when non-null. Verify by
|
|
246
|
-
// omitting all optional props.
|
|
247
|
-
const tree = extractDocumentTree(h(DocDocument, {}))
|
|
248
|
-
expect(tree.type).toBe('document')
|
|
249
|
-
expect(tree.props).not.toHaveProperty('title')
|
|
250
|
-
expect(tree.props).not.toHaveProperty('author')
|
|
251
|
-
expect(tree.props).not.toHaveProperty('subject')
|
|
252
|
-
})
|
|
253
|
-
})
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
renderApiReferenceEntries,
|
|
3
|
-
renderLlmsFullSection,
|
|
4
|
-
renderLlmsTxtLine,
|
|
5
|
-
} from '@pyreon/manifest'
|
|
6
|
-
import manifest from '../manifest'
|
|
7
|
-
|
|
8
|
-
describe('gen-docs — document-primitives snapshot', () => {
|
|
9
|
-
it('renders a llms.txt bullet starting with the package prefix', () => {
|
|
10
|
-
const line = renderLlmsTxtLine(manifest)
|
|
11
|
-
expect(line.startsWith('- @pyreon/document-primitives —')).toBe(true)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('renders a llms-full.txt section with the right header', () => {
|
|
15
|
-
const section = renderLlmsFullSection(manifest)
|
|
16
|
-
expect(section.startsWith('## @pyreon/document-primitives —')).toBe(true)
|
|
17
|
-
expect(section).toContain('```typescript')
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('renders MCP api-reference entries for every api[] item', () => {
|
|
21
|
-
const record = renderApiReferenceEntries(manifest)
|
|
22
|
-
expect(Object.keys(record).sort()).toEqual([
|
|
23
|
-
'document-primitives/DocButton',
|
|
24
|
-
'document-primitives/DocCode',
|
|
25
|
-
'document-primitives/DocColumn',
|
|
26
|
-
'document-primitives/DocDivider',
|
|
27
|
-
'document-primitives/DocDocument',
|
|
28
|
-
'document-primitives/DocHeading',
|
|
29
|
-
'document-primitives/DocImage',
|
|
30
|
-
'document-primitives/DocLink',
|
|
31
|
-
'document-primitives/DocList',
|
|
32
|
-
'document-primitives/DocListItem',
|
|
33
|
-
'document-primitives/DocPage',
|
|
34
|
-
'document-primitives/DocPageBreak',
|
|
35
|
-
'document-primitives/DocQuote',
|
|
36
|
-
'document-primitives/DocRow',
|
|
37
|
-
'document-primitives/DocSection',
|
|
38
|
-
'document-primitives/DocSpacer',
|
|
39
|
-
'document-primitives/DocTable',
|
|
40
|
-
'document-primitives/DocText',
|
|
41
|
-
'document-primitives/createDocumentExport',
|
|
42
|
-
'document-primitives/extractDocNode',
|
|
43
|
-
])
|
|
44
|
-
})
|
|
45
|
-
})
|