You've already forked serverless-plugin-typescript
mirror of
https://github.com/encounter/serverless-plugin-typescript.git
synced 2026-03-30 11:37:55 -07:00
134 lines
4.5 KiB
TypeScript
134 lines
4.5 KiB
TypeScript
import * as ts from 'typescript'
|
|
import * as fs from 'fs-extra'
|
|
import * as _ from 'lodash'
|
|
import { ServerlessFunction } from './types'
|
|
import * as path from 'path'
|
|
|
|
export function makeDefaultTypescriptConfig() {
|
|
const defaultTypescriptConfig: ts.CompilerOptions = {
|
|
preserveConstEnums: true,
|
|
strictNullChecks: true,
|
|
sourceMap: true,
|
|
target: ts.ScriptTarget.ES5,
|
|
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
lib: ['lib.es2015.d.ts'],
|
|
rootDir: './',
|
|
}
|
|
|
|
return defaultTypescriptConfig
|
|
}
|
|
|
|
export function extractFileNames(cwd: string, provider: string, functions?: { [key: string]: ServerlessFunction }): string[] {
|
|
|
|
// The Google provider will use the entrypoint not from the definition of the
|
|
// handler function, but instead from the package.json:main field, or via a
|
|
// index.js file. This check reads the current package.json in the same way
|
|
// that we already read the tsconfig.json file, by inspecting the current
|
|
// working directory. If the packageFile does not contain a valid main, then
|
|
// it instead selects the index.js file.
|
|
if (provider === 'google') {
|
|
const packageFilePath = path.join(cwd, 'package.json')
|
|
if (fs.existsSync(packageFilePath)) {
|
|
|
|
// Load in the package.json file.
|
|
const packageFile = JSON.parse(fs.readFileSync(packageFilePath).toString())
|
|
|
|
// Either grab the package.json:main field, or use the index.ts file.
|
|
// (This will be transpiled to index.js).
|
|
const main = packageFile.main ? packageFile.main.replace(/\.js$/, '.ts') : 'index.ts'
|
|
|
|
// Check that the file indeed exists.
|
|
if (!fs.existsSync(path.join(cwd, main))) {
|
|
console.log(`Cannot locate entrypoint, ${main} not found`)
|
|
throw new Error('Typescript compilation failed')
|
|
}
|
|
|
|
return [main]
|
|
}
|
|
}
|
|
|
|
return _.values(functions)
|
|
.map(fn => fn.handler)
|
|
.map(h => {
|
|
const fnName = _.last(h.split('.'))
|
|
const fnNameLastAppearanceIndex = h.lastIndexOf(fnName)
|
|
// replace only last instance to allow the same name for file and handler
|
|
return h.substring(0, fnNameLastAppearanceIndex) + 'ts'
|
|
})
|
|
}
|
|
|
|
export async function run(fileNames: string[], options: ts.CompilerOptions): Promise<string[]> {
|
|
options.listEmittedFiles = true
|
|
const program = ts.createProgram(fileNames, options)
|
|
|
|
const emitResult = program.emit()
|
|
|
|
const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
|
|
|
|
allDiagnostics.forEach(diagnostic => {
|
|
if (!diagnostic.file) {
|
|
console.log(diagnostic)
|
|
}
|
|
const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start)
|
|
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
|
|
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`)
|
|
})
|
|
|
|
if (emitResult.emitSkipped) {
|
|
throw new Error('Typescript compilation failed')
|
|
}
|
|
|
|
return emitResult.emittedFiles.filter(filename => filename.endsWith('.js'))
|
|
}
|
|
|
|
/*
|
|
* based on rootFileNames returns list of all related (e.g. imported) source files
|
|
*/
|
|
export function getSourceFiles(
|
|
rootFileNames: string[],
|
|
options: ts.CompilerOptions
|
|
): string[] {
|
|
const program = ts.createProgram(rootFileNames, options)
|
|
const programmFiles = program.getSourceFiles()
|
|
.map(file => file.fileName)
|
|
.filter(file => {
|
|
return file.split(path.sep).indexOf('node_modules') < 0
|
|
})
|
|
return programmFiles
|
|
}
|
|
|
|
export function getTypescriptConfig(
|
|
cwd: string,
|
|
logger?: { log: (str: string) => void }
|
|
): ts.CompilerOptions {
|
|
const configFilePath = path.join(cwd, 'tsconfig.json')
|
|
|
|
if (fs.existsSync(configFilePath)) {
|
|
|
|
const configFileText = fs.readFileSync(configFilePath).toString()
|
|
const result = ts.parseConfigFileTextToJson(configFilePath, configFileText)
|
|
if (result.error) {
|
|
throw new Error(JSON.stringify(result.error))
|
|
}
|
|
|
|
const configParseResult = ts.parseJsonConfigFileContent(result.config, ts.sys, path.dirname(configFilePath))
|
|
if (configParseResult.errors.length > 0) {
|
|
throw new Error(JSON.stringify(configParseResult.errors))
|
|
}
|
|
|
|
if (logger) {
|
|
logger.log(`Using local tsconfig.json`)
|
|
}
|
|
|
|
// disallow overrriding rootDir
|
|
if (configParseResult.options.rootDir && path.resolve(configParseResult.options.rootDir) !== path.resolve(cwd) && logger) {
|
|
logger.log('Warning: "rootDir" from local tsconfig.json is overriden')
|
|
}
|
|
configParseResult.options.rootDir = cwd
|
|
|
|
return configParseResult.options
|
|
}
|
|
|
|
return makeDefaultTypescriptConfig()
|
|
}
|