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.
@@ -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
- }