Add TypeScript support (#994)
This commit is contained in:
Родитель
7d708716e3
Коммит
03274e2bbe
|
@ -6,8 +6,9 @@
|
|||
import { parseError } from 'vscode-azureextensionui';
|
||||
import { localize } from "./localize";
|
||||
|
||||
interface IFunctionJson {
|
||||
export interface IFunctionJson {
|
||||
disabled?: boolean;
|
||||
scriptFile?: string;
|
||||
bindings: IFunctionBinding[];
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as fse from 'fs-extra';
|
|||
import * as path from 'path';
|
||||
import { IAzureUserInput } from 'vscode-azureextensionui';
|
||||
import { ProjectLanguage } from '../../constants';
|
||||
import { IFunctionJson } from '../../FunctionConfig';
|
||||
import { localize } from "../../localize";
|
||||
import { IScriptFunctionTemplate } from '../../templates/parseScriptTemplates';
|
||||
import * as fsUtil from '../../utils/fs';
|
||||
|
@ -42,8 +43,8 @@ export function getScriptFileNameFromLanguage(language: string): string | undefi
|
|||
*/
|
||||
export class ScriptFunctionCreator extends FunctionCreatorBase {
|
||||
protected _template: IScriptFunctionTemplate;
|
||||
protected _functionName: string;
|
||||
private _language: string;
|
||||
private _functionName: string;
|
||||
|
||||
constructor(functionAppPath: string, template: IScriptFunctionTemplate, language: string) {
|
||||
super(functionAppPath, template);
|
||||
|
@ -74,7 +75,13 @@ export class ScriptFunctionCreator extends FunctionCreatorBase {
|
|||
for (const key of Object.keys(userSettings)) {
|
||||
this._template.functionConfig.inBinding[key] = userSettings[key];
|
||||
}
|
||||
await fsUtil.writeFormattedJson(path.join(functionPath, 'function.json'), this._template.functionConfig.functionJson);
|
||||
|
||||
const functionJson: IFunctionJson = this._template.functionConfig.functionJson;
|
||||
if (this.editFunctionJson) {
|
||||
await this.editFunctionJson(functionJson);
|
||||
}
|
||||
|
||||
await fsUtil.writeFormattedJson(path.join(functionPath, 'function.json'), functionJson);
|
||||
|
||||
const mainFileName: string | undefined = getScriptFileNameFromLanguage(this._language);
|
||||
if (mainFileName) {
|
||||
|
@ -84,6 +91,8 @@ export class ScriptFunctionCreator extends FunctionCreatorBase {
|
|||
}
|
||||
}
|
||||
|
||||
protected editFunctionJson?(functionJson: IFunctionJson): Promise<void>;
|
||||
|
||||
private validateTemplateName(name: string | undefined): string | undefined {
|
||||
if (!name) {
|
||||
return localize('azFunc.emptyTemplateNameError', 'The template name cannot be empty.');
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { tsConfigFileName, tsDefaultOutDir } from '../../constants';
|
||||
import { IFunctionJson } from '../../FunctionConfig';
|
||||
import { ScriptFunctionCreator } from './ScriptFunctionCreator';
|
||||
|
||||
export class TypeScriptFunctionCreator extends ScriptFunctionCreator {
|
||||
protected async editFunctionJson(functionJson: IFunctionJson): Promise<void> {
|
||||
let outDir: string = tsDefaultOutDir;
|
||||
try {
|
||||
const tsconfigPath: string = path.join(this._functionAppPath, tsConfigFileName);
|
||||
// tslint:disable-next-line:no-unsafe-any
|
||||
outDir = (await fse.readJSON(tsconfigPath)).compilerOptions.outDir;
|
||||
} catch {
|
||||
// ignore and use default outDir
|
||||
}
|
||||
|
||||
functionJson.scriptFile = path.join('..', outDir, this._functionName, 'index.js');
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import { CSharpFunctionCreator } from './CSharpFunctionCreator';
|
|||
import { FunctionCreatorBase } from './FunctionCreatorBase';
|
||||
import { JavaFunctionCreator } from './JavaFunctionCreator';
|
||||
import { ScriptFunctionCreator } from './ScriptFunctionCreator';
|
||||
import { TypeScriptFunctionCreator } from './TypeScriptFunctionCreator';
|
||||
|
||||
async function promptForSetting(actionContext: IActionContext, localSettingsPath: string, setting: IFunctionSetting): Promise<string> {
|
||||
if (setting.resourceType !== undefined) {
|
||||
|
@ -68,7 +69,7 @@ async function promptForStringSetting(setting: IFunctionSetting): Promise<string
|
|||
return await ext.ui.showInputBox(options);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:max-func-body-length
|
||||
// tslint:disable-next-line:max-func-body-length cyclomatic-complexity
|
||||
export async function createFunction(
|
||||
actionContext: IActionContext,
|
||||
functionAppPath?: string,
|
||||
|
@ -144,6 +145,9 @@ export async function createFunction(
|
|||
case ProjectLanguage.CSharp:
|
||||
functionCreator = new CSharpFunctionCreator(functionAppPath, template);
|
||||
break;
|
||||
case ProjectLanguage.TypeScript:
|
||||
functionCreator = new TypeScriptFunctionCreator(functionAppPath, <IScriptFunctionTemplate>template, language);
|
||||
break;
|
||||
default:
|
||||
functionCreator = new ScriptFunctionCreator(functionAppPath, <IScriptFunctionTemplate>template, language);
|
||||
break;
|
||||
|
|
|
@ -4,38 +4,105 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fse from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { func, funcWatchProblemMatcher, gitignoreFileName, hostFileName, hostStartCommand, localSettingsFileName, ProjectRuntime, proxiesFileName, TemplateFilter } from '../../constants';
|
||||
import { ILocalAppSettings } from '../../LocalAppSettings';
|
||||
import { confirmOverwriteFile, writeFormattedJson } from "../../utils/fs";
|
||||
import { ProjectCreatorBase } from './ProjectCreatorBase';
|
||||
|
||||
// https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
// tslint:disable-next-line:no-multiline-string
|
||||
const gitignore: string = `bin
|
||||
const gitignore: string = `# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Azure Functions artifacts
|
||||
bin
|
||||
obj
|
||||
csx
|
||||
.vs
|
||||
edge
|
||||
Publish
|
||||
|
||||
*.user
|
||||
*.suo
|
||||
*.cscfg
|
||||
*.Cache
|
||||
project.lock.json
|
||||
|
||||
/packages
|
||||
/TestResults
|
||||
|
||||
/tools/NuGet.exe
|
||||
/App_Data
|
||||
/secrets
|
||||
/data
|
||||
.secrets
|
||||
appsettings.json
|
||||
local.settings.json
|
||||
|
||||
node_modules
|
||||
# TypeScript output
|
||||
dist
|
||||
out
|
||||
`;
|
||||
|
||||
/**
|
||||
|
@ -47,6 +114,8 @@ export class ScriptProjectCreatorBase extends ProjectCreatorBase {
|
|||
public readonly templateFilter: TemplateFilter = TemplateFilter.All;
|
||||
public readonly functionsWorkerRuntime: string | undefined;
|
||||
|
||||
protected funcignore: string[] = ['.git*', '.vscode', 'local.settings.json', 'test'];
|
||||
|
||||
public getTasksJson(): {} {
|
||||
return {
|
||||
version: '2.0.0',
|
||||
|
@ -101,6 +170,11 @@ export class ScriptProjectCreatorBase extends ProjectCreatorBase {
|
|||
if (await confirmOverwriteFile(gitignorePath)) {
|
||||
await fse.writeFile(gitignorePath, gitignore);
|
||||
}
|
||||
|
||||
const funcIgnorePath: string = path.join(this.functionAppPath, '.funcignore');
|
||||
if (await confirmOverwriteFile(funcIgnorePath)) {
|
||||
await fse.writeFile(funcIgnorePath, this.funcignore.sort().join(os.EOL));
|
||||
}
|
||||
}
|
||||
|
||||
public async onInitProjectForVSCode(): Promise<void> {
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { IActionContext } from 'vscode-azureextensionui';
|
||||
import { extInstallTaskName, func, funcWatchProblemMatcher, hostStartCommand, ProjectRuntime, tsConfigFileName, tsDefaultOutDir } from '../../constants';
|
||||
import { confirmOverwriteFile, writeFormattedJson } from '../../utils/fs';
|
||||
import { JavaScriptProjectCreator } from "./JavaScriptProjectCreator";
|
||||
|
||||
const pruneTaskLabel: string = 'prune';
|
||||
|
||||
export class TypeScriptProjectCreator extends JavaScriptProjectCreator {
|
||||
public readonly preDeployTask: string = pruneTaskLabel;
|
||||
|
||||
constructor(functionAppPath: string, actionContext: IActionContext, runtime: ProjectRuntime | undefined) {
|
||||
super(functionAppPath, actionContext, runtime);
|
||||
this.funcignore = this.funcignore.concat('*.js.map', '*.ts', 'tsconfig.json');
|
||||
}
|
||||
|
||||
public async onCreateNewProject(): Promise<void> {
|
||||
await super.onCreateNewProject();
|
||||
|
||||
const tsconfigPath: string = path.join(this.functionAppPath, tsConfigFileName);
|
||||
if (await confirmOverwriteFile(tsconfigPath)) {
|
||||
const tsconfigJson: {} = {
|
||||
compilerOptions: {
|
||||
module: 'commonjs',
|
||||
target: 'es6',
|
||||
outDir: tsDefaultOutDir,
|
||||
rootDir: '.',
|
||||
sourceMap: true,
|
||||
strict: false
|
||||
}
|
||||
};
|
||||
await writeFormattedJson(tsconfigPath, tsconfigJson);
|
||||
}
|
||||
|
||||
const packagePath: string = path.join(this.functionAppPath, 'package.json');
|
||||
if (await confirmOverwriteFile(packagePath)) {
|
||||
const packageJson: {} = {
|
||||
name: path.basename(this.functionAppPath),
|
||||
description: '',
|
||||
version: '0.1.0',
|
||||
scripts: {
|
||||
build: 'tsc',
|
||||
watch: 'tsc -w',
|
||||
test: 'echo \"No tests yet...\"'
|
||||
},
|
||||
dependencies: {},
|
||||
devDependencies: {
|
||||
'@azure/functions': '^1.0.1-beta2',
|
||||
typescript: '^3.3.3'
|
||||
}
|
||||
};
|
||||
await writeFormattedJson(packagePath, packageJson);
|
||||
|
||||
const packageLockJson: {} = {
|
||||
name: path.basename(this.functionAppPath),
|
||||
version: '0.1.0',
|
||||
lockfileVersion: 1,
|
||||
requires: true,
|
||||
dependencies: {
|
||||
'@azure/functions': {
|
||||
version: '1.0.1-beta2',
|
||||
resolved: 'https://registry.npmjs.org/@azure/functions/-/functions-1.0.1-beta2.tgz',
|
||||
integrity: 'sha512-ewVNxU2fqSCLbLuHwwvcL2ExgYNIhaztgHQfBShM9bpCBlAufTrvqlGnsEMfYv2F+BmJrkvhcDWE7E8cDz4X0g==',
|
||||
dev: true
|
||||
},
|
||||
typescript: {
|
||||
version: '3.3.3',
|
||||
resolved: 'https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz',
|
||||
integrity: 'sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==',
|
||||
dev: true
|
||||
}
|
||||
}
|
||||
};
|
||||
const packageLockPath: string = path.join(this.functionAppPath, 'package-lock.json');
|
||||
await writeFormattedJson(packageLockPath, packageLockJson);
|
||||
}
|
||||
}
|
||||
|
||||
public getTasksJson(): {} {
|
||||
const npmInstallTaskName: string = 'npm: install';
|
||||
const npmBuildTaskName: string = 'npm: build';
|
||||
return {
|
||||
version: '2.0.0',
|
||||
tasks: [
|
||||
{
|
||||
type: func,
|
||||
command: hostStartCommand,
|
||||
problemMatcher: funcWatchProblemMatcher,
|
||||
isBackground: true,
|
||||
dependsOn: npmBuildTaskName
|
||||
},
|
||||
{
|
||||
type: 'npm',
|
||||
script: 'build',
|
||||
dependsOn: this.runtime === ProjectRuntime.v1 ? npmInstallTaskName : [extInstallTaskName, npmInstallTaskName],
|
||||
problemMatcher: '$tsc'
|
||||
},
|
||||
{
|
||||
type: 'shell',
|
||||
label: pruneTaskLabel,
|
||||
command: 'npm prune --production',
|
||||
dependsOn: npmBuildTaskName,
|
||||
problemMatcher: []
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import { JavaScriptProjectCreator } from './JavaScriptProjectCreator';
|
|||
import { ProjectCreatorBase } from './ProjectCreatorBase';
|
||||
import { PythonProjectCreator } from './PythonProjectCreator';
|
||||
import { ScriptProjectCreatorBase } from './ScriptProjectCreatorBase';
|
||||
import { TypeScriptProjectCreator } from './TypeScriptProjectCreator';
|
||||
|
||||
export async function createNewProject(
|
||||
actionContext: IActionContext,
|
||||
|
@ -46,8 +47,9 @@ export async function createNewProject(
|
|||
const previewDescription: string = localize('previewDescription', '(Preview)');
|
||||
// Only display 'supported' languages that can be debugged in VS Code
|
||||
const languagePicks: QuickPickItem[] = [
|
||||
{ label: ProjectLanguage.JavaScript, description: '' },
|
||||
{ label: ProjectLanguage.CSharp, description: '' },
|
||||
{ label: ProjectLanguage.JavaScript },
|
||||
{ label: ProjectLanguage.TypeScript },
|
||||
{ label: ProjectLanguage.CSharp },
|
||||
{ label: ProjectLanguage.Python, description: previewDescription },
|
||||
{ label: ProjectLanguage.Java, description: previewDescription }
|
||||
];
|
||||
|
@ -102,6 +104,9 @@ export function getProjectCreator(language: string, functionAppPath: string, act
|
|||
case ProjectLanguage.Python:
|
||||
projectCreatorType = PythonProjectCreator;
|
||||
break;
|
||||
case ProjectLanguage.TypeScript:
|
||||
projectCreatorType = TypeScriptProjectCreator;
|
||||
break;
|
||||
default:
|
||||
projectCreatorType = ScriptProjectCreatorBase;
|
||||
break;
|
||||
|
|
|
@ -87,3 +87,6 @@ export const funcPackCommand: string = `${func} ${packCommand}`;
|
|||
export const funcWatchProblemMatcher: string = '$func-watch';
|
||||
|
||||
export const localhost: string = '127.0.0.1';
|
||||
|
||||
export const tsDefaultOutDir: string = 'dist';
|
||||
export const tsConfigFileName: string = 'tsconfig.json';
|
||||
|
|
|
@ -59,6 +59,7 @@ export class FuncTaskProvider implements TaskProvider {
|
|||
debugProvider = this._pythonDebugProvider;
|
||||
break;
|
||||
case ProjectLanguage.JavaScript:
|
||||
case ProjectLanguage.TypeScript:
|
||||
debugProvider = this._nodeDebugProvider;
|
||||
break;
|
||||
case ProjectLanguage.Java:
|
||||
|
|
|
@ -11,7 +11,7 @@ import { FuncDebugProviderBase } from './FuncDebugProviderBase';
|
|||
export const defaultNodeDebugPort: number = 9229;
|
||||
|
||||
export const nodeDebugConfig: DebugConfiguration = {
|
||||
name: localize('attachJS', 'Attach to JavaScript Functions'),
|
||||
name: localize('attachNode', 'Attach to Node Functions'),
|
||||
type: 'node',
|
||||
request: 'attach',
|
||||
port: defaultNodeDebugPort,
|
||||
|
|
|
@ -117,7 +117,7 @@ suite('Create New Project Tests', async function (this: ISuiteCallbackContext):
|
|||
const typeScriptProject: string = 'TypeScriptProject';
|
||||
test(typeScriptProject, async () => {
|
||||
const projectPath: string = path.join(testFolderPath, typeScriptProject);
|
||||
await testCreateNewProject(projectPath, ProjectLanguage.TypeScript, true);
|
||||
await testCreateNewProject(projectPath, ProjectLanguage.TypeScript, false);
|
||||
await validateVSCodeProjectFiles(projectPath, false);
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче