jsii-reflect 1.117.0 → 1.118.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/bin/jsii-query +2 -0
- package/bin/jsii-query.d.ts +2 -0
- package/bin/jsii-query.js +137 -0
- package/lib/hierarchical-set.d.ts +17 -0
- package/lib/hierarchical-set.js +154 -0
- package/lib/jsii-query.d.ts +41 -0
- package/lib/jsii-query.js +307 -0
- package/lib/method.d.ts +4 -0
- package/lib/method.js +10 -0
- package/lib/property.d.ts +4 -0
- package/lib/property.js +10 -0
- package/lib/type-system.d.ts +1 -0
- package/package.json +6 -6
- package/test/__snapshots__/jsii-tree.test.js.snap +27 -6
- package/test/__snapshots__/tree.test.js.snap +17 -3
- package/test/hierarchical-set.test.d.ts +2 -0
- package/test/hierarchical-set.test.js +58 -0
- package/test/jsii-query.test.d.ts +2 -0
- package/test/jsii-query.test.js +88 -0
- package/test/type-system.test.js +2 -0
package/bin/jsii-query
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("@jsii/check-node/run");
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const yargs = require("yargs");
|
|
6
|
+
const jsii_query_1 = require("../lib/jsii-query");
|
|
7
|
+
async function main() {
|
|
8
|
+
const argv = await yargs
|
|
9
|
+
.usage('$0 <FILE> [QUERY...]', 'Queries a jsii file for its entries.', (args) => args
|
|
10
|
+
.positional('FILE', {
|
|
11
|
+
type: 'string',
|
|
12
|
+
desc: 'path to a .jsii file or directory to load',
|
|
13
|
+
})
|
|
14
|
+
.positional('QUERY', {
|
|
15
|
+
type: 'string',
|
|
16
|
+
desc: 'a query or filter expression to include or exclude items',
|
|
17
|
+
}))
|
|
18
|
+
.option('types', {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
alias: 't',
|
|
21
|
+
desc: 'after selecting API elements, show all selected types, as well as types containing selected members',
|
|
22
|
+
default: false,
|
|
23
|
+
})
|
|
24
|
+
.option('members', {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
alias: 'm',
|
|
27
|
+
desc: 'after selecting API elements, show all selected members, as well as members of selected types',
|
|
28
|
+
default: false,
|
|
29
|
+
})
|
|
30
|
+
.options('docs', {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
alias: 'd',
|
|
33
|
+
desc: 'show documentation for selected elements',
|
|
34
|
+
default: false,
|
|
35
|
+
})
|
|
36
|
+
.option('closure', {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
alias: 'c',
|
|
39
|
+
default: false,
|
|
40
|
+
desc: 'Load dependencies of package without assuming its a JSII package itself',
|
|
41
|
+
})
|
|
42
|
+
.strict().epilogue(`
|
|
43
|
+
REMARKS
|
|
44
|
+
-------
|
|
45
|
+
|
|
46
|
+
There can be more than one QUERY part, which progressively filters from or adds
|
|
47
|
+
to the list of selected elements.
|
|
48
|
+
|
|
49
|
+
QUERY is of the format:
|
|
50
|
+
|
|
51
|
+
[<op>]<kind>[:<expression>]
|
|
52
|
+
|
|
53
|
+
Where:
|
|
54
|
+
|
|
55
|
+
<op> The type of operation to apply. Absent means '.'
|
|
56
|
+
+ Adds new API elements matching the selector to the selection.
|
|
57
|
+
If this selects types, it also includes all type's members.
|
|
58
|
+
- Removes API elements from the current selection that match
|
|
59
|
+
the selector.
|
|
60
|
+
. Removes API elements from the current selection that do NOT
|
|
61
|
+
match the selector (i.e., retain only those that DO match
|
|
62
|
+
the selector) (default)
|
|
63
|
+
<kind> Type of API element to select. One of 'type' or 'member',
|
|
64
|
+
or any of its more specific sub-types such as 'class',
|
|
65
|
+
'interface', 'struct', 'enum', 'property', 'method', etc.
|
|
66
|
+
Also supports aliases like 'c', 'm', 'mem', 's', 'p', etc.
|
|
67
|
+
<expression> A JavaScript expression that will be evaluated against
|
|
68
|
+
the member. Has access to a number of attributes like
|
|
69
|
+
kind, ancestors, abstract, base, datatype, docs, interfaces,
|
|
70
|
+
name, initializer, optional, overrides, protected, returns,
|
|
71
|
+
parameters, static, variadic, type. The types are the
|
|
72
|
+
same types as offered by the jsii-reflect class model.
|
|
73
|
+
|
|
74
|
+
If the first expression of the query has operator '+', then the query starts
|
|
75
|
+
empty and the selector determines the initial set. Otherwise the query starts
|
|
76
|
+
with all elements and the first expression is a filter on it.
|
|
77
|
+
|
|
78
|
+
This file evaluates the expressions as JavaScript, so this tool is not safe
|
|
79
|
+
against untrusted input!
|
|
80
|
+
|
|
81
|
+
Don't forget to mind your shell escaping rules when you write query expressions.
|
|
82
|
+
|
|
83
|
+
Don't forget to add -- to terminate option parsing if you write negative expressions.
|
|
84
|
+
|
|
85
|
+
EXAMPLES
|
|
86
|
+
-------
|
|
87
|
+
|
|
88
|
+
Select all enums:
|
|
89
|
+
$ jsii-query --types node_modules/aws-cdk-lib enum
|
|
90
|
+
|
|
91
|
+
Select all methods with "grant" in their name:
|
|
92
|
+
$ jsii-query --members node_modules/aws-cdk-lib 'method:name.includes("grant")'
|
|
93
|
+
|
|
94
|
+
Select all classes that have a grant method:
|
|
95
|
+
$ jsii-query --types node_modules/aws-cdk-lib class 'method:name.includes("grant")'
|
|
96
|
+
-or-
|
|
97
|
+
$ jsii-query --types -- node_modules/aws-cdk-lib -interface 'method:name.includes("grant")'
|
|
98
|
+
^^^^ note this
|
|
99
|
+
|
|
100
|
+
Select all classes that have methods that are named either 'foo' or 'bar':
|
|
101
|
+
$ jsii-query --types node_modules/some-package '+method:name=="foo"' '+method:name=="bar"' .class
|
|
102
|
+
|
|
103
|
+
`).argv;
|
|
104
|
+
// Add some fields that we know are there but yargs typing doesn't know
|
|
105
|
+
const options = argv;
|
|
106
|
+
if (!(options.types || options.members)) {
|
|
107
|
+
throw new Error('At least --types or --members must be specified');
|
|
108
|
+
}
|
|
109
|
+
// Yargs is annoying; if the user uses '--' to terminate the option list,
|
|
110
|
+
// it will not parse positionals into `QUERY` but into `_`
|
|
111
|
+
const expressions = [...options.QUERY, ...options._]
|
|
112
|
+
.map(String)
|
|
113
|
+
.map(jsii_query_1.parseExpression);
|
|
114
|
+
const result = await (0, jsii_query_1.jsiiQuery)({
|
|
115
|
+
fileName: options.FILE,
|
|
116
|
+
expressions,
|
|
117
|
+
closure: options.closure,
|
|
118
|
+
returnTypes: options.types,
|
|
119
|
+
returnMembers: options.members,
|
|
120
|
+
});
|
|
121
|
+
for (const element of result) {
|
|
122
|
+
console.log((0, jsii_query_1.renderElement)(element));
|
|
123
|
+
if (options.docs) {
|
|
124
|
+
console.log(chalk.gray((0, jsii_query_1.renderDocs)(element)
|
|
125
|
+
.split('\n')
|
|
126
|
+
.map((line) => ` ${line}`)
|
|
127
|
+
.join('\n')));
|
|
128
|
+
console.log('');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
process.exitCode = result.length > 0 ? 0 : 1;
|
|
132
|
+
}
|
|
133
|
+
main().catch((e) => {
|
|
134
|
+
console.log(e);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
|
137
|
+
//# sourceMappingURL=jsii-query.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type HierarchicalElement = string[];
|
|
2
|
+
export declare class HierarchicalSet {
|
|
3
|
+
private root;
|
|
4
|
+
constructor(elements?: Iterable<HierarchicalElement>);
|
|
5
|
+
addAll(elements: Iterable<HierarchicalElement>): this;
|
|
6
|
+
add(element: HierarchicalElement): this;
|
|
7
|
+
/**
|
|
8
|
+
* Remove every element from LHS that doesn't have a prefix in RHS
|
|
9
|
+
*/
|
|
10
|
+
intersect(rhs: HierarchicalSet): this;
|
|
11
|
+
remove(rhs: Iterable<HierarchicalElement>): this;
|
|
12
|
+
get size(): number;
|
|
13
|
+
[Symbol.iterator](): Iterator<HierarchicalElement, HierarchicalElement, any>;
|
|
14
|
+
has(el: HierarchicalElement): boolean;
|
|
15
|
+
private findNode;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=hierarchical-set.d.ts.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HierarchicalSet = void 0;
|
|
4
|
+
class HierarchicalSet {
|
|
5
|
+
constructor(elements) {
|
|
6
|
+
this.root = {
|
|
7
|
+
exists: false,
|
|
8
|
+
children: {},
|
|
9
|
+
};
|
|
10
|
+
if (elements) {
|
|
11
|
+
this.addAll(elements);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
addAll(elements) {
|
|
15
|
+
for (const element of elements) {
|
|
16
|
+
this.add(element);
|
|
17
|
+
}
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
add(element) {
|
|
21
|
+
if (element.length === 0) {
|
|
22
|
+
throw new Error('Elements may not be empty');
|
|
23
|
+
}
|
|
24
|
+
let node = this.root;
|
|
25
|
+
for (const segment of element) {
|
|
26
|
+
if (!(segment in node.children)) {
|
|
27
|
+
node.children[segment] = {
|
|
28
|
+
exists: false,
|
|
29
|
+
children: {},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
node = node.children[segment];
|
|
33
|
+
}
|
|
34
|
+
node.exists = true;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Remove every element from LHS that doesn't have a prefix in RHS
|
|
39
|
+
*/
|
|
40
|
+
intersect(rhs) {
|
|
41
|
+
const retainSet = new HierarchicalSet();
|
|
42
|
+
for (const el of Array.from(this)) {
|
|
43
|
+
let found = false;
|
|
44
|
+
for (let i = 0; i < el.length && !found; i++) {
|
|
45
|
+
found = found || rhs.has(el.slice(0, i + 1));
|
|
46
|
+
}
|
|
47
|
+
if (found) {
|
|
48
|
+
retainSet.add(el);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.root = retainSet.root;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
remove(rhs) {
|
|
55
|
+
for (const el of rhs) {
|
|
56
|
+
const found = this.findNode(el);
|
|
57
|
+
if (found) {
|
|
58
|
+
const [parent, key] = found;
|
|
59
|
+
delete parent.children[key];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
get size() {
|
|
65
|
+
return Array.from(this).length;
|
|
66
|
+
}
|
|
67
|
+
[Symbol.iterator]() {
|
|
68
|
+
if (Object.keys(this.root.children).length === 0) {
|
|
69
|
+
return {
|
|
70
|
+
next() {
|
|
71
|
+
return { done: true };
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const stack = [];
|
|
76
|
+
function cursorFrom(node) {
|
|
77
|
+
return {
|
|
78
|
+
trie: node.children,
|
|
79
|
+
keys: Object.keys(node.children),
|
|
80
|
+
index: 0,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
stack.push(cursorFrom(this.root));
|
|
84
|
+
let done = false;
|
|
85
|
+
let cur = stack[stack.length - 1];
|
|
86
|
+
/**
|
|
87
|
+
* Move 'cur' to the next node in the trie
|
|
88
|
+
*/
|
|
89
|
+
function advance() {
|
|
90
|
+
// If we can descend, let's
|
|
91
|
+
if (!isEmpty(cur.trie[cur.keys[cur.index]])) {
|
|
92
|
+
stack.push(cursorFrom(cur.trie[cur.keys[cur.index]]));
|
|
93
|
+
cur = stack[stack.length - 1];
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
cur.index += 1;
|
|
97
|
+
while (cur.index >= cur.keys.length) {
|
|
98
|
+
stack.pop();
|
|
99
|
+
if (stack.length === 0) {
|
|
100
|
+
done = true;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
cur = stack[stack.length - 1];
|
|
104
|
+
// Advance the pointer after coming back.
|
|
105
|
+
cur.index += 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
next() {
|
|
110
|
+
while (!done && !cur.trie[cur.keys[cur.index]].exists) {
|
|
111
|
+
advance();
|
|
112
|
+
}
|
|
113
|
+
const value = !done ? stack.map((f) => f.keys[f.index]) : undefined;
|
|
114
|
+
// Node's Array.from doesn't quite correctly implement the iterator protocol.
|
|
115
|
+
// If we return { value: <something>, done: true } it will pretend to never
|
|
116
|
+
// have seen <something>, so we need to split this into 2 steps.
|
|
117
|
+
// The TypeScript typings don't agree, so 'as any' that away.
|
|
118
|
+
const ret = (value ? { value, done } : { done });
|
|
119
|
+
if (!done) {
|
|
120
|
+
advance();
|
|
121
|
+
}
|
|
122
|
+
return ret;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
has(el) {
|
|
127
|
+
const found = this.findNode(el);
|
|
128
|
+
if (!found) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
const [node, last] = found;
|
|
132
|
+
return node.children?.[last]?.exists ?? false;
|
|
133
|
+
}
|
|
134
|
+
findNode(el) {
|
|
135
|
+
if (el.length === 0) {
|
|
136
|
+
throw new Error('Elements may not be empty');
|
|
137
|
+
}
|
|
138
|
+
const parts = [...el];
|
|
139
|
+
let parent = this.root;
|
|
140
|
+
while (parts.length > 1) {
|
|
141
|
+
const next = parts.splice(0, 1)[0];
|
|
142
|
+
parent = parent.children?.[next];
|
|
143
|
+
if (!parent) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return [parent, parts[0]];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.HierarchicalSet = HierarchicalSet;
|
|
151
|
+
function isEmpty(node) {
|
|
152
|
+
return Object.keys(node.children).length === 0;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=hierarchical-set.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import '@jsii/check-node/run';
|
|
2
|
+
import { Documentable } from '../lib';
|
|
3
|
+
export interface JsiiQueryOptions {
|
|
4
|
+
readonly fileName: string;
|
|
5
|
+
readonly expressions: QExpr[];
|
|
6
|
+
readonly closure?: boolean;
|
|
7
|
+
readonly returnTypes?: boolean;
|
|
8
|
+
readonly returnMembers?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function jsiiQuery(options: JsiiQueryOptions): Promise<ApiElement[]>;
|
|
11
|
+
export declare class Predicate {
|
|
12
|
+
private readonly fn;
|
|
13
|
+
constructor(expr?: string);
|
|
14
|
+
apply(context: Record<string, unknown>): boolean;
|
|
15
|
+
}
|
|
16
|
+
type QExpr = QSelect | QFilter;
|
|
17
|
+
/**
|
|
18
|
+
* Select adds elements
|
|
19
|
+
*/
|
|
20
|
+
interface QSelect {
|
|
21
|
+
readonly op: 'select';
|
|
22
|
+
readonly kind: ApiKind;
|
|
23
|
+
readonly expression?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Filter retains elements
|
|
27
|
+
*/
|
|
28
|
+
interface QFilter {
|
|
29
|
+
readonly op: 'filter';
|
|
30
|
+
readonly remove: boolean;
|
|
31
|
+
readonly kind: ApiKind;
|
|
32
|
+
readonly expression?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseExpression(expr: string): QExpr;
|
|
35
|
+
export declare function renderElement(el: ApiElement): string;
|
|
36
|
+
export declare function renderDocs(el: ApiElement): string;
|
|
37
|
+
declare const VALID_KINDS: readonly ["type", "interface", "class", "enum", "struct", "member", "property", "method", "initializer"];
|
|
38
|
+
type ApiKind = (typeof VALID_KINDS)[number];
|
|
39
|
+
type ApiElement = Documentable;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=jsii-query.d.ts.map
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Predicate = void 0;
|
|
4
|
+
exports.jsiiQuery = jsiiQuery;
|
|
5
|
+
exports.parseExpression = parseExpression;
|
|
6
|
+
exports.renderElement = renderElement;
|
|
7
|
+
exports.renderDocs = renderDocs;
|
|
8
|
+
/* eslint-disable @typescript-eslint/no-implied-eval */
|
|
9
|
+
require("@jsii/check-node/run");
|
|
10
|
+
const lib_1 = require("../lib");
|
|
11
|
+
const hierarchical_set_1 = require("./hierarchical-set");
|
|
12
|
+
const JSII_TREE_SUPPORTED_FEATURES = [
|
|
13
|
+
'intersection-types',
|
|
14
|
+
'class-covariant-overrides',
|
|
15
|
+
];
|
|
16
|
+
async function jsiiQuery(options) {
|
|
17
|
+
const typesys = new lib_1.TypeSystem();
|
|
18
|
+
if (options.closure) {
|
|
19
|
+
await typesys.loadNpmDependencies(options.fileName, {
|
|
20
|
+
validate: false,
|
|
21
|
+
supportedFeatures: JSII_TREE_SUPPORTED_FEATURES,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await typesys.load(options.fileName, {
|
|
26
|
+
validate: false,
|
|
27
|
+
supportedFeatures: JSII_TREE_SUPPORTED_FEATURES,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const universe = selectAll(typesys);
|
|
31
|
+
const selectedElements = selectApiElements(universe, options.expressions);
|
|
32
|
+
expandSelectToParentsAndChildren(universe, selectedElements, options);
|
|
33
|
+
// The keys are sortable, so sort them, then get the original API elements back
|
|
34
|
+
// and return only those that were asked for.
|
|
35
|
+
// Then retain only the kinds we asked for, and sort them
|
|
36
|
+
return Array.from(selectedElements)
|
|
37
|
+
.sort()
|
|
38
|
+
.map((key) => universe.get(stringFromKey(key)))
|
|
39
|
+
.filter((x) => (isType(x) && options.returnTypes) ||
|
|
40
|
+
(isMember(x) && options.returnMembers));
|
|
41
|
+
}
|
|
42
|
+
// - if we are asking for types, include any type that's a parent of any of the selected members
|
|
43
|
+
// - if we are asking for members, include all members that are a child of any of the selected types
|
|
44
|
+
function expandSelectToParentsAndChildren(universe, selected, options) {
|
|
45
|
+
if (options.returnTypes) {
|
|
46
|
+
// All type keys from either type keys or member keys
|
|
47
|
+
selected.addAll(Array.from(selected).map(typeKey));
|
|
48
|
+
}
|
|
49
|
+
if (options.returnMembers) {
|
|
50
|
+
const allElements = new hierarchical_set_1.HierarchicalSet(Array.from(universe.keys()).map(keyFromString));
|
|
51
|
+
// Add all member keys that are members of a selected type
|
|
52
|
+
selected.addAll(new hierarchical_set_1.HierarchicalSet(allElements).intersect(selected));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isType(x) {
|
|
56
|
+
return (x instanceof lib_1.ClassType ||
|
|
57
|
+
x instanceof lib_1.InterfaceType ||
|
|
58
|
+
x instanceof lib_1.EnumType);
|
|
59
|
+
}
|
|
60
|
+
function isMember(x) {
|
|
61
|
+
return x instanceof lib_1.Callable || x instanceof lib_1.Property;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns a unique key per API element, used because the jsii-reflect members don't guarantee uniqueness at the object level
|
|
65
|
+
*
|
|
66
|
+
* Keys have the property that parent keys are a prefix of child keys, and that the keys are in sort order
|
|
67
|
+
*/
|
|
68
|
+
function apiElementKey(x) {
|
|
69
|
+
if (isType(x)) {
|
|
70
|
+
return [`${x.fqn}`];
|
|
71
|
+
}
|
|
72
|
+
if (isMember(x)) {
|
|
73
|
+
const sort = x instanceof lib_1.Method && x.static
|
|
74
|
+
? '000'
|
|
75
|
+
: x instanceof lib_1.Initializer
|
|
76
|
+
? '001'
|
|
77
|
+
: '002';
|
|
78
|
+
return [`${x.parentType.fqn}`, `${sort}${x.name}`];
|
|
79
|
+
}
|
|
80
|
+
throw new Error('huh');
|
|
81
|
+
}
|
|
82
|
+
function stringFromKey(x) {
|
|
83
|
+
return x.map((s) => `${s}#`).join('');
|
|
84
|
+
}
|
|
85
|
+
function keyFromString(x) {
|
|
86
|
+
return x.split('#').slice(0, -1);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Given a type or member key, return the type key
|
|
90
|
+
*/
|
|
91
|
+
function typeKey(x) {
|
|
92
|
+
return [x[0]];
|
|
93
|
+
}
|
|
94
|
+
function selectApiElements(universe, expressions) {
|
|
95
|
+
const allKeys = new hierarchical_set_1.HierarchicalSet(Array.from(universe.keys()).map(keyFromString));
|
|
96
|
+
const currentSelection = expressions.length === 0 || expressions[0].op === 'filter'
|
|
97
|
+
? new hierarchical_set_1.HierarchicalSet(allKeys)
|
|
98
|
+
: new hierarchical_set_1.HierarchicalSet();
|
|
99
|
+
for (const expr of expressions) {
|
|
100
|
+
const thisQuery = Array.from(filterElements(universe, allKeys, expr.kind, expr.expression));
|
|
101
|
+
if (expr.op === 'filter' && expr.remove) {
|
|
102
|
+
currentSelection.remove(thisQuery);
|
|
103
|
+
}
|
|
104
|
+
else if (expr.op === 'filter') {
|
|
105
|
+
currentSelection.intersect(new hierarchical_set_1.HierarchicalSet(thisQuery));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
currentSelection.addAll(thisQuery);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return currentSelection;
|
|
112
|
+
}
|
|
113
|
+
function* filterElements(universe, elements, kind, expression) {
|
|
114
|
+
const pred = new Predicate(expression);
|
|
115
|
+
for (const key of elements) {
|
|
116
|
+
const el = universe.get(stringFromKey(key));
|
|
117
|
+
if (!el) {
|
|
118
|
+
throw new Error(`Key not in universe: ${stringFromKey(key)}`);
|
|
119
|
+
}
|
|
120
|
+
if (matches(el, kind, pred)) {
|
|
121
|
+
yield key;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
class Predicate {
|
|
126
|
+
constructor(expr) {
|
|
127
|
+
if (!expr) {
|
|
128
|
+
this.fn = () => true;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const args = API_ELEMENT_ATTRIBUTES.join(',');
|
|
132
|
+
const body = `return Boolean(${expr});`;
|
|
133
|
+
try {
|
|
134
|
+
this.fn = Function(args, body);
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
throw new Error(`Syntax error in selector: ${body}: ${e}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
apply(context) {
|
|
142
|
+
return this.fn(...API_ELEMENT_ATTRIBUTES.map((attr) => context[attr]));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.Predicate = Predicate;
|
|
146
|
+
/**
|
|
147
|
+
* Whether a given API element matches the filter
|
|
148
|
+
*/
|
|
149
|
+
function matches(el, kind, pred) {
|
|
150
|
+
const context = {};
|
|
151
|
+
if (el instanceof lib_1.ClassType) {
|
|
152
|
+
if (!['type', 'class'].includes(kind))
|
|
153
|
+
return false;
|
|
154
|
+
context.kind = 'class';
|
|
155
|
+
}
|
|
156
|
+
if (el instanceof lib_1.InterfaceType) {
|
|
157
|
+
const moreSpecificInterfaceType = el.datatype ? 'struct' : 'interface';
|
|
158
|
+
if (!['type', moreSpecificInterfaceType].includes(kind))
|
|
159
|
+
return false;
|
|
160
|
+
context.kind = moreSpecificInterfaceType;
|
|
161
|
+
}
|
|
162
|
+
if (el instanceof lib_1.EnumType) {
|
|
163
|
+
if (!['type', 'enum'].includes(kind))
|
|
164
|
+
return false;
|
|
165
|
+
context.kind = 'enum';
|
|
166
|
+
}
|
|
167
|
+
if (el instanceof lib_1.Property) {
|
|
168
|
+
if (!['member', 'property'].includes(kind))
|
|
169
|
+
return false;
|
|
170
|
+
context.kind = 'property';
|
|
171
|
+
}
|
|
172
|
+
if (el instanceof lib_1.Callable) {
|
|
173
|
+
const moreSpecificCallable = el instanceof lib_1.Initializer ? 'initializer' : 'method';
|
|
174
|
+
if (!['member', moreSpecificCallable].includes(kind))
|
|
175
|
+
return false;
|
|
176
|
+
context.kind = moreSpecificCallable;
|
|
177
|
+
}
|
|
178
|
+
Object.assign(context, Object.fromEntries(API_ELEMENT_ATTRIBUTES.map((attr) => [attr, el[attr]])));
|
|
179
|
+
const ret = pred.apply(context);
|
|
180
|
+
return ret;
|
|
181
|
+
}
|
|
182
|
+
function selectAll(typesys) {
|
|
183
|
+
return new Map([
|
|
184
|
+
...typesys.classes,
|
|
185
|
+
...typesys.interfaces,
|
|
186
|
+
...typesys.enums,
|
|
187
|
+
...typesys.methods,
|
|
188
|
+
...typesys.properties,
|
|
189
|
+
].map((el) => [stringFromKey(apiElementKey(el)), el]));
|
|
190
|
+
}
|
|
191
|
+
const KIND_ALIASES = {
|
|
192
|
+
t: 'type',
|
|
193
|
+
c: 'class',
|
|
194
|
+
i: 'interface',
|
|
195
|
+
s: 'struct',
|
|
196
|
+
e: 'enum',
|
|
197
|
+
p: 'property',
|
|
198
|
+
prop: 'property',
|
|
199
|
+
mem: 'member',
|
|
200
|
+
m: 'method',
|
|
201
|
+
init: 'initializer',
|
|
202
|
+
ctr: 'initializer',
|
|
203
|
+
constructor: 'initializer',
|
|
204
|
+
};
|
|
205
|
+
function parseExpression(expr) {
|
|
206
|
+
let op;
|
|
207
|
+
if (expr[0].match(/[a-z]/i)) {
|
|
208
|
+
op = '.';
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
op = expr[0];
|
|
212
|
+
expr = expr.slice(1);
|
|
213
|
+
}
|
|
214
|
+
if (!['-', '+', '.'].includes(op)) {
|
|
215
|
+
throw new Error(`Invalid operator: ${op} (must be +, - or .)`);
|
|
216
|
+
}
|
|
217
|
+
const operator = op;
|
|
218
|
+
const [kind_, ...expressionParts] = expr.split(':');
|
|
219
|
+
const kind = (KIND_ALIASES[kind_] ??
|
|
220
|
+
kind_);
|
|
221
|
+
if (!VALID_KINDS.includes(kind)) {
|
|
222
|
+
throw new Error(`Invalid kind: ${kind} (must be one of ${VALID_KINDS.join(', ')})`);
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
op: operator === '+' ? 'select' : 'filter',
|
|
226
|
+
remove: operator === '-',
|
|
227
|
+
kind,
|
|
228
|
+
expression: expressionParts?.join(':'),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function renderElement(el) {
|
|
232
|
+
if (el instanceof lib_1.ClassType) {
|
|
233
|
+
return combine(el.abstract ? 'abstract' : '', 'class', el.fqn);
|
|
234
|
+
}
|
|
235
|
+
if (el instanceof lib_1.InterfaceType) {
|
|
236
|
+
if (el.spec.datatype) {
|
|
237
|
+
return combine('struct', el.fqn);
|
|
238
|
+
}
|
|
239
|
+
return combine('interface', el.fqn);
|
|
240
|
+
}
|
|
241
|
+
if (el instanceof lib_1.EnumType) {
|
|
242
|
+
return combine('enum', el.fqn);
|
|
243
|
+
}
|
|
244
|
+
if (el instanceof lib_1.Property) {
|
|
245
|
+
const opt = el.optional ? '?' : '';
|
|
246
|
+
return combine(el.static ? 'static' : '', el.immutable ? 'readonly' : '', `${el.parentType.fqn}#${el.name}${opt}: ${el.type.toString()}`);
|
|
247
|
+
}
|
|
248
|
+
if (el instanceof lib_1.Method) {
|
|
249
|
+
return combine(el.static ? 'static' : '', `${el.parentType.fqn}#${el.name}(${renderParams(el.parameters)}): ${el.returns.toString()}`);
|
|
250
|
+
}
|
|
251
|
+
if (el instanceof lib_1.Initializer) {
|
|
252
|
+
return `${el.parentType.fqn}(${renderParams(el.parameters)}`;
|
|
253
|
+
}
|
|
254
|
+
return '???';
|
|
255
|
+
}
|
|
256
|
+
function renderDocs(el) {
|
|
257
|
+
return el.docs.toString();
|
|
258
|
+
}
|
|
259
|
+
function renderParams(ps) {
|
|
260
|
+
return (ps ?? [])
|
|
261
|
+
.map((p) => {
|
|
262
|
+
const opt = p.optional ? '?' : '';
|
|
263
|
+
const varia = p.variadic ? '...' : '';
|
|
264
|
+
const arr = p.variadic ? '[]' : '';
|
|
265
|
+
return `${varia}${p.name}${opt}: ${p.type.toString()}${arr}`;
|
|
266
|
+
})
|
|
267
|
+
.join(', ');
|
|
268
|
+
}
|
|
269
|
+
function combine(...xs) {
|
|
270
|
+
return xs.filter((x) => x).join(' ');
|
|
271
|
+
}
|
|
272
|
+
// A list of all valid API element kinds
|
|
273
|
+
const VALID_KINDS = [
|
|
274
|
+
// Types
|
|
275
|
+
'type',
|
|
276
|
+
'interface',
|
|
277
|
+
'class',
|
|
278
|
+
'enum',
|
|
279
|
+
'struct',
|
|
280
|
+
// Members
|
|
281
|
+
'member',
|
|
282
|
+
'property',
|
|
283
|
+
'method',
|
|
284
|
+
'initializer',
|
|
285
|
+
];
|
|
286
|
+
const API_ELEMENT_ATTRIBUTES = [
|
|
287
|
+
'kind',
|
|
288
|
+
// Types
|
|
289
|
+
'ancestors',
|
|
290
|
+
'abstract',
|
|
291
|
+
'base',
|
|
292
|
+
'datatype',
|
|
293
|
+
'docs',
|
|
294
|
+
'interfaces',
|
|
295
|
+
'name',
|
|
296
|
+
// Members
|
|
297
|
+
'initializer',
|
|
298
|
+
'optional',
|
|
299
|
+
'overrides',
|
|
300
|
+
'protected',
|
|
301
|
+
'returns',
|
|
302
|
+
'parameters',
|
|
303
|
+
'static',
|
|
304
|
+
'variadic',
|
|
305
|
+
'type',
|
|
306
|
+
];
|
|
307
|
+
//# sourceMappingURL=jsii-query.js.map
|
package/lib/method.d.ts
CHANGED
|
@@ -39,5 +39,9 @@ export declare class Method extends Callable implements Documentable, Overridabl
|
|
|
39
39
|
* Indicates if this is a static method.
|
|
40
40
|
*/
|
|
41
41
|
get static(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The Method that this method overrides, if any
|
|
44
|
+
*/
|
|
45
|
+
get overriddenMethod(): Method | undefined;
|
|
42
46
|
}
|
|
43
47
|
//# sourceMappingURL=method.d.ts.map
|
package/lib/method.js
CHANGED
|
@@ -61,6 +61,16 @@ class Method extends callable_1.Callable {
|
|
|
61
61
|
get static() {
|
|
62
62
|
return !!this.spec.static;
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The Method that this method overrides, if any
|
|
66
|
+
*/
|
|
67
|
+
get overriddenMethod() {
|
|
68
|
+
const o = this.overrides;
|
|
69
|
+
if (o && (o.isClassType() || o.isInterfaceType())) {
|
|
70
|
+
return o.ownMethods.find((m) => m.name === this.name);
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
64
74
|
}
|
|
65
75
|
exports.Method = Method;
|
|
66
76
|
__decorate([
|
package/lib/property.d.ts
CHANGED
|
@@ -51,5 +51,9 @@ export declare class Property extends OptionalValue implements Documentable, Ove
|
|
|
51
51
|
* Return the location in the repository
|
|
52
52
|
*/
|
|
53
53
|
get locationInRepository(): SourceLocation | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The Property that this property overrides, if any
|
|
56
|
+
*/
|
|
57
|
+
get overriddenProperty(): Property | undefined;
|
|
54
58
|
}
|
|
55
59
|
//# sourceMappingURL=property.d.ts.map
|
package/lib/property.js
CHANGED
|
@@ -76,6 +76,16 @@ class Property extends optional_value_1.OptionalValue {
|
|
|
76
76
|
get locationInRepository() {
|
|
77
77
|
return (0, source_1.locationInRepository)(this);
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The Property that this property overrides, if any
|
|
81
|
+
*/
|
|
82
|
+
get overriddenProperty() {
|
|
83
|
+
const o = this.overrides;
|
|
84
|
+
if (o && (o.isClassType() || o.isInterfaceType())) {
|
|
85
|
+
return o.ownProperties.find((p) => p.name === this.name);
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
79
89
|
}
|
|
80
90
|
exports.Property = Property;
|
|
81
91
|
//# sourceMappingURL=property.js.map
|
package/lib/type-system.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsii-reflect",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.118.0",
|
|
4
4
|
"description": "strongly-typed reflection library and tools for jsii",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": {
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
"package": "package-js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@jsii/check-node": "1.
|
|
38
|
-
"@jsii/spec": "1.
|
|
37
|
+
"@jsii/check-node": "1.118.0",
|
|
38
|
+
"@jsii/spec": "1.118.0",
|
|
39
39
|
"chalk": "^4",
|
|
40
40
|
"fs-extra": "^10.1.0",
|
|
41
|
-
"oo-ascii-tree": "^1.
|
|
41
|
+
"oo-ascii-tree": "^1.118.0",
|
|
42
42
|
"yargs": "^17.7.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@scope/jsii-calc-lib": "^1.
|
|
45
|
+
"@scope/jsii-calc-lib": "^1.118.0",
|
|
46
46
|
"@types/fs-extra": "^9.0.13",
|
|
47
47
|
"@types/yargs": "^17.0.33",
|
|
48
48
|
"jsii": "^5.9.10",
|
|
49
|
-
"jsii-build-tools": "^1.
|
|
49
|
+
"jsii-build-tools": "^1.118.0",
|
|
50
50
|
"jsii-calc": "^3.20.120"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -211,14 +211,28 @@ exports[`jsii-tree --all 1`] = `
|
|
|
211
211
|
│ │ │ │ ├─┬ class SubSubclass (stable)
|
|
212
212
|
│ │ │ │ │ ├── base: Subclass
|
|
213
213
|
│ │ │ │ │ └─┬ members
|
|
214
|
-
│ │ │ │ │
|
|
214
|
+
│ │ │ │ │ ├── <initializer>() initializer (stable)
|
|
215
|
+
│ │ │ │ │ ├─┬ sayHello() method (stable)
|
|
216
|
+
│ │ │ │ │ │ └── returns: string
|
|
217
|
+
│ │ │ │ │ ├─┬ name property (stable)
|
|
218
|
+
│ │ │ │ │ │ └── type: string
|
|
219
|
+
│ │ │ │ │ └─┬ unique property (stable)
|
|
220
|
+
│ │ │ │ │ └── type: string
|
|
215
221
|
│ │ │ │ ├─┬ class Subclass (stable)
|
|
216
222
|
│ │ │ │ │ ├── base: Superclass
|
|
217
223
|
│ │ │ │ │ └─┬ members
|
|
218
|
-
│ │ │ │ │
|
|
224
|
+
│ │ │ │ │ ├── <initializer>() initializer (stable)
|
|
225
|
+
│ │ │ │ │ ├─┬ sayHello() method (stable)
|
|
226
|
+
│ │ │ │ │ │ └── returns: string
|
|
227
|
+
│ │ │ │ │ └─┬ name property (stable)
|
|
228
|
+
│ │ │ │ │ └── type: string
|
|
219
229
|
│ │ │ │ ├─┬ class Superclass (stable)
|
|
220
230
|
│ │ │ │ │ └─┬ members
|
|
221
|
-
│ │ │ │ │
|
|
231
|
+
│ │ │ │ │ ├── <initializer>() initializer (stable)
|
|
232
|
+
│ │ │ │ │ ├─┬ sayHello() method (stable)
|
|
233
|
+
│ │ │ │ │ │ └── returns: string
|
|
234
|
+
│ │ │ │ │ └─┬ name property (stable)
|
|
235
|
+
│ │ │ │ │ └── type: string
|
|
222
236
|
│ │ │ │ └─┬ interface IBase (stable)
|
|
223
237
|
│ │ │ │ └─┬ members
|
|
224
238
|
│ │ │ │ └─┬ something property (stable)
|
|
@@ -4510,13 +4524,20 @@ exports[`jsii-tree --members 1`] = `
|
|
|
4510
4524
|
│ │ │ │ │ └── addUnrelatedMember property
|
|
4511
4525
|
│ │ │ │ ├─┬ class SubSubclass
|
|
4512
4526
|
│ │ │ │ │ └─┬ members
|
|
4513
|
-
│ │ │ │ │
|
|
4527
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
4528
|
+
│ │ │ │ │ ├── sayHello() method
|
|
4529
|
+
│ │ │ │ │ ├── name property
|
|
4530
|
+
│ │ │ │ │ └── unique property
|
|
4514
4531
|
│ │ │ │ ├─┬ class Subclass
|
|
4515
4532
|
│ │ │ │ │ └─┬ members
|
|
4516
|
-
│ │ │ │ │
|
|
4533
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
4534
|
+
│ │ │ │ │ ├── sayHello() method
|
|
4535
|
+
│ │ │ │ │ └── name property
|
|
4517
4536
|
│ │ │ │ ├─┬ class Superclass
|
|
4518
4537
|
│ │ │ │ │ └─┬ members
|
|
4519
|
-
│ │ │ │ │
|
|
4538
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
4539
|
+
│ │ │ │ │ ├── sayHello() method
|
|
4540
|
+
│ │ │ │ │ └── name property
|
|
4520
4541
|
│ │ │ │ └─┬ interface IBase
|
|
4521
4542
|
│ │ │ │ └─┬ members
|
|
4522
4543
|
│ │ │ │ └── something property
|
|
@@ -406,14 +406,28 @@ exports[`showAll 1`] = `
|
|
|
406
406
|
│ │ │ │ ├─┬ class SubSubclass
|
|
407
407
|
│ │ │ │ │ ├── base: Subclass
|
|
408
408
|
│ │ │ │ │ └─┬ members
|
|
409
|
-
│ │ │ │ │
|
|
409
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
410
|
+
│ │ │ │ │ ├─┬ sayHello() method
|
|
411
|
+
│ │ │ │ │ │ └── returns: string
|
|
412
|
+
│ │ │ │ │ ├─┬ name property
|
|
413
|
+
│ │ │ │ │ │ └── type: string
|
|
414
|
+
│ │ │ │ │ └─┬ unique property
|
|
415
|
+
│ │ │ │ │ └── type: string
|
|
410
416
|
│ │ │ │ ├─┬ class Subclass
|
|
411
417
|
│ │ │ │ │ ├── base: Superclass
|
|
412
418
|
│ │ │ │ │ └─┬ members
|
|
413
|
-
│ │ │ │ │
|
|
419
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
420
|
+
│ │ │ │ │ ├─┬ sayHello() method
|
|
421
|
+
│ │ │ │ │ │ └── returns: string
|
|
422
|
+
│ │ │ │ │ └─┬ name property
|
|
423
|
+
│ │ │ │ │ └── type: string
|
|
414
424
|
│ │ │ │ ├─┬ class Superclass
|
|
415
425
|
│ │ │ │ │ └─┬ members
|
|
416
|
-
│ │ │ │ │
|
|
426
|
+
│ │ │ │ │ ├── <initializer>() initializer
|
|
427
|
+
│ │ │ │ │ ├─┬ sayHello() method
|
|
428
|
+
│ │ │ │ │ │ └── returns: string
|
|
429
|
+
│ │ │ │ │ └─┬ name property
|
|
430
|
+
│ │ │ │ │ └── type: string
|
|
417
431
|
│ │ │ │ └─┬ interface IBase
|
|
418
432
|
│ │ │ │ └─┬ members
|
|
419
433
|
│ │ │ │ └─┬ something property
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const hierarchical_set_1 = require("../lib/hierarchical-set");
|
|
4
|
+
test('empty set', () => {
|
|
5
|
+
expect(Array.from(new hierarchical_set_1.HierarchicalSet())).toEqual([]);
|
|
6
|
+
});
|
|
7
|
+
test('set iteration', () => {
|
|
8
|
+
const hs = new hierarchical_set_1.HierarchicalSet([
|
|
9
|
+
['a'],
|
|
10
|
+
['a', 'b', 'c'],
|
|
11
|
+
['a', 'b', 'd'],
|
|
12
|
+
['a', 'e'],
|
|
13
|
+
['f'],
|
|
14
|
+
]);
|
|
15
|
+
expect(Array.from(hs)).toEqual([
|
|
16
|
+
['a'],
|
|
17
|
+
['a', 'b', 'c'],
|
|
18
|
+
['a', 'b', 'd'],
|
|
19
|
+
['a', 'e'],
|
|
20
|
+
['f'],
|
|
21
|
+
]);
|
|
22
|
+
});
|
|
23
|
+
test('add prefix after child', () => {
|
|
24
|
+
const hs = new hierarchical_set_1.HierarchicalSet();
|
|
25
|
+
hs.addAll([['a', 'b']]);
|
|
26
|
+
hs.addAll([['a']]);
|
|
27
|
+
expect(Array.from(hs)).toEqual([['a'], ['a', 'b']]);
|
|
28
|
+
});
|
|
29
|
+
describe('remove', () => {
|
|
30
|
+
test('remove literals', () => {
|
|
31
|
+
const x = new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c'], ['d']]);
|
|
32
|
+
x.remove([['a', 'b'], ['c']]);
|
|
33
|
+
expect(Array.from(x)).toEqual([['d']]);
|
|
34
|
+
});
|
|
35
|
+
test('remove parents', () => {
|
|
36
|
+
const x = new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c'], ['d']]);
|
|
37
|
+
x.remove([['a']]);
|
|
38
|
+
expect(Array.from(x)).toEqual([['c'], ['d']]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('intersect', () => {
|
|
42
|
+
test('retains literal elements', () => {
|
|
43
|
+
const x = new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c'], ['d']]);
|
|
44
|
+
x.intersect(new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c']]));
|
|
45
|
+
expect(Array.from(x)).toEqual([['a', 'b'], ['c']]);
|
|
46
|
+
});
|
|
47
|
+
test('retains children of parents', () => {
|
|
48
|
+
const x = new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c'], ['d']]);
|
|
49
|
+
x.intersect(new hierarchical_set_1.HierarchicalSet([['a']]));
|
|
50
|
+
expect(Array.from(x)).toEqual([['a', 'b']]);
|
|
51
|
+
});
|
|
52
|
+
test('parent and child only retains child', () => {
|
|
53
|
+
const x = new hierarchical_set_1.HierarchicalSet([['a'], ['a', 'b']]);
|
|
54
|
+
x.intersect(new hierarchical_set_1.HierarchicalSet([['a', 'b'], ['c']]));
|
|
55
|
+
expect(Array.from(x)).toEqual([['a', 'b']]);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=hierarchical-set.test.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const jsii_query_1 = require("../lib/jsii-query");
|
|
5
|
+
describe('parseExpression', () => {
|
|
6
|
+
test('+', () => {
|
|
7
|
+
expect((0, jsii_query_1.parseExpression)('+type')).toMatchObject({
|
|
8
|
+
op: 'select',
|
|
9
|
+
kind: 'type',
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
test('-', () => {
|
|
13
|
+
expect((0, jsii_query_1.parseExpression)('-type')).toMatchObject({
|
|
14
|
+
op: 'filter',
|
|
15
|
+
kind: 'type',
|
|
16
|
+
remove: true,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
test('.', () => {
|
|
20
|
+
expect((0, jsii_query_1.parseExpression)('.type')).toMatchObject({
|
|
21
|
+
op: 'filter',
|
|
22
|
+
kind: 'type',
|
|
23
|
+
remove: false,
|
|
24
|
+
});
|
|
25
|
+
expect((0, jsii_query_1.parseExpression)('type')).toMatchObject({
|
|
26
|
+
op: 'filter',
|
|
27
|
+
kind: 'type',
|
|
28
|
+
remove: false,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
test('with expression', () => {
|
|
32
|
+
expect((0, jsii_query_1.parseExpression)('.property:name.startsWith("x")')).toMatchObject({
|
|
33
|
+
op: 'filter',
|
|
34
|
+
kind: 'property',
|
|
35
|
+
remove: false,
|
|
36
|
+
expression: 'name.startsWith("x")',
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('Predicate', () => {
|
|
41
|
+
test('Simple', () => {
|
|
42
|
+
const p = new jsii_query_1.Predicate('name.startsWith("ba")');
|
|
43
|
+
expect(p.apply({ name: 'banana' })).toBeTruthy();
|
|
44
|
+
expect(p.apply({ name: 'blob' })).toBeFalsy();
|
|
45
|
+
});
|
|
46
|
+
test('empty', () => {
|
|
47
|
+
const p = new jsii_query_1.Predicate();
|
|
48
|
+
expect(p.apply({ name: 'banana' })).toBeTruthy();
|
|
49
|
+
expect(p.apply({ name: 'blob' })).toBeTruthy();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('filtering', () => {
|
|
53
|
+
test('empty filter returns everything', async () => {
|
|
54
|
+
const result = await query([], 'members');
|
|
55
|
+
expect(result.length).toBeGreaterThan(700);
|
|
56
|
+
expect(result).toContainEqual('readonly jsii-calc.ExportedBaseClass#success: boolean');
|
|
57
|
+
});
|
|
58
|
+
test('filter on method name', async () => {
|
|
59
|
+
const result = await query([(0, jsii_query_1.parseExpression)('method:name.includes("con")')], 'members');
|
|
60
|
+
expect(result).toContainEqual('static @scope/jsii-calc-base-of-base.StaticConsumer#consume(..._args: any[]): void');
|
|
61
|
+
});
|
|
62
|
+
test('filter on methods but expect types', async () => {
|
|
63
|
+
const result = await query([(0, jsii_query_1.parseExpression)('method:name.includes("con")')], 'types');
|
|
64
|
+
expect(result).toContainEqual('class @scope/jsii-calc-base-of-base.StaticConsumer');
|
|
65
|
+
});
|
|
66
|
+
test('filter on type but expect members', async () => {
|
|
67
|
+
const result = await query([(0, jsii_query_1.parseExpression)('class:name == "StaticConsumer"')], 'members');
|
|
68
|
+
expect(result).toContainEqual('static @scope/jsii-calc-base-of-base.StaticConsumer#consume(..._args: any[]): void');
|
|
69
|
+
});
|
|
70
|
+
test('filter on classes with a separate expression', async () => {
|
|
71
|
+
const result = await query([
|
|
72
|
+
(0, jsii_query_1.parseExpression)('method:name.includes("con")'),
|
|
73
|
+
(0, jsii_query_1.parseExpression)('class'),
|
|
74
|
+
], 'members');
|
|
75
|
+
expect(result).toContainEqual('static @scope/jsii-calc-base-of-base.StaticConsumer#consume(..._args: any[]): void');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
async function query(exp, what = 'all') {
|
|
79
|
+
const jsiiCalcDir = path.dirname(require.resolve('jsii-calc/package.json'));
|
|
80
|
+
const result = await (0, jsii_query_1.jsiiQuery)({
|
|
81
|
+
fileName: jsiiCalcDir,
|
|
82
|
+
expressions: exp,
|
|
83
|
+
returnMembers: what !== 'types',
|
|
84
|
+
returnTypes: what !== 'members',
|
|
85
|
+
});
|
|
86
|
+
return result.map(jsii_query_1.renderElement);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=jsii-query.test.js.map
|
package/test/type-system.test.js
CHANGED
|
@@ -180,6 +180,8 @@ test('overridden member knows about both parent types', () => {
|
|
|
180
180
|
expect(booMethod.parentType).toBe(subType);
|
|
181
181
|
expect(booMethod.definingType).toBe(subType);
|
|
182
182
|
expect(booMethod.overrides).toBe(superType);
|
|
183
|
+
const superBooMethod = superType.allMethods.find((m) => m.name === 'boo');
|
|
184
|
+
expect(booMethod.overriddenMethod).toEqual(superBooMethod);
|
|
183
185
|
});
|
|
184
186
|
describe('Stability', () => {
|
|
185
187
|
test('can be read on an item', () => {
|