@zudojs/docs 1.0.0 → 1.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.
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* untrusted node content cannot break out of a table, code fence,
|
|
6
6
|
* heading or link.
|
|
7
7
|
*/
|
|
8
|
-
const CALLOUT_LABELS =
|
|
9
|
-
note
|
|
10
|
-
warning
|
|
11
|
-
tip
|
|
12
|
-
danger
|
|
13
|
-
|
|
8
|
+
const CALLOUT_LABELS = new Map([
|
|
9
|
+
["note", "NOTE"],
|
|
10
|
+
["warning", "WARNING"],
|
|
11
|
+
["tip", "TIP"],
|
|
12
|
+
["danger", "DANGER"],
|
|
13
|
+
]);
|
|
14
14
|
/**
|
|
15
15
|
* Converts a list of documentation nodes to markdown.
|
|
16
16
|
*
|
|
@@ -65,7 +65,11 @@ export function nodesToMarkdown(nodes) {
|
|
|
65
65
|
lines.push("");
|
|
66
66
|
break;
|
|
67
67
|
case "callout": {
|
|
68
|
-
|
|
68
|
+
// A Map, not a plain-object lookup: a kind of "constructor" coming
|
|
69
|
+
// from untrusted JSON must not resolve to Object.prototype.constructor
|
|
70
|
+
// and print a function's source as the label.
|
|
71
|
+
const label = CALLOUT_LABELS.get(node.kind) ??
|
|
72
|
+
singleLine(String(node.kind)).toUpperCase();
|
|
69
73
|
const [first = "", ...rest] = node.value.split(/\r?\n/);
|
|
70
74
|
lines.push(`> **${label}:** ${first}`);
|
|
71
75
|
for (const line of rest) {
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
export declare function deepFreeze<T>(value: T, seen?: WeakSet<object>): T;
|
|
10
10
|
/**
|
|
11
11
|
* Returns a deep-frozen copy of `value`, leaving the caller's object
|
|
12
|
-
* untouched. Falls back to
|
|
13
|
-
* cannot be structurally cloned (e.g. contains
|
|
12
|
+
* untouched. Falls back to a recursive copy of plain objects, arrays and
|
|
13
|
+
* Dates when the value cannot be structurally cloned (e.g. contains
|
|
14
|
+
* functions); those are kept by reference.
|
|
14
15
|
*/
|
|
15
16
|
export declare function deepFreezeClone<T>(value: T): T;
|
|
16
17
|
//# sourceMappingURL=utils.freeze.d.ts.map
|
|
@@ -24,8 +24,9 @@ export function deepFreeze(value, seen = new WeakSet()) {
|
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Returns a deep-frozen copy of `value`, leaving the caller's object
|
|
27
|
-
* untouched. Falls back to
|
|
28
|
-
* cannot be structurally cloned (e.g. contains
|
|
27
|
+
* untouched. Falls back to a recursive copy of plain objects, arrays and
|
|
28
|
+
* Dates when the value cannot be structurally cloned (e.g. contains
|
|
29
|
+
* functions); those are kept by reference.
|
|
29
30
|
*/
|
|
30
31
|
export function deepFreezeClone(value) {
|
|
31
32
|
let copy;
|
|
@@ -33,15 +34,38 @@ export function deepFreezeClone(value) {
|
|
|
33
34
|
copy = structuredClone(value);
|
|
34
35
|
}
|
|
35
36
|
catch {
|
|
36
|
-
copy =
|
|
37
|
+
copy = deepCopy(value, new WeakMap());
|
|
37
38
|
}
|
|
38
39
|
return deepFreeze(copy);
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Recursive fallback for values `structuredClone` rejects. A shallow copy
|
|
43
|
+
* was not enough: `deepFreeze` then walked into the caller's nested
|
|
44
|
+
* objects and froze them in place.
|
|
45
|
+
*/
|
|
46
|
+
function deepCopy(value, seen) {
|
|
47
|
+
if (typeof value !== "object" || value === null)
|
|
48
|
+
return value;
|
|
49
|
+
if (seen.has(value))
|
|
50
|
+
return seen.get(value);
|
|
51
|
+
if (value instanceof Date) {
|
|
52
|
+
return new Date(value.getTime());
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
const copy = [];
|
|
56
|
+
seen.set(value, copy);
|
|
57
|
+
for (const item of value)
|
|
58
|
+
copy.push(deepCopy(item, seen));
|
|
59
|
+
return copy;
|
|
60
|
+
}
|
|
61
|
+
if (isPlainObject(value)) {
|
|
62
|
+
const copy = {};
|
|
63
|
+
seen.set(value, copy);
|
|
64
|
+
for (const [key, item] of Object.entries(value)) {
|
|
65
|
+
copy[key] = deepCopy(item, seen);
|
|
66
|
+
}
|
|
67
|
+
return copy;
|
|
68
|
+
}
|
|
45
69
|
return value;
|
|
46
70
|
}
|
|
47
71
|
function isPlainObject(value) {
|
|
@@ -43,11 +43,14 @@ export function validateNavigation(items, registeredIds) {
|
|
|
43
43
|
});
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
// The same node object mounted in two places is still the document
|
|
47
|
+
// appearing twice in the navigation, so the duplicate check runs on
|
|
48
|
+
// every visit; only the per-node checks and the descent are skipped
|
|
49
|
+
// for a node already seen.
|
|
50
|
+
const firstVisit = !visited.has(node);
|
|
48
51
|
visited.add(node);
|
|
49
52
|
if (node.documentId) {
|
|
50
|
-
if (!registeredIds.has(node.documentId)) {
|
|
53
|
+
if (firstVisit && !registeredIds.has(node.documentId)) {
|
|
51
54
|
issues.push({
|
|
52
55
|
severity: "error",
|
|
53
56
|
code: "NAVIGATION_UNKNOWN_DOCUMENT",
|
|
@@ -65,14 +68,14 @@ export function validateNavigation(items, registeredIds) {
|
|
|
65
68
|
}
|
|
66
69
|
seenIds.add(node.documentId);
|
|
67
70
|
}
|
|
68
|
-
else if (!node.children || node.children.length === 0) {
|
|
71
|
+
else if (firstVisit && (!node.children || node.children.length === 0)) {
|
|
69
72
|
issues.push({
|
|
70
73
|
severity: "warning",
|
|
71
74
|
code: "NAVIGATION_EMPTY_ITEM",
|
|
72
75
|
message: `Navigation item "${node.title}" has neither a documentId nor children.`,
|
|
73
76
|
});
|
|
74
77
|
}
|
|
75
|
-
if (node.children) {
|
|
78
|
+
if (firstVisit && node.children) {
|
|
76
79
|
walk(node.children, [...ancestors, node]);
|
|
77
80
|
}
|
|
78
81
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/docs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Documentation infrastructure with structured document model, registry, validation, navigation, and generation.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,13 +11,17 @@
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@zudojs/errors": "1.0.
|
|
14
|
+
"@zudojs/errors": "1.0.1"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"typescript": "7.0.2",
|
|
18
18
|
"vitest": "^4.1.11"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Oluwayemi Oyinlola",
|
|
23
|
+
"url": "https://github.com/oyinlola-tech"
|
|
24
|
+
},
|
|
21
25
|
"type": "module",
|
|
22
26
|
"files": [
|
|
23
27
|
"dist",
|