Skip to content

Commit

Permalink
Merge pull request #4 from viqueen/issue/LABSET-138-import-modules-rule
Browse files Browse the repository at this point in the history
LABSET-138 import modules rule
  • Loading branch information
viqueen authored May 29, 2023
2 parents b349726 + 5dcf365 commit cd7f2d6
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 3 deletions.
25 changes: 24 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/**
* Copyright 2023 Hasnae Rehioui
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
Expand All @@ -8,7 +23,7 @@ module.exports = {
modules: true,
},
},
plugins: ['@typescript-eslint', 'import'],
plugins: ['@typescript-eslint', 'import', '@labset-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
Expand All @@ -20,6 +35,14 @@ module.exports = {
node: true,
},
rules: {
'@labset-eslint/license-notice': [
'error',
{
license: 'Apache-2.0',
copyRightYear: '2023',
copyRightName: 'Hasnae Rehioui',
},
],
'@typescript-eslint/no-unused-vars': [
'error',
{
Expand Down
15 changes: 15 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/**
* Copyright 2023 Hasnae Rehioui
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Config } from 'jest';

export default async (): Promise<Config> => {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@labset-eslint/eslint-plugin",
"version": "1.2.0",
"version": "1.3.0",
"description": "collection of eslint rules needed to ensure ts open-source packages structure is consistent",
"repository": "[email protected]:viqueen/eslint-plugin.git",
"author": "Hasnae R. <>",
Expand All @@ -21,6 +21,7 @@
"lint": "eslint src/ --ext .ts,.tsx,.js"
},
"devDependencies": {
"@labset-eslint/eslint-plugin": "^1.2.0",
"@types/eslint": "^8.40.0",
"@types/jest": "^29.5.1",
"@types/node": "^20.2.3",
Expand Down
126 changes: 126 additions & 0 deletions src/import-modules-rule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Copyright 2023 Hasnae Rehioui
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as fs from 'fs';
import path from 'path';

import { Rule } from 'eslint';
import * as ESTree from 'estree';

const handleImportDeclaration =
(context: Rule.RuleContext) =>
(node: ESTree.ImportDeclaration & Rule.NodeParentExtension) => {
const [definition] = context.options;
if (!definition) {
context.report({
node,
message: 'missing import-modules configuration'
});
return;
}
const { alias, modulesDir } = definition;
if (!alias || !modulesDir) {
context.report({
node,
message: 'invalid import-modules configuration'
});
return;
}
const importValue = node.source.value as string;
const monorepoImport = importValue.startsWith(alias);

if (!monorepoImport) return;

const patternStr = `${alias}[-]?([^/]+)/([^/]+)`;
const pattern = new RegExp(patternStr);
const matches = importValue.match(pattern);
if (matches) return;

const moduleRelative = importValue.replace(`${alias}/`, '');
const packageFile = path.resolve(
process.cwd(),
modulesDir,
moduleRelative,
'package.json'
);
const moduleFile = path.resolve(
process.cwd(),
modulesDir,
`${moduleRelative}.ts`
);

let packageName: string;
if (fs.existsSync(packageFile)) {
packageName = JSON.parse(
fs.readFileSync(packageFile).toString()
).name;
} else {
// TODO: LABSET-139 context.getFilename is deprecated, but its replacement does not work
const relative = path.relative(
path.dirname(context.getFilename()),
moduleFile
);
packageName = `./${relative.replace('.ts', '')}`;
}

context.report({
node,
messageId: 'invalidImport',
data: {
importPath: importValue,
updatedPath: packageName
},
fix: (fixer) => {
if (node.source) {
return fixer.replaceText(node.source, `'${packageName}'`);
}
return null;
}
});
};

const importModulesRule = () => {
return {
key: 'import-modules',
rule: {
meta: {
docs: {
description: 'import from monorepo module'
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
alias: { type: 'string' },
modulesDir: { type: 'string ' }
}
}
],
messages: {
invalidImport:
'Import from {{importPath}} should be replaced with {{updatedPath}}'
}
},
create(context: Rule.RuleContext): Rule.RuleListener {
return {
ImportDeclaration: handleImportDeclaration(context)
};
}
}
};
};

export { importModulesRule };
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { importModulesRule } from './import-modules-rule';
import { licenseNoticeRule } from './license-notice-rule';

const licenseNotice = licenseNoticeRule();
const importModules = importModulesRule();

const rules = {
[licenseNotice.key]: licenseNotice.rule
[licenseNotice.key]: licenseNotice.rule,
[importModules.key]: importModules.rule
};

export { rules };
2 changes: 2 additions & 0 deletions test/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// noinspection JSUnusedGlobalSymbols

export default async () => {
// ignore
};
2 changes: 2 additions & 0 deletions test/global-teardown.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// noinspection JSUnusedGlobalSymbols

export default async () => {
// ignore
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,11 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"

"@labset-eslint/eslint-plugin@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@labset-eslint/eslint-plugin/-/eslint-plugin-1.2.0.tgz#0a1a7786980a85389ecfb97fa84f0b09e31e12d7"
integrity sha512-Mz3G4wUrQ2XhmcX/BCoIiuanbHGdPqxfW5ORCTe5Kx2pG9J3lsknnxXy1FToQ7ZUy1QvGqli6yU2X+VcqHgF0g==

"@nodelib/[email protected]":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
Expand Down

0 comments on commit cd7f2d6

Please sign in to comment.