@traqula/core 0.0.16 → 0.0.18
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/README.md +51 -3
- package/lib/Transformers.d.ts +76 -17
- package/lib/Transformers.js +200 -88
- package/lib/Transformers.js.map +1 -1
- package/lib/generator-builder/generatorTypes.d.ts +47 -1
- package/lib/generator-builder/generatorTypes.js.map +1 -1
- package/lib/index.cjs +202 -88
- package/lib/indirection-builder/helpers.d.ts +7 -1
- package/lib/indirection-builder/helpers.js.map +1 -1
- package/lib/parser-builder/dynamicParser.js +1 -1
- package/lib/parser-builder/dynamicParser.js.map +1 -1
- package/lib/parser-builder/parserBuilder.js +1 -0
- package/lib/parser-builder/parserBuilder.js.map +1 -1
- package/lib/parser-builder/ruleDefTypes.d.ts +6 -0
- package/lib/parser-builder/ruleDefTypes.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -51,9 +51,9 @@ Creating a builder is as easy as:
|
|
|
51
51
|
const sparql11Tokens = LexerBuilder.create(<const> [select, describe]);
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
A new lexer can be created from an existing one by calling:
|
|
54
|
+
A new lexer can be created from an existing one, and altered by calling:
|
|
55
55
|
```typescript
|
|
56
|
-
const sparql11AdjustTokens = sparql11Tokens.addBefore(select, BuiltInAdjust);
|
|
56
|
+
const sparql11AdjustTokens = LexerBuilder.create(sparql11Tokens).addBefore(select, BuiltInAdjust);
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
### Parser Builder
|
|
@@ -96,6 +96,22 @@ Rules can be [parameterized](https://chevrotain.io/docs/features/parameterized_r
|
|
|
96
96
|
Personally I create a function that can be used to create multiple `ParserRule` objects.
|
|
97
97
|
The result of a rule should match the type provided in the `ParserRule` definition, and is the result of a call of `SUBRULE` with that rule.
|
|
98
98
|
|
|
99
|
+
##### Testing the correctness of your parser
|
|
100
|
+
By default, the parser builder will construct a parser that does not perform validation (to be more speedy).
|
|
101
|
+
When creating a parser, you best enable the validation by passing a context to the parser builder like:
|
|
102
|
+
```typescript
|
|
103
|
+
const context = {
|
|
104
|
+
tokenVocabulary: myLexerVoc,
|
|
105
|
+
lexerConfig: {
|
|
106
|
+
skipValidations: false,
|
|
107
|
+
ensureOptimizations: true,
|
|
108
|
+
},
|
|
109
|
+
parserConfig: {
|
|
110
|
+
skipValidations: false,
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
99
115
|
#### Patching rules
|
|
100
116
|
|
|
101
117
|
When a rule definition calls to a subrule using `SUBRULE(mySub)`, the implementation itself is not necessarily called.
|
|
@@ -133,6 +149,38 @@ The idea is that GeneratorRules and ParserRules can be tied together in the same
|
|
|
133
149
|
*/
|
|
134
150
|
export const iri: GeneratorRule<'iri', IriTerm> = <const> {
|
|
135
151
|
name: 'iri',
|
|
136
|
-
gImpl: () => ast => ast.value,
|
|
152
|
+
gImpl: ({ PRINT }) => ast => { PRINT(ast.value) },
|
|
137
153
|
};
|
|
138
154
|
```
|
|
155
|
+
|
|
156
|
+
While implementing a generator, you can easily support pretty print indentation manipulating `traqulaIndentation` context item.
|
|
157
|
+
The key for this context item can be accessed like:
|
|
158
|
+
```typescript
|
|
159
|
+
import { traqulaIndentation } from '@traqula/core';
|
|
160
|
+
C[traqulaIndentation] += 2;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### A word on round tripping:
|
|
164
|
+
|
|
165
|
+
The generator builder can significantly help you with creating a round tripping parser.
|
|
166
|
+
Basically what that allows you to do is to keep information that the AST finds 'unimportant' within the generated string.
|
|
167
|
+
Take for example capitalization and spaces in the sparql spec.
|
|
168
|
+
Both are ignored in the AST, but if you want to generate the same string out of your AST, yuo need to store them somewhere.
|
|
169
|
+
Traqula helps you store this information using it's `Node` `Localization`.
|
|
170
|
+
|
|
171
|
+
Localization basically allows you to remember what _portion of the original string_ a node represents.
|
|
172
|
+
Take for example the `SENTENCE`: `I Love Traqula`, If we ignore spaces and caps in the ast, a valid representation would be:
|
|
173
|
+
```
|
|
174
|
+
SENTENCE-node{ words: [ WORD-node{ value: "i" }, WORD-node{ value: "love" }, WORD-node{ value: "traqula" } ] }
|
|
175
|
+
```
|
|
176
|
+
If we generated we would loe the capitalisation and get: `i love traqula` for example.
|
|
177
|
+
Round tripping will add a `source localization` for each node,
|
|
178
|
+
we therefore register that our SENTENCE starts at 0 and ends at 19, while our words have ranges 0-1, 2-6, 12-19.
|
|
179
|
+
Using this information our generator can reconstruct the original string (given the original string).
|
|
180
|
+
The magic happens when we start manipulating the words, so imagine we want to lowercase the word 'Love',
|
|
181
|
+
we would simply annotate in the `localization` that the node should be generated (and not reconstructed),
|
|
182
|
+
and we can generate the sentence: `I love Traqula`.
|
|
183
|
+
|
|
184
|
+
To support this feature, the generator requires that your AST follows a tree structure with respect to the ranges.
|
|
185
|
+
That means that a node cannot start later, or end earlier than its children.
|
|
186
|
+
In our example: A sentence cannot start after the first word start, nor can it end before the last word ends.
|
package/lib/Transformers.d.ts
CHANGED
|
@@ -3,35 +3,68 @@ type Safeness = 'safe' | 'unsafe';
|
|
|
3
3
|
type SafeWrap<Safe extends Safeness, obj extends object> = Safe extends 'safe' ? {
|
|
4
4
|
[key in keyof obj]: unknown;
|
|
5
5
|
} : obj;
|
|
6
|
+
export interface VisitContext {
|
|
7
|
+
shortcut?: boolean;
|
|
8
|
+
continue?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface SelectiveTraversalContext<Nodes> {
|
|
11
|
+
next?: Nodes[];
|
|
12
|
+
shortcut?: boolean;
|
|
13
|
+
}
|
|
6
14
|
export declare class TransformerType<Nodes extends Pick<Node, 'type'>> {
|
|
15
|
+
protected clone<T>(obj: T): T;
|
|
7
16
|
protected safeObjectVisit(value: unknown, mapper: (some: object) => any): unknown;
|
|
8
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Recursively transforms all objects that are not arrays. Mapper is called on deeper objects first.
|
|
19
|
+
* @param startObject object to start iterating from
|
|
20
|
+
* @param mapper mapper to transform the various objects - argument is a copy of the original
|
|
21
|
+
* @param preVisitor callback that is evaluated before iterating deeper.
|
|
22
|
+
* If continues is false, we do not iterate deeper, current object is still mapped. - default: true
|
|
23
|
+
* If shortcut is true, we do not iterate deeper, nor do we branch out, this mapper will be the last one called.
|
|
24
|
+
* - Default false
|
|
25
|
+
*/
|
|
26
|
+
transformObject(startObject: object, mapper: (some: object) => any, preVisitor?: (some: object) => VisitContext): unknown;
|
|
27
|
+
/**
|
|
28
|
+
* Visitor that visits all objects. Visits deeper objects first.
|
|
29
|
+
*/
|
|
30
|
+
visitObject(startObject: object, visitor: (some: object) => void, preVisitor?: (some: object) => VisitContext): void;
|
|
31
|
+
transformNode<Safe extends 'safe' | 'unsafe' = 'safe'>(startObject: object, nodeCallBacks: {
|
|
9
32
|
[T in Nodes['type']]?: {
|
|
10
33
|
transform?: (op: SafeWrap<Safe, Extract<Nodes, {
|
|
11
34
|
type: T;
|
|
12
35
|
}>>) => any;
|
|
13
|
-
|
|
36
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
14
37
|
type: T;
|
|
15
|
-
}>) =>
|
|
38
|
+
}>) => VisitContext;
|
|
16
39
|
};
|
|
17
40
|
}): any;
|
|
18
|
-
visitNode(
|
|
41
|
+
visitNode(startObject: object, nodeCallBacks: {
|
|
42
|
+
[T in Nodes['type']]?: {
|
|
43
|
+
visitor?: (op: Extract<Nodes, {
|
|
44
|
+
type: T;
|
|
45
|
+
}>) => void;
|
|
46
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
47
|
+
type: T;
|
|
48
|
+
}>) => VisitContext;
|
|
49
|
+
};
|
|
50
|
+
}): void;
|
|
51
|
+
traverseNodes(currentNode: Nodes, traverse: {
|
|
19
52
|
[T in Nodes['type']]?: (op: Extract<Nodes, {
|
|
20
53
|
type: T;
|
|
21
|
-
}>) =>
|
|
54
|
+
}>) => SelectiveTraversalContext<Nodes>;
|
|
22
55
|
}): void;
|
|
23
56
|
}
|
|
24
57
|
export declare class TransformerSubType<Nodes extends Pick<Node, 'type' | 'subType'>> extends TransformerType<Nodes> {
|
|
25
|
-
transformNodeSpecific<Safe extends 'safe' | 'unsafe' = 'safe'>(
|
|
58
|
+
transformNodeSpecific<Safe extends 'safe' | 'unsafe' = 'safe'>(startObject: object, nodeCallBacks: {
|
|
26
59
|
[T in Nodes['type']]?: {
|
|
27
60
|
transform?: (op: SafeWrap<Safe, Extract<Nodes, {
|
|
28
61
|
type: T;
|
|
29
62
|
}>>) => any;
|
|
30
|
-
|
|
63
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
31
64
|
type: T;
|
|
32
|
-
}>) =>
|
|
65
|
+
}>) => VisitContext;
|
|
33
66
|
};
|
|
34
|
-
}, nodeSpecificCallBacks
|
|
67
|
+
}, nodeSpecificCallBacks: {
|
|
35
68
|
[Type in Nodes['type']]?: {
|
|
36
69
|
[SubType in Extract<Nodes, {
|
|
37
70
|
type: Type;
|
|
@@ -41,21 +74,47 @@ export declare class TransformerSubType<Nodes extends Pick<Node, 'type' | 'subTy
|
|
|
41
74
|
type: Type;
|
|
42
75
|
subType: SubType;
|
|
43
76
|
}>>) => any;
|
|
44
|
-
|
|
77
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
45
78
|
type: Type;
|
|
46
79
|
subType: SubType;
|
|
47
|
-
}>) =>
|
|
80
|
+
}>) => VisitContext;
|
|
48
81
|
};
|
|
49
82
|
};
|
|
50
83
|
}): any;
|
|
51
84
|
/**
|
|
52
85
|
* When both nodeCallBack and NodeSpecific callBack are matched, will only look at nodeSpecifCallback
|
|
53
86
|
*/
|
|
54
|
-
visitNodeSpecific(
|
|
55
|
-
[T in Nodes['type']]?:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
visitNodeSpecific(startObject: object, nodeCallBacks: {
|
|
88
|
+
[T in Nodes['type']]?: {
|
|
89
|
+
visitor?: (op: Extract<Nodes, {
|
|
90
|
+
type: T;
|
|
91
|
+
}>) => void;
|
|
92
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
93
|
+
type: T;
|
|
94
|
+
}>) => VisitContext;
|
|
95
|
+
};
|
|
96
|
+
}, nodeSpecificCallBacks: {
|
|
97
|
+
[Type in Nodes['type']]?: {
|
|
98
|
+
[Subtype in Extract<Nodes, {
|
|
99
|
+
type: Type;
|
|
100
|
+
subType: string;
|
|
101
|
+
}>['subType']]?: {
|
|
102
|
+
visitor?: (op: Extract<Nodes, {
|
|
103
|
+
type: Type;
|
|
104
|
+
subType: Subtype;
|
|
105
|
+
}>) => void;
|
|
106
|
+
preVisitor?: (op: Extract<Nodes, {
|
|
107
|
+
type: Type;
|
|
108
|
+
subType: Subtype;
|
|
109
|
+
}>) => VisitContext;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
}): void;
|
|
113
|
+
traverseSubNodes(currentNode: Nodes, traverseNode: {
|
|
114
|
+
[Type in Nodes['type']]?: (op: Extract<Nodes, {
|
|
115
|
+
type: Type;
|
|
116
|
+
}>) => SelectiveTraversalContext<Nodes>;
|
|
117
|
+
}, traverseSubNode: {
|
|
59
118
|
[Type in Nodes['type']]?: {
|
|
60
119
|
[Subtype in Extract<Nodes, {
|
|
61
120
|
type: Type;
|
|
@@ -63,7 +122,7 @@ export declare class TransformerSubType<Nodes extends Pick<Node, 'type' | 'subTy
|
|
|
63
122
|
}>['subType']]?: (op: Extract<Nodes, {
|
|
64
123
|
type: Type;
|
|
65
124
|
subType: Subtype;
|
|
66
|
-
}>) =>
|
|
125
|
+
}>) => SelectiveTraversalContext<Nodes>;
|
|
67
126
|
};
|
|
68
127
|
}): void;
|
|
69
128
|
}
|
package/lib/Transformers.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export class TransformerType {
|
|
2
|
+
clone(obj) {
|
|
3
|
+
const newObj = Object.create(Object.getPrototypeOf(obj));
|
|
4
|
+
Object.defineProperties(newObj, Object.getOwnPropertyDescriptors(obj));
|
|
5
|
+
return newObj;
|
|
6
|
+
}
|
|
2
7
|
safeObjectVisit(value, mapper) {
|
|
3
8
|
if (value && typeof value === 'object') {
|
|
4
|
-
// If you wonder why this is all so hard, this is the reason. We cannot lose the methods of our Array objects
|
|
5
9
|
if (Array.isArray(value)) {
|
|
6
10
|
return value.map(x => this.safeObjectVisit(x, mapper));
|
|
7
11
|
}
|
|
@@ -9,106 +13,214 @@ export class TransformerType {
|
|
|
9
13
|
}
|
|
10
14
|
return value;
|
|
11
15
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Recursively transforms all objects that are not arrays. Mapper is called on deeper objects first.
|
|
18
|
+
* @param startObject object to start iterating from
|
|
19
|
+
* @param mapper mapper to transform the various objects - argument is a copy of the original
|
|
20
|
+
* @param preVisitor callback that is evaluated before iterating deeper.
|
|
21
|
+
* If continues is false, we do not iterate deeper, current object is still mapped. - default: true
|
|
22
|
+
* If shortcut is true, we do not iterate deeper, nor do we branch out, this mapper will be the last one called.
|
|
23
|
+
* - Default false
|
|
24
|
+
*/
|
|
25
|
+
transformObject(startObject, mapper, preVisitor = () => ({})) {
|
|
26
|
+
let didShortCut = false;
|
|
27
|
+
const recurse = (curObject) => {
|
|
28
|
+
const copy = this.clone(curObject);
|
|
29
|
+
const context = preVisitor(copy);
|
|
30
|
+
didShortCut = context.shortcut ?? false;
|
|
31
|
+
const continues = context.continue ?? true;
|
|
32
|
+
if (continues && !didShortCut) {
|
|
33
|
+
for (const [key, value] of Object.entries(copy)) {
|
|
34
|
+
if (didShortCut) {
|
|
35
|
+
return copy;
|
|
36
|
+
}
|
|
37
|
+
copy[key] =
|
|
38
|
+
this.safeObjectVisit(value, obj => recurse(obj));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return mapper(copy);
|
|
42
|
+
};
|
|
43
|
+
return recurse(startObject);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Visitor that visits all objects. Visits deeper objects first.
|
|
47
|
+
*/
|
|
48
|
+
visitObject(startObject, visitor, preVisitor = () => ({})) {
|
|
49
|
+
let didShortCut = false;
|
|
50
|
+
const recurse = (curObject) => {
|
|
51
|
+
const context = preVisitor(curObject);
|
|
52
|
+
didShortCut = context.shortcut ?? false;
|
|
53
|
+
const continues = context.continue ?? true;
|
|
54
|
+
if (continues && !didShortCut) {
|
|
55
|
+
for (const value of Object.values(curObject)) {
|
|
56
|
+
if (didShortCut) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.safeObjectVisit(value, obj => recurse(obj));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
visitor(curObject);
|
|
63
|
+
};
|
|
64
|
+
recurse(startObject);
|
|
65
|
+
}
|
|
66
|
+
transformNode(startObject, nodeCallBacks) {
|
|
67
|
+
const transformWrapper = (curObject) => {
|
|
68
|
+
const casted = curObject;
|
|
69
|
+
if (casted.type) {
|
|
70
|
+
const ogFunc = nodeCallBacks[casted.type]?.transform;
|
|
71
|
+
if (ogFunc) {
|
|
72
|
+
return ogFunc(casted);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
25
75
|
return curObject;
|
|
26
|
-
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
76
|
+
};
|
|
77
|
+
const preTransformWrapper = (curObject) => {
|
|
78
|
+
const casted = curObject;
|
|
79
|
+
if (casted.type) {
|
|
80
|
+
const ogFunc = nodeCallBacks[casted.type]?.preVisitor;
|
|
81
|
+
if (ogFunc) {
|
|
82
|
+
return ogFunc(casted);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {};
|
|
86
|
+
};
|
|
87
|
+
return this.transformObject(startObject, transformWrapper, preTransformWrapper);
|
|
36
88
|
}
|
|
37
|
-
visitNode(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
shouldIterate = callback(curObject);
|
|
46
|
-
}
|
|
47
|
-
if (shouldIterate) {
|
|
48
|
-
for (const value of Object.values(curObject)) {
|
|
49
|
-
this.safeObjectVisit(value, obj => this.visitNode(obj, nodeCallBacks));
|
|
89
|
+
visitNode(startObject, nodeCallBacks) {
|
|
90
|
+
const visitWrapper = (curObject) => {
|
|
91
|
+
const casted = curObject;
|
|
92
|
+
if (casted.type) {
|
|
93
|
+
const ogFunc = nodeCallBacks[casted.type]?.visitor;
|
|
94
|
+
if (ogFunc) {
|
|
95
|
+
ogFunc(casted);
|
|
96
|
+
}
|
|
50
97
|
}
|
|
51
|
-
}
|
|
98
|
+
};
|
|
99
|
+
const preVisitWrapper = (curObject) => {
|
|
100
|
+
const casted = curObject;
|
|
101
|
+
if (casted.type) {
|
|
102
|
+
const ogFunc = nodeCallBacks[casted.type]?.preVisitor;
|
|
103
|
+
if (ogFunc) {
|
|
104
|
+
return ogFunc(casted);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return {};
|
|
108
|
+
};
|
|
109
|
+
this.visitObject(startObject, visitWrapper, preVisitWrapper);
|
|
110
|
+
}
|
|
111
|
+
traverseNodes(currentNode, traverse) {
|
|
112
|
+
let didShortCut = false;
|
|
113
|
+
const recurse = (curNode) => {
|
|
114
|
+
const traverser = traverse[curNode.type];
|
|
115
|
+
if (traverser) {
|
|
116
|
+
const { next, shortcut } = traverser(curNode);
|
|
117
|
+
didShortCut = shortcut ?? false;
|
|
118
|
+
if (!didShortCut) {
|
|
119
|
+
for (const node of next ?? []) {
|
|
120
|
+
if (didShortCut) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
recurse(node);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
recurse(currentNode);
|
|
52
129
|
}
|
|
53
130
|
}
|
|
54
131
|
export class TransformerSubType extends TransformerType {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
continueCheck = specific[casted.subType]?.continue;
|
|
68
|
-
transformation = specific[casted.subType]?.transform;
|
|
132
|
+
transformNodeSpecific(startObject, nodeCallBacks, nodeSpecificCallBacks) {
|
|
133
|
+
const transformWrapper = (curObject) => {
|
|
134
|
+
let ogTransform;
|
|
135
|
+
const casted = curObject;
|
|
136
|
+
if (casted.type && casted.subType) {
|
|
137
|
+
const specific = nodeSpecificCallBacks[casted.type];
|
|
138
|
+
if (specific) {
|
|
139
|
+
ogTransform = specific[casted.subType]?.transform;
|
|
140
|
+
}
|
|
141
|
+
if (!ogTransform) {
|
|
142
|
+
ogTransform = nodeCallBacks[casted.type]?.transform;
|
|
143
|
+
}
|
|
69
144
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
return
|
|
145
|
+
return ogTransform ? ogTransform(casted) : curObject;
|
|
146
|
+
};
|
|
147
|
+
const preVisitWrapper = (curObject) => {
|
|
148
|
+
let ogPreVisit;
|
|
149
|
+
const casted = curObject;
|
|
150
|
+
if (casted.type && casted.subType) {
|
|
151
|
+
const specific = nodeSpecificCallBacks[casted.type];
|
|
152
|
+
if (specific) {
|
|
153
|
+
ogPreVisit = specific[casted.subType]?.preVisitor;
|
|
154
|
+
}
|
|
155
|
+
if (!ogPreVisit) {
|
|
156
|
+
ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return ogPreVisit ? ogPreVisit(casted) : curObject;
|
|
160
|
+
};
|
|
161
|
+
return this.transformObject(startObject, transformWrapper, preVisitWrapper);
|
|
87
162
|
}
|
|
88
163
|
/**
|
|
89
164
|
* When both nodeCallBack and NodeSpecific callBack are matched, will only look at nodeSpecifCallback
|
|
90
165
|
*/
|
|
91
|
-
visitNodeSpecific(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
166
|
+
visitNodeSpecific(startObject, nodeCallBacks, nodeSpecificCallBacks) {
|
|
167
|
+
const visitWrapper = (curObject) => {
|
|
168
|
+
let ogTransform;
|
|
169
|
+
const casted = curObject;
|
|
170
|
+
if (casted.type && casted.subType) {
|
|
171
|
+
const specific = nodeSpecificCallBacks[casted.type];
|
|
172
|
+
if (specific) {
|
|
173
|
+
ogTransform = specific[casted.subType]?.visitor;
|
|
174
|
+
}
|
|
175
|
+
if (!ogTransform) {
|
|
176
|
+
ogTransform = nodeCallBacks[casted.type]?.visitor;
|
|
177
|
+
}
|
|
98
178
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
callback = nodeCallBacks[curObject.type];
|
|
102
|
-
}
|
|
103
|
-
let shouldIterate = true;
|
|
104
|
-
if (callback) {
|
|
105
|
-
shouldIterate = callback(curObject) ?? true;
|
|
106
|
-
}
|
|
107
|
-
if (shouldIterate) {
|
|
108
|
-
for (const value of Object.values(curObject)) {
|
|
109
|
-
this.safeObjectVisit(value, obj => this.visitNodeSpecific(obj, nodeCallBacks, nodeSpecificCallBacks));
|
|
179
|
+
if (ogTransform) {
|
|
180
|
+
ogTransform(casted);
|
|
110
181
|
}
|
|
111
|
-
}
|
|
182
|
+
};
|
|
183
|
+
const preVisitWrapper = (curObject) => {
|
|
184
|
+
let ogPreVisit;
|
|
185
|
+
const casted = curObject;
|
|
186
|
+
if (casted.type && casted.subType) {
|
|
187
|
+
const specific = nodeSpecificCallBacks[casted.type];
|
|
188
|
+
if (specific) {
|
|
189
|
+
ogPreVisit = specific[casted.subType]?.preVisitor;
|
|
190
|
+
}
|
|
191
|
+
if (!ogPreVisit) {
|
|
192
|
+
ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return ogPreVisit ? ogPreVisit(casted) : curObject;
|
|
196
|
+
};
|
|
197
|
+
this.visitObject(startObject, visitWrapper, preVisitWrapper);
|
|
198
|
+
}
|
|
199
|
+
traverseSubNodes(currentNode, traverseNode, traverseSubNode) {
|
|
200
|
+
let didShortCut = false;
|
|
201
|
+
const recurse = (curNode) => {
|
|
202
|
+
let traverser;
|
|
203
|
+
const subObj = traverseSubNode[curNode.type];
|
|
204
|
+
if (subObj) {
|
|
205
|
+
traverser = subObj[curNode.subType];
|
|
206
|
+
}
|
|
207
|
+
if (!traverser) {
|
|
208
|
+
traverser = traverseNode[curNode.type];
|
|
209
|
+
}
|
|
210
|
+
if (traverser) {
|
|
211
|
+
const { next, shortcut } = traverser(curNode);
|
|
212
|
+
didShortCut = shortcut ?? false;
|
|
213
|
+
if (!didShortCut) {
|
|
214
|
+
for (const node of next ?? []) {
|
|
215
|
+
if (didShortCut) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
recurse(node);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
recurse(currentNode);
|
|
112
224
|
}
|
|
113
225
|
}
|
|
114
226
|
//# sourceMappingURL=Transformers.js.map
|
package/lib/Transformers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transformers.js","sourceRoot":"","sources":["Transformers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Node } from './nodeTypings.js';\n\ntype Safeness = 'safe' | 'unsafe';\ntype SafeWrap<Safe extends Safeness, obj extends object> = Safe extends 'safe' ? {[key in keyof obj]: unknown } : obj;\n\nexport class TransformerType<Nodes extends Pick<Node, 'type'>> {\n protected safeObjectVisit(value: unknown, mapper: (some: object) => any): unknown {\n if (value && typeof value === 'object') {\n // If you wonder why this is all so hard, this is the reason. We cannot lose the methods of our Array objects\n if (Array.isArray(value)) {\n return value.map(x => this.safeObjectVisit(x, mapper));\n }\n return mapper(value);\n }\n return value;\n }\n\n public transformNode<Safe extends 'safe' | 'unsafe' = 'safe'>(\n curObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: T }>>) => any;\n continue?: (op: Extract<Nodes, { type: T }>) => boolean;\n }},\n ): any {\n let continueCheck: ((node: any) => boolean) | undefined;\n let transformation: ((node: any) => unknown) | undefined;\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n continueCheck = nodeCallBacks[casted.type]?.continue;\n transformation = nodeCallBacks[casted.type]?.transform;\n }\n let shouldContinue = true;\n if (continueCheck) {\n shouldContinue = continueCheck(curObject);\n }\n if (!shouldContinue) {\n return curObject;\n }\n const copy: { type?: unknown } = { ...curObject };\n for (const [ key, value ] of Object.entries(copy)) {\n (<Record<string, unknown>> copy)[key] =\n this.safeObjectVisit(value, obj => this.transformNode(obj, nodeCallBacks));\n }\n if (transformation) {\n return transformation(copy);\n }\n return copy;\n }\n\n public visitNode(\n curObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: (op: Extract<Nodes, { type: T }>) => boolean },\n ): void {\n let callback: ((node: any) => boolean) | undefined;\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n callback = nodeCallBacks[casted.type];\n }\n let shouldIterate = true;\n if (callback) {\n shouldIterate = callback(curObject);\n }\n if (shouldIterate) {\n for (const value of Object.values(curObject)) {\n this.safeObjectVisit(value, obj => this.visitNode(obj, nodeCallBacks));\n }\n }\n }\n}\n\nexport class TransformerSubType<Nodes extends Pick<Node, 'type' | 'subType'>> extends TransformerType<Nodes> {\n // Public visitObjects(curObject: object, visitor: (current: object) => void): void {\n // for (const value of Object.values(curObject)) {\n // this.safeObjectVisit(value, obj => this.visitObjects(obj, visitor));\n // }\n // }\n\n public transformNodeSpecific<Safe extends 'safe' | 'unsafe' = 'safe'>(\n curObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: T }>>) => any;\n continue?: (op: Extract<Nodes, { type: T }>) => boolean;\n }},\n nodeSpecificCallBacks: {[Type in Nodes['type']]?: {\n [SubType in Extract<Nodes, { type: Type; subType: string }>['subType']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: Type; subType: SubType }>>) => any;\n continue?: (op: Extract<Nodes, { type: Type; subType: SubType }>) => boolean;\n }}} = {},\n ): any {\n let continueCheck: ((node: any) => boolean) | undefined;\n let transformation: ((node: any) => unknown) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }>curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n continueCheck = specific[<keyof typeof specific> casted.subType]?.continue;\n transformation = specific[<keyof typeof specific> casted.subType]?.transform;\n }\n }\n let shouldContinue = true;\n if (continueCheck) {\n shouldContinue = continueCheck(curObject);\n }\n if (!shouldContinue) {\n return curObject;\n }\n const copy: { type?: unknown } = { ...curObject };\n for (const [ key, value ] of Object.entries(copy)) {\n (<Record<string, unknown>> copy)[key] =\n this.safeObjectVisit(value, obj => this.transformNodeSpecific(obj, nodeCallBacks, nodeSpecificCallBacks));\n }\n if (transformation) {\n return transformation(copy);\n }\n return copy;\n }\n\n /**\n * When both nodeCallBack and NodeSpecific callBack are matched, will only look at nodeSpecifCallback\n */\n public visitNodeSpecific(\n curObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: (op: Extract<Nodes, { type: T }>) => boolean | void },\n nodeSpecificCallBacks: {[Type in Nodes['type']]?:\n {[Subtype in Extract<Nodes, { type: Type; subType: string }>['subType']]?:\n (op: Extract<Nodes, { type: Type; subType: Subtype }>) => boolean | void }} = {},\n ): void {\n let callback: ((node: any) => boolean | void) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }> curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n callback = specific[<keyof typeof specific>casted.subType];\n }\n }\n if (!callback && casted.type) {\n callback = nodeCallBacks[(<{ type: Nodes['type'] }> curObject).type];\n }\n let shouldIterate = true;\n if (callback) {\n shouldIterate = callback(curObject) ?? true;\n }\n if (shouldIterate) {\n for (const value of Object.values(curObject)) {\n this.safeObjectVisit(value, obj => this.visitNodeSpecific(obj, nodeCallBacks, nodeSpecificCallBacks));\n }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Transformers.js","sourceRoot":"","sources":["Transformers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Node } from './nodeTypings.js';\n\ntype Safeness = 'safe' | 'unsafe';\ntype SafeWrap<Safe extends Safeness, obj extends object> = Safe extends 'safe' ? {[key in keyof obj]: unknown } : obj;\n\nexport interface VisitContext {\n shortcut?: boolean;\n continue?: boolean;\n}\n\nexport interface SelectiveTraversalContext<Nodes> {\n next?: Nodes[];\n shortcut?: boolean;\n}\n\nexport class TransformerType<Nodes extends Pick<Node, 'type'>> {\n protected clone<T>(obj: T): T {\n const newObj = Object.create(Object.getPrototypeOf(obj));\n Object.defineProperties(\n newObj,\n Object.getOwnPropertyDescriptors(obj),\n );\n return newObj;\n }\n\n protected safeObjectVisit(value: unknown, mapper: (some: object) => any): unknown {\n if (value && typeof value === 'object') {\n if (Array.isArray(value)) {\n return value.map(x => this.safeObjectVisit(x, mapper));\n }\n return mapper(value);\n }\n return value;\n }\n\n /**\n * Recursively transforms all objects that are not arrays. Mapper is called on deeper objects first.\n * @param startObject object to start iterating from\n * @param mapper mapper to transform the various objects - argument is a copy of the original\n * @param preVisitor callback that is evaluated before iterating deeper.\n * If continues is false, we do not iterate deeper, current object is still mapped. - default: true\n * If shortcut is true, we do not iterate deeper, nor do we branch out, this mapper will be the last one called.\n * - Default false\n */\n public transformObject(\n startObject: object,\n mapper: (some: object) => any,\n preVisitor: (some: object) => VisitContext = () => ({}),\n ): unknown {\n let didShortCut = false;\n const recurse = (curObject: object): unknown => {\n const copy = this.clone(curObject);\n const context = preVisitor(copy);\n didShortCut = context.shortcut ?? false;\n const continues = context.continue ?? true;\n if (continues && !didShortCut) {\n for (const [ key, value ] of Object.entries(copy)) {\n if (didShortCut) {\n return copy;\n }\n (<Record<string, unknown>> copy)[key] =\n this.safeObjectVisit(value, obj => recurse(obj));\n }\n }\n return mapper(copy);\n };\n\n return recurse(startObject);\n }\n\n /**\n * Visitor that visits all objects. Visits deeper objects first.\n */\n public visitObject(\n startObject: object,\n visitor: (some: object) => void,\n preVisitor: (some: object) => VisitContext = () => ({}),\n ): void {\n let didShortCut = false;\n\n const recurse = (curObject: object): void => {\n const context = preVisitor(curObject);\n didShortCut = context.shortcut ?? false;\n const continues = context.continue ?? true;\n if (continues && !didShortCut) {\n for (const value of Object.values(curObject)) {\n if (didShortCut) {\n return;\n }\n this.safeObjectVisit(value, obj => recurse(obj));\n }\n }\n visitor(curObject);\n };\n recurse(startObject);\n }\n\n public transformNode<Safe extends 'safe' | 'unsafe' = 'safe'>(\n startObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: T }>>) => any;\n preVisitor?: (op: Extract<Nodes, { type: T }>) => VisitContext;\n }},\n ): any {\n const transformWrapper = (curObject: object): unknown => {\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n const ogFunc: ((node: any) => unknown) | undefined = nodeCallBacks[casted.type]?.transform;\n if (ogFunc) {\n return ogFunc(casted);\n }\n }\n return curObject;\n };\n const preTransformWrapper = (curObject: object): VisitContext => {\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n const ogFunc: ((node: any) => VisitContext) | undefined = nodeCallBacks[casted.type]?.preVisitor;\n if (ogFunc) {\n return ogFunc(casted);\n }\n }\n return {};\n };\n return this.transformObject(startObject, transformWrapper, preTransformWrapper);\n }\n\n public visitNode(\n startObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n visitor?: (op: Extract<Nodes, { type: T }>) => void;\n preVisitor?: (op: Extract<Nodes, { type: T }>) => VisitContext;\n }},\n ): void {\n const visitWrapper = (curObject: object): void => {\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n const ogFunc: ((node: any) => unknown) | undefined = nodeCallBacks[casted.type]?.visitor;\n if (ogFunc) {\n ogFunc(casted);\n }\n }\n };\n const preVisitWrapper = (curObject: object): VisitContext => {\n const casted = <{ type?: Nodes['type'] }>curObject;\n if (casted.type) {\n const ogFunc: ((node: any) => VisitContext) | undefined = nodeCallBacks[casted.type]?.preVisitor;\n if (ogFunc) {\n return ogFunc(casted);\n }\n }\n return {};\n };\n this.visitObject(startObject, visitWrapper, preVisitWrapper);\n }\n\n public traverseNodes(\n currentNode: Nodes,\n traverse: {[T in Nodes['type']]?: (op: Extract<Nodes, { type: T }>) => SelectiveTraversalContext<Nodes> },\n ): void {\n let didShortCut = false;\n\n const recurse = (curNode: Nodes): void => {\n const traverser = traverse[<Nodes['type']>curNode.type];\n if (traverser) {\n const { next, shortcut } = traverser(<any>curNode);\n didShortCut = shortcut ?? false;\n if (!didShortCut) {\n for (const node of next ?? []) {\n if (didShortCut) {\n return;\n }\n recurse(node);\n }\n }\n }\n };\n\n recurse(currentNode);\n }\n}\n\nexport class TransformerSubType<Nodes extends Pick<Node, 'type' | 'subType'>> extends TransformerType<Nodes> {\n public transformNodeSpecific<Safe extends 'safe' | 'unsafe' = 'safe'>(\n startObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: T }>>) => any;\n preVisitor?: (op: Extract<Nodes, { type: T }>) => VisitContext;\n }},\n nodeSpecificCallBacks: {[Type in Nodes['type']]?: {\n [SubType in Extract<Nodes, { type: Type; subType: string }>['subType']]?: {\n transform?: (op: SafeWrap<Safe, Extract<Nodes, { type: Type; subType: SubType }>>) => any;\n preVisitor?: (op: Extract<Nodes, { type: Type; subType: SubType }>) => VisitContext;\n }}},\n ): any {\n const transformWrapper = (curObject: object): unknown => {\n let ogTransform: ((node: any) => unknown) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }>curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n ogTransform = specific[<keyof typeof specific> casted.subType]?.transform;\n }\n if (!ogTransform) {\n ogTransform = nodeCallBacks[casted.type]?.transform;\n }\n }\n return ogTransform ? ogTransform(casted) : curObject;\n };\n const preVisitWrapper = (curObject: object): VisitContext => {\n let ogPreVisit: ((node: any) => VisitContext) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }>curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n ogPreVisit = specific[<keyof typeof specific> casted.subType]?.preVisitor;\n }\n if (!ogPreVisit) {\n ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;\n }\n }\n return ogPreVisit ? ogPreVisit(casted) : curObject;\n };\n return this.transformObject(startObject, transformWrapper, preVisitWrapper);\n }\n\n /**\n * When both nodeCallBack and NodeSpecific callBack are matched, will only look at nodeSpecifCallback\n */\n public visitNodeSpecific(\n startObject: object,\n nodeCallBacks: {[T in Nodes['type']]?: {\n visitor?: (op: Extract<Nodes, { type: T }>) => void;\n preVisitor?: (op: Extract<Nodes, { type: T }>) => VisitContext;\n }},\n nodeSpecificCallBacks: {[Type in Nodes['type']]?:\n {[Subtype in Extract<Nodes, { type: Type; subType: string }>['subType']]?: {\n visitor?: (op: Extract<Nodes, { type: Type; subType: Subtype }>) => void;\n preVisitor?: (op: Extract<Nodes, { type: Type; subType: Subtype }>) => VisitContext;\n }}},\n ): void {\n const visitWrapper = (curObject: object): void => {\n let ogTransform: ((node: any) => void) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }>curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n ogTransform = specific[<keyof typeof specific> casted.subType]?.visitor;\n }\n if (!ogTransform) {\n ogTransform = nodeCallBacks[casted.type]?.visitor;\n }\n }\n if (ogTransform) {\n ogTransform(casted);\n }\n };\n const preVisitWrapper = (curObject: object): VisitContext => {\n let ogPreVisit: ((node: any) => VisitContext) | undefined;\n const casted = <{ type?: Nodes['type']; subType?: string }>curObject;\n if (casted.type && casted.subType) {\n const specific = nodeSpecificCallBacks[casted.type];\n if (specific) {\n ogPreVisit = specific[<keyof typeof specific> casted.subType]?.preVisitor;\n }\n if (!ogPreVisit) {\n ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;\n }\n }\n return ogPreVisit ? ogPreVisit(casted) : curObject;\n };\n this.visitObject(startObject, visitWrapper, preVisitWrapper);\n }\n\n public traverseSubNodes(\n currentNode: Nodes,\n traverseNode: {[Type in Nodes['type']]?:\n (op: Extract<Nodes, { type: Type }>) => SelectiveTraversalContext<Nodes> },\n traverseSubNode: {[Type in Nodes['type']]?:\n {[Subtype in Extract<Nodes, { type: Type; subType: string }>['subType']]?:\n (op: Extract<Nodes, { type: Type; subType: Subtype }>) => SelectiveTraversalContext<Nodes> }},\n ): void {\n let didShortCut = false;\n\n const recurse = (curNode: Nodes): void => {\n let traverser: ((call: any) => SelectiveTraversalContext<Nodes>) | undefined;\n const subObj = traverseSubNode[<Nodes['type']>curNode.type];\n if (subObj) {\n traverser = subObj[<keyof typeof subObj>curNode.subType];\n }\n if (!traverser) {\n traverser = traverseNode[<Nodes['type']>curNode.type];\n }\n if (traverser) {\n const { next, shortcut } = traverser(<any>curNode);\n didShortCut = shortcut ?? false;\n if (!didShortCut) {\n for (const node of next ?? []) {\n if (didShortCut) {\n return;\n }\n recurse(node);\n }\n }\n }\n };\n\n recurse(currentNode);\n }\n}\n"]}
|
|
@@ -26,12 +26,58 @@ ParamType extends any[] = any[]> = {
|
|
|
26
26
|
gImpl: (def: RuleDefArg) => (ast: AstType, context: Context, ...params: ParamType) => void;
|
|
27
27
|
};
|
|
28
28
|
export interface RuleDefArg {
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Call another generator rule so it can generate its string representation.
|
|
31
|
+
* @param rule the rule to be called
|
|
32
|
+
* @param input the ast input to work on
|
|
33
|
+
* @param arg the remaining parameters required by this rule.
|
|
34
|
+
* @constructor
|
|
35
|
+
*/
|
|
36
|
+
SUBRULE: <T, U extends any[]>(rule: GeneratorRule<any, any, T, U>, input: T, ...arg: U) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Print the characters to the output string
|
|
39
|
+
* @param args arguments to be printed
|
|
40
|
+
* @constructor
|
|
41
|
+
*/
|
|
30
42
|
PRINT: (...args: string[]) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Print the character to the output stream ensuring there is a space to the left oif what you print.
|
|
45
|
+
* If a space was printed right before this, it will not print a space.
|
|
46
|
+
* @param args
|
|
47
|
+
* @constructor
|
|
48
|
+
*/
|
|
31
49
|
PRINT_SPACE_LEFT: (...args: string[]) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Prints all arguments as one word, ensuring it has a space before and behind each word
|
|
52
|
+
* @param args
|
|
53
|
+
* @constructor
|
|
54
|
+
*/
|
|
32
55
|
PRINT_WORD: (...args: string[]) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Prints all arguments as words, ensuring they all have a space before and behind them.
|
|
58
|
+
* @param args
|
|
59
|
+
* @constructor
|
|
60
|
+
*/
|
|
33
61
|
PRINT_WORDS: (...args: string[]) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Ensures that what you print is on a newline with the indentation equal to the indentation currently setup.
|
|
64
|
+
* @param args
|
|
65
|
+
* @constructor
|
|
66
|
+
*/
|
|
34
67
|
PRINT_ON_EMPTY: (...args: string[]) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Handles the location of a node as if it was generated using a SUBRULE.
|
|
70
|
+
* Can be used to generate many nodes within a single subrule call while still having correct localization handling.
|
|
71
|
+
* @param loc
|
|
72
|
+
* @param nodeHandle
|
|
73
|
+
* @constructor
|
|
74
|
+
*/
|
|
35
75
|
HANDLE_LOC: <T>(loc: Localized, nodeHandle: () => T) => T | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Catchup the string until a given length,
|
|
78
|
+
* printing everything from the current catchup location until the index you provide.
|
|
79
|
+
* @param until
|
|
80
|
+
* @constructor
|
|
81
|
+
*/
|
|
36
82
|
CATCHUP: (until: number) => void;
|
|
37
83
|
}
|