Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { dirname } from 'path'

import type { ArgumentPlaceholder, Expression, SpreadElement, JSXNamespacedName } from '@babel/types'
import mergeOptions from 'merge-options'
import { z } from 'zod'
Expand Down Expand Up @@ -215,10 +217,26 @@ export const parseSource = (source: string, { functionName }: FindISCDeclaration
}

export const augmentFunctionConfig = (
mainFile: string,
tomlConfig: FunctionConfig,
inSourceConfig: InSourceConfig = {},
): FunctionConfig & InSourceConfig => {
return mergeOptions.call({ concatArrays: true }, tomlConfig, inSourceConfig)
) => {
const mergedConfig = mergeOptions.call({ concatArrays: true }, tomlConfig, inSourceConfig) as FunctionConfig &
InSourceConfig

// We can't simply merge included files from the TOML and from in-source
// configuration because their globs are relative to different base paths.
// In the future, we could shift things around so we resolve each glob
// relative to the right base, but for now we say that included files in
// the source override any files defined in the TOML. It doesn't make a lot
// of sense to be defining include files for a framework-generated function
// in the TOML anyway.
if (inSourceConfig?.includedFiles && inSourceConfig.includedFiles.length !== 0) {
mergedConfig.includedFiles = inSourceConfig.includedFiles
mergedConfig.includedFilesBasePath = dirname(mainFile)
}

return mergedConfig
}

export type ISCHandlerArg = ArgumentPlaceholder | Expression | SpreadElement | JSXNamespacedName
Expand Down
2 changes: 1 addition & 1 deletion packages/zip-it-and-ship-it/src/runtimes/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const zipFunction: ZipFunction = async function ({

const staticAnalysisResult = await parseFile(mainFile, { functionName: name })
const runtimeAPIVersion = staticAnalysisResult.runtimeAPIVersion === 2 ? 2 : 1
const mergedConfig = augmentFunctionConfig(config, staticAnalysisResult.config)
const mergedConfig = augmentFunctionConfig(mainFile, config, staticAnalysisResult.config)
const pluginsModulesPath = await getPluginsModulesPath(srcDir)
const bundlerName = await getBundlerName({
config: mergedConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export default async () =>
})

export const config = {
includedFiles: ['blog/author*'],
includedFiles: ['../../blog/post*'],
}
61 changes: 31 additions & 30 deletions packages/zip-it-and-ship-it/tests/v2api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { promisify } from 'util'

import merge from 'deepmerge'
import glob from 'glob'
import { pathExists } from 'path-exists'
import semver from 'semver'
import { dir as getTmpDir } from 'tmp-promise'
import { afterEach, describe, expect, test, vi } from 'vitest'
Expand Down Expand Up @@ -598,39 +599,39 @@ describe.runIf(semver.gte(nodeVersion, '18.13.0'))('V2 functions API', () => {
},
)

testMany(
'Includes in the bundle files included in the TOML and in the function source',
['bundler_default'],
async (options) => {
const fixtureName = 'v2-api-included-files'
const { files, tmpDir } = await zipFixture(fixtureName, {
fixtureDir: FIXTURES_ESM_DIR,
opts: merge(options, {
archiveFormat: ARCHIVE_FORMAT.NONE,
config: {
'*': {
includedFiles: ['blog/post*'],
},
test('Includes in the bundle files included in the function source', async () => {
const fixtureName = 'v2-api-included-files'
const { files, tmpDir } = await zipFixture(`${fixtureName}/netlify/functions`, {
fixtureDir: FIXTURES_ESM_DIR,
opts: {
archiveFormat: ARCHIVE_FORMAT.NONE,
basePath: resolve(FIXTURES_ESM_DIR, fixtureName),
config: {
'*': {
includedFiles: ['blog/author*'],
},
}),
})
},
},
})

const [{ name: archive, entryFilename, includedFiles, runtimeAPIVersion }] = files
const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`)
const { body: bodyStream, multiValueHeaders = {}, statusCode } = await invokeLambda(func)
const body = await readAsBuffer(bodyStream)
const [{ name: archive, entryFilename, includedFiles, runtimeAPIVersion }] = files
const func = await importFunctionFile(`${tmpDir}/${archive}/${entryFilename}`)
const { body: bodyStream, multiValueHeaders = {}, statusCode } = await invokeLambda(func)
const body = await readAsBuffer(bodyStream)

expect(body).toBe('<h1>Hello world</h1>')
expect(multiValueHeaders['content-type']).toEqual(['text/html'])
expect(statusCode).toBe(200)
expect(runtimeAPIVersion).toBe(2)
expect(includedFiles).toEqual([
resolve(FIXTURES_ESM_DIR, fixtureName, 'blog/author1.md'),
resolve(FIXTURES_ESM_DIR, fixtureName, 'blog/post1.md'),
resolve(FIXTURES_ESM_DIR, fixtureName, 'blog/post2.md'),
])
},
)
expect(body).toBe('<h1>Hello world</h1>')
expect(multiValueHeaders['content-type']).toEqual(['text/html'])
expect(statusCode).toBe(200)
expect(runtimeAPIVersion).toBe(2)
expect(includedFiles).toEqual([
resolve(FIXTURES_ESM_DIR, fixtureName, 'blog/post1.md'),
resolve(FIXTURES_ESM_DIR, fixtureName, 'blog/post2.md'),
])

for (const path of includedFiles as string[]) {
expect(await pathExists(path)).toBeTruthy()
}
})

test('Uses the bundler specified in the `nodeBundler` property from the in-source configuration', async () => {
const fixtureName = 'v2-api-bundler-none'
Expand Down