diff --git a/vscode-web-ext/dist/web/extension.js b/vscode-web-ext/dist/web/extension.js
index 2136eae..4416795 100644
--- a/vscode-web-ext/dist/web/extension.js
+++ b/vscode-web-ext/dist/web/extension.js
@@ -1,1194 +1 @@
-/******/ (() => { // webpackBootstrap
-/******/ "use strict";
-/******/ var __webpack_modules__ = ([
-/* 0 */,
-/* 1 */
-/***/ ((module) => {
-
-module.exports = require("vscode");
-
-/***/ }),
-/* 2 */
-/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
-
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.FileSystemWrapper = void 0;
-const vscode = __webpack_require__(1);
-const fileSystemWrapperBase_1 = __webpack_require__(3);
-class FileSystemWrapper extends fileSystemWrapperBase_1.FileSystemWrapperBase {
- joinPath(path1, path2) {
- return vscode.Uri.joinPath(vscode.Uri.parse(path1), path2).toString();
- }
- dirName(path1) {
- const i = path1.lastIndexOf('/');
- if (i < 0) {
- throw new Error(`Failed to extract parent folder name from path ${path1}. The path does not contain a separator.`);
- }
- return path1.substring(0, i);
- }
- async readFile(path) {
- const uri = vscode.Uri.parse(path);
- const bytes = await vscode.workspace.fs.readFile(uri);
- return new TextDecoder().decode(bytes);
- }
- async isDirectory(path) {
- const uri = vscode.Uri.parse(path);
- const stat = await vscode.workspace.fs.stat(uri);
- return stat.type === vscode.FileType.Directory;
- }
- async readDir(path) {
- const uri = vscode.Uri.parse(path);
- const files = await vscode.workspace.fs.readDirectory(uri);
- return files.map(f => f[0]);
- }
- async pathExists(path) {
- const uri = vscode.Uri.parse(path);
- try {
- const stat = await vscode.workspace.fs.stat(uri);
- return stat.type === vscode.FileType.File || stat.type === vscode.FileType.Directory;
- }
- catch (err) {
- return false;
- }
- }
-}
-exports.FileSystemWrapper = FileSystemWrapper;
-
-
-/***/ }),
-/* 3 */
-/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
-
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.FileSystemWrapperBase = void 0;
-const traverseFunctionProjectUtils_1 = __webpack_require__(4);
-const ExcludedFolders = ['node_modules', 'target', 'bin', 'obj', '.vs', '.vscode', '.env', '.python_packages', '.git', '.github'];
-class FileSystemWrapperBase {
- async readFunctionsJson(hostJsonFolder, log) {
- let functions = {};
- // Reading function.json files, in parallel
- const promises = (await this.readDir(hostJsonFolder)).map(async (functionName) => {
- const fullPath = this.joinPath(hostJsonFolder, functionName);
- const functionJsonFilePath = this.joinPath(fullPath, 'function.json');
- const isDirectory = await this.isDirectory(fullPath);
- const functionJsonExists = await this.pathExists(functionJsonFilePath);
- if (isDirectory && functionJsonExists) {
- try {
- const functionJsonString = await this.readFile(functionJsonFilePath);
- const functionJson = JSON.parse(functionJsonString);
- functions[functionName] = { bindings: functionJson.bindings, isCalledBy: [], isSignalledBy: [] };
- }
- catch (err) {
- log(`>>> Failed to parse ${functionJsonFilePath}: ${err}`);
- }
- }
- });
- await Promise.all(promises);
- return functions;
- }
- async readProxiesJson(projectFolder, log) {
- const proxiesJsonPath = this.joinPath(projectFolder, 'proxies.json');
- if (!(await this.pathExists(proxiesJsonPath))) {
- return {};
- }
- const proxiesJsonString = await this.readFile(proxiesJsonPath);
- try {
- const proxies = JSON.parse(proxiesJsonString).proxies;
- if (!proxies) {
- return {};
- }
- var notAddedToCsProjFile = false;
- if (await this.isCSharpProjectAsync(projectFolder)) {
- // Also checking that proxies.json is added to .csproj file
- const csProjFile = await this.findFileRecursivelyAsync(projectFolder, '.+\\.csproj$', true);
- const proxiesJsonEntryRegex = new RegExp(`\\s*=\\s*"proxies.json"\\s*>`);
- if (!!csProjFile && csProjFile.code && (!proxiesJsonEntryRegex.exec(csProjFile.code))) {
- notAddedToCsProjFile = true;
- }
- }
- // Also adding filePath and lineNr
- for (var proxyName in proxies) {
- const proxy = proxies[proxyName];
- proxy.filePath = proxiesJsonPath;
- if (notAddedToCsProjFile) {
- proxy.warningNotAddedToCsProjFile = true;
- }
- const proxyNameRegex = new RegExp(`"${proxyName}"\\s*:`);
- const match = proxyNameRegex.exec(proxiesJsonString);
- if (!!match) {
- proxy.pos = match.index;
- proxy.lineNr = (0, traverseFunctionProjectUtils_1.posToLineNr)(proxiesJsonString, proxy.pos);
- }
- }
- return proxies;
- }
- catch (err) {
- log(`>>> Failed to parse ${proxiesJsonPath}: ${err}`);
- return {};
- }
- }
- async isCSharpProjectAsync(projectFolder) {
- return (await this.readDir(projectFolder)).some(fn => {
- fn = fn.toLowerCase();
- return (fn.endsWith('.csproj') && fn !== 'extensions.csproj');
- });
- }
- async isFSharpProjectAsync(projectFolder) {
- return (await this.readDir(projectFolder)).some(fn => {
- fn = fn.toLowerCase();
- return fn.endsWith('.fsproj');
- });
- }
- async isJavaProjectAsync(projectFolder) {
- const javaFileMatch = await this.findFileRecursivelyAsync(projectFolder, `.+\\.java$`, false);
- return !!javaFileMatch;
- }
- async findFileRecursivelyAsync(folder, fileName, returnFileContents, pattern) {
- const fileNameRegex = typeof fileName === 'string' ? new RegExp(fileName, 'i') : fileName;
- const subFolders = [];
- for (const name of await this.readDir(folder)) {
- const fullPath = this.joinPath(folder, name);
- const isDirectory = await this.isDirectory(fullPath);
- if (!!isDirectory) {
- if (!ExcludedFolders.includes(name.toLowerCase())) {
- subFolders.push(fullPath);
- }
- }
- else if (!!fileNameRegex.exec(name)) {
- if (!pattern) {
- return {
- filePath: fullPath,
- code: returnFileContents ? (await this.readFile(fullPath)) : undefined
- };
- }
- const code = await this.readFile(fullPath);
- const match = pattern.exec(code);
- if (!!match) {
- return {
- filePath: fullPath,
- code: returnFileContents ? code : undefined,
- pos: match.index,
- length: match[0].length
- };
- }
- }
- }
- // Now recursively trying subfolders. Doing this _after_ checking the current folder.
- for (const subFolder of subFolders) {
- const result = await this.findFileRecursivelyAsync(subFolder, fileNameRegex, returnFileContents, pattern);
- if (!!result) {
- return result;
- }
- }
- return undefined;
- }
- async *findFilesRecursivelyAsync(folder, fileNameRegex) {
- for (const name of await this.readDir(folder)) {
- var fullPath = this.joinPath(folder, name);
- const isDirectory = await this.isDirectory(fullPath);
- if (!!isDirectory) {
- if (ExcludedFolders.includes(name.toLowerCase())) {
- continue;
- }
- for await (const path of this.findFilesRecursivelyAsync(fullPath, fileNameRegex)) {
- yield path;
- }
- }
- else if (!!fileNameRegex.exec(name)) {
- yield fullPath;
- }
- }
- }
- async *findFunctionsRecursivelyAsync(folder, fileNameRegex, functionAttributeRegex, functionNamePosInRegex) {
- for await (const fullPath of this.findFilesRecursivelyAsync(folder, fileNameRegex)) {
- const code = await this.readFile(fullPath);
- var match;
- while (!!(match = functionAttributeRegex.exec(code))) {
- let functionName = (0, traverseFunctionProjectUtils_1.cleanupFunctionName)(match[functionNamePosInRegex]);
- const functionAttributeEndPos = match.index + match[0].length;
- const body = (0, traverseFunctionProjectUtils_1.getCodeInBrackets)(code, functionAttributeEndPos, '{', '}', '\n');
- if (body.openBracketPos >= 0 && !!body.code) {
- yield {
- functionName,
- filePath: fullPath,
- pos: match.index,
- lineNr: (0, traverseFunctionProjectUtils_1.posToLineNr)(code, match.index),
- declarationCode: body.code.substring(0, body.openBracketPos),
- bodyCode: body.code.substring(body.openBracketPos)
- };
- }
- else {
- // Returning the rest of the file
- yield {
- functionName,
- filePath: fullPath,
- pos: match.index,
- lineNr: (0, traverseFunctionProjectUtils_1.posToLineNr)(code, match.index),
- declarationCode: code.substring(functionAttributeEndPos),
- bodyCode: code.substring(functionAttributeEndPos)
- };
- break;
- }
- }
- }
- }
-}
-exports.FileSystemWrapperBase = FileSystemWrapperBase;
-
-
-/***/ }),
-/* 4 */
-/***/ ((__unused_webpack_module, exports) => {
-
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.BindingsParser = exports.TraversalRegexes = exports.getCodeInBracketsReverse = exports.getCodeInBrackets = exports.posToLineNr = exports.mapActivitiesToOrchestrator = exports.getEventNames = exports.removeNamespace = exports.cleanupFunctionName = void 0;
-function cleanupFunctionName(name) {
- if (!name) {
- return name;
- }
- const nameofMatch = new RegExp(`nameof\\s*\\(\\s*([\\w\\.]+)\\s*\\)`).exec(name);
- if (!!nameofMatch) {
- return removeNamespace(nameofMatch[1]);
- }
- name = name.trim();
- if (name.startsWith('"')) {
- return name.replace(/^"/, '').replace(/"$/, '');
- }
- return removeNamespace(name);
-}
-exports.cleanupFunctionName = cleanupFunctionName;
-function removeNamespace(name) {
- if (!name) {
- return name;
- }
- const dotPos = name.lastIndexOf('.');
- if (dotPos >= 0) {
- name = name.substring(dotPos + 1);
- }
- return name.trim();
-}
-exports.removeNamespace = removeNamespace;
-// Tries to extract event names that this orchestrator is awaiting
-function getEventNames(orchestratorCode) {
- const result = [];
- const regex = TraversalRegexes.waitForExternalEventRegex;
- var match;
- while (!!(match = regex.exec(orchestratorCode))) {
- result.push(match[4]);
- }
- return result;
-}
-exports.getEventNames = getEventNames;
-// Tries to match orchestrator with its activities
-function mapActivitiesToOrchestrator(functions, orch, activityNames) {
- for (const activityName of activityNames) {
- // If this orchestrator seems to be calling this activity
- const regex = TraversalRegexes.getCallActivityRegex(activityName);
- if (!!regex.exec(orch.code)) {
- // Then mapping this activity to this orchestrator
- functions[activityName].isCalledBy = functions[activityName].isCalledBy ?? [];
- functions[activityName].isCalledBy.push(orch.name);
- }
- }
-}
-exports.mapActivitiesToOrchestrator = mapActivitiesToOrchestrator;
-// Primitive way of getting a line number out of symbol position
-function posToLineNr(code, pos) {
- if (!code) {
- return 0;
- }
- const lineBreaks = code.substr(0, pos).match(/(\r\n|\r|\n)/g);
- return !lineBreaks ? 1 : lineBreaks.length + 1;
-}
-exports.posToLineNr = posToLineNr;
-// Complements regex's inability to keep up with nested brackets
-function getCodeInBrackets(str, startFrom, openingBracket, closingBracket, mustHaveSymbols = '') {
- var bracketCount = 0, openBracketPos = -1, mustHaveSymbolFound = !mustHaveSymbols;
- for (var i = startFrom; i < str.length; i++) {
- switch (str[i]) {
- case openingBracket:
- if (bracketCount <= 0) {
- openBracketPos = i;
- }
- bracketCount++;
- break;
- case closingBracket:
- bracketCount--;
- if (bracketCount <= 0 && mustHaveSymbolFound) {
- return { code: str.substring(startFrom, i + 1), openBracketPos: openBracketPos - startFrom };
- }
- break;
- }
- if (bracketCount > 0 && mustHaveSymbols.includes(str[i])) {
- mustHaveSymbolFound = true;
- }
- }
- return { code: '', openBracketPos: -1 };
-}
-exports.getCodeInBrackets = getCodeInBrackets;
-// Complements regex's inability to keep up with nested brackets
-function getCodeInBracketsReverse(str, openingBracket, closingBracket) {
- var bracketCount = 0, closingBracketPos = 0;
- for (var i = str.length - 1; i >= 0; i--) {
- switch (str[i]) {
- case closingBracket:
- if (bracketCount <= 0) {
- closingBracketPos = i;
- }
- bracketCount++;
- break;
- case openingBracket:
- bracketCount--;
- if (bracketCount <= 0) {
- return { code: str.substring(0, closingBracketPos + 1), openBracketPos: i };
- }
- break;
- }
- }
- return { code: '', openBracketPos: -1 };
-}
-exports.getCodeInBracketsReverse = getCodeInBracketsReverse;
-// General-purpose regexes
-class TraversalRegexes {
- static getStartNewOrchestrationRegex(orchName) {
- return new RegExp(`(StartNew|StartNewAsync|start_new|scheduleNewOrchestrationInstance)(\\s*<[\\w\\.-\\[\\]\\<\\>,\\s]+>)?\\s*\\(\\s*(["'\`]|nameof\\s*\\(\\s*[\\w\\.-]*|[\\w\\s\\.]+\\.\\s*)${orchName}\\s*["'\\),]{1}`, 'i');
- }
- static getCallSubOrchestratorRegex(subOrchName) {
- return new RegExp(`(CallSubOrchestrator|CallSubOrchestratorWithRetry|call_sub_orchestrator)(Async)?(\\s*<[\\w\\.-\\[\\]\\<\\>,\\s]+>)?\\s*\\(\\s*(["'\`]|nameof\\s*\\(\\s*[\\w\\.-]*|[\\w\\s\\.]+\\.\\s*)${subOrchName}\\s*["'\\),]{1}`, 'i');
- }
- static getRaiseEventRegex(eventName) {
- return new RegExp(`(RaiseEvent|raise_event)(Async)?(.|\r|\n)*${eventName}`, 'i');
- }
- static getSignalEntityRegex(entityName) {
- return new RegExp(`${entityName}\\s*["'>]{1}`);
- }
- static getDotNetFunctionNameRegex(funcName) {
- return new RegExp(`FunctionName(Attribute)?\\s*\\(\\s*(nameof\\s*\\(\\s*|["'\`]|[\\w\\s\\.]+\\.\\s*)${funcName}\\s*["'\`\\)]{1}`);
- }
- static getJavaFunctionNameRegex(funcName) {
- return new RegExp(`@\\s*FunctionName\\s*\\(["\\s\\w\\.-]*${funcName}"?\\)`);
- }
- static getCallActivityRegex(activityName) {
- return new RegExp(`(CallActivity|call_activity)[\\s\\w,\\.-<>\\[\\]\\(\\)\\?]*\\([\\s\\w\\.-]*["'\`]?${activityName}\\s*["'\`\\),]{1}`, 'i');
- }
- static getClassDefinitionRegex(className) {
- return new RegExp(`class\\s*${className}`);
- }
-}
-exports.TraversalRegexes = TraversalRegexes;
-TraversalRegexes.continueAsNewRegex = new RegExp(`ContinueAsNew\\s*\\(`, 'i');
-TraversalRegexes.waitForExternalEventRegex = new RegExp(`(WaitForExternalEvent|wait_for_external_event)(<[\\s\\w,\\.-\\[\\]\\(\\)\\<\\>]+>)?\\s*\\(\\s*(nameof\\s*\\(\\s*|["'\`]|[\\w\\s\\.]+\\.\\s*)?([\\s\\w\\.-]+)\\s*["'\`\\),]{1}`, 'gi');
-// In .Net not all bindings are mentioned in function.json, so we need to analyze source code to extract them
-class BindingsParser {
- // Extracts additional bindings info from C#/F# source code
- static tryExtractBindings(funcCode) {
- const result = [];
- if (!funcCode) {
- return result;
- }
- const regex = this.bindingAttributeRegex;
- var match;
- while (!!(match = regex.exec(funcCode))) {
- const isReturn = !!match[3];
- let attributeName = match[4];
- if (attributeName.endsWith(`Attribute`)) {
- attributeName = attributeName.substring(0, attributeName.length - `Attribute`.length);
- }
- const attributeCodeStartIndex = match.index + match[0].length;
- const attributeCode = getCodeInBrackets(funcCode, attributeCodeStartIndex, '(', ')', '').code;
- this.isOutRegex.lastIndex = attributeCodeStartIndex + attributeCode.length;
- const isOut = !!this.isOutRegex.exec(funcCode);
- switch (attributeName) {
- case 'BlobInput':
- case 'BlobOutput':
- case 'Blob': {
- const binding = {
- type: 'blob',
- direction: attributeName === 'Blob' ? (isReturn || isOut ? 'out' : 'in') : (attributeName === 'BlobOutput' ? 'out' : 'in')
- };
- const paramsMatch = this.blobParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.path = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'BlobTrigger': {
- const binding = { type: 'blobTrigger' };
- const paramsMatch = this.blobParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.path = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'TableInput':
- case 'TableOutput':
- case 'Table': {
- const binding = {
- type: 'table',
- direction: attributeName === 'Table' ? (isReturn || isOut ? 'out' : 'in') : (attributeName === 'TableOutput' ? 'out' : 'in')
- };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.tableName = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'CosmosDBInput':
- case 'CosmosDBOutput':
- case 'CosmosDB': {
- const binding = {
- type: 'cosmosDB',
- direction: attributeName === 'CosmosDB' ? (isReturn || isOut ? 'out' : 'in') : (attributeName === 'CosmosDBOutput' ? 'out' : 'in')
- };
- const paramsMatch = this.cosmosDbParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.databaseName = paramsMatch[1];
- binding.collectionName = paramsMatch[3];
- }
- result.push(binding);
- break;
- }
- case 'CosmosDBTrigger': {
- const binding = { type: 'cosmosDBTrigger' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.databaseName = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'EventGrid':
- case 'EventGridOutput': {
- const binding = { type: 'eventGrid', direction: 'out' };
- const paramsMatch = this.eventGridParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.topicEndpointUri = paramsMatch[1];
- binding.topicKeySetting = paramsMatch[3];
- }
- result.push(binding);
- break;
- }
- case 'EventGridTrigger': {
- const binding = { type: 'eventGridTrigger' };
- const paramsMatch = this.eventGridParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.topicEndpointUri = paramsMatch[1];
- binding.topicKeySetting = paramsMatch[3];
- }
- result.push(binding);
- break;
- }
- case 'EventHub':
- case 'EventHubOutput': {
- const binding = { type: 'eventHub', direction: 'out' };
- const paramsMatch = this.eventHubParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.eventHubName = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'EventHubTrigger': {
- const binding = { type: 'eventHubTrigger' };
- const paramsMatch = this.eventHubParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.eventHubName = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'Kafka':
- case 'KafkaOutput': {
- const binding = { type: 'kafka', direction: 'out' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.brokerList = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'KafkaTrigger': {
- const binding = { type: 'kafkaTrigger' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.brokerList = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'Queue':
- case 'QueueOutput': {
- const binding = { type: 'queue', direction: 'out' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'QueueTrigger': {
- const binding = { type: 'queueTrigger' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'ServiceBus':
- case 'ServiceBusOutput': {
- const binding = { type: 'serviceBus', direction: 'out' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'ServiceBusTrigger':
- case 'ServiceBusQueueTrigger':
- case 'ServiceBusTopicTrigger': {
- const binding = { type: 'serviceBusTrigger' };
- const paramsMatch = this.singleParamRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[2];
- }
- result.push(binding);
- break;
- }
- case 'SignalRConnectionInfo':
- case 'SignalRConnectionInfoInput': {
- const binding = { type: 'signalRConnectionInfo', direction: 'in' };
- const paramsMatch = this.signalRConnInfoParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding.hubName = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'SignalR':
- case 'SignalROutput': {
- const binding = { type: 'signalR', direction: 'out' };
- const paramsMatch = this.signalRParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['hubName'] = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'SignalRTrigger': {
- const binding = { type: 'signalRTrigger' };
- const paramsMatch = this.signalRParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['hubName'] = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'RabbitMQ':
- case 'RabbitMQOutput': {
- const binding = { type: 'rabbitMQ', direction: 'out' };
- const paramsMatch = this.rabbitMqParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'RabbitMQTrigger': {
- const binding = { type: 'rabbitMQTrigger' };
- const paramsMatch = this.rabbitMqParamsRegex.exec(attributeCode);
- if (!!paramsMatch) {
- binding['queueName'] = paramsMatch[1];
- }
- result.push(binding);
- break;
- }
- case 'SendGrid':
- case 'SendGridOutput': {
- result.push({ type: 'sendGrid', direction: 'out' });
- break;
- }
- case 'TwilioSms': {
- result.push({ type: 'twilioSms', direction: 'out' });
- break;
- }
- case 'HttpTrigger': {
- const binding = { type: 'httpTrigger', methods: [] };
- const httpTriggerRouteMatch = this.httpTriggerRouteRegex.exec(attributeCode);
- if (!!httpTriggerRouteMatch) {
- binding.route = httpTriggerRouteMatch[1];
- }
- const lowerAttributeCode = attributeCode.toLowerCase();
- for (const httpMethod of this.httpMethods) {
- if (lowerAttributeCode.includes(`"${httpMethod}"`)) {
- binding.methods.push(httpMethod);
- }
- }
- result.push(binding);
- result.push({ type: 'http', direction: 'out' });
- break;
- }
- case 'OrchestrationTrigger':
- case 'DurableOrchestrationTrigger': {
- result.push({ type: 'orchestrationTrigger', direction: 'in' });
- break;
- }
- case 'ActivityTrigger':
- case 'DurableActivityTrigger': {
- result.push({ type: 'activityTrigger', direction: 'in' });
- break;
- }
- case 'EntityTrigger':
- case 'DurableEntityTrigger': {
- result.push({ type: 'entityTrigger', direction: 'in' });
- break;
- }
- default: {
- result.push({ type: attributeName, direction: isReturn || isOut ? 'out' : 'in' });
- break;
- }
- }
- }
- return result;
- }
- static getFunctionAttributeRegex() {
- return new RegExp(`\\[\\s*Function(Name)?(Attribute)?\\s*\\((["\\w\\s\\.\\(\\)-]+)\\)\\s*\\]`, 'g');
- }
- static getJavaFunctionAttributeRegex() {
- return new RegExp(`@\\s*FunctionName\\s*\\((["\\w\\s\\.\\(\\)-]+)\\)`, 'g');
- }
- static getFSharpFunctionAttributeRegex() {
- return new RegExp(`\\[<\\s*Function(Name)?\\s*\\((["\\w\\s\\.\\(\\)-]+)\\)`, 'g');
- }
-}
-exports.BindingsParser = BindingsParser;
-BindingsParser.bindingAttributeRegex = new RegExp(`(\\[|@)(<)?\\s*(return:)?\\s*(\\w+)`, 'g');
-BindingsParser.singleParamRegex = new RegExp(`("|nameof\\s*\\()?([\\w\\.-]+)`);
-BindingsParser.eventHubParamsRegex = new RegExp(`"([^"]+)"`);
-BindingsParser.signalRParamsRegex = new RegExp(`"([^"]+)"`);
-BindingsParser.rabbitMqParamsRegex = new RegExp(`"([^"]+)"`);
-BindingsParser.blobParamsRegex = new RegExp(`"([^"]+)"`);
-BindingsParser.cosmosDbParamsRegex = new RegExp(`"([^"]+)"(.|\r|\n)+?"([^"]+)"`);
-BindingsParser.signalRConnInfoParamsRegex = new RegExp(`"([^"]+)"`);
-BindingsParser.eventGridParamsRegex = new RegExp(`"([^"]+)"(.|\r|\n)+?"([^"]+)"`);
-BindingsParser.isOutRegex = new RegExp(`^\\s*\\]\\s*(out |ICollector|IAsyncCollector).*?(,|\\()`, 'g');
-BindingsParser.httpMethods = [`get`, `head`, `post`, `put`, `delete`, `connect`, `options`, `trace`, `patch`];
-BindingsParser.httpTriggerRouteRegex = new RegExp(`Route\\s*=\\s*"(.*)"`);
-BindingsParser.functionReturnTypeRegex = new RegExp(`public\\s*(static\\s*|async\\s*)*(Task\\s*<\\s*)?([\\w\\.]+)`);
-
-
-/***/ }),
-/* 5 */
-/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
-
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.FunctionGraphView = void 0;
-const vscode = __webpack_require__(1);
-const functionProjectParser_1 = __webpack_require__(6);
-const FileSystemWrapper_1 = __webpack_require__(2);
-// Represents the function graph view
-class FunctionGraphView {
- constructor(_context, _functionProjectUri) {
- this._context = _context;
- this._functionProjectUri = _functionProjectUri;
- // Reference to the already opened WebView with the main page
- this._webViewPanel = null;
- this._staticsFolder = vscode.Uri.joinPath(this._context.extensionUri, 'HtmlStatics');
- this._webViewPanel = this.showWebView();
- }
- // Closes this web view
- cleanup() {
- if (!!this._webViewPanel) {
- this._webViewPanel.dispose();
- }
- }
- // Opens a WebView with function graph page in it
- showWebView() {
- const title = `Functions Graph (${this._functionProjectUri.fsPath})`;
- const panel = vscode.window.createWebviewPanel(FunctionGraphView.viewType, title, vscode.ViewColumn.One, {
- retainContextWhenHidden: true,
- enableScripts: true,
- localResourceRoots: [this._staticsFolder]
- });
- const fileUri = vscode.Uri.joinPath(this._staticsFolder, 'index.html');
- vscode.workspace.fs.readFile(fileUri).then(htmlBytes => {
- let html = new TextDecoder().decode(htmlBytes);
- html = this.fixLinksToStatics(html, this._staticsFolder, panel.webview);
- html = this.embedTheme(html);
- panel.webview.html = html;
- }, err => {
- vscode.window.showErrorMessage(`az-func-as-a-graph failed. ${err.message ?? err}`);
- });
- // handle events from WebView
- panel.webview.onDidReceiveMessage(request => this.handleMessageFromWebView(panel.webview, request), undefined, this._context.subscriptions);
- return panel;
- }
- // Embeds the current color theme
- embedTheme(html) {
- if ([2, 3].includes(vscode.window.activeColorTheme.kind)) {
- return html.replace('', '');
- }
- return html;
- }
- // Does communication between code in WebView and this class
- handleMessageFromWebView(webView, request) {
- switch (request.kind) {
- case 'ShowMessage':
- vscode.window.showInformationMessage(request.data);
- return;
- case 'ShowError':
- vscode.window.showErrorMessage(`az-func-as-a-graph failed. ${request.data}`);
- return;
- case 'SaveAs':
- // Just to be extra sure...
- if (!this.looksLikeSvg(request.data)) {
- vscode.window.showErrorMessage(`Invalid data format. Save failed.`);
- return;
- }
- // Saving some file to local hard drive
- vscode.window.showSaveDialog({ defaultUri: vscode.Uri.file('func-map.svg'), filters: { 'SVG Images': ['svg'] } }).then(filePath => {
- if (!filePath) {
- return;
- }
- const bytes = new TextEncoder().encode(request.data);
- vscode.workspace.fs.writeFile(filePath, bytes).then(() => {
- vscode.window.showInformationMessage(`SVG image saved to ${filePath}`);
- }, err => {
- vscode.window.showErrorMessage(`Failed to save. ${err.message ?? err}`);
- });
- });
- return;
- case 'SaveFunctionGraphAsJson':
- if (!this._traversalResult) {
- return;
- }
- // Saving some file to local hard drive
- vscode.window.showSaveDialog({ defaultUri: vscode.Uri.file('func-map.json'), filters: { 'JSON': ['json'] } }).then(filePath => {
- if (!filePath) {
- return;
- }
- const bytes = new TextEncoder().encode(JSON.stringify(this._traversalResult, null, 3));
- vscode.workspace.fs.writeFile(filePath, bytes).then(() => {
- vscode.window.showInformationMessage(`Diagram JSON saved to ${filePath}`);
- }, err => {
- vscode.window.showErrorMessage(`Failed to save. ${err.message ?? err}`);
- });
- });
- return;
- case 'GotoFunctionCode':
- if (!this._traversalResult) {
- return;
- }
- const functionName = request.data;
- var functionOrProxy = null;
- if (functionName.startsWith('proxy.')) {
- functionOrProxy = this._traversalResult.proxies[functionName.substr(6)];
- }
- else {
- functionOrProxy = this._traversalResult.functions[functionName];
- }
- vscode.window.showTextDocument(vscode.Uri.parse(functionOrProxy.filePath)).then(ed => {
- const pos = ed.document.positionAt(!!functionOrProxy.pos ? functionOrProxy.pos : 0);
- ed.selection = new vscode.Selection(pos, pos);
- ed.revealRange(new vscode.Range(pos, pos));
- });
- return;
- case 'Refresh':
- functionProjectParser_1.FunctionProjectParser.parseFunctions(this._functionProjectUri.toString(), new FileSystemWrapper_1.FileSystemWrapper(), console.log).then(res => {
- console.log(`>>>>>> ${this._functionProjectUri}: ${Object.keys(res.functions).length} functions`);
- this._traversalResult = res;
- webView.postMessage(this._traversalResult);
- }).catch(err => {
- this._traversalResult = undefined;
- webView.postMessage(undefined);
- vscode.window.showErrorMessage(`az-func-as-a-graph failed. ${err.message ?? err}`);
- });
- return;
- }
- }
- fixLinksToStatics(originalHtml, staticsFolder, webView) {
- var resultHtml = originalHtml;
- const regex = / (href|src)="\/([0-9a-z.\/]+)"/ig;
- var match;
- while (match = regex.exec(originalHtml)) {
- const relativePath = match[2];
- const localPath = vscode.Uri.joinPath(staticsFolder, relativePath);
- const newPath = webView.asWebviewUri(localPath).toString();
- resultHtml = resultHtml.replace(`/${relativePath}`, newPath);
- }
- return resultHtml;
- }
- // Validates incoming SVG, just to be extra sure...
- looksLikeSvg(data) {
- return data.startsWith('