source: frontend/node_modules/tsconfig-paths/src/tsconfig-loader.ts

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 5.7 KB
Line 
1import * as path from "path";
2import * as fs from "fs";
3// tslint:disable:no-require-imports
4import JSON5 = require("json5");
5import StripBom = require("strip-bom");
6// tslint:enable:no-require-imports
7
8/**
9 * Typing for the parts of tsconfig that we care about
10 */
11export interface Tsconfig {
12 extends?: string | string[];
13 compilerOptions?: {
14 baseUrl?: string;
15 paths?: { [key: string]: Array<string> };
16 strict?: boolean;
17 };
18}
19
20export interface TsConfigLoaderResult {
21 tsConfigPath: string | undefined;
22 baseUrl: string | undefined;
23 paths: { [key: string]: Array<string> } | undefined;
24}
25
26export interface TsConfigLoaderParams {
27 getEnv: (key: string) => string | undefined;
28 cwd: string;
29 loadSync?(
30 cwd: string,
31 filename?: string,
32 baseUrl?: string
33 ): TsConfigLoaderResult;
34}
35
36export function tsConfigLoader({
37 getEnv,
38 cwd,
39 loadSync = loadSyncDefault,
40}: TsConfigLoaderParams): TsConfigLoaderResult {
41 const TS_NODE_PROJECT = getEnv("TS_NODE_PROJECT");
42 const TS_NODE_BASEURL = getEnv("TS_NODE_BASEURL");
43
44 // tsconfig.loadSync handles if TS_NODE_PROJECT is a file or directory
45 // and also overrides baseURL if TS_NODE_BASEURL is available.
46 const loadResult = loadSync(cwd, TS_NODE_PROJECT, TS_NODE_BASEURL);
47 return loadResult;
48}
49
50function loadSyncDefault(
51 cwd: string,
52 filename?: string,
53 baseUrl?: string
54): TsConfigLoaderResult {
55 // Tsconfig.loadSync uses path.resolve. This is why we can use an absolute path as filename
56
57 const configPath = resolveConfigPath(cwd, filename);
58
59 if (!configPath) {
60 return {
61 tsConfigPath: undefined,
62 baseUrl: undefined,
63 paths: undefined,
64 };
65 }
66 const config = loadTsconfig(configPath);
67
68 return {
69 tsConfigPath: configPath,
70 baseUrl:
71 baseUrl ||
72 (config && config.compilerOptions && config.compilerOptions.baseUrl),
73 paths: config && config.compilerOptions && config.compilerOptions.paths,
74 };
75}
76
77function resolveConfigPath(cwd: string, filename?: string): string | undefined {
78 if (filename) {
79 const absolutePath = fs.lstatSync(filename).isDirectory()
80 ? path.resolve(filename, "./tsconfig.json")
81 : path.resolve(cwd, filename);
82
83 return absolutePath;
84 }
85
86 if (fs.statSync(cwd).isFile()) {
87 return path.resolve(cwd);
88 }
89
90 const configAbsolutePath = walkForTsConfig(cwd);
91 return configAbsolutePath ? path.resolve(configAbsolutePath) : undefined;
92}
93
94export function walkForTsConfig(
95 directory: string,
96 existsSync: (path: string) => boolean = fs.existsSync
97): string | undefined {
98 const configPath = path.join(directory, "./tsconfig.json");
99 if (existsSync(configPath)) {
100 return configPath;
101 }
102
103 const parentDirectory = path.join(directory, "../");
104
105 // If we reached the top
106 if (directory === parentDirectory) {
107 return undefined;
108 }
109
110 return walkForTsConfig(parentDirectory, existsSync);
111}
112
113export function loadTsconfig(
114 configFilePath: string,
115 existsSync: (path: string) => boolean = fs.existsSync,
116 readFileSync: (filename: string) => string = (filename: string) =>
117 fs.readFileSync(filename, "utf8")
118): Tsconfig | undefined {
119 if (!existsSync(configFilePath)) {
120 return undefined;
121 }
122
123 const configString = readFileSync(configFilePath);
124 const cleanedJson = StripBom(configString);
125 let config: Tsconfig;
126 try {
127 config = JSON5.parse(cleanedJson);
128 } catch (e) {
129 throw new Error(`${configFilePath} is malformed ${e.message}`);
130 }
131
132 let extendedConfig = config.extends;
133 if (extendedConfig) {
134 let base: Tsconfig;
135
136 if (Array.isArray(extendedConfig)) {
137 base = extendedConfig.reduce(
138 (currBase, extendedConfigElement) =>
139 mergeTsconfigs(
140 currBase,
141 loadTsconfigFromExtends(
142 configFilePath,
143 extendedConfigElement,
144 existsSync,
145 readFileSync
146 )
147 ),
148 {}
149 );
150 } else {
151 base = loadTsconfigFromExtends(
152 configFilePath,
153 extendedConfig,
154 existsSync,
155 readFileSync
156 );
157 }
158
159 return mergeTsconfigs(base, config);
160 }
161 return config;
162}
163
164/**
165 * Intended to be called only from loadTsconfig.
166 * Parameters don't have defaults because they should use the same as loadTsconfig.
167 */
168function loadTsconfigFromExtends(
169 configFilePath: string,
170 extendedConfigValue: string,
171 // eslint-disable-next-line no-shadow
172 existsSync: (path: string) => boolean,
173 readFileSync: (filename: string) => string
174): Tsconfig {
175 if (
176 typeof extendedConfigValue === "string" &&
177 extendedConfigValue.indexOf(".json") === -1
178 ) {
179 extendedConfigValue += ".json";
180 }
181 const currentDir = path.dirname(configFilePath);
182 let extendedConfigPath = path.join(currentDir, extendedConfigValue);
183 if (
184 extendedConfigValue.indexOf("/") !== -1 &&
185 extendedConfigValue.indexOf(".") !== -1 &&
186 !existsSync(extendedConfigPath)
187 ) {
188 extendedConfigPath = path.join(
189 currentDir,
190 "node_modules",
191 extendedConfigValue
192 );
193 }
194
195 const config =
196 loadTsconfig(extendedConfigPath, existsSync, readFileSync) || {};
197
198 // baseUrl should be interpreted as relative to extendedConfigPath,
199 // but we need to update it so it is relative to the original tsconfig being loaded
200 if (config.compilerOptions?.baseUrl) {
201 const extendsDir = path.dirname(extendedConfigValue);
202 config.compilerOptions.baseUrl = path.join(
203 extendsDir,
204 config.compilerOptions.baseUrl
205 );
206 }
207
208 return config;
209}
210
211function mergeTsconfigs(
212 base: Tsconfig | undefined,
213 config: Tsconfig | undefined
214): Tsconfig {
215 base = base || {};
216 config = config || {};
217
218 return {
219 ...base,
220 ...config,
221 compilerOptions: {
222 ...base.compilerOptions,
223 ...config.compilerOptions,
224 },
225 };
226}
Note: See TracBrowser for help on using the repository browser.