pr-checkmate 1.23.19 → 1.23.20

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/cspell.json CHANGED
@@ -1237,23 +1237,23 @@
1237
1237
  "רטינול"
1238
1238
  ],
1239
1239
  "ignorePaths": [
1240
- "**/node_modules/**",
1241
- "**/dist/**",
1242
- "**/.git/**",
1243
- "**/build/**",
1244
- "**/coverage/**",
1245
- "**/.next/**",
1246
- "**/.nuxt/**",
1247
- "**/out/**",
1248
- "**/__pycache__/**",
1249
- "**/.pytest_cache/**",
1250
- "**/.venv/**",
1251
- "**/venv/**",
1252
- "**/package-lock.json",
1253
- "**/yarn.lock",
1254
- "**/pnpm-lock.yaml",
1255
- "**/*.min.js",
1256
- "**/*.min.css"
1240
+ "/**/node_modules/**",
1241
+ "/**/dist/**",
1242
+ "/**/.git/**",
1243
+ "/**/build/**",
1244
+ "/**/coverage/**",
1245
+ "/**/.next/**",
1246
+ "/**/.nuxt/**",
1247
+ "/**/out/**",
1248
+ "/**/__pycache__/**",
1249
+ "/**/.pytest_cache/**",
1250
+ "/**/.venv/**",
1251
+ "/**/venv/**",
1252
+ "/**/package-lock.json",
1253
+ "/**/yarn.lock",
1254
+ "/**/pnpm-lock.yaml",
1255
+ "/**/*.min.js",
1256
+ "/**/*.min.css"
1257
1257
  ],
1258
1258
  "enableFiletypes": ["typescript", "javascript", "markdown", "json"],
1259
1259
  "ignoreRegExpList": ["/https?:\\/\\/[^\\s]+/g", "/\\b[0-9a-f]{7,40}\\b/gi"]
@@ -1,2 +1,27 @@
1
+ import { CspellConfig } from '../../../interfaces';
1
2
  import { Check } from '../../types';
3
+ /**
4
+ * Anchors an ignore glob to the repository root.
5
+ *
6
+ * cspell matches `ignorePaths` against each file's ABSOLUTE path, so an unanchored
7
+ * `**\/build/**` also matches every ancestor directory of the workspace. On Bitbucket
8
+ * Pipelines the clone lives in `/opt/atlassian/pipelines/agent/build`, so that one
9
+ * pattern excluded the entire repository and the check silently spellchecked nothing.
10
+ * A leading `/` anchors the pattern to the config's directory (the repo root) while
11
+ * `/**\/dir/**` still matches at any depth INSIDE the repo — verified against cspell 10.
12
+ *
13
+ * Patterns that are already anchored (`/…`) or plainly relative (`dir/**`,
14
+ * `CHANGELOG.md`) are left untouched: they cannot match an ancestor.
15
+ */
16
+ export declare function anchorIgnoreGlob(pattern: string): string;
17
+ /**
18
+ * Folds the client's `cspell` block from pr-checkmate.json into the bundled
19
+ * defaults. `enabled` is deliberately not carried over — it gates the check
20
+ * itself (see `applies`) and is not a cspell setting.
21
+ *
22
+ * Lists are appended so a client extends the curated vocabulary instead of
23
+ * replacing it; `language` is the one exception and replaces the default, because
24
+ * a client writing `"en"` means exactly that and appending would be meaningless.
25
+ */
26
+ export declare function mergeCspellConfig(defaultConfig: CspellConfig, userConfig: Partial<CspellConfig>): CspellConfig;
2
27
  export declare const spellcheckCheck: Check;
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.spellcheckCheck = void 0;
7
+ exports.anchorIgnoreGlob = anchorIgnoreGlob;
8
+ exports.mergeCspellConfig = mergeCspellConfig;
7
9
  const node_fs_1 = __importDefault(require("node:fs"));
8
10
  const node_path_1 = __importDefault(require("node:path"));
9
11
  const config_1 = require("../../../config");
@@ -23,6 +25,47 @@ function loadUserCspellConfig(cwd) {
23
25
  return {};
24
26
  }
25
27
  }
28
+ /**
29
+ * Anchors an ignore glob to the repository root.
30
+ *
31
+ * cspell matches `ignorePaths` against each file's ABSOLUTE path, so an unanchored
32
+ * `**\/build/**` also matches every ancestor directory of the workspace. On Bitbucket
33
+ * Pipelines the clone lives in `/opt/atlassian/pipelines/agent/build`, so that one
34
+ * pattern excluded the entire repository and the check silently spellchecked nothing.
35
+ * A leading `/` anchors the pattern to the config's directory (the repo root) while
36
+ * `/**\/dir/**` still matches at any depth INSIDE the repo — verified against cspell 10.
37
+ *
38
+ * Patterns that are already anchored (`/…`) or plainly relative (`dir/**`,
39
+ * `CHANGELOG.md`) are left untouched: they cannot match an ancestor.
40
+ */
41
+ function anchorIgnoreGlob(pattern) {
42
+ return pattern.startsWith('**/') ? `/${pattern}` : pattern;
43
+ }
44
+ /**
45
+ * Folds the client's `cspell` block from pr-checkmate.json into the bundled
46
+ * defaults. `enabled` is deliberately not carried over — it gates the check
47
+ * itself (see `applies`) and is not a cspell setting.
48
+ *
49
+ * Lists are appended so a client extends the curated vocabulary instead of
50
+ * replacing it; `language` is the one exception and replaces the default, because
51
+ * a client writing `"en"` means exactly that and appending would be meaningless.
52
+ */
53
+ function mergeCspellConfig(defaultConfig, userConfig) {
54
+ const dictionaries = [...(defaultConfig.dictionaries ?? []), ...(userConfig.dictionaries ?? [])];
55
+ return {
56
+ ...defaultConfig,
57
+ language: userConfig.language || defaultConfig.language,
58
+ words: [...defaultConfig.words, ...(userConfig.words || [])],
59
+ // Client globs are anchored too — a repo's own pattern is meant to be relative
60
+ // to that repo, never to whatever directories sit above the checkout.
61
+ ignorePaths: [...defaultConfig.ignorePaths, ...(userConfig.ignorePaths || [])].map(anchorIgnoreGlob),
62
+ ignoreRegExpList: [...defaultConfig.ignoreRegExpList, ...(userConfig.ignoreRegExpList || [])],
63
+ // The bundled dictionaries arrive through `import`, so there is nothing to
64
+ // override here. cspell ignores names it cannot resolve, so a client typo
65
+ // costs coverage but never fails the run.
66
+ ...(dictionaries.length > 0 ? { dictionaries } : {}),
67
+ };
68
+ }
26
69
  function createTempCspellConfig(cwd) {
27
70
  const packageConfigPath = (0, config_1.getPackageConfigPath)('cspell.json');
28
71
  const packageConfigDir = node_path_1.default.dirname(packageConfigPath);
@@ -40,11 +83,8 @@ function createTempCspellConfig(cwd) {
40
83
  }
41
84
  });
42
85
  const mergedConfig = {
43
- ...defaultConfig,
86
+ ...mergeCspellConfig(defaultConfig, userConfig),
44
87
  import: resolvedImports,
45
- words: [...defaultConfig.words, ...(userConfig.words || [])],
46
- ignorePaths: [...defaultConfig.ignorePaths, ...(userConfig.ignorePaths || [])],
47
- ignoreRegExpList: [...defaultConfig.ignoreRegExpList, ...(userConfig.ignoreRegExpList || [])],
48
88
  };
49
89
  const tempConfigPath = node_path_1.default.join(cwd, '.cspell.temp.json');
50
90
  node_fs_1.default.writeFileSync(tempConfigPath, JSON.stringify(mergedConfig, null, 2));
@@ -53,26 +93,46 @@ function createTempCspellConfig(cwd) {
53
93
  exports.spellcheckCheck = {
54
94
  name: 'Spellcheck',
55
95
  phase: 'informational',
56
- applies() {
57
- return true;
96
+ /**
97
+ * Clients turn the check off with `cspell.enabled: false` (or the `spellcheck`
98
+ * alias the config interface uses). The universal `severity: { Spellcheck: "off" }`
99
+ * switch keeps working too — this is the per-check flag every other check exposes.
100
+ */
101
+ applies(ctx) {
102
+ return ctx.config.cspell?.enabled !== false && ctx.config.spellcheck?.enabled !== false;
58
103
  },
59
104
  async run(ctx) {
60
- const files = await (0, targets_1.resolveScopedTargetFiles)(ctx, ['*.ts', '*.tsx', '*.js', '*.jsx', '*.md', '*.mdx', '*.json'], (0, config_1.getSourcePaths)());
61
- if (files === null)
105
+ const targets = await (0, targets_1.resolveScopedTargetFiles)(ctx, ['*.ts', '*.tsx', '*.js', '*.jsx', '*.md', '*.mdx', '*.json'], (0, config_1.getSourcePaths)());
106
+ if (targets === null)
62
107
  return (0, types_1.skip)('git unavailable');
108
+ // Committed build output and test reports are dropped here, in JS, against
109
+ // repo-RELATIVE paths — a client cannot fix a typo in a generated file, so
110
+ // reporting one is noise that buries the real findings. Neither cspell
111
+ // mechanism can do this safely: `--exclude` ignores glob anchoring outright
112
+ // (`--exclude=/**/build/**` still matches an ancestor `build` dir, which on
113
+ // Bitbucket Pipelines is the checkout itself), and `ignorePaths` only reaches
114
+ // repos that have no cspell config of their own. Filtering the list keeps one
115
+ // rule for every repo. `ignoreDirs` already covers plain directory names via
116
+ // `resolveTargetFiles`; this adds the composite globs it cannot express
117
+ // (`**/cypress/videos/**`, `**/jest-html-reporters-*/**`).
118
+ const files = targets.filter(f => !(0, utils_1.matchesAnyGlob)(f, config_1.IGNORE_PATTERNS));
63
119
  if (files.length === 0)
64
120
  return (0, types_1.pass)('no files to spellcheck');
65
- const patterns = [...files, ...config_1.IGNORE_PATTERNS.map(p => `--exclude=${p}`)];
66
121
  const hasLocal = (0, config_1.hasLocalConfig)(['cspell.json', '.cspell.json', 'cspell.config.json']);
67
122
  let tempConfigPath = null;
68
123
  const cspellBin = (0, utils_1.resolvePackageBin)('cspell', 'bin.mjs');
124
+ // `--no-must-find-files`: cspell exits 1 when it checked nothing, which the
125
+ // exit-code mapping below would report as "spelling issues found" — a warning
126
+ // about problems that do not exist. Every file being excluded is a pass, not a
127
+ // finding.
128
+ const baseArgs = [...files, '--no-progress', '--no-must-find-files'];
69
129
  let args;
70
130
  if (hasLocal) {
71
- args = [...patterns, '--no-progress'];
131
+ args = baseArgs;
72
132
  }
73
133
  else {
74
134
  tempConfigPath = createTempCspellConfig(ctx.cwd);
75
- args = [...patterns, '--config', tempConfigPath, '--no-progress'];
135
+ args = [...baseArgs, '--config', tempConfigPath];
76
136
  }
77
137
  try {
78
138
  const result = await (0, execa_1.execa)(process.execPath, [cspellBin, ...args], {
package/dist/init.js CHANGED
@@ -58,8 +58,14 @@ const DEFAULT_CONFIG = {
58
58
  prettier: {
59
59
  rules: {},
60
60
  },
61
- // Cspell customization
61
+ // Spellcheck (cspell). `enabled: false` turns the check off — that part always
62
+ // applies. The lists feed the cspell config pr-checkmate generates, so they are
63
+ // ignored when the repo has a cspell.json of its own; all of them are appended to
64
+ // the bundled defaults. `ignorePaths` takes globs to skip (e.g. "CHANGELOG.md",
65
+ // "generated/**"), anchored to the repo root so a pattern never matches a
66
+ // directory above the checkout.
62
67
  cspell: {
68
+ enabled: true,
63
69
  words: [],
64
70
  ignorePaths: [],
65
71
  ignoreRegExpList: [],
@@ -19,6 +19,8 @@ export interface CspellConfig {
19
19
  ignorePaths: string[];
20
20
  enableFiletypes: string[];
21
21
  ignoreRegExpList: string[];
22
+ dictionaries?: string[];
23
+ enabled?: boolean;
22
24
  }
23
25
  export interface PRCheckMateConfig {
24
26
  sourcePath: string | string[];
@@ -42,10 +44,19 @@ export interface PRCheckMateConfig {
42
44
  config?: Record<string, any>;
43
45
  };
44
46
  spellcheck?: {
47
+ enabled?: boolean;
45
48
  words?: string[];
46
49
  ignoreWords?: string[];
47
50
  ignorePaths?: string[];
48
51
  };
52
+ cspell?: {
53
+ enabled?: boolean;
54
+ words?: string[];
55
+ ignorePaths?: string[];
56
+ ignoreRegExpList?: string[];
57
+ dictionaries?: string[];
58
+ language?: string;
59
+ };
49
60
  security?: {
50
61
  gitleaks?: {
51
62
  enabled?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-checkmate",
3
- "version": "1.23.19",
3
+ "version": "1.23.20",
4
4
  "description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -149,6 +149,18 @@
149
149
  "caseCollision": { "$ref": "#/$defs/toggle" },
150
150
  "sensitiveFileGuard": { "$ref": "#/$defs/toggle" },
151
151
  "configValidation": { "$ref": "#/$defs/toggle" },
152
+ "cspell": {
153
+ "description": "Spellcheck control. 'enabled: false' turns the check off. The other fields configure the cspell config pr-checkmate generates, so they apply only when the repository has no cspell.json of its own: 'words', 'ignorePaths', 'ignoreRegExpList' and 'dictionaries' are appended to the bundled defaults, 'language' replaces it. Ignore globs are anchored to the repository root, so '**/dist/**' never matches a directory above the checkout.",
154
+ "type": "object",
155
+ "properties": {
156
+ "enabled": { "type": "boolean" },
157
+ "language": { "type": "string" },
158
+ "words": { "type": "array", "items": { "type": "string" } },
159
+ "dictionaries": { "type": "array", "items": { "type": "string" } },
160
+ "ignorePaths": { "type": "array", "items": { "type": "string" } },
161
+ "ignoreRegExpList": { "type": "array", "items": { "type": "string" } }
162
+ }
163
+ },
152
164
  "yamlLint": {
153
165
  "type": "object",
154
166
  "properties": {
@@ -1237,23 +1237,23 @@
1237
1237
  "רטינול"
1238
1238
  ],
1239
1239
  "ignorePaths": [
1240
- "**/node_modules/**",
1241
- "**/dist/**",
1242
- "**/.git/**",
1243
- "**/build/**",
1244
- "**/coverage/**",
1245
- "**/.next/**",
1246
- "**/.nuxt/**",
1247
- "**/out/**",
1248
- "**/__pycache__/**",
1249
- "**/.pytest_cache/**",
1250
- "**/.venv/**",
1251
- "**/venv/**",
1252
- "**/package-lock.json",
1253
- "**/yarn.lock",
1254
- "**/pnpm-lock.yaml",
1255
- "**/*.min.js",
1256
- "**/*.min.css"
1240
+ "/**/node_modules/**",
1241
+ "/**/dist/**",
1242
+ "/**/.git/**",
1243
+ "/**/build/**",
1244
+ "/**/coverage/**",
1245
+ "/**/.next/**",
1246
+ "/**/.nuxt/**",
1247
+ "/**/out/**",
1248
+ "/**/__pycache__/**",
1249
+ "/**/.pytest_cache/**",
1250
+ "/**/.venv/**",
1251
+ "/**/venv/**",
1252
+ "/**/package-lock.json",
1253
+ "/**/yarn.lock",
1254
+ "/**/pnpm-lock.yaml",
1255
+ "/**/*.min.js",
1256
+ "/**/*.min.css"
1257
1257
  ],
1258
1258
  "enableFiletypes": ["typescript", "javascript", "markdown", "json"],
1259
1259
  "ignoreRegExpList": ["/https?:\\/\\/[^\\s]+/g", "/\\b[0-9a-f]{7,40}\\b/gi"]
@@ -149,6 +149,18 @@
149
149
  "caseCollision": { "$ref": "#/$defs/toggle" },
150
150
  "sensitiveFileGuard": { "$ref": "#/$defs/toggle" },
151
151
  "configValidation": { "$ref": "#/$defs/toggle" },
152
+ "cspell": {
153
+ "description": "Spellcheck control. 'enabled: false' turns the check off. The other fields configure the cspell config pr-checkmate generates, so they apply only when the repository has no cspell.json of its own: 'words', 'ignorePaths', 'ignoreRegExpList' and 'dictionaries' are appended to the bundled defaults, 'language' replaces it. Ignore globs are anchored to the repository root, so '**/dist/**' never matches a directory above the checkout.",
154
+ "type": "object",
155
+ "properties": {
156
+ "enabled": { "type": "boolean" },
157
+ "language": { "type": "string" },
158
+ "words": { "type": "array", "items": { "type": "string" } },
159
+ "dictionaries": { "type": "array", "items": { "type": "string" } },
160
+ "ignorePaths": { "type": "array", "items": { "type": "string" } },
161
+ "ignoreRegExpList": { "type": "array", "items": { "type": "string" } }
162
+ }
163
+ },
152
164
  "yamlLint": {
153
165
  "type": "object",
154
166
  "properties": {