Line data Source code
1 : import 'package:analyzer/dart/element/element.dart';
2 : import 'package:analyzer/dart/element/nullability_suffix.dart';
3 : import 'package:analyzer/dart/element/type.dart';
4 : import 'package:flutter_navigation_generator/src/models/importable_type.dart';
5 : import 'package:path/path.dart' as p;
6 :
7 : abstract class ImportableTypeResolver {
8 : String? resolveImport(Element element);
9 :
10 : ImportableType resolveType(
11 : DartType type, {
12 : bool isRequired = false,
13 : String? name,
14 : bool forceNullable = false,
15 : });
16 :
17 : ImportableType resolveFunctionType(FunctionType function,
18 : [ExecutableElement? executableElement]);
19 :
20 0 : static String? relative(String? path, Uri? to) {
21 : if (path == null || to == null) {
22 : return null;
23 : }
24 0 : var fileUri = Uri.parse(path);
25 0 : var libName = to.pathSegments.first;
26 0 : if ((to.scheme == 'package' &&
27 0 : fileUri.scheme == 'package' &&
28 0 : fileUri.pathSegments.first == libName) ||
29 0 : (to.scheme == 'asset' && fileUri.scheme != 'package')) {
30 0 : if (fileUri.path == to.path) {
31 0 : return fileUri.pathSegments.last;
32 : } else {
33 0 : return p.posix
34 0 : .relative(fileUri.path, from: to.path)
35 0 : .replaceFirst('../', '');
36 : }
37 : } else {
38 : return path;
39 : }
40 : }
41 :
42 3 : static String? resolveAssetImport(String? path) {
43 : if (path == null) {
44 : return null;
45 : }
46 1 : var fileUri = Uri.parse(path);
47 2 : if (fileUri.scheme == "asset") {
48 0 : return "/${fileUri.path}";
49 : }
50 : return path;
51 : }
52 : }
53 :
54 : class ImportableTypeResolverImpl extends ImportableTypeResolver {
55 : final List<LibraryElement> libs;
56 :
57 0 : ImportableTypeResolverImpl(this.libs);
58 :
59 0 : @override
60 : String? resolveImport(Element? element) {
61 : // return early if source is null or element is a core type
62 0 : if (element?.source == null || _isCoreDartType(element)) {
63 : return null;
64 : }
65 :
66 0 : for (var lib in libs) {
67 0 : if (!_isCoreDartType(lib) &&
68 0 : lib.exportNamespace.definedNames.values.contains(element)) {
69 0 : return lib.identifier;
70 : }
71 : }
72 : return null;
73 : }
74 :
75 0 : bool _isCoreDartType(Element? element) {
76 0 : return element?.source?.fullName == 'dart:core';
77 : }
78 :
79 0 : @override
80 : ImportableType resolveFunctionType(FunctionType function,
81 : [ExecutableElement? executableElement]) {
82 : final functionElement =
83 0 : executableElement ?? function.element ?? function.alias?.element;
84 : if (functionElement == null) {
85 0 : throw 'Can not resolve function type \nTry using an alias e.g typedef MyFunction = ${function.getDisplayString(withNullability: false)};';
86 : }
87 0 : final displayName = functionElement.displayName;
88 : var functionName = displayName;
89 :
90 : Element elementToImport = functionElement;
91 0 : var enclosingElement = functionElement.enclosingElement;
92 :
93 0 : if (enclosingElement != null && enclosingElement is ClassElement) {
94 0 : functionName = '${enclosingElement.displayName}.$displayName';
95 : elementToImport = enclosingElement;
96 : }
97 :
98 0 : return ImportableType(
99 : className: functionName,
100 0 : import: resolveImport(elementToImport),
101 0 : isNullable: function.nullabilitySuffix == NullabilitySuffix.question,
102 : );
103 : }
104 :
105 0 : List<ImportableType> _resolveTypeArguments(DartType typeToCheck) {
106 0 : final importableTypes = <ImportableType>[];
107 0 : if (typeToCheck is ParameterizedType) {
108 0 : for (DartType type in typeToCheck.typeArguments) {
109 0 : if (type.element is TypeParameterElement) {
110 0 : importableTypes.add(const ImportableType(className: 'dynamic'));
111 : } else {
112 0 : importableTypes.add(ImportableType(
113 0 : className: type.element?.name?.replaceAll('?', '') ??
114 0 : type.getDisplayString(withNullability: false),
115 0 : import: resolveImport(type.element),
116 0 : isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
117 0 : typeArguments: _resolveTypeArguments(type),
118 : ));
119 : }
120 : }
121 : }
122 : return importableTypes;
123 : }
124 :
125 0 : @override
126 : ImportableType resolveType(
127 : DartType type, {
128 : bool isRequired = false,
129 : String? name,
130 : bool forceNullable = false,
131 : }) {
132 0 : return ImportableType(
133 : className:
134 0 : type.element?.name ?? type.getDisplayString(withNullability: false),
135 : name: name,
136 : isNullable:
137 0 : forceNullable || type.nullabilitySuffix == NullabilitySuffix.question,
138 0 : import: resolveImport(type.element),
139 : isRequired: isRequired,
140 0 : typeArguments: _resolveTypeArguments(type),
141 : );
142 : }
143 : }
|