@@ -5,27 +5,32 @@ open Fable.Core.JsInterop
5
5
6
6
module Node = Node.Api
7
7
8
+ let inline nodeOnly ( f : unit -> 'a option ) : 'a option =
9
+ if not BrowserOrNode.isNode then None
10
+ else f ()
11
+
8
12
let getPackageJsonPath ( exampleFilePath : string ) =
9
- let parts =
10
- exampleFilePath
11
- |> String.split Path.separator
12
- |> List.ofArray
13
- match parts |> List.tryFindIndexBack ((=) " node_modules" ) with
14
- | None -> None
15
- | Some i ->
16
- let prefix , rest = List.splitAt ( i+ 1 ) parts
17
- if rest = [] then None
18
- else
19
- let packageName =
20
- match rest with
21
- | userName :: packageName :: _ when userName.StartsWith( " @" ) -> [ userName; packageName]
22
- | packageName :: _ -> [ packageName]
23
- | _ -> failwith " impossible_getPackageJsonPath_root"
24
- let path =
25
- prefix @ packageName @ [ " package.json" ] |> String.concat Path.separator
13
+ nodeOnly <| fun () ->
14
+ let parts =
15
+ exampleFilePath
16
+ |> String.split Path.separator
17
+ |> List.ofArray
18
+ match parts |> List.tryFindIndexBack ((=) " node_modules" ) with
19
+ | None -> None
20
+ | Some i ->
21
+ let prefix , rest = List.splitAt ( i+ 1 ) parts
22
+ if rest = [] then None
23
+ else
24
+ let packageName =
25
+ match rest with
26
+ | userName :: packageName :: _ when userName.StartsWith( " @" ) -> [ userName; packageName]
27
+ | packageName :: _ -> [ packageName]
28
+ | _ -> failwith " impossible_getPackageJsonPath_root"
29
+ let path =
30
+ prefix @ packageName @ [ " package.json" ] |> String.concat Path.separator
26
31
27
- if not <| Node.fs.existsSync(! ^path ) then None
28
- else Some ( Path.absolute path)
32
+ if not <| Node.fs.existsSync(! ^path ) then None
33
+ else Some ( Path.absolute path)
29
34
30
35
type IPackageExportItemEntry =
31
36
inherit JSRecord< string, string>
@@ -42,83 +47,81 @@ type IPackageJson =
42
47
abstract typings: string option
43
48
abstract exports: JSRecord < string , IPackageExportItem > option
44
49
45
- let getPackageJson ( path : string ) : IPackageJson =
46
- let content = Node.fs.readFileSync( path, " utf-8" )
47
- !! JS.JSON.parse( content)
48
-
49
50
let getPackageInfo ( exampleFilePath : string ) : Syntax.PackageInfo option =
50
- match getPackageJsonPath exampleFilePath with
51
- | None -> None
52
- | Some path ->
53
- let p = getPackageJson path
54
-
55
- let rootPath = Path.dirname path
56
-
57
- let name =
58
- if p.name.StartsWith( " @types/" ) then
59
- let tmp = p.name.Substring( 7 )
60
- if tmp.Contains( " __" ) then " @" + tmp.Replace( " __" , " /" )
61
- else tmp
62
- else p.name
63
-
64
- let shortName =
65
- p.name
66
- |> String.splitThenRemoveEmptyEntries " /"
67
- |> Array.skipWhile ( fun s -> s.StartsWith( " @" ))
68
- |> String.concat " /"
69
-
70
- let exports =
71
- match p.exports with
72
- | None -> []
73
- | Some exports ->
74
- [
75
- for k, v in exports.entries do
76
- match v.types with
77
- | None -> ()
78
- | Some types ->
79
- if JS.typeof types = " string" then
80
- yield k, !! types
81
- else
82
- let types = !! types : IPackageExportItemEntry
83
- match types.`` default `` with
84
- | Some v -> yield k, v
85
- | None ->
86
- yield !
87
- types.entries
88
- |> Array.tryPick ( fun ( _ , v ) ->
89
- if JS.typeof v = " string" && v.EndsWith( " .d.ts" ) then Some v
90
- else None)
91
- |> Option.map ( fun v -> k, v)
92
- |> Option.toList
93
- ]
94
-
95
- let indexFile =
96
- match Option.orElse p.types p.typings, exports |> List.tryFind ( fst >> (=) " ." ) with
97
- | None, None ->
98
- let index = Path.join [ rootPath; " index.d.ts" ]
99
- if not <| Node.fs.existsSync(! ^index ) then None
100
- else
101
- Path.relative index |> Node.path.normalize |> Some
102
- | Some typings, _
103
- | None, Some (_, typings) ->
104
- Path.join [ rootPath; typings] |> Path.relative |> Node.path.normalize |> Some
105
-
106
- let exports =
107
- exports
108
- |> List.filter ( fst >> (<>) " ." )
109
- |> List.map ( fun ( k , v ) ->
110
- {| submodule = k;
111
- file = Path.join [ rootPath; v] |> Path.relative |> Node.path.normalize |})
112
-
113
- Some {
114
- name = name
115
- shortName = shortName
116
- isDefinitelyTyped = p.name.StartsWith( " @types/" )
117
- version = p.version
118
- rootPath = rootPath
119
- indexFile = indexFile
120
- exports = exports
121
- }
51
+ nodeOnly <| fun () ->
52
+ match getPackageJsonPath exampleFilePath with
53
+ | None -> None
54
+ | Some path ->
55
+ let p =
56
+ let content = Node.fs.readFileSync( path, " utf-8" )
57
+ !! JS.JSON.parse( content) : IPackageJson
58
+
59
+ let rootPath = Path.dirname path
60
+
61
+ let name =
62
+ if p.name.StartsWith( " @types/" ) then
63
+ let tmp = p.name.Substring( 7 )
64
+ if tmp.Contains( " __" ) then " @" + tmp.Replace( " __" , " /" )
65
+ else tmp
66
+ else p.name
67
+
68
+ let shortName =
69
+ p.name
70
+ |> String.splitThenRemoveEmptyEntries " /"
71
+ |> Array.skipWhile ( fun s -> s.StartsWith( " @" ))
72
+ |> String.concat " /"
73
+
74
+ let exports =
75
+ match p.exports with
76
+ | None -> []
77
+ | Some exports ->
78
+ [
79
+ for k, v in exports.entries do
80
+ match v.types with
81
+ | None -> ()
82
+ | Some types ->
83
+ if JS.typeof types = " string" then
84
+ yield k, !! types
85
+ else
86
+ let types = !! types : IPackageExportItemEntry
87
+ match types.`` default `` with
88
+ | Some v -> yield k, v
89
+ | None ->
90
+ yield !
91
+ types.entries
92
+ |> Array.tryPick ( fun ( _ , v ) ->
93
+ if JS.typeof v = " string" && v.EndsWith( " .d.ts" ) then Some v
94
+ else None)
95
+ |> Option.map ( fun v -> k, v)
96
+ |> Option.toList
97
+ ]
98
+
99
+ let indexFile =
100
+ match Option.orElse p.types p.typings, exports |> List.tryFind ( fst >> (=) " ." ) with
101
+ | None, None ->
102
+ let index = Path.join [ rootPath; " index.d.ts" ]
103
+ if not <| Node.fs.existsSync(! ^index ) then None
104
+ else Some index
105
+ | Some typings, _
106
+ | None, Some (_, typings) ->
107
+ Path.join [ rootPath; typings] |> Some
108
+
109
+ let exports =
110
+ exports
111
+ |> List.filter ( fst >> (<>) " ." )
112
+ |> List.map ( fun ( k , v ) ->
113
+ {| submodule = k;
114
+ file = Path.join [ rootPath; v] |})
115
+
116
+ Some {
117
+ name = name
118
+ shortName = shortName
119
+ isDefinitelyTyped = p.name.StartsWith( " @types/" )
120
+ version = p.version
121
+ rootPath = rootPath
122
+ indexFile = indexFile
123
+ exports = exports
124
+ }
122
125
123
126
type InferenceResult =
124
127
| Valid of string
@@ -132,7 +135,7 @@ module InferenceResult =
132
135
| Valid s | Heuristic s -> Some s
133
136
| Unknown -> None
134
137
135
- let inferPackageInfoFromFileName ( sourceFile : Path.Relative ) : {| name: string ; isDefinitelyTyped: bool ; rest: string list |} option =
138
+ let inferPackageInfoFromFileName ( sourceFile : Path.Absolute ) : {| name: string ; isDefinitelyTyped: bool ; rest: string list |} option =
136
139
let parts =
137
140
sourceFile
138
141
|> fun x ->
@@ -154,7 +157,7 @@ let inferPackageInfoFromFileName (sourceFile: Path.Relative) : {| name: string;
154
157
let inline stripExtension path =
155
158
path |> String.replace " .ts" " " |> String.replace " .d" " "
156
159
157
- let getJsModuleName ( info : Syntax.PackageInfo option ) ( sourceFile : Path.Relative ) =
160
+ let getJsModuleName ( info : Syntax.PackageInfo option ) ( sourceFile : Path.Absolute ) =
158
161
let getSubmodule rest =
159
162
match List.rev rest with
160
163
| " index.d.ts" :: name :: _ -> name
@@ -166,7 +169,7 @@ let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Relative
166
169
info.name |> Valid
167
170
else
168
171
// make it relative to the package root directory
169
- let relativePath = Path.diff info.rootPath ( Path.absolute sourceFile)
172
+ let relativePath = Path.diff info.rootPath sourceFile
170
173
if info.isDefinitelyTyped then
171
174
Path.join [ info.name; stripExtension relativePath] |> Valid
172
175
else
@@ -198,7 +201,7 @@ let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Relative
198
201
info.name + " /" + getSubmodule rest
199
202
|> Heuristic
200
203
201
- let deriveModuleName ( info : Syntax.PackageInfo option ) ( srcs : Path.Relative list ) =
204
+ let deriveModuleName ( info : Syntax.PackageInfo option ) ( srcs : Path.Absolute list ) =
202
205
match srcs with
203
206
| [] -> invalidArg " srcs" " source is empty"
204
207
| [ src] -> getJsModuleName info src
@@ -219,11 +222,18 @@ let deriveModuleName (info: Syntax.PackageInfo option) (srcs: Path.Relative list
219
222
else
220
223
fallback ()
221
224
222
- let resolveRelativeImportPath ( info : Syntax.PackageInfo option ) ( currentFile : Path.Relative ) ( path : string ) =
225
+ let resolveRelativeImportPath ( info : Syntax.PackageInfo option ) ( currentFile : Path.Absolute ) ( allFiles : Path.Absolute list ) ( path : string ) =
223
226
if path.StartsWith( " ." ) then
224
227
let targetPath =
225
228
let path = Path.join [ Path.dirname currentFile; path]
226
- if not <| path.EndsWith( " .ts" ) then Path.join [ path; " index.d.ts" ]
229
+ if not <| path.EndsWith( " .ts" ) then
230
+ let tryFind p =
231
+ if allFiles |> List.contains p then Some p
232
+ else None
233
+ tryFind $" {path}.d.ts"
234
+ |> Option.orElseWith ( fun () -> tryFind ( Path.join [ path; " index.d.ts" ]))
235
+ |> Option.orElseWith ( fun () -> allFiles |> List.tryFind ( fun p -> p.StartsWith( path)))
236
+ |> Option.defaultWith ( fun () -> Path.join [ path; " index.d.ts" ])
227
237
else path
228
238
getJsModuleName info targetPath
229
239
else
0 commit comments