This repository has been archived by the owner on May 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
feat: support CommonJS syntax in V2 functions #1585
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
afefe6c
feat: add `inputModuleFormat` property
eduardoboucas e84a84b
feat: add `tsConfig` to `listFunctions` output
eduardoboucas de1e1af
chore: update tests
eduardoboucas f496e0c
chore: update tests
eduardoboucas 409bf7d
chore: update snapshots
eduardoboucas d6ae4f1
chore: update snapshot
eduardoboucas 9b852fb
refactor: rename methods
eduardoboucas c52807a
feat: return `jsModuleFormat` property
eduardoboucas d1b747c
feat: add bundled paths to `inputs`
eduardoboucas c0be11c
feat: force bundler to NFT in V2 functions
eduardoboucas dab476c
chore: fix test
eduardoboucas 881a5bd
Merge branch 'feat/cjs-v2' into feat/function-metadata
eduardoboucas c93099f
refactor: remove `tsconfig` property
eduardoboucas d8362dd
refactor: remove traces of `tsconfig`
eduardoboucas 9f7ee46
feat: support CJS in V2 functions
eduardoboucas 71a96be
refactor: tidy up
eduardoboucas 83ffde3
Merge branch 'main' into feat/function-metadata
eduardoboucas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,22 +8,27 @@ import { getRoutes, Route } from '../../../utils/routes.js' | |
import { RUNTIME } from '../../runtime.js' | ||
import { NODE_BUNDLER } from '../bundlers/types.js' | ||
import { createBindingsMethod } from '../parser/bindings.js' | ||
import { getExports } from '../parser/exports.js' | ||
import { traverseNodes } from '../parser/exports.js' | ||
import { getImports } from '../parser/imports.js' | ||
import { safelyParseSource, safelyReadSource } from '../parser/index.js' | ||
import type { ModuleFormat } from '../utils/module_format.js' | ||
|
||
import { parse as parseSchedule } from './properties/schedule.js' | ||
|
||
export const IN_SOURCE_CONFIG_MODULE = '@netlify/functions' | ||
|
||
export type ISCValues = { | ||
invocationMode?: InvocationMode | ||
routes?: Route[] | ||
runtimeAPIVersion?: number | ||
schedule?: string | ||
methods?: string[] | ||
} | ||
|
||
export interface StaticAnalysisResult extends ISCValues { | ||
inputModuleFormat?: ModuleFormat | ||
invocationMode?: InvocationMode | ||
runtimeAPIVersion?: number | ||
} | ||
|
||
interface FindISCDeclarationsOptions { | ||
functionName: string | ||
logger: Logger | ||
|
@@ -45,22 +50,6 @@ const validateScheduleFunction = (functionFound: boolean, scheduleFound: boolean | |
} | ||
} | ||
|
||
// Parses a JS/TS file and looks for in-source config declarations. It returns | ||
// an array of all declarations found, with `property` indicating the name of | ||
// the property and `data` its value. | ||
export const findISCDeclarationsInPath = async ( | ||
sourcePath: string, | ||
{ functionName, logger }: FindISCDeclarationsOptions, | ||
): Promise<ISCValues> => { | ||
const source = await safelyReadSource(sourcePath) | ||
|
||
if (source === null) { | ||
return {} | ||
} | ||
|
||
return findISCDeclarations(source, { functionName, logger }) | ||
} | ||
|
||
/** | ||
* Normalizes method names into arrays of uppercase strings. | ||
* (e.g. "get" becomes ["GET"]) | ||
|
@@ -84,10 +73,32 @@ const normalizeMethods = (input: unknown, name: string): string[] | undefined => | |
}) | ||
} | ||
|
||
export const findISCDeclarations = ( | ||
/** | ||
* Loads a file at a given path, parses it into an AST, and returns a series of | ||
* data points, such as in-source configuration properties and other metadata. | ||
*/ | ||
export const parseFile = async ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was renamed from |
||
sourcePath: string, | ||
{ functionName, logger }: FindISCDeclarationsOptions, | ||
): Promise<StaticAnalysisResult> => { | ||
const source = await safelyReadSource(sourcePath) | ||
|
||
if (source === null) { | ||
return {} | ||
} | ||
|
||
return parseSource(source, { functionName, logger }) | ||
} | ||
|
||
/** | ||
* Takes a JS/TS source as a string, parses it into an AST, and returns a | ||
* series of data points, such as in-source configuration properties and | ||
* other metadata. | ||
*/ | ||
export const parseSource = ( | ||
source: string, | ||
{ functionName, logger }: FindISCDeclarationsOptions, | ||
): ISCValues => { | ||
): StaticAnalysisResult => { | ||
const ast = safelyParseSource(source) | ||
|
||
if (ast === null) { | ||
|
@@ -101,27 +112,28 @@ export const findISCDeclarations = ( | |
let scheduleFound = false | ||
|
||
const getAllBindings = createBindingsMethod(ast.body) | ||
const { configExport, defaultExport, handlerExports } = getExports(ast.body, getAllBindings) | ||
const isV2API = handlerExports.length === 0 && defaultExport !== undefined | ||
const { configExport, handlerExports, hasDefaultExport, inputModuleFormat } = traverseNodes(ast.body, getAllBindings) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We were not using the contents of |
||
const isV2API = handlerExports.length === 0 && hasDefaultExport | ||
|
||
if (isV2API) { | ||
const config: ISCValues = { | ||
const result: StaticAnalysisResult = { | ||
inputModuleFormat, | ||
runtimeAPIVersion: 2, | ||
} | ||
|
||
logger.system('detected v2 function') | ||
|
||
if (typeof configExport.schedule === 'string') { | ||
config.schedule = configExport.schedule | ||
result.schedule = configExport.schedule | ||
} | ||
|
||
if (configExport.method !== undefined) { | ||
config.methods = normalizeMethods(configExport.method, functionName) | ||
result.methods = normalizeMethods(configExport.method, functionName) | ||
} | ||
|
||
config.routes = getRoutes(configExport.path, functionName, config.methods ?? []) | ||
result.routes = getRoutes(configExport.path, functionName, result.methods ?? []) | ||
|
||
return config | ||
return result | ||
} | ||
|
||
const iscExports = handlerExports | ||
|
@@ -171,7 +183,7 @@ export const findISCDeclarations = ( | |
|
||
const mergedExports: ISCValues = iscExports.reduce((acc, obj) => ({ ...acc, ...obj }), {}) | ||
|
||
return { ...mergedExports, runtimeAPIVersion: 1 } | ||
return { ...mergedExports, inputModuleFormat, runtimeAPIVersion: 1 } | ||
} | ||
|
||
export type ISCHandlerArg = ArgumentPlaceholder | Expression | SpreadElement | JSXNamespacedName | ||
|
@@ -181,5 +193,9 @@ export type ISCExportWithCallExpression = { | |
args: ISCHandlerArg[] | ||
local: string | ||
} | ||
export type ISCExportWithObject = { | ||
type: 'object-expression' | ||
object: Record<string, unknown> | ||
} | ||
export type ISCExportOther = { type: 'other' } | ||
export type ISCExport = ISCExportWithCallExpression | ISCExportOther | ||
export type ISCExport = ISCExportWithCallExpression | ISCExportWithObject | ISCExportOther |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were using the term "ISC" to contain properties that are not part of the in-source configuration spec, like
invocationMode
orruntimeAPIVersion
. They were grouped together because we extract both those properties and the ISC properties using the same static analysis step, but functionally they are different things.So now we have a
ISCValues
type that holds just the in-source configuration properties, and aStaticAnalysisResult
that holds those plus some additional metadata properties we'll extract using the static analysis mechanism.A big part of this diff is just renaming ISC-related terms to a more generic "static analysis result".