• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

typeorm / typeorm / 20518473296

26 Dec 2025 07:37AM UTC coverage: 80.909%. Remained the same
20518473296

push

github

web-flow
feat: add error handling and log warning for ormconfig loading failures (#11871)

27012 of 32813 branches covered (82.32%)

Branch coverage included in aggregate %.

25 of 43 new or added lines in 1 file covered. (58.14%)

1 existing line in 1 file now uncovered.

91363 of 113494 relevant lines covered (80.5%)

69534.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.09
/src/connection/ConnectionOptionsReader.ts
1
import appRootPath from "app-root-path"
26✔
2
import path from "path"
26✔
3

26✔
4
import { DataSourceOptions } from "../data-source/DataSourceOptions"
26✔
5
import { TypeORMError } from "../error"
26✔
6
import { PlatformTools } from "../platform/PlatformTools"
26✔
7
import { importOrRequireFile } from "../util/ImportUtils"
26✔
8
import { isAbsolute } from "../util/PathUtils"
26✔
9
import { ConnectionOptionsEnvReader } from "./options-reader/ConnectionOptionsEnvReader"
26✔
10

26✔
11
/**
26✔
12
 * Reads connection options from the ormconfig.
26✔
13
 */
26✔
14
export class ConnectionOptionsReader {
26✔
15
    // -------------------------------------------------------------------------
26✔
16
    // Constructor
26✔
17
    // -------------------------------------------------------------------------
26✔
18

26✔
19
    constructor(
26✔
20
        protected options?: {
312✔
21
            /**
312✔
22
             * Directory where ormconfig should be read from.
312✔
23
             * By default its your application root (where your app package.json is located).
312✔
24
             */
312✔
25
            root?: string
312✔
26

312✔
27
            /**
312✔
28
             * Filename of the ormconfig configuration. By default its equal to "ormconfig".
312✔
29
             */
312✔
30
            configName?: string
312✔
31
        },
312✔
32
    ) {}
312✔
33

26✔
34
    // -------------------------------------------------------------------------
26✔
35
    // Public Methods
26✔
36
    // -------------------------------------------------------------------------
26✔
37

26✔
38
    /**
26✔
39
     * Returns all connection options read from the ormconfig.
26✔
40
     */
26✔
41
    async all(): Promise<DataSourceOptions[]> {
26✔
42
        const options = await this.load()
424✔
43
        if (!options)
424✔
44
            throw new TypeORMError(
424✔
45
                `No connection options were found in any orm configuration files.`,
26✔
46
            )
26✔
47

398✔
48
        return options
398✔
49
    }
398✔
50

26✔
51
    /**
26✔
52
     * Gets a connection with a given name read from ormconfig.
26✔
53
     * If connection with such name would not be found then it throw error.
26✔
54
     */
26✔
55
    async get(name: string): Promise<DataSourceOptions> {
26✔
56
        const allOptions = await this.all()
294✔
57
        const targetOptions = allOptions.find(
294✔
58
            (options) =>
294✔
59
                options.name === name || (name === "default" && !options.name),
294!
60
        )
294✔
61
        if (!targetOptions)
294✔
62
            throw new TypeORMError(
294!
63
                `Cannot find connection ${name} because its not defined in any orm configuration files.`,
×
64
            )
×
65

294✔
66
        return targetOptions
294✔
67
    }
294✔
68

26✔
69
    /**
26✔
70
     * Checks if there is a TypeORM configuration file.
26✔
71
     */
26✔
72
    async has(name: string): Promise<boolean> {
26✔
73
        const allOptions = await this.load()
×
74
        if (!allOptions) return false
×
75

×
76
        const targetOptions = allOptions.find(
×
77
            (options) =>
×
78
                options.name === name || (name === "default" && !options.name),
×
79
        )
×
80
        return !!targetOptions
×
81
    }
×
82

26✔
83
    // -------------------------------------------------------------------------
26✔
84
    // Protected Methods
26✔
85
    // -------------------------------------------------------------------------
26✔
86

26✔
87
    /**
26✔
88
     * Loads all connection options from a configuration file.
26✔
89
     *
26✔
90
     * todo: get in count NODE_ENV somehow
26✔
91
     */
26✔
92
    protected async load(): Promise<DataSourceOptions[] | undefined> {
26✔
93
        let connectionOptions:
424✔
94
            | DataSourceOptions
424✔
95
            | DataSourceOptions[]
424✔
96
            | undefined = undefined
424✔
97

424✔
98
        const fileFormats = [
424✔
99
            "env",
424✔
100
            "js",
424✔
101
            "mjs",
424✔
102
            "cjs",
424✔
103
            "ts",
424✔
104
            "mts",
424✔
105
            "cts",
424✔
106
            "json",
424✔
107
        ]
424✔
108

424✔
109
        // Detect if baseFilePath contains file extension
424✔
110
        const possibleExtension = this.baseFilePath.substr(
424✔
111
            this.baseFilePath.lastIndexOf("."),
424✔
112
        )
424✔
113
        const fileExtension = fileFormats.find(
424✔
114
            (extension) => `.${extension}` === possibleExtension,
424✔
115
        )
424✔
116

424✔
117
        // try to find any of following configuration formats
424✔
118
        const foundFileFormat =
424✔
119
            fileExtension ||
424✔
120
            fileFormats.find((format) => {
372✔
121
                return PlatformTools.fileExist(this.baseFilePath + "." + format)
1,598✔
122
            })
372✔
123

424✔
124
        // Determine config file name
424✔
125
        const configFile = fileExtension
424✔
126
            ? this.baseFilePath
424✔
127
            : this.baseFilePath + "." + foundFileFormat
424✔
128

424✔
129
        // if .env file found then load all its variables into process.env using dotenv package
424✔
130
        if (foundFileFormat === "env") {
424✔
131
            try {
78✔
132
                PlatformTools.dotenv(configFile)
78✔
133
            } catch (err) {
78!
NEW
134
                PlatformTools.logWarn(
×
NEW
135
                    `Warning: Could not load environment variables from .env file at ${configFile}`,
×
NEW
136
                    err instanceof Error ? err.message : String(err),
×
NEW
137
                )
×
NEW
138
            }
×
139
        } else if (PlatformTools.fileExist(this.baseDirectory + "/.env")) {
424!
NEW
140
            try {
×
NEW
141
                PlatformTools.dotenv(this.baseDirectory + "/.env")
×
NEW
142
            } catch (err) {
×
NEW
143
                PlatformTools.logWarn(
×
NEW
144
                    `Warning: Could not load environment variables from .env file at ${this.baseDirectory + "/.env"}`,
×
NEW
145
                    err instanceof Error ? err.message : String(err),
×
NEW
146
                )
×
NEW
147
            }
×
UNCOV
148
        }
×
149

424✔
150
        // try to find connection options from any of available sources of configuration
424✔
151
        if (
424✔
152
            PlatformTools.getEnvVariable("TYPEORM_CONNECTION") ||
424✔
153
            PlatformTools.getEnvVariable("TYPEORM_URL")
346✔
154
        ) {
424✔
155
            connectionOptions = new ConnectionOptionsEnvReader().read()
78✔
156
        } else if (
424✔
157
            foundFileFormat === "js" ||
346✔
158
            foundFileFormat === "mjs" ||
346✔
159
            foundFileFormat === "cjs" ||
346✔
160
            foundFileFormat === "ts" ||
346✔
161
            foundFileFormat === "mts" ||
346✔
162
            foundFileFormat === "cts"
138✔
163
        ) {
346✔
164
            try {
208✔
165
                const [importOrRequireResult, moduleSystem] =
208✔
166
                    await importOrRequireFile(configFile)
208✔
167
                const configModule = await importOrRequireResult
182✔
168

182✔
169
                if (
182✔
170
                    moduleSystem === "esm" ||
182✔
171
                    (configModule &&
182✔
172
                        "__esModule" in configModule &&
182✔
173
                        "default" in configModule)
182✔
174
                ) {
208✔
175
                    connectionOptions = configModule.default
26✔
176
                } else {
208✔
177
                    connectionOptions = configModule
156✔
178
                }
156✔
179
            } catch (err) {
208✔
180
                PlatformTools.logWarn(
26✔
181
                    `Warning: Could not load ormconfig file at ${configFile}`,
26✔
182
                    err instanceof Error ? err.message : String(err),
26!
183
                )
26✔
184
            }
26✔
185
        } else if (foundFileFormat === "json") {
346!
186
            try {
138✔
187
                connectionOptions = require(configFile)
138✔
188
            } catch (err) {
138!
NEW
189
                PlatformTools.logWarn(
×
NEW
190
                    `Warning: Could not load ormconfig file at ${configFile}`,
×
NEW
191
                    err instanceof Error ? err.message : String(err),
×
NEW
192
                )
×
NEW
193
            }
×
194
        }
138✔
195

424✔
196
        // normalize and return connection options
424✔
197
        if (connectionOptions) {
424✔
198
            return this.normalizeConnectionOptions(connectionOptions)
398✔
199
        }
398✔
200

26✔
201
        return undefined
26✔
202
    }
26✔
203

26✔
204
    /**
26✔
205
     * Normalize connection options.
26✔
206
     */
26✔
207
    protected normalizeConnectionOptions(
26✔
208
        connectionOptions: DataSourceOptions | DataSourceOptions[],
398✔
209
    ): DataSourceOptions[] {
398✔
210
        if (!Array.isArray(connectionOptions))
398✔
211
            connectionOptions = [connectionOptions]
398✔
212

398✔
213
        connectionOptions.forEach((options) => {
398✔
214
            options.baseDirectory = this.baseDirectory
550✔
215
            if (options.entities) {
550✔
216
                const entities = (options.entities as any[]).map((entity) => {
104✔
217
                    if (
26✔
218
                        typeof entity === "string" &&
26!
219
                        entity.substr(0, 1) !== "/"
×
220
                    )
26✔
221
                        return this.baseDirectory + "/" + entity
26!
222

26✔
223
                    return entity
26✔
224
                })
104✔
225
                Object.assign(connectionOptions, { entities: entities })
104✔
226
            }
104✔
227
            if (options.subscribers) {
550✔
228
                const subscribers = (options.subscribers as any[]).map(
78✔
229
                    (subscriber) => {
78✔
230
                        if (
×
231
                            typeof subscriber === "string" &&
×
232
                            subscriber.substr(0, 1) !== "/"
×
233
                        )
×
234
                            return this.baseDirectory + "/" + subscriber
×
235

×
236
                        return subscriber
×
237
                    },
78✔
238
                )
78✔
239
                Object.assign(connectionOptions, { subscribers: subscribers })
78✔
240
            }
78✔
241
            if (options.migrations) {
550✔
242
                const migrations = (options.migrations as any[]).map(
78✔
243
                    (migration) => {
78✔
244
                        if (
×
245
                            typeof migration === "string" &&
×
246
                            migration.substr(0, 1) !== "/"
×
247
                        )
×
248
                            return this.baseDirectory + "/" + migration
×
249

×
250
                        return migration
×
251
                    },
78✔
252
                )
78✔
253
                Object.assign(connectionOptions, { migrations: migrations })
78✔
254
            }
78✔
255

550✔
256
            // make database path file in sqlite relative to package.json
550✔
257
            if (
550✔
258
                options.type === "sqlite" ||
550✔
259
                options.type === "better-sqlite3"
350✔
260
            ) {
550✔
261
                if (
270✔
262
                    typeof options.database === "string" &&
270✔
263
                    !isAbsolute(options.database) &&
270✔
264
                    options.database.substr(0, 1) !== "/" && // unix absolute
270✔
265
                    options.database.substr(1, 2) !== ":\\" && // windows absolute
270✔
266
                    options.database !== ":memory:"
214✔
267
                ) {
270✔
268
                    Object.assign(options, {
110✔
269
                        database: this.baseDirectory + "/" + options.database,
110✔
270
                    })
110✔
271
                }
110✔
272
            }
270✔
273
        })
398✔
274

398✔
275
        return connectionOptions
398✔
276
    }
398✔
277

26✔
278
    /**
26✔
279
     * Gets directory where configuration file should be located and configuration file name.
26✔
280
     */
26✔
281
    protected get baseFilePath(): string {
26✔
282
        return path.resolve(this.baseDirectory, this.baseConfigName)
2,870✔
283
    }
2,870✔
284

26✔
285
    /**
26✔
286
     * Gets directory where configuration file should be located.
26✔
287
     */
26✔
288
    protected get baseDirectory(): string {
26✔
289
        return this.options?.root ?? appRootPath.path
3,876!
290
    }
3,876✔
291

26✔
292
    /**
26✔
293
     * Gets configuration file name.
26✔
294
     */
26✔
295
    protected get baseConfigName(): string {
26✔
296
        return this.options?.configName ?? "ormconfig"
2,870✔
297
    }
2,870✔
298
}
26✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc