eslint-factory: extract nonStringKind to shared module; align setOutput rule with CORE_ALIASES#45973
Conversation
…etOutput rule with CORE_ALIASES - Create `non-string-kind.ts` with shared `nonStringKind()`, kind constants, and `NonStringKind` type - Update `no-core-setoutput-non-string` to use `CORE_ALIASES` (adds `coreObj` coverage) and import from shared module - Update `no-core-exportvariable-non-string` to import from shared module (removes duplicate) - Add `coreObj.setOutput` valid and invalid test cases Closes #45929 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Centralizes non-string value detection and extends setOutput linting to the coreObj alias.
Changes:
- Extracts shared non-string classification logic.
- Aligns
setOutputalias handling withexportVariable. - Adds
coreObj.setOutputcoverage.
Show a summary per file
| File | Description |
|---|---|
non-string-kind.ts |
Adds shared value classification. |
no-core-setoutput-non-string.ts |
Supports all core aliases. |
no-core-setoutput-non-string.test.ts |
Tests coreObj behavior. |
no-core-exportvariable-non-string.ts |
Uses the shared classifier. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Medium
| // Object must be a known @actions/core alias (`core` or `coreObj`) | ||
| if (callee.object.type !== AST_NODE_TYPES.Identifier || !CORE_ALIASES.has(callee.object.name)) return; |
|
✅ Test Quality Sentinel completed test quality analysis. No test files were added or modified in this PR. Test Quality Sentinel skipped. |
|
✅ PR Code Quality Reviewer completed the code quality review. |
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
|
✅ Design Decision Gate 🏗️ completed the design decision gate check. No ADR enforcement needed: PR does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100). |
There was a problem hiding this comment.
{"pull_request_number":45973,"event":"COMMENT","body":"### Review Summary
The refactoring is clean and correct. The shared non-string-kind.ts module eliminates drift risk, and the CORE_ALIASES fix closes the detection gap for coreObj.setOutput. New tests cover the previously-missed cases.
The one outstanding item is already captured in the inline comment: meta.docs.description (and likely README) still references only core.setOutput, which understates the rule scope after the CORE_ALIASES expansion."}
🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 18.4 AIC · ⌖ 4.29 AIC · ⊞ 5K
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design and /tdd — commenting with minor improvement suggestions; no blocking issues.
📋 Key Themes & Highlights
Key Themes
- Test constant coupling: new
coreObjtest cases use raw string literals (e.g."numeric literal") that duplicate values from the freshly-extracted constants — a constant rename would silently leave tests passing. - Surface width: three of the five exported constants (
NUMERIC_LITERAL_KIND,BOOLEAN_LITERAL_KIND,LENGTH_KIND) are not imported by any consumer today; exporting them without a stated reason widens the API unnecessarily. - Coverage gap: the new valid-case test for
coreObjcould add a.lengthinvalid case to match the parity thecorealias tests already have.
Positive Highlights
- ✅ Clean DRY extraction — 78 lines of duplicated logic removed across two rule files
- ✅ Bug fix is well-motivated and the PR description is thorough
- ✅ Good test additions covering numeric, boolean, and null cases for the new alias
- ✅ Symmetric fix:
setOutputrule now usesCORE_ALIASESconsistent withexportVariable
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 32.3 AIC · ⌖ 4.63 AIC · ⊞ 6.7K
Comment /matt to run again
| cjsRuleTester.run("no-core-setoutput-non-string", noCoreSetOutputNonStringRule, { | ||
| valid: [], | ||
| invalid: [ | ||
| { |
There was a problem hiding this comment.
[/tdd] Test assertions use raw string literals for kind data instead of the exported constants — if a constant value changes, the tests will silently pass against stale strings.
💡 Suggested fix
Import and use the constants:
import { NUMERIC_LITERAL_KIND, BOOLEAN_LITERAL_KIND, NULL_KIND } from "./non-string-kind";
// then:
data: { kind: NUMERIC_LITERAL_KIND, valueText: "0" },This makes the test a true regression guard against constant renames.
@copilot please address this.
| export const NULL_KIND = "null" as const; | ||
| export const UNDEFINED_KIND = "undefined" as const; | ||
| export const LENGTH_KIND = ".length (number)" as const; | ||
|
|
There was a problem hiding this comment.
[/codebase-design] NUMERIC_LITERAL_KIND, BOOLEAN_LITERAL_KIND, and LENGTH_KIND are exported but no rule file imports them — only NULL_KIND and UNDEFINED_KIND are imported externally. Exporting unused symbols unnecessarily widens the module's public surface.
💡 Suggestion
Keep only NULL_KIND, UNDEFINED_KIND, NonStringKind, and nonStringKind exported. Either remove the export keyword from the other three constants, or document the intent to make them a public API.
@copilot please address this.
| }); | ||
| }); | ||
|
|
||
| it("valid: coreObj alias with string value is accepted", () => { |
There was a problem hiding this comment.
[/tdd] The new valid-case test covers roundedAIC (an identifier) and "hello" (a string literal), but not expr.length — the .length form is a supported valid passthrough in the shared nonStringKind() (returns non-null, so it should be flagged, not accepted). This could be a spec question worth clarifying with a test.
💡 Context
nonStringKind returns LENGTH_KIND for expr.length, meaning coreObj.setOutput("x", arr.length) is flagged. A test that explicitly asserts this for the coreObj alias (like the core alias tests already do) would complete the coverage.
@copilot please address this.
There was a problem hiding this comment.
Review: Non-blocking observations
The core change is correct — extracting nonStringKind() to a shared module and aligning setOutput to use CORE_ALIASES fixes the real bug. Two issues with the new tests are worth addressing before this is considered complete.
📋 Findings
1. Boolean test omits data field (no-core-setoutput-non-string.test.ts line ~104)
The numeric coreObj test verifies data: { kind, valueText } but the boolean test does not, so a broken message interpolation for booleans goes undetected.
2. Hardcoded kind string literals in test assertions (no-core-setoutput-non-string.test.ts line ~89)
Tests use "numeric literal" etc. as raw strings instead of importing the exported constants from non-string-kind.ts. If a constant value is renamed, tests silently pass while the rule emits the new name — defeating the shared-module centralisation.
(An existing comment on line 36 of no-core-setoutput-non-string.ts also flags that meta.docs.description still says core.setOutput only and should be updated.)
🔎 Code quality review by PR Code Quality Reviewer · 36.8 AIC · ⌖ 4.58 AIC · ⊞ 5.6K
Comment /review to run again
Comments that could not be inline-anchored
eslint-factory/src/rules/no-core-setoutput-non-string.test.ts:104
Boolean error assertion omits data field, leaving message interpolation unverified. The numeric coreObj test (a few lines above) explicitly asserts data: { kind: "numeric literal", valueText: "0" }, but this boolean case does not, so a broken kind or valueText in the boolean branch would go undetected.
<details>
<summary>💡 Suggested fix</summary>
Add the data field to match the numeric test's pattern:
errors: [
{
messageId: "nonStringValue",
data: { kind: "bool…
</details>
<details><summary>eslint-factory/src/rules/no-core-setoutput-non-string.test.ts:89</summary>
**Test assertions hardcode kind string literals instead of importing the exported constants**, defeating the centralisation benefit of the new shared module.
<details>
<summary>💡 Suggested fix</summary>
Import the constants and use them in `data` fields:
```ts
import { NUMERIC_LITERAL_KIND, BOOLEAN_LITERAL_KIND, NULL_KIND } from "./non-string-kind";
// then in errors:
data: { kind: NUMERIC_LITERAL_KIND, valueText: "0" },If NUMERIC_LITERAL_KIND is renamed from "numeric literal" to…
|
🎉 This pull request is included in a new release. Release: |
no-core-setoutput-non-stringhardcodedcallee.object.name !== "core", socoreObj.setOutput("x", 0)escaped detection while the identical call oncorewas flagged. Both rules also embedded a verbatim-duplicatednonStringKind()implementation, creating drift risk.Changes
non-string-kind.ts— shared module exportingnonStringKind(), the five kind constants, andNonStringKindtype; single source of truth for both rules.no-core-setoutput-non-string— replaces hardcodedname !== "core"with!CORE_ALIASES.has(name), matching theexportVariabletwin. Removes local duplicate, imports from shared module.no-core-exportvariable-non-string— removes local duplicate, imports from shared module.coreObjstring values and invalid cases forcoreObj.setOutputwith numeric, boolean, and null args: