File tree Expand file tree Collapse file tree
tests/cli/specify-config-lint Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11import { join , resolve } from 'node:path' ;
22import { pathToFileURL } from 'node:url' ;
3- import { getConfigState } from '../config.ts' ;
3+ import { CLI_CONFIG_PATH_ENV , getConfigState } from '../config.ts' ;
44import { insertConfigArg , parseArgs , parseCliArgs } from './args.ts' ;
55import { hasHelpFlag , printCommandHelp } from './help.ts' ;
66
@@ -153,6 +153,15 @@ async function runRslintCLI(args: string[]): Promise<void> {
153153 return printCommandHelp ( 'lint' ) ;
154154 }
155155
156+ // Rslint's JS plugin workers inherit `process.env`. Clear an inherited path so
157+ // that a run without `--config` still searches cwd.
158+ const { configPath } = getConfigState ( ) ;
159+ if ( configPath === undefined ) {
160+ delete process . env [ CLI_CONFIG_PATH_ENV ] ;
161+ } else {
162+ process . env [ CLI_CONFIG_PATH_ENV ] = configPath ;
163+ }
164+
156165 const argv = [
157166 process . execPath ,
158167 'rslint' ,
Original file line number Diff line number Diff line change @@ -140,6 +140,13 @@ export const getConfigState = (): ConfigState => {
140140 return globalThis . __rstackCliState ;
141141} ;
142142
143+ /**
144+ * Passes the `--config` path to Rslint's JS plugin workers, which import the
145+ * internal lint config in a fresh realm without the CLI state above. Only that
146+ * config reads it.
147+ */
148+ export const CLI_CONFIG_PATH_ENV = 'RSTACK_CLI_CONFIG_PATH' ;
149+
143150type Define = {
144151 /**
145152 * Inherits shared configs from left to right, followed by the project's own
Original file line number Diff line number Diff line change 11import { existsSync } from 'node:fs' ;
22import { join } from 'node:path' ;
3- import { loadRstackConfig , type LoadedRstackConfig } from './config.ts' ;
3+ import {
4+ CLI_CONFIG_PATH_ENV ,
5+ loadRstackConfig ,
6+ type LoadedRstackConfig ,
7+ } from './config.ts' ;
48import type { RslintConfig } from '@rslint/core' ;
59import { color , logger } from 'rslog' ;
610import { resolveRslintConfig } from './configLayers.ts' ;
711
812// Expose the loaded config so `rs check` can pass it to fmt instead of loading
9- // and executing the Rstack config a second time.
10- export const loadedConfig : LoadedRstackConfig = await loadRstackConfig ( ) ;
13+ // and executing the Rstack config a second time. Rslint also imports this
14+ // module in its JS plugin workers, which get `--config` from the environment.
15+ export const loadedConfig : LoadedRstackConfig = await loadRstackConfig ( {
16+ configFilePath : process . env [ CLI_CONFIG_PATH_ENV ] ,
17+ } ) ;
1118const { configs } = loadedConfig ;
1219const lintConfig = await resolveRslintConfig ( [ configs ] ) ;
1320
Original file line number Diff line number Diff line change 1+ import path from 'node:path' ;
2+ import { test } from '#test-helpers' ;
3+ import { expect } from 'rstack/test' ;
4+
5+ // Rslint runs JS plugin rules in worker threads, which must also load the
6+ // config selected by `--config` instead of searching cwd.
7+ test ( 'should run JS plugin rules from --config outside cwd' , async ( {
8+ execCli,
9+ logHelper,
10+ } ) => {
11+ expect ( ( ) =>
12+ execCli ( 'lint -c workspace/app/rstack.config.ts workspace/app/src' ) ,
13+ ) . toThrow ( ) ;
14+ await logHelper . expectLog ( 'foo is not allowed' ) ;
15+ } ) ;
16+
17+ test ( 'should prefer --config JS plugin rules over the cwd config' , async ( {
18+ cwd,
19+ execCli,
20+ logHelper,
21+ } ) => {
22+ expect ( ( ) =>
23+ execCli ( 'lint -c app/rstack.config.ts app/src' , {
24+ cwd : path . join ( cwd , 'workspace' ) ,
25+ } ) ,
26+ ) . toThrow ( ) ;
27+ await logHelper . expectLog ( 'foo is not allowed' ) ;
28+ logHelper . expectNoLog ( 'rule from the cwd config' ) ;
29+ } ) ;
30+
31+ test ( 'should ignore an inherited config path without --config' , async ( {
32+ cwd,
33+ execCli,
34+ logHelper,
35+ } ) => {
36+ const workspace = path . join ( cwd , 'workspace' ) ;
37+ expect ( ( ) =>
38+ execCli ( 'lint app/src' , {
39+ cwd : workspace ,
40+ env : {
41+ RSTACK_CLI_CONFIG_PATH : path . join ( workspace , 'app/rstack.config.ts' ) ,
42+ } ,
43+ } ) ,
44+ ) . toThrow ( ) ;
45+ await logHelper . expectLog ( 'rule from the cwd config' ) ;
46+ logHelper . expectNoLog ( 'foo is not allowed' ) ;
47+ } ) ;
Original file line number Diff line number Diff line change 1+ import { define } from 'rstack' ;
2+
3+ type Context = { report : ( descriptor : object ) => void } ;
4+
5+ define . lint ( [
6+ {
7+ files : [ '**/*.js' ] ,
8+ plugins : {
9+ local : {
10+ rules : {
11+ 'no-foo' : {
12+ meta : { messages : { foo : 'foo is not allowed' } } ,
13+ create : ( context : Context ) => ( {
14+ Identifier ( node : { name : string } ) {
15+ if ( node . name === 'foo' ) {
16+ context . report ( { node, messageId : 'foo' } ) ;
17+ }
18+ } ,
19+ } ) ,
20+ } ,
21+ } ,
22+ } ,
23+ } ,
24+ rules : { 'local/no-foo' : 'error' } ,
25+ } ,
26+ ] ) ;
Original file line number Diff line number Diff line change 1+ export const foo = 1 ;
Original file line number Diff line number Diff line change 1+ import { define } from 'rstack' ;
2+
3+ type Context = { report : ( descriptor : object ) => void } ;
4+
5+ // Registers the same plugin name as `app/rstack.config.ts` with another rule.
6+ define . lint ( [
7+ {
8+ plugins : {
9+ local : {
10+ rules : {
11+ 'no-foo' : {
12+ meta : { messages : { cwd : 'rule from the cwd config' } } ,
13+ create : ( context : Context ) => ( {
14+ Program ( node : object ) {
15+ context . report ( { node, messageId : 'cwd' } ) ;
16+ } ,
17+ } ) ,
18+ } ,
19+ } ,
20+ } ,
21+ } ,
22+ rules : { 'local/no-foo' : 'error' } ,
23+ } ,
24+ ] ) ;
You can’t perform that action at this time.
0 commit comments