@longzai-intelligence-oxlint/code-style-plugin 0.1.23 → 0.1.24
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={"@longzai-intelligence-oxlint/code-style-plugin/no-inline-type-definition":`error`,"@longzai-intelligence-oxlint/code-style-plugin/prefer-split-export-const":`off`,"@longzai-intelligence-oxlint/code-style-plugin/require-interface-naming":`off`,"@longzai-intelligence-oxlint/code-style-plugin/require-dto-naming":`error`,"@longzai-intelligence-oxlint/code-style-plugin/require-class-suffix":`error`,"@longzai-intelligence-oxlint/code-style-plugin/no-class-suffix-alias":`error`,"@longzai-intelligence-oxlint/code-style-plugin/no-console":`error`};export{e as recommended};
|
|
1
|
+
import"../rolldown-runtime-BqT_7tdF.js";const e={"@longzai-intelligence-oxlint/code-style-plugin/no-inline-type-definition":`error`,"@longzai-intelligence-oxlint/code-style-plugin/prefer-split-export-const":`off`,"@longzai-intelligence-oxlint/code-style-plugin/require-interface-naming":`off`,"@longzai-intelligence-oxlint/code-style-plugin/require-dto-naming":`error`,"@longzai-intelligence-oxlint/code-style-plugin/require-class-suffix":`error`,"@longzai-intelligence-oxlint/code-style-plugin/no-class-suffix-alias":`error`,"@longzai-intelligence-oxlint/code-style-plugin/no-console":`error`,"@longzai-intelligence-oxlint/code-style-plugin/no-handwritten-shebang":`error`};export{e as recommended};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "./rolldown-runtime-BqT_7tdF.js";
|
|
1
2
|
import * as z from "zod/mini";
|
|
2
3
|
import { hasIPrefix } from "@longzai-intelligence-oxlint/utils";
|
|
3
4
|
//#region src/rules/no-class-suffix-alias.rule.d.ts
|
|
@@ -17,6 +18,15 @@ declare const noClassSuffixAliasRule: import("@oxlint/plugins").Rule;
|
|
|
17
18
|
*/
|
|
18
19
|
declare const noConsoleRule: import("@oxlint/plugins").Rule;
|
|
19
20
|
//#endregion
|
|
21
|
+
//#region src/rules/no-handwritten-shebang.rule.d.ts
|
|
22
|
+
/**
|
|
23
|
+
* 禁止 bin 产物包入口源码手写 shebang 的门禁规则
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* 仅当所属包 bin 指向 dist 产物时报错,此时 banner 是 shebang 的唯一合法来源
|
|
27
|
+
*/
|
|
28
|
+
declare const noHandwrittenShebangRule: import("@oxlint/plugins").Rule;
|
|
29
|
+
//#endregion
|
|
20
30
|
//#region src/rules/no-inline-type-definition/utils.d.ts
|
|
21
31
|
/**
|
|
22
32
|
* 递归检查类型节点是否包含内联类型定义
|
|
@@ -242,4 +252,4 @@ declare const requireInterfaceNamingRule: import("@oxlint/plugins").Rule;
|
|
|
242
252
|
*/
|
|
243
253
|
declare const codeStylePlugin: import("@oxlint/plugins").Plugin;
|
|
244
254
|
//#endregion
|
|
245
|
-
export { SUFFIX_MAPPINGS, type SuffixMapping, codeStylePlugin, codeStylePlugin as default, getInlineTypeDescription, getParamName, hasIPrefix, hasInlineType, isDtoFile, isFunctionNode, isMethodDefinition, isTSFunctionType, isTSIntersectionType, isTSTypeLiteral, isTSUnionType, noClassSuffixAliasRule, noConsoleRule, noInlineTypeDefinitionRule, preferSplitExportConstRule, requireClassSuffixRule, requireDtoNamingRule, requireInterfaceNamingRule };
|
|
255
|
+
export { SUFFIX_MAPPINGS, type SuffixMapping, codeStylePlugin, codeStylePlugin as default, getInlineTypeDescription, getParamName, hasIPrefix, hasInlineType, isDtoFile, isFunctionNode, isMethodDefinition, isTSFunctionType, isTSIntersectionType, isTSTypeLiteral, isTSUnionType, noClassSuffixAliasRule, noConsoleRule, noHandwrittenShebangRule, noInlineTypeDefinitionRule, preferSplitExportConstRule, requireClassSuffixRule, requireDtoNamingRule, requireInterfaceNamingRule };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";import*as n from"zod/mini";import{hasIPrefix as r,isValidDtoNameCamelCase as i,isValidDtoNameUpperCase as a}from"@longzai-intelligence-oxlint/utils";function o(e){return e.endsWith(`Class`)}const s=e({meta:{type:`problem`,docs:{description:`禁止在 import 别名中使用 "Class" 后缀`}},createOnce(e){return{ImportSpecifier(t){let n=t.local.name,r=t.imported.type===`Identifier`?t.imported.name:n;n!==r&&o(n)&&e.report({node:t,message:`导入别名 "${n}" 使用了 "Class" 后缀,这是不允许的命名方式。请使用更具描述性的名称,或直接使用原始名称 "${r}"`})}}}}),c=/* @__PURE__ */ new Set([`console.log`,`console.warn`,`console.error`,`console.info`,`console.debug`,`console.trace`,`console.dir`,`console.table`]);function l(e){let t=e.callee;return t.type===`Identifier`?t.name:t.type===`MemberExpression`&&t.property.type===`Identifier`&&t.object.type===`Identifier`?`${t.object.name}.${t.property.name}`:null}const u=e({meta:{type:`problem`,docs:{description:`禁止使用 console 方法,必须使用 @longzai-intelligence/logger-preset-* 或 react-devtools(ADR 0038)`}},createOnce(e){return{CallExpression(t){if(t.type!==`CallExpression`)return;let n=l(t);n&&c.has(n)&&e.report({node:t,message:`检测到 '${n}' — 必须使用 @longzai-intelligence/logger-preset-* 代替(ADR 0038)`})}}}}),ee=n.object({type:n.literal(`TSTypeLiteral`)}),d=n.object({type:n.literal(`TSFunctionType`)}),te=n.object({type:n.literal(`TSUnionType`),types:n.array(n.unknown())}),f=n.object({type:n.literal(`TSIntersectionType`),types:n.array(n.unknown())}),p=n.object({type:n.literal(`Identifier`),name:n.string()}),m=n.object({type:n.literal(`RestElement`),argument:n.object({name:n.string()})}),h=n.union([p,m]),g=n.object({typeAnnotation:n.unknown()}),_=n.object({type:n.literal(`MethodDefinition`),key:n.object({type:n.string(),name:n.optional(n.string())}),value:n.object({params:n.optional(n.array(n.unknown())),returnType:n.optional(n.union([g,n.null()]))}),kind:n.enum([`method`,`constructor`,`get`,`set`])}),ne=n.object({returnType:g}),v=n.object({id:n.optional(n.object({name:n.optional(n.string())})),params:n.optional(n.array(n.unknown())),returnType:n.optional(n.unknown())}),y=n.object({params:n.optional(n.array(n.unknown()))});function b(e){return ee.safeParse(e).success}function x(e){return d.safeParse(e).success}function S(e){return te.safeParse(e).success}function C(e){return f.safeParse(e).success}function w(e){return h.safeParse(e).success}function T(e){if(typeof e!=`object`||!e||!(`type`in e))return!1;let t=[`FunctionDeclaration`,`FunctionExpression`,`ArrowFunctionExpression`,`MethodDefinition`],n=e.type;return typeof n==`string`&&t.includes(n)}function E(e){return _.safeParse(e).success}function D(e){return ne.safeParse(e).success}function O(e){return v.safeParse(e).success}function k(e){return y.safeParse(e).success}function A(e){return b(e)||x(e)?!0:S(e)||C(e)?e.types.some(A):!1}function j(e){return b(e)?`对象类型`:x(e)?`函数类型`:`内联类型`}function M(e){return w(e)?e.type===`Identifier`?e.name:e.type===`RestElement`?e.argument.name:null:null}function N(e,t,n,r,i,a){i?e.report({node:t,message:`参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`}):a?e.report({node:t,message:`方法 "${a}" 的参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`}):e.report({node:t,message:`参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`})}function P(e,t,n,r,i){i?e.report({node:t,message:`方法 "${i}" 的返回值使用了内联${n}定义。请将其提取为具名的 type。`}):r?e.report({node:t,message:`函数 "${r}" 的返回值使用了内联${n}定义。请将其提取为具名的 type。`}):e.report({node:t,message:`匿名函数的返回值使用了内联${n}定义。请将其提取为具名的 type。`})}function F(e,t,n,r,i){if(typeof e!=`object`||!e||!(`typeAnnotation`in e)||e.typeAnnotation===null||typeof e.typeAnnotation!=`object`||!(`typeAnnotation`in e.typeAnnotation))return;let a=e.typeAnnotation.typeAnnotation;A(a)&&N(t,n,M(e)??`未知参数`,j(a),r,i)}function I(e,t,n,r,i){for(let a of e)F(a,t,n,i??!1,r)}function L(e,t,n,r,i){if(typeof e!=`object`||!e||!(`typeAnnotation`in e))return;let a=e.typeAnnotation;A(a)&&P(t,n,j(a),r,i)}function R(e,t){if(!T(e)||!O(e))return;let n=null;`id`in e&&e.id!==null&&typeof e.id==`object`&&`name`in e.id&&typeof e.id.name==`string`&&(n=e.id.name),k(e)&&I(e.params??[],t,e),D(e)&&L(e.returnType,t,e,n??void 0)}function z(e,t){T(e)&&k(e)&&(k(e)&&I(e.params??[],t,e),D(e)&&L(e.returnType,t,e))}function B(e,t){if(!E(e))return;let n=e.key,r=n&&`name`in n&&typeof n.name==`string`?n.name:`未知方法`,i=e.value;if(i&&`params`in i&&Array.isArray(i.params)&&I(i.params,t,e,r,e.kind===`constructor`),i&&`returnType`in i&&i.returnType&&typeof i.returnType==`object`&&`typeAnnotation`in i.returnType){let n=i.returnType;L(n,t,e,void 0,r)}}const V=e({meta:{type:`suggestion`,docs:{description:`禁止在函数参数和返回值中使用内联类型定义,强制使用具名类型`}},createOnce(e){return{FunctionDeclaration(t){R(t,e)},FunctionExpression(t){R(t,e)},ArrowFunctionExpression(t){z(t,e)},MethodDefinition(t){B(t,e)}}}});function H(e){let t=[];if(e.type===`Identifier`&&t.push(e.name),e.type===`ObjectPattern`)for(let n of e.properties)n.type===`Property`&&`value`in n?n.value.type===`Identifier`&&t.push(n.value.name):n.type===`RestElement`&&n.argument.type===`Identifier`&&t.push(n.argument.name);if(e.type===`ArrayPattern`)for(let n of e.elements)n&&n.type===`Identifier`&&t.push(n.name);return t}const U=e({meta:{type:`suggestion`,docs:{description:`将 export const/let/var 拆分为独立的声明和导出语句`}},createOnce(e){return{ExportNamedDeclaration(t){if(!t.declaration||t.declaration.type!==`VariableDeclaration`)return;let n=t.declaration;if(n.kind!==`const`&&n.kind!==`let`&&n.kind!==`var`||n.declarations.length===0)return;let r=[];for(let e of n.declarations)r.push(...H(e.id));r.length!==0&&e.report({node:t,message:`应将 \`export ${n.kind} ${r.join(`, `)}\` 拆分为独立的声明和导出语句`})}}}}),W=[{suffix:`.service.drizzle.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.service.memory.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.service.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.controller.ts`,classSuffix:`Controller`,isInterface:!1,isPrefix:!1},{suffix:`.module.ts`,classSuffix:`Module`,isInterface:!1,isPrefix:!1},{suffix:`.repository.drizzle.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.repository.memory.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.repository.interface.ts`,classSuffix:`Repository`,isInterface:!0,isPrefix:!0},{suffix:`.repository.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.entity.ts`,classSuffix:`Entity`,isInterface:!1,isPrefix:!1},{suffix:`.orm-entity.ts`,classSuffix:`OrmEntity`,isInterface:!1,isPrefix:!1},{suffix:`.dto.ts`,classSuffix:`DTO`,isInterface:!1,isPrefix:!1},{suffix:`.port.interface.ts`,classSuffix:`Port`,isInterface:!0,isPrefix:!0},{suffix:`.interface.ts`,classSuffix:``,isInterface:!0,isPrefix:!0},{suffix:`.port.ts`,classSuffix:`Port`,isInterface:!0,isPrefix:!1},{suffix:`.port.adapter.ts`,classSuffix:`PortAdapter`,isInterface:!1,isPrefix:!1},{suffix:`.adapter.ts`,classSuffix:`Adapter`,isInterface:!1,isPrefix:!1},{suffix:`.events.ts`,classSuffix:`Event`,isInterface:!1,isPrefix:!1},{suffix:`.mapper.ts`,classSuffix:`Mapper`,isInterface:!1,isPrefix:!1},{suffix:`.vo.ts`,classSuffix:`VO`,isInterface:!1,isPrefix:!1},{suffix:`.usecase.ts`,classSuffix:`UseCase`,isInterface:!1,isPrefix:!1},{suffix:`.errors.ts`,classSuffix:`Error`,isInterface:!1,isPrefix:!1}];function G(e){for(let t of W)if(e.endsWith(t.suffix))return t;return null}function K(e,t){if(t.isPrefix&&t.isInterface){if(t.classSuffix){let n=t.classSuffix;return e.startsWith(`I`)&&e.endsWith(n)&&e.length>1+n.length}return e.startsWith(`I`)&&e.length>1}return t.isPrefix?e.startsWith(`I`)&&e.length>1:e.endsWith(t.classSuffix)&&e.length>t.classSuffix.length}function q(e){return e.isPrefix&&e.isInterface?e.classSuffix?`I${e.classSuffix}(如 IUser${e.classSuffix})`:`I 前缀(如 IUser)`:e.isPrefix?`I 前缀(如 IUser)`:`${e.classSuffix} 后缀`}const J=e({meta:{type:`problem`,docs:{description:`强制执行类名与文件类型后缀的一致性`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||!G(t))return!1},ClassDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=G(n);if(!r||r.isInterface||!t.id)return;let i=t.id.name;K(i,r)||e.report({node:t,message:`类名 "${i}" 不符合命名规范。文件 "${n}" 中的类应使用 ${q(r)}`})},TSInterfaceDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=G(n);if(!r||!r.isInterface)return;let i=t.id.name;K(i,r)||e.report({node:t,message:`接口名 "${i}" 不符合命名规范。文件 "${n}" 中的接口应使用 ${q(r)}`})}}}});function Y(e){return e.endsWith(`.dto.ts`)}function X(e){return e.endsWith(`DTO`)}const Z=e({meta:{type:`problem`,docs:{description:`强制执行 DTO 文件中的接口命名规范(Dto 后缀,驼峰式)`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||!Y(t))return!1},TSInterfaceDeclaration(t){let n=t.id.name;X(n)?e.report({node:t,message:`接口名 "${n}" 后缀应使用 Dto(驼峰式)而非 DTO(全大写)`}):i(n)||e.report({node:t,message:`DTO 文件中的接口名 "${n}" 应以 Dto 结尾(如 UserResponseDto)`})}}}}),re=[`types.ts`,`types.d.ts`],ie=[`.port.interface.ts`,`.repository.interface.ts`,`.types.ts`,`.types.d.ts`,`.events.ts`,`.d.ts`];function ae(e,t){return r(e)?!1:!t.endsWith(`.dto.ts`)||a(e)}function oe(e){return e.endsWith(`.dto.ts`)?`DTO 后缀(如 UserDTO),禁止 I 前缀`:`PascalCase(如 User、UserRepository),禁止 I 前缀`}function se(e){if(re.includes(e))return!0;for(let t of ie)if(e.endsWith(t))return!0;return!1}function ce(e){return e.endsWith(`.port.ts`)?e.replace(`.port.ts`,`.port.interface.ts`):e.endsWith(`.repository.ts`)?e.replace(`.repository.ts`,`.repository.interface.ts`):e.replace(`.ts`,`.interface.ts`)}const Q=e({meta:{type:`problem`,docs:{description:`强制执行接口命名规范(禁止 I 前缀,使用 PascalCase)和文件命名规范`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||se(t))return!1},TSInterfaceDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,i=n.endsWith(`.interface.ts`)||n.endsWith(`.interface.tsx`),a=t.id.name;ae(a,n)||(r(a)?e.report({node:t,message:`接口名 "${a}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${a.substring(1)}"`}):n.endsWith(`.dto.ts`)&&a.endsWith(`Dto`)?e.report({node:t,message:`接口名 "${a}" 后缀应使用 DTO(全大写)而非 Dto(驼峰式)`}):e.report({node:t,message:`接口名 "${a}" 不符合命名规范。接口名应使用 ${oe(n)}`})),!i&&!n.endsWith(`.dto.ts`)&&!n.endsWith(`.tsx`)&&e.report({node:t,message:`包含接口 "${a}" 的文件 "${n}" 应命名为 "${ce(n)}"`})}}}}),$=t({meta:{name:`@longzai-intelligence-oxlint/code-style-plugin`},rules:{"no-console":u,"no-inline-type-definition":V,"prefer-split-export-const":U,"require-interface-naming":Q,"require-dto-naming":Z,"require-class-suffix":J,"no-class-suffix-alias":s}});export{W as SUFFIX_MAPPINGS,$ as codeStylePlugin,$ as default,j as getInlineTypeDescription,M as getParamName,r as hasIPrefix,A as hasInlineType,Y as isDtoFile,T as isFunctionNode,E as isMethodDefinition,x as isTSFunctionType,C as isTSIntersectionType,b as isTSTypeLiteral,S as isTSUnionType,s as noClassSuffixAliasRule,u as noConsoleRule,V as noInlineTypeDefinitionRule,U as preferSplitExportConstRule,J as requireClassSuffixRule,Z as requireDtoNamingRule,Q as requireInterfaceNamingRule};
|
|
1
|
+
import"./rolldown-runtime-BqT_7tdF.js";import{defineRule as e,eslintCompatPlugin as t}from"@oxlint/plugins";import{existsSync as n,readFileSync as r}from"node:fs";import{dirname as i,join as a}from"node:path";import*as o from"zod/mini";import{hasIPrefix as s,isValidDtoNameCamelCase as ee,isValidDtoNameUpperCase as te}from"@longzai-intelligence-oxlint/utils";function c(e){return e.endsWith(`Class`)}const l=e({meta:{type:`problem`,docs:{description:`禁止在 import 别名中使用 "Class" 后缀`}},createOnce(e){return{ImportSpecifier(t){let n=t.local.name,r=t.imported.type===`Identifier`?t.imported.name:n;n!==r&&c(n)&&e.report({node:t,message:`导入别名 "${n}" 使用了 "Class" 后缀,这是不允许的命名方式。请使用更具描述性的名称,或直接使用原始名称 "${r}"`})}}}}),u=/* @__PURE__ */ new Set([`console.log`,`console.warn`,`console.error`,`console.info`,`console.debug`,`console.trace`,`console.dir`,`console.table`]);function d(e){let t=e.callee;return t.type===`Identifier`?t.name:t.type===`MemberExpression`&&t.property.type===`Identifier`&&t.object.type===`Identifier`?`${t.object.name}.${t.property.name}`:null}const f=e({meta:{type:`problem`,docs:{description:`禁止使用 console 方法,必须使用 @longzai-intelligence/logger-preset-* 或 react-devtools(ADR 0038)`}},createOnce(e){return{CallExpression(t){if(t.type!==`CallExpression`)return;let n=d(t);n&&u.has(n)&&e.report({node:t,message:`检测到 '${n}' — 必须使用 @longzai-intelligence/logger-preset-* 代替(ADR 0038)`})}}}}),p=/\/src\/(index|main|cli)\.(ts|mts|cts)$/,m=/(^|\/)dist\//;function ne(e){return e.replace(/\\/g,`/`)}function h(e){return typeof e==`object`&&!!e}function re(e){return e.startsWith(`#!`)}function g(e){return p.test(ne(e))}function ie(e){let t=e;for(let e=0;e<4;e+=1){let e=a(t,`package.json`);if(n(e))try{let t=JSON.parse(r(e,`utf8`));return h(t)?t:null}catch{return null}let o=i(t);if(o===t)break;t=o}return null}function ae(e){let t=e.bin;return(typeof t==`string`?[t]:h(t)?Object.values(t).filter(e=>typeof e==`string`):[]).some(e=>m.test(e.replace(/^\.\//,``)))}const _={noHandwrittenShebang:`入口源码手写 shebang 属被裁定的错误方式,bin 产物首行 shebang 应由 "lzi-builder.config.ts" 的 banner 在构建期注入。请删除源码首行的 "#!" 行并补 banner 配置。`},v=e({meta:{type:`problem`,docs:{description:`禁止所属包 bin 指向 dist 产物的入口源码手写 shebang`}},createOnce(e){return{before(){let t=e.filename;if(!g(t))return!1},Program(t){let n=e.sourceCode.text;if(!re(n))return;let r=ie(i(i(e.filename)));r!==null&&ae(r)&&e.report({node:t,message:_.noHandwrittenShebang})}}}}),y=o.object({type:o.literal(`TSTypeLiteral`)}),b=o.object({type:o.literal(`TSFunctionType`)}),x=o.object({type:o.literal(`TSUnionType`),types:o.array(o.unknown())}),oe=o.object({type:o.literal(`TSIntersectionType`),types:o.array(o.unknown())}),se=o.object({type:o.literal(`Identifier`),name:o.string()}),ce=o.object({type:o.literal(`RestElement`),argument:o.object({name:o.string()})}),le=o.union([se,ce]),S=o.object({typeAnnotation:o.unknown()}),ue=o.object({type:o.literal(`MethodDefinition`),key:o.object({type:o.string(),name:o.optional(o.string())}),value:o.object({params:o.optional(o.array(o.unknown())),returnType:o.optional(o.union([S,o.null()]))}),kind:o.enum([`method`,`constructor`,`get`,`set`])}),de=o.object({returnType:S}),fe=o.object({id:o.optional(o.object({name:o.optional(o.string())})),params:o.optional(o.array(o.unknown())),returnType:o.optional(o.unknown())}),pe=o.object({params:o.optional(o.array(o.unknown()))});function C(e){return y.safeParse(e).success}function w(e){return b.safeParse(e).success}function T(e){return x.safeParse(e).success}function E(e){return oe.safeParse(e).success}function D(e){return le.safeParse(e).success}function O(e){if(typeof e!=`object`||!e||!(`type`in e))return!1;let t=[`FunctionDeclaration`,`FunctionExpression`,`ArrowFunctionExpression`,`MethodDefinition`],n=e.type;return typeof n==`string`&&t.includes(n)}function k(e){return ue.safeParse(e).success}function A(e){return de.safeParse(e).success}function j(e){return fe.safeParse(e).success}function M(e){return pe.safeParse(e).success}function N(e){return C(e)||w(e)?!0:T(e)||E(e)?e.types.some(N):!1}function P(e){return C(e)?`对象类型`:w(e)?`函数类型`:`内联类型`}function F(e){return D(e)?e.type===`Identifier`?e.name:e.type===`RestElement`?e.argument.name:null:null}function I(e,t,n,r,i,a){i?e.report({node:t,message:`参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`}):a?e.report({node:t,message:`方法 "${a}" 的参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`}):e.report({node:t,message:`参数 "${n}" 使用了内联${r}定义。请将其提取为具名的 type。`})}function L(e,t,n,r,i){i?e.report({node:t,message:`方法 "${i}" 的返回值使用了内联${n}定义。请将其提取为具名的 type。`}):r?e.report({node:t,message:`函数 "${r}" 的返回值使用了内联${n}定义。请将其提取为具名的 type。`}):e.report({node:t,message:`匿名函数的返回值使用了内联${n}定义。请将其提取为具名的 type。`})}function R(e,t,n,r,i){if(typeof e!=`object`||!e||!(`typeAnnotation`in e)||e.typeAnnotation===null||typeof e.typeAnnotation!=`object`||!(`typeAnnotation`in e.typeAnnotation))return;let a=e.typeAnnotation.typeAnnotation;N(a)&&I(t,n,F(e)??`未知参数`,P(a),r,i)}function z(e,t,n,r,i){for(let a of e)R(a,t,n,i??!1,r)}function B(e,t,n,r,i){if(typeof e!=`object`||!e||!(`typeAnnotation`in e))return;let a=e.typeAnnotation;N(a)&&L(t,n,P(a),r,i)}function V(e,t){if(!O(e)||!j(e))return;let n=null;`id`in e&&e.id!==null&&typeof e.id==`object`&&`name`in e.id&&typeof e.id.name==`string`&&(n=e.id.name),M(e)&&z(e.params??[],t,e),A(e)&&B(e.returnType,t,e,n??void 0)}function me(e,t){O(e)&&M(e)&&(M(e)&&z(e.params??[],t,e),A(e)&&B(e.returnType,t,e))}function he(e,t){if(!k(e))return;let n=e.key,r=n&&`name`in n&&typeof n.name==`string`?n.name:`未知方法`,i=e.value;if(i&&`params`in i&&Array.isArray(i.params)&&z(i.params,t,e,r,e.kind===`constructor`),i&&`returnType`in i&&i.returnType&&typeof i.returnType==`object`&&`typeAnnotation`in i.returnType){let n=i.returnType;B(n,t,e,void 0,r)}}const H=e({meta:{type:`suggestion`,docs:{description:`禁止在函数参数和返回值中使用内联类型定义,强制使用具名类型`}},createOnce(e){return{FunctionDeclaration(t){V(t,e)},FunctionExpression(t){V(t,e)},ArrowFunctionExpression(t){me(t,e)},MethodDefinition(t){he(t,e)}}}});function ge(e){let t=[];if(e.type===`Identifier`&&t.push(e.name),e.type===`ObjectPattern`)for(let n of e.properties)n.type===`Property`&&`value`in n?n.value.type===`Identifier`&&t.push(n.value.name):n.type===`RestElement`&&n.argument.type===`Identifier`&&t.push(n.argument.name);if(e.type===`ArrayPattern`)for(let n of e.elements)n&&n.type===`Identifier`&&t.push(n.name);return t}const U=e({meta:{type:`suggestion`,docs:{description:`将 export const/let/var 拆分为独立的声明和导出语句`}},createOnce(e){return{ExportNamedDeclaration(t){if(!t.declaration||t.declaration.type!==`VariableDeclaration`)return;let n=t.declaration;if(n.kind!==`const`&&n.kind!==`let`&&n.kind!==`var`||n.declarations.length===0)return;let r=[];for(let e of n.declarations)r.push(...ge(e.id));r.length!==0&&e.report({node:t,message:`应将 \`export ${n.kind} ${r.join(`, `)}\` 拆分为独立的声明和导出语句`})}}}}),W=[{suffix:`.service.drizzle.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.service.memory.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.service.ts`,classSuffix:`Service`,isInterface:!1,isPrefix:!1},{suffix:`.controller.ts`,classSuffix:`Controller`,isInterface:!1,isPrefix:!1},{suffix:`.module.ts`,classSuffix:`Module`,isInterface:!1,isPrefix:!1},{suffix:`.repository.drizzle.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.repository.memory.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.repository.interface.ts`,classSuffix:`Repository`,isInterface:!0,isPrefix:!0},{suffix:`.repository.ts`,classSuffix:`Repository`,isInterface:!1,isPrefix:!1},{suffix:`.entity.ts`,classSuffix:`Entity`,isInterface:!1,isPrefix:!1},{suffix:`.orm-entity.ts`,classSuffix:`OrmEntity`,isInterface:!1,isPrefix:!1},{suffix:`.dto.ts`,classSuffix:`DTO`,isInterface:!1,isPrefix:!1},{suffix:`.port.interface.ts`,classSuffix:`Port`,isInterface:!0,isPrefix:!0},{suffix:`.interface.ts`,classSuffix:``,isInterface:!0,isPrefix:!0},{suffix:`.port.ts`,classSuffix:`Port`,isInterface:!0,isPrefix:!1},{suffix:`.port.adapter.ts`,classSuffix:`PortAdapter`,isInterface:!1,isPrefix:!1},{suffix:`.adapter.ts`,classSuffix:`Adapter`,isInterface:!1,isPrefix:!1},{suffix:`.events.ts`,classSuffix:`Event`,isInterface:!1,isPrefix:!1},{suffix:`.mapper.ts`,classSuffix:`Mapper`,isInterface:!1,isPrefix:!1},{suffix:`.vo.ts`,classSuffix:`VO`,isInterface:!1,isPrefix:!1},{suffix:`.usecase.ts`,classSuffix:`UseCase`,isInterface:!1,isPrefix:!1},{suffix:`.errors.ts`,classSuffix:`Error`,isInterface:!1,isPrefix:!1}];function G(e){for(let t of W)if(e.endsWith(t.suffix))return t;return null}function K(e,t){if(t.isPrefix&&t.isInterface){if(t.classSuffix){let n=t.classSuffix;return e.startsWith(`I`)&&e.endsWith(n)&&e.length>1+n.length}return e.startsWith(`I`)&&e.length>1}return t.isPrefix?e.startsWith(`I`)&&e.length>1:e.endsWith(t.classSuffix)&&e.length>t.classSuffix.length}function q(e){return e.isPrefix&&e.isInterface?e.classSuffix?`I${e.classSuffix}(如 IUser${e.classSuffix})`:`I 前缀(如 IUser)`:e.isPrefix?`I 前缀(如 IUser)`:`${e.classSuffix} 后缀`}const J=e({meta:{type:`problem`,docs:{description:`强制执行类名与文件类型后缀的一致性`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||!G(t))return!1},ClassDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=G(n);if(!r||r.isInterface||!t.id)return;let i=t.id.name;K(i,r)||e.report({node:t,message:`类名 "${i}" 不符合命名规范。文件 "${n}" 中的类应使用 ${q(r)}`})},TSInterfaceDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=G(n);if(!r||!r.isInterface)return;let i=t.id.name;K(i,r)||e.report({node:t,message:`接口名 "${i}" 不符合命名规范。文件 "${n}" 中的接口应使用 ${q(r)}`})}}}});function Y(e){return e.endsWith(`.dto.ts`)}function X(e){return e.endsWith(`DTO`)}const Z=e({meta:{type:`problem`,docs:{description:`强制执行 DTO 文件中的接口命名规范(Dto 后缀,驼峰式)`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||!Y(t))return!1},TSInterfaceDeclaration(t){let n=t.id.name;X(n)?e.report({node:t,message:`接口名 "${n}" 后缀应使用 Dto(驼峰式)而非 DTO(全大写)`}):ee(n)||e.report({node:t,message:`DTO 文件中的接口名 "${n}" 应以 Dto 结尾(如 UserResponseDto)`})}}}}),_e=[`types.ts`,`types.d.ts`],ve=[`.port.interface.ts`,`.repository.interface.ts`,`.types.ts`,`.types.d.ts`,`.events.ts`,`.d.ts`];function ye(e,t){return s(e)?!1:!t.endsWith(`.dto.ts`)||te(e)}function be(e){return e.endsWith(`.dto.ts`)?`DTO 后缀(如 UserDTO),禁止 I 前缀`:`PascalCase(如 User、UserRepository),禁止 I 前缀`}function xe(e){if(_e.includes(e))return!0;for(let t of ve)if(e.endsWith(t))return!0;return!1}function Se(e){return e.endsWith(`.port.ts`)?e.replace(`.port.ts`,`.port.interface.ts`):e.endsWith(`.repository.ts`)?e.replace(`.repository.ts`,`.repository.interface.ts`):e.replace(`.ts`,`.interface.ts`)}const Q=e({meta:{type:`problem`,docs:{description:`强制执行接口命名规范(禁止 I 前缀,使用 PascalCase)和文件命名规范`}},createOnce(e){return{before(){let t=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`)||xe(t))return!1},TSInterfaceDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=n.endsWith(`.interface.ts`)||n.endsWith(`.interface.tsx`),i=t.id.name;ye(i,n)||(s(i)?e.report({node:t,message:`接口名 "${i}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${i.substring(1)}"`}):n.endsWith(`.dto.ts`)&&i.endsWith(`Dto`)?e.report({node:t,message:`接口名 "${i}" 后缀应使用 DTO(全大写)而非 Dto(驼峰式)`}):e.report({node:t,message:`接口名 "${i}" 不符合命名规范。接口名应使用 ${be(n)}`})),!r&&!n.endsWith(`.dto.ts`)&&!n.endsWith(`.tsx`)&&e.report({node:t,message:`包含接口 "${i}" 的文件 "${n}" 应命名为 "${Se(n)}"`})}}}}),$=t({meta:{name:`@longzai-intelligence-oxlint/code-style-plugin`},rules:{"no-console":f,"no-inline-type-definition":H,"prefer-split-export-const":U,"require-interface-naming":Q,"require-dto-naming":Z,"require-class-suffix":J,"no-class-suffix-alias":l,"no-handwritten-shebang":v}});export{W as SUFFIX_MAPPINGS,$ as codeStylePlugin,$ as default,P as getInlineTypeDescription,F as getParamName,s as hasIPrefix,N as hasInlineType,Y as isDtoFile,O as isFunctionNode,k as isMethodDefinition,w as isTSFunctionType,E as isTSIntersectionType,C as isTSTypeLiteral,T as isTSUnionType,l as noClassSuffixAliasRule,f as noConsoleRule,v as noHandwrittenShebangRule,H as noInlineTypeDefinitionRule,U as preferSplitExportConstRule,J as requireClassSuffixRule,Z as requireDtoNamingRule,Q as requireInterfaceNamingRule};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"node:module";export{};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-oxlint/code-style-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"typecheck:test": "lzi-tsgo typecheck tsconfig/test.json"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@longzai-intelligence-oxlint/core": "0.1.
|
|
39
|
-
"@longzai-intelligence-oxlint/utils": "0.1.
|
|
38
|
+
"@longzai-intelligence-oxlint/core": "0.1.24",
|
|
39
|
+
"@longzai-intelligence-oxlint/utils": "0.1.24",
|
|
40
40
|
"@oxlint/plugins": "^1.74.0",
|
|
41
41
|
"zod": "^4.4.3"
|
|
42
42
|
},
|