@zgeoff/oxlint-config 0.2.13 → 0.3.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
@@ -11,8 +11,8 @@ the shared agent guidelines, `zgeoff/test-beside-module` keeps each test file be
11
11
  tests, `zgeoff/import-zones` fails an import that crosses a module boundary the repo declares,
12
12
  `zgeoff/no-restricted-words` keeps the words in its `words` option out of a path's text,
13
13
  `zgeoff/no-abbreviated-names` reports each abbreviated value name it lists with its full word,
14
- `zgeoff/no-file-snapshot` bans file snapshots, and `zgeoff/setup-test-only` keeps a test file's
15
- module level to `setupTest()` and its tests.
14
+ `zgeoff/no-file-snapshot` bans file snapshots, `zgeoff/setup-test-only` keeps a test file's module
15
+ level to `setupTest()` and its tests, and `zgeoff/no-class` bans every class but a custom error.
16
16
 
17
17
  ## Usage
18
18
 
@@ -157,6 +157,15 @@ linted file that has a `__snapshots__/<file name>.snap` beside it, at the first
157
157
  file-level disable comment covers it. oxlint never visits a `.snap` file, so a snapshot file whose
158
158
  test file is gone is not reported.
159
159
 
160
+ ## `zgeoff/no-class`
161
+
162
+ Objects come from factory functions, as the code-style skill requires, so the rule reports every
163
+ class declaration and class expression, in test files too. A custom error stays a class, because
164
+ `instanceof` checks and stack traces need one. The rule counts a class as a custom error when its
165
+ `extends` clause holds `Error` or another name that ends in `Error`, bare or as a member such as
166
+ `errors.BrewError`. It does not check the name of the class itself, and it reports a superclass
167
+ reached through a computed member, such as `errors['BrewError']`.
168
+
160
169
  ## `zgeoff/import-zones`
161
170
 
162
171
  Off unless a repo configures it. The options name zones (path globs, relative to the repo root) and
package/no-class.js ADDED
@@ -0,0 +1,40 @@
1
+ // a custom error stays a class, since `instanceof` checks and stack traces
2
+ // need one: its superclass is `Error` or another name that ends in `Error`,
3
+ // bare or as a member such as `errors.BrewError`
4
+ const noClass = {
5
+ meta: {
6
+ type: 'problem',
7
+ messages: {
8
+ banned:
9
+ 'Build this with a factory function (`create<X>` or `make<X>`), not a class. Only a custom error may be a class: `class XError extends Error`.',
10
+ },
11
+ schema: [],
12
+ },
13
+ create(context) {
14
+ const checkClass = (node) => {
15
+ if (!isCustomError(node)) {
16
+ context.report({ node, messageId: 'banned' });
17
+ }
18
+ };
19
+
20
+ return { ClassDeclaration: checkClass, ClassExpression: checkClass };
21
+ },
22
+ };
23
+
24
+ function isCustomError(node) {
25
+ return findSuperclassName(node.superClass)?.endsWith('Error') ?? false;
26
+ }
27
+
28
+ function findSuperclassName(superClass) {
29
+ if (superClass?.type === 'Identifier') {
30
+ return superClass.name;
31
+ }
32
+
33
+ if (superClass?.type === 'MemberExpression' && !superClass.computed) {
34
+ return superClass.property.name;
35
+ }
36
+
37
+ return null;
38
+ }
39
+
40
+ export default noClass;
package/oxlintrc.json CHANGED
@@ -26,6 +26,7 @@
26
26
  "zgeoff/no-await-in-condition": "error",
27
27
  "zgeoff/no-await-in-logical": "error",
28
28
  "zgeoff/no-switch": "error",
29
+ "zgeoff/no-class": "error",
29
30
  "zgeoff/no-jsdoc": "error",
30
31
  "zgeoff/max-consecutive-line-comments": ["error", { "max": 3 }],
31
32
  "zgeoff/no-comment-rule-override": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zgeoff/oxlint-config",
3
- "version": "0.2.13",
3
+ "version": "0.3.0",
4
4
  "description": "Shareable oxlint config: strict categories, house-style rules, and a custom JS plugin",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,6 +15,7 @@
15
15
  "no-restricted-words.js",
16
16
  "no-abbreviated-names.js",
17
17
  "max-consecutive-line-comments.js",
18
+ "no-class.js",
18
19
  "no-jsdoc.js",
19
20
  "no-comment-rule-override.js",
20
21
  "test-beside-module.js",
package/plugin.js CHANGED
@@ -2,6 +2,7 @@ import functionVerb from './function-verb.js';
2
2
  import importZones from './import-zones.js';
3
3
  import maxConsecutiveLineComments from './max-consecutive-line-comments.js';
4
4
  import noAbbreviatedNames from './no-abbreviated-names.js';
5
+ import noClass from './no-class.js';
5
6
  import noCommentRuleOverride from './no-comment-rule-override.js';
6
7
  import noFileSnapshot from './no-file-snapshot.js';
7
8
  import noJSDoc from './no-jsdoc.js';
@@ -104,6 +105,7 @@ const plugin = {
104
105
  'Branch with match(...).exhaustive() from ts-pattern, never switch.',
105
106
  ['SwitchStatement'],
106
107
  ),
108
+ 'no-class': noClass,
107
109
  'no-jsdoc': noJSDoc,
108
110
  'max-consecutive-line-comments': maxConsecutiveLineComments,
109
111
  'no-comment-rule-override': noCommentRuleOverride,