Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
Spec
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
7 / 7
10
100.00% covered (success)
100.00%
1 / 1
 isNode
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 isBlock
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isInline
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isLeaf
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isMark
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 nodeDefaults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 markDefaults
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Richtext;
6
7/**
8 * The richtext format vocabulary (v1) — the single source of truth
9 * for node and mark names, attribute defaults, and content models.
10 * See docs/richtext-format.md for the full specification.
11 */
12final class Spec
13{
14    public const array ALIGNMENTS = ['left', 'center', 'right', 'justify'];
15
16    /**
17     * Attribute defaults per node type. Attributes equal to their
18     * default are omitted in canonical form. Defaults are frozen per
19     * format version — changing one is a breaking change.
20     */
21    public const array NODE_DEFAULTS = [
22        'paragraph' => ['class' => 'default', 'align' => null],
23        'heading' => ['align' => null],
24        'orderedList' => ['start' => 1],
25        'horizontalRule' => ['class' => null],
26        'image' => ['meta' => null],
27    ];
28
29    /** Mark attribute defaults, same omission rule as node defaults. */
30    public const array MARK_DEFAULTS = [
31        'link' => ['target' => null, 'class' => null],
32    ];
33
34    /** Content models of the non-leaf nodes. */
35    public const array CONTENT = [
36        'doc' => 'block+',
37        'paragraph' => 'inline*',
38        'heading' => 'inline*',
39        'bulletList' => 'listItem+',
40        'orderedList' => 'listItem+',
41        'listItem' => 'paragraph block*',
42        'blockquote' => 'block+',
43        'codeBlock' => 'text*',
44    ];
45
46    public const array BLOCKS = [
47        'paragraph',
48        'heading',
49        'bulletList',
50        'orderedList',
51        'blockquote',
52        'codeBlock',
53        'horizontalRule',
54    ];
55
56    public const array INLINE = ['text', 'hardBreak', 'image'];
57
58    public const array MARKS = [
59        'bold',
60        'code',
61        'italic',
62        'link',
63        'strike',
64        'style',
65        'subscript',
66        'superscript',
67        'underline',
68    ];
69
70    /** Outermost-to-innermost nesting order when rendering marks. */
71    public const array MARK_ORDER = [
72        'link',
73        'style',
74        'bold',
75        'italic',
76        'underline',
77        'strike',
78        'subscript',
79        'superscript',
80        'code',
81    ];
82
83    public static function isNode(string $type): bool
84    {
85        return (
86            $type === 'doc'
87                || $type === 'listItem'
88                || in_array($type, self::BLOCKS, true)
89                || in_array($type, self::INLINE, true)
90        );
91    }
92
93    public static function isBlock(string $type): bool
94    {
95        return in_array($type, self::BLOCKS, true);
96    }
97
98    public static function isInline(string $type): bool
99    {
100        return in_array($type, self::INLINE, true);
101    }
102
103    public static function isLeaf(string $type): bool
104    {
105        return !isset(self::CONTENT[$type]);
106    }
107
108    public static function isMark(string $type): bool
109    {
110        return in_array($type, self::MARKS, true);
111    }
112
113    /** @return array<string, mixed> */
114    public static function nodeDefaults(string $type): array
115    {
116        return self::NODE_DEFAULTS[$type] ?? [];
117    }
118
119    /** @return array<string, mixed> */
120    public static function markDefaults(string $type): array
121    {
122        return self::MARK_DEFAULTS[$type] ?? [];
123    }
124}