eslint-plugin-ts-fortress 0.3.0 → 0.4.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.
package/README.md CHANGED
@@ -15,6 +15,39 @@ configured TypeScript project is not required.
15
15
 
16
16
  ## Usage (flat config)
17
17
 
18
+ The plugin ships a `recommended` config preset that registers the plugin and
19
+ turns on **every** rule at `error`:
20
+
21
+ ```ts
22
+ // eslint.config.mts
23
+ import { eslintPluginTsFortress } from 'eslint-plugin-ts-fortress';
24
+
25
+ export default [eslintPluginTsFortress.configs.recommended];
26
+ ```
27
+
28
+ Since the preset is a plain flat-config object, individual rules can be
29
+ adjusted by a later config entry:
30
+
31
+ ```ts
32
+ // eslint.config.mts
33
+ import {
34
+ eslintPluginTsFortress,
35
+ type EslintTsFortressRules,
36
+ } from 'eslint-plugin-ts-fortress';
37
+
38
+ export default [
39
+ eslintPluginTsFortress.configs.recommended,
40
+ {
41
+ files: ['src/legacy/**'],
42
+ rules: {
43
+ 'ts-fortress/prefer-canonical-length-constrained-type': 'off',
44
+ } satisfies Partial<EslintTsFortressRules>,
45
+ },
46
+ ];
47
+ ```
48
+
49
+ Or register the plugin yourself and pick the rules one by one:
50
+
18
51
  ```ts
19
52
  // eslint.config.mts
20
53
  import {
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { eslintPluginTsFortress } from './plugin.mjs';
2
2
  export type { EslintTsFortressRules, EslintTsFortressRulesOption, } from './rule-types.mjs';
3
3
  export { tsFortressRules } from './rules/index.mjs';
4
- export { type ESLintPlugin } from './types.mjs';
4
+ export { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';
5
5
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EACV,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EACV,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/plugin.d.mts CHANGED
@@ -1,3 +1,22 @@
1
1
  import { type ESLintPlugin } from './types.mjs';
2
- export declare const eslintPluginTsFortress: ESLintPlugin;
2
+ export declare const eslintPluginTsFortress: {
3
+ readonly meta: {
4
+ readonly name: 'eslint-plugin-ts-fortress';
5
+ };
6
+ readonly rules: {
7
+ readonly 'prefer-canonical-length-constrained-type': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useCanonicalType", readonly [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
8
+ };
9
+ readonly configs: {
10
+ /** Enables every rule of this plugin at `error`. */
11
+ readonly recommended: {
12
+ readonly name: 'ts-fortress/recommended';
13
+ readonly plugins: {
14
+ readonly 'ts-fortress': ESLintPlugin;
15
+ };
16
+ readonly rules: {
17
+ readonly 'ts-fortress/prefer-canonical-length-constrained-type': 'error';
18
+ };
19
+ };
20
+ };
21
+ };
3
22
  //# sourceMappingURL=plugin.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,sBAAsB,EAAE,YAK3B,CAAC"}
1
+ {"version":3,"file":"plugin.d.mts","sourceRoot":"","sources":["../src/plugin.mts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AA8BvE,eAAO,MAAM,sBAAsB;;iBAE/B,IAAI,EAAE,2BAA2B;;;;;;QAIjC,oDAAoD;iBACpD,WAAW;2BAtBP,yBAAyB;;yBAQzB,aAAa,EAAI,YAAY;;;iFAdqB,OAAO;;;;CA8BhC,CAAC"}
package/dist/plugin.mjs CHANGED
@@ -1,10 +1,32 @@
1
1
  import { tsFortressRules } from './rules/rules.mjs';
2
2
 
3
+ const recommendedRules = {
4
+ "ts-fortress/prefer-canonical-length-constrained-type": "error"
5
+ };
6
+ const recommendedConfig = {
7
+ name: "ts-fortress/recommended",
8
+ plugins: {
9
+ // Resolved lazily so that this config registers the *same* object that
10
+ // `eslintPluginTsFortress` refers to. ESLint rejects a plugin name that
11
+ // maps to two different objects with `Cannot redefine plugin`, which is
12
+ // what a user combining this preset with their own
13
+ // `plugins: { 'ts-fortress': eslintPluginTsFortress }` entry would hit if
14
+ // the preset embedded a separate copy of the plugin.
15
+ get "ts-fortress"() {
16
+ return eslintPluginTsFortress;
17
+ }
18
+ },
19
+ rules: recommendedRules
20
+ };
3
21
  const eslintPluginTsFortress = {
4
22
  meta: {
5
23
  name: "eslint-plugin-ts-fortress"
6
24
  },
7
- rules: tsFortressRules
25
+ rules: tsFortressRules,
26
+ configs: {
27
+ /** Enables every rule of this plugin at `error`. */
28
+ recommended: recommendedConfig
29
+ }
8
30
  };
9
31
 
10
32
  export { eslintPluginTsFortress };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","sources":["../src/plugin.mts"],"sourcesContent":["import { tsFortressRules } from './rules/index.mjs';\nimport { type ESLintPlugin } from './types.mjs';\n\nexport const eslintPluginTsFortress: ESLintPlugin = {\n meta: {\n name: 'eslint-plugin-ts-fortress',\n },\n rules: tsFortressRules,\n} as const;\n"],"names":[],"mappings":";;AAGO,MAAM,sBAAA,GAAuC;AAAA,EAClD,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM;AAAA,GACR;AAAA,EACA,KAAA,EAAO;AACT;;;;"}
1
+ {"version":3,"file":"plugin.mjs","sources":["../src/plugin.mts"],"sourcesContent":["import { tsFortressRules } from './rules/index.mjs';\nimport { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';\n\n/**\n * Every rule this plugin ships, at `error`.\n *\n * The `satisfies` clause below is keyed off {@link tsFortressRules}, so adding\n * a rule without listing it here fails to type-check.\n */\nconst recommendedRules = {\n 'ts-fortress/prefer-canonical-length-constrained-type': 'error',\n} as const satisfies Readonly<\n Record<`ts-fortress/${keyof typeof tsFortressRules}`, 'error'>\n>;\n\nconst recommendedConfig = {\n name: 'ts-fortress/recommended',\n plugins: {\n // Resolved lazily so that this config registers the *same* object that\n // `eslintPluginTsFortress` refers to. ESLint rejects a plugin name that\n // maps to two different objects with `Cannot redefine plugin`, which is\n // what a user combining this preset with their own\n // `plugins: { 'ts-fortress': eslintPluginTsFortress }` entry would hit if\n // the preset embedded a separate copy of the plugin.\n get 'ts-fortress'(): ESLintPlugin {\n return eslintPluginTsFortress;\n },\n },\n rules: recommendedRules,\n} as const satisfies ESLintFlatConfig;\n\nexport const eslintPluginTsFortress = {\n meta: {\n name: 'eslint-plugin-ts-fortress',\n },\n rules: tsFortressRules,\n configs: {\n /** Enables every rule of this plugin at `error`. */\n recommended: recommendedConfig,\n },\n} as const satisfies ESLintPlugin;\n"],"names":[],"mappings":";;AASA,MAAM,gBAAA,GAAmB;AAAA,EACvB,sDAAA,EAAwD;AAC1D,CAAA;AAIA,MAAM,iBAAA,GAAoB;AAAA,EACxB,IAAA,EAAM,yBAAA;AAAA,EACN,OAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOP,IAAI,aAAA,GAA8B;AAChC,MAAA,OAAO,sBAAA;AAAA,IACT;AAAA,GACF;AAAA,EACA,KAAA,EAAO;AACT,CAAA;AAEO,MAAM,sBAAA,GAAyB;AAAA,EACpC,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM;AAAA,GACR;AAAA,EACA,KAAA,EAAO,eAAA;AAAA,EACP,OAAA,EAAS;AAAA;AAAA,IAEP,WAAA,EAAa;AAAA;AAEjB;;;;"}
package/dist/types.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type TSESLint } from '@typescript-eslint/utils';
2
2
  import { type DeepReadonly } from 'ts-type-forge';
3
3
  export type ESLintPlugin = DeepReadonly<TSESLint.FlatConfig.Plugin>;
4
+ export type ESLintFlatConfig = DeepReadonly<TSESLint.FlatConfig.Config>;
4
5
  //# sourceMappingURL=types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-ts-fortress",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "ESLint rules that steer schema definitions toward ts-fortress idioms.",
6
6
  "keywords": [
package/src/index.mts CHANGED
@@ -4,4 +4,4 @@ export type {
4
4
  EslintTsFortressRulesOption,
5
5
  } from './rule-types.mjs';
6
6
  export { tsFortressRules } from './rules/index.mjs';
7
- export { type ESLintPlugin } from './types.mjs';
7
+ export { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';
package/src/plugin.mts CHANGED
@@ -1,9 +1,41 @@
1
1
  import { tsFortressRules } from './rules/index.mjs';
2
- import { type ESLintPlugin } from './types.mjs';
2
+ import { type ESLintFlatConfig, type ESLintPlugin } from './types.mjs';
3
3
 
4
- export const eslintPluginTsFortress: ESLintPlugin = {
4
+ /**
5
+ * Every rule this plugin ships, at `error`.
6
+ *
7
+ * The `satisfies` clause below is keyed off {@link tsFortressRules}, so adding
8
+ * a rule without listing it here fails to type-check.
9
+ */
10
+ const recommendedRules = {
11
+ 'ts-fortress/prefer-canonical-length-constrained-type': 'error',
12
+ } as const satisfies Readonly<
13
+ Record<`ts-fortress/${keyof typeof tsFortressRules}`, 'error'>
14
+ >;
15
+
16
+ const recommendedConfig = {
17
+ name: 'ts-fortress/recommended',
18
+ plugins: {
19
+ // Resolved lazily so that this config registers the *same* object that
20
+ // `eslintPluginTsFortress` refers to. ESLint rejects a plugin name that
21
+ // maps to two different objects with `Cannot redefine plugin`, which is
22
+ // what a user combining this preset with their own
23
+ // `plugins: { 'ts-fortress': eslintPluginTsFortress }` entry would hit if
24
+ // the preset embedded a separate copy of the plugin.
25
+ get 'ts-fortress'(): ESLintPlugin {
26
+ return eslintPluginTsFortress;
27
+ },
28
+ },
29
+ rules: recommendedRules,
30
+ } as const satisfies ESLintFlatConfig;
31
+
32
+ export const eslintPluginTsFortress = {
5
33
  meta: {
6
34
  name: 'eslint-plugin-ts-fortress',
7
35
  },
8
36
  rules: tsFortressRules,
9
- } as const;
37
+ configs: {
38
+ /** Enables every rule of this plugin at `error`. */
39
+ recommended: recommendedConfig,
40
+ },
41
+ } as const satisfies ESLintPlugin;
@@ -0,0 +1,24 @@
1
+ import { eslintPluginTsFortress } from './plugin.mjs';
2
+ import { tsFortressRules } from './rules/index.mjs';
3
+
4
+ describe('eslintPluginTsFortress.configs.recommended', () => {
5
+ const recommended = eslintPluginTsFortress.configs.recommended;
6
+
7
+ test('enables every rule of the plugin, and nothing else, at "error"', () => {
8
+ assert.deepStrictEqual(
9
+ recommended.rules,
10
+ Object.fromEntries(
11
+ Object.keys(tsFortressRules).map((name) => [
12
+ `ts-fortress/${name}`,
13
+ 'error',
14
+ ]),
15
+ ),
16
+ );
17
+ });
18
+
19
+ test('registers the exported plugin object itself', () => {
20
+ // Registering a *copy* would make `Cannot redefine plugin` errors possible
21
+ // for users who also list the plugin in their own `plugins` record.
22
+ expect(recommended.plugins['ts-fortress']).toBe(eslintPluginTsFortress);
23
+ });
24
+ });
package/src/types.mts CHANGED
@@ -2,3 +2,5 @@ import { type TSESLint } from '@typescript-eslint/utils';
2
2
  import { type DeepReadonly } from 'ts-type-forge';
3
3
 
4
4
  export type ESLintPlugin = DeepReadonly<TSESLint.FlatConfig.Plugin>;
5
+
6
+ export type ESLintFlatConfig = DeepReadonly<TSESLint.FlatConfig.Config>;