diff --git a/.eslintplugin/code-limited-top-functions.ts b/.eslintplugin/code-limited-top-functions.ts new file mode 100644 index 0000000000000..97eef9a6e9d78 --- /dev/null +++ b/.eslintplugin/code-limited-top-functions.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as eslint from 'eslint'; +import { dirname, relative } from 'path'; +import minimatch from 'minimatch'; + +export = new class implements eslint.Rule.RuleModule { + + readonly meta: eslint.Rule.RuleMetaData = { + messages: { + layerbreaker: 'You are only allowed to define limited top level functions.' + }, + schema: { + type: "array", + items: { + type: "object", + additionalProperties: { + type: "array", + items: { + type: "string" + } + } + } + } + }; + + create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { + let fileRelativePath = relative(dirname(__dirname), context.getFilename()); + if (!fileRelativePath.endsWith('/')) { + fileRelativePath += '/'; + } + const ruleArgs = >context.options[0]; + + const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key)); + if (!matchingKey) { + // nothing + return {}; + } + + const restrictedFunctions = ruleArgs[matchingKey]; + + return { + FunctionDeclaration: (node: any) => { + const isTopLevel = node.parent.type === 'Program'; + const functionName = node.id.name; + if (isTopLevel && !restrictedFunctions.includes(node.id.name)) { + context.report({ + node, + message: `Top-level function '${functionName}' is restricted in this file. Allowed functions are: ${restrictedFunctions.join(', ')}.` + }); + } + }, + ExportNamedDeclaration(node: any) { + if (node.declaration && node.declaration.type === 'FunctionDeclaration') { + const functionName = node.declaration.id.name; + const isTopLevel = node.parent.type === 'Program'; + if (isTopLevel && !restrictedFunctions.includes(node.declaration.id.name)) { + context.report({ + node, + message: `Top-level function '${functionName}' is restricted in this file. Allowed functions are: ${restrictedFunctions.join(', ')}.` + }); + } + } + } + } + } +}; diff --git a/.eslintrc.json b/.eslintrc.json index e5294d9351cd3..27a94df6dcce2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1203,6 +1203,15 @@ "**/*" ] } + ], + "local/code-limited-top-functions": [ + "error", + { + "src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts": [ + "webviewPreloads", + "preloadsScriptStr" + ] + } ] } }