Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions modules/eslint-plugin/schematics/ng-add/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
"default": "all",
"enum": [
"all",
"allTypedChecked",
"component-store",
"effects",
"effectsTypedChecked",
"operators",
"signals",
"signalsTypedChecked",
"store"
],
"x-prompt": {
Expand All @@ -24,6 +27,10 @@
"value": "all",
"label": "all"
},
{
"value": "allTypedChecked",
"label": "allTypedChecked"
},
{
"value": "component-store",
"label": "component-store"
Expand All @@ -32,6 +39,10 @@
"value": "effects",
"label": "effects"
},
{
"value": "effectsTypedChecked",
"label": "effectsTypedChecked"
},
{
"value": "operators",
"label": "operators"
Expand All @@ -40,6 +51,10 @@
"value": "signals",
"label": "signals"
},
{
"value": "signalsTypedChecked",
"label": "signalsTypedChecked"
},
{
"value": "store",
"label": "store"
Expand Down
64 changes: 32 additions & 32 deletions modules/eslint-plugin/scripts/generate-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,52 @@ import { NgRxRule } from '../src/rule-creator';
const RULE_MODULE = '@ngrx';
const CONFIG_DIRECTORY = './modules/eslint-plugin/src/configs/';

writeConfig('all', (_rule) => true);
writeConfig('store', (rule) => rule.meta.docs?.ngrxModule === 'store');
writeConfig('effects', (rule) => rule.meta.docs?.ngrxModule === 'effects');
const isModule = (rule: NgRxRule, moduleName: string) =>
rule.meta.docs?.ngrxModule === moduleName;
const isTypeChecked = (rule: NgRxRule) =>
rule.meta.docs?.requiresTypeChecking === true;

writeConfig('all', (rule) => !isTypeChecked(rule));
writeConfig('allTypeChecked', (_rule) => true);

writeConfig(
'store',
(rule) => isModule(rule, 'store') && !isTypeChecked(rule)
);

writeConfig(
'effects',
(rule) => isModule(rule, 'effects') && !isTypeChecked(rule)
);
writeConfig('effectsTypeChecked', (rule) => isModule(rule, 'effects'));

writeConfig(
'component-store',
(rule) => rule.meta.docs?.ngrxModule === 'component-store'
(rule) => isModule(rule, 'component-store') && !isTypeChecked(rule)
);

writeConfig(
'operators',
(rule) => rule.meta.docs?.ngrxModule === 'operators'
(rule) => isModule(rule, 'operators') && !isTypeChecked(rule)
);

writeConfig(
'signals',
(rule) => isModule(rule, 'signals') && !isTypeChecked(rule)
);
writeConfig('signals', (rule) => rule.meta.docs?.ngrxModule === 'signals');
writeConfig('signalsTypeChecked', (rule) => isModule(rule, 'signals'));

async function writeConfig(
configName:
| 'all'
| 'allTypeChecked'
| 'store'
| 'effects'
| 'effectsTypeChecked'
| 'component-store'
| 'operators'
| 'signals',
| 'signals'
| 'signalsTypeChecked',
predicate: (rule: NgRxRule) => boolean
) {
const rulesForConfig = Object.entries(rulesForGenerate).filter(
Expand All @@ -42,14 +67,6 @@ import { NgRxRule } from '../src/rule-creator';
},
{}
);
const requireParserOptions: null | Record<string, string | number> =
rulesForConfig.some(([_, rule]) => rule.meta.docs?.requiresTypeChecking)
? {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json',
}
: null;

const tsCode = `
/**
Expand All @@ -67,7 +84,6 @@ import { NgRxRule } from '../src/rule-creator';
name: 'ngrx/base',
languageOptions: {
parser,
sourceType: 'module',
},
plugins: {
'@ngrx': plugin,
Expand All @@ -77,15 +93,6 @@ import { NgRxRule } from '../src/rule-creator';
name: 'ngrx/${configName}',
languageOptions: {
parser,
${
requireParserOptions
? `parserOptions: ${JSON.stringify(
requireParserOptions,
null,
2
)},`
: ''
}
},
rules: ${JSON.stringify(configRules, null, 2)}
},
Expand All @@ -104,13 +111,6 @@ import { NgRxRule } from '../src/rule-creator';
plugins: ['@ngrx'],
rules: configRules,
};
if (requireParserOptions) {
jsonConfig.parserOptions = {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json',
};
}
const jsonConfigFormatted = await format(
JSON.stringify(jsonConfig, null, 2),
{
Expand Down
11 changes: 8 additions & 3 deletions modules/eslint-plugin/spec/exported-rules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,23 @@ describe('ESLint V8', () => {
});
test('exports all configurations', () => {
const configs = getAllConfigs();
expect(configs.length).toBe(6);
expect(configs.length).toBe(9);
});
});

describe('ESLint V9', () => {
test('exports all rules ', () => {
const rules = getAllRules();
expect(Object.keys((configs.all[1] as any).rules).length).toBe(
expect(Object.keys((configs.allTypeChecked[1] as any).rules).length).toBe(
rules.length
);
});
test('there is a difference between typed checke rules ', () => {
expect(
Object.keys((configs.allTypeChecked[1] as any).rules).length
).toBeGreaterThan(Object.keys((configs.all[1] as any).rules).length);
});
test('exports all configurations', () => {
expect(Object.keys(configs).length).toBe(6);
expect(Object.keys(configs).length).toBe(9);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Ok {
constructor(customStore: ComponentStore<MoviesState>) {
const movies = customStore.select((state) => state.movies);
const selectedId = this.customStore.select((state) => state.selectedId);

this.movie$ = this.customStore.select(
this.movies$,
this.selectedId$,
Expand Down Expand Up @@ -208,7 +208,11 @@ class NotOk {
}`),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Ok {
constructor(private customStore: ComponentStore<MoviesState>) {
const movies = customStore.select((state) => state.movies);
this.firstMovie$ = customStore.select(movies, (movies) => movies[0]);

this.movies$ = this.customStore.select((state) => state.movies);
this.firstMovie$ = this.customStore.select(this.movies$, (movies) => movies[0]);
}
Expand Down Expand Up @@ -87,7 +87,7 @@ import { ComponentStore } from '@ngrx/component-store'

class NotOk {
readonly movies$ = this.customStore.select((state) => state.movies).pipe(
filter(Boolean),
filter(Boolean),
map((movies) => movies)
~~~~~~~~~~~~~~~~~~~~~~~ [${messageId}]
)
Expand Down Expand Up @@ -133,7 +133,11 @@ const invalidInject: () => InvalidTestCase<MessageIds, Options>[] = () => [
}`),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ class BooksStore extends ComponentStore<BooksState> implements OnDestroy {
}`),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: valid(),
invalid: invalid(),
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: valid(),
invalid: invalid(),
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,11 @@ class NotOk6 {
}`),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,11 @@ class Effect {
}`),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@ type Options = ESLintUtils.InferOptionsTypeFromRule<typeof rule>;
const validConstructor: () => (string | ValidTestCase<Options>)[] = () => [
`
import { Store } from '@ngrx/store'

class Ok {
readonly effect = somethingOutside();
}`,
`
import { Store } from '@ngrx/store'

class Ok1 {
effect = createEffect(() => this.actions.pipe(
ofType('PING'),
tap(() => ({ type: 'PONG' }))
))

constructor(private actions: Actions, private store: Store) {}
}`,
`
import { Store } from '@ngrx/store'

class Ok2 {
readonly effect: CreateEffectMetadata

constructor(private actions: Actions, private store$: Store) {
this.effect = createEffect(
() => ({ scheduler = asyncScheduler } = {}) =>
Expand Down Expand Up @@ -591,7 +591,11 @@ class NotOk7 {
),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: [...validConstructor(), ...validInject()],
invalid: [...invalidConstructor(), ...invalidInject()],
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,11 @@ export class AppModule {}`,
),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: valid(),
invalid: invalid(),
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: valid(),
invalid: invalid(),
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ export class Effects {
),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: valid(),
invalid: invalid(),
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: valid(),
invalid: invalid(),
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,11 @@ class Effect {
),
];

ruleTester().run(path.parse(__filename).name, rule, {
valid: valid(),
invalid: invalid(),
});
ruleTester(rule.meta.docs?.requiresTypeChecking).run(
path.parse(__filename).name,
rule,
{
valid: valid(),
invalid: invalid(),
}
);
Loading