Skip to content

Instantly share code, notes, and snippets.

@capitaletech
Forked from Illyism/custom-rules.js
Created March 17, 2025 05:38
Show Gist options
  • Save capitaletech/f0aeb33a4fdeb8a555b30059ac5708cc to your computer and use it in GitHub Desktop.
Save capitaletech/f0aeb33a4fdeb8a555b30059ac5708cc to your computer and use it in GitHub Desktop.

Revisions

  1. @Illyism Illyism revised this gist Mar 16, 2025. 1 changed file with 77 additions and 18 deletions.
    95 changes: 77 additions & 18 deletions custom-rules.js
    Original file line number Diff line number Diff line change
    @@ -4,61 +4,120 @@
    * - Counts only actual code (ignores comments)
    * - Gives helpful refactoring suggestions
    * - Works perfectly with Cursor AI's "Fix in Chat"
    *
    *
    * Custom ESLint rule to limit file size to 200 lines
    * @type {import("eslint").Rule.RuleModule}
    */
    export const maxFileLines = {
    meta: {
    type: 'suggestion',
    docs: {
    description: 'Enforce maximum file line count of 200',
    description: 'Enforce maximum file line count (default: 200)',
    category: 'Best Practices',
    recommended: true,
    },
    schema: [], // no options
    schema: [
    {
    type: 'object',
    properties: {
    max: { type: 'integer', minimum: 1 },
    skipBlankLines: { type: 'boolean' },
    skipComments: { type: 'boolean' },
    skipImports: { type: 'boolean' },
    },
    additionalProperties: false,
    },
    ],
    messages: {
    tooManyLines:
    'File has too many lines ({{count}}). Maximum allowed is 200 lines. Please split this file into smaller, more focused modules with single responsibilities. Consider extracting utility functions, separating components, or moving complex logic into dedicated files.',
    'File has too many lines ({{count}}). Maximum allowed is {{max}} lines. Please split this file into smaller, more focused modules with single responsibilities. Consider extracting utility functions, separating components, or moving complex logic into dedicated files.',
    },
    },
    create(context) {
    // Get rule options with defaults
    const options = {
    max: 200,
    skipBlankLines: true,
    skipComments: true,
    skipImports: true,
    ...context.options[0],
    }
    const maxLines = options.max
    const skipBlankLines = options.skipBlankLines !== false
    const skipComments = options.skipComments !== false
    const skipImports = options.skipImports !== false

    return {
    Program(node) {
    const sourceCode = context.sourceCode()
    const lines = sourceCode.lines || sourceCode.text.split(/\r?\n/)
    const lines = context.sourceCode.lines || context.sourceCode.text.split(/\r?\n/)

    // Count non-empty, non-comment lines
    let codeLineCount = 0
    const comments = sourceCode.getAllComments()
    const comments = context.sourceCode.getAllComments()
    const commentLines = new Set()
    const importLines = new Set()

    // Mark all comment lines
    comments.forEach(comment => {
    const startLine = comment.loc.start.line
    const endLine = comment.loc.end.line
    // Mark all comment lines if we're skipping them
    if (skipComments) {
    comments.forEach(comment => {
    const startLine = comment.loc.start.line
    const endLine = comment.loc.end.line

    for (let i = startLine; i <= endLine; i++) {
    commentLines.add(i)
    }
    })
    for (let i = startLine; i <= endLine; i++) {
    commentLines.add(i)
    }
    })
    }

    // Mark all import lines if we're skipping them
    if (skipImports) {
    context.sourceCode.ast.body.forEach(statement => {
    if (
    statement.type === 'ImportDeclaration' ||
    (statement.type === 'ExpressionStatement' &&
    statement.expression.type === 'CallExpression' &&
    statement.expression.callee.name === 'require')
    ) {
    const startLine = statement.loc.start.line
    const endLine = statement.loc.end.line

    for (let i = startLine; i <= endLine; i++) {
    importLines.add(i)
    }
    }
    })
    }

    // Count actual code lines
    for (let i = 0; i < lines.length; i++) {
    const lineNumber = i + 1
    const line = lines[i].trim()

    if (line.length > 0 && !commentLines.has(lineNumber)) {
    codeLineCount++
    // Skip blank lines if configured to do so
    if (skipBlankLines && line.length === 0) {
    continue
    }

    // Skip comment lines if configured to do so
    if (skipComments && commentLines.has(lineNumber)) {
    continue
    }

    // Skip import lines if configured to do so
    if (skipImports && importLines.has(lineNumber)) {
    continue
    }

    codeLineCount++
    }

    if (codeLineCount > 200) {
    if (codeLineCount > maxLines) {
    context.report({
    node,
    messageId: 'tooManyLines',
    data: {
    count: codeLineCount,
    max: maxLines,
    },
    })
    }
  2. @Illyism Illyism revised this gist Mar 15, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion custom-rules.js
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ export const maxFileLines = {
    create(context) {
    return {
    Program(node) {
    const sourceCode = context.getSourceCode()
    const sourceCode = context.sourceCode()
    const lines = sourceCode.lines || sourceCode.text.split(/\r?\n/)

    // Count non-empty, non-comment lines
  3. @Illyism Illyism revised this gist Mar 15, 2025. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions custom-rules.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,10 @@
    /**
    * 🧠 My game-changing ESLint rule that makes AI coding 10x better:
    * - Enforces 200-line max file size
    * - Counts only actual code (ignores comments)
    * - Gives helpful refactoring suggestions
    * - Works perfectly with Cursor AI's "Fix in Chat"
    *
    * Custom ESLint rule to limit file size to 200 lines
    * @type {import("eslint").Rule.RuleModule}
    */
  4. @Illyism Illyism revised this gist Mar 15, 2025. No changes.
  5. @Illyism Illyism revised this gist Mar 15, 2025. No changes.
  6. @Illyism Illyism created this gist Mar 15, 2025.
    71 changes: 71 additions & 0 deletions custom-rules.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    /**
    * Custom ESLint rule to limit file size to 200 lines
    * @type {import("eslint").Rule.RuleModule}
    */
    export const maxFileLines = {
    meta: {
    type: 'suggestion',
    docs: {
    description: 'Enforce maximum file line count of 200',
    category: 'Best Practices',
    recommended: true,
    },
    schema: [], // no options
    messages: {
    tooManyLines:
    'File has too many lines ({{count}}). Maximum allowed is 200 lines. Please split this file into smaller, more focused modules with single responsibilities. Consider extracting utility functions, separating components, or moving complex logic into dedicated files.',
    },
    },
    create(context) {
    return {
    Program(node) {
    const sourceCode = context.getSourceCode()
    const lines = sourceCode.lines || sourceCode.text.split(/\r?\n/)

    // Count non-empty, non-comment lines
    let codeLineCount = 0
    const comments = sourceCode.getAllComments()
    const commentLines = new Set()

    // Mark all comment lines
    comments.forEach(comment => {
    const startLine = comment.loc.start.line
    const endLine = comment.loc.end.line

    for (let i = startLine; i <= endLine; i++) {
    commentLines.add(i)
    }
    })

    // Count actual code lines
    for (let i = 0; i < lines.length; i++) {
    const lineNumber = i + 1
    const line = lines[i].trim()

    if (line.length > 0 && !commentLines.has(lineNumber)) {
    codeLineCount++
    }
    }

    if (codeLineCount > 200) {
    context.report({
    node,
    messageId: 'tooManyLines',
    data: {
    count: codeLineCount,
    },
    })
    }
    },
    }
    },
    }

    /**
    * Plugin object with our custom rules
    */
    export const customRules = {
    rules: {
    'max-file-lines': maxFileLines,
    },
    }
    19 changes: 19 additions & 0 deletions eslint.config.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    import js from '@eslint/js'
    import { customRules } from './custom-rules.js'

    /**
    * A minimal shared ESLint configuration with custom rules.
    *
    * @type {import("eslint").Linter.Config[]}
    */
    export const config = [
    js.configs.recommended,
    {
    plugins: {
    'custom-rules': customRules,
    },
    rules: {
    'custom-rules/max-file-lines': 'warn',
    },
    },
    ]