This repository was archived by the owner on Apr 1, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 457
Expand file tree
/
Copy pathResolution.hs
More file actions
125 lines (117 loc) · 5.34 KB
/
Resolution.hs
File metadata and controls
125 lines (117 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{-# LANGUAGE FlexibleContexts, RecordWildCards #-}
module Language.TypeScript.Resolution
( ImportPath (..)
, IsRelative (..)
, importPath
, toName
, resolveWithNodejsStrategy
, resolveModule
, resolveNonRelativePath
, javascriptExtensions
, typescriptExtensions
) where
import qualified Data.Map as Map
import System.FilePath.Posix
import Data.Abstract.BaseError
import Data.Abstract.Evaluatable
import qualified Data.Abstract.Module as M
import Data.Abstract.Package
import Data.Abstract.Path
import Data.ImportPath
import qualified Data.Language as Language
-- Node.js resolution algorithm: https://nodejs.org/api/modules.html#modules_all_together
--
-- NB: TypeScript has a couple of different strategies, but the main one (and the
-- only one we support) mimics Node.js.
resolveWithNodejsStrategy :: ( Has (Modules address value) sig m
, Has (Reader M.ModuleInfo) sig m
, Has (Reader PackageInfo) sig m
, Has (Reader Span) sig m
, Has (Resumable (BaseError ResolutionError)) sig m
, Has Trace sig m
)
=> ImportPath
-> [String]
-> Evaluator term address value m M.ModulePath
resolveWithNodejsStrategy (ImportPath path NonRelative) exts = resolveNonRelativePath path exts
resolveWithNodejsStrategy (ImportPath path _) exts = resolveRelativePath path exts
-- | Resolve a relative TypeScript import to a known 'ModuleName' or fail.
--
-- import { b } from "./moduleB" in /root/src/moduleA.ts
--
-- /root/src/moduleB.ts
-- /root/src/moduleB/package.json (if it specifies a "types" property)
-- /root/src/moduleB/index.ts
resolveRelativePath :: ( Has (Modules address value) sig m
, Has (Reader M.ModuleInfo) sig m
, Has (Reader PackageInfo) sig m
, Has (Reader Span) sig m
, Has (Resumable (BaseError ResolutionError)) sig m
, Has Trace sig m
)
=> FilePath
-> [String]
-> Evaluator term address value m M.ModulePath
resolveRelativePath relImportPath exts = do
M.ModuleInfo{..} <- currentModule
let relRootDir = takeDirectory modulePath
let path = joinPaths relRootDir relImportPath
trace ("attempting to resolve (relative) require/import " <> show relImportPath)
resolveModule path exts >>= either notFound (\x -> x <$ traceResolve relImportPath path)
where
notFound xs = throwResolutionError $ NotFoundError relImportPath xs Language.TypeScript
-- | Resolve a non-relative TypeScript import to a known 'ModuleName' or fail.
--
-- import { b } from "moduleB" in source file /root/src/moduleA.ts
--
-- /root/src/node_modules/moduleB.ts
-- /root/src/node_modules/moduleB/package.json (if it specifies a "types" property)
-- /root/src/node_modules/moduleB/index.ts
--
-- /root/node_modules/moduleB.ts, etc
-- /node_modules/moduleB.ts, etc
resolveNonRelativePath :: ( Has (Modules address value) sig m
, Has (Reader M.ModuleInfo) sig m
, Has (Reader PackageInfo) sig m
, Has (Reader Span) sig m
, Has (Resumable (BaseError ResolutionError)) sig m
, Has Trace sig m
)
=> FilePath
-> [String]
-> Evaluator term address value m M.ModulePath
resolveNonRelativePath name exts = do
M.ModuleInfo{..} <- currentModule
go "." modulePath mempty
where
nodeModulesPath dir = takeDirectory dir </> "node_modules" </> name
-- Recursively search in a 'node_modules' directory, stepping up a directory each time.
go root path searched = do
trace ("attempting to resolve (non-relative) require/import " <> show name)
res <- resolveModule (nodeModulesPath path) exts
case res of
Left xs | parentDir <- takeDirectory path , root /= parentDir -> go root parentDir (searched <> xs)
| otherwise -> notFound (searched <> xs)
Right m -> m <$ traceResolve name m
notFound xs = throwResolutionError $ NotFoundError name xs Language.TypeScript
-- | Resolve a module name to a ModulePath.
resolveModule :: ( Has (Modules address value) sig m
, Has (Reader PackageInfo) sig m
, Has Trace sig m
)
=> FilePath -- ^ Module path used as directory to search in
-> [String] -- ^ File extensions to look for
-> Evaluator term address value m (Either [FilePath] M.ModulePath)
resolveModule path' exts = do
let path = makeRelative "." path'
PackageInfo{..} <- currentPackage
let packageDotJSON = Map.lookup (path </> "package.json") packageResolutions
let searchPaths = ((path <.>) <$> exts)
<> maybe mempty (:[]) packageDotJSON
<> (((path </> "index") <.>) <$> exts)
trace ("searching in " <> show searchPaths)
maybe (Left searchPaths) Right <$> resolve searchPaths
typescriptExtensions :: [String]
typescriptExtensions = ["ts", "tsx", "d.ts"]
javascriptExtensions :: [String]
javascriptExtensions = ["js"]