expo-modules-test-core 56.0.0 → 56.0.2
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/LICENSE +21 -0
- package/android/build.gradle +2 -2
- package/build/index.js +18 -16
- package/build/index.js.map +1 -1
- package/package.json +12 -8
- package/src/index.ts +18 -16
- package/build/getStructure.d.ts +0 -3
- package/build/getStructure.d.ts.map +0 -1
- package/build/getStructure.js +0 -244
- package/build/getStructure.js.map +0 -1
- package/build/mockgen.d.ts +0 -4
- package/build/mockgen.d.ts.map +0 -1
- package/build/mockgen.js +0 -391
- package/build/mockgen.js.map +0 -1
- package/build/types.d.ts +0 -55
- package/build/types.d.ts.map +0 -1
- package/build/types.js +0 -3
- package/build/types.js.map +0 -1
- package/src/getStructure.ts +0 -299
- package/src/mockgen.ts +0 -525
- package/src/types.ts +0 -65
package/src/getStructure.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
// convert requires above to imports
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import fsNode from 'fs';
|
|
4
|
-
import { globSync } from 'glob';
|
|
5
|
-
import XML from 'xml-js';
|
|
6
|
-
import YAML from 'yaml';
|
|
7
|
-
|
|
8
|
-
import type {
|
|
9
|
-
Closure,
|
|
10
|
-
CursorInfoOutput,
|
|
11
|
-
FileType,
|
|
12
|
-
FullyAnnotatedDecl,
|
|
13
|
-
OutputModuleDefinition,
|
|
14
|
-
Structure,
|
|
15
|
-
} from './types';
|
|
16
|
-
|
|
17
|
-
const rootDir = process.cwd();
|
|
18
|
-
const pattern = `${rootDir}/**/*.swift`;
|
|
19
|
-
|
|
20
|
-
function getStructureFromFile(file: FileType) {
|
|
21
|
-
const command = 'sourcekitten structure --file ' + file.path;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
const output = execSync(command);
|
|
25
|
-
return JSON.parse(output.toString());
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error('An error occurred while executing the command:', error);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
// find an object with "key.typename" : "ModuleDefinition" somewhere in the structure and return it
|
|
31
|
-
function findModuleDefinitionInStructure(structure: Structure): Structure[] | null {
|
|
32
|
-
if (!structure) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
if (structure?.['key.typename'] === 'ModuleDefinition') {
|
|
36
|
-
const root = structure?.['key.substructure'];
|
|
37
|
-
if (!root) {
|
|
38
|
-
console.warn('Found ModuleDefinition but it is malformed');
|
|
39
|
-
}
|
|
40
|
-
return root;
|
|
41
|
-
}
|
|
42
|
-
const substructure = structure['key.substructure'];
|
|
43
|
-
if (Array.isArray(substructure) && substructure.length > 0) {
|
|
44
|
-
for (const child of substructure) {
|
|
45
|
-
let result = null;
|
|
46
|
-
result = findModuleDefinitionInStructure(child);
|
|
47
|
-
if (result) {
|
|
48
|
-
return result;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Read string straight from file – needed since we can't get cursorinfo for modulename
|
|
56
|
-
function getIdentifierFromOffsetObject(offsetObject: Structure, file: FileType) {
|
|
57
|
-
// adding 1 and removing 1 to get rid of quotes
|
|
58
|
-
return file.content
|
|
59
|
-
.substring(offsetObject['key.offset'], offsetObject['key.offset'] + offsetObject['key.length'])
|
|
60
|
-
.replaceAll('"', '');
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function maybeUnwrapXMLStructs(type: string | Partial<{ _text: string; 'ref.struct': string }>) {
|
|
64
|
-
if (!type) {
|
|
65
|
-
return type;
|
|
66
|
-
}
|
|
67
|
-
if (typeof type === 'string') {
|
|
68
|
-
return type;
|
|
69
|
-
}
|
|
70
|
-
if (type['_text']) {
|
|
71
|
-
return type['_text'];
|
|
72
|
-
}
|
|
73
|
-
if (type['ref.struct']) {
|
|
74
|
-
return maybeUnwrapXMLStructs(type['ref.struct']);
|
|
75
|
-
}
|
|
76
|
-
return type;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function maybeWrapArray<T>(itemOrItems: T[] | T | null) {
|
|
80
|
-
if (!itemOrItems) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
if (Array.isArray(itemOrItems)) {
|
|
84
|
-
return itemOrItems;
|
|
85
|
-
} else {
|
|
86
|
-
return [itemOrItems];
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function parseXMLAnnotatedDeclarations(cursorInfoOutput: CursorInfoOutput) {
|
|
91
|
-
const xml = cursorInfoOutput['key.fully_annotated_decl'];
|
|
92
|
-
if (!xml) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
const parsed = XML.xml2js(xml, { compact: true }) as FullyAnnotatedDecl;
|
|
96
|
-
|
|
97
|
-
const parameters =
|
|
98
|
-
maybeWrapArray(parsed?.['decl.function.free']?.['decl.var.parameter'])?.map((p) => ({
|
|
99
|
-
name: maybeUnwrapXMLStructs(p['decl.var.parameter.argument_label']),
|
|
100
|
-
typename: maybeUnwrapXMLStructs(p['decl.var.parameter.type']),
|
|
101
|
-
})) ?? [];
|
|
102
|
-
const returnType = maybeUnwrapXMLStructs(
|
|
103
|
-
parsed?.['decl.function.free']?.['decl.function.returntype']
|
|
104
|
-
);
|
|
105
|
-
return { parameters, returnType };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
let cachedSDKPath: string | null = null;
|
|
109
|
-
function getSDKPath() {
|
|
110
|
-
if (cachedSDKPath) {
|
|
111
|
-
return cachedSDKPath;
|
|
112
|
-
}
|
|
113
|
-
const sdkPath = execSync('xcrun --sdk iphoneos --show-sdk-path').toString().trim();
|
|
114
|
-
cachedSDKPath = sdkPath;
|
|
115
|
-
return cachedSDKPath;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Read type description with sourcekitten, works only for variables
|
|
119
|
-
function getTypeFromOffsetObject(offsetObject: Structure, file: FileType) {
|
|
120
|
-
if (!offsetObject) {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
const request = {
|
|
124
|
-
'key.request': 'source.request.cursorinfo',
|
|
125
|
-
'key.sourcefile': file.path,
|
|
126
|
-
'key.offset': offsetObject['key.offset'],
|
|
127
|
-
'key.compilerargs': [file.path, '-target', 'arm64-apple-ios', '-sdk', getSDKPath()],
|
|
128
|
-
};
|
|
129
|
-
const yamlRequest = YAML.stringify(request, {
|
|
130
|
-
defaultStringType: 'QUOTE_DOUBLE',
|
|
131
|
-
lineWidth: 0,
|
|
132
|
-
defaultKeyType: 'PLAIN',
|
|
133
|
-
// needed since behaviour of sourcekitten is not consistent
|
|
134
|
-
} as any).replace('"source.request.cursorinfo"', 'source.request.cursorinfo');
|
|
135
|
-
|
|
136
|
-
const command = 'sourcekitten request --yaml "' + yamlRequest.replaceAll('"', '\\"') + '"';
|
|
137
|
-
try {
|
|
138
|
-
const output = execSync(command, { stdio: 'pipe' });
|
|
139
|
-
return parseXMLAnnotatedDeclarations(JSON.parse(output.toString()));
|
|
140
|
-
} catch (error) {
|
|
141
|
-
console.error('An error occurred while executing the command:', error);
|
|
142
|
-
}
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function hasSubstructure(structureObject: Structure) {
|
|
147
|
-
return structureObject?.['key.substructure'] && structureObject['key.substructure'].length > 0;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function parseClosureTypes(structureObject: Structure) {
|
|
151
|
-
const closure = structureObject['key.substructure']?.find(
|
|
152
|
-
(s) => s['key.kind'] === 'source.lang.swift.expr.closure'
|
|
153
|
-
);
|
|
154
|
-
if (!closure) {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
const parameters = closure['key.substructure']
|
|
158
|
-
?.filter((s) => s['key.kind'] === 'source.lang.swift.decl.var.parameter')
|
|
159
|
-
.map((p) => ({ name: p['key.name'], typename: p['key.typename'] }));
|
|
160
|
-
|
|
161
|
-
const returnType = closure?.['key.typename'] ?? 'unknown';
|
|
162
|
-
return { parameters, returnType };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Used for functions,async functions, all of shape Identifier(name, closure or function)
|
|
166
|
-
function findNamedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) {
|
|
167
|
-
const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);
|
|
168
|
-
|
|
169
|
-
return definitionsOfType.reduce<
|
|
170
|
-
{ name: string; types: ReturnType<typeof getTypeFromOffsetObject> }[]
|
|
171
|
-
>((acc, d) => {
|
|
172
|
-
const definitionParams = d['key.substructure'];
|
|
173
|
-
|
|
174
|
-
if (definitionParams[0] == null) {
|
|
175
|
-
return acc;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const name = getIdentifierFromOffsetObject(definitionParams[0], file);
|
|
179
|
-
let types = null;
|
|
180
|
-
|
|
181
|
-
if (definitionParams[1] == null) {
|
|
182
|
-
acc.push({ name, types });
|
|
183
|
-
return acc;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (hasSubstructure(definitionParams[1])) {
|
|
187
|
-
types = parseClosureTypes(definitionParams[1]);
|
|
188
|
-
} else {
|
|
189
|
-
types = getTypeFromOffsetObject(definitionParams[1], file);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
acc.push({ name, types });
|
|
193
|
-
return acc;
|
|
194
|
-
}, []);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Used for events
|
|
198
|
-
function findGroupedDefinitionsOfType(type: string, moduleDefinition: Structure[], file: FileType) {
|
|
199
|
-
const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);
|
|
200
|
-
return definitionsOfType.flatMap((d) => {
|
|
201
|
-
const definitionParams = d['key.substructure'];
|
|
202
|
-
return definitionParams.map((d) => ({ name: getIdentifierFromOffsetObject(d, file) }));
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
function findAndParseNestedClassesOfType(
|
|
206
|
-
moduleDefinition: Structure[],
|
|
207
|
-
file: FileType,
|
|
208
|
-
type: string
|
|
209
|
-
) {
|
|
210
|
-
// we support reading definitions from closure only
|
|
211
|
-
const definitionsOfType = moduleDefinition.filter((md) => md['key.name'] === type);
|
|
212
|
-
return definitionsOfType
|
|
213
|
-
.map((df) => {
|
|
214
|
-
const nestedModuleDefinition =
|
|
215
|
-
df['key.substructure']?.[1]?.['key.substructure']?.[0]?.['key.substructure']?.[0]?.[
|
|
216
|
-
'key.substructure'
|
|
217
|
-
];
|
|
218
|
-
const nameStructure = df['key.substructure']?.[0];
|
|
219
|
-
if (!nestedModuleDefinition || !nameStructure) {
|
|
220
|
-
console.warn('Could not parse definition');
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
const name = getIdentifierFromOffsetObject(nameStructure, file).replace('.self', '');
|
|
224
|
-
// let's drop nested view field and classes (are null anyways)
|
|
225
|
-
const {
|
|
226
|
-
views: _,
|
|
227
|
-
classes: _2,
|
|
228
|
-
...definition
|
|
229
|
-
} = parseModuleDefinition(nestedModuleDefinition, file);
|
|
230
|
-
return { ...definition, name };
|
|
231
|
-
})
|
|
232
|
-
.flatMap((f) => (f ? [f] : []));
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function omitParamsFromClosureArguments<T extends Closure>(
|
|
236
|
-
definitions: T[],
|
|
237
|
-
paramsToOmit: string[]
|
|
238
|
-
) {
|
|
239
|
-
return definitions.map((d) => ({
|
|
240
|
-
...d,
|
|
241
|
-
types: {
|
|
242
|
-
...d.types,
|
|
243
|
-
parameters: d.types?.parameters?.filter((t, idx) => !paramsToOmit.includes(t.name)) ?? [],
|
|
244
|
-
},
|
|
245
|
-
}));
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Some blocks have additional modifiers like runOnQueue – we may need to do additional traversing to get to the function definition
|
|
249
|
-
function parseBlockModifiers(structureObject: Structure) {
|
|
250
|
-
if (structureObject['key.name']?.includes('runOnQueue')) {
|
|
251
|
-
const structure = structureObject['key.substructure'][0];
|
|
252
|
-
if (structure != null) {
|
|
253
|
-
return structure;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return structureObject;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function parseModuleDefinition(
|
|
260
|
-
moduleDefinition: Structure[],
|
|
261
|
-
file: FileType
|
|
262
|
-
): OutputModuleDefinition {
|
|
263
|
-
const preparedModuleDefinition = moduleDefinition.map(parseBlockModifiers);
|
|
264
|
-
const parsedDefinition = {
|
|
265
|
-
name: findNamedDefinitionsOfType('Name', preparedModuleDefinition, file)[0]?.name ?? '',
|
|
266
|
-
functions: findNamedDefinitionsOfType('Function', preparedModuleDefinition, file),
|
|
267
|
-
asyncFunctions: omitParamsFromClosureArguments(
|
|
268
|
-
findNamedDefinitionsOfType('AsyncFunction', preparedModuleDefinition, file),
|
|
269
|
-
['promise']
|
|
270
|
-
),
|
|
271
|
-
events: findGroupedDefinitionsOfType('Events', preparedModuleDefinition, file),
|
|
272
|
-
properties: findNamedDefinitionsOfType('Property', preparedModuleDefinition, file),
|
|
273
|
-
props: omitParamsFromClosureArguments(
|
|
274
|
-
findNamedDefinitionsOfType('Prop', preparedModuleDefinition, file),
|
|
275
|
-
['view']
|
|
276
|
-
),
|
|
277
|
-
constants: findNamedDefinitionsOfType('Constant', preparedModuleDefinition, file),
|
|
278
|
-
views: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'View'),
|
|
279
|
-
classes: findAndParseNestedClassesOfType(preparedModuleDefinition, file, 'Class'),
|
|
280
|
-
};
|
|
281
|
-
return parsedDefinition;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function findModuleDefinitionsInFiles(files: string[]) {
|
|
285
|
-
const modules = [];
|
|
286
|
-
for (const path of files) {
|
|
287
|
-
const file = { path, content: fsNode.readFileSync(path, 'utf8') };
|
|
288
|
-
const definition = findModuleDefinitionInStructure(getStructureFromFile(file));
|
|
289
|
-
if (definition) {
|
|
290
|
-
modules.push(parseModuleDefinition(definition, file));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return modules;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export function getAllExpoModulesInWorkingDirectory() {
|
|
297
|
-
const files = globSync(pattern);
|
|
298
|
-
return findModuleDefinitionsInFiles(files);
|
|
299
|
-
}
|