tsprose 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Gwynerva
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ <img src="./.github/assets/banner.svg" alt="TSProse banner">
2
+
3
+ <p></p>
4
+
5
+ # TSProse
6
+
7
+ Write and structure prose content using TypeScript TSX with strong typing.
8
+
9
+ - Write prose using **TSX** syntax
10
+ - Define **your own** element schemas and tags
11
+ - Link any elements with **"uniques"** system (e.g. for cross-referencing)
12
+ - Convert raw TSX output into a stable, linkable prose tree
13
+ - **Storage** system for attaching async/heavy/reusable data to elements
14
+
15
+ TSProse is a **parser + structurer**: you write content in TSX, TSProse turns it into a typed element tree. Rendering, styling, and analysis are up to you.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install tsprose
21
+ ```
22
+
23
+ Configure your `tsconfig.json` to use TSProse as the JSX runtime:
24
+
25
+ ```jsonc
26
+ {
27
+ "compilerOptions": {
28
+ "jsx": "react-jsx",
29
+ "jsxImportSource": "tsprose",
30
+ },
31
+ }
32
+ ```
33
+
34
+ ## Core idea
35
+
36
+ The idea is simple — you define schemas and tags, use tags to write raw prose in TSX, convert raw prose to prose with stable IDs and collected uniques, then do whatever you want with the prose tree (render, analyze, serialize, etc):
37
+
38
+ 1. **Schema** — Describes an element’s shape and rules (block vs inliner, linkable or not, typed data/children).
39
+ 2. **Tag (TSX)** — The callable you use in TSX files; it creates/configures **raw elements** according to the schema.
40
+ 3. **RawElement** — The initial, unprocessed elements produced by evaluating your TSX.
41
+ 4. **ProseElement** (via **`rawToProse`** function) — raw elements are transformed into prose elements via `rawToProse()` which assigns stable IDs to linkable elements and collects uniques.
42
+ 5. (optional) **Storage** — Attach async/heavy/reusable data to elements (e.g. computed metadata) when needed.
43
+ 6. **Use the prose tree** — Render, analyze, serialize, etc.
44
+
45
+ ## Get started (minimal example)
46
+
47
+ This example defines two elements:
48
+
49
+ - `paragraph` (block, linkable, optional data)
50
+ - `bold` (inliner, non-linkable)
51
+
52
+ ```ts
53
+ import {
54
+ defineSchema,
55
+ defineTag,
56
+ defineDocument,
57
+ rawToProse,
58
+ ensureTagInlinerChildren,
59
+ ensureTagChildren,
60
+ type BlockSchema,
61
+ type InlinerSchema,
62
+ type TextSchema,
63
+ } from 'tsprose';
64
+
65
+ //
66
+ // 1. Schemas
67
+ //
68
+
69
+ interface ParagraphSchema extends BlockSchema {
70
+ name: 'paragraph';
71
+ type: 'block';
72
+ linkable: true;
73
+ Data: { center?: boolean } | undefined;
74
+ Storage: undefined;
75
+ Children: InlinerSchema[];
76
+ }
77
+
78
+ const paragraphSchema = defineSchema<ParagraphSchema>({
79
+ name: 'paragraph',
80
+ type: 'block',
81
+ linkable: true,
82
+ });
83
+
84
+ interface BoldSchema extends InlinerSchema {
85
+ name: 'bold';
86
+ type: 'inliner';
87
+ linkable: false;
88
+ Data: undefined;
89
+ Storage: undefined;
90
+ Children: TextSchema[];
91
+ }
92
+
93
+ const boldSchema = defineSchema<BoldSchema>({
94
+ name: 'bold',
95
+ type: 'inliner',
96
+ linkable: false,
97
+ });
98
+
99
+ //
100
+ // 2. Tags
101
+ //
102
+
103
+ const P = defineTag({ tagName: 'P', schema: paragraphSchema })<{ center?: true }>(
104
+ ({ tagName, props, children, element }) => {
105
+ ensureTagInlinerChildren(tagName, children);
106
+ element.children = children;
107
+
108
+ if (props.center) {
109
+ element.data = { center: true };
110
+ }
111
+ },
112
+ );
113
+
114
+ const B = defineTag({ tagName: 'B', schema: boldSchema })(({ tagName, children, element }) => {
115
+ // `text` is built-in; strings become text elements automatically.
116
+ ensureTagInlinerChildren(tagName, children);
117
+ element.children = children;
118
+ });
119
+
120
+ //
121
+ // 3. Document (TSX)
122
+ //
123
+
124
+ const document = defineDocument('my-document-id', {
125
+ uniques: { intro: P },
126
+ })(({ uniques }) => (
127
+ <>
128
+ <P $={uniques.intro} center>
129
+ Hello <B>world</B>
130
+ </P>
131
+ </>
132
+ ));
133
+
134
+ //
135
+ // 4. Convert to prose (stable IDs + collected uniques)
136
+ //
137
+
138
+ const { prose, uniques } = await rawToProse({ rawProse: document.rawProse });
139
+
140
+ console.log(prose.schema.name); // "mix" (fragment)
141
+ console.log(uniques.intro.id); // "intro"
142
+ ```
143
+
144
+ ## Next steps
145
+
146
+ - Walk the tree (`walkPre*` / `walkPost*`) to render/analyze
147
+ - Serialize (`toJSON` / `fromJSON`) if you need persistence
148
+ - Attach async data via storage (`fillProseStorage`) when you need it
149
+
150
+ ## License
151
+
152
+ [MIT](./LICENSE)
@@ -0,0 +1,3 @@
1
+ import type { RawElement } from './element.js';
2
+ export type NormalizedChildren = RawElement[] | undefined;
3
+ export declare function normalizeChildren(children: any, childStep?: (child: RawElement) => void): NormalizedChildren;
@@ -0,0 +1,86 @@
1
+ import { mixSchema } from './default/mix.js';
2
+ import { textSchema } from './default/text.js';
3
+ import { isRawElement, makeRawElement } from './elementUtils.js';
4
+ import { isUnique } from './unique.js';
5
+ import { hash } from './utils/hash.js';
6
+ export function normalizeChildren(children, childStep) {
7
+ if (children === undefined) {
8
+ return undefined;
9
+ }
10
+ const childrenArray = Array.isArray(children) ? children : [children];
11
+ if (childrenArray.length === 0) {
12
+ return undefined;
13
+ }
14
+ const normalizedChildren = [];
15
+ for (const child of childrenArray) {
16
+ //
17
+ // <Mix>
18
+ //
19
+ if (isRawElement(child, mixSchema)) {
20
+ const subNormalized = normalizeChildren(child.children, childStep);
21
+ if (subNormalized) {
22
+ normalizedChildren.push(...subNormalized);
23
+ }
24
+ continue;
25
+ }
26
+ //
27
+ // Raw Element
28
+ //
29
+ if (isRawElement(child)) {
30
+ const clone = structuredClone(child);
31
+ childStep?.(clone);
32
+ normalizedChildren.push(clone);
33
+ continue;
34
+ }
35
+ //
36
+ // Unique
37
+ //
38
+ if (isUnique(child)) {
39
+ const clone = structuredClone(child.rawElement);
40
+ clone.slug = clone.uniqueName;
41
+ delete clone.uniqueName;
42
+ childStep?.(clone);
43
+ normalizedChildren.push(clone);
44
+ continue;
45
+ }
46
+ //
47
+ // Array
48
+ //
49
+ if (Array.isArray(child)) {
50
+ const subNormalized = normalizeChildren(child, childStep);
51
+ if (subNormalized) {
52
+ normalizedChildren.push(...subNormalized);
53
+ }
54
+ continue;
55
+ }
56
+ //
57
+ // Skip falsy values (null, false, empty string, etc.) but not 0
58
+ //
59
+ if (child === undefined ||
60
+ child === null ||
61
+ child === false ||
62
+ child === '') {
63
+ continue;
64
+ }
65
+ //
66
+ // Something else. Just stringify and maybe merge with previous text node if possible.
67
+ //
68
+ const strChild = String(child);
69
+ const textRawElement = makeRawElement({
70
+ schema: textSchema,
71
+ elementHandler: (element) => {
72
+ element.data = strChild;
73
+ },
74
+ });
75
+ childStep?.(textRawElement);
76
+ const lastNormalized = normalizedChildren.at(-1);
77
+ if (isRawElement(lastNormalized, textSchema)) {
78
+ lastNormalized.data += strChild;
79
+ lastNormalized.hash = hash(lastNormalized.data, 12);
80
+ }
81
+ else {
82
+ normalizedChildren.push(textRawElement);
83
+ }
84
+ }
85
+ return normalizedChildren;
86
+ }
@@ -0,0 +1,10 @@
1
+ import { type Schema } from '../schema.js';
2
+ export interface MixSchema extends Schema {
3
+ name: 'mix';
4
+ type: 'block';
5
+ linkable: false;
6
+ Data: undefined;
7
+ Storage: undefined;
8
+ Children: Schema[];
9
+ }
10
+ export declare const mixSchema: MixSchema;
@@ -0,0 +1,6 @@
1
+ import { defineSchema } from '../schema.js';
2
+ export const mixSchema = defineSchema({
3
+ name: 'mix',
4
+ type: 'block',
5
+ linkable: false,
6
+ });
@@ -0,0 +1,10 @@
1
+ import { type Schema } from '../schema.js';
2
+ export interface TextSchema extends Schema {
3
+ name: 'text';
4
+ type: 'inliner';
5
+ linkable: false;
6
+ Data: string;
7
+ Storage: undefined;
8
+ Children: undefined;
9
+ }
10
+ export declare const textSchema: TextSchema;
@@ -0,0 +1,6 @@
1
+ import { defineSchema } from '../schema.js';
2
+ export const textSchema = defineSchema({
3
+ name: 'text',
4
+ type: 'inliner',
5
+ linkable: false,
6
+ });
@@ -0,0 +1,28 @@
1
+ import type { RawElement } from './element.js';
2
+ import type { LinkableTag } from './tag.js';
3
+ import { type AutoUnique, type ToUnique } from './unique.js';
4
+ export declare const DOCUMENT_PREFIX = "__TSPROSE_document";
5
+ export declare const DOCUMENT_AUTO_ID = "__TSPROSE_documentAutoId";
6
+ export interface Document<UniquesTemplate extends DocumentUniquesTemplate = DocumentUniquesTemplate> {
7
+ [DOCUMENT_PREFIX]: true;
8
+ documentId: string;
9
+ uniques: DocumentUniques<UniquesTemplate>;
10
+ rawProse: RawElement;
11
+ }
12
+ export type DocumentUniquesTemplate<Template extends Record<string, LinkableTag> = Record<string, LinkableTag>> = Template;
13
+ export type DocumentUniques<UniquesTemplate extends DocumentUniquesTemplate = DocumentUniquesTemplate> = {
14
+ [UniqueName in keyof UniquesTemplate]: ToUnique<UniquesTemplate[UniqueName]>;
15
+ };
16
+ export type DocumentContentCreator<UniquesTemplate extends DocumentUniquesTemplate = DocumentUniquesTemplate> = (context: {
17
+ uniques: DocumentUniques<UniquesTemplate>;
18
+ autoUnique: () => AutoUnique;
19
+ }) => RawElement;
20
+ export type DocumentFinalizer<UniquesTemplate extends DocumentUniquesTemplate = DocumentUniquesTemplate> = (contentCreator: DocumentContentCreator<UniquesTemplate>) => Document<UniquesTemplate>;
21
+ export declare function defineDocument(): DocumentFinalizer<{}>;
22
+ export declare function defineDocument<UniquesTemplate extends DocumentUniquesTemplate>(documentParameters: {
23
+ uniques: UniquesTemplate;
24
+ }): DocumentFinalizer<UniquesTemplate>;
25
+ export declare function defineDocument<UniquesTemplate extends DocumentUniquesTemplate>(documentId: string, documentParameters: {
26
+ uniques: UniquesTemplate;
27
+ }): DocumentFinalizer<UniquesTemplate>;
28
+ export declare function injectDocumentId(documentId: string, injectTo: string, defineDocumentAlias?: string): string;
@@ -0,0 +1,61 @@
1
+ import { TSProseError } from './error.js';
2
+ import { defineAutoUnique, defineUnique, } from './unique.js';
3
+ export const DOCUMENT_PREFIX = '__TSPROSE_document';
4
+ export const DOCUMENT_AUTO_ID = '__TSPROSE_documentAutoId';
5
+ export function defineDocument(arg1, arg2) {
6
+ const documentId = typeof arg1 === 'string' ? arg1 : DOCUMENT_AUTO_ID;
7
+ const uniquesTemplate = typeof arg1 === 'object' && 'uniques' in arg1
8
+ ? arg1.uniques
9
+ : arg2 && 'uniques' in arg2
10
+ ? arg2.uniques
11
+ : {};
12
+ const uniques = Object.fromEntries(Object.entries(uniquesTemplate).map(([key, value]) => [
13
+ key,
14
+ defineUnique({
15
+ documentId,
16
+ name: key,
17
+ tag: value,
18
+ }),
19
+ ]));
20
+ let autoUniquesCounter = 1;
21
+ const autoUnique = () => defineAutoUnique({
22
+ documentId,
23
+ name: `auto-unique-${autoUniquesCounter++}`,
24
+ });
25
+ function finalizeDocument(contentCreator) {
26
+ const rawProse = contentCreator({ uniques, autoUnique });
27
+ for (const unique of Object.values(uniques)) {
28
+ try {
29
+ unique.rawElement;
30
+ }
31
+ catch {
32
+ throw new TSProseError(`Unique "${unique.name}" for <${unique.tag.tagName}> was not used in the document content!\nAll uniques defined in the document must be used in the content creator function!`);
33
+ }
34
+ }
35
+ return {
36
+ [DOCUMENT_PREFIX]: true,
37
+ documentId,
38
+ uniques,
39
+ rawProse,
40
+ };
41
+ }
42
+ return finalizeDocument;
43
+ }
44
+ //
45
+ // injectDocumentId
46
+ //
47
+ export function injectDocumentId(documentId, injectTo, defineDocumentAlias) {
48
+ const funcName = defineDocumentAlias ?? 'defineDocument';
49
+ const escapedFuncName = funcName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
+ const escapedId = documentId.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
51
+ const regex = new RegExp(`\\b${escapedFuncName}\\((\\s*)(?!['"\`])`, 'g');
52
+ return injectTo.replace(regex, (match, whitespace, offset) => {
53
+ const afterChar = injectTo[offset + match.length];
54
+ if (afterChar === ')' || afterChar === undefined) {
55
+ // defineDocument() → defineDocument('id')
56
+ return `${funcName}(${whitespace}'${escapedId}'`;
57
+ }
58
+ // defineDocument({ → defineDocument('id', {
59
+ return `${funcName}('${escapedId}',${whitespace}`;
60
+ });
61
+ }
@@ -0,0 +1,33 @@
1
+ import type { BlockSchema, InlinerSchema, LinkableSchema, Schema } from './schema.js';
2
+ export declare const RAW_ELEMENT_PREFIX = "__TSPROSE_rawElement";
3
+ export type ToRawElement<TSchema extends Schema, TagName extends string = string> = TSchema extends Schema ? {
4
+ [RAW_ELEMENT_PREFIX]: true;
5
+ schema: TSchema;
6
+ hash: string;
7
+ tagName?: TagName;
8
+ slug?: string;
9
+ uniqueName?: string;
10
+ data: TSchema['Data'];
11
+ storageKey: TSchema['Storage'] extends undefined ? undefined : string;
12
+ children: ToRawElementChildren<TSchema['Children']>;
13
+ } : never;
14
+ type ToRawElementChildren<TChildren> = TChildren extends (infer E extends Schema)[] ? ToRawElement<E>[] : TChildren extends undefined ? undefined : never;
15
+ export type RawElement = ToRawElement<Schema>;
16
+ export type BlockRawElement = ToRawElement<BlockSchema>;
17
+ export type InlinerRawElement = ToRawElement<InlinerSchema>;
18
+ export type LinkableRawElement = ToRawElement<LinkableSchema>;
19
+ export declare const PROSE_ELEMENT_PREFIX = "__TSPROSE_proseElement";
20
+ export type ToProseElement<TSchema extends Schema> = {
21
+ [PROSE_ELEMENT_PREFIX]: true;
22
+ schema: TSchema;
23
+ id: TSchema['linkable'] extends false ? undefined : string;
24
+ data: TSchema['Data'];
25
+ storageKey: TSchema['Storage'] extends undefined ? undefined : string;
26
+ children: ToProseElementChildren<TSchema['Children']>;
27
+ };
28
+ type ToProseElementChildren<TChildren> = TChildren extends (infer E extends Schema)[] ? ToProseElement<E>[] : TChildren extends undefined ? undefined : never;
29
+ export type ProseElement = ToProseElement<Schema>;
30
+ export type BlockProseElement = ToProseElement<BlockSchema>;
31
+ export type InlinerProseElement = ToProseElement<InlinerSchema>;
32
+ export type LinkableProseElement = ToProseElement<LinkableSchema>;
33
+ export {};
@@ -0,0 +1,8 @@
1
+ //
2
+ // Raw Element
3
+ //
4
+ export const RAW_ELEMENT_PREFIX = '__TSPROSE_rawElement';
5
+ //
6
+ // Prose Element
7
+ //
8
+ export const PROSE_ELEMENT_PREFIX = '__TSPROSE_proseElement';
@@ -0,0 +1,33 @@
1
+ import { type BlockProseElement, type BlockRawElement, type InlinerProseElement, type InlinerRawElement, type ToProseElement, type ToRawElement } from './element.js';
2
+ import type { Schema } from './schema.js';
3
+ export declare function makeRawElement<TSchema extends Schema, ElementHandler extends (element: ToRawElement<TSchema, TagName>) => void, TagName extends string>(parameters: {
4
+ schema: TSchema;
5
+ tagName?: TagName;
6
+ elementHandler?: ElementHandler;
7
+ }): ToRawElement<TSchema, TagName>;
8
+ export declare function makeProseElement<TSchema extends Schema, ElementHandler extends (element: ToProseElement<TSchema>) => void>(parameters: {
9
+ schema: TSchema;
10
+ elementHandler?: ElementHandler;
11
+ }): ToProseElement<TSchema>;
12
+ export declare function isRawElement<TSchema extends Schema>(element: any, schema?: TSchema): element is ToRawElement<TSchema>;
13
+ export declare function isProseElement<TSchema extends Schema>(element: any, schema?: TSchema): element is ToProseElement<TSchema>;
14
+ export declare function ensureRawElement<TSchema extends Schema>(element: any, schema?: TSchema): asserts element is ToRawElement<TSchema>;
15
+ export declare function ensureProseElement<TSchema extends Schema>(element: any, schema?: TSchema): asserts element is ToProseElement<TSchema>;
16
+ export declare function isRawBlock(element: any): element is BlockRawElement;
17
+ export declare function isRawInliner(element: any): element is InlinerRawElement;
18
+ export declare function isProseBlock(element: any): element is BlockProseElement;
19
+ export declare function isProseInliner(element: any): element is InlinerProseElement;
20
+ export declare function ensureRawBlock(element: any): asserts element is BlockRawElement;
21
+ export declare function ensureRawInliner(element: any): asserts element is InlinerRawElement;
22
+ export declare function ensureProseBlock(element: any): asserts element is BlockProseElement;
23
+ export declare function ensureProseInliner(element: any): asserts element is InlinerProseElement;
24
+ export declare function hasChildren<T>(element: {
25
+ children?: T[];
26
+ }): element is {
27
+ children: [T, ...T[]];
28
+ };
29
+ export declare function ensureChildren<T>(element: {
30
+ children?: T[];
31
+ }): asserts element is {
32
+ children: [T, ...T[]];
33
+ };
@@ -0,0 +1,92 @@
1
+ import { PROSE_ELEMENT_PREFIX, RAW_ELEMENT_PREFIX, } from './element.js';
2
+ import { TSProseError } from './error.js';
3
+ import { hash } from './utils/hash.js';
4
+ export function makeRawElement(parameters) {
5
+ const element = {
6
+ [RAW_ELEMENT_PREFIX]: true,
7
+ schema: parameters.schema,
8
+ tagName: parameters.tagName,
9
+ };
10
+ parameters.elementHandler?.(element);
11
+ element.hash = hash(element.schema.name +
12
+ JSON.stringify(element.data) +
13
+ JSON.stringify(element.children?.map((child) => child.hash).join()), 12);
14
+ return element;
15
+ }
16
+ export function makeProseElement(parameters) {
17
+ const element = {
18
+ [PROSE_ELEMENT_PREFIX]: true,
19
+ schema: parameters.schema,
20
+ };
21
+ parameters.elementHandler?.(element);
22
+ return element;
23
+ }
24
+ export function isRawElement(element, schema) {
25
+ return isElement(RAW_ELEMENT_PREFIX, element, schema);
26
+ }
27
+ export function isProseElement(element, schema) {
28
+ return isElement(PROSE_ELEMENT_PREFIX, element, schema);
29
+ }
30
+ function isElement(prefix, element, schema) {
31
+ if (element?.[prefix] === true) {
32
+ if (schema) {
33
+ return schema.name === element?.schema?.name;
34
+ }
35
+ return true;
36
+ }
37
+ return false;
38
+ }
39
+ export function ensureRawElement(element, schema) {
40
+ ensureElement(RAW_ELEMENT_PREFIX, element, schema);
41
+ }
42
+ export function ensureProseElement(element, schema) {
43
+ ensureElement(PROSE_ELEMENT_PREFIX, element, schema);
44
+ }
45
+ function ensureElement(prefix, element, schema) {
46
+ if (!isElement(prefix, element, schema)) {
47
+ throw new TSProseError(`Not a ${prefix === RAW_ELEMENT_PREFIX ? 'RawElement' : 'ProseElement'}${schema ? ` with "${schema.name}" schema` : ''}!\nProvided:${JSON.stringify(element)}`);
48
+ }
49
+ }
50
+ export function isRawBlock(element) {
51
+ return isType('raw', 'block', element);
52
+ }
53
+ export function isRawInliner(element) {
54
+ return isType('raw', 'inliner', element);
55
+ }
56
+ export function isProseBlock(element) {
57
+ return isType('prose', 'block', element);
58
+ }
59
+ export function isProseInliner(element) {
60
+ return isType('prose', 'inliner', element);
61
+ }
62
+ function isType(elementType, type, element) {
63
+ if (elementType === 'raw' ? isRawElement(element) : isProseElement(element)) {
64
+ return element.schema.type === type;
65
+ }
66
+ return false;
67
+ }
68
+ export function ensureRawBlock(element) {
69
+ ensureType('raw', 'block', element);
70
+ }
71
+ export function ensureRawInliner(element) {
72
+ ensureType('raw', 'inliner', element);
73
+ }
74
+ export function ensureProseBlock(element) {
75
+ ensureType('prose', 'block', element);
76
+ }
77
+ export function ensureProseInliner(element) {
78
+ ensureType('prose', 'inliner', element);
79
+ }
80
+ function ensureType(elementType, type, element) {
81
+ if (!isType(elementType, type, element)) {
82
+ throw new TSProseError(`Not a ${elementType} ${type}!\nProvided:${JSON.stringify(element)}`);
83
+ }
84
+ }
85
+ export function hasChildren(element) {
86
+ return element.children !== undefined && element.children.length > 0;
87
+ }
88
+ export function ensureChildren(element) {
89
+ if (!hasChildren(element)) {
90
+ throw new TSProseError('Provided element has no children!');
91
+ }
92
+ }
@@ -0,0 +1,3 @@
1
+ export declare class TSProseError extends Error {
2
+ constructor(message: string);
3
+ }
package/dist/error.js ADDED
@@ -0,0 +1,6 @@
1
+ export class TSProseError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'TSProseError';
5
+ }
6
+ }
@@ -0,0 +1,57 @@
1
+ //
2
+ // Images
3
+ //
4
+
5
+ declare module '*.png' {
6
+ const src: string;
7
+ export default src;
8
+ }
9
+
10
+ declare module '*.jpg' {
11
+ const src: string;
12
+ export default src;
13
+ }
14
+
15
+ declare module '*.jpeg' {
16
+ const src: string;
17
+ export default src;
18
+ }
19
+
20
+ declare module '*.gif' {
21
+ const src: string;
22
+ export default src;
23
+ }
24
+
25
+ declare module '*.bmp' {
26
+ const src: string;
27
+ export default src;
28
+ }
29
+
30
+ declare module '*.webp' {
31
+ const src: string;
32
+ export default src;
33
+ }
34
+
35
+ declare module '*.svg' {
36
+ const src: string;
37
+ export default src;
38
+ }
39
+
40
+ //
41
+ // Videos
42
+ //
43
+
44
+ declare module '*.mp4' {
45
+ const src: string;
46
+ export default src;
47
+ }
48
+
49
+ declare module '*.webm' {
50
+ const src: string;
51
+ export default src;
52
+ }
53
+
54
+ declare module '*.ogg' {
55
+ const src: string;
56
+ export default src;
57
+ }
package/dist/id.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { RawElement } from './element.js';
2
+ export type IdMaker = (rawElement: RawElement, takenIds?: Set<string>) => string;
3
+ export declare const defaultIdMaker: IdMaker;
package/dist/id.js ADDED
@@ -0,0 +1,17 @@
1
+ export const defaultIdMaker = (rawElement, takenIds) => {
2
+ takenIds ||= new Set();
3
+ let id = '';
4
+ const humanReadable = rawElement.uniqueName || rawElement.slug;
5
+ if (humanReadable) {
6
+ id = humanReadable;
7
+ }
8
+ else {
9
+ id = rawElement.schema.name + '-' + rawElement.hash.substring(0, 9);
10
+ }
11
+ let candidate = id;
12
+ let counter = 1;
13
+ while (takenIds.has(candidate)) {
14
+ candidate = `${id}-${counter++}`;
15
+ }
16
+ return candidate;
17
+ };
@@ -0,0 +1,17 @@
1
+ export * from './default/mix.js';
2
+ export * from './default/text.js';
3
+ export * from './utils/hash.js';
4
+ export * from './children.js';
5
+ export * from './document.js';
6
+ export * from './element.js';
7
+ export * from './elementUtils.js';
8
+ export * from './error.js';
9
+ export * from './id.js';
10
+ export * from './json.js';
11
+ export * from './rawToProse.js';
12
+ export * from './schema.js';
13
+ export * from './storage.js';
14
+ export * from './tag.js';
15
+ export * from './tagUtils.js';
16
+ export * from './unique.js';
17
+ export * from './walk.js';