На момент написания этой статьи у меня уже было опубликовано рабочее расширение для торговой площадки Visual Studio Code под названием OpenAPI Linter. Хотел поделиться своим опытом сборки.

Что такое линтер?

Lint, или линтер, — это инструмент статического анализа кода, используемый для пометки ошибок программирования, багов, стилистических ошибок и подозрительных конструкций.

Я вытащил приведенную выше цитату из википедии сюда. Я хотел бы добавить, что линтер используется не только для пометки проблем, но иногда и для их исправления. Я расскажу об этом подробнее в разделе ESLint ниже.

Одним из самых популярных линтеров является ESLint. Бьюсь об заклад, 99% программистов JavaScript использовали его прямо или косвенно:

Возьмем, к примеру, этот скриншот, линтер нашел пару проблем в фрагменте кода. Красные подчеркивания — это ошибки, желтые — предупреждения. Мы могли бы навести курсор, чтобы прочитать более подробную информацию:

Вы можете видеть, что есть также опция «Быстрое исправление…», что означает наличие предлагаемых исправлений проблемы, предоставленной линтером. Мы могли бы просто применить исправление, щелкнув мышью, или мы могли бы настроить Visual Studio Code для автоматического исправления при сохранении.

Spectral, линтер для OpenAPI

Спектральный — это линтер для OpenAPI.

Spectral — это линтер JSON/YAML с открытым исходным кодом, который позволяет вам создавать руководства по стилю для ваших структурированных данных; такие вещи, как описания OpenAPI/AsyncAPI/RAML, конфигурация Kubernetes, действия GitHub, вы называете это, Spectral может помочь вам lint. Убедитесь, что они не только «технически правильны», но и полезны.

Вот скриншот с официального сайта Spectral:

RingCentral использует преимущества Spectral для улучшения качества наших спецификаций API.

Spectral также предоставляет JavaScript API. Таким образом, вы можете программно вызывать linter API.

Загрузите новое расширение Visual Studio Code

Лучшим ресурсом для справки является руководство Ваше первое расширение. Самый простой способ начать работу — установить Yeoman и VS Code Extension Generator.

Сгенерированный код готов к запуску. Чтобы запустить/отладить его, просто нажмите F5.

Расширение языкового сервера

Существует много видов расширений Visual Studio Code, которые можно создать. Но для создания расширения линтера для Visual Studio Code лучше всего создать Language Server Extension. Официальное руководство/учебник довольно всеобъемлющее, и настоятельно рекомендуется сначала ознакомиться с ним, прежде чем продолжать читать здесь.

Начать с нуля может быть ошеломляюще. Поэтому предлагаю просто скопировать код из примера LSP.

Фрагмент кода клиента

Наш клиентский код основан на шаблоне кода из примера LSP. Мы только внесли некоторые заметные изменения в clientOptions:

const clientOptions: LanguageClientOptions = {
    // Register the server for plain text documents
    documentSelector: [
      { scheme: 'file', language: 'yaml' },
    ],
    synchronize: {
      // Notify the server about file changes to '.spectral.yml files contained in the workspace
      fileEvents: workspace.createFileSystemWatcher('**/.spectral.yml')
    }
  };

Таким образом, расширение будет анализировать документы на языке yaml. И он также заметит сервер, если мы внесем изменения в файл .spectral.yml.

Фрагменты кода сервера

const fakeFS: any = {
  promises: {
    async readFile(filepath: string) {
      if (filepath === '/.spectral-default.yaml') {
        return `extends: ["spectral:oas", "spectral:asyncapi"]`;
      }
      return fs.promises.readFile(filepath);
    },
  },
};
const spectral = new Spectral();
...
const customRules = await bundleAndLoadRuleset(settings.spectralRulesetsFile, {
  fs: fakeFS,
  fetch: globalThis.fetch,
});
spectral.setRuleset(customRules);

Spectral поддерживает пользовательские наборы правил. Мы могли бы определить пользовательские правила в файле и загрузить правила. Обратите внимание, что мы определили файл правил клиента по умолчанию с именем /.spectral-default.yaml и его содержимым extends: [“spectral:oas”, “spectral:asyncapi”] . Это означает, что если пользователь не укажет никаких пользовательских правил, мы будем использовать правила из spectral:oas и spectral:asyncapi, предоставленные проектом Spectral, в качестве правил по умолчанию.

const loadConfig = async () => {
  let settings: LinterSettings;
  if(initialized) {
    const workspacePath = (await connection.workspace.getWorkspaceFolders())![0].uri;
    let spectralRulesetsFile = join(workspacePath, '.spectral.yml');
    if(spectralRulesetsFile.startsWith('file:')) {
      spectralRulesetsFile = spectralRulesetsFile.substring(5);
    }
    if(fs.existsSync(spectralRulesetsFile)){
      settings = {spectralRulesetsFile};
    } else {
      settings = await connection.workspace.getConfiguration('openApiLinter') as LinterSettings;
      if(!fs.existsSync(settings.spectralRulesetsFile ?? '')) {
        settings.spectralRulesetsFile = '/.spectral-default.yaml';
      }
    }
  } else {
    settings = {spectralRulesetsFile: '/.spectral-default.yaml'};
  }
...

Прежде всего, мы пытаемся найти файл конфигурации в корне рабочей области. Если его нет, мы попытаемся найти файл конфигурации, указанный в конфигурации расширения. Если он также не существует, вместо этого мы будем использовать файл конфигурации по умолчанию. В этом случае у пользователей будет возможность указать файлы конфигурации на разных уровнях.

async function validateTextDocument(textDocument: TextDocument): Promise<void> {
  const text = textDocument.getText();
  let diagnostics: Diagnostic[] = [];
  if(text.startsWith('openapi:')) {
    const issues = await spectral.run(new Document(text, Yaml, 'spec.yaml'));
    diagnostics = issues.map(issue => ({
      severity: issue.severity + 1,
      code: issue.code,
      range: issue.range,
      message: issue.message,
      source: 'OpenAPI Linter'
    })) as Diagnostic[];
  }
  // Send the computed diagnostics to VSCode.
  connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
}

Теперь пришло время сделать настоящую работу по линтингу. Мы просто вызываем Spectral API, чтобы получить список issues, затем переводим проблемы в diagnostics, который используется кодом Visual Studio. При всей подготовительной работе эта часть короткая и простая.

А вот как это выглядит в рабочем состоянии:

Полный исходный код

Исходный код OpenAPI Linter доступен на GitHub.

Краткое содержание

В этой статье мы рассмотрели многое, от того, что такое линтер, до того, как на самом деле кодировать линтер. Теперь у вас должна быть вся необходимая информация для написания собственного расширения linter для Visual Studio Code.

Чтобы узнать больше о функциях RingCentral, обязательно посетите наш сайт для разработчиков, а если вы когда-нибудь застряли, обязательно посетите наш форум для разработчиков.

Хотите быть в курсе новых API и функций? Присоединяйтесь к нашей Программе, которая изменит правила игры и получайте отличные награды за развитие своих навыков и получение дополнительной информации о RingCentral!