Skip to content

Commit 15fd566

Browse files
committed
Migrate to core library
1 parent dd70f13 commit 15fd566

29 files changed

+1411
-12060
lines changed

lib/Common.fs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
module Ts2Ml.Common
22

33
type ILogger =
4-
abstract tracef: fmt:Printf.StringFormat<'T, 'Result> -> 'T
5-
abstract warnf: fmt:Printf.StringFormat<'T, 'Result> -> 'T
4+
abstract tracef: fmt:Printf.StringFormat<'T, unit> -> 'T
5+
abstract warnf: fmt:Printf.StringFormat<'T, unit> -> 'T
66
abstract errorf: fmt:Printf.StringFormat<'T, 'Result> -> 'T
77

8-
type GlobalOptions =
9-
abstract verbose: bool with get
10-
abstract nowarn: bool with get
11-
abstract merge: bool with get, set
8+
type IOptions =
129
abstract followRelativeReferences: bool with get, set
1310

14-
type IContext<'Options when 'Options :> GlobalOptions> =
11+
type IContext<'Options when 'Options :> IOptions> =
1512
abstract options: 'Options
1613
abstract logger: ILogger
1714

1815
type IContext =
19-
inherit IContext<GlobalOptions>
16+
inherit IContext<IOptions>
2017

2118
/// Stateful class to rename overloaded identifiers.
2219
type OverloadRenamer(?rename: string -> int -> string, ?used: Set<string * string>) =

lib/DataTypes/Graph.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Ts2Ml.DataTypes
1+
namespace DataTypes
22

33
type Graph<'node when 'node: comparison> = Map<'node, 'node list>
44

lib/DataTypes/Text.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Ts2Ml.DataTypes
1+
namespace DataTypes
22

33
open Ts2Ml.Extensions
44

lib/DataTypes/Trie.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Ts2Ml.DataTypes
1+
namespace DataTypes
22

33
type Trie<'k, 'v when 'k: comparison> = {
44
value: 'v option

lib/Extensions.fs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,18 +142,13 @@ module Path =
142142
module Node = Node.Api
143143

144144
type Absolute = string
145-
/// relative to current directory
146-
type Relative = string
147145
type Difference = string
148146

149-
let relative (path: string) : Relative =
150-
Node.path.relative(Node.``process``.cwd(), path)
151-
152147
let absolute (path: string) : Absolute =
153148
if Node.path.isAbsolute(path) then path
154149
else Node.path.resolve(path)
155150

156-
let diff (fromPath: string) (toPath: string) : Difference =
151+
let diff (fromPath: Absolute) (toPath: Absolute) : string =
157152
let fromPath =
158153
if Node.fs.lstatSync(!^fromPath).isDirectory() then fromPath
159154
else Node.path.dirname(fromPath)

lib/JsHelper.fs

Lines changed: 111 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,32 @@ open Fable.Core.JsInterop
55

66
module Node = Node.Api
77

8+
let inline nodeOnly (f: unit -> 'a option) : 'a option =
9+
if not BrowserOrNode.isNode then None
10+
else f ()
11+
812
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
2631

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)
2934

3035
type IPackageExportItemEntry =
3136
inherit JSRecord<string, string>
@@ -42,83 +47,81 @@ type IPackageJson =
4247
abstract typings: string option
4348
abstract exports: JSRecord<string, IPackageExportItem> option
4449

45-
let getPackageJson (path: string) : IPackageJson =
46-
let content = Node.fs.readFileSync(path, "utf-8")
47-
!!JS.JSON.parse(content)
48-
4950
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+
}
122125

123126
type InferenceResult =
124127
| Valid of string
@@ -132,7 +135,7 @@ module InferenceResult =
132135
| Valid s | Heuristic s -> Some s
133136
| Unknown -> None
134137

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 =
136139
let parts =
137140
sourceFile
138141
|> fun x ->
@@ -154,7 +157,7 @@ let inferPackageInfoFromFileName (sourceFile: Path.Relative) : {| name: string;
154157
let inline stripExtension path =
155158
path |> String.replace ".ts" "" |> String.replace ".d" ""
156159

157-
let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Relative) =
160+
let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Absolute) =
158161
let getSubmodule rest =
159162
match List.rev rest with
160163
| "index.d.ts" :: name :: _ -> name
@@ -166,7 +169,7 @@ let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Relative
166169
info.name |> Valid
167170
else
168171
// 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
170173
if info.isDefinitelyTyped then
171174
Path.join [info.name; stripExtension relativePath] |> Valid
172175
else
@@ -198,7 +201,7 @@ let getJsModuleName (info: Syntax.PackageInfo option) (sourceFile: Path.Relative
198201
info.name + "/" + getSubmodule rest
199202
|> Heuristic
200203

201-
let deriveModuleName (info: Syntax.PackageInfo option) (srcs: Path.Relative list) =
204+
let deriveModuleName (info: Syntax.PackageInfo option) (srcs: Path.Absolute list) =
202205
match srcs with
203206
| [] -> invalidArg "srcs" "source is empty"
204207
| [src] -> getJsModuleName info src
@@ -219,11 +222,18 @@ let deriveModuleName (info: Syntax.PackageInfo option) (srcs: Path.Relative list
219222
else
220223
fallback ()
221224

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) =
223226
if path.StartsWith(".") then
224227
let targetPath =
225228
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"])
227237
else path
228238
getJsModuleName info targetPath
229239
else

0 commit comments

Comments
 (0)