Skip to content
This repository was archived by the owner on Mar 20, 2025. It is now read-only.

Commit d4ec906

Browse files
jackiewmachariakhendrikseeduardoboucas
authored
feat: support for multiple paths in in source configuration (#230)
* feat: support for multiple paths in in source configuration * fix: use array for isc path properties * fix: support both array and string path properties * fix: fix linting * fix: have a string usecase in declaration tests by transforming json array to string * fix: remove file-level eslint-disable-max-depth * fix: change conditional for cache config and path length * fix: change conditional for adding all different types of config * fix: remove fallback to empty object * fix: change comment * fix: undo changing config fixtures to use an array as path * fix: update comments * Update node/declaration.ts Co-authored-by: Eduardo Bouças <[email protected]> * fix: change mutation of config.path * fix: formatting Co-authored-by: khen <[email protected]> Co-authored-by: Eduardo Bouças <[email protected]>
1 parent 94c6ec6 commit d4ec906

File tree

4 files changed

+89
-11
lines changed

4 files changed

+89
-11
lines changed

node/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const enum Cache {
2929

3030
export interface FunctionConfig {
3131
cache?: Cache
32-
path?: string
32+
path?: string | string[]
3333
}
3434

3535
const getConfigExtractor = () => {

node/declaration.test.ts

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ const deployConfig = {
99
layers: [],
1010
}
1111

12-
test('In source config takes precedence over netlify.toml config', () => {
12+
test('In-source config takes precedence over netlify.toml config', () => {
1313
const tomlConfig = [
1414
{ function: 'geolocation', path: '/geo', cache: 'off' },
1515
{ function: 'json', path: '/json', cache: 'manual' },
1616
]
1717

1818
const funcConfig = {
19-
geolocation: { path: '/geo-isc', cache: 'manual' },
19+
geolocation: { path: ['/geo-isc', '/*'], cache: 'manual' },
2020
json: { path: '/json', cache: 'off' },
2121
} as Record<string, FunctionConfig>
2222

2323
const expectedDeclarations = [
2424
{ function: 'geolocation', path: '/geo-isc', cache: 'manual' },
25+
{ function: 'geolocation', path: '/*', cache: 'manual' },
2526
{ function: 'json', path: '/json', cache: 'off' },
2627
]
2728

@@ -30,14 +31,14 @@ test('In source config takes precedence over netlify.toml config', () => {
3031
expect(declarations).toEqual(expectedDeclarations)
3132
})
3233

33-
test("Declarations don't break if no in source config is provided", () => {
34+
test("Declarations don't break if no in-source config is provided", () => {
3435
const tomlConfig = [
3536
{ function: 'geolocation', path: '/geo', cache: 'off' },
3637
{ function: 'json', path: '/json', cache: 'manual' },
3738
]
3839

3940
const funcConfig = {
40-
geolocation: { path: '/geo-isc', cache: 'manual' },
41+
geolocation: { path: ['/geo-isc'], cache: 'manual' },
4142
json: {},
4243
} as Record<string, FunctionConfig>
4344

@@ -51,11 +52,11 @@ test("Declarations don't break if no in source config is provided", () => {
5152
expect(declarations).toEqual(expectedDeclarations)
5253
})
5354

54-
test('In source config works independent of the netlify.toml file if a path is defined and otherwise if no path is set', () => {
55+
test('In-source config works independent of the netlify.toml file if a path is defined and otherwise if no path is set', () => {
5556
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }]
5657

5758
const funcConfigWithPath = {
58-
json: { path: '/json', cache: 'off' },
59+
json: { path: ['/json', '/json-isc'], cache: 'off' },
5960
} as Record<string, FunctionConfig>
6061

6162
const funcConfigWithoutPath = {
@@ -65,6 +66,7 @@ test('In source config works independent of the netlify.toml file if a path is d
6566
const expectedDeclarationsWithISCPath = [
6667
{ function: 'geolocation', path: '/geo', cache: 'off' },
6768
{ function: 'json', path: '/json', cache: 'off' },
69+
{ function: 'json', path: '/json-isc', cache: 'off' },
6870
]
6971

7072
const expectedDeclarationsWithoutISCPath = [{ function: 'geolocation', path: '/geo', cache: 'off' }]
@@ -75,3 +77,53 @@ test('In source config works independent of the netlify.toml file if a path is d
7577
const declarationsWithoutISCPath = getDeclarationsFromConfig(tomlConfig, funcConfigWithoutPath, deployConfig)
7678
expect(declarationsWithoutISCPath).toEqual(expectedDeclarationsWithoutISCPath)
7779
})
80+
81+
test('In-source config works if only the cache config property is set', () => {
82+
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }]
83+
84+
const funcConfig = {
85+
geolocation: { cache: 'manual' },
86+
} as Record<string, FunctionConfig>
87+
88+
const expectedDeclarations = [{ function: 'geolocation', path: '/geo', cache: 'manual' }]
89+
90+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations)
91+
})
92+
93+
test("In-source config path property works if it's not an array", () => {
94+
const tomlConfig = [{ function: 'json', path: '/json-toml', cache: 'off' }]
95+
96+
const funcConfig = {
97+
json: { path: '/json', cache: 'manual' },
98+
} as Record<string, FunctionConfig>
99+
100+
const expectedDeclarations = [{ function: 'json', path: '/json', cache: 'manual' }]
101+
102+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations)
103+
})
104+
105+
test("In-source config path property works if it's not an array and it's not present in toml or deploy config", () => {
106+
const tomlConfig = [{ function: 'geolocation', path: '/geo', cache: 'off' }]
107+
const funcConfig = {
108+
json: { path: '/json-isc', cache: 'manual' },
109+
} as Record<string, FunctionConfig>
110+
111+
const expectedDeclarations = [
112+
{ function: 'geolocation', path: '/geo', cache: 'off' },
113+
{ function: 'json', path: '/json-isc', cache: 'manual' },
114+
]
115+
116+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations)
117+
})
118+
119+
test('In-source config works if path property is an empty array with cache value specified', () => {
120+
const tomlConfig = [{ function: 'json', path: '/json-toml', cache: 'off' }]
121+
122+
const funcConfig = {
123+
json: { path: [], cache: 'manual' },
124+
} as Record<string, FunctionConfig>
125+
126+
const expectedDeclarations = [{ function: 'json', path: '/json-toml', cache: 'manual' }]
127+
128+
expect(getDeclarationsFromConfig(tomlConfig, funcConfig, deployConfig)).toEqual(expectedDeclarations)
129+
})

node/declaration.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,44 @@ export const getDeclarationsFromConfig = (
3030
// a function configuration object, we replace the path because that object
3131
// takes precedence.
3232
for (const declaration of [...tomlDeclarations, ...deployConfig.declarations]) {
33-
const config = functionsConfig[declaration.function] ?? {}
33+
const config = functionsConfig[declaration.function]
34+
35+
// If no config is found, add the declaration as is
36+
if (!config) {
37+
declarations.push(declaration)
38+
39+
// If we have a path specified as either a string or non-empty array
40+
// create a declaration for each path
41+
} else if (config.path?.length) {
42+
const paths = Array.isArray(config.path) ? config.path : [config.path]
43+
44+
paths.forEach((path) => {
45+
declarations.push({ ...declaration, ...config, path })
46+
})
47+
48+
// With an in-source config without a path, add the config to the declaration
49+
} else {
50+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
51+
const { path, ...rest } = config
52+
declarations.push({ ...declaration, ...rest })
53+
}
3454

3555
functionsVisited.add(declaration.function)
36-
declarations.push({ ...declaration, ...config })
3756
}
3857

3958
// Finally, we must create declarations for functions that are not declared
4059
// in the TOML at all.
4160
for (const name in functionsConfig) {
42-
const { path, ...config } = functionsConfig[name]
61+
const { ...config } = functionsConfig[name]
62+
const { path } = functionsConfig[name]
4363

64+
// If we have path specified create a declaration for each path
4465
if (!functionsVisited.has(name) && path) {
45-
declarations.push({ ...config, function: name, path })
66+
const paths = Array.isArray(path) ? path : [path]
67+
68+
paths.forEach((singlePath) => {
69+
declarations.push({ ...config, function: name, path: singlePath })
70+
})
4671
}
4772
}
4873

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"test:dev": "run-s test:dev:*",
3030
"test:ci": "run-s test:ci:*",
3131
"test:dev:vitest": "cross-env FORCE_COLOR=0 vitest run",
32+
"test:dev:vitest:watch": "cross-env FORCE_COLOR=0 vitest watch",
3233
"test:dev:deno": "deno test --allow-all deno",
3334
"test:ci:vitest": "cross-env FORCE_COLOR=0 vitest run",
3435
"test:ci:deno": "deno test --allow-all deno",

0 commit comments

Comments
 (0)