mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
* fix(lint): resolve module-boundary and prefer-inject errors Retag workspace-shell-util as type:data-access to match its injectable services that depend on @iptvnator/services, and convert RemoteControlService to inject(HttpClient). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): enforce max-lines 400 with generated baseline Add a max-lines ESLint error (hard cap 400 raw lines per TypeScript file) per the repo file-size rule. The 134 pre-existing offenders are baselined in tools/eslint/max-lines-baseline.mjs, regenerable via generate-max-lines-baseline.mjs; the list should only shrink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(ci): enforce lint on PRs and guard coverage policy drift - Add a Lint job to ci.yml running nx run-many -t lint --all, so module-boundary tags, legacy-alias bans, and max-lines gate merges. - Fix the root lint script (was linting only electron-backend). - Add tools/coverage/check-coverage-policy.mjs: fails CI when a project with a test target is missing from coverage-policy.json; wired into coverage:ci as coverage:policy:check. - Run Tier B/C unit tests in CI without coverage (list derived from the policy), so website/packaging/remote-control tests run on PRs. - Replace the hand-picked 16-project test:unit:ci list with --all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: document CI lint enforcement and coverage policy guard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): address bot review feedback on policy guard and baseline generator - Drive Tier B/C validation from each policy entry's validationCommand (falling back to nx test), skipping projects with an e2e target since the E2E workflow already runs them (Codex). - Fail when a Tier A entry has no test target (Greptile, adapted: checking all entries against test targets would false-positive on the intentionally spec-less e2e/mock-server tiers). - Guard against missing JSON array in nx show projects output (Greptile). - Scan .tsx files in the max-lines baseline generator to match the ESLint rule's file patterns (Greptile). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
279 lines
11 KiB
JavaScript
279 lines
11 KiB
JavaScript
import nx from '@nx/eslint-plugin';
|
|
import { maxLinesBaseline } from './tools/eslint/max-lines-baseline.mjs';
|
|
|
|
const legacyBareAliases = [
|
|
'components',
|
|
'm3u-state',
|
|
'm3u-utils',
|
|
'services',
|
|
'shared-interfaces',
|
|
'shared-portals',
|
|
'remote-control',
|
|
'database',
|
|
'database-schema',
|
|
'database-path-utils',
|
|
'workspace-dashboard-feature',
|
|
'workspace-dashboard-data-access',
|
|
];
|
|
|
|
export default [
|
|
...nx.configs['flat/base'],
|
|
...nx.configs['flat/typescript'],
|
|
...nx.configs['flat/javascript'],
|
|
{
|
|
ignores: ['**/dist'],
|
|
},
|
|
{
|
|
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
|
|
rules: {
|
|
'@nx/enforce-module-boundaries': [
|
|
'error',
|
|
{
|
|
enforceBuildableLibDependency: true,
|
|
allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$'],
|
|
depConstraints: [
|
|
{
|
|
sourceTag: 'type:app',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:feature',
|
|
'type:ui',
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:e2e',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:feature',
|
|
'type:ui',
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:dev-app',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:feature',
|
|
'type:ui',
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:website',
|
|
onlyDependOnLibsWithTags: ['type:ui', 'type:util'],
|
|
},
|
|
{
|
|
sourceTag: 'type:feature',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:feature',
|
|
'type:ui',
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:ui',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:ui',
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:data-access',
|
|
onlyDependOnLibsWithTags: [
|
|
'type:data-access',
|
|
'type:util',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'type:util',
|
|
onlyDependOnLibsWithTags: ['type:util'],
|
|
},
|
|
{
|
|
sourceTag: 'domain:portal-shared',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:portal-shared',
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
'scope:portal',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:m3u',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:portal-shared',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:playlist-import',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:m3u',
|
|
'domain:playlist-import',
|
|
'domain:playback',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'domain:stalker',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:playback',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:portal-shared',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:shared-contracts',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:shared-contracts',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:shared-runtime',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:m3u',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:shared-ui',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:portal-shared',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:xtream',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:xtream',
|
|
'domain:portal-shared',
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:stalker',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:stalker',
|
|
'domain:portal-shared',
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
{
|
|
sourceTag: 'domain:workspace',
|
|
onlyDependOnLibsWithTags: [
|
|
'domain:workspace',
|
|
'domain:portal-shared',
|
|
'domain:xtream',
|
|
'domain:stalker',
|
|
'domain:m3u',
|
|
'domain:playback',
|
|
'domain:shared-contracts',
|
|
'domain:shared-runtime',
|
|
'domain:shared-ui',
|
|
'scope:shared',
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
paths: legacyBareAliases.map((name) => ({
|
|
name,
|
|
message:
|
|
'Use the scoped @iptvnator/* path alias instead of the legacy bare alias.',
|
|
})),
|
|
patterns: legacyBareAliases.map((name) => ({
|
|
group: [`${name}/*`],
|
|
message:
|
|
'Use the scoped @iptvnator/* path alias instead of the legacy bare alias.',
|
|
})),
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
'**/*.ts',
|
|
'**/*.tsx',
|
|
'**/*.cts',
|
|
'**/*.mts',
|
|
'**/*.js',
|
|
'**/*.jsx',
|
|
'**/*.cjs',
|
|
'**/*.mjs',
|
|
],
|
|
// Override or add rules here
|
|
rules: {
|
|
'@angular-eslint/template/click-events-have-key-events': 'off',
|
|
'@angular-eslint/template/interactive-supports-focus': 'off',
|
|
},
|
|
},
|
|
{
|
|
// CLAUDE.md file-size rule: keep TypeScript files under 300 lines,
|
|
// hard maximum 400. Files that predate the rule are baselined below.
|
|
files: ['**/*.ts', '**/*.tsx'],
|
|
rules: {
|
|
'max-lines': [
|
|
'error',
|
|
{ max: 400, skipBlankLines: false, skipComments: false },
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: maxLinesBaseline,
|
|
rules: {
|
|
'max-lines': 'off',
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
'apps/web/src/app/app.component.ts',
|
|
'apps/electron-backend/src/app/events/player.events.ts',
|
|
'libs/epg/data-access/**/*.ts',
|
|
'libs/ui/playback/**/*.ts',
|
|
],
|
|
rules: {
|
|
'no-console': ['warn', { allow: ['debug', 'warn', 'error'] }],
|
|
},
|
|
},
|
|
];
|