Как мое правило знает, когда eslint делается со всеми файлами? - PullRequest
0 голосов
/ 05 июня 2019

В настоящее время я конвертирую свое правило TSLint в ESLint. Вот версия TSLint.

import * as Lint from 'tslint'
import * as ts from 'typescript'
import en from '../app/src/i18n/en'

// counter to keep track of already process files
// we need this to know when we are done, e.g. at the last file
let rootFileCount = -1

// temporary storage for all keys that are used in our components
const foundKeys = new Set()

export class Rule extends Lint.Rules.TypedRule {
  public static FAILURE_STRING =
    'could not find i18n key in english language file'

  public applyWithProgram(
    sourceFile: ts.SourceFile,
    program: ts.Program
  ): Lint.RuleFailure[] {
    // at start set the counter to the number of files
    if (rootFileCount === -1) {
      rootFileCount = program.getRootFileNames().length - 1
    } else {
      // decrease counter for every file visited
      rootFileCount -= 1
    }

    const failures = this.applyWithFunction(sourceFile, walk)

    // when done with files check if we have unused keys inside our translation files
    if (rootFileCount === 0) {
      Object.keys(en).forEach(key => {
        if (!foundKeys.has(key)) {
          throw new Error(`i18n key "${key}" is not being used in any file`)
        }
      })
    }

    return failures
  }
}

function walk(ctx: Lint.WalkContext<void>): void {
  return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void {
    if (node.kind === ts.SyntaxKind.CallExpression) {
      const callExpression = node as ts.CallExpression
      if (callExpression.expression.getText() === 'i18n.transl') {
        const arg = callExpression.arguments[0]
        const argumentName = (arg as ts.Identifier).text
        if (!en[argumentName]) {
          ctx.addFailureAtNode(node, Rule.FAILURE_STRING)
        }
        foundKeys.add(argumentName)
      }
    }
    return ts.forEachChild(node, cb)
  })
}

Что это делает? Он просматривает все мои файлы и ищет i18n.transl('foo'). Мы используем языковые файлы, которые выглядят так:

// en.js
module.exports = {
  foo: 'foo in english'
}

// de.js
module.exports = {
  foo: 'foo in german'
}

Правило должно находить ключи внутри наших языковых файлов, которые мы никогда не используем в нашем приложении. Допустим, наши языковые файлы выглядят так:

// en.js
module.exports = {
  foo: 'foo in english',
  bar: 'bar in english'
}

// de.js
module.exports = {
  foo: 'foo in german',
  bar: 'bar in german'
}

Но i18n.transl('bar') никогда не используется.

Моя проблема: как мне узнать, когда ESLint завершает работу со всеми моими файлами? Это будет шанс сравнить реальные языковые файлы со всеми вхождениями, найденными в приложении. В TSLint я использовал program.getRootFileNames().length, чтобы получить общее количество обрабатываемых файлов. Затем я просто начал обратный отсчет и в 0 сравнил языковой файл en с моим временным набором foundKeys.

Я знаю о хуках Program и Program:exit, но они только для одного файла. Мне нужны крючки для чего-то ESLint:start и ESLint:done.

Я также просмотрел все существующие правила, но не смог найти никаких подсказок. Все они работают с отдельными файлами, а не с несколькими.

Есть идеи? Я застрял. Спасибо!

...