@bablr/agast-helpers 0.7.1 → 0.8.0
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/lib/builders.js +70 -27
- package/lib/children.js +120 -0
- package/lib/object.js +86 -0
- package/lib/path-facade.js +39 -0
- package/lib/path.js +386 -448
- package/lib/print.js +51 -87
- package/lib/shorthand.js +26 -1
- package/lib/stream.js +33 -13
- package/lib/symbols.js +3 -1
- package/lib/template.js +23 -36
- package/lib/tree.js +368 -122
- package/package.json +8 -5
- package/lib/sumtree.js +0 -62
package/lib/builders.js
CHANGED
|
@@ -11,14 +11,13 @@ import {
|
|
|
11
11
|
InitializerTag,
|
|
12
12
|
LiteralTag,
|
|
13
13
|
TokenGroup,
|
|
14
|
-
|
|
14
|
+
AttributeDefinition,
|
|
15
|
+
BindingTag,
|
|
15
16
|
} from './symbols.js';
|
|
16
17
|
|
|
17
|
-
const { freeze } = Object;
|
|
18
|
+
const { freeze, hasOwn } = Object;
|
|
18
19
|
const { isArray } = Array;
|
|
19
20
|
|
|
20
|
-
const isObject = (val) => val !== null && typeof val === 'object';
|
|
21
|
-
|
|
22
21
|
function* relatedNodes(properties) {
|
|
23
22
|
for (const value of Object.values(properties)) {
|
|
24
23
|
if (isArray(value)) {
|
|
@@ -37,22 +36,45 @@ const find = (predicate, iterable) => {
|
|
|
37
36
|
}
|
|
38
37
|
};
|
|
39
38
|
|
|
40
|
-
export const
|
|
41
|
-
|
|
39
|
+
export const buildProperty = (reference, binding, node) => {
|
|
40
|
+
if (node?.binding) throw new Error();
|
|
41
|
+
if (!reference.flags) throw new Error();
|
|
42
|
+
if (!isArray(node) && typeof node === 'object' && !hasOwn(node, 'properties')) throw new Error();
|
|
43
|
+
|
|
44
|
+
if (reference.value) throw new Error();
|
|
45
|
+
|
|
46
|
+
return freeze({ reference, binding, node });
|
|
42
47
|
};
|
|
43
48
|
|
|
44
|
-
export const
|
|
45
|
-
if (
|
|
46
|
-
|
|
49
|
+
export const buildFacadeProperty = (reference, binding, node) => {
|
|
50
|
+
if (node?.binding) throw new Error();
|
|
51
|
+
if (!reference.flags) throw new Error();
|
|
52
|
+
if (!isArray(node) && typeof node === 'object' && !node.properties) throw new Error();
|
|
53
|
+
|
|
54
|
+
if (reference.value) throw new Error();
|
|
55
|
+
|
|
56
|
+
return freeze({ reference, binding, node });
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const buildTokenGroup = (tokens) => {
|
|
60
|
+
return freeze({ type: TokenGroup, value: tokens });
|
|
47
61
|
};
|
|
48
62
|
|
|
49
63
|
export const buildBeginningOfStreamToken = () => {
|
|
50
64
|
return freeze({ type: Symbol.for('@bablr/beginning-of-stream'), value: undefined });
|
|
51
65
|
};
|
|
52
66
|
|
|
53
|
-
export const buildReferenceTag = (
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
export const buildReferenceTag = (
|
|
68
|
+
type = null,
|
|
69
|
+
name = null,
|
|
70
|
+
isArray = false,
|
|
71
|
+
flags = referenceFlags,
|
|
72
|
+
index,
|
|
73
|
+
) => {
|
|
74
|
+
if (type != null && !isString(type)) throw new Error();
|
|
75
|
+
if (name != null && !isString(name)) throw new Error();
|
|
76
|
+
if (name == null && type == null) throw new Error();
|
|
77
|
+
if (index) throw new Error();
|
|
56
78
|
let { hasGap, expression } = flags;
|
|
57
79
|
|
|
58
80
|
hasGap = !!hasGap;
|
|
@@ -60,7 +82,7 @@ export const buildReferenceTag = (name, isArray = false, flags = referenceFlags,
|
|
|
60
82
|
|
|
61
83
|
return freeze({
|
|
62
84
|
type: ReferenceTag,
|
|
63
|
-
value: freeze({ name, isArray,
|
|
85
|
+
value: freeze({ type, name, isArray, flags: freeze({ hasGap, expression }) }),
|
|
64
86
|
});
|
|
65
87
|
};
|
|
66
88
|
|
|
@@ -69,38 +91,42 @@ export const buildNullTag = () => {
|
|
|
69
91
|
};
|
|
70
92
|
|
|
71
93
|
export const buildInitializerTag = (isArray = false) => {
|
|
72
|
-
return freeze({ type: InitializerTag, value: { isArray } });
|
|
94
|
+
return freeze({ type: InitializerTag, value: freeze({ isArray }) });
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const buildBindingTag = (languagePath = []) => {
|
|
98
|
+
if (!isArray(languagePath)) throw new Error();
|
|
99
|
+
return freeze({ type: BindingTag, value: freeze({ languagePath }) });
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const buildChild = (type, value) => {
|
|
103
|
+
return freeze({ type, value });
|
|
73
104
|
};
|
|
74
105
|
|
|
75
106
|
export const buildGapTag = () => {
|
|
76
107
|
return freeze({ type: GapTag, value: undefined });
|
|
77
108
|
};
|
|
78
109
|
|
|
79
|
-
export const buildShiftTag = (index) => {
|
|
110
|
+
export const buildShiftTag = (index, height) => {
|
|
80
111
|
if (!Number.isFinite(index)) throw new Error();
|
|
81
|
-
|
|
112
|
+
if (!Number.isFinite(height)) throw new Error();
|
|
113
|
+
return freeze({ type: ShiftTag, value: freeze({ index, height }) });
|
|
82
114
|
};
|
|
83
115
|
|
|
84
|
-
export const buildDoctypeTag = (attributes = {}) => {
|
|
116
|
+
export const buildDoctypeTag = (attributes = {}, version = 0) => {
|
|
85
117
|
return freeze({
|
|
86
118
|
type: DoctypeTag,
|
|
87
|
-
value: { doctype: 'cstml', version
|
|
119
|
+
value: freeze({ doctype: 'cstml', version, attributes: freeze(attributes) }),
|
|
88
120
|
});
|
|
89
121
|
};
|
|
90
122
|
|
|
91
|
-
export const buildOpenNodeTag = (
|
|
92
|
-
flags = nodeFlags,
|
|
93
|
-
language = null,
|
|
94
|
-
type = null,
|
|
95
|
-
attributes = {},
|
|
96
|
-
) => {
|
|
123
|
+
export const buildOpenNodeTag = (flags = nodeFlags, type = null, attributes = {}) => {
|
|
97
124
|
if (printType(type).startsWith('https://')) throw new Error();
|
|
98
125
|
|
|
99
126
|
return freeze({
|
|
100
127
|
type: OpenNodeTag,
|
|
101
128
|
value: freeze({
|
|
102
129
|
flags: freeze(flags),
|
|
103
|
-
language,
|
|
104
130
|
type: isString(type) ? Symbol.for(type) : type,
|
|
105
131
|
attributes,
|
|
106
132
|
}),
|
|
@@ -118,12 +144,18 @@ export const buildLiteralTag = (value) => {
|
|
|
118
144
|
return freeze({ type: LiteralTag, value });
|
|
119
145
|
};
|
|
120
146
|
|
|
147
|
+
export const buildAttributeDefinition = (path, value) => {
|
|
148
|
+
return freeze({ type: AttributeDefinition, value: freeze({ path, value }) });
|
|
149
|
+
};
|
|
150
|
+
|
|
121
151
|
const flagsWithGap = new WeakMap();
|
|
122
152
|
|
|
123
|
-
export const getFlagsWithGap = (flags) => {
|
|
153
|
+
export const getFlagsWithGap = (flags, hasGap = true) => {
|
|
154
|
+
if (flags.hasGap === hasGap) return flags;
|
|
155
|
+
|
|
124
156
|
let gapFlags = flagsWithGap.get(flags);
|
|
125
157
|
if (!gapFlags) {
|
|
126
|
-
gapFlags = { ...flags, hasGap
|
|
158
|
+
gapFlags = { ...flags, hasGap };
|
|
127
159
|
flagsWithGap.set(flags, gapFlags);
|
|
128
160
|
}
|
|
129
161
|
return gapFlags;
|
|
@@ -132,6 +164,15 @@ export const getFlagsWithGap = (flags) => {
|
|
|
132
164
|
export const nodeFlags = freeze({
|
|
133
165
|
token: false,
|
|
134
166
|
hasGap: false,
|
|
167
|
+
fragment: false,
|
|
168
|
+
cover: false,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
export const fragmentFlags = freeze({
|
|
172
|
+
token: false,
|
|
173
|
+
hasGap: false,
|
|
174
|
+
fragment: true,
|
|
175
|
+
cover: false,
|
|
135
176
|
});
|
|
136
177
|
|
|
137
178
|
const hasGap = (properties) => {
|
|
@@ -149,6 +190,8 @@ const getFlags = (flags, properties) => {
|
|
|
149
190
|
export const tokenFlags = freeze({
|
|
150
191
|
token: true,
|
|
151
192
|
hasGap: false,
|
|
193
|
+
fragment: false,
|
|
194
|
+
cover: false,
|
|
152
195
|
});
|
|
153
196
|
|
|
154
197
|
export const referenceFlags = freeze({
|
package/lib/children.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
|
|
2
|
+
import {
|
|
3
|
+
BindingTag,
|
|
4
|
+
InitializerTag,
|
|
5
|
+
LiteralTag,
|
|
6
|
+
OpenNodeTag,
|
|
7
|
+
Property,
|
|
8
|
+
ReferenceTag,
|
|
9
|
+
} from './symbols.js';
|
|
10
|
+
|
|
11
|
+
const { isArray } = Array;
|
|
12
|
+
const { freeze } = Object;
|
|
13
|
+
|
|
14
|
+
export { defaultNodeSize };
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
btreeFrom: sumTreeFrom,
|
|
18
|
+
from,
|
|
19
|
+
btreeFromValues: sumTreeFromValues,
|
|
20
|
+
fromValues,
|
|
21
|
+
findBalancePoint,
|
|
22
|
+
splitValues,
|
|
23
|
+
collapses,
|
|
24
|
+
nodeCollapses,
|
|
25
|
+
nodeCanDonate,
|
|
26
|
+
pop,
|
|
27
|
+
push: push_,
|
|
28
|
+
addAt,
|
|
29
|
+
isValidNode,
|
|
30
|
+
assertValidNode,
|
|
31
|
+
getValues,
|
|
32
|
+
getSums,
|
|
33
|
+
setValues,
|
|
34
|
+
isLeafNode,
|
|
35
|
+
traverse,
|
|
36
|
+
getSize,
|
|
37
|
+
findPath,
|
|
38
|
+
getAt,
|
|
39
|
+
replaceAt,
|
|
40
|
+
} = buildModule(
|
|
41
|
+
defaultNodeSize,
|
|
42
|
+
(acc, val) => {
|
|
43
|
+
const { references, specialTypes } = acc;
|
|
44
|
+
if (isArray(val)) {
|
|
45
|
+
acc.lineBreaks += val[2].lineBreaks;
|
|
46
|
+
for (const { 0: key, 1: value } of Object.entries(val[2].references)) {
|
|
47
|
+
references[key] = (references[key] ?? 0) + value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
for (const { 0: key, 1: value } of Object.entries(val[2].specialTypes)) {
|
|
51
|
+
specialTypes[key] = (specialTypes[key] ?? 0) + value;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
if (val.type === LiteralTag) {
|
|
55
|
+
let text = val.value;
|
|
56
|
+
let idx = 0;
|
|
57
|
+
while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
|
|
58
|
+
acc.lineBreaks++;
|
|
59
|
+
}
|
|
60
|
+
} else if (val.type === ReferenceTag) {
|
|
61
|
+
const { type, name } = val.value;
|
|
62
|
+
if (type) {
|
|
63
|
+
specialTypes[type] = (specialTypes[type] ?? 0) + 1;
|
|
64
|
+
} else {
|
|
65
|
+
references[name] = (references[name] ?? 0) + 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return acc;
|
|
70
|
+
},
|
|
71
|
+
() => ({
|
|
72
|
+
lineBreaks: 0,
|
|
73
|
+
references: {},
|
|
74
|
+
specialTypes: {},
|
|
75
|
+
}),
|
|
76
|
+
(stats) => {
|
|
77
|
+
freeze(stats);
|
|
78
|
+
freeze(stats.references);
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const push = (children, tag) => {
|
|
83
|
+
let lastTag = getAt(-1, children);
|
|
84
|
+
|
|
85
|
+
if (tag.type === Property && lastTag.type !== BindingTag) {
|
|
86
|
+
throw new Error();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (lastTag?.type === ReferenceTag && ![BindingTag, InitializerTag].includes(tag.type)) {
|
|
90
|
+
throw new Error();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return push_(children, tag);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
sumTreeFrom as btreeFrom,
|
|
98
|
+
from,
|
|
99
|
+
sumTreeFromValues as btreeFromValues,
|
|
100
|
+
fromValues,
|
|
101
|
+
findBalancePoint,
|
|
102
|
+
splitValues,
|
|
103
|
+
collapses,
|
|
104
|
+
nodeCollapses,
|
|
105
|
+
nodeCanDonate,
|
|
106
|
+
pop,
|
|
107
|
+
push,
|
|
108
|
+
addAt,
|
|
109
|
+
isValidNode,
|
|
110
|
+
assertValidNode,
|
|
111
|
+
getValues,
|
|
112
|
+
getSums,
|
|
113
|
+
setValues,
|
|
114
|
+
isLeafNode,
|
|
115
|
+
traverse,
|
|
116
|
+
getSize,
|
|
117
|
+
findPath,
|
|
118
|
+
getAt,
|
|
119
|
+
replaceAt,
|
|
120
|
+
};
|
package/lib/object.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const { hasOwn, freeze, isFrozen, seal, isSealed, getPrototypeOf, getOwnPropertySymbols } =
|
|
2
|
+
Object;
|
|
3
|
+
export const { isArray } = Array;
|
|
4
|
+
|
|
5
|
+
export const has = (obj, path) => {
|
|
6
|
+
let value = obj;
|
|
7
|
+
for (const part of path) {
|
|
8
|
+
if (!hasOwn(value, part)) return false;
|
|
9
|
+
value = value[part];
|
|
10
|
+
}
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const get = (obj, path) => {
|
|
15
|
+
let value = obj;
|
|
16
|
+
for (const part of path) {
|
|
17
|
+
value = value[part];
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const set = (obj, path, value) => {
|
|
23
|
+
let obj_ = obj;
|
|
24
|
+
|
|
25
|
+
let lastKey;
|
|
26
|
+
for (let i = 0; i < path.length; i++) {
|
|
27
|
+
let key = path[i] < 0 ? obj_.length + path[i] : path[i];
|
|
28
|
+
let deeper = obj_[key];
|
|
29
|
+
|
|
30
|
+
if (path.length - 1 === i) {
|
|
31
|
+
lastKey = key;
|
|
32
|
+
} else if (deeper !== undefined) {
|
|
33
|
+
obj_ = deeper;
|
|
34
|
+
} else if (Number.isFinite(path[i + 1])) {
|
|
35
|
+
obj_ = deeper = obj_[key] = [];
|
|
36
|
+
} else {
|
|
37
|
+
obj_ = deeper = obj_[key] = {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
obj_[lastKey] = value;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const immSet = (obj, path, value) => {
|
|
45
|
+
let obj_ = obj;
|
|
46
|
+
|
|
47
|
+
let objs = [];
|
|
48
|
+
|
|
49
|
+
for (let i = 0; i < path.length; i++) {
|
|
50
|
+
let key = path[i] < 0 ? obj_.length + path[i] : path[i];
|
|
51
|
+
let deeper = obj_[key];
|
|
52
|
+
|
|
53
|
+
if (obj_) {
|
|
54
|
+
objs.push(obj_);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (path.length - 1 === i || hasOwn(obj_, deeper)) {
|
|
58
|
+
obj_ = deeper;
|
|
59
|
+
} else if (Number.isFinite(path[i + 1])) {
|
|
60
|
+
obj_ = [];
|
|
61
|
+
objs.push(obj_);
|
|
62
|
+
} else {
|
|
63
|
+
obj_ = {};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let newValue = value;
|
|
68
|
+
for (let i = objs.length - 1; i >= 0; i--) {
|
|
69
|
+
obj_ = objs[i];
|
|
70
|
+
obj_ = isArray(obj_) ? [...obj_] : { ...obj_ };
|
|
71
|
+
obj_[path[i]] = newValue;
|
|
72
|
+
freeze(obj_);
|
|
73
|
+
newValue = obj_;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return obj_;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const isObject = (obj) => obj !== null && typeof obj === 'object';
|
|
80
|
+
export const isPlainObject = (val) => val && [Object.prototype, null].includes(getPrototypeOf(val));
|
|
81
|
+
export const isFunction = (obj) => typeof obj === 'function';
|
|
82
|
+
export const isSymbol = (obj) => typeof obj === 'symbol';
|
|
83
|
+
export const isString = (obj) => typeof obj === 'string';
|
|
84
|
+
export const isType = (obj) => isSymbol(obj) || isString(obj);
|
|
85
|
+
export const isRegex = (obj) => obj instanceof RegExp;
|
|
86
|
+
export const isPattern = (obj) => isString(obj) || isRegex(obj);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CloseNodeTag, ReferenceTag } from './symbols.js';
|
|
2
|
+
|
|
3
|
+
export function* allTagPathsFor(range, options = {}) {
|
|
4
|
+
if (range == null) return;
|
|
5
|
+
|
|
6
|
+
const { unshift = false } = options;
|
|
7
|
+
let startPath = range[0];
|
|
8
|
+
let endPath = range[1];
|
|
9
|
+
let path = startPath;
|
|
10
|
+
|
|
11
|
+
while (path) {
|
|
12
|
+
if (path.inner && path.previousSibling.tag.type === ReferenceTag) {
|
|
13
|
+
path = path.inner.tagPathAt(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (path.path.depth < startPath.path.depth) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
yield path;
|
|
21
|
+
|
|
22
|
+
if (endPath && endPath.equalTo(path)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let propPath = path.path.parent && path.path.parent.tagPathAt(path.path.referenceIndex + 2);
|
|
27
|
+
|
|
28
|
+
if (endPath && path.tag.type === CloseNodeTag && propPath && endPath.equalTo(propPath)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
path = unshift ? path.nextUnshifted : path.next;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function* allTagsFor(range, options = {}) {
|
|
36
|
+
for (let path of allTagPathsFor(range, options)) {
|
|
37
|
+
yield path.tag;
|
|
38
|
+
}
|
|
39
|
+
}
|