// Flat ESLint config — MAINTAINER / CI ONLY. Never runs on the serve or Docker
// path (constitution Principle I: dev-only tooling is exempt, same category as
// scripts/build-tailwind.sh). It enforces the module-migration guardrails:
//
//   * max-lines — the 1,500-line size norm, as a WARNING ratchet. Legacy
//     monoliths warn (the "this is over the norm, split it" signal) and shrink
//     as the refactor lands; warnings do not fail CI. Genuinely-large files are
//     exempted below, mirroring the signed register in docs/size-exemptions.md.
//   * import-x/no-unresolved + no-cycle — module hygiene, scoped to the real
//     ES-module graphs the refactor produces (a plugin's src/ tree, .mjs
//     tests). no-unresolved (a HARD error) catches broken import paths;
//     no-cycle enforces the downward-only layering rule. Core's classic scripts
//     have no import graph, so both are dormant today and become live gates the
//     moment module code appears — validated against the first real module
//     plugin (R1 pilot).

const importX = require('eslint-plugin-import-x');

// Per-file size ceilings — a mirror of docs/size-exemptions.md (canonical).
// Keep in sync; each entry corresponds to a signed row in the register.
const SIZE_EXEMPTIONS = [
    { files: ['**/static/capabilities.js'], max: 1600 },
    { files: ['**/plugins/capability_inspector/screen.js'], max: 100000 },
    { files: ['**/plugins/folder_library/screen.js'], max: 100000 },
];

const sizeRule = (max) => ['warn', { max, skipBlankLines: false, skipComments: false }];

module.exports = [
    {
        ignores: [
            'node_modules/**',
            'static/vendor/**',
            'plugins/**/assets/vendor/**',
            '**/*.min.js',
            'static/tailwind.min.css',
        ],
    },
    // Size norm across all first-party JS. Classic scripts are parsed as
    // scripts (no import/export); module files get their own block below.
    {
        files: ['**/*.js', '**/*.cjs'],
        languageOptions: { ecmaVersion: 'latest', sourceType: 'script' },
        rules: { 'max-lines': sizeRule(1500) },
    },
    // ES-module graphs (a plugin's src/ tree, .mjs tests, core's own static/js/
    // tree): module parsing + the acyclic-imports hard gate + the size norm. A
    // migrated bundled plugin's entry `import './src/main.js'` screen.js must
    // parse as a module — add its glob here in that plugin's migration PR
    // (classic screen.js stays a script).
    //
    // `static/app.js` is listed explicitly: it is served as
    // <script type="module"> (R3a) and now `import`s its carved-out modules, so
    // parsing it as a script would be a syntax error. It is the ENTRY of core's
    // module graph, which is what makes no-cycle meaningful here — a carved
    // module that imports app.js back would close a cycle and fail this gate.
    {
        files: ['**/src/**/*.js', '**/*.mjs', 'static/app.js', 'static/js/**/*.js', 'static/highway.js'],
        languageOptions: { ecmaVersion: 'latest', sourceType: 'module' },
        plugins: { 'import-x': importX },
        // v4 flat-config resolver (resolver-next + createNodeResolver). Without
        // it the import rules silently skip imports they can't resolve.
        settings: { 'import-x/resolver-next': [importX.createNodeResolver()] },
        rules: {
            'max-lines': sizeRule(1500),
            'import-x/no-unresolved': 'error',
            'import-x/no-cycle': 'error',
        },
    },
    // Signed size exemptions (docs/size-exemptions.md) — raise the ceiling so
    // registered files don't warn below it.
    ...SIZE_EXEMPTIONS.map(({ files, max }) => ({ files, rules: { 'max-lines': sizeRule(max) } })),
];
