• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / jdita / e8f8ab9c-2df3-498c-a466-87a135bc5448

27 Jan 2024 12:27PM UTC coverage: 92.208% (-0.005%) from 92.213%
e8f8ab9c-2df3-498c-a466-87a135bc5448

Pull #133

circleci

marmoure
[bugfix] fix tsdoc missing references
Pull Request #133: Documentation for JDita

396 of 447 branches covered (0.0%)

Branch coverage included in aggregate %.

63 of 68 new or added lines in 15 files covered. (92.65%)

2 existing lines in 1 file now uncovered.

953 of 1016 relevant lines covered (93.8%)

22.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.62
/src/utils.ts
1
import { BasicValue, OrArray, ChildTypes, ChildType, ReferenceContentScope } from "./classes";
2

3
/**
4
 * has - Check if an array has a value
5
 *
6
 * @param array - Array
7
 * @param value - Value
8
 * @returns Boolean
9
 */
10
export function has<T>(array: Array<T>, value: T): boolean {
1✔
11
    return array.indexOf(value) >= 0;
358✔
12
}
13

14
/**
15
 * isOrUndefined - Check if a value is undefined or not
16
 *
17
 * @param check - Function to check the value
18
 * @param value - Value
19
 * @returns - Boolean
20
 */
21
export function isOrUndefined<T extends BasicValue>(check: (value?: BasicValue) => boolean, value?: BasicValue): value is T {
1✔
22
    return typeof value === 'undefined' || check(value);
406✔
23
}
24

25
/**
26
 * isReferenceContentScope - Checks if a value is a ReferenceContentScope
27
 *
28
 * @param value - String
29
 * @returns - If the value is a ReferenceContentScope
30
 */
31
export const isReferenceContentScope = (value?: BasicValue): value is ReferenceContentScope => has(['local', 'peer', 'external'], value);
1✔
32

33
/**
34
 * @remarks
35
 * When a node is a group we use this list to check if a node name is valid
36
 */
37
const phGroup = ['ph', 'b', 'i', 'u', 'sub', 'sup'];
1✔
38
const dataGroup = ['data'];
1✔
39

40
/**
41
 * Node groups
42
 * 
43
 * @remarks
44
 * Group all similar nodes
45
 */
46
export const nodeGroups: Record<string, Array<string>> = {
1✔
47
    'ph': phGroup,
48
    'data': dataGroup,
49
    'common-inline': ['text', ...phGroup, 'image', ...dataGroup],
50
    'all-inline': ['text', ...phGroup, 'image', 'xref', ...dataGroup],
51
    'simple-blocks': ['p', 'ul', 'ol', 'dl', 'pre', 'audio', 'video', 'fn', 'note', ...dataGroup],
52
    'fn-blocks': ['p', 'ul', 'ol', 'dl', ...dataGroup],
53
    'all-blocks': ['p', 'ul', 'ol', 'dl', 'pre', 'audio', 'video', 'simpletable', 'fig', 'fn', 'note', ...dataGroup],
54
    'list-blocks': ['p', 'ul', 'ol', 'dl', 'pre', 'audio', 'video', 'simpletable', 'fig', 'note', ...dataGroup],
55
    'fig-blocks': ['p', 'ul', 'ol', 'dl', 'pre', 'audio', 'video', 'simpletable', ...dataGroup],
56
}
57

58
/**
59
 * splitTypenames - Converts a string to an array of strings
60
 * it splits the string by `|`
61
 * 
62
 * @privateRemarks
63
 * This is only used in tests
64
 * 
65
 * @param value - string
66
 * @returns - String[]
67
 */
68
export function splitTypenames(value: string): string[] {
1✔
69
    if (value[0] !== '(') {
21✔
70
        return value.split('|');
6✔
71
    }
72

73
    // if the string starts with `(` and ends with `)` then remove them
74
    const last = value.slice(-1);
15✔
75
    return has(['+', '*', '?'], last)
15✔
76
        ? value.slice(1, -2).split('|').map(type => type + last)
50!
77
        : value.slice(1, -1).split('|');
78
}
79

80
/**
81
 * childTypeToString - Convert a child type to a string
82
 * 
83
 * @param type - ChildType object
84
 * @param getNodeName - Get node name function
85
 * @returns - string
86
 */
87
function childTypeToString(type: ChildType, getNodeName?: (nodeName: string) => string): string {
88
    return (type.isGroup
43✔
89
        ? nodeGroups[type.name].length === 1
43✔
90
            ? (getNodeName
4!
91
                ? nodeGroups[type.name].map(getNodeName)
4!
92
                : nodeGroups[type.name]
93
            ).join('|')
94
            : '(' + (getNodeName
95
                ? nodeGroups[type.name].map(getNodeName)
×
96
                : nodeGroups[type.name]
97
            ).join('|') + ')'
98
        : getNodeName ? getNodeName(type.name) : type.name
39✔
99
    ) + (type.single
100
        ? type.required ? '' : '?'
68✔
101
        : type.required ? '+' : '*');
18✔
102
}
103

104
/**
105
 * customChildTypesToString - Serialize a child type object to a string with a custom function to get the node name
106
 *
107
 * @param type - ChildType Array
108
 * @param getNodeName - function to get the node name
109
 * @param topLevel - start of the document
110
 * @returns string - Serialized ChildType Array
111
 */
112
export function customChildTypesToString(type: ChildTypes, getNodeName?: (nodeName: string) => string, topLevel = true): string {
1✔
113
    if (Array.isArray(type)) {
52✔
114
        const types = type.map(subType => customChildTypesToString(subType, getNodeName, false)).join('|');
37✔
115
        return topLevel || type.length === 1 ? types : '(' + types + ')';
9✔
116
    } else {
117
        return childTypeToString(type, getNodeName)
43✔
118
    }
119
}
120

121
/**
122
 * childTypesToString - Serialize a child type object to a string
123
 *
124
 * @param type - ChildType Array
125
 * @param topLevel - start of the document
126
 * @returns string - Serialized ChildType Array
127
 */
128
export function childTypesToString(type: ChildTypes, topLevel = true): string {
1✔
129
    return customChildTypesToString(type, undefined, topLevel);
14✔
130
}
131

132
/**
133
 * stringToChildTypes - Convert the array list of string to child objects
134
 * 
135
 * @remarks
136
 * `?` - optional
137
 * `+` - required
138
 * `*` - optional and multiple
139
 * `%` - group
140
 *
141
 * @param value - String or Array of strings
142
 * @param topLevel - Entry of the document
143
 * @returns Array of ChildType objects , @see {@link ChildType}
144
 */
145
export function stringToChildTypes(value: OrArray<string>, topLevel = true): ChildTypes[] {
1✔
146
    if (typeof value === 'string') {
391✔
147
        if (value === '') {
250✔
148
            return [];
2✔
149
        }
150
        if (value.indexOf('|') < 0) {
248✔
151
            const last = value.slice(-1);
229✔
152
            const result: ChildType = has(['+', '*', '?'], last)
229✔
153
            ? {
229✔
154
                name: value.slice(0, -1),
155
                single: last === '?',
156
                required: last === '+',
157
                isGroup: false,
158
            } : {
159
                name: value,
160
                single: true,
161
                required: true,
162
                isGroup: false,
163
            };
164
            if (result.name[0] === '%') {
229✔
165
                result.name = result.name.substr(1);
72✔
166
                result.isGroup = true;
72✔
167
            }
168
            return topLevel && !Array.isArray(result) ? [ result ] : result as unknown as ChildTypes[];
229✔
169
        } else {
170
            return stringToChildTypes(splitTypenames(value), false);
19✔
171
        }
172
    } else {
173
        return value.map(subType => stringToChildTypes(subType, false)).filter(type => !Array.isArray(type) || type.length > 0);
235✔
174
    }
175
}
176

177
/**
178
 * acceptsNodeName - Check whether a child type accepts a node name
179
 *
180
 * @param value - Node name
181
 * @param childType - String or an ChildType object or an array ChildType objects
182
 * @returns ChildType | undefined - returns the ChildType oject if it's accepted or undefined if it's not
183
 */
184
export function acceptsNodeName(value: string, childType: ChildTypes): ChildType | undefined {
1✔
185
    // if child type is an array
186
    if (Array.isArray(childType)) {
355✔
187
        let result: ChildType | undefined;
188
        childType.some(type => {
100✔
189
            // if any of the children in the array accepts the node name then return true
190
            result = acceptsNodeName(value, type);
156✔
191
            if (result) {
156✔
192
                return true;
96✔
193
            }
194
        });
195
        return result;
100✔
196
    } else {
197
        // if child type is not a group
198
        // then check if the child type name is equal to the value
199
        // if it's a group check if the value is in the group
200
        return !childType.isGroup
255✔
201
            ? (childType.name === value ? childType : undefined)
396✔
202
            : (has(nodeGroups[childType.name], value) ? childType : undefined);
114✔
203
    }
204
}
205

206
/**
207
 * isChildTypeSingle - check if the child belongs to a group of elements eg: `list-blocks` or `all-line`
208
 *
209
 * @param childType - String or an ChildType object or an array ChildType objects
210
 * @returns Boolean - Whether the child is a group or not
211
 */
212
export function isChildTypeSingle(childType: string | ChildType | ChildTypes): boolean {
1✔
213
    // if it's an Array 
214
    if (Array.isArray(childType)) {
89✔
215
        let result = true;
32✔
216
        // if any of the children in the array is not a single type then return false
217
        childType.some(type => {
32✔
218
            result = isChildTypeSingle(type);
48✔
219
            return !result;
48✔
220
        });
221
        return result;
32✔
222
    } else {
223
        // it's a string
224
        if (typeof childType === 'string') {
57!
225
            // parse the string using `stringToChildTypes` and check if it's a single type
226
            // single type can be denoted by the lack of `%` in the beginning of the string
UNCOV
227
            return isChildTypeSingle(stringToChildTypes(childType));
×
228
        }
229
        // if the oject is already parsed then return the single property
230
        return !!childType.single;
57✔
231
    }
232
}
233

234
/**
235
 * isChildTypeRequired - Check if a child is required
236
 * 
237
 * the required property is denoted by `+` or the lack of `?` in the end of the string
238
 * This means the child must be present in the node in the order specified by the parent node
239
 * 
240
 * @param childType -  String or an ChildType object or an array ChildType objects
241
 * @returns Boolean - Whether the child is required or not
242
 */
243
export function isChildTypeRequired(childType: string | ChildType | ChildTypes): boolean {
1✔
244
    // console.log(childType);
245
    // if it's an Array
246
    if (Array.isArray(childType)) {
8!
247
        let result = true;
×
248
        // if one of the children in the array is required then return true
249
        childType.some(type => {
×
250
            result = !isChildTypeRequired(type);
×
251
            return !result;
×
252
        });
253
        return result;
×
254
    } else {
255
        if (typeof childType === 'string') {
8!
256
            // if it's a string parse it and check if it's required
UNCOV
257
            return isChildTypeRequired(stringToChildTypes(childType));
×
258
        }
259
        // if the oject is already parsed then return the required property
260
        return !!childType.required;
8✔
261
    }
262
}
263

264
/**
265
 * childTypesArray - Check whether the child types is an array or not and return an array
266
 *
267
 * @param childTypes - ChildType array or ChildType object
268
 * @returns - ChildType array
269
 */
270
export function childTypesArray(childTypes: ChildTypes): ChildTypes[] {
1✔
271
    return Array.isArray(childTypes) ? childTypes : [childTypes];
×
272
}
273

274
/**
275
 * areFieldsValid - Attribute validator
276
 *
277
 * @param fields - Array of attribute names
278
 * @param value - Object of attribute values
279
 * @param validations - Validation functions
280
 * @returns Boolean - Whether the attributes are valid or not
281
 */
282
export function areFieldsValid(fields: string[], value: Record<string, BasicValue>, ...validations: ((field: string, value: BasicValue) => boolean)[]): boolean {
1✔
283
    for (const field of fields) {
42✔
284
        let valid = false;
322✔
285
        for (const validation of validations) {
322✔
286
            if (validation(field, value[field])) {
322!
287
                valid = true;
322✔
288
                break;
322✔
289
            }
290
        }
291
        if (!valid) {
322!
292
            return false;
×
293
        }
294
    }
295
    return true;
42✔
296
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc