@skapxd/eslint-opinionated 0.15.0 → 0.17.0

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.
Files changed (39) hide show
  1. package/README.md +196 -35
  2. package/dist/astro/index.js +0 -3
  3. package/dist/astro/index.js.map +1 -1
  4. package/dist/astro/index.mjs +2 -2
  5. package/dist/{chunk-O5BXMSNR.mjs → chunk-3GEFHNU7.mjs} +7 -14
  6. package/dist/chunk-3GEFHNU7.mjs.map +1 -0
  7. package/dist/{chunk-OVC5GQV3.mjs → chunk-54EOEKYS.mjs} +2 -2
  8. package/dist/{chunk-DJDXQWCP.mjs → chunk-GSQWHSHV.mjs} +2 -2
  9. package/dist/{chunk-MLFXSEY7.mjs → chunk-PD77UDUY.mjs} +321 -30
  10. package/dist/chunk-PD77UDUY.mjs.map +1 -0
  11. package/dist/{chunk-F6GJW5A4.mjs → chunk-QDQUU6QK.mjs} +49 -37
  12. package/dist/chunk-QDQUU6QK.mjs.map +1 -0
  13. package/dist/cli.js +17 -5
  14. package/dist/cli.js.map +1 -1
  15. package/dist/cli.mjs +17 -5
  16. package/dist/cli.mjs.map +1 -1
  17. package/dist/index.js +377 -78
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +10 -7
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/nest/index.d.mts +11 -13
  22. package/dist/nest/index.d.ts +11 -13
  23. package/dist/nest/index.js +34 -38
  24. package/dist/nest/index.js.map +1 -1
  25. package/dist/nest/index.mjs +2 -2
  26. package/dist/next/index.js +0 -3
  27. package/dist/next/index.js.map +1 -1
  28. package/dist/next/index.mjs +2 -2
  29. package/dist/shared/index.d.mts +51 -14
  30. package/dist/shared/index.d.ts +51 -14
  31. package/dist/shared/index.js +367 -64
  32. package/dist/shared/index.js.map +1 -1
  33. package/dist/shared/index.mjs +2 -2
  34. package/package.json +41 -16
  35. package/dist/chunk-F6GJW5A4.mjs.map +0 -1
  36. package/dist/chunk-MLFXSEY7.mjs.map +0 -1
  37. package/dist/chunk-O5BXMSNR.mjs.map +0 -1
  38. /package/dist/{chunk-OVC5GQV3.mjs.map → chunk-54EOEKYS.mjs.map} +0 -0
  39. /package/dist/{chunk-DJDXQWCP.mjs.map → chunk-GSQWHSHV.mjs.map} +0 -0
package/README.md CHANGED
@@ -98,11 +98,11 @@ la que defiende el axioma más fundamental (el orden es jerárquico).
98
98
 
99
99
  | # | Axioma | Reglas que lo ejecutan |
100
100
  | --- | --- | --- |
101
- | A1 | **Los estados imposibles son irrepresentables.** El tipo modela exactamente los estados válidos; lo inválido no compila. | `prefer-tagged-union-state`, `no-runtime-state-guard`, `requires-strict-tsconfig`, `no-impossible-branch`, `no-explicit-any`, `consistent-type-definitions` |
102
- | A2 | **Ningún efecto es invisible al tipo.** Si una operación puede fallar, su firma lo confiesa — no una convención oral ni un `throw` sorpresa. | `await-requires-result`, `no-try-catch`, `no-promise-chain`, `no-ad-hoc-ok-result`, `@typescript-eslint/no-floating-promises` |
101
+ | A1 | **Los estados imposibles son irrepresentables.** El tipo modela exactamente los estados válidos; lo inválido no compila. | `prefer-tagged-union-state`, `no-runtime-state-guard`, `requires-strict-tsconfig`, `no-impossible-branch`, `no-explicit-any`, `prefer-type-over-interface` |
102
+ | A2 | **Ningún efecto es invisible al tipo.** Si una operación puede fallar, su firma lo confiesa — no una convención oral ni un `throw` sorpresa. | `await-requires-result`, `no-try-catch`, `no-promise-chain`, `no-ad-hoc-ok-result`, `no-floating-promises` |
103
103
  | A3 | **La información no se destruye.** Un error que se transforma conserva su `cause`; uno que se detecta llega a alguien. Nadie decide "esto no importa" en silencio. | `result-error-requires-cause`, `result-error-requires-handling` |
104
104
  | A4 | **Una unidad, una responsabilidad, un nombre semántico.** El árbol de archivos cuenta una historia; una clase expone una intención. | `one-root-function-per-file`, `max-public-methods`, `no-default-export`, `jsx-return-name-pascal-case`, `max-hook-size` |
105
- | A5 | **Las decisiones se declaran, no se interpretan.** Cada rama es explícita y exhaustiva; un caso ignorado es una decisión visible, no un hueco. | `no-else`, `no-nested-if`, `prefer-ts-pattern`, `@typescript-eslint/ban-ts-comment`, el `void promesa()` de `no-floating-promises` |
105
+ | A5 | **Las decisiones se declaran, no se interpretan.** Cada rama es explícita y exhaustiva; un caso ignorado es una decisión visible, no un hueco. | `no-else`, `no-nested-if`, `prefer-ts-pattern`, `no-silenced-compiler`, el `void promesa()` de `no-floating-promises` |
106
106
  | A6 | **Evidencia sobre convención.** Una regla decide por lo que el type-checker o los imports demuestran, no por cómo se llama un archivo o un campo. | la implementación type-aware de las reglas de Result, `nest-no-direct-instantiation` (@Injectable resuelto por símbolo), la exención ORM por decorador de `class-properties-require-readonly` |
107
107
  | A7 | **Las fronteras son explícitas y únicas.** Lo que cruza una capa lo hace por un contrato, una sola vez, sin túneles. | `no-deep-relative-imports`, `no-tunnel-props`, `nest-no-result-response`, `nest-no-swagger-in-controllers`, `nest-no-inline-query-params` |
108
108
  | A8 | **Inmutable por defecto.** La mutación es la excepción que se pide con evidencia, no el estado natural de las cosas. | `class-properties-require-readonly`, `no-accessors` |
@@ -333,7 +333,7 @@ El orden no es arbitrario: va de "cada hallazgo es un bug que ya tienes" hacia
333
333
  **Ola 1 — bugs gratis y fixes únicos.** Señal pura, arreglo puntual, cero
334
334
  rediseño. Aquí el equipo aprende que el linter encuentra cosas reales:
335
335
 
336
- - `@typescript-eslint/no-floating-promises` — cada hallazgo es un error que
336
+ - `skapxd/no-floating-promises` — cada hallazgo es un error que
337
337
  hoy muere sin que nadie lo vea (en un backend real en producción: 12).
338
338
  - `skapxd/nest-requires-swagger-plugin` y `skapxd/nest-validation-pipe-config`
339
339
  — un hallazgo por proyecto, un fix de configuración, y quedan vigiladas las
@@ -398,8 +398,9 @@ diseño, no solo disciplina. Para cuando el equipo ya vio el patrón en la ola 3
398
398
  - `requires-strict-tsconfig` al máximo: `["strict", "noImplicitReturns",
399
399
  "noUncheckedIndexedAccess"]`. Sube un flag a la vez — cada uno aflora
400
400
  errores de compilación que son bugs latentes, no burocracia.
401
- - `@typescript-eslint/no-explicit-any`, `no-non-null-assertion` y
402
- `ban-ts-comment` — se cierran las tres puertas de escape del compilador.
401
+ - `skapxd/no-explicit-any`, `skapxd/no-non-null-assertion` y
402
+ `skapxd/no-silenced-compiler` — se cierran las tres puertas de escape del
403
+ compilador.
403
404
  - `skapxd/class-properties-require-readonly` — el cambio se modela con
404
405
  instancias nuevas.
405
406
  - `skapxd/prefer-tagged-union-state` y `skapxd/no-runtime-state-guard` — los
@@ -677,7 +678,7 @@ Detalles del preset:
677
678
  se escribe `void bootstrap();` — fire-and-forget declarado.
678
679
  - Los specs colocados (`*.spec.ts`, `*.e2e-spec.ts`) relajan
679
680
  `await-requires-result`, `no-try-catch`, `result-error-requires-handling` y
680
- `@typescript-eslint/no-non-null-assertion` (el `!` sobre un fixture es el
681
+ `no-non-null-assertion` (el `!` sobre un fixture es el
681
682
  arrange del test): un test awaitea helpers libremente y descartar un Result
682
683
  en una aserción no es perder un trace. `no-floating-promises` sigue activa
683
684
  en specs: un `await` olvidado es un falso verde.
@@ -747,6 +748,19 @@ export default [
747
748
  ];
748
749
  ```
749
750
 
751
+ Para librerías npm escritas en TypeScript (tsup o equivalente). Trae las
752
+ bases completas + el set type-driven (tipado, con `projectService`) +
753
+ `await-requires-result` + el contrato de empaquetado:
754
+
755
+ - `skapxd/package-requires-typed-exports` — los `exports` del package.json
756
+ cablean los tipos **por condición** (`import` → `.d.mts`, `require` →
757
+ `.d.ts`); el `types` único por subpath es el bug "FalseCJS".
758
+ - `skapxd/untrusted-module-requires-adapter` — inerte hasta que declares tu
759
+ inventario de paquetes con tipos mentirosos (ver su sección).
760
+
761
+ **Este mismo repo se lintea con este preset** — dogfood: la regla de exports
762
+ nos obligó a corregir nuestro propio package.json al nacer.
763
+
750
764
  ### Strict (sin escape via `eslint-disable`)
751
765
 
752
766
  Un prompt o un agente puede saltarse cualquier regla con
@@ -819,14 +833,20 @@ de cada regla):
819
833
  | `no-default-export` | `allowFilePatterns` (globs, aditivos a los integrados) |
820
834
  | `no-else` | `allowFilePatterns` (globs) |
821
835
  | `no-emoji` | `allowFilePatterns` (globs) |
836
+ | `no-explicit-any` | las de la regla original de typescript-eslint (`fixToUnknown`, ...) |
837
+ | `no-floating-promises` | las de la regla original de typescript-eslint (`ignoreVoid`, `allowList`, ...) |
822
838
  | `no-impossible-branch` | las de la regla original de typescript-eslint (`allowConstantLoopConditions`, ...) |
839
+ | `no-silenced-compiler` | las de `ban-ts-comment` (`ts-expect-error`, `ts-ignore`, `ts-nocheck`, `minimumDescriptionLength`) |
840
+ | `prefer-type-over-interface` | la de `consistent-type-definitions` (`"type"` o `"interface"`; los presets pasan `"type"`) |
823
841
  | `no-functions-inside-components` | `allowJsxCallbacks`, `allowArrayMapCallbacks` (ambas `true` por defecto) |
824
842
  | `no-nested-if` | `allowFilePatterns` (globs) |
825
843
  | `no-promise-chain` | `methods` |
826
844
  | `no-runtime-state-guard` | `allowFilePatterns` (globs) |
827
845
  | `no-tunnel-props` | `allowFilePatterns` (globs), `allowPropPatterns` (regex) |
828
846
  | `prefer-abort-signal` | `allowFilePatterns` (globs), `effectNames` (default `["useEffect", "useLayoutEffect"]`) |
847
+ | `package-requires-typed-exports` | `allowFilePatterns` (globs), `anchorFilePatterns` (default `src/index.ts(x)`, `src/main.ts`) |
829
848
  | `prefer-tagged-union-state` | `allowFilePatterns` (globs), `loadingPatterns` (regex, en minúsculas), `errorPatterns` (regex, en minúsculas) |
849
+ | `untrusted-module-requires-adapter` | `modules` (default `[]` — inerte), `adapterFilePatterns` (globs), `allowFilePatterns` (globs) |
830
850
  | `requires-strict-tsconfig` | `allowFilePatterns` (globs), `anchorFilePatterns` (globs), `requiredCompilerOptions` |
831
851
  | `result-error-requires-handling` | `allowFilePatterns` (globs) |
832
852
 
@@ -863,16 +883,23 @@ matchea en cualquier carpeta). Las 7 reglas restantes no tienen opciones: su
863
883
  | `skapxd/no-default-export` | Prohíbe `export default`; el nombre del símbolo es el contrato. Exime configs/stories y, en el preset `next`, los entrypoints del App Router. |
864
884
  | `skapxd/no-else` | Prohíbe `else`/`else if`: el else es el estado sin nombre. Retorno anticipado, ternario simple o `match()`. |
865
885
  | `skapxd/no-emoji` | Prohíbe emojis en strings y JSX; cada sistema los renderiza distinto. Usa un icono SVG. |
886
+ | `skapxd/no-explicit-any` | Prohíbe `any`: apaga el sistema de tipos donde más se necesita. `unknown` para lo desconocido, el tipo real para lo demás. Wrapper de typescript-eslint. |
887
+ | `skapxd/no-floating-promises` | Promesas sin `await` ni `void`: el rechazo muere sin pasar por trySafe. El mensaje corrige el consejo upstream (`.then/.catch` aquí están prohibidos). Wrapper de typescript-eslint. |
866
888
  | `skapxd/no-impossible-branch` | Condiciones que el type-checker demuestra constantes: la pregunta ya tiene respuesta. Es `@typescript-eslint/no-unnecessary-condition` con nombre semántico y mensajes que enseñan el fix. |
867
889
  | `skapxd/no-nested-if` | Prohíbe `if` anidados: retorno anticipado o `match()`. Menos carga cognitiva y sin puntos ciegos para las demás reglas. |
890
+ | `skapxd/no-non-null-assertion` | Prohíbe el `!`: es "cállate, yo sé más que tú" dicho al compilador. Modela el tipo o maneja la duda. Wrapper de typescript-eslint. |
868
891
  | `skapxd/no-runtime-state-guard` | Prohíbe `if (this.x) throw` en métodos: el estado inválido se hace irrepresentable en el tipo, no se vigila en runtime. |
892
+ | `skapxd/no-silenced-compiler` | Prohíbe `@ts-ignore`/`@ts-nocheck`: silenciar la alarma no arregla el incendio. `@ts-expect-error` con descripción queda para tests de tipos. Wrapper de `ban-ts-comment`. |
869
893
  | `skapxd/no-tunnel-props` | Ninguna prop viaja más de un nivel: quien la recibe no puede reenviarla a otro componente. Mata el prop drilling. |
870
894
  | `skapxd/prefer-abort-signal` | Listeners en efectos se limpian con `AbortController` (`{ signal }` + `abort()`), no con `removeEventListener`. |
871
895
  | `skapxd/prefer-tagged-union-state` | Prohíbe estados inconsistentes representables: flag de loading + campo de error independientes → unión etiquetada. |
896
+ | `skapxd/prefer-type-over-interface` | Las uniones discriminadas son types; un `type` no crece en silencio por declaration merging. Wrapper de `consistent-type-definitions`. |
872
897
  | `skapxd/no-functions-inside-components` | Prohíbe definir funciones dentro de componentes React. |
873
898
  | `skapxd/no-try-catch` | Prohíbe `try/catch`; usa `trySafe` de `@skapxd/result`. |
874
899
  | `skapxd/no-promise-chain` | Prohíbe `.then/.catch/.finally`; usa `await` (+ `trySafe`). |
875
900
  | `skapxd/prefer-ts-pattern` | Prohíbe `switch` y ternarios anidados; usa `match()` de ts-pattern. |
901
+ | `skapxd/package-requires-typed-exports` | Los `exports` del package.json declaran `types` por condición (`import` → `.d.mts`, `require` → `.d.ts`): mata el bug FalseCJS. Preset `package`. |
902
+ | `skapxd/untrusted-module-requires-adapter` | Los paquetes con tipos mentirosos (@types desfasados) solo se importan desde su adaptador: la mentira vive en UN archivo. Preset `package`. |
876
903
  | `skapxd/no-jsx-ternary-null` | Prefiere `cond && <El />` sobre `cond ? <El /> : null` en JSX. |
877
904
 
878
905
  ### `skapxd/one-root-function-per-file`
@@ -995,34 +1022,29 @@ Fuera del default, a propósito: `exactOptionalPropertyTypes` y
995
1022
  con muchas librerías — se agregan vía `requiredCompilerOptions` si el
996
1023
  proyecto los soporta.
997
1024
 
998
- Además, los **presets tipados activan reglas curadas de typescript-eslint**
999
- (que ya es peer dependency no se reimplementan):
1000
-
1001
- - `@typescript-eslint/no-explicit-any` `any` apaga el sistema de tipos:
1002
- todo el esfuerzo muere donde aparece uno.
1003
- - `@typescript-eslint/consistent-type-definitions` con `type` — las uniones
1004
- discriminadas son types.
1005
- - `@typescript-eslint/no-floating-promises` cierra el hueco que
1006
- `await-requires-result` no ve: una llamada async **sin** `await` no produce
1007
- `AwaitExpression`, así que el rechazo muere sin pasar por `trySafe`
1008
- (medido: 12 promesas flotantes vivas en un backend Nest real). La única
1009
- salida es `void promesa()`: fire-and-forget declarado y greppeable.
1010
- - `@typescript-eslint/no-non-null-assertion` `!` es "cállate, yo más
1011
- que tú" dicho al compilador. Si no puede ser nulo, que lo diga el tipo.
1012
- (En `nest/tests` queda apagada: el `!` sobre un fixture cuya existencia el
1013
- propio test garantiza es el arrange, no una mentira.)
1014
- - `skapxd/no-impossible-branch` la generalización type-aware de
1015
- `no-runtime-state-guard`: si el tipo dice que un estado es imposible, el
1016
- guard defensivo sobra; si el guard hace falta, lo que está mal es el tipo.
1017
- Es `@typescript-eslint/no-unnecessary-condition` **re-registrada bajo
1018
- nuestro namespace** (ver su sección): mismo motor, nombre que dice lo que
1019
- defiende y mensajes que enseñan el fix. Por eso esta regla y
1020
- `requires-strict-tsconfig` van juntas: sin `noUncheckedIndexedAccess`,
1021
- `array[i]` miente y la regla acusaría guards necesarios.
1022
- - `@typescript-eslint/ban-ts-comment` — un error de tipos se arregla
1023
- modelando mejor, no silenciando la alarma: `@ts-ignore` y `@ts-nocheck`
1024
- prohibidos. `@ts-expect-error` **con descripción** queda permitido: es la
1025
- forma legítima de testear que un estado inválido de verdad no compila.
1025
+ Además, los **presets tipados activan reglas curadas de typescript-eslint**,
1026
+ todas **re-registradas bajo el namespace skapxd** (mismo motor, cero
1027
+ reimplementación — typescript-eslint ya es peer dependency): nombres que
1028
+ dicen lo que defienden, mensajes en español que enseñan el fix, y un solo
1029
+ namespace en toda tu lista de pendientes. Cada una tiene su sección propia:
1030
+
1031
+ - `skapxd/no-explicit-any` — `any` apaga el sistema de tipos: todo el
1032
+ esfuerzo muere donde aparece uno.
1033
+ - `skapxd/prefer-type-over-interface` (era `consistent-type-definitions`)
1034
+ las uniones discriminadas son types.
1035
+ - `skapxd/no-floating-promises` cierra el hueco que `await-requires-result`
1036
+ no ve: una llamada async **sin** `await` no produce `AwaitExpression`, así
1037
+ que el rechazo muere sin pasar por `trySafe` (medido: 12 promesas
1038
+ flotantes vivas en un backend Nest real).
1039
+ - `skapxd/no-non-null-assertion` `!` es "cállate, yo más que tú" dicho
1040
+ al compilador. (En `nest/tests` queda apagada: el `!` sobre un fixture es
1041
+ el arrange, no una mentira.)
1042
+ - `skapxd/no-impossible-branch` (era `no-unnecessary-condition`) la
1043
+ generalización type-aware de `no-runtime-state-guard`. Va de la mano de
1044
+ `requires-strict-tsconfig`: sin `noUncheckedIndexedAccess`, `array[i]`
1045
+ miente y la regla acusaría guards necesarios.
1046
+ - `skapxd/no-silenced-compiler` (era `ban-ts-comment`) un error de tipos
1047
+ se arregla modelando mejor, no silenciando la alarma.
1026
1048
 
1027
1049
  Ausencias deliberadas, no olvidos:
1028
1050
 
@@ -1907,6 +1929,83 @@ del críptico "Unnecessary conditional". Los presets tipados activan este
1907
1929
  nombre y **no** el original: una sola fuente de verdad para configurarla,
1908
1930
  silenciarla o buscarla.
1909
1931
 
1932
+ ### `skapxd/no-explicit-any`
1933
+
1934
+ Prohíbe `any`. No es una regla de estilo: `any` apaga el sistema de tipos en
1935
+ todo lo que toca — el esfuerzo de modelar estados imposibles muere donde
1936
+ aparece uno, y se propaga en silencio a cada valor derivado. El mensaje
1937
+ enseña la salida: `unknown` para lo genuinamente desconocido (obliga a
1938
+ estrechar antes de usar — la duda queda declarada y verificada), el tipo
1939
+ real para lo que tiene forma conocida.
1940
+
1941
+ Bajo el capó es `@typescript-eslint/no-explicit-any`
1942
+ ([doc original](https://typescript-eslint.io/rules/no-explicit-any/))
1943
+ re-registrada bajo nuestro namespace con mensajes que enseñan (ver
1944
+ `skapxd/no-impossible-branch` para el patrón). Los presets tipados activan
1945
+ este nombre, no el original.
1946
+
1947
+ ### `skapxd/no-floating-promises`
1948
+
1949
+ Una llamada async **sin** `await` no produce `AwaitExpression` — es el punto
1950
+ ciego de `await-requires-result`: el rechazo muere sin pasar por `trySafe`,
1951
+ sin trace y sin que nadie lo decidiera (medido al absorberla: 12 promesas
1952
+ flotantes vivas en un backend en producción).
1953
+
1954
+ Esta regla existía en typescript-eslint
1955
+ ([doc original](https://typescript-eslint.io/rules/no-floating-promises/)),
1956
+ pero su mensaje recomendaba *"end with a call to `.catch`, or end with a
1957
+ call to `.then` with a rejection handler"* — **dos caminos que
1958
+ `no-promise-chain` prohíbe**. Obedecer a una regla te estrellaba con la
1959
+ otra. El wrapper corrige el consejo para este sistema: las dos salidas
1960
+ legales son `await` (y ahí entra el pipeline de Result) o `void promesa()`
1961
+ — el fire-and-forget declarado y greppeable del axioma A5 (así se escribe
1962
+ el `bootstrap()` del `main.ts` de Nest: `void bootstrap();`).
1963
+
1964
+ ### `skapxd/no-non-null-assertion`
1965
+
1966
+ Prohíbe el `!` (non-null assertion): es "cállate, yo sé más que tú" dicho al
1967
+ compilador — y un `!` equivocado es un crash en runtime que el tipo juraba
1968
+ imposible. Si el valor de verdad no puede ser nulo, que lo diga el tipo
1969
+ (modela mejor, o estrecha con un guard que el compilador verifique); si
1970
+ puede serlo, el `!` no resuelve la duda: la esconde.
1971
+
1972
+ La excepción legítima vive en los tests: el `!` sobre un fixture cuya
1973
+ existencia el propio test garantiza es el arrange, no una mentira — por eso
1974
+ `nest/tests` la apaga en specs. Bajo el capó es
1975
+ `@typescript-eslint/no-non-null-assertion`
1976
+ ([doc original](https://typescript-eslint.io/rules/no-non-null-assertion/))
1977
+ re-registrada con mensajes propios.
1978
+
1979
+ ### `skapxd/no-silenced-compiler`
1980
+
1981
+ No silencies al compilador: `@ts-ignore` y `@ts-nocheck` apagan la alarma en
1982
+ vez de arreglar el incendio. Si el compilador es el muro de contención del
1983
+ sistema, nadie lo apaga cuando el modelado se pone difícil — un error de
1984
+ tipos se resuelve modelando mejor el dominio.
1985
+
1986
+ La puerta que queda abierta, a propósito: `@ts-expect-error` **con
1987
+ descripción**. Es la forma legítima de testear que un estado inválido de
1988
+ verdad NO compila (la otra mitad son los tests de tipos con `expectTypeOf`,
1989
+ ver la sección de `requires-strict-tsconfig`) — y a diferencia de
1990
+ `@ts-ignore`, avisa cuando la supresión deja de hacer falta. Bajo el capó es
1991
+ `@typescript-eslint/ban-ts-comment`
1992
+ ([doc original](https://typescript-eslint.io/rules/ban-ts-comment/)) con un
1993
+ nombre que dice lo que defiende y mensajes propios.
1994
+
1995
+ ### `skapxd/prefer-type-over-interface`
1996
+
1997
+ Usa `type`, no `interface`. Las uniones discriminadas — la columna vertebral
1998
+ del modelado de estados de este paquete — son types, y la homogeneidad
1999
+ elimina la pregunta "¿esto puede crecer por declaration merging?": un `type`
2000
+ no puede ser extendido en silencio desde otro archivo; lo que declara es
2001
+ todo lo que hay.
2002
+
2003
+ Bajo el capó es `@typescript-eslint/consistent-type-definitions`
2004
+ ([doc original](https://typescript-eslint.io/rules/consistent-type-definitions/))
2005
+ re-registrada con un nombre que declara la opinión (como los demás
2006
+ `prefer-*`). Ojo si la activas suelta: el default upstream prefiere
2007
+ `interface` — los presets la pasan como `["error", "type"]`.
2008
+
1910
2009
  ### `skapxd/no-functions-inside-components`
1911
2010
 
1912
2011
  Prohíbe definir funciones **con peso propio** dentro de un componente React
@@ -2147,6 +2246,68 @@ no puede traer `signal`.
2147
2246
  `effectNames` permite cubrir wrappers propios (`["useEffect",
2148
2247
  "useLayoutEffect", "useIsomorphicEffect"]`).
2149
2248
 
2249
+ ### `skapxd/package-requires-typed-exports`
2250
+
2251
+ El contrato de empaquetado de una librería TypeScript dual (ESM + CJS): cada
2252
+ condición del mapa `exports` declara **sus propios tipos**, del sabor
2253
+ correcto.
2254
+
2255
+ ```jsonc
2256
+ "exports": {
2257
+ ".": {
2258
+ "import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" },
2259
+ "require": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }
2260
+ }
2261
+ }
2262
+ ```
2263
+
2264
+ El antipatrón que mata es el **"FalseCJS"** (el hallazgo #1 de
2265
+ [arethetypeswrong](https://arethetypeswrong.github.io)): un `types` único por
2266
+ subpath apuntando al `.d.ts` — los consumidores ESM con
2267
+ `moduleResolution: node16` reciben tipos CJS y el contrato miente en la
2268
+ frontera más pública que tiene una librería. tsup con `dts: true` ya genera
2269
+ los dos sabores (`.d.mts` y `.d.ts`); esta regla verifica que el package.json
2270
+ de verdad los cablee y que los archivos existan en disco. Anclada al
2271
+ entrypoint (`src/index.ts` por defecto): un reporte por paquete.
2272
+
2273
+ Dogfood: esta regla nació reportando a este mismo repo — nuestros `exports`
2274
+ tenían el bug y el lint no volvió a verde hasta corregirlos.
2275
+
2276
+ ### `skapxd/untrusted-module-requires-adapter`
2277
+
2278
+ ¿Qué pasa cuando los tipos de un paquete de terceros **mienten**? El clásico:
2279
+ un paquete escrito en JS cuyos tipos viven aparte (`@types/...`) y van
2280
+ desfasados del runtime real, o índices que juran nunca devolver `undefined`.
2281
+ Todo el sistema de este paquete descansa en que el tipo dice la verdad
2282
+ (`no-impossible-branch` le cree ciegamente) — un tipo mentiroso envenena cada
2283
+ regla type-aware que lo toque.
2284
+
2285
+ El playbook, en orden:
2286
+
2287
+ 1. **Armadura de tsconfig primero**: `noUncheckedIndexedAccess` corrige de
2288
+ raíz la clase más común de mentira (index signatures optimistas) sin
2289
+ tocar al tercero — `requires-strict-tsconfig` ya lo exige.
2290
+ 2. **Frontera anticorrupción** (lo que esta regla impone): declara el módulo
2291
+ como no confiable y enciérralo tras UN adaptador. El adaptador importa el
2292
+ paquete, re-declara los tipos honestos (lo que el runtime de verdad
2293
+ devuelve) y exporta esa versión. El resto del código importa el adaptador
2294
+ y razona con tipos veraces — la mentira queda en un archivo auditable.
2295
+ 3. **`@ts-expect-error` con descripción** dentro del adaptador si hace falta
2296
+ forzar la corrección — es la puerta que `no-silenced-compiler` deja
2297
+ abierta, declarada y con porqué.
2298
+ 4. **Arregla el upstream**: PR a DefinitelyTyped. Mientras llega, los pasos
2299
+ 1-3 te protegen.
2300
+
2301
+ ```js
2302
+ "skapxd/untrusted-module-requires-adapter": ["error", {
2303
+ adapterFilePatterns: ["src/lib/xlsx-adapter.ts"],
2304
+ modules: ["xlsx"],
2305
+ }]
2306
+ ```
2307
+
2308
+ Sin `modules` declarados la regla es inerte: el inventario de sospechosos es
2309
+ una decisión del proyecto, no una adivinanza del linter (axioma A5).
2310
+
2150
2311
  ### `skapxd/no-jsx-ternary-null`
2151
2312
 
2152
2313
  Cuando renderizas JSX condicional y una rama del ternario es `null`, prefiere la
@@ -64,9 +64,6 @@ function createBaseLanguageOptions() {
64
64
  };
65
65
  }
66
66
 
67
- // src/shared/configs/create-shared-configs.ts
68
- var import_typescript_eslint3 = __toESM(require("typescript-eslint"));
69
-
70
67
  // src/shared/configs/create-typed-language-options.ts
71
68
  var import_typescript_eslint2 = __toESM(require("typescript-eslint"));
72
69
  function createTypedLanguageOptions() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/astro/index.ts","../../src/shared/configs/base-rules.ts","../../src/shared/configs/create-base-language-options.ts","../../src/shared/configs/create-shared-configs.ts","../../src/shared/configs/create-typed-language-options.ts","../../src/astro/configs.ts"],"sourcesContent":["export { createAstroConfigs } from \"./configs\";\n","export const baseRules = {\n \"skapxd/class-properties-require-readonly\": \"error\",\n \"skapxd/max-public-methods\": \"error\",\n \"skapxd/no-accessors\": \"error\",\n \"skapxd/no-ad-hoc-ok-result\": \"error\",\n \"skapxd/no-deep-relative-imports\": \"error\",\n \"skapxd/no-default-export\": \"error\",\n \"skapxd/no-else\": \"error\",\n \"skapxd/no-emoji\": \"error\",\n \"skapxd/no-nested-if\": \"error\",\n \"skapxd/no-runtime-state-guard\": \"error\",\n \"skapxd/no-promise-chain\": \"error\",\n \"skapxd/no-try-catch\": \"error\",\n \"skapxd/one-root-function-per-file\": \"error\",\n \"skapxd/prefer-tagged-union-state\": \"error\",\n \"skapxd/requires-strict-tsconfig\": \"error\",\n \"skapxd/prefer-ts-pattern\": \"error\",\n \"skapxd/result-error-requires-cause\": \"error\",\n \"skapxd/result-error-requires-handling\": \"error\",\n};\n","import tseslint from \"typescript-eslint\";\n\n// Variante sin type-checking: solo el parser, para presets que aplican a TS\n// pero no necesitan projectService (base, package, next/base, next/react).\nexport function createBaseLanguageOptions() {\n return {\n parser: tseslint.parser,\n };\n}\n","import tseslint from \"typescript-eslint\";\nimport { baseRules } from \"./base-rules\";\nimport { createBaseLanguageOptions } from \"./create-base-language-options\";\nimport { createTypedLanguageOptions } from \"./create-typed-language-options\";\nimport { typeDrivenRules } from \"./type-driven-rules\";\n\nexport function createSharedConfigs(pluginReference: unknown) {\n const baseLanguageOptions = createBaseLanguageOptions();\n const typedLanguageOptions = createTypedLanguageOptions();\n\n return {\n backend: {\n languageOptions: typedLanguageOptions,\n name: \"skapxd/shared/backend\",\n plugins: {\n \"@typescript-eslint\": tseslint.plugin,\n skapxd: pluginReference,\n },\n rules: {\n ...baseRules,\n ...typeDrivenRules,\n // La regla obligatoria del sistema de errores es await-requires-result\n // (todo await resuelve en Result). async-functions-return-result queda\n // apagada por defecto: exigir la firma por decreto choca con los bordes\n // del framework y bloquea la adopción incremental; la presión sobre los\n // awaits produce el mismo estado final. Ver \"¿Por qué está apagada por\n // defecto?\" en el README.\n \"skapxd/await-requires-result\": \"error\",\n },\n },\n base: {\n languageOptions: baseLanguageOptions,\n name: \"skapxd/shared/base\",\n plugins: { skapxd: pluginReference },\n rules: baseRules,\n },\n frontend: {\n languageOptions: typedLanguageOptions,\n name: \"skapxd/shared/frontend\",\n plugins: {\n \"@typescript-eslint\": tseslint.plugin,\n skapxd: pluginReference,\n },\n rules: {\n ...baseRules,\n ...typeDrivenRules,\n // En el front no se obliga a retornar Result, pero todo await debe\n // resolver en uno: o la función llamada ya retorna Promise<Result>\n // (camino preferido: errores modelados en el dominio) o se envuelve\n // en trySafe en el sitio.\n \"skapxd/await-requires-result\": \"error\",\n \"skapxd/jsx-return-name-pascal-case\": \"error\",\n // Anti prop-drilling: ninguna prop viaja más de un nivel. Quien la\n // crea puede pasarla a UN hijo; quien la recibe no la reenvía —\n // estado y acciones a un store global o custom hook.\n \"skapxd/no-functions-inside-components\": \"error\",\n \"skapxd/no-tunnel-props\": \"error\",\n // Listeners en efectos: un AbortController por efecto, cleanup con\n // un solo abort() en vez de removeEventListener por listener.\n \"skapxd/prefer-abort-signal\": \"error\",\n \"skapxd/no-jsx-ternary-null\": \"error\",\n \"skapxd/max-hook-size\": [\n \"error\",\n {\n maxLines: 120,\n maxUseState: 1,\n },\n ],\n },\n },\n package: {\n languageOptions: baseLanguageOptions,\n name: \"skapxd/shared/package\",\n plugins: { skapxd: pluginReference },\n rules: {\n \"skapxd/one-root-function-per-file\": \"error\",\n },\n },\n };\n}\n","import tseslint from \"typescript-eslint\";\n\nexport function createTypedLanguageOptions() {\n return {\n // Sin el parser explícito, un consumidor que use solo estos presets\n // obtiene \"Parsing error\" en cada archivo TS (espree no parsea TS).\n parser: tseslint.parser,\n parserOptions: {\n projectService: true,\n },\n };\n}\n","import {\n baseRules,\n createBaseLanguageOptions,\n createTypedLanguageOptions,\n} from \"#/shared/configs\";\n\nexport function createAstroConfigs(pluginReference: unknown) {\n const baseLanguageOptions = createBaseLanguageOptions();\n const typedLanguageOptions = createTypedLanguageOptions();\n\n return [\n {\n files: [\"src/**/*.{ts,tsx}\"],\n languageOptions: baseLanguageOptions,\n name: \"skapxd/astro/base\",\n plugins: { skapxd: pluginReference },\n rules: baseRules,\n },\n // Los .astro no llevan parser propio: lo aporta eslint-plugin-astro,\n // que el consumidor debe tener configurado.\n {\n files: [\"src/**/*.astro\"],\n name: \"skapxd/astro/astro-files\",\n plugins: { skapxd: pluginReference },\n rules: baseRules,\n },\n {\n files: [\"src/**/*.{ts,tsx}\"],\n languageOptions: typedLanguageOptions,\n name: \"skapxd/astro/typescript\",\n plugins: { skapxd: pluginReference },\n rules: {\n \"skapxd/await-requires-result\": \"error\",\n \"skapxd/result-error-requires-cause\": \"error\",\n \"skapxd/result-error-requires-handling\": \"error\",\n },\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,YAAY;AAAA,EACvB,4CAA4C;AAAA,EAC5C,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,8BAA8B;AAAA,EAC9B,mCAAmC;AAAA,EACnC,4BAA4B;AAAA,EAC5B,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,uBAAuB;AAAA,EACvB,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,mCAAmC;AAAA,EACnC,4BAA4B;AAAA,EAC5B,sCAAsC;AAAA,EACtC,yCAAyC;AAC3C;;;ACnBA,+BAAqB;AAId,SAAS,4BAA4B;AAC1C,SAAO;AAAA,IACL,QAAQ,yBAAAA,QAAS;AAAA,EACnB;AACF;;;ACRA,IAAAC,4BAAqB;;;ACArB,IAAAC,4BAAqB;AAEd,SAAS,6BAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA,IAGL,QAAQ,0BAAAC,QAAS;AAAA,IACjB,eAAe;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA,EACF;AACF;;;ACLO,SAAS,mBAAmB,iBAA0B;AAC3D,QAAM,sBAAsB,0BAA0B;AACtD,QAAM,uBAAuB,2BAA2B;AAExD,SAAO;AAAA,IACL;AAAA,MACE,OAAO,CAAC,mBAAmB;AAAA,MAC3B,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,IACT;AAAA;AAAA;AAAA,IAGA;AAAA,MACE,OAAO,CAAC,gBAAgB;AAAA,MACxB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,OAAO,CAAC,mBAAmB;AAAA,MAC3B,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,QACL,gCAAgC;AAAA,QAChC,sCAAsC;AAAA,QACtC,yCAAyC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;","names":["tseslint","import_typescript_eslint","import_typescript_eslint","tseslint"]}
1
+ {"version":3,"sources":["../../src/astro/index.ts","../../src/shared/configs/base-rules.ts","../../src/shared/configs/create-base-language-options.ts","../../src/shared/configs/create-typed-language-options.ts","../../src/astro/configs.ts"],"sourcesContent":["export { createAstroConfigs } from \"./configs\";\n","export const baseRules = {\n \"skapxd/class-properties-require-readonly\": \"error\",\n \"skapxd/max-public-methods\": \"error\",\n \"skapxd/no-accessors\": \"error\",\n \"skapxd/no-ad-hoc-ok-result\": \"error\",\n \"skapxd/no-deep-relative-imports\": \"error\",\n \"skapxd/no-default-export\": \"error\",\n \"skapxd/no-else\": \"error\",\n \"skapxd/no-emoji\": \"error\",\n \"skapxd/no-nested-if\": \"error\",\n \"skapxd/no-runtime-state-guard\": \"error\",\n \"skapxd/no-promise-chain\": \"error\",\n \"skapxd/no-try-catch\": \"error\",\n \"skapxd/one-root-function-per-file\": \"error\",\n \"skapxd/prefer-tagged-union-state\": \"error\",\n \"skapxd/requires-strict-tsconfig\": \"error\",\n \"skapxd/prefer-ts-pattern\": \"error\",\n \"skapxd/result-error-requires-cause\": \"error\",\n \"skapxd/result-error-requires-handling\": \"error\",\n};\n","import tseslint from \"typescript-eslint\";\n\n// Variante sin type-checking: solo el parser, para presets que aplican a TS\n// pero no necesitan projectService (base, package, next/base, next/react).\nexport function createBaseLanguageOptions() {\n return {\n parser: tseslint.parser,\n };\n}\n","import tseslint from \"typescript-eslint\";\n\nexport function createTypedLanguageOptions() {\n return {\n // Sin el parser explícito, un consumidor que use solo estos presets\n // obtiene \"Parsing error\" en cada archivo TS (espree no parsea TS).\n parser: tseslint.parser,\n parserOptions: {\n projectService: true,\n },\n };\n}\n","import {\n baseRules,\n createBaseLanguageOptions,\n createTypedLanguageOptions,\n} from \"#/shared/configs\";\n\nexport function createAstroConfigs(pluginReference: unknown) {\n const baseLanguageOptions = createBaseLanguageOptions();\n const typedLanguageOptions = createTypedLanguageOptions();\n\n return [\n {\n files: [\"src/**/*.{ts,tsx}\"],\n languageOptions: baseLanguageOptions,\n name: \"skapxd/astro/base\",\n plugins: { skapxd: pluginReference },\n rules: baseRules,\n },\n // Los .astro no llevan parser propio: lo aporta eslint-plugin-astro,\n // que el consumidor debe tener configurado.\n {\n files: [\"src/**/*.astro\"],\n name: \"skapxd/astro/astro-files\",\n plugins: { skapxd: pluginReference },\n rules: baseRules,\n },\n {\n files: [\"src/**/*.{ts,tsx}\"],\n languageOptions: typedLanguageOptions,\n name: \"skapxd/astro/typescript\",\n plugins: { skapxd: pluginReference },\n rules: {\n \"skapxd/await-requires-result\": \"error\",\n \"skapxd/result-error-requires-cause\": \"error\",\n \"skapxd/result-error-requires-handling\": \"error\",\n },\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,YAAY;AAAA,EACvB,4CAA4C;AAAA,EAC5C,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,8BAA8B;AAAA,EAC9B,mCAAmC;AAAA,EACnC,4BAA4B;AAAA,EAC5B,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,uBAAuB;AAAA,EACvB,iCAAiC;AAAA,EACjC,2BAA2B;AAAA,EAC3B,uBAAuB;AAAA,EACvB,qCAAqC;AAAA,EACrC,oCAAoC;AAAA,EACpC,mCAAmC;AAAA,EACnC,4BAA4B;AAAA,EAC5B,sCAAsC;AAAA,EACtC,yCAAyC;AAC3C;;;ACnBA,+BAAqB;AAId,SAAS,4BAA4B;AAC1C,SAAO;AAAA,IACL,QAAQ,yBAAAA,QAAS;AAAA,EACnB;AACF;;;ACRA,IAAAC,4BAAqB;AAEd,SAAS,6BAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA,IAGL,QAAQ,0BAAAC,QAAS;AAAA,IACjB,eAAe;AAAA,MACb,gBAAgB;AAAA,IAClB;AAAA,EACF;AACF;;;ACLO,SAAS,mBAAmB,iBAA0B;AAC3D,QAAM,sBAAsB,0BAA0B;AACtD,QAAM,uBAAuB,2BAA2B;AAExD,SAAO;AAAA,IACL;AAAA,MACE,OAAO,CAAC,mBAAmB;AAAA,MAC3B,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,IACT;AAAA;AAAA;AAAA,IAGA;AAAA,MACE,OAAO,CAAC,gBAAgB;AAAA,MACxB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,OAAO,CAAC,mBAAmB;AAAA,MAC3B,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,QACL,gCAAgC;AAAA,QAChC,sCAAsC;AAAA,QACtC,yCAAyC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;","names":["tseslint","import_typescript_eslint","tseslint"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createAstroConfigs
3
- } from "../chunk-DJDXQWCP.mjs";
4
- import "../chunk-F6GJW5A4.mjs";
3
+ } from "../chunk-GSQWHSHV.mjs";
4
+ import "../chunk-QDQUU6QK.mjs";
5
5
  export {
6
6
  createAstroConfigs
7
7
  };
@@ -2,10 +2,7 @@ import {
2
2
  baseRules,
3
3
  createTypedLanguageOptions,
4
4
  typeDrivenRules
5
- } from "./chunk-F6GJW5A4.mjs";
6
-
7
- // src/nest/configs.ts
8
- import tseslint from "typescript-eslint";
5
+ } from "./chunk-QDQUU6QK.mjs";
9
6
 
10
7
  // src/constants/nest-entrypoint-file-patterns.ts
11
8
  var nestEntrypointFilePatterns = [
@@ -46,10 +43,9 @@ function createNestConfigs(pluginReference) {
46
43
  files: ["src/**/*.ts"],
47
44
  languageOptions: typedLanguageOptions,
48
45
  name: "skapxd/nest/base",
49
- plugins: {
50
- "@typescript-eslint": tseslint.plugin,
51
- skapxd: pluginReference
52
- },
46
+ // Solo el plugin skapxd: las reglas de typescript-eslint entran
47
+ // re-registradas bajo nuestro namespace (typeDrivenRules).
48
+ plugins: { skapxd: pluginReference },
53
49
  rules: {
54
50
  ...baseRules,
55
51
  ...typeDrivenRules,
@@ -117,16 +113,13 @@ function createNestConfigs(pluginReference) {
117
113
  {
118
114
  files: ["**/*.spec.ts", "**/*.e2e-spec.ts"],
119
115
  name: "skapxd/nest/tests",
120
- plugins: {
121
- "@typescript-eslint": tseslint.plugin,
122
- skapxd: pluginReference
123
- },
116
+ plugins: { skapxd: pluginReference },
124
117
  rules: {
125
118
  // El `!` sobre un fixture cuya existencia el propio test garantiza
126
119
  // no es mentirle al compilador: es el arrange. no-floating-promises
127
120
  // sí queda activa — un await olvidado en un spec es un falso verde.
128
- "@typescript-eslint/no-non-null-assertion": "off",
129
121
  "skapxd/await-requires-result": "off",
122
+ "skapxd/no-non-null-assertion": "off",
130
123
  "skapxd/no-try-catch": "off",
131
124
  "skapxd/result-error-requires-handling": "off"
132
125
  }
@@ -137,4 +130,4 @@ function createNestConfigs(pluginReference) {
137
130
  export {
138
131
  createNestConfigs
139
132
  };
140
- //# sourceMappingURL=chunk-O5BXMSNR.mjs.map
133
+ //# sourceMappingURL=chunk-3GEFHNU7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants/nest-entrypoint-file-patterns.ts","../src/constants/nest-framework-hook-names.ts","../src/nest/configs.ts"],"sourcesContent":["// @ts-nocheck\n// Entrypoints de un proyecto Nest donde exigir Promise<Result> no aplica:\n// el bootstrap debe crashear ruidoso, no modelar errores de dominio.\n// Globs (matchean en cualquier carpeta), basados en proyectos reales:\n// main.ts, main.module.ts/app.module.ts, instrumentation.ts, app-cluster.ts.\nexport const nestEntrypointFilePatterns = [\n \"src/main.ts\",\n \"src/app-cluster.ts\",\n \"src/instrumentation.ts\",\n];\n","// @ts-nocheck\n// Métodos públicos que NO cuentan hacia el límite porque son callbacks del\n// framework (NestJS): los llama el container/router/HTTP layer, nunca el\n// código de negocio. Contarlos forzaría refactors sin semántica.\nexport const nestFrameworkHookNames = [\n // Lifecycle hooks — https://docs.nestjs.com/fundamentals/lifecycle-events\n \"onModuleInit\",\n \"onModuleDestroy\",\n \"onApplicationBootstrap\",\n \"onApplicationShutdown\",\n \"beforeApplicationShutdown\",\n // Interfaces del request pipeline\n \"canActivate\", // CanActivate (Guard)\n \"intercept\", // NestInterceptor\n \"transform\", // PipeTransform\n \"catch\", // ExceptionFilter\n \"use\", // NestMiddleware\n];\n","import { nestEntrypointFilePatterns } from \"#/constants/nest-entrypoint-file-patterns\";\nimport { nestFrameworkHookNames } from \"#/constants/nest-framework-hook-names\";\nimport {\n baseRules,\n createTypedLanguageOptions,\n typeDrivenRules,\n} from \"#/shared/configs\";\n\nexport function createNestConfigs(pluginReference: unknown) {\n const typedLanguageOptions = createTypedLanguageOptions();\n\n return [\n // El dominio completo (services, controllers, modules, guards, ...).\n // Las carpetas fuera de src (dev/, scripts/, e2e/, integration-test/)\n // quedan fuera del preset a propósito: no son la app.\n {\n files: [\"src/**/*.ts\"],\n languageOptions: typedLanguageOptions,\n name: \"skapxd/nest/base\",\n // Solo el plugin skapxd: las reglas de typescript-eslint entran\n // re-registradas bajo nuestro namespace (typeDrivenRules).\n plugins: { skapxd: pluginReference },\n rules: {\n ...baseRules,\n ...typeDrivenRules,\n // Nota: class-properties-require-readonly viene de las bases sin\n // override — la exención de la capa de persistencia es por\n // PROPIEDAD (decoradores @Prop/@Column verificados contra los\n // imports de @nestjs/mongoose/typeorm), no por nombre de archivo.\n // La regla agnóstica de las bases, con el conocimiento del\n // framework inyectado: los hooks de Nest (onModuleInit,\n // canActivate, intercept, ...) no cuentan como superficie pública.\n \"skapxd/max-public-methods\": [\n \"error\",\n { ignore: [...nestFrameworkHookNames] },\n ],\n // Todo await resuelve en Result, salvo los entrypoints (main.ts,\n // instrumentation): ahí el bootstrap debe crashear ruidoso.\n \"skapxd/await-requires-result\": [\n \"error\",\n { allowFilePatterns: [...nestEntrypointFilePatterns] },\n ],\n // El contrato HTTP se documenta en los DTOs (@ApiProperty), no en el\n // controller: el plugin @nestjs/swagger introspecciona el resto.\n \"skapxd/nest-dto-requires-api-property\": \"error\",\n // Los DTOs de input validan en runtime con class-validator (+ @Type\n // de class-transformer para anidados); los out-*/-response quedan\n // exentos: el server los produce, no los recibe.\n \"skapxd/nest-dto-requires-validation\": \"error\",\n // El controller es la frontera: consume el Result con match() y\n // traduce a DTO o HttpException. Devolverlo crudo serializa el\n // envelope { ok, error } al cliente.\n \"skapxd/nest-no-result-response\": \"error\",\n \"skapxd/nest-no-swagger-in-controllers\": \"error\",\n // Configuración del proyecto verificada por el lint: el plugin de\n // swagger en nest-cli.json (la premisa de las reglas de swagger) y\n // un ValidationPipe con transform + whitelist (la premisa de las\n // reglas de DTOs).\n \"skapxd/nest-requires-swagger-plugin\": \"error\",\n \"skapxd/nest-validation-pipe-config\": \"error\",\n },\n },\n // En services, las dependencias entran por el constructor (DI), no con\n // `new`.\n {\n files: [\"src/**/*.service.ts\"],\n name: \"skapxd/nest/services\",\n plugins: { skapxd: pluginReference },\n rules: {\n \"skapxd/nest-no-direct-instantiation\": \"error\",\n },\n },\n // La forma de controllers y gateways la dicta el framework (un método\n // por ruta/evento): ahí el límite de métodos públicos no aporta\n // semántica. Y 2+ query params individuales son un DTO disfrazado.\n {\n files: [\"src/**/*.controller.ts\", \"src/**/*.gateway.ts\"],\n name: \"skapxd/nest/controllers\",\n plugins: { skapxd: pluginReference },\n rules: {\n \"skapxd/max-public-methods\": \"off\",\n \"skapxd/nest-no-inline-query-params\": \"error\",\n },\n },\n // Specs colocados: los tests awaitean helpers y SUTs libremente, y\n // descartar un Result en una aserción no es perder un trace.\n {\n files: [\"**/*.spec.ts\", \"**/*.e2e-spec.ts\"],\n name: \"skapxd/nest/tests\",\n plugins: { skapxd: pluginReference },\n rules: {\n // El `!` sobre un fixture cuya existencia el propio test garantiza\n // no es mentirle al compilador: es el arrange. no-floating-promises\n // sí queda activa — un await olvidado en un spec es un falso verde.\n \"skapxd/await-requires-result\": \"off\",\n \"skapxd/no-non-null-assertion\": \"off\",\n \"skapxd/no-try-catch\": \"off\",\n \"skapxd/result-error-requires-handling\": \"off\",\n },\n },\n ];\n}\n"],"mappings":";;;;;;;AAKO,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF;;;ACLO,IAAM,yBAAyB;AAAA;AAAA,EAEpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;;;ACTO,SAAS,kBAAkB,iBAA0B;AAC1D,QAAM,uBAAuB,2BAA2B;AAExD,SAAO;AAAA;AAAA;AAAA;AAAA,IAIL;AAAA,MACE,OAAO,CAAC,aAAa;AAAA,MACrB,iBAAiB;AAAA,MACjB,MAAM;AAAA;AAAA;AAAA,MAGN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,QACL,GAAG;AAAA,QACH,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQH,6BAA6B;AAAA,UAC3B;AAAA,UACA,EAAE,QAAQ,CAAC,GAAG,sBAAsB,EAAE;AAAA,QACxC;AAAA;AAAA;AAAA,QAGA,gCAAgC;AAAA,UAC9B;AAAA,UACA,EAAE,mBAAmB,CAAC,GAAG,0BAA0B,EAAE;AAAA,QACvD;AAAA;AAAA;AAAA,QAGA,yCAAyC;AAAA;AAAA;AAAA;AAAA,QAIzC,uCAAuC;AAAA;AAAA;AAAA;AAAA,QAIvC,kCAAkC;AAAA,QAClC,yCAAyC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKzC,uCAAuC;AAAA,QACvC,sCAAsC;AAAA,MACxC;AAAA,IACF;AAAA;AAAA;AAAA,IAGA;AAAA,MACE,OAAO,CAAC,qBAAqB;AAAA,MAC7B,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,QACL,uCAAuC;AAAA,MACzC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,MACE,OAAO,CAAC,0BAA0B,qBAAqB;AAAA,MACvD,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA,QACL,6BAA6B;AAAA,QAC7B,sCAAsC;AAAA,MACxC;AAAA,IACF;AAAA;AAAA;AAAA,IAGA;AAAA,MACE,OAAO,CAAC,gBAAgB,kBAAkB;AAAA,MAC1C,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,gBAAgB;AAAA,MACnC,OAAO;AAAA;AAAA;AAAA;AAAA,QAIL,gCAAgC;AAAA,QAChC,gCAAgC;AAAA,QAChC,uBAAuB;AAAA,QACvB,yCAAyC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  baseRules,
7
7
  createBaseLanguageOptions,
8
8
  createTypedLanguageOptions
9
- } from "./chunk-F6GJW5A4.mjs";
9
+ } from "./chunk-QDQUU6QK.mjs";
10
10
 
11
11
  // src/next/configs.ts
12
12
  var nextDefaultExportFileGlob = `{${[
@@ -71,4 +71,4 @@ function createNextConfigs(pluginReference) {
71
71
  export {
72
72
  createNextConfigs
73
73
  };
74
- //# sourceMappingURL=chunk-OVC5GQV3.mjs.map
74
+ //# sourceMappingURL=chunk-54EOEKYS.mjs.map
@@ -2,7 +2,7 @@ import {
2
2
  baseRules,
3
3
  createBaseLanguageOptions,
4
4
  createTypedLanguageOptions
5
- } from "./chunk-F6GJW5A4.mjs";
5
+ } from "./chunk-QDQUU6QK.mjs";
6
6
 
7
7
  // src/astro/configs.ts
8
8
  function createAstroConfigs(pluginReference) {
@@ -41,4 +41,4 @@ function createAstroConfigs(pluginReference) {
41
41
  export {
42
42
  createAstroConfigs
43
43
  };
44
- //# sourceMappingURL=chunk-DJDXQWCP.mjs.map
44
+ //# sourceMappingURL=chunk-GSQWHSHV.mjs.map