deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
119
dev-packages/private-eslint-plugin/rules/runtime-import-check.js
Normal file
119
dev-packages/private-eslint-plugin/rules/runtime-import-check.js
Normal file
@@ -0,0 +1,119 @@
|
||||
// @ts-check
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2021 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Runtime-specific folders according to our coding guidelines.
|
||||
*/
|
||||
const folders = {
|
||||
common: 'common',
|
||||
browser: 'browser',
|
||||
node: 'node',
|
||||
electronCommon: 'electron-common',
|
||||
electronBrowser: 'electron-browser',
|
||||
electronNode: 'electron-node',
|
||||
electronMain: 'electron-main',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {object} ImportRule
|
||||
* @property {string[]} allowed
|
||||
* @property {string[]} restricted
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} src
|
||||
* @param {string[]} allowedFolders
|
||||
* @returns {[string, ImportRule]}
|
||||
*/
|
||||
function allow(src, allowedFolders) {
|
||||
const allowed = [src, ...allowedFolders];
|
||||
const restricted = Object.values(folders).filter(folder => !allowed.includes(folder));
|
||||
return [src, { allowed, restricted }];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of folders to the list of allowed/restricted folders to import from.
|
||||
* @type {[string, ImportRule][]}
|
||||
*/
|
||||
const importRuleMapping = [
|
||||
allow(folders.common, []),
|
||||
allow(folders.browser, [folders.common]),
|
||||
allow(folders.node, [folders.common]),
|
||||
allow(folders.electronCommon, [folders.common]),
|
||||
allow(folders.electronBrowser, [folders.electronCommon, folders.browser, folders.common]),
|
||||
allow(folders.electronNode, [folders.electronCommon, folders.node, folders.common]),
|
||||
allow(folders.electronMain, [folders.electronCommon, folders.node, folders.common]),
|
||||
];
|
||||
|
||||
/** @type {import('eslint').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
fixable: 'code',
|
||||
docs: {
|
||||
description: 'prevent imports from folders meant for incompatible runtimes.',
|
||||
url: 'https://github.com/eclipse-theia/theia/tree/master/doc/code-organization.md'
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
let relativeFilePath = path.relative(context.getCwd(), context.getFilename());
|
||||
// Normalize the path so we only deal with forward slashes.
|
||||
if (process.platform === 'win32') {
|
||||
relativeFilePath = relativeFilePath.replace(/\\/g, '/');
|
||||
}
|
||||
// Search for a folder following our naming conventions, keep the left-most match.
|
||||
// e.g. `src/electron-node/browser/node/...` should match `electron-node`
|
||||
let lowestIndex = Infinity;
|
||||
/** @type {ImportRule | undefined} */
|
||||
let matchedImportRule;
|
||||
/** @type {string | undefined} */
|
||||
let matchedFolder;
|
||||
for (const [folder, importRule] of importRuleMapping) {
|
||||
const index = relativeFilePath.indexOf(`/${folder}/`);
|
||||
if (index !== -1 && index < lowestIndex) {
|
||||
matchedImportRule = importRule;
|
||||
matchedFolder = folder;
|
||||
lowestIndex = index;
|
||||
}
|
||||
}
|
||||
// File doesn't follow our naming convention so we'll bail now.
|
||||
if (matchedFolder === undefined) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
checkModuleImport(node.source);
|
||||
},
|
||||
TSExternalModuleReference(node) {
|
||||
checkModuleImport(node.expression);
|
||||
},
|
||||
};
|
||||
function checkModuleImport(node) {
|
||||
const module = /** @type {string} */(node.value);
|
||||
if (matchedImportRule.restricted.some(restricted => module.includes(`/${restricted}/`) || module.endsWith(`/${restricted}`))) {
|
||||
context.report({
|
||||
node,
|
||||
message: `'${module}' cannot be imported in '${matchedFolder}', only '${matchedImportRule.allowed.join(', ')}' ${matchedImportRule.allowed.length === 1 ? 'is' : 'are'} allowed.`
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user