From a319b6ea2a2ec9a66e30e237fca9d6b4c46f4d57 Mon Sep 17 00:00:00 2001 From: neverland Date: Thu, 24 Sep 2026 17:45:58 +0800 Subject: [PATCH 1/2] refactor(config): concatenate lint config layers --- packages/rstack/src/lintConfig.ts | 10 +++++++ packages/rstack/src/rslintConfig.ts | 11 +++----- .../rstack/tests/config/lint-merge.test.ts | 26 +++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 packages/rstack/src/lintConfig.ts create mode 100644 packages/rstack/tests/config/lint-merge.test.ts diff --git a/packages/rstack/src/lintConfig.ts b/packages/rstack/src/lintConfig.ts new file mode 100644 index 00000000..1cadf632 --- /dev/null +++ b/packages/rstack/src/lintConfig.ts @@ -0,0 +1,10 @@ +import type { RslintConfig } from '@rslint/core'; +import type { Configs } from './config.ts'; +import { resolveConfigLayers } from './configLayers.ts'; + +export const resolveRslintConfig = async ( + layers: readonly Configs[], +): Promise => { + const configs = await resolveConfigLayers(layers, 'lint'); + return configs.length > 1 ? configs.flat() : configs[0]; +}; diff --git a/packages/rstack/src/rslintConfig.ts b/packages/rstack/src/rslintConfig.ts index b1f4faa6..7d45e30f 100644 --- a/packages/rstack/src/rslintConfig.ts +++ b/packages/rstack/src/rslintConfig.ts @@ -3,24 +3,19 @@ import { join } from 'node:path'; import { loadRstackConfig, type LoadedRstackConfig } from './config.ts'; import type { RslintConfig } from '@rslint/core'; import { color, logger } from 'rslog'; +import { resolveRslintConfig } from './lintConfig.ts'; // Expose the loaded config so `rs check` can pass it to fmt instead of loading // and executing the Rstack config a second time. export const loadedConfig: LoadedRstackConfig = await loadRstackConfig(); const { configs } = loadedConfig; -const lintDefinition = configs.lint; +const lintConfig = await resolveRslintConfig([configs]); -let lintConfig: RslintConfig; - -if (lintDefinition === undefined) { +if (lintConfig === undefined) { logger.error( `No lint configuration found. Add ${color.cyan('define.lint(...)')} to your Rstack config file.`, ); process.exit(1); -} else if (typeof lintDefinition === 'function') { - lintConfig = await lintDefinition(); -} else { - lintConfig = lintDefinition; } const basePath = process.cwd(); diff --git a/packages/rstack/tests/config/lint-merge.test.ts b/packages/rstack/tests/config/lint-merge.test.ts new file mode 100644 index 00000000..b68723b7 --- /dev/null +++ b/packages/rstack/tests/config/lint-merge.test.ts @@ -0,0 +1,26 @@ +import type { RslintConfig } from '@rslint/core'; +import { expect, test } from 'rstack/test'; +import { normalizeRstackConfig } from '../../src/config.ts'; +import { resolveRslintConfig } from '../../src/lintConfig.ts'; + +test('concatenates lint layers in order without merging entries', async () => { + const shared: RslintConfig = [ + { ignores: ['dist/**'] }, + [{ files: ['**/*.js'], rules: { 'no-debugger': 'error' } }], + ]; + const project: RslintConfig = [{ rules: { 'no-debugger': 'off' } }]; + + const config = await resolveRslintConfig([ + { lint: shared }, + normalizeRstackConfig({ lint: () => Promise.resolve(project) }), + ]); + + expect(config).toEqual([...shared, ...project]); +}); + +test('preserves a single lint config and distinguishes missing from empty', async () => { + const config: RslintConfig = []; + + expect(await resolveRslintConfig([{}])).toBeUndefined(); + expect(await resolveRslintConfig([{}, { lint: config }])).toBe(config); +}); From 35e47578f1777a19c3548d995e95e8e675bc0a3d Mon Sep 17 00:00:00 2001 From: neverland Date: Sat, 26 Sep 2026 10:25:10 +0800 Subject: [PATCH 2/2] refactor(config): move lint resolver into config layers --- packages/rstack/src/configLayers.ts | 9 ++++++++- packages/rstack/src/lintConfig.ts | 10 ---------- packages/rstack/src/rslintConfig.ts | 2 +- packages/rstack/tests/config/lint-merge.test.ts | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 packages/rstack/src/lintConfig.ts diff --git a/packages/rstack/src/configLayers.ts b/packages/rstack/src/configLayers.ts index f97ae2b5..dd83834c 100644 --- a/packages/rstack/src/configLayers.ts +++ b/packages/rstack/src/configLayers.ts @@ -28,7 +28,7 @@ type ConfigArgs = K extends 'app' /** * Resolve one tool from ordered, normalized config layers. Lint factories are - * already wrapped by define.lint; merging belongs to the tool adapters. + * already wrapped by define.lint. This function does not merge the results. */ export const resolveConfigLayers = async ( layers: readonly Configs[], @@ -56,3 +56,10 @@ export const resolveConfigLayers = async ( return configs; }; + +export const resolveRslintConfig = async ( + layers: readonly Configs[], +): Promise => { + const configs = await resolveConfigLayers(layers, 'lint'); + return configs.length > 1 ? configs.flat() : configs[0]; +}; diff --git a/packages/rstack/src/lintConfig.ts b/packages/rstack/src/lintConfig.ts deleted file mode 100644 index 1cadf632..00000000 --- a/packages/rstack/src/lintConfig.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RslintConfig } from '@rslint/core'; -import type { Configs } from './config.ts'; -import { resolveConfigLayers } from './configLayers.ts'; - -export const resolveRslintConfig = async ( - layers: readonly Configs[], -): Promise => { - const configs = await resolveConfigLayers(layers, 'lint'); - return configs.length > 1 ? configs.flat() : configs[0]; -}; diff --git a/packages/rstack/src/rslintConfig.ts b/packages/rstack/src/rslintConfig.ts index 7d45e30f..c221f359 100644 --- a/packages/rstack/src/rslintConfig.ts +++ b/packages/rstack/src/rslintConfig.ts @@ -3,7 +3,7 @@ import { join } from 'node:path'; import { loadRstackConfig, type LoadedRstackConfig } from './config.ts'; import type { RslintConfig } from '@rslint/core'; import { color, logger } from 'rslog'; -import { resolveRslintConfig } from './lintConfig.ts'; +import { resolveRslintConfig } from './configLayers.ts'; // Expose the loaded config so `rs check` can pass it to fmt instead of loading // and executing the Rstack config a second time. diff --git a/packages/rstack/tests/config/lint-merge.test.ts b/packages/rstack/tests/config/lint-merge.test.ts index b68723b7..10824723 100644 --- a/packages/rstack/tests/config/lint-merge.test.ts +++ b/packages/rstack/tests/config/lint-merge.test.ts @@ -1,7 +1,7 @@ import type { RslintConfig } from '@rslint/core'; import { expect, test } from 'rstack/test'; import { normalizeRstackConfig } from '../../src/config.ts'; -import { resolveRslintConfig } from '../../src/lintConfig.ts'; +import { resolveRslintConfig } from '../../src/configLayers.ts'; test('concatenates lint layers in order without merging entries', async () => { const shared: RslintConfig = [