UNPKG

2.4 kBJavaScriptView Raw
1'use strict';
2
3var identity = require('../nodes/identity.js');
4var visit = require('../visit.js');
5
6/**
7 * Verify that the input string is a valid anchor.
8 *
9 * Will throw on errors.
10 */
11function anchorIsValid(anchor) {
12 if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
13 const sa = JSON.stringify(anchor);
14 const msg = `Anchor must not contain whitespace or control characters: ${sa}`;
15 throw new Error(msg);
16 }
17 return true;
18}
19function anchorNames(root) {
20 const anchors = new Set();
21 visit.visit(root, {
22 Value(_key, node) {
23 if (node.anchor)
24 anchors.add(node.anchor);
25 }
26 });
27 return anchors;
28}
29/** Find a new anchor name with the given `prefix` and a one-indexed suffix. */
30function findNewAnchor(prefix, exclude) {
31 for (let i = 1; true; ++i) {
32 const name = `${prefix}${i}`;
33 if (!exclude.has(name))
34 return name;
35 }
36}
37function createNodeAnchors(doc, prefix) {
38 const aliasObjects = [];
39 const sourceObjects = new Map();
40 let prevAnchors = null;
41 return {
42 onAnchor: (source) => {
43 aliasObjects.push(source);
44 if (!prevAnchors)
45 prevAnchors = anchorNames(doc);
46 const anchor = findNewAnchor(prefix, prevAnchors);
47 prevAnchors.add(anchor);
48 return anchor;
49 },
50 /**
51 * With circular references, the source node is only resolved after all
52 * of its child nodes are. This is why anchors are set only after all of
53 * the nodes have been created.
54 */
55 setAnchors: () => {
56 for (const source of aliasObjects) {
57 const ref = sourceObjects.get(source);
58 if (typeof ref === 'object' &&
59 ref.anchor &&
60 (identity.isScalar(ref.node) || identity.isCollection(ref.node))) {
61 ref.node.anchor = ref.anchor;
62 }
63 else {
64 const error = new Error('Failed to resolve repeated object (this should not happen)');
65 error.source = source;
66 throw error;
67 }
68 }
69 },
70 sourceObjects
71 };
72}
73
74exports.anchorIsValid = anchorIsValid;
75exports.anchorNames = anchorNames;
76exports.createNodeAnchors = createNodeAnchors;
77exports.findNewAnchor = findNewAnchor;