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 ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('./jsii-query.js');
@@ -0,0 +1,2 @@
1
+ import '@jsii/check-node/run';
2
+ //# sourceMappingURL=jsii-query.d.ts.map
@@ -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
@@ -44,6 +44,7 @@ export declare class TypeSystem {
44
44
  */
45
45
  loadNpmDependencies(packageRoot: string, options?: {
46
46
  validate?: boolean;
47
+ supportedFeatures?: JsiiFeature[];
47
48
  }): Promise<void>;
48
49
  /**
49
50
  * Loads a jsii module or a single .jsii file into the type system.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsii-reflect",
3
- "version": "1.117.0",
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.117.0",
38
- "@jsii/spec": "1.117.0",
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.117.0",
41
+ "oo-ascii-tree": "^1.118.0",
42
42
  "yargs": "^17.7.2"
43
43
  },
44
44
  "devDependencies": {
45
- "@scope/jsii-calc-lib": "^1.117.0",
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.117.0",
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
- │ │ │ │ │ └── <initializer>() initializer (stable)
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
- │ │ │ │ │ └── <initializer>() initializer (stable)
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
- │ │ │ │ │ └── <initializer>() initializer (stable)
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
- │ │ │ │ │ └── <initializer>() initializer
4527
+ │ │ │ │ │ ├── <initializer>() initializer
4528
+ │ │ │ │ │ ├── sayHello() method
4529
+ │ │ │ │ │ ├── name property
4530
+ │ │ │ │ │ └── unique property
4514
4531
  │ │ │ │ ├─┬ class Subclass
4515
4532
  │ │ │ │ │ └─┬ members
4516
- │ │ │ │ │ └── <initializer>() initializer
4533
+ │ │ │ │ │ ├── <initializer>() initializer
4534
+ │ │ │ │ │ ├── sayHello() method
4535
+ │ │ │ │ │ └── name property
4517
4536
  │ │ │ │ ├─┬ class Superclass
4518
4537
  │ │ │ │ │ └─┬ members
4519
- │ │ │ │ │ └── <initializer>() initializer
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
- │ │ │ │ │ └── <initializer>() initializer
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
- │ │ │ │ │ └── <initializer>() initializer
419
+ │ │ │ │ │ ├── <initializer>() initializer
420
+ │ │ │ │ │ ├─┬ sayHello() method
421
+ │ │ │ │ │ │ └── returns: string
422
+ │ │ │ │ │ └─┬ name property
423
+ │ │ │ │ │ └── type: string
414
424
  │ │ │ │ ├─┬ class Superclass
415
425
  │ │ │ │ │ └─┬ members
416
- │ │ │ │ │ └── <initializer>() initializer
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hierarchical-set.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=jsii-query.test.d.ts.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
@@ -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', () => {