@bablr/agast-helpers 0.7.1 → 0.9.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 +110 -49
- package/lib/object.js +86 -0
- package/lib/path-facade.js +44 -0
- package/lib/path.js +780 -556
- package/lib/print.js +75 -97
- package/lib/shorthand.js +26 -1
- package/lib/stream.js +55 -163
- package/lib/symbols.js +6 -2
- package/lib/tags.js +236 -0
- package/lib/template.js +28 -37
- package/lib/tree.js +391 -213
- package/package.json +11 -6
- package/lib/sumtree.js +0 -62
package/lib/builders.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isSymbol } from './object.js';
|
|
2
2
|
import { printType } from './print.js';
|
|
3
3
|
import {
|
|
4
4
|
DoctypeTag,
|
|
@@ -10,49 +10,63 @@ import {
|
|
|
10
10
|
NullTag,
|
|
11
11
|
InitializerTag,
|
|
12
12
|
LiteralTag,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
AttributeDefinition,
|
|
14
|
+
BindingTag,
|
|
15
|
+
Document,
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (isArray(value)) {
|
|
25
|
-
for (let value of btree.traverse(value)) {
|
|
26
|
-
yield value.node;
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
yield value.node;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
21
|
+
export const buildProperty = (reference, binding = null, node = undefined) => {
|
|
22
|
+
if (node?.binding) throw new Error();
|
|
23
|
+
if (!reference.flags) throw new Error();
|
|
24
|
+
if (!isArray(node) && typeof node === 'object' && !hasOwn(node, 'tags')) throw new Error();
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
26
|
+
if (reference.value) throw new Error();
|
|
27
|
+
|
|
28
|
+
return freeze({ reference, binding, node });
|
|
38
29
|
};
|
|
39
30
|
|
|
40
|
-
export const
|
|
41
|
-
|
|
31
|
+
export const buildPropertyWrapper = (tags, property) => {
|
|
32
|
+
freeze(tags);
|
|
33
|
+
freeze(property);
|
|
34
|
+
|
|
35
|
+
if (![ReferenceTag, ShiftTag].includes(tags[0].type)) throw new Error();
|
|
36
|
+
if (property.node && !(tags[1]?.type === InitializerTag || tags.length === 3)) throw new Error();
|
|
37
|
+
|
|
38
|
+
return freeze({ tags, property });
|
|
42
39
|
};
|
|
43
40
|
|
|
44
|
-
export const
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
export const buildDocument = (doctypeTag, fragment) => {
|
|
42
|
+
return freeze({ type: Document, value: freeze({ doctypeTag, fragment }) });
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const buildFacadeProperty = (reference, binding, node) => {
|
|
46
|
+
if (node?.binding) throw new Error();
|
|
47
|
+
if (!reference.flags) throw new Error();
|
|
48
|
+
if (!isArray(node) && typeof node === 'object' && !node.tags) throw new Error();
|
|
49
|
+
|
|
50
|
+
if (reference.value) throw new Error();
|
|
51
|
+
|
|
52
|
+
return freeze({ reference, binding, node });
|
|
47
53
|
};
|
|
48
54
|
|
|
49
55
|
export const buildBeginningOfStreamToken = () => {
|
|
50
56
|
return freeze({ type: Symbol.for('@bablr/beginning-of-stream'), value: undefined });
|
|
51
57
|
};
|
|
52
58
|
|
|
53
|
-
export const buildReferenceTag = (
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
export const buildReferenceTag = (
|
|
60
|
+
type = null,
|
|
61
|
+
name = null,
|
|
62
|
+
isArray = false,
|
|
63
|
+
flags = referenceFlags,
|
|
64
|
+
index,
|
|
65
|
+
) => {
|
|
66
|
+
if (type != null && !['.', '#', '@', '_'].includes(type)) throw new Error();
|
|
67
|
+
if (name != null && !isString(name)) throw new Error();
|
|
68
|
+
if (name == null && type == null) throw new Error();
|
|
69
|
+
if (index) throw new Error();
|
|
56
70
|
let { hasGap, expression } = flags;
|
|
57
71
|
|
|
58
72
|
hasGap = !!hasGap;
|
|
@@ -60,49 +74,82 @@ export const buildReferenceTag = (name, isArray = false, flags = referenceFlags,
|
|
|
60
74
|
|
|
61
75
|
return freeze({
|
|
62
76
|
type: ReferenceTag,
|
|
63
|
-
value: freeze({ name, isArray,
|
|
77
|
+
value: freeze({ type, name, isArray, flags: freeze({ hasGap, expression }) }),
|
|
64
78
|
});
|
|
65
79
|
};
|
|
66
80
|
|
|
81
|
+
export const buildReference = (
|
|
82
|
+
type = null,
|
|
83
|
+
name = null,
|
|
84
|
+
isArray = false,
|
|
85
|
+
flags = referenceFlags,
|
|
86
|
+
index,
|
|
87
|
+
) => {
|
|
88
|
+
return buildReferenceTag(type, name, isArray, flags, index).value;
|
|
89
|
+
};
|
|
90
|
+
|
|
67
91
|
export const buildNullTag = () => {
|
|
68
92
|
return freeze({ type: NullTag, value: undefined });
|
|
69
93
|
};
|
|
70
94
|
|
|
95
|
+
export const buildInitializer = (isArray = false) => {
|
|
96
|
+
return freeze({ isArray });
|
|
97
|
+
};
|
|
98
|
+
|
|
71
99
|
export const buildInitializerTag = (isArray = false) => {
|
|
72
|
-
return freeze({ type: InitializerTag, value:
|
|
100
|
+
return freeze({ type: InitializerTag, value: buildInitializer(isArray) });
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const buildBinding = (languagePath = []) => {
|
|
104
|
+
if (!isArray(languagePath)) throw new Error();
|
|
105
|
+
return freeze({ languagePath });
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const buildBindingTag = (languagePath = []) => {
|
|
109
|
+
if (!isArray(languagePath)) throw new Error();
|
|
110
|
+
return freeze({ type: BindingTag, value: freeze({ languagePath }) });
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const buildChild = (type, value) => {
|
|
114
|
+
if (!isSymbol(type)) throw new Error();
|
|
115
|
+
return freeze({ type, value });
|
|
73
116
|
};
|
|
74
117
|
|
|
75
118
|
export const buildGapTag = () => {
|
|
76
119
|
return freeze({ type: GapTag, value: undefined });
|
|
77
120
|
};
|
|
78
121
|
|
|
79
|
-
export const buildShiftTag = (index) => {
|
|
122
|
+
export const buildShiftTag = (index, height) => {
|
|
80
123
|
if (!Number.isFinite(index)) throw new Error();
|
|
81
|
-
|
|
124
|
+
if (!Number.isFinite(height)) throw new Error();
|
|
125
|
+
return freeze({ type: ShiftTag, value: freeze({ index, height }) });
|
|
82
126
|
};
|
|
83
127
|
|
|
84
|
-
export const buildDoctypeTag = (
|
|
128
|
+
export const buildDoctypeTag = (version = 0) => {
|
|
85
129
|
return freeze({
|
|
86
130
|
type: DoctypeTag,
|
|
87
|
-
value: { doctype: 'cstml', version
|
|
131
|
+
value: freeze({ doctype: 'cstml', version }),
|
|
88
132
|
});
|
|
89
133
|
};
|
|
90
134
|
|
|
91
135
|
export const buildOpenNodeTag = (
|
|
92
136
|
flags = nodeFlags,
|
|
93
|
-
language = null,
|
|
94
137
|
type = null,
|
|
95
138
|
attributes = {},
|
|
139
|
+
literalValue = null,
|
|
140
|
+
selfClosing = !!literalValue,
|
|
96
141
|
) => {
|
|
97
142
|
if (printType(type).startsWith('https://')) throw new Error();
|
|
143
|
+
if (literalValue && (!isString(literalValue) || !flags.token)) throw new Error();
|
|
98
144
|
|
|
99
145
|
return freeze({
|
|
100
146
|
type: OpenNodeTag,
|
|
101
147
|
value: freeze({
|
|
102
148
|
flags: freeze(flags),
|
|
103
|
-
language,
|
|
104
149
|
type: isString(type) ? Symbol.for(type) : type,
|
|
150
|
+
literalValue,
|
|
105
151
|
attributes,
|
|
152
|
+
selfClosing,
|
|
106
153
|
}),
|
|
107
154
|
});
|
|
108
155
|
};
|
|
@@ -118,12 +165,20 @@ export const buildLiteralTag = (value) => {
|
|
|
118
165
|
return freeze({ type: LiteralTag, value });
|
|
119
166
|
};
|
|
120
167
|
|
|
168
|
+
export const buildAttributeDefinition = (path, value) => {
|
|
169
|
+
if (!path?.length) throw new Error();
|
|
170
|
+
freeze(path);
|
|
171
|
+
return freeze({ type: AttributeDefinition, value: freeze({ path, value }) });
|
|
172
|
+
};
|
|
173
|
+
|
|
121
174
|
const flagsWithGap = new WeakMap();
|
|
122
175
|
|
|
123
|
-
export const getFlagsWithGap = (flags) => {
|
|
176
|
+
export const getFlagsWithGap = (flags, hasGap = true) => {
|
|
177
|
+
if (flags.hasGap === hasGap) return flags;
|
|
178
|
+
|
|
124
179
|
let gapFlags = flagsWithGap.get(flags);
|
|
125
180
|
if (!gapFlags) {
|
|
126
|
-
gapFlags = { ...flags, hasGap
|
|
181
|
+
gapFlags = { ...flags, hasGap };
|
|
127
182
|
flagsWithGap.set(flags, gapFlags);
|
|
128
183
|
}
|
|
129
184
|
return gapFlags;
|
|
@@ -132,23 +187,29 @@ export const getFlagsWithGap = (flags) => {
|
|
|
132
187
|
export const nodeFlags = freeze({
|
|
133
188
|
token: false,
|
|
134
189
|
hasGap: false,
|
|
190
|
+
fragment: false,
|
|
191
|
+
cover: false,
|
|
135
192
|
});
|
|
136
193
|
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
194
|
+
export const fragmentFlags = freeze({
|
|
195
|
+
token: false,
|
|
196
|
+
hasGap: false,
|
|
197
|
+
fragment: true,
|
|
198
|
+
cover: true,
|
|
199
|
+
});
|
|
140
200
|
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
};
|
|
201
|
+
export const multiFragmentFlags = freeze({
|
|
202
|
+
token: false,
|
|
203
|
+
hasGap: false,
|
|
204
|
+
fragment: true,
|
|
205
|
+
cover: false,
|
|
206
|
+
});
|
|
148
207
|
|
|
149
208
|
export const tokenFlags = freeze({
|
|
150
209
|
token: true,
|
|
151
210
|
hasGap: false,
|
|
211
|
+
fragment: false,
|
|
212
|
+
cover: false,
|
|
152
213
|
});
|
|
153
214
|
|
|
154
215
|
export const referenceFlags = freeze({
|
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,44 @@
|
|
|
1
|
+
import { CloseNodeTag, OpenNodeTag, 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 tagPath = startPath;
|
|
10
|
+
|
|
11
|
+
while (tagPath) {
|
|
12
|
+
if (tagPath.inner && tagPath.previousSibling.tag.type === ReferenceTag) {
|
|
13
|
+
tagPath = tagPath.inner.tagPathAt(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (tagPath.path.depth < startPath.path.depth) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
yield tagPath;
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
tagPath.tag.type === CloseNodeTag ||
|
|
24
|
+
(tagPath.tag.type === OpenNodeTag && tagPath.tag.value.selfClosing)
|
|
25
|
+
) {
|
|
26
|
+
let propPath = tagPath.path.parentPropertyPath;
|
|
27
|
+
if (endPath && propPath && endPath.equalTo(propPath.path.tagPathAt(propPath.tagsIndex, 2))) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (endPath && endPath.equalTo(tagPath)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
tagPath = unshift ? tagPath.nextUnshifted : tagPath.next;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function* allTagsFor(range, options = {}) {
|
|
41
|
+
for (let path of allTagPathsFor(range, options)) {
|
|
42
|
+
yield path.tag;
|
|
43
|
+
}
|
|
44
|
+
}
|