@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 CHANGED
@@ -11,14 +11,13 @@ import {
11
11
  InitializerTag,
12
12
  LiteralTag,
13
13
  TokenGroup,
14
- EmbeddedNode,
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 buildTokenGroup = (tokens) => {
41
- return freeze({ type: TokenGroup, value: tokens });
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 buildEmbeddedNode = (node) => {
45
- if (!isObject(node)) throw new Error();
46
- return freeze({ type: EmbeddedNode, value: node });
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 = (name, isArray = false, flags = referenceFlags, index = null) => {
54
- if (name == null || !/[a-zA-Z.#@]/.test(name)) throw new Error('reference must have a name');
55
- if (index != null && !Number.isFinite(index)) throw new Error();
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, index, flags: freeze({ hasGap, expression }) }),
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
- return freeze({ type: ShiftTag, value: freeze({ index }) });
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: 0, attributes: freeze(attributes) },
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: true };
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({
@@ -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
+ }