@blumintinc/eslint-plugin-blumint 1.20.67 → 1.20.68

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/lib/index.js CHANGED
@@ -223,7 +223,7 @@ function noFrontendImportsFromFunctionsPatterns(pattern) {
223
223
  module.exports = {
224
224
  meta: {
225
225
  name: '@blumintinc/eslint-plugin-blumint',
226
- version: '1.20.67',
226
+ version: '1.20.68',
227
227
  },
228
228
  parseOptions: {
229
229
  ecmaVersion: 2020,
@@ -54,17 +54,28 @@ function isNameInScope(scope, name) {
54
54
  * between consecutive lines. Reading it from the source keeps emitted code in
55
55
  * the author's units instead of assuming a two-space, space-indented file.
56
56
  */
57
- function indentUnitOf(text) {
57
+ function indentUnitOf(sourceCode) {
58
+ const text = sourceCode.getText();
59
+ const blockComments = sourceCode
60
+ .getAllComments()
61
+ .filter((comment) => comment.type === utils_1.AST_TOKEN_TYPES.Block)
62
+ .map((comment) => comment.range);
63
+ // A block comment's interior lines carry whatever alignment the comment uses
64
+ // — the `*` one column in from its own indentation, or, for commented-out
65
+ // code, the original code's depths. Neither is a nesting step of the file, and
66
+ // counting them makes a JSDoc-heavy file look 1-space indented. Keying on the
67
+ // comment's range rather than a leading `*` also covers a body without them.
68
+ const continuesBlockComment = (offset) => blockComments.some(([start, end]) => start < offset && offset < end);
58
69
  const frequencies = new Map();
59
70
  let previous = '';
71
+ let offset = 0;
60
72
  for (const line of text.split('\n')) {
73
+ const lineStart = offset;
74
+ offset += line.length + 1;
61
75
  if (line.trim() === '') {
62
76
  continue;
63
77
  }
64
- // A block comment's continuation lines align on the `*` one column in from
65
- // the comment's own indentation. That is comment alignment, not a nesting
66
- // step, and counting it makes any JSDoc-heavy file look 1-space indented.
67
- if (line.trimStart().startsWith('*')) {
78
+ if (continuesBlockComment(lineStart)) {
68
79
  continue;
69
80
  }
70
81
  const match = /^[ \t]*/.exec(line);
@@ -121,7 +132,7 @@ exports.preferUnionFromConstArray = (0, createRule_1.createRule)({
121
132
  let indentUnit = null;
122
133
  const fileIndentUnit = () => {
123
134
  if (indentUnit === null) {
124
- indentUnit = indentUnitOf(sourceCode.getText());
135
+ indentUnit = indentUnitOf(sourceCode);
125
136
  }
126
137
  return indentUnit;
127
138
  };
@@ -17,9 +17,11 @@ type ParserOptionsCarrier = {
17
17
  * and its rule silently drops out of the fixer, convergence, collision and
18
18
  * crash sweeps. `src/tests/no-local-rule-tester.test.ts` enforces that.
19
19
  *
20
- * A file needing parser options the shared instances do not declare — ES module
21
- * scope analysis, a type-aware `project` — attaches them per case rather than
22
- * forking a tester. RuleTester deep merges each case's config over the tester's,
20
+ * A file needing parser options the shared instances do not declare — a
21
+ * type-aware `project`, a non-default `ecmaVersion` — attaches them per case
22
+ * rather than forking a tester. The shared instances already declare ES module
23
+ * scope analysis, so a case restating `sourceType: 'module'` is redundant but
24
+ * harmless. RuleTester deep merges each case's config over the tester's,
23
25
  * and options a case declares itself still win over the ones applied here, so a
24
26
  * case keeps any override it already had. Carrying the options on the case also
25
27
  * means the harvested corpus records the parser configuration a snippet was
@@ -3,12 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withParserOptions = exports.ruleTesterMarkdown = exports.ruleTesterJson = exports.ruleTesterJsx = exports.ruleTesterTs = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const eslint_1 = require("eslint");
6
+ /**
7
+ * `sourceType: 'module'` matches how the linted codebase actually parses: every
8
+ * consumer source file is an ES module, so its top-level declarations live in a
9
+ * module scope nested inside the global one.
10
+ *
11
+ * `@typescript-eslint/parser` defaults to `'script'`, under which a top-level
12
+ * `import`/`const` still binds — the binding hangs off the *global* scope rather
13
+ * than a module scope. References therefore still resolve either way, but the
14
+ * scope shape differs: under `'script'` `globalScope.variables` carries the
15
+ * file's own declarations and there is no module scope at all. A rule that
16
+ * discriminates on `scope.type`, walks `globalScope.childScopes`, or reads
17
+ * `globalScope.variables` would otherwise be exercised against a shape no real
18
+ * file has. `src/tests/rule-tester-parse-mode.test.ts` pins this.
19
+ */
20
+ const SHARED_PARSER_OPTIONS = {
21
+ sourceType: 'module',
22
+ };
6
23
  exports.ruleTesterTs = new utils_1.ESLintUtils.RuleTester({
7
24
  parser: '@typescript-eslint/parser',
25
+ parserOptions: { ...SHARED_PARSER_OPTIONS },
8
26
  });
9
27
  exports.ruleTesterJsx = new utils_1.ESLintUtils.RuleTester({
10
28
  parser: '@typescript-eslint/parser',
11
29
  parserOptions: {
30
+ ...SHARED_PARSER_OPTIONS,
12
31
  ecmaFeatures: {
13
32
  jsx: true,
14
33
  },
@@ -32,9 +51,11 @@ exports.ruleTesterMarkdown = new eslint_1.RuleTester({
32
51
  * and its rule silently drops out of the fixer, convergence, collision and
33
52
  * crash sweeps. `src/tests/no-local-rule-tester.test.ts` enforces that.
34
53
  *
35
- * A file needing parser options the shared instances do not declare — ES module
36
- * scope analysis, a type-aware `project` — attaches them per case rather than
37
- * forking a tester. RuleTester deep merges each case's config over the tester's,
54
+ * A file needing parser options the shared instances do not declare — a
55
+ * type-aware `project`, a non-default `ecmaVersion` — attaches them per case
56
+ * rather than forking a tester. The shared instances already declare ES module
57
+ * scope analysis, so a case restating `sourceType: 'module'` is redundant but
58
+ * harmless. RuleTester deep merges each case's config over the tester's,
38
59
  * and options a case declares itself still win over the ones applied here, so a
39
60
  * case keeps any override it already had. Carrying the options on the case also
40
61
  * means the harvested corpus records the parser configuration a snippet was
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "1.20.67",
3
+ "version": "1.20.68",
4
4
  "description": "Custom eslint rules for use within BluMint",
5
5
  "author": {
6
6
  "name": "Brodie McGuire",
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "version": "1.20.68",
4
+ "date": "2026-08-01T18:03:14.950Z",
5
+ "rules": [
6
+ {
7
+ "name": "prefer-union-from-const-array",
8
+ "changeType": "fix",
9
+ "issues": [
10
+ 1577
11
+ ],
12
+ "summary": "exclude block comments by range when inferring the indent unit (closes #1577)"
13
+ }
14
+ ]
15
+ },
2
16
  {
3
17
  "version": "1.20.67",
4
18
  "date": "2026-08-01T17:17:30.817Z",