From 78fe6aee56fd7439f2915e345cebaa8ca4943a1c Mon Sep 17 00:00:00 2001 From: viqueen Date: Mon, 29 May 2023 09:13:07 +1000 Subject: [PATCH 1/5] LABSET-138: welcome initial import modules rule --- src/import-modules-rule/index.ts | 34 ++++++++++++++++++++++++++++++++ src/index.ts | 5 ++++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/import-modules-rule/index.ts diff --git a/src/import-modules-rule/index.ts b/src/import-modules-rule/index.ts new file mode 100644 index 0000000..d5b2650 --- /dev/null +++ b/src/import-modules-rule/index.ts @@ -0,0 +1,34 @@ +import { Rule } from 'eslint'; +import * as ESTree from 'estree'; + +const handleImportDeclaration = + (_context: Rule.RuleContext) => + (_node: ESTree.ImportDeclaration & Rule.NodeParentExtension) => { + // todo + }; + +const importModulesRule = () => { + return { + key: 'import-modules', + rule: { + meta: { + docs: { + description: 'import from monorepo module' + }, + fixable: 'code', + schema: [], + messages: { + invalidImport: + 'Import from {{importPath}} should be replaced with {{updatedPath}}' + } + }, + create(context: Rule.RuleContext): Rule.RuleListener { + return { + ImportDeclaration: handleImportDeclaration(context) + }; + } + } + }; +}; + +export { importModulesRule }; diff --git a/src/index.ts b/src/index.ts index 4f51aaa..072b74f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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 }; From 424cc5519333d58a47662f14b10b9dd9f1f81a01 Mon Sep 17 00:00:00 2001 From: viqueen Date: Mon, 29 May 2023 09:14:31 +1000 Subject: [PATCH 2/5] LABSET-138: configure license notice eslint plugin --- .eslintrc.js | 25 ++++++++++++++++++++++++- jest.config.ts | 15 +++++++++++++++ package.json | 1 + src/import-modules-rule/index.ts | 15 +++++++++++++++ test/global-setup.ts | 2 ++ test/global-teardown.ts | 2 ++ yarn.lock | 5 +++++ 7 files changed, 64 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index b1637cb..4478981 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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', @@ -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', @@ -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', { diff --git a/jest.config.ts b/jest.config.ts index 260b4e9..cba1a43 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -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 => { diff --git a/package.json b/package.json index 0604ef8..2811d86 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/import-modules-rule/index.ts b/src/import-modules-rule/index.ts index d5b2650..ff7ddf3 100644 --- a/src/import-modules-rule/index.ts +++ b/src/import-modules-rule/index.ts @@ -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 { Rule } from 'eslint'; import * as ESTree from 'estree'; diff --git a/test/global-setup.ts b/test/global-setup.ts index 391935a..c6690e6 100644 --- a/test/global-setup.ts +++ b/test/global-setup.ts @@ -1,3 +1,5 @@ +// noinspection JSUnusedGlobalSymbols + export default async () => { // ignore }; diff --git a/test/global-teardown.ts b/test/global-teardown.ts index 391935a..c6690e6 100644 --- a/test/global-teardown.ts +++ b/test/global-teardown.ts @@ -1,3 +1,5 @@ +// noinspection JSUnusedGlobalSymbols + export default async () => { // ignore }; diff --git a/yarn.lock b/yarn.lock index 78a5e20..a08a546 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" From ad3c6a4b7905992a8e6c92575aade314383335b7 Mon Sep 17 00:00:00 2001 From: viqueen Date: Mon, 29 May 2023 09:34:40 +1000 Subject: [PATCH 3/5] LABSET-138: simple import modules rule, it should validate tsconfig.json but for now we just pass in config in eslintrc --- src/import-modules-rule/index.ts | 74 ++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/import-modules-rule/index.ts b/src/import-modules-rule/index.ts index ff7ddf3..9f7f1dc 100644 --- a/src/import-modules-rule/index.ts +++ b/src/import-modules-rule/index.ts @@ -13,13 +13,81 @@ * 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) => { - // todo + (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 { + const relative = path.relative( + path.dirname(context.filename), + 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 = () => { From 455ef374942fe531e237d79e41ee3ea8760be20d Mon Sep 17 00:00:00 2001 From: viqueen Date: Mon, 29 May 2023 10:01:12 +1000 Subject: [PATCH 4/5] LABSET-138: simple import modules rule to use within typescript monorepos --- src/import-modules-rule/index.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/import-modules-rule/index.ts b/src/import-modules-rule/index.ts index 9f7f1dc..8825b57 100644 --- a/src/import-modules-rule/index.ts +++ b/src/import-modules-rule/index.ts @@ -67,8 +67,9 @@ const handleImportDeclaration = 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.filename), + path.dirname(context.getFilename()), moduleFile ); packageName = `./${relative.replace('.ts', '')}`; @@ -99,7 +100,15 @@ const importModulesRule = () => { description: 'import from monorepo module' }, fixable: 'code', - schema: [], + schema: [ + { + type: 'object', + properties: { + alias: { type: 'string' }, + modulesDir: { type: 'string ' } + } + } + ], messages: { invalidImport: 'Import from {{importPath}} should be replaced with {{updatedPath}}' From 5dcf36516df28f981d006f0dcd6d1494b7500277 Mon Sep 17 00:00:00 2001 From: viqueen Date: Mon, 29 May 2023 10:01:41 +1000 Subject: [PATCH 5/5] LABSET-138: prepare for release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2811d86..af9f5bb 100644 --- a/package.json +++ b/package.json @@ -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": "git@github.com:viqueen/eslint-plugin.git", "author": "Hasnae R. <>",