@longzai-intelligence-oxlint/architecture-domain-plugin 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";import{existsSync as n}from"node:fs";import{join as r}from"node:path";const i=[{pattern:/^(?!create)[A-Za-z]+Repository(Drizzle|Memory|Sqlite|Mysql)$/,message:`具体仓储实现类应从 typeorm 入口导出`},{pattern:/[A-Z_]+_REPOSITORY_TOKEN$/,message:`Repository Token 不应从主入口导出`},{pattern:/^(?!create)[A-Za-z]*Table$/,message:`数据库表定义不应从主入口导出`},{pattern:/[A-Za-z]+OrmEntity$/,message:`ORM 实体应从 typeorm 入口导出`},{pattern:/[A-Z_]+_ORM_ENTITIES$/,message:`实体集合应从 typeorm 入口导出`},{pattern:/[A-Za-z]+OrmMapper$/,message:`ORM Mapper 不应从主入口导出`}];function a(e){let t=e.replace(/\\/g,`/`);return!!(t.includes(`/domains/`)&&t.endsWith(`/src/index.ts`)||t.includes(`/domains/`)&&t.endsWith(`/index.ts`)&&(t.includes(`/domain/`)||t.includes(`/application/`)||t.includes(`/infrastructure/`)))}function o(e){let t=e.replace(/\\/g,`/`);return a(t)&&t.split(`/`).length>6}function s(e){if(/^create|^make|^build/.test(e))return null;for(let{pattern:t,message:n}of i)if(t.test(e))return n;return null}function c(e){return e.exported.type===`Identifier`?e.exported.name:e.exported.type===`Literal`&&typeof e.exported.value==`string`?e.exported.value:null}function l(e,t){for(let n of e){if(n.type!==`ExportSpecifier`)continue;let e=c(n);if(!e)continue;let r=s(e);r&&t.report({node:n,message:`禁止导出 "${e}"。${r}。`})}}function u(e,t){if(e.declarations.length!==0){for(let n of e.declarations)if(n.id.type===`Identifier`){let e=n.id.name,r=s(e);r&&t.report({node:n,message:`禁止导出 "${e}"。${r}。`})}}}const d=e({meta:{type:`problem`,docs:{description:`检查 Domain 包入口文件的导出是否符合规范`}},createOnce(e){return{before(){let t=e.filename;if(!a(t))return!1},ExportAllDeclaration(t){e.report({node:t,message:`禁止使用 export * 通配符导出。请使用显式导出,明确导出内容。`})},ExportNamedDeclaration(t){o(e.filename)||(t.specifiers&&l(t.specifiers,e),t.declaration?.type===`VariableDeclaration`&&u(t.declaration,e))}}}}),f=[`data-source.ts`,`data-source.config.ts`,`database.module.ts`,`database.ts`,`database.config.ts`,`database.service.ts`];function p(e){return f.some(t=>e===t||e.endsWith(t))}function m(e){return e.replace(/\\/g,`/`).includes(`/domains/`)}const h=e({meta:{type:`problem`,docs:{description:`检查 Domain 包中的 TypeORM 相关导入是否符合规范`}},createOnce(e){return{before(){let t=e.filename;if(!m(t))return!1},ImportDeclaration(t){let n=t.source.type===`Literal`&&typeof t.source.value==`string`?t.source.value:null;if(!n)return;let r=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;/\/typeorm$/.test(n)&&!p(r)&&e.report({node:t,message:`禁止从 TypeORM 入口 "${n}" 导入。只有 DataSource 文件允许导入 TypeORM 入口。`}),/\/infrastructure\//.test(n)&&e.report({node:t,message:`禁止从 Infrastructure 层深度导入 "${n}"。Domain 层应通过 Contract 包的 Port 接口访问基础设施。`})}}}}),g=[{name:`apps`,severity:`error`,description:`应用层目录`},{name:`domains`,severity:`error`,description:`领域层目录`},{name:`packages`,severity:`error`,description:`技术层目录`},{name:`infrastructure`,severity:`warn`,description:`基础设施层目录`},{name:`templates`,severity:`warn`,description:`模板层目录`},{name:`docs`,severity:`warn`,description:`文档层目录`}];function _(e){return typeof e==`object`&&!!e&&`directories`in e}function v(e,t){
|
|
1
|
+
import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";import{existsSync as n}from"node:fs";import{join as r}from"node:path";const i=[{pattern:/^(?!create)[A-Za-z]+Repository(Drizzle|Memory|Sqlite|Mysql)$/,message:`具体仓储实现类应从 typeorm 入口导出`},{pattern:/[A-Z_]+_REPOSITORY_TOKEN$/,message:`Repository Token 不应从主入口导出`},{pattern:/^(?!create)[A-Za-z]*Table$/,message:`数据库表定义不应从主入口导出`},{pattern:/[A-Za-z]+OrmEntity$/,message:`ORM 实体应从 typeorm 入口导出`},{pattern:/[A-Z_]+_ORM_ENTITIES$/,message:`实体集合应从 typeorm 入口导出`},{pattern:/[A-Za-z]+OrmMapper$/,message:`ORM Mapper 不应从主入口导出`}];function a(e){let t=e.replace(/\\/g,`/`);return!!(t.includes(`/domains/`)&&t.endsWith(`/src/index.ts`)||t.includes(`/domains/`)&&t.endsWith(`/index.ts`)&&(t.includes(`/domain/`)||t.includes(`/application/`)||t.includes(`/infrastructure/`)))}function o(e){let t=e.replace(/\\/g,`/`);return a(t)&&t.split(`/`).length>6}function s(e){if(/^create|^make|^build/.test(e))return null;for(let{pattern:t,message:n}of i)if(t.test(e))return n;return null}function c(e){return e.exported.type===`Identifier`?e.exported.name:e.exported.type===`Literal`&&typeof e.exported.value==`string`?e.exported.value:null}function l(e,t){for(let n of e){if(n.type!==`ExportSpecifier`)continue;let e=c(n);if(!e)continue;let r=s(e);r&&t.report({node:n,message:`禁止导出 "${e}"。${r}。`})}}function u(e,t){if(e.declarations.length!==0){for(let n of e.declarations)if(n.id.type===`Identifier`){let e=n.id.name,r=s(e);r&&t.report({node:n,message:`禁止导出 "${e}"。${r}。`})}}}const d=e({meta:{type:`problem`,docs:{description:`检查 Domain 包入口文件的导出是否符合规范`}},createOnce(e){return{before(){let t=e.filename;if(!a(t))return!1},ExportAllDeclaration(t){e.report({node:t,message:`禁止使用 export * 通配符导出。请使用显式导出,明确导出内容。`})},ExportNamedDeclaration(t){o(e.filename)||(t.specifiers&&l(t.specifiers,e),t.declaration?.type===`VariableDeclaration`&&u(t.declaration,e))}}}}),f=[`data-source.ts`,`data-source.config.ts`,`database.module.ts`,`database.ts`,`database.config.ts`,`database.service.ts`];function p(e){return f.some(t=>e===t||e.endsWith(t))}function m(e){return e.replace(/\\/g,`/`).includes(`/domains/`)}const h=e({meta:{type:`problem`,docs:{description:`检查 Domain 包中的 TypeORM 相关导入是否符合规范`}},createOnce(e){return{before(){let t=e.filename;if(!m(t))return!1},ImportDeclaration(t){let n=t.source.type===`Literal`&&typeof t.source.value==`string`?t.source.value:null;if(!n)return;let r=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;/\/typeorm$/.test(n)&&!p(r)&&e.report({node:t,message:`禁止从 TypeORM 入口 "${n}" 导入。只有 DataSource 文件允许导入 TypeORM 入口。`}),/\/infrastructure\//.test(n)&&e.report({node:t,message:`禁止从 Infrastructure 层深度导入 "${n}"。Domain 层应通过 Contract 包的 Port 接口访问基础设施。`})}}}}),g=[{name:`apps`,severity:`error`,description:`应用层目录`},{name:`domains`,severity:`error`,description:`领域层目录`},{name:`packages`,severity:`error`,description:`技术层目录`},{name:`infrastructure`,severity:`warn`,description:`基础设施层目录`},{name:`templates`,severity:`warn`,description:`模板层目录`},{name:`docs`,severity:`warn`,description:`文档层目录`}];function _(e){return typeof e==`object`&&!!e&&`directories`in e}function v(e,t){let i=r(e,t,`README.md`);return n(i)}const y=new Set,b=e({meta:{type:`problem`,docs:{description:`检查分层目录是否包含 README.md 文件`}},createOnce(e){let t=null;function i(){if(t===null){let n=e.options?.[0],r=n&&typeof n==`object`?n:{};t=_(r)&&Array.isArray(r.directories)?r.directories:g}return t}return{before(){i()},Program(t){let a=e.cwd;if(y.has(a))return;y.add(a);let o=i();for(let i of o){let o=i.name,s=r(a,o);n(s)&&(v(a,o)||((i.severity||`error`)===`warn`?e.report({node:t,message:`分层目录 "${o}" (${i.description??o}) 建议添加 README.md 文件,阐明该层职责。`}):e.report({node:t,message:`分层目录 "${o}" (${i.description??o}) 缺少 README.md 文件。分层目录必须包含 README.md 文件,阐明该层职责。`})))}}}}});function x(e){let t=e.replace(/\\/g,`/`);return t.endsWith(`.port-adapter.ts`)||t.endsWith(`.port.adapter.ts`)}function S(e){let t=e.replace(/\\/g,`/`);return t.includes(`/entities/`)&&t.endsWith(`.entity.ts`)&&t.includes(`/domain/`)&&t.includes(`/implementation/`)}function C(e){if(e.type!==`ClassDeclaration`||!(`implements`in e)||!Array.isArray(e.implements))return null;let t=e.implements;function n(e){return typeof e==`object`&&!!e&&`expression`in e}return t.every(n)?t:null}function w(e){if(`accessibility`in e){let t=e.accessibility;if(typeof t==`string`)return t}}function T(e){let t=C(e);if(!t)return!1;for(let e of t)if(e.expression.type===`Identifier`&&e.expression.name.endsWith(`Port`))return!0;return!1}const E=e({meta:{type:`problem`,docs:{description:`检查 PortAdapter 实现是否符合规范`}},createOnce(e){return{ClassDeclaration(t){x(e.filename)&&(T(t)||e.report({node:t,message:`PortAdapter 类必须实现 Port 接口。请添加 implements 语句,如 class XxxPortAdapter implements IXxxPort。`}))},MethodDefinition(t){if(!x(e.filename)||t.kind===`constructor`)return;let n=w(t);if(n===`private`||n===`protected`)return;let r=e.sourceCode.getText(t).toString();!r.includes(`Result`)&&!r.includes(`Promise<Result`)&&t.key.type===`Identifier`&&e.report({node:t,message:`PortAdapter 公共方法 "${t.key.name}" 必须返回 Result 或 Promise<Result> 类型。`})},ImportDeclaration(t){if(!S(e.filename))return;let n=t.source.type===`Literal`&&typeof t.source.value==`string`?t.source.value:null;if(!(!n||!n.endsWith(`-contract`)))for(let n of t.specifiers){if(n.type!==`ImportSpecifier`)continue;let t=n.imported.type===`Identifier`?n.imported.name:null;t&&(t.endsWith(`Props`)||t.endsWith(`Input`))&&e.report({node:n,message:`Entity 文件禁止从 Contract 包导入 "${t}"。Props 和 Input 类型属于 Contract 层,Entity 应使用自己的内部类型。`})}}}}}),D=new Set([`DOMAIN_ENTITIES`,`ALL_ENTITIES`,`ENTITIES`,`ORM_ENTITIES`]);function O(e){let t=e.replace(/\\/g,`/`);return t.includes(`/domains/`)&&t.includes(`/implementation/src/typeorm.ts`)}function k(e){return e.replace(/\\/g,`/`).match(/\/domains\/([^/]+)\/implementation\/src\/typeorm\.ts$/)?.[1]?.toUpperCase()??null}function A(e,t){let n=e.length,r=t.length,i=Array.from({length:r+1},(e,t)=>t);for(let a=1;a<=n;a++){let n=[a];for(let o=1;o<=r;o++)n[o]=e.charAt(a-1)===t.charAt(o-1)?i[o-1]??0:1+Math.min(i[o]??0,n[o-1]??0,i[o-1]??0);i=[...n]}return i[r]??0}function j(e,t){return e===t?null:e.endsWith(`_ENTITIES`)&&!e.endsWith(`_ORM_ENTITIES`)?`导出名称 "${e}" 缺少 ORM 前缀。应使用 "${t}" 而非 "${e.replace(`_ORM_ENTITIES`,`_ENTITIES`)}"`:D.has(e)?`导出名称 "${e}" 使用了通用名称。应使用具体的域名称 "${t}"`:A(e,t)<=2?`导出名称 "${e}" 可能是 "${t}" 的拼写错误`:e.toUpperCase()===t.toUpperCase()?`导出名称 "${e}" 大小写不正确。应使用 "${t}"`:`导出名称 "${e}" 不符合命名规范。应使用 "${t}"`}const M={"domain-export":d,"domain-typeorm-import":h,"layer-readme-required":b,"require-domain-entities-naming":e({meta:{type:`problem`,docs:{description:`检查 Domain 实体集合的导出命名是否符合规范`}},createOnce(e){return{before(){let t=e.filename;if(!O(t))return!1},ExportNamedDeclaration(t){let n=k(e.filename);if(!n)return;let r=`${n}_ORM_ENTITIES`;if(t.specifiers)for(let n of t.specifiers){if(n.type!==`ExportSpecifier`)continue;let t=n.exported.type===`Identifier`?n.exported.name:null;if(!t||!t.endsWith(`_ENTITIES`)&&!t.endsWith(`_ORM_ENTITIES`))continue;let i=j(t,r);i&&e.report({node:n,message:i})}if(t.declaration?.type===`VariableDeclaration`)for(let n of t.declaration.declarations){if(n.id.type!==`Identifier`)continue;let t=n.id.name;if(!t.endsWith(`_ENTITIES`)&&!t.endsWith(`_ORM_ENTITIES`))continue;let i=j(t,r);i&&e.report({node:n,message:i})}}}}}),"port-adapter-implementation":E},N=t({meta:{name:`@longzai-intelligence-oxlint/architecture-domain-plugin`},rules:M});export{N as architectureDomainPlugin,N as default,M as domainRules};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-oxlint/architecture-domain-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"typecheck:test": "lzi-tsgo typecheck tsconfig/test.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@longzai-intelligence-oxlint/core": "0.1.
|
|
34
|
+
"@longzai-intelligence-oxlint/core": "0.1.13",
|
|
35
35
|
"@oxlint/plugins": "^1.74.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@longzai-intelligence-oxlint/testing": "0.1.
|
|
38
|
+
"@longzai-intelligence-oxlint/testing": "0.1.13",
|
|
39
39
|
"@vitest/coverage-v8": "^4.1.10",
|
|
40
40
|
"typescript": "^6.0.3"
|
|
41
41
|
},
|