in src/shared/cloudformation/templateRegistry.ts [99:245]
export function getResourcesForHandlerFromTemplateDatum(
filepath: string,
handler: string,
templateDatum: WatchedItem<CloudFormation.Template>
): { name: string; resourceData: CloudFormation.Resource }[] {
const matchingResources: { name: string; resourceData: CloudFormation.Resource }[] = []
const templateDirname = path.dirname(templateDatum.path)
// template isn't a parent or sibling of file
if (!isInDirectory(templateDirname, path.dirname(filepath))) {
return []
}
// no resources
const resources = templateDatum.item.Resources
if (!resources) {
return []
}
for (const key of Object.keys(resources)) {
const resource = resources[key]
// check if some sort of serverless function
if (
resource &&
[CloudFormation.SERVERLESS_FUNCTION_TYPE, CloudFormation.LAMBDA_FUNCTION_TYPE].includes(resource.Type)
) {
// parse template values that could potentially be refs
const registeredRuntime = CloudFormation.getStringForProperty(
resource.Properties,
'Runtime',
templateDatum.item
)
const registeredCodeUri = CloudFormation.getStringForProperty(
resource.Properties,
'CodeUri',
templateDatum.item
)
const registeredHandler = CloudFormation.getStringForProperty(
resource.Properties,
'Handler',
templateDatum.item
)
// properties for image type templates
const registeredPackageType = CloudFormation.getStringForProperty(
resource.Properties,
'PackageType',
templateDatum.item
)
const registeredDockerContext = CloudFormation.getStringForProperty(
resource.Metadata,
'DockerContext',
templateDatum.item
)
const registeredDockerFile = CloudFormation.getStringForProperty(
resource.Metadata,
'Dockerfile',
templateDatum.item
)
if (registeredRuntime && registeredHandler && registeredCodeUri) {
// Java and .NET are currently special cases in that the filepath and handler aren't specific.
// For now: check if handler matches and check if the code URI contains the filepath.
// TODO: Can we use Omnisharp or some sort of Java tooling to help guide us better?
if (dotNetRuntimes.includes(registeredRuntime) || javaRuntimes.includes(registeredRuntime)) {
if (
handler === registeredHandler &&
isInDirectory(
pathutils.normalize(path.join(templateDirname, registeredCodeUri)),
pathutils.normalize(filepath)
)
) {
matchingResources.push({ name: key, resourceData: resource })
}
} else if (goRuntimes.includes(registeredRuntime)) {
// Go is another special case. The handler merely refers to the compiled binary.
// We ignore checking for a handler name match, since it is not relevant
// See here: https://github.com/aws/aws-lambda-go
if (
isInDirectory(
pathutils.normalize(path.join(templateDirname, registeredCodeUri)),
pathutils.normalize(filepath)
)
) {
matchingResources.push({ name: key, resourceData: resource })
}
} else {
// Interpreted languages all follow the same spec:
// ./path/to/handler/without/file/extension.handlerName
// Check to ensure filename and handler both match.
try {
const parsedLambda = getLambdaDetails({
Handler: registeredHandler,
Runtime: registeredRuntime,
})
const functionName = handler.split('.').pop()
if (
pathutils.normalize(filepath) ===
pathutils.normalize(
path.join(templateDirname, registeredCodeUri, parsedLambda.fileName)
) &&
functionName === parsedLambda.functionName
) {
matchingResources.push({ name: key, resourceData: resource })
}
} catch (e) {
getLogger().warn(
`Resource ${key} in template ${templateDirname} has invalid runtime for handler ${handler}: ${registeredRuntime}`
)
}
}
// not direct-invoke type, attempt image type
} else if (registeredPackageType === 'Image' && registeredDockerContext && registeredDockerFile) {
// path must be inside dockerDir
const dockerDir = path.join(templateDirname, registeredDockerContext)
if (isInDirectory(dockerDir, filepath)) {
let adjustedHandler: string = handler
if (!filepath.endsWith('.cs')) {
// reframe path to be relative to dockerDir instead of package.json
// omit filename and append filename + function name from handler
const relPath = path.relative(dockerDir, path.dirname(filepath))
const handlerParts = pathutils.normalizeSeparator(handler).split('/')
adjustedHandler = pathutils.normalizeSeparator(
path.join(relPath, handlerParts[handlerParts.length - 1])
)
}
try {
// open dockerfile and see if it has a handler that matches the handler represented by this file
const fileText = readFileSync(path.join(dockerDir, registeredDockerFile)).toString()
// exact match within quotes to avoid shorter paths being picked up
if (
new RegExp(`['"]${adjustedHandler}['"]`, 'g').test(pathutils.normalizeSeparator(fileText))
) {
matchingResources.push({ name: key, resourceData: resource })
}
} catch (e) {
// file read error
getLogger().error(e as Error)
}
}
} else {
getLogger().verbose(`Resource ${key} in template ${templateDirname} does not match handler ${handler}`)
}
}
}
return matchingResources
}