expo-type-information 0.0.9 → 0.0.11
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/build/commands/inlineModulesInterfaceCommand.js +38 -6
- package/build/commands/inlineModulesInterfaceCommand.js.map +1 -1
- package/build/swift/sourcekittenTypeInformation.js +108 -12
- package/build/swift/sourcekittenTypeInformation.js.map +1 -1
- package/build/types.d.ts +1 -0
- package/package.json +2 -2
- package/src/commands/inlineModulesInterfaceCommand.ts +42 -6
- package/src/swift/sourcekittenTypeInformation.ts +150 -29
- package/src/types.ts +1 -0
- package/tests/TestModule.swift +38 -1
- package/tests/__snapshots__/typeInformation.test.ts.snap +114 -34
|
@@ -47,6 +47,8 @@ const swiftDeclarationKind = {
|
|
|
47
47
|
varParameter: 'source.lang.swift.decl.var.parameter',
|
|
48
48
|
closure: 'source.lang.swift.expr.closure',
|
|
49
49
|
enumcase: 'source.lang.swift.decl.enumcase',
|
|
50
|
+
varStatic: 'source.lang.swift.decl.var.static',
|
|
51
|
+
varGlobal: 'source.lang.swift.decl.var.global',
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
function isSwiftDictionary(type: string): boolean {
|
|
@@ -82,6 +84,14 @@ function isEnumStructure(structure: Structure): boolean {
|
|
|
82
84
|
return structure['key.kind'] === swiftDeclarationKind.enum;
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
function isClassStructure(structure: Structure): boolean {
|
|
88
|
+
return structure['key.kind'] === swiftDeclarationKind.class;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isStructStructure(structure: Structure): boolean {
|
|
92
|
+
return structure['key.kind'] === swiftDeclarationKind.struct;
|
|
93
|
+
}
|
|
94
|
+
|
|
85
95
|
function isRecordStructure(structure: Structure): boolean {
|
|
86
96
|
const isRecordOrClass =
|
|
87
97
|
structure['key.kind'] === swiftDeclarationKind.struct ||
|
|
@@ -256,6 +266,66 @@ function getIdentifierFromOffsetObject(offsetObject: Structure, file: FileType)
|
|
|
256
266
|
return file.content.substring(startIndex, endIndex).replaceAll('"', '');
|
|
257
267
|
}
|
|
258
268
|
|
|
269
|
+
function getLiteralOrResolvedIdentifier(offsetObject: Structure, ctx: ParseContext): string {
|
|
270
|
+
const { namespaces, file } = ctx;
|
|
271
|
+
const startIndex = offsetObject['key.offset'];
|
|
272
|
+
const endIndex = offsetObject['key.offset'] + offsetObject['key.length'];
|
|
273
|
+
const literalOrIdentifier = file.content.substring(startIndex, endIndex);
|
|
274
|
+
|
|
275
|
+
if (literalOrIdentifier.startsWith('"')) {
|
|
276
|
+
return literalOrIdentifier.replaceAll('"', '');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const parts = literalOrIdentifier.split('.');
|
|
280
|
+
|
|
281
|
+
const traverse = (baseObj: namespace | string | null, keys: string[]) => {
|
|
282
|
+
let current = baseObj;
|
|
283
|
+
for (const key of keys) {
|
|
284
|
+
if (typeof current === 'string' || current === null) {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
const subNamespace = current[key];
|
|
288
|
+
if (subNamespace === undefined) {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
current = subNamespace;
|
|
292
|
+
}
|
|
293
|
+
return current;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const n0 = traverse(namespaces, parts);
|
|
297
|
+
if (typeof n0 === 'string') {
|
|
298
|
+
return n0.replaceAll('"', '');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const n1 = traverse(namespaces[''] || {}, parts);
|
|
302
|
+
if (typeof n1 === 'string') {
|
|
303
|
+
return n1.replaceAll('"', '');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return parts[parts.length - 1] ?? literalOrIdentifier;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function isStringLiteral(str: string): boolean {
|
|
310
|
+
return str.length > 1 && str[0] == '"' && str[str.length - 1] == '"';
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function getInitializerValue(structure: Structure, file: FileType): string | null {
|
|
314
|
+
const nameEnd = structure['key.nameoffset'] + structure['key.namelength'];
|
|
315
|
+
const declarationEnd = structure['key.offset'] + structure['key.length'];
|
|
316
|
+
if (!nameEnd || !declarationEnd) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
const valueSubstring = file.content.substring(nameEnd, declarationEnd);
|
|
320
|
+
const indexOfInitializerStart = valueSubstring.indexOf('=');
|
|
321
|
+
const initializer = valueSubstring.slice(indexOfInitializerStart + 1).trim();
|
|
322
|
+
|
|
323
|
+
if (!isStringLiteral(initializer)) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
return initializer;
|
|
327
|
+
}
|
|
328
|
+
|
|
259
329
|
function hasSubstructure(structure: Structure) {
|
|
260
330
|
return structure?.['key.substructure'] && structure['key.substructure'].length > 0;
|
|
261
331
|
}
|
|
@@ -518,9 +588,10 @@ function getClosureBodyStructure(structure: Structure): Structure | null {
|
|
|
518
588
|
|
|
519
589
|
async function parseModuleClassStructure(
|
|
520
590
|
structure: Structure,
|
|
521
|
-
|
|
522
|
-
|
|
591
|
+
options: SwiftFileTypeInformationOptions,
|
|
592
|
+
ctx: ParseContext
|
|
523
593
|
): Promise<ClassDeclaration> {
|
|
594
|
+
const { file } = ctx;
|
|
524
595
|
const nestedModuleSubstructure = getClosureBodyStructure(structure)?.['key.substructure'];
|
|
525
596
|
const nameSubstrucutre = structure['key.substructure']?.[0];
|
|
526
597
|
const name = nameSubstrucutre
|
|
@@ -542,10 +613,10 @@ async function parseModuleClassStructure(
|
|
|
542
613
|
// `parseModuleStructure` returns `ModuleClassDeclaration` with a found name or with the provided 'UNUSED_NAME', we don't need it here.
|
|
543
614
|
const classTypeInfo = await parseModuleStructure(
|
|
544
615
|
nestedModuleSubstructure,
|
|
545
|
-
file,
|
|
546
616
|
'UNUSED_NAME',
|
|
547
617
|
structure['key.offset'],
|
|
548
|
-
options
|
|
618
|
+
options,
|
|
619
|
+
ctx
|
|
549
620
|
);
|
|
550
621
|
return {
|
|
551
622
|
name,
|
|
@@ -615,9 +686,10 @@ async function parseModulePropDeclaration(
|
|
|
615
686
|
|
|
616
687
|
async function parseModuleViewDeclaration(
|
|
617
688
|
substructure: Structure,
|
|
618
|
-
|
|
619
|
-
|
|
689
|
+
options: SwiftFileTypeInformationOptions,
|
|
690
|
+
ctx: ParseContext
|
|
620
691
|
): Promise<ViewDeclaration | null> {
|
|
692
|
+
const { file } = ctx;
|
|
621
693
|
// The View arguments is a.self for some class a we want.
|
|
622
694
|
const suffixLength = 5;
|
|
623
695
|
const nameSubstrucutre = substructure['key.substructure']?.[0];
|
|
@@ -634,17 +706,20 @@ async function parseModuleViewDeclaration(
|
|
|
634
706
|
|
|
635
707
|
return await parseModuleStructure(
|
|
636
708
|
viewSubstructure,
|
|
637
|
-
file,
|
|
638
709
|
name,
|
|
639
710
|
viewStructure['key.offset'],
|
|
640
|
-
options
|
|
711
|
+
options,
|
|
712
|
+
ctx
|
|
641
713
|
);
|
|
642
714
|
}
|
|
643
715
|
|
|
644
|
-
function parseModuleEventDeclaration(structure: Structure,
|
|
645
|
-
structure['key.substructure'].forEach((substructure) =>
|
|
646
|
-
|
|
647
|
-
|
|
716
|
+
function parseModuleEventDeclaration(structure: Structure, events: string[], ctx: ParseContext) {
|
|
717
|
+
structure['key.substructure'].forEach((substructure) => {
|
|
718
|
+
const eventName = getLiteralOrResolvedIdentifier(substructure, ctx);
|
|
719
|
+
if (eventName) {
|
|
720
|
+
events.push(eventName);
|
|
721
|
+
}
|
|
722
|
+
});
|
|
648
723
|
}
|
|
649
724
|
|
|
650
725
|
function hasFieldAttribute(attributes: Attribute[] | null, file: FileType): boolean {
|
|
@@ -740,13 +815,23 @@ function parsePropertyString(
|
|
|
740
815
|
};
|
|
741
816
|
}
|
|
742
817
|
|
|
818
|
+
type namespace = {
|
|
819
|
+
[key: string]: namespace | string | null;
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
type ParseContext = {
|
|
823
|
+
file: FileType;
|
|
824
|
+
namespaces: { [key: string]: namespace };
|
|
825
|
+
};
|
|
826
|
+
|
|
743
827
|
async function parseModuleStructure(
|
|
744
828
|
moduleStructure: Structure[],
|
|
745
|
-
file: FileType,
|
|
746
829
|
name: string,
|
|
747
830
|
definitionOffset: number,
|
|
748
|
-
options: SwiftFileTypeInformationOptions
|
|
831
|
+
options: SwiftFileTypeInformationOptions,
|
|
832
|
+
ctx: ParseContext
|
|
749
833
|
): Promise<ModuleClassDeclaration> {
|
|
834
|
+
const { file } = ctx;
|
|
750
835
|
const moduleClassDeclaration: ModuleClassDeclaration = {
|
|
751
836
|
name,
|
|
752
837
|
constants: [],
|
|
@@ -797,7 +882,7 @@ async function parseModuleStructure(
|
|
|
797
882
|
}
|
|
798
883
|
case 'Class':
|
|
799
884
|
moduleClassDeclaration.classes.push(
|
|
800
|
-
await parseModuleClassStructure(structure,
|
|
885
|
+
await parseModuleClassStructure(structure, options, ctx)
|
|
801
886
|
);
|
|
802
887
|
break;
|
|
803
888
|
case 'Property': {
|
|
@@ -835,14 +920,14 @@ async function parseModuleStructure(
|
|
|
835
920
|
);
|
|
836
921
|
break;
|
|
837
922
|
case 'View': {
|
|
838
|
-
const viewDeclaration = await parseModuleViewDeclaration(structure,
|
|
923
|
+
const viewDeclaration = await parseModuleViewDeclaration(structure, options, ctx);
|
|
839
924
|
if (viewDeclaration) {
|
|
840
925
|
moduleClassDeclaration.views.push(viewDeclaration);
|
|
841
926
|
}
|
|
842
927
|
break;
|
|
843
928
|
}
|
|
844
929
|
case 'Events':
|
|
845
|
-
parseModuleEventDeclaration(structure,
|
|
930
|
+
parseModuleEventDeclaration(structure, moduleClassDeclaration.events, ctx);
|
|
846
931
|
break;
|
|
847
932
|
default:
|
|
848
933
|
console.warn(`Module substructure not supported. ${structure['key.name']}`);
|
|
@@ -993,6 +1078,41 @@ function collectModuleTypeIdentifiers(
|
|
|
993
1078
|
});
|
|
994
1079
|
}
|
|
995
1080
|
|
|
1081
|
+
function parseNamespaces(
|
|
1082
|
+
structure: Structure,
|
|
1083
|
+
namespaces: { [key: string]: namespace },
|
|
1084
|
+
file: FileType,
|
|
1085
|
+
currentNamespace: namespace
|
|
1086
|
+
) {
|
|
1087
|
+
if (
|
|
1088
|
+
isModuleStructure(structure) ||
|
|
1089
|
+
isRecordStructure(structure) ||
|
|
1090
|
+
isStructStructure(structure) ||
|
|
1091
|
+
isEnumStructure(structure) ||
|
|
1092
|
+
isClassStructure(structure)
|
|
1093
|
+
) {
|
|
1094
|
+
const moduleName = structure['key.name'];
|
|
1095
|
+
namespaces[moduleName] = namespaces[moduleName] || {};
|
|
1096
|
+
const ns: namespace = namespaces[moduleName];
|
|
1097
|
+
currentNamespace[moduleName] = ns;
|
|
1098
|
+
structure['key.substructure'].forEach((substructure) => {
|
|
1099
|
+
parseNamespaces(substructure, namespaces, file, ns);
|
|
1100
|
+
});
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
if (
|
|
1104
|
+
structure['key.kind'] === swiftDeclarationKind.varStatic ||
|
|
1105
|
+
structure['key.kind'] === swiftDeclarationKind.varGlobal
|
|
1106
|
+
) {
|
|
1107
|
+
currentNamespace[structure['key.name']] = getInitializerValue(structure, file);
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
const substructures = structure['key.substructure'];
|
|
1111
|
+
substructures?.forEach((substructure) =>
|
|
1112
|
+
parseNamespaces(substructure, namespaces, file, currentNamespace)
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
996
1116
|
export type SwiftFileTypeInformationOptions = {
|
|
997
1117
|
typeInference: boolean;
|
|
998
1118
|
};
|
|
@@ -1006,13 +1126,12 @@ export async function getSwiftFileTypeInformation(
|
|
|
1006
1126
|
const modulesStructures: { name: string; structure: Structure }[] = [];
|
|
1007
1127
|
const recordsStructures: Structure[] = [];
|
|
1008
1128
|
const enumsStructures: Structure[] = [];
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
);
|
|
1129
|
+
const fileStructure = getStructureFromFile(file);
|
|
1130
|
+
parseStructure(fileStructure, '', modulesStructures, recordsStructures, enumsStructures);
|
|
1131
|
+
|
|
1132
|
+
const namespaces: { [key: string]: namespace } = {};
|
|
1133
|
+
namespaces[''] = {};
|
|
1134
|
+
parseNamespaces(fileStructure, namespaces, file, namespaces['']);
|
|
1016
1135
|
|
|
1017
1136
|
const inferredTypeParametersCount = new Map<string, number>();
|
|
1018
1137
|
const moduleClasses: ModuleClassDeclaration[] = [];
|
|
@@ -1034,14 +1153,16 @@ export async function getSwiftFileTypeInformation(
|
|
|
1034
1153
|
const recordsPromise = taskAll(recordsStructures, recordMap);
|
|
1035
1154
|
const moduleClassDeclarationsPromise = taskAll(
|
|
1036
1155
|
modulesStructures.filter(({ structure }) => hasSubstructure(structure)),
|
|
1037
|
-
({ structure, name }) =>
|
|
1038
|
-
|
|
1156
|
+
({ structure, name }) => {
|
|
1157
|
+
namespaces[name] = namespaces[name] || {};
|
|
1158
|
+
return parseModuleStructure(
|
|
1039
1159
|
structure['key.substructure'],
|
|
1040
|
-
file,
|
|
1041
1160
|
name,
|
|
1042
1161
|
structure['key.offset'],
|
|
1043
|
-
options
|
|
1044
|
-
|
|
1162
|
+
options,
|
|
1163
|
+
{ namespaces, file }
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1045
1166
|
);
|
|
1046
1167
|
|
|
1047
1168
|
const [records, moduleClassDeclarations] = await Promise.all([
|
package/src/types.ts
CHANGED
package/tests/TestModule.swift
CHANGED
|
@@ -3,7 +3,20 @@ import WebKit
|
|
|
3
3
|
|
|
4
4
|
public class TestModule: Module {
|
|
5
5
|
public func definition() -> ModuleDefinition {
|
|
6
|
-
Events(
|
|
6
|
+
Events(
|
|
7
|
+
"event1",
|
|
8
|
+
"event2",
|
|
9
|
+
"event3",
|
|
10
|
+
globalEventName,
|
|
11
|
+
privateGlobalEventName,
|
|
12
|
+
EventNames.staticLetEvent,
|
|
13
|
+
EventNames.staticVarEvent,
|
|
14
|
+
EventStructNamespace.structEvent,
|
|
15
|
+
EventClassNamespace.classEvent,
|
|
16
|
+
OuterNamespace.InnerNamespace.nestedEvent,
|
|
17
|
+
// TODO(@HubertBer) Maybe fix this if this is needed, for now just document we don't support it
|
|
18
|
+
globalAssignedToGlobal
|
|
19
|
+
)
|
|
7
20
|
|
|
8
21
|
Constant("StringConstant") { () -> Int in
|
|
9
22
|
return "Swift constant 1283"
|
|
@@ -196,3 +209,27 @@ enum IntBackedEnum1: Int {
|
|
|
196
209
|
enum IntBackedEnum2: Something, Int, SomethingElse {
|
|
197
210
|
case simpleCase
|
|
198
211
|
}
|
|
212
|
+
// Global variable names
|
|
213
|
+
let globalEventName = "onGlobalEvent"
|
|
214
|
+
|
|
215
|
+
private let privateGlobalEventName = "onPrivateGlobalEvent"
|
|
216
|
+
private let globalAssignedToGlobal = globalEventName
|
|
217
|
+
|
|
218
|
+
enum EventNames {
|
|
219
|
+
static let staticLetEvent = "onStaticLetEvent"
|
|
220
|
+
static var staticVarEvent = "onStaticVarEvent"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
struct EventStructNamespace {
|
|
224
|
+
static let structEvent = "onStructEvent"
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
class EventClassNamespace {
|
|
228
|
+
static let classEvent = "onClassEvent"
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
enum OuterNamespace {
|
|
232
|
+
enum InnerNamespace {
|
|
233
|
+
static let nestedEvent = "onNestedEvent"
|
|
234
|
+
}
|
|
235
|
+
}
|