Skip to content

Commit 026da36

Browse files
author
Lukas Holzer
authored
refactor: remove path-exists dependency and replace with node native fs.existsSync (#4839)
1 parent 89ab67d commit 026da36

File tree

10 files changed

+74
-71
lines changed

10 files changed

+74
-71
lines changed

package-lock.json

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/config/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
"netlify-redirect-parser": "^14.1.1",
7676
"omit.js": "^2.0.2",
7777
"p-locate": "^6.0.0",
78-
"path-exists": "^5.0.0",
7978
"path-type": "^5.0.0",
8079
"toml": "^3.0.0",
8180
"tomlify-j0.4": "^3.0.0",

packages/config/src/error.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// We distinguish between errors thrown intentionally and uncaught exceptions
22
// (such as bugs) with a `customErrorInfo.type` property.
3-
export const throwUserError = function (messageOrError, error) {
3+
export const throwUserError = function (messageOrError: string | Error, error?: Error) {
44
const errorA = getError(messageOrError, error)
55
errorA[CUSTOM_ERROR_KEY] = { type: USER_ERROR_TYPE }
66
throw errorA
77
}
88

99
// Can pass either `message`, `error` or `message, error`
10-
const getError = function (messageOrError, error) {
10+
const getError = function (messageOrError: string | Error, error?: Error) {
1111
if (messageOrError instanceof Error) {
1212
return messageOrError
1313
}

packages/config/src/files.js

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1+
import { existsSync } from 'fs'
12
import { resolve, relative, parse } from 'path'
23

34
import { getProperty, setProperty, deleteProperty } from 'dot-prop'
4-
import { pathExists } from 'path-exists'
55

66
import { throwUserError } from './error.js'
77
import { mergeConfigs } from './merge.js'
88
import { isTruthy } from './utils/remove_falsy.js'
99

1010
// Make configuration paths relative to `buildDir` and converts them to
1111
// absolute paths
12-
export const resolveConfigPaths = async function ({ config, repositoryRoot, buildDir, baseRelDir }) {
12+
export const resolveConfigPaths = function ({ config, repositoryRoot, buildDir, baseRelDir }) {
1313
const baseRel = baseRelDir ? buildDir : repositoryRoot
1414
const configA = resolvePaths(config, FILE_PATH_CONFIG_PROPS, baseRel, repositoryRoot)
15-
const configB = await addDefaultPaths(configA, repositoryRoot, baseRel)
15+
const configB = addDefaultPaths(configA, repositoryRoot, baseRel)
1616
return configB
1717
}
1818

@@ -72,14 +72,11 @@ const getWindowsDrive = function (path) {
7272

7373
// Some configuration properties have default values that are only set if a
7474
// specific directory/file exists in the build directory
75-
const addDefaultPaths = async function (config, repositoryRoot, baseRel) {
76-
const defaultPathsConfigs = await Promise.all(
77-
DEFAULT_PATHS.map(({ defaultPath, getConfig, propName }) =>
78-
addDefaultPath({ repositoryRoot, baseRel, defaultPath, getConfig, propName }),
79-
),
80-
)
81-
const defaultPathsConfigsA = defaultPathsConfigs.filter(Boolean)
82-
return mergeConfigs([...defaultPathsConfigsA, config])
75+
const addDefaultPaths = function (config, repositoryRoot, baseRel) {
76+
const defaultPathsConfigs = DEFAULT_PATHS.map(({ defaultPath, getConfig, propName }) =>
77+
addDefaultPath({ repositoryRoot, baseRel, defaultPath, getConfig, propName }),
78+
).filter(Boolean)
79+
return mergeConfigs([...defaultPathsConfigs, config])
8380
}
8481

8582
const DEFAULT_PATHS = [
@@ -101,10 +98,10 @@ const DEFAULT_PATHS = [
10198
},
10299
]
103100

104-
const addDefaultPath = async function ({ repositoryRoot, baseRel, defaultPath, getConfig, propName }) {
101+
const addDefaultPath = function ({ repositoryRoot, baseRel, defaultPath, getConfig, propName }) {
105102
const absolutePath = resolvePath(repositoryRoot, baseRel, defaultPath, propName)
106103

107-
if (!(await pathExists(absolutePath))) {
104+
if (!existsSync(absolutePath)) {
108105
return
109106
}
110107

packages/config/src/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ const normalizeConfigAndContext = function (config, origin) {
279279
const resolveFiles = async function ({ config, repositoryRoot, base, baseRelDir }) {
280280
const baseA = getBase(base, repositoryRoot, config)
281281
const buildDir = await getBuildDir(repositoryRoot, baseA)
282-
const configA = await resolveConfigPaths({ config, repositoryRoot, buildDir, baseRelDir })
282+
const configA = resolveConfigPaths({ config, repositoryRoot, buildDir, baseRelDir })
283283
const configB = addBase(configA, baseA)
284284
return { config: configB, buildDir, base: baseA }
285285
}

packages/config/src/mutations/update.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { promises as fs } from 'fs'
2-
3-
import { pathExists } from 'path-exists'
1+
import { existsSync, promises as fs } from 'fs'
42

53
import { ensureConfigPriority } from '../context.js'
64
import { addHeaders } from '../headers.js'
@@ -63,7 +61,7 @@ const saveConfig = async function (configPath, simplifiedConfig) {
6361
// Deletes `_headers/_redirects` since they are merged to `netlify.toml`,
6462
// to fix any priority problem.
6563
const deleteSideFile = async function (filePath) {
66-
if (filePath === undefined || !(await pathExists(filePath))) {
64+
if (filePath === undefined || !existsSync(filePath)) {
6765
return
6866
}
6967

@@ -105,7 +103,7 @@ const backupFile = async function (original, backup) {
105103
// this makes sure we don't restore stale files
106104
await deleteNoError(backup)
107105

108-
if (!(await pathExists(original))) {
106+
if (!existsSync(original)) {
109107
return
110108
}
111109

@@ -121,7 +119,7 @@ const deleteNoError = async (path) => {
121119
}
122120

123121
const copyOrDelete = async function (src, dest) {
124-
if (await pathExists(src)) {
122+
if (existsSync(src)) {
125123
await fs.copyFile(src, dest)
126124
return
127125
}

packages/config/src/options/base.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { promises as fs } from 'fs'
1+
import { existsSync, promises as fs } from 'fs'
22
import { dirname, relative, sep } from 'path'
33

4-
import { pathExists } from 'path-exists'
5-
64
// Retrieve `base` override.
75
// This uses any directory below `repositoryRoot` and above (or equal to)
86
// `cwd` that has a `.netlify` or `netlify.toml`. This allows Netlify CLI users
@@ -58,7 +56,7 @@ const locatePath = async function (paths) {
5856
}
5957

6058
const returnIfExists = async function (path) {
61-
if (!(await pathExists(path))) {
59+
if (!existsSync(path)) {
6260
return
6361
}
6462

packages/config/src/parse.js renamed to packages/config/src/parse.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
import { promises as fs } from 'fs'
2-
3-
import { pathExists } from 'path-exists'
1+
import { existsSync, promises as fs } from 'fs'
42

53
import { throwUserError } from './error.js'
64
import { throwOnInvalidTomlSequence } from './log/messages.js'
75
import { parseToml } from './utils/toml.js'
86

9-
// Load the configuration file and parse it (TOML)
10-
export const parseConfig = async function (configPath) {
7+
/**
8+
* Load the configuration file and parse it (TOML)
9+
* @param configPath The path to the toml file
10+
* @returns
11+
*/
12+
export const parseConfig = async function (configPath?: string) {
1113
if (configPath === undefined) {
1214
return {}
1315
}
1416

15-
if (!(await pathExists(configPath))) {
17+
if (!existsSync(configPath)) {
1618
throwUserError('Configuration file does not exist')
1719
}
1820

1921
return await readConfigPath(configPath)
2022
}
2123

22-
// Same but `configPath` is required and `configPath` might point to a
23-
// non-existing file.
24+
/**
25+
* Same but `configPath` is required and `configPath` might point to a
26+
* non-existing file.
27+
*/
2428
export const parseOptionalConfig = async function (configPath) {
25-
if (!(await pathExists(configPath))) {
29+
if (!existsSync(configPath)) {
2630
return {}
2731
}
2832

@@ -41,7 +45,9 @@ const readConfigPath = async function (configPath) {
4145
}
4246
}
4347

44-
// Reach the configuration file's raw content
48+
/**
49+
* Reach the configuration file's raw content
50+
*/
4551
const readConfig = async function (configPath) {
4652
try {
4753
return await fs.readFile(configPath, 'utf8')
@@ -60,10 +66,12 @@ const validateTomlBlackslashes = function (configString) {
6066
throwOnInvalidTomlSequence(invalidSequence)
6167
}
6268

63-
// The TOML specification forbids unrecognized backslash sequences. However,
64-
// `toml-node` does not respect the specification and do not fail on those.
65-
// Therefore, we print a warning message.
66-
// This only applies to " and """ strings, not ' nor '''
67-
// Also, """ strings can use trailing backslashes.
69+
/**
70+
* The TOML specification forbids unrecognized backslash sequences. However,
71+
* `toml-node` does not respect the specification and do not fail on those.
72+
* Therefore, we print a warning message.
73+
* This only applies to " and """ strings, not ' nor '''
74+
* Also, """ strings can use trailing backslashes.
75+
*/
6876
const INVALID_TOML_BLACKSLASH =
6977
/\n[a-zA-Z]+ *= *(?:(?:""".*(?<!\\)(\\[^"\\btnfruU\n]).*""")|(?:"(?!")[^\n]*(?<!\\)(\\[^"\\btnfruU])[^\n]*"))/su

packages/config/src/path.js renamed to packages/config/src/path.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
import { existsSync } from 'fs'
12
import { resolve } from 'path'
23

34
import { findUp } from 'find-up'
45
import pLocate from 'p-locate'
5-
import { pathExists } from 'path-exists'
66

7-
// Configuration location can be:
8-
// - a local path with the --config CLI flag
9-
// - a `netlify.*` file in the `repositoryRoot/{base}`
10-
// - a `netlify.*` file in the `repositoryRoot`
11-
// - a `netlify.*` file in the current directory or any parent
7+
/**
8+
* Configuration location can be:
9+
* - a local path with the --config CLI flag
10+
* - a `netlify.*` file in the `repositoryRoot/{base}`
11+
* - a `netlify.*` file in the `repositoryRoot`
12+
* - a `netlify.*` file in the current directory or any parent
13+
*/
1214
export const getConfigPath = async function ({ configOpt, cwd, repositoryRoot, configBase }) {
1315
const configPath = await pLocate(
1416
[
@@ -22,28 +24,32 @@ export const getConfigPath = async function ({ configOpt, cwd, repositoryRoot, c
2224
return configPath
2325
}
2426

25-
// --config CLI flag
26-
const searchConfigOpt = function (cwd, configOpt) {
27+
/** --config CLI flag */
28+
const searchConfigOpt = function (cwd: string, configOpt?: string) {
2729
if (configOpt === undefined) {
2830
return
2931
}
3032

3133
return resolve(cwd, configOpt)
3234
}
3335

34-
// Look for `repositoryRoot/{base}/netlify.*`
35-
const searchBaseConfigFile = function (repositoryRoot, configBase) {
36+
/**
37+
* Look for `repositoryRoot/{base}/netlify.*`
38+
*/
39+
const searchBaseConfigFile = function (repositoryRoot, configBase?: string) {
3640
if (configBase === undefined) {
3741
return
3842
}
3943

4044
return searchConfigFile(configBase)
4145
}
4246

43-
// Look for several file extensions for `netlify.*`
44-
const searchConfigFile = async function (cwd) {
47+
/**
48+
* Look for several file extensions for `netlify.*`
49+
*/
50+
const searchConfigFile = function (cwd: string): string | undefined {
4551
const path = resolve(cwd, FILENAME)
46-
if (!(await pathExists(path))) {
52+
if (!existsSync(path)) {
4753
return
4854
}
4955
return path

packages/config/tests/mutate/tests.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { promises as fs } from 'fs'
1+
import { existsSync, promises as fs } from 'fs'
22
import { fileURLToPath } from 'url'
33

44
import { Fixture, normalizeOutput } from '@netlify/testing'
55
import test from 'ava'
66
import del from 'del'
7-
import { pathExists } from 'path-exists'
87

98
import { updateConfig } from '../../lib/main.js'
109

@@ -50,19 +49,19 @@ const initFixtureDir = async function (fixtureName) {
5049
// Create temporary copies of `netlify.toml` and `redirects` from the fixture
5150
// directory to use in tests
5251
const copyIfExists = async function (fixturePath, tempPath) {
53-
if (await pathExists(fixturePath)) {
52+
if (existsSync(fixturePath)) {
5453
await fs.copyFile(fixturePath, tempPath)
5554
return
5655
}
5756

58-
if (await pathExists(tempPath)) {
57+
if (existsSync(tempPath)) {
5958
await del(tempPath)
6059
}
6160
}
6261

6362
test('updateConfig() saves netlify.toml', async (t) => {
6463
const { configPath } = await runUpdateConfig('save')
65-
t.true(await pathExists(configPath))
64+
t.true(existsSync(configPath))
6665
})
6766

6867
test('updateConfig() updates the configuration so it can be read again', async (t) => {
@@ -73,7 +72,7 @@ test('updateConfig() updates the configuration so it can be read again', async (
7372

7473
test('updateConfig() is a noop when where are no config mutations', async (t) => {
7574
const { configPath } = await runUpdateConfig('noop', { configMutations: [] })
76-
t.false(await pathExists(configPath))
75+
t.false(existsSync(configPath))
7776
})
7877

7978
test('updateConfig() has higher priority than context properties', async (t) => {
@@ -91,19 +90,19 @@ test('updateConfig() merges with the existing netlify.toml', async (t) => {
9190
test('updateConfig() deletes _redirects when redirects were changed', async (t) => {
9291
const { redirectsPath } = await runUpdateConfig('redirects_change', { configMutations: [redirectsMutation] })
9392
t.is(typeof redirectsPath, 'string')
94-
t.false(await pathExists(redirectsPath))
93+
t.false(existsSync(redirectsPath))
9594
})
9695

9796
test('updateConfig() deletes _redirects on changes even if redirects were not changed', async (t) => {
9897
const { redirectsPath } = await runUpdateConfig('redirects_no_change')
9998
t.is(typeof redirectsPath, 'string')
100-
t.false(await pathExists(redirectsPath))
99+
t.false(existsSync(redirectsPath))
101100
})
102101

103102
test('updateConfig() does not delete _redirects if it does not exist', async (t) => {
104103
const { redirectsPath } = await runUpdateConfig('redirects_none')
105104
t.is(typeof redirectsPath, 'string')
106-
t.false(await pathExists(redirectsPath))
105+
t.false(existsSync(redirectsPath))
107106
})
108107

109108
test('updateConfig() does not delete _redirects if redirectsPath not provided', async (t) => {
@@ -112,25 +111,25 @@ test('updateConfig() does not delete _redirects if redirectsPath not provided',
112111
redirectsPath: undefined,
113112
})
114113
t.is(typeof redirectsPath, 'string')
115-
t.true(await pathExists(redirectsPath))
114+
t.true(existsSync(redirectsPath))
116115
})
117116

118117
test('updateConfig() deletes _headers when headers were changed', async (t) => {
119118
const { headersPath } = await runUpdateConfig('headers_change', { configMutations: [headersMutation] })
120119
t.is(typeof headersPath, 'string')
121-
t.false(await pathExists(headersPath))
120+
t.false(existsSync(headersPath))
122121
})
123122

124123
test('updateConfig() deletes _headers on changes even if headers were not changed', async (t) => {
125124
const { headersPath } = await runUpdateConfig('headers_no_change')
126125
t.is(typeof headersPath, 'string')
127-
t.false(await pathExists(headersPath))
126+
t.false(existsSync(headersPath))
128127
})
129128

130129
test('updateConfig() does not delete _headers if it does not exist', async (t) => {
131130
const { headersPath } = await runUpdateConfig('headers_none')
132131
t.is(typeof headersPath, 'string')
133-
t.false(await pathExists(headersPath))
132+
t.false(existsSync(headersPath))
134133
})
135134

136135
test('updateConfig() does not delete _headers if headersPath not provided', async (t) => {
@@ -139,5 +138,5 @@ test('updateConfig() does not delete _headers if headersPath not provided', asyn
139138
headersPath: undefined,
140139
})
141140
t.is(typeof headersPath, 'string')
142-
t.true(await pathExists(headersPath))
141+
t.true(existsSync(headersPath))
143142
})

0 commit comments

Comments
 (0)