@longzai-intelligence-oxlint/presets 0.2.1 → 0.2.3

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
- import"../rolldown-runtime-BqT_7tdF.js";import"../rolldown-runtime-BqT_7tdF-BqT_7tdF.js";import{n as e,r as t,t as n}from"../dist-CskvMq7J.js";import{defineRule as r,eslintCompatPlugin as i}from"@oxlint/plugins";import{existsSync as a,readFileSync as ee}from"node:fs";import{dirname as o,join as te}from"node:path";import*as s from"zod/mini";function c(e){return e.endsWith(`Class`)}const l=r({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=r({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=te(t,`package.json`);if(a(e))try{let t=JSON.parse(ee(e,`utf8`));return h(t)?t:null}catch{return null}let n=o(t);if(n===t)break;t=n}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=r({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(o(o(e.filename)));r!==null&&ae(r)&&e.report({node:t,message:_.noHandwrittenShebang})}}}}),y=s.object({type:s.literal(`TSTypeLiteral`)}),b=s.object({type:s.literal(`TSFunctionType`)}),x=s.object({type:s.literal(`TSUnionType`),types:s.array(s.unknown())}),oe=s.object({type:s.literal(`TSIntersectionType`),types:s.array(s.unknown())}),se=s.object({type:s.literal(`Identifier`),name:s.string()}),ce=s.object({type:s.literal(`RestElement`),argument:s.object({name:s.string()})}),le=s.union([se,ce]),S=s.object({typeAnnotation:s.unknown()}),ue=s.object({type:s.literal(`MethodDefinition`),key:s.object({type:s.string(),name:s.optional(s.string())}),value:s.object({params:s.optional(s.array(s.unknown())),returnType:s.optional(s.union([S,s.null()]))}),kind:s.enum([`method`,`constructor`,`get`,`set`])}),de=s.object({returnType:S}),fe=s.object({id:s.optional(s.object({name:s.optional(s.string())})),params:s.optional(s.array(s.unknown())),returnType:s.optional(s.unknown())}),pe=s.object({params:s.optional(s.array(s.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=r({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=r({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=r({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=r({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(n){let r=n.id.name;X(r)?e.report({node:n,message:`接口名 "${r}" 后缀应使用 Dto(驼峰式)而非 DTO(全大写)`}):t(r)||e.report({node:n,message:`DTO 文件中的接口名 "${r}" 应以 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(t,r){return e(t)?!1:!r.endsWith(`.dto.ts`)||n(t)}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=r({meta:{type:`problem`,docs:{description:`强制执行接口命名规范(禁止 I 前缀,使用 PascalCase)和文件命名规范`}},createOnce(t){return{before(){let e=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(e.endsWith(`.test.ts`)||e.endsWith(`.spec.ts`)||xe(e))return!1},TSInterfaceDeclaration(n){let r=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``,i=r.endsWith(`.interface.ts`)||r.endsWith(`.interface.tsx`),a=n.id.name;ye(a,r)||(e(a)?t.report({node:n,message:`接口名 "${a}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${a.substring(1)}"`}):r.endsWith(`.dto.ts`)&&a.endsWith(`Dto`)?t.report({node:n,message:`接口名 "${a}" 后缀应使用 DTO(全大写)而非 Dto(驼峰式)`}):t.report({node:n,message:`接口名 "${a}" 不符合命名规范。接口名应使用 ${be(r)}`})),!i&&!r.endsWith(`.dto.ts`)&&!r.endsWith(`.tsx`)&&t.report({node:n,message:`包含接口 "${a}" 的文件 "${r}" 应命名为 "${Se(r)}"`})}}}}),$=i({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,e 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};
1
+ import"../rolldown-runtime-BqT_7tdF.js";import"../rolldown-runtime-BqT_7tdF-BqT_7tdF.js";import{n as e,r as t,t as n}from"../dist-CskvMq7J.js";import{defineRule as r,eslintCompatPlugin as i}from"@oxlint/plugins";import{existsSync as a,readFileSync as ee}from"node:fs";import{dirname as o,join as te}from"node:path";import*as s from"zod/mini";function c(e){return e.endsWith(`Class`)}const l=r({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=r({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=te(t,`package.json`);if(a(e))try{let t=JSON.parse(ee(e,`utf8`));return h(t)?t:null}catch{return null}let n=o(t);if(n===t)break;t=n}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 oe={noHandwrittenShebang:`入口源码手写 shebang 属被裁定的错误方式,bin 产物首行 shebang 应由 "lzi-builder.config.ts" 的 banner 在构建期注入。请删除源码首行的 "#!" 行并补 banner 配置。`},_=r({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(o(o(e.filename)));r!==null&&ae(r)&&e.report({node:t,message:oe.noHandwrittenShebang})}}}}),v=s.object({type:s.literal(`TSTypeLiteral`)}),y=s.object({type:s.literal(`TSFunctionType`)}),b=s.object({type:s.literal(`TSUnionType`),types:s.array(s.unknown())}),se=s.object({type:s.literal(`TSIntersectionType`),types:s.array(s.unknown())}),ce=s.object({type:s.literal(`Identifier`),name:s.string()}),le=s.object({type:s.literal(`RestElement`),argument:s.object({name:s.string()})}),ue=s.union([ce,le]),x=s.object({typeAnnotation:s.unknown()}),de=s.object({type:s.literal(`MethodDefinition`),key:s.object({type:s.string(),name:s.optional(s.string())}),value:s.object({params:s.optional(s.array(s.unknown())),returnType:s.optional(s.union([x,s.null()]))}),kind:s.enum([`method`,`constructor`,`get`,`set`])}),fe=s.object({returnType:x}),pe=s.object({id:s.optional(s.object({name:s.optional(s.string())})),params:s.optional(s.array(s.unknown())),returnType:s.optional(s.unknown())}),me=s.object({params:s.optional(s.array(s.unknown()))});function S(e){return v.safeParse(e).success}function C(e){return y.safeParse(e).success}function w(e){return b.safeParse(e).success}function T(e){return se.safeParse(e).success}function E(e){return ue.safeParse(e).success}function D(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 O(e){return de.safeParse(e).success}function k(e){return fe.safeParse(e).success}function A(e){return pe.safeParse(e).success}function j(e){return me.safeParse(e).success}function M(e){return S(e)||C(e)?!0:w(e)||T(e)?e.types.some(M):!1}function N(e){return S(e)?`对象类型`:C(e)?`函数类型`:`内联类型`}function P(e){return E(e)?e.type===`Identifier`?e.name:e.type===`RestElement`?e.argument.name:null:null}function F(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 I(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 L(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;M(a)&&F(t,n,P(e)??`未知参数`,N(a),r,i)}function R(e,t,n,r,i){for(let a of e)L(a,t,n,i??!1,r)}function z(e,t,n,r,i){if(typeof e!=`object`||!e||!(`typeAnnotation`in e))return;let a=e.typeAnnotation;M(a)&&I(t,n,N(a),r,i)}function B(e,t){if(!D(e)||!A(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),j(e)&&R(e.params??[],t,e),k(e)&&z(e.returnType,t,e,n??void 0)}function he(e,t){D(e)&&j(e)&&(j(e)&&R(e.params??[],t,e),k(e)&&z(e.returnType,t,e))}function ge(e,t){if(!O(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)&&R(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;z(n,t,e,void 0,r)}}const V=r({meta:{type:`suggestion`,docs:{description:`禁止在函数参数和返回值中使用内联类型定义,强制使用具名类型`}},createOnce(e){return{FunctionDeclaration(t){B(t,e)},FunctionExpression(t){B(t,e)},ArrowFunctionExpression(t){he(t,e)},MethodDefinition(t){ge(t,e)}}}}),H=/^(?:eslint-disable(?:-next-line|-line)?|eslint-enable|oxlint-disable(?:-next-line|-line)?|oxlint-enable|biome-ignore|stylelint-disable(?:-next-line|-line)?|stylelint-enable|@ts-ignore|@ts-nocheck)(?=[\s,]|$)/;function _e(e){let t=e.trimStart();return H.exec(t)?.[0]??null}const U=r({meta:{type:`problem`,docs:{description:`禁止 eslint-disable、oxlint-disable、biome-ignore、stylelint-disable、@ts-ignore、@ts-nocheck 等抑制注释`}},createOnce(e){return{Program(){let t=e.sourceCode.getAllComments();for(let n of t){if(n.type===`Shebang`)continue;let t=_e(n.value);t!==null&&e.report({node:n,message:`检测到抑制指令 ${t},抑制注释不是合法豁免手段,请从源头消除违例或在包级 oxlint.config.ts 的 ignorePatterns 登记路径豁免`})}}}}});function ve(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 W=r({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(...ve(e.id));r.length!==0&&e.report({node:t,message:`应将 \`export ${n.kind} ${r.join(`, `)}\` 拆分为独立的声明和导出语句`})}}}}),G=[{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 K(e){for(let t of G)if(e.endsWith(t.suffix))return t;return null}function q(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 J(e){return e.isPrefix&&e.isInterface?e.classSuffix?`I${e.classSuffix}(如 IUser${e.classSuffix})`:`I 前缀(如 IUser)`:e.isPrefix?`I 前缀(如 IUser)`:`${e.classSuffix} 后缀`}const Y=r({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`)||!K(t))return!1},ClassDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=K(n);if(!r||r.isInterface||!t.id)return;let i=t.id.name;q(i,r)||e.report({node:t,message:`类名 "${i}" 不符合命名规范。文件 "${n}" 中的类应使用 ${J(r)}`})},TSInterfaceDeclaration(t){let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=K(n);if(!r||!r.isInterface)return;let i=t.id.name;q(i,r)||e.report({node:t,message:`接口名 "${i}" 不符合命名规范。文件 "${n}" 中的接口应使用 ${J(r)}`})}}}});function X(e){return e.endsWith(`.dto.ts`)}function ye(e){return e.endsWith(`DTO`)}const Z=r({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`)||!X(t))return!1},TSInterfaceDeclaration(n){let r=n.id.name;ye(r)?e.report({node:n,message:`接口名 "${r}" 后缀应使用 Dto(驼峰式)而非 DTO(全大写)`}):t(r)||e.report({node:n,message:`DTO 文件中的接口名 "${r}" 应以 Dto 结尾(如 UserResponseDto)`})}}}}),be=[`types.ts`,`types.d.ts`],xe=[`.port.interface.ts`,`.repository.interface.ts`,`.types.ts`,`.types.d.ts`,`.events.ts`,`.d.ts`];function Se(t,r){return e(t)?!1:!r.endsWith(`.dto.ts`)||n(t)}function Ce(e){return e.endsWith(`.dto.ts`)?`DTO 后缀(如 UserDTO),禁止 I 前缀`:`PascalCase(如 User、UserRepository),禁止 I 前缀`}function we(e){if(be.includes(e))return!0;for(let t of xe)if(e.endsWith(t))return!0;return!1}function Te(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=r({meta:{type:`problem`,docs:{description:`强制执行接口命名规范(禁止 I 前缀,使用 PascalCase)和文件命名规范`}},createOnce(t){return{before(){let e=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(e.endsWith(`.test.ts`)||e.endsWith(`.spec.ts`)||we(e))return!1},TSInterfaceDeclaration(n){let r=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``,i=r.endsWith(`.interface.ts`)||r.endsWith(`.interface.tsx`),a=n.id.name;Se(a,r)||(e(a)?t.report({node:n,message:`接口名 "${a}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${a.substring(1)}"`}):r.endsWith(`.dto.ts`)&&a.endsWith(`Dto`)?t.report({node:n,message:`接口名 "${a}" 后缀应使用 DTO(全大写)而非 Dto(驼峰式)`}):t.report({node:n,message:`接口名 "${a}" 不符合命名规范。接口名应使用 ${Ce(r)}`})),!i&&!r.endsWith(`.dto.ts`)&&!r.endsWith(`.tsx`)&&t.report({node:n,message:`包含接口 "${a}" 的文件 "${r}" 应命名为 "${Te(r)}"`})}}}}),$=i({meta:{name:`@longzai-intelligence-oxlint/code-style-plugin`},rules:{"no-console":f,"no-inline-type-definition":V,"prefer-split-export-const":W,"require-interface-naming":Q,"require-dto-naming":Z,"require-class-suffix":Y,"no-class-suffix-alias":l,"no-handwritten-shebang":_,"no-lint-suppression":U}});export{G as SUFFIX_MAPPINGS,$ as codeStylePlugin,$ as default,N as getInlineTypeDescription,P as getParamName,e as hasIPrefix,M as hasInlineType,X as isDtoFile,D as isFunctionNode,O as isMethodDefinition,C as isTSFunctionType,T as isTSIntersectionType,S as isTSTypeLiteral,w as isTSUnionType,l as noClassSuffixAliasRule,f as noConsoleRule,_ as noHandwrittenShebangRule,V as noInlineTypeDefinitionRule,U as noLintSuppressionRule,W as preferSplitExportConstRule,Y as requireClassSuffixRule,Z as requireDtoNamingRule,Q as requireInterfaceNamingRule};
@@ -1 +1 @@
1
- import"../rolldown-runtime-BqT_7tdF.js";import{n as e}from"../dist-CskvMq7J.js";import{defineRule as t,eslintCompatPlugin as n}from"@oxlint/plugins";import{existsSync as r,readdirSync as i}from"node:fs";import a from"node:path";const o=[`index.ts`,`index.tsx`,`main.ts`,`main.tsx`,`App.tsx`],s=[`types.ts`,`errors.ts`,`constants.ts`],c=[`persistence.ts`,`typeorm.ts`,`hono.ts`,`react.ts`,`vue.ts`,`next.ts`,`electron.ts`,`browser.ts`,`node.ts`],l=[...o,...s,...c],u=[`impl`,`functions`,`methods`,`handlers`,`classes`,`class`,`manager`,`object`,`processor`,`process`,`common`,`logic`,`hooks`,`component`],d=[{pattern:/^use[A-Z][a-zA-Z]*\.spec\.tsx?$/,caseStyle:`camelCase`,description:`Hook 测试文件应使用 camelCase 并以 use 前缀开头(如 useChat.spec.ts)`},{pattern:/^use[A-Z][a-zA-Z]*\.test\.tsx?$/,caseStyle:`camelCase`,description:`Hook 测试文件应使用 camelCase 并以 use 前缀开头(如 useChat.test.ts)`},{pattern:/^use[A-Z][a-zA-Z]*\.types\.ts$/,caseStyle:`camelCase`,description:`Hook 类型文件应使用 camelCase 并以 use 前缀开头(如 useChat.types.ts)`},{pattern:/\.spec\.ts$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.spec.ts 格式(kebab-case)`},{pattern:/\.test\.ts$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.test.ts 格式(kebab-case)`},{pattern:/\.spec\.tsx$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.spec.tsx 格式(kebab-case)`},{pattern:/\.test\.tsx$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.test.tsx 格式(kebab-case)`},{pattern:/^use[A-Z][a-zA-Z]*\.tsx?$/,caseStyle:`camelCase`,description:`Hook 文件应使用 camelCase 并以 use 前缀开头(如 useChat.ts)`}],f=[{pattern:/\.service\.drizzle\.ts$/,caseStyle:`kebab-case`,description:`Drizzle Service 文件应使用 xxx.service.drizzle.ts 格式(kebab-case)`},{pattern:/\.service\.memory\.ts$/,caseStyle:`kebab-case`,description:`Memory Service 文件应使用 xxx.service.memory.ts 格式(kebab-case)`},{pattern:/\.service\.ts$/,caseStyle:`kebab-case`,description:`服务文件应使用 xxx.service.ts 格式(kebab-case)`},{pattern:/\.controller\.ts$/,caseStyle:`kebab-case`,description:`控制器文件应使用 xxx.controller.ts 格式(kebab-case)`},{pattern:/\.module\.ts$/,caseStyle:`kebab-case`,description:`模块文件应使用 xxx.module.ts 格式(kebab-case)`},{pattern:/\.repository\.drizzle\.ts$/,caseStyle:`kebab-case`,description:`Drizzle Repository 文件应使用 xxx.repository.drizzle.ts 格式(kebab-case)`},{pattern:/\.repository\.memory\.ts$/,caseStyle:`kebab-case`,description:`Memory Repository 文件应使用 xxx.repository.memory.ts 格式(kebab-case)`},{pattern:/\.repository\.interface\.ts$/,caseStyle:`kebab-case`,description:`Repository 接口文件应使用 xxx.repository.interface.ts 格式(kebab-case)`},{pattern:/\.repository\.types\.ts$/,caseStyle:`kebab-case`,description:`Repository 类型文件应使用 xxx.repository.types.ts 格式(kebab-case)`},{pattern:/\.repository\.ts$/,caseStyle:`kebab-case`,description:`Repository 文件应使用 xxx.repository.ts 格式(kebab-case)`},{pattern:/\.entity\.types\.ts$/,caseStyle:`kebab-case`,description:`Entity 类型文件应使用 xxx.entity.types.ts 格式(kebab-case)`},{pattern:/\.entity\.interface\.ts$/,caseStyle:`kebab-case`,description:`Entity 接口文件应使用 xxx.entity.interface.ts 格式(kebab-case)`},{pattern:/\.entity\.ts$/,caseStyle:`kebab-case`,description:`Entity 文件应使用 xxx.entity.ts 格式(kebab-case)`},{pattern:/\.dto\.ts$/,caseStyle:`kebab-case`,description:`DTO 文件应使用 xxx.dto.ts 格式(kebab-case)`},{pattern:/\.port\.interface\.ts$/,caseStyle:`kebab-case`,description:`Port 接口文件应使用 xxx.port.interface.ts 格式(kebab-case)`},{pattern:/\.interface\.ts$/,caseStyle:`kebab-case`,description:`接口文件应使用 xxx.interface.ts 格式(kebab-case)`},{pattern:/\.interface\.tsx$/,caseStyle:`kebab-case`,description:`接口文件应使用 xxx.interface.tsx 格式(kebab-case)`},{pattern:/\.types\.ts$/,caseStyle:`kebab-case`,description:`类型文件应使用 xxx.types.ts 格式(kebab-case)`},{pattern:/\.schema\.ts$/,caseStyle:`kebab-case`,description:`Schema 文件应使用 xxx.schema.ts 格式(kebab-case)`},{pattern:/\.port\.ts$/,caseStyle:`kebab-case`,description:`Port 文件应使用 xxx.port.ts 格式(kebab-case)`},{pattern:/\.port-adapter\.factory\.ts$/,caseStyle:`kebab-case`,description:`Port Adapter Factory 文件应使用 xxx.port-adapter.factory.ts 格式(kebab-case)`},{pattern:/\.port-adapter\.ts$/,caseStyle:`kebab-case`,description:`Port Adapter 文件应使用 xxx.port-adapter.ts 格式(kebab-case)`},{pattern:/\.adapter\.ts$/,caseStyle:`kebab-case`,description:`Adapter 文件应使用 xxx.adapter.ts 格式(kebab-case)`},{pattern:/\.client\.ts$/,caseStyle:`kebab-case`,description:`客户端文件应使用 xxx.client.ts 格式(kebab-case)`},{pattern:/\.events\.ts$/,caseStyle:`kebab-case`,description:`Events 文件应使用 xxx.events.ts 格式(kebab-case)`},{pattern:/\.mapper\.ts$/,caseStyle:`kebab-case`,description:`Mapper 文件应使用 xxx.mapper.ts 格式(kebab-case)`},{pattern:/\.ipc\.ts$/,caseStyle:`kebab-case`,description:`IPC 文件应使用 xxx.ipc.ts 格式(kebab-case)`},{pattern:/\.config\.ts$/,caseStyle:`kebab-case`,description:`配置文件应使用 xxx.config.ts 格式(kebab-case)`},{pattern:/\.errors\.ts$/,caseStyle:`kebab-case`,description:`错误文件应使用 xxx.errors.ts 格式(kebab-case)`},{pattern:/\.utils\.ts$/,caseStyle:`kebab-case`,description:`工具函数文件应使用 xxx.utils.ts 格式(kebab-case)`},{pattern:/\.constants\.ts$/,caseStyle:`kebab-case`,description:`常量文件应使用 xxx.constants.ts 格式(kebab-case)`},{pattern:/\.atom\.ts$/,caseStyle:`kebab-case`,description:`Atom 文件应使用 xxx.atom.ts 格式(kebab-case)`},{pattern:/\.vo\.ts$/,caseStyle:`kebab-case`,description:`值对象文件应使用 xxx.vo.ts 格式(kebab-case)`},{pattern:/\.usecase\.ts$/,caseStyle:`kebab-case`,description:`UseCase 文件应使用 xxx.usecase.ts 格式(kebab-case)`},{pattern:/\.styles\.css$/,caseStyle:`kebab-case`,description:`样式文件应使用 xxx.styles.css 格式(kebab-case)`},{pattern:/\.extension\.tsx?$/,caseStyle:`kebab-case`,description:`扩展文件应使用 xxx.extension.ts(x) 格式(kebab-case)`}],p=[{pattern:/^[A-Z][a-zA-Z0-9]*\.types\.ts$/,caseStyle:`PascalCase`,description:`类型文件可使用 PascalCase(如 DataExtractor.types.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.utils\.ts$/,caseStyle:`PascalCase`,description:`工具函数文件可使用 PascalCase(如 DataExtractor.utils.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.constants\.ts$/,caseStyle:`PascalCase`,description:`常量文件可使用 PascalCase(如 ByteVisualizer.constants.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.guards\.ts$/,caseStyle:`PascalCase`,description:`守卫文件可使用 PascalCase(如 DataExtractor.guards.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.helpers\.ts$/,caseStyle:`PascalCase`,description:`辅助函数文件可使用 PascalCase(如 TableVisualizer.helpers.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.groups\.ts$/,caseStyle:`PascalCase`,description:`分组文件可使用 PascalCase(如 TableVisualizer.groups.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.type-guards\.ts$/,caseStyle:`PascalCase`,description:`类型守卫文件可使用 PascalCase(如 TableVisualizer.type-guards.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.test\.ts$/,caseStyle:`PascalCase`,description:`测试文件可使用 PascalCase(如 DataExtractor.test.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.[a-z][-a-z]*\.test\.ts$/,caseStyle:`PascalCase`,description:`伴生测试文件可使用 PascalCase(如 DataExtractor.guards.test.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.[a-z][-a-z]*\.test\.tsx$/,caseStyle:`PascalCase`,description:`伴生测试文件可使用 PascalCase(如 PacketCompare.test.tsx)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.test\.tsx$/,caseStyle:`PascalCase`,description:`测试文件可使用 PascalCase(如 ByteVisualizer.test.tsx)`}],m={pattern:/^[a-z][a-zA-Z0-9_-]*\.tsx$/,caseStyle:`PascalCase`,description:`组件文件应使用 PascalCase(如 ChatPage.tsx),小写开头不允许`},h={pattern:/^[A-Z][a-zA-Z0-9]*\.tsx$/,caseStyle:`PascalCase`,description:`React 组件文件可使用 PascalCase(如 ChatPage.tsx)`},g=[...d,...p,...f,m,h];function _(e){return/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(e)}function v(e){return e.split(`.`).every(e=>_(e)&&e.length>0)}function y(e){return/^[A-Z][a-zA-Z0-9]*$/.test(e)}function b(e){return/^[a-z][a-zA-Z0-9]*$/.test(e)}function x(e){let t=e.split(`.`)[0];return t!==void 0&&t.length>0&&y(t)}function S(e){return e.split(`.`).every(e=>_(e)&&e.length>0)}function ee(e,t){switch(t){case`kebab-case`:return v(e);case`PascalCase`:return y(e);case`camelCase`:return b(e);case`kebab-case-test`:return S(e);default:return!0}}function te(e){return/^v\d+(-[a-z0-9-]+)?\.ts$/.test(e)}function C(e){let t=e.replace(/\.tsx?$/,``);for(let e of u){if(t.endsWith(`.${e}`))return e;let n=t.split(`.`);if(n.length>=2&&n[n.length-1]===e)return e}return null}function w(e){return!!(l.includes(e)||e.endsWith(`.d.ts`)||te(e)||e.startsWith(`[`)||e.startsWith(`_`))}function T(e,t){let n=e.replace(/\\/g,`/`);for(let e of t){let t=e.replace(/[.+^${}()|[\]\\]/g,`\\$&`).replace(/\*\*\//g,`<<DOUBLE_STAR_SLASH>>`).replace(/\*\*/g,`<<DOUBLE_STAR>>`).replace(/\*/g,`[^/]*`).replace(/<<DOUBLE_STAR_SLASH>>/g,`(.*\\/)?`).replace(/<<DOUBLE_STAR>>/g,`.*`);if(RegExp(`.*${t}`).test(n))return!0}return!1}function E(e,t){if(t===h)return e.replace(/\.tsx$/,``);let n=t.pattern.source;if(n.startsWith(`^`)&&n.endsWith(`$`)){if(n.includes(`\\.test\\.`)||n.includes(`\\.spec\\.`))return e.replace(/\.(test|spec)\.(tsx?|jsx?)$/,``);let t=e.match(/^([A-Z][a-zA-Z0-9]*)\.[a-z][-a-z]*\.tsx?$/);return t&&t[1]?t[1]:n.includes(`\\.types\\.`)?e.replace(/\.types\.ts$/,``):e.replace(/\.[^.]+$/,``)}return e.replace(t.pattern,``)}[...l];const D=/* @__PURE__ */ new Map;function O(e){let t=D.get(e);if(t!==void 0)return t;let n;try{n=r(e)}catch{n=!1}return D.set(e,n),n}const k=/^([A-Z][a-zA-Z0-9]*)\.[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*\.ts$/;function A(e){return e.match(k)?.[1]??null}function j(e,t){let n=A(t);if(!n)return!1;let r=`${n}.tsx`,i=e.substring(0,e.lastIndexOf(`/`));return O(a.join(i,r))}function M(e){let t=e.replace(/\.(test|spec)\.(tsx|ts)$/,``);return y(t)||x(t)}function N(e,t){if(!(t.endsWith(`.test.tsx`)||t.endsWith(`.spec.tsx`)||t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`))||!M(t))return{status:`not-component-test`};let n=t.replace(/\.(test|spec)\.(tsx|ts)$/,`.tsx`),r=t.replace(/\.(test|spec)\.(tsx|ts)$/,`.ts`);if(e.includes(`/__tests__/`))return F(e,n)||F(e,r)?{status:`component-test-found`}:{status:`not-component-test`};if(e.includes(`/components/`)){let t=e.substring(0,e.lastIndexOf(`/`)),i=e.indexOf(`/components/`),o=e.substring(0,i+11),s=t;for(;;){if(P(s,n)||P(s,r))return{status:`component-test-found`};if(s===o)break;let e=a.dirname(s);if(e===s)break;s=e}}return{status:`not-component-test`}}function P(e,t){if(O(a.join(e,t)))return!0;try{let n=i(e,{withFileTypes:!0});for(let r of n)if(r.isDirectory()&&O(a.join(e,r.name,t)))return!0}catch{}return!1}function F(e,t){let n=e.indexOf(`/__tests__/`),r=e.substring(0,n),i=e.substring(n+11),o=a.dirname(i),s=o===`.`?r:a.join(r,o);for(;;){if(P(s,t))return!0;if(s===r)break;let e=a.dirname(s);if(e===s)break;s=e}return!1}function I(e){return typeof e==`object`&&!!e}function L(e,t){let n=I(t)?t:void 0;return!!(n?.skipPatterns?.length&&T(e,n.skipPatterns))}const R=t({meta:{type:`problem`,docs:{description:`强制执行文件命名规范`},schema:[{type:`object`,properties:{skipPatterns:{type:`array`,items:{type:`string`}}},additionalProperties:!1}]},createOnce(e){return{before(){if(L(e.filename,e.options?.[0])||w(e.filename.replace(/\\/g,`/`).split(`/`).pop()??``))return!1},Program(t){if(L(e.filename,e.options?.[0]))return;let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=e.filename.replace(/\\/g,`/`),i=C(n);if(i!==`hooks`&&j(r,n))return;if(N(r,n).status===`component-test-found`){let e=n.replace(/\.(test|spec)\.(tsx|ts)$/,``);if(y(e)||x(e))return}if(i!==null){let r=i===`hooks`?`hook 文件应使用 use 前缀小驼峰且不带后缀,如 useRepos.ts`:i===`component`?`组件文件应使用大驼峰且不带后缀,如 RepoList.tsx`:`.${i} 后缀语义过于泛化,请改用具体语义后缀`;e.report({node:t,message:`文件命名违规: ${n}。禁用 .${i} 后缀,${r}`});return}let a=g.find(e=>e.pattern.test(n));a&&(ee(E(n,a),a.caseStyle)||e.report({node:t,message:`文件命名违规: ${n}。${a.description}`}))}}}}),ne=[`.types.ts`,`.types.d.ts`];function z(e){return ne.some(t=>e.endsWith(t))}const B=t({meta:{type:`problem`,docs:{description:`强制执行 types 文件中的接口命名规范(禁止 I 前缀)`}},createOnce(t){return{before(){let e=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(e.endsWith(`.test.ts`)||e.endsWith(`.spec.ts`)||!z(e))return!1},TSInterfaceDeclaration(n){let r=n.id.name;e(r)&&t.report({node:n,message:`类型文件中的接口名 "${r}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${r.substring(1)}"`})}}}}),V=[`impl`,`functions`,`methods`,`handlers`,`classes`,`class`,`manager`,`object`,`processor`,`process`,`common`,`logic`],H=/* @__PURE__ */ new Set([`index.ts`,`index.tsx`,`main.ts`,`main.tsx`,`App.tsx`,`types.ts`,`errors.ts`,`constants.ts`,`types.d.ts`,`persistence.ts`,`typeorm.ts`,`migrate.ts`,`seed.ts`,`hono.ts`,`react.ts`,`vue.ts`,`next.ts`,`electron.ts`,`browser.ts`,`node.ts`]);function U(e){if(!e.endsWith(`.ts`)&&!e.endsWith(`.tsx`))return!1;let t=e.replace(/\.tsx?$/,``);return/^use[A-Z][a-zA-Z0-9]*$/.test(t)}function W(e){if(!e.endsWith(`.tsx`))return!1;let t=e.replace(`.tsx`,``);return/^[A-Z][a-zA-Z0-9]*$/.test(t)}function G(e){return/^v\d+(-[a-z0-9-]+)?\.ts$/.test(e)}function K(e){let t=e.replace(/\.tsx?$/,``);return[/s$/,/es$/,/ies$/].some(e=>e.test(t))}function q(e){return e.endsWith(`.types.ts`)?!0:/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.tsx?$/.test(e)||/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.tsx?$/.test(e)}function J(e){let t=e.replace(/\.tsx?$/,``);for(let e of V){if(t.endsWith(`.${e}`))return e;let n=t.split(`.`);if(n.length>=2&&n[n.length-1]===e)return e}return null}function Y(e){let t=[],n=e.replace(/\.tsx?$/,``);return(n.includes(`service`)||n.includes(`Service`))&&t.push(`.service.ts`),(n.includes(`controller`)||n.includes(`Controller`))&&t.push(`.controller.ts`),(n.includes(`utils`)||n.includes(`helper`))&&t.push(`.utils.ts`),(n.includes(`constant`)||n.includes(`Constant`))&&t.push(`.constants.ts`),(n.includes(`config`)||n.includes(`Config`))&&t.push(`.config.ts`),t.length===0&&t.push(`.utils.ts`,`.config.ts`,`.constants.ts`),t}function X(e){for(let t of[`.test.ts`,`.test.tsx`,`.spec.ts`,`.spec.tsx`])if(e.endsWith(t)){let n=t.endsWith(`.tsx`)?`.tsx`:`.ts`;return e.replace(t,n)}return e}function Z(e){return typeof e==`object`&&!!e}function re(e,t,n,r){return!!(n?.skipPatterns&&T(r,n.skipPatterns)||H.has(t)||t.endsWith(`.d.ts`)||e.startsWith(`[`)||e.startsWith(`_`)||t.endsWith(`.tsx`)||e.endsWith(`.test.ts`)||e.endsWith(`.test.tsx`)||e.endsWith(`.spec.ts`)||e.endsWith(`.spec.tsx`)||G(t)||W(t)||U(t)||!J(t)&&K(t))}const Q=t({meta:{type:`problem`,docs:{description:`强制执行文件类型后缀规范,确保文件名明确表达其用途`},schema:[{type:`object`,properties:{skipPatterns:{type:`array`,items:{type:`string`}}},additionalProperties:!1}]},createOnce(e){return{Program(t){let n=e.options?.[0],r=Z(n)?n:void 0,i=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,a=X(i);if(re(i,a,r,e.filename))return;let o=J(a);if(o){e.report({node:t,message:`文件 "${i}" 使用了禁止的后缀 ".${o}"。该后缀语义过于泛化,无法表达文件用途。请使用更具体的后缀,如 ".utils"、".service" 等。`});return}if(q(a))return;let s=Y(a);e.report({node:t,message:`文件 "${i}" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: ${s.join(`, `)}`})}}}}),$=n({meta:{name:`@longzai-intelligence-oxlint/file-naming-plugin`},rules:{"file-naming":R,"require-type-naming":B,"require-type-suffix":Q}});export{$ as default,$ as fileNamingPlugin,R as fileNamingRule,B as requireTypeNamingRule,Q as requireTypeSuffixRule};
1
+ import"../rolldown-runtime-BqT_7tdF.js";import{n as e}from"../dist-CskvMq7J.js";import{defineRule as t,eslintCompatPlugin as n}from"@oxlint/plugins";import{existsSync as r,readdirSync as i}from"node:fs";import a from"node:path";const o=[`index.ts`,`index.tsx`,`main.ts`,`main.tsx`,`App.tsx`],s=[`types.ts`,`errors.ts`,`constants.ts`],c=[`persistence.ts`,`typeorm.ts`,`hono.ts`,`react.ts`,`vue.ts`,`next.ts`,`electron.ts`,`browser.ts`,`node.ts`],l=[...o,...s,...c],u=[`impl`,`functions`,`methods`,`handlers`,`classes`,`class`,`manager`,`object`,`processor`,`process`,`common`,`logic`,`hooks`,`component`],d=[{pattern:/^use[A-Z][a-zA-Z]*\.spec\.tsx?$/,caseStyle:`camelCase`,description:`Hook 测试文件应使用 camelCase 并以 use 前缀开头(如 useChat.spec.ts)`},{pattern:/^use[A-Z][a-zA-Z]*\.test\.tsx?$/,caseStyle:`camelCase`,description:`Hook 测试文件应使用 camelCase 并以 use 前缀开头(如 useChat.test.ts)`},{pattern:/^use[A-Z][a-zA-Z]*\.types\.ts$/,caseStyle:`camelCase`,description:`Hook 类型文件应使用 camelCase 并以 use 前缀开头(如 useChat.types.ts)`},{pattern:/\.spec\.ts$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.spec.ts 格式(kebab-case)`},{pattern:/\.test\.ts$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.test.ts 格式(kebab-case)`},{pattern:/\.spec\.tsx$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.spec.tsx 格式(kebab-case)`},{pattern:/\.test\.tsx$/,caseStyle:`kebab-case-test`,description:`测试文件应使用 xxx.test.tsx 格式(kebab-case)`},{pattern:/^use[A-Z][a-zA-Z]*\.tsx?$/,caseStyle:`camelCase`,description:`Hook 文件应使用 camelCase 并以 use 前缀开头(如 useChat.ts)`}],f=[{pattern:/\.service\.drizzle\.ts$/,caseStyle:`kebab-case`,description:`Drizzle Service 文件应使用 xxx.service.drizzle.ts 格式(kebab-case)`},{pattern:/\.service\.memory\.ts$/,caseStyle:`kebab-case`,description:`Memory Service 文件应使用 xxx.service.memory.ts 格式(kebab-case)`},{pattern:/\.service\.ts$/,caseStyle:`kebab-case`,description:`服务文件应使用 xxx.service.ts 格式(kebab-case)`},{pattern:/\.controller\.ts$/,caseStyle:`kebab-case`,description:`控制器文件应使用 xxx.controller.ts 格式(kebab-case)`},{pattern:/\.module\.ts$/,caseStyle:`kebab-case`,description:`模块文件应使用 xxx.module.ts 格式(kebab-case)`},{pattern:/\.repository\.drizzle\.ts$/,caseStyle:`kebab-case`,description:`Drizzle Repository 文件应使用 xxx.repository.drizzle.ts 格式(kebab-case)`},{pattern:/\.repository\.memory\.ts$/,caseStyle:`kebab-case`,description:`Memory Repository 文件应使用 xxx.repository.memory.ts 格式(kebab-case)`},{pattern:/\.repository\.interface\.ts$/,caseStyle:`kebab-case`,description:`Repository 接口文件应使用 xxx.repository.interface.ts 格式(kebab-case)`},{pattern:/\.repository\.types\.ts$/,caseStyle:`kebab-case`,description:`Repository 类型文件应使用 xxx.repository.types.ts 格式(kebab-case)`},{pattern:/\.repository\.ts$/,caseStyle:`kebab-case`,description:`Repository 文件应使用 xxx.repository.ts 格式(kebab-case)`},{pattern:/\.entity\.types\.ts$/,caseStyle:`kebab-case`,description:`Entity 类型文件应使用 xxx.entity.types.ts 格式(kebab-case)`},{pattern:/\.entity\.interface\.ts$/,caseStyle:`kebab-case`,description:`Entity 接口文件应使用 xxx.entity.interface.ts 格式(kebab-case)`},{pattern:/\.entity\.ts$/,caseStyle:`kebab-case`,description:`Entity 文件应使用 xxx.entity.ts 格式(kebab-case)`},{pattern:/\.dto\.ts$/,caseStyle:`kebab-case`,description:`DTO 文件应使用 xxx.dto.ts 格式(kebab-case)`},{pattern:/\.port\.interface\.ts$/,caseStyle:`kebab-case`,description:`Port 接口文件应使用 xxx.port.interface.ts 格式(kebab-case)`},{pattern:/\.interface\.ts$/,caseStyle:`kebab-case`,description:`接口文件应使用 xxx.interface.ts 格式(kebab-case)`},{pattern:/\.interface\.tsx$/,caseStyle:`kebab-case`,description:`接口文件应使用 xxx.interface.tsx 格式(kebab-case)`},{pattern:/\.types\.ts$/,caseStyle:`kebab-case`,description:`类型文件应使用 xxx.types.ts 格式(kebab-case)`},{pattern:/\.schema\.ts$/,caseStyle:`kebab-case`,description:`Schema 文件应使用 xxx.schema.ts 格式(kebab-case)`},{pattern:/\.port\.ts$/,caseStyle:`kebab-case`,description:`Port 文件应使用 xxx.port.ts 格式(kebab-case)`},{pattern:/\.port-adapter\.factory\.ts$/,caseStyle:`kebab-case`,description:`Port Adapter Factory 文件应使用 xxx.port-adapter.factory.ts 格式(kebab-case)`},{pattern:/\.port-adapter\.ts$/,caseStyle:`kebab-case`,description:`Port Adapter 文件应使用 xxx.port-adapter.ts 格式(kebab-case)`},{pattern:/\.adapter\.ts$/,caseStyle:`kebab-case`,description:`Adapter 文件应使用 xxx.adapter.ts 格式(kebab-case)`},{pattern:/\.client\.ts$/,caseStyle:`kebab-case`,description:`客户端文件应使用 xxx.client.ts 格式(kebab-case)`},{pattern:/\.events\.ts$/,caseStyle:`kebab-case`,description:`Events 文件应使用 xxx.events.ts 格式(kebab-case)`},{pattern:/\.mapper\.ts$/,caseStyle:`kebab-case`,description:`Mapper 文件应使用 xxx.mapper.ts 格式(kebab-case)`},{pattern:/\.ipc\.ts$/,caseStyle:`kebab-case`,description:`IPC 文件应使用 xxx.ipc.ts 格式(kebab-case)`},{pattern:/\.config\.ts$/,caseStyle:`kebab-case`,description:`配置文件应使用 xxx.config.ts 格式(kebab-case)`},{pattern:/\.errors\.ts$/,caseStyle:`kebab-case`,description:`错误文件应使用 xxx.errors.ts 格式(kebab-case)`},{pattern:/\.utils\.ts$/,caseStyle:`kebab-case`,description:`工具函数文件应使用 xxx.utils.ts 格式(kebab-case)`},{pattern:/\.constants\.ts$/,caseStyle:`kebab-case`,description:`常量文件应使用 xxx.constants.ts 格式(kebab-case)`},{pattern:/\.atom\.ts$/,caseStyle:`kebab-case`,description:`Atom 文件应使用 xxx.atom.ts 格式(kebab-case)`},{pattern:/\.vo\.ts$/,caseStyle:`kebab-case`,description:`值对象文件应使用 xxx.vo.ts 格式(kebab-case)`},{pattern:/\.usecase\.ts$/,caseStyle:`kebab-case`,description:`UseCase 文件应使用 xxx.usecase.ts 格式(kebab-case)`},{pattern:/\.styles\.css$/,caseStyle:`kebab-case`,description:`样式文件应使用 xxx.styles.css 格式(kebab-case)`},{pattern:/\.extension\.tsx?$/,caseStyle:`kebab-case`,description:`扩展文件应使用 xxx.extension.ts(x) 格式(kebab-case)`}],p=[{pattern:/^[A-Z][a-zA-Z0-9]*\.types\.ts$/,caseStyle:`PascalCase`,description:`类型文件可使用 PascalCase(如 DataExtractor.types.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.utils\.ts$/,caseStyle:`PascalCase`,description:`工具函数文件可使用 PascalCase(如 DataExtractor.utils.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.constants\.ts$/,caseStyle:`PascalCase`,description:`常量文件可使用 PascalCase(如 ByteVisualizer.constants.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.guards\.ts$/,caseStyle:`PascalCase`,description:`守卫文件可使用 PascalCase(如 DataExtractor.guards.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.helpers\.ts$/,caseStyle:`PascalCase`,description:`辅助函数文件可使用 PascalCase(如 TableVisualizer.helpers.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.groups\.ts$/,caseStyle:`PascalCase`,description:`分组文件可使用 PascalCase(如 TableVisualizer.groups.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.type-guards\.ts$/,caseStyle:`PascalCase`,description:`类型守卫文件可使用 PascalCase(如 TableVisualizer.type-guards.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.test\.ts$/,caseStyle:`PascalCase`,description:`测试文件可使用 PascalCase(如 DataExtractor.test.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.[a-z][-a-z]*\.test\.ts$/,caseStyle:`PascalCase`,description:`伴生测试文件可使用 PascalCase(如 DataExtractor.guards.test.ts)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.[a-z][-a-z]*\.test\.tsx$/,caseStyle:`PascalCase`,description:`伴生测试文件可使用 PascalCase(如 PacketCompare.test.tsx)`},{pattern:/^[A-Z][a-zA-Z0-9]*\.test\.tsx$/,caseStyle:`PascalCase`,description:`测试文件可使用 PascalCase(如 ByteVisualizer.test.tsx)`}],m={pattern:/^[a-z][a-zA-Z0-9_-]*\.tsx$/,caseStyle:`PascalCase`,description:`组件文件应使用 PascalCase(如 ChatPage.tsx),小写开头不允许`},h={pattern:/^[A-Z][a-zA-Z0-9]*\.tsx$/,caseStyle:`PascalCase`,description:`React 组件文件可使用 PascalCase(如 ChatPage.tsx)`},g=[...d,...p,...f,m,h];function _(e){return/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(e)}function v(e){return e.split(`.`).every(e=>_(e)&&e.length>0)}function y(e){return/^[A-Z][a-zA-Z0-9]*$/.test(e)}function b(e){return/^[a-z][a-zA-Z0-9]*$/.test(e)}function x(e){let t=e.split(`.`)[0];return t!==void 0&&t.length>0&&y(t)}function S(e){return e.split(`.`).every(e=>_(e)&&e.length>0)}function ee(e,t){switch(t){case`kebab-case`:return v(e);case`PascalCase`:return y(e);case`camelCase`:return b(e);case`kebab-case-test`:return S(e);default:return!0}}function te(e){return/^v\d+(-[a-z0-9-]+)?\.ts$/.test(e)}function C(e){let t=e.replace(/\.tsx?$/,``);for(let e of u){if(t.endsWith(`.${e}`))return e;let n=t.split(`.`);if(n.length>=2&&n[n.length-1]===e)return e}return null}function w(e){return!!(l.includes(e)||e.endsWith(`.d.ts`)||te(e)||e.startsWith(`[`)||e.startsWith(`_`))}function T(e,t){let n=e.replace(/\\/g,`/`);for(let e of t){let t=e.replace(/[.+^${}()|[\]\\]/g,`\\$&`).replace(/\*\*\//g,`<<DOUBLE_STAR_SLASH>>`).replace(/\*\*/g,`<<DOUBLE_STAR>>`).replace(/\*/g,`[^/]*`).replace(/<<DOUBLE_STAR_SLASH>>/g,`(.*\\/)?`).replace(/<<DOUBLE_STAR>>/g,`.*`);if(RegExp(`.*${t}`).test(n))return!0}return!1}function E(e,t){if(t===h)return e.replace(/\.tsx$/,``);let n=t.pattern.source;if(n.startsWith(`^`)&&n.endsWith(`$`)){if(n.includes(`\\.test\\.`)||n.includes(`\\.spec\\.`))return e.replace(/\.(test|spec)\.(tsx?|jsx?)$/,``);let t=e.match(/^([A-Z][a-zA-Z0-9]*)\.[a-z][-a-z]*\.tsx?$/);return t&&t[1]?t[1]:n.includes(`\\.types\\.`)?e.replace(/\.types\.ts$/,``):e.replace(/\.[^.]+$/,``)}return e.replace(t.pattern,``)}[...l];const D=/* @__PURE__ */ new Map;function O(e){let t=D.get(e);if(t!==void 0)return t;let n;try{n=r(e)}catch{n=!1}return D.set(e,n),n}const k=/^([A-Z][a-zA-Z0-9]*)\.[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*\.ts$/;function A(e){return e.match(k)?.[1]??null}function j(e,t){let n=A(t);if(!n)return!1;let r=`${n}.tsx`,i=e.substring(0,e.lastIndexOf(`/`));return O(a.join(i,r))}function M(e){let t=e.replace(/\.(test|spec)\.(tsx|ts)$/,``);return y(t)||x(t)}function N(e,t){if(!(t.endsWith(`.test.tsx`)||t.endsWith(`.spec.tsx`)||t.endsWith(`.test.ts`)||t.endsWith(`.spec.ts`))||!M(t))return{status:`not-component-test`};let n=t.replace(/\.(test|spec)\.(tsx|ts)$/,`.tsx`),r=t.replace(/\.(test|spec)\.(tsx|ts)$/,`.ts`);if(e.includes(`/__tests__/`))return F(e,n)||F(e,r)?{status:`component-test-found`}:{status:`not-component-test`};if(e.includes(`/components/`)){let t=e.substring(0,e.lastIndexOf(`/`)),i=e.indexOf(`/components/`),o=e.substring(0,i+11),s=t;for(;;){if(P(s,n)||P(s,r))return{status:`component-test-found`};if(s===o)break;let e=a.dirname(s);if(e===s)break;s=e}}return{status:`not-component-test`}}function P(e,t){if(O(a.join(e,t)))return!0;try{let n=i(e,{withFileTypes:!0});for(let r of n)if(r.isDirectory()&&O(a.join(e,r.name,t)))return!0}catch{}return!1}function F(e,t){let n=e.indexOf(`/__tests__/`),r=e.substring(0,n),i=e.substring(n+11),o=a.dirname(i),s=o===`.`?r:a.join(r,o);for(;;){if(P(s,t))return!0;if(s===r)break;let e=a.dirname(s);if(e===s)break;s=e}return!1}function I(e){return typeof e==`object`&&!!e}function L(e,t){let n=I(t)?t:void 0;return!!(n?.skipPatterns?.length&&T(e,n.skipPatterns))}const R=t({meta:{type:`problem`,docs:{description:`强制执行文件命名规范`},schema:[{type:`object`,properties:{skipPatterns:{type:`array`,items:{type:`string`}}},additionalProperties:!1}]},createOnce(e){return{before(){if(L(e.filename,e.options?.[0])||w(e.filename.replace(/\\/g,`/`).split(`/`).pop()??``))return!1},Program(t){if(L(e.filename,e.options?.[0]))return;let n=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,r=e.filename.replace(/\\/g,`/`),i=C(n);if(i!==`hooks`&&j(r,n))return;if(N(r,n).status===`component-test-found`){let e=n.replace(/\.(test|spec)\.(tsx|ts)$/,``);if(y(e)||x(e))return}if(i!==null){let r=i===`hooks`?`hook 文件应使用 use 前缀小驼峰且不带后缀,如 useRepos.ts`:i===`component`?`组件文件应使用大驼峰且不带后缀,如 RepoList.tsx`:`.${i} 后缀语义过于泛化,请改用具体语义后缀`;e.report({node:t,message:`文件命名违规: ${n}。禁用 .${i} 后缀,${r}`});return}let a=g.find(e=>e.pattern.test(n));a&&(ee(E(n,a),a.caseStyle)||e.report({node:t,message:`文件命名违规: ${n}。${a.description}`}))}}}}),ne=[`.types.ts`,`.types.d.ts`];function z(e){return ne.some(t=>e.endsWith(t))}const B=t({meta:{type:`problem`,docs:{description:`强制执行 types 文件中的接口命名规范(禁止 I 前缀)`}},createOnce(t){return{before(){let e=t.filename.replace(/\\/g,`/`).split(`/`).pop()??``;if(e.endsWith(`.test.ts`)||e.endsWith(`.spec.ts`)||!z(e))return!1},TSInterfaceDeclaration(n){let r=n.id.name;e(r)&&t.report({node:n,message:`类型文件中的接口名 "${r}" 使用了 I 前缀。现代 TypeScript 不推荐使用匈牙利命名法,建议使用 "${r.substring(1)}"`})}}}}),V=[`impl`,`functions`,`methods`,`handlers`,`classes`,`class`,`manager`,`object`,`processor`,`process`,`common`,`logic`],H=/* @__PURE__ */ new Set([`index.ts`,`index.tsx`,`main.ts`,`main.tsx`,`App.tsx`,`bootstrap.ts`,`types.ts`,`errors.ts`,`constants.ts`,`types.d.ts`,`persistence.ts`,`typeorm.ts`,`migrate.ts`,`seed.ts`,`hono.ts`,`react.ts`,`vue.ts`,`next.ts`,`electron.ts`,`browser.ts`,`node.ts`]);function U(e){if(!e.endsWith(`.ts`)&&!e.endsWith(`.tsx`))return!1;let t=e.replace(/\.tsx?$/,``);return/^use[A-Z][a-zA-Z0-9]*$/.test(t)}function W(e){if(!e.endsWith(`.tsx`))return!1;let t=e.replace(`.tsx`,``);return/^[A-Z][a-zA-Z0-9]*$/.test(t)}function G(e){return/^v\d+(-[a-z0-9-]+)?\.ts$/.test(e)}function K(e){let t=e.replace(/\.tsx?$/,``);return[/s$/,/es$/,/ies$/].some(e=>e.test(t))}function q(e){return e.endsWith(`.types.ts`)?!0:/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.tsx?$/.test(e)||/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*\.tsx?$/.test(e)}function J(e){let t=e.replace(/\.tsx?$/,``);for(let e of V){if(t.endsWith(`.${e}`))return e;let n=t.split(`.`);if(n.length>=2&&n[n.length-1]===e)return e}return null}function Y(e){let t=[],n=e.replace(/\.tsx?$/,``);return(n.includes(`service`)||n.includes(`Service`))&&t.push(`.service.ts`),(n.includes(`controller`)||n.includes(`Controller`))&&t.push(`.controller.ts`),(n.includes(`utils`)||n.includes(`helper`))&&t.push(`.utils.ts`),(n.includes(`constant`)||n.includes(`Constant`))&&t.push(`.constants.ts`),(n.includes(`config`)||n.includes(`Config`))&&t.push(`.config.ts`),t.length===0&&t.push(`.utils.ts`,`.config.ts`,`.constants.ts`),t}function X(e){for(let t of[`.test.ts`,`.test.tsx`,`.spec.ts`,`.spec.tsx`])if(e.endsWith(t)){let n=t.endsWith(`.tsx`)?`.tsx`:`.ts`;return e.replace(t,n)}return e}function Z(e){return typeof e==`object`&&!!e}function re(e,t,n,r){return!!(n?.skipPatterns&&T(r,n.skipPatterns)||H.has(t)||t.endsWith(`.d.ts`)||e.startsWith(`[`)||e.startsWith(`_`)||t.endsWith(`.tsx`)||e.endsWith(`.test.ts`)||e.endsWith(`.test.tsx`)||e.endsWith(`.spec.ts`)||e.endsWith(`.spec.tsx`)||G(t)||W(t)||U(t)||!J(t)&&K(t))}const Q=t({meta:{type:`problem`,docs:{description:`强制执行文件类型后缀规范,确保文件名明确表达其用途`},schema:[{type:`object`,properties:{skipPatterns:{type:`array`,items:{type:`string`}}},additionalProperties:!1}]},createOnce(e){return{Program(t){let n=e.options?.[0],r=Z(n)?n:void 0,i=e.filename.replace(/\\/g,`/`).split(`/`).pop()??``,a=X(i);if(re(i,a,r,e.filename))return;let o=J(a);if(o){e.report({node:t,message:`文件 "${i}" 使用了禁止的后缀 ".${o}"。该后缀语义过于泛化,无法表达文件用途。请使用更具体的后缀,如 ".utils"、".service" 等。`});return}if(q(a))return;let s=Y(a);e.report({node:t,message:`文件 "${i}" 缺少类型后缀。除特殊文件外,所有文件应使用 xxx.yyy.ts 格式明确表达用途。建议: ${s.join(`, `)}`})}}}}),$=n({meta:{name:`@longzai-intelligence-oxlint/file-naming-plugin`},rules:{"file-naming":R,"require-type-naming":B,"require-type-suffix":Q}});export{$ as default,$ as fileNamingPlugin,R as fileNamingRule,B as requireTypeNamingRule,Q as requireTypeSuffixRule};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-oxlint/presets",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Longzai Intelligence oxlint 配置预设",
5
5
  "keywords": [
6
6
  "config",
@@ -100,33 +100,33 @@
100
100
  "zod": "^4.4.3"
101
101
  },
102
102
  "devDependencies": {
103
- "@longzai-intelligence-oxlint/architecture-core-plugin": "0.2.1",
104
- "@longzai-intelligence-oxlint/architecture-electron-plugin": "0.2.1",
105
- "@longzai-intelligence-oxlint/architecture-library-plugin": "0.2.1",
106
- "@longzai-intelligence-oxlint/code-style-plugin": "0.2.1",
107
- "@longzai-intelligence-oxlint/composer-plugin": "0.2.1",
108
- "@longzai-intelligence-oxlint/core": "0.2.1",
109
- "@longzai-intelligence-oxlint/design-rules-plugin": "0.2.1",
110
- "@longzai-intelligence-oxlint/elysia-route-plugin": "0.2.1",
111
- "@longzai-intelligence-oxlint/eslint-config-plugin": "0.2.1",
112
- "@longzai-intelligence-oxlint/file-naming-plugin": "0.2.1",
113
- "@longzai-intelligence-oxlint/lzi-builder-config-plugin": "0.2.1",
114
- "@longzai-intelligence-oxlint/lzi-config-plugin": "0.2.1",
115
- "@longzai-intelligence-oxlint/nestjs-route-plugin": "0.2.1",
116
- "@longzai-intelligence-oxlint/package-json-plugin": "0.2.1",
117
- "@longzai-intelligence-oxlint/perfectionist-plugin": "0.2.1",
118
- "@longzai-intelligence-oxlint/react-plugin": "0.2.1",
119
- "@longzai-intelligence-oxlint/schema-type-separation-plugin": "0.2.1",
120
- "@longzai-intelligence-oxlint/stylistic-plugin": "0.2.1",
121
- "@longzai-intelligence-oxlint/tsconfig-plugin": "0.2.1",
122
- "@longzai-intelligence-oxlint/tsdoc-plugin": "0.2.1",
123
- "@longzai-intelligence-oxlint/tsdown-config-plugin": "0.2.1",
124
- "@longzai-intelligence-oxlint/tsup-config-plugin": "0.2.1",
125
- "@longzai-intelligence-oxlint/typeorm-plugin": "0.2.1",
126
- "@longzai-intelligence-oxlint/typescript-eslint-plugin": "0.2.1",
127
- "@longzai-intelligence-oxlint/utils": "0.2.1",
128
- "@longzai-intelligence-oxlint/vitest-config-plugin": "0.2.1",
129
- "@longzai-intelligence-oxlint/zod-plugin": "0.2.1",
103
+ "@longzai-intelligence-oxlint/architecture-core-plugin": "0.2.3",
104
+ "@longzai-intelligence-oxlint/architecture-electron-plugin": "0.2.3",
105
+ "@longzai-intelligence-oxlint/architecture-library-plugin": "0.2.3",
106
+ "@longzai-intelligence-oxlint/code-style-plugin": "0.2.3",
107
+ "@longzai-intelligence-oxlint/composer-plugin": "0.2.3",
108
+ "@longzai-intelligence-oxlint/core": "0.2.3",
109
+ "@longzai-intelligence-oxlint/design-rules-plugin": "0.2.3",
110
+ "@longzai-intelligence-oxlint/elysia-route-plugin": "0.2.3",
111
+ "@longzai-intelligence-oxlint/eslint-config-plugin": "0.2.3",
112
+ "@longzai-intelligence-oxlint/file-naming-plugin": "0.2.3",
113
+ "@longzai-intelligence-oxlint/lzi-builder-config-plugin": "0.2.3",
114
+ "@longzai-intelligence-oxlint/lzi-config-plugin": "0.2.3",
115
+ "@longzai-intelligence-oxlint/nestjs-route-plugin": "0.2.3",
116
+ "@longzai-intelligence-oxlint/package-json-plugin": "0.2.3",
117
+ "@longzai-intelligence-oxlint/perfectionist-plugin": "0.2.3",
118
+ "@longzai-intelligence-oxlint/react-plugin": "0.2.3",
119
+ "@longzai-intelligence-oxlint/schema-type-separation-plugin": "0.2.3",
120
+ "@longzai-intelligence-oxlint/stylistic-plugin": "0.2.3",
121
+ "@longzai-intelligence-oxlint/tsconfig-plugin": "0.2.3",
122
+ "@longzai-intelligence-oxlint/tsdoc-plugin": "0.2.3",
123
+ "@longzai-intelligence-oxlint/tsdown-config-plugin": "0.2.3",
124
+ "@longzai-intelligence-oxlint/tsup-config-plugin": "0.2.3",
125
+ "@longzai-intelligence-oxlint/typeorm-plugin": "0.2.3",
126
+ "@longzai-intelligence-oxlint/typescript-eslint-plugin": "0.2.3",
127
+ "@longzai-intelligence-oxlint/utils": "0.2.3",
128
+ "@longzai-intelligence-oxlint/vitest-config-plugin": "0.2.3",
129
+ "@longzai-intelligence-oxlint/zod-plugin": "0.2.3",
130
130
  "@vitest/coverage-v8": "^4.1.10"
131
131
  },
132
132
  "peerDependencies": {