Skip to content

feat: RSS-CORE-00 swagger editor - #16

Merged
FierceSloth merged 8 commits into
developfrom
feature/swaggerEditor
Jul 6, 2026
Merged

FierceSloth merged 8 commits into
developfrom
feature/swaggerEditor

Conversation

@FierceSloth

@FierceSloth FierceSloth commented Jul 3, 2026 •

Copy link
Copy Markdown
Owner

📋 Trello Task ID

  • RSS-SE-## (Task ID / Trello Card)
  • No ID (Epic merge: feature/swagger-editor → develop)

⚡️ Summary

Merge the Swagger Editor epic into develop. This includes integrating a code editor for API specifications, implementing format conversion (JSON/YAML), adding OpenAPI schema validation, creating the main responsive split view, and synchronizing state between the editor and viewer.

Included stories:

  • RSS-SE-11 — integrate swagger editor
  • RSS-SE-12 — implement json to yaml conversion
  • RSS-SE-13 — add openapi validation
  • RSS-SE-15 — create main page responsive split view
  • RSS-SE-16 — synchronize editor and viewer
  • RSS-CORE-00 — address code review feedback
  • RSS-CORE-00 — address coderabbit code review feedback

🛠 Type of change

  • feat (New feature)
  • fix (Bug fix)
  • refactor (Code improvement / Refactoring without changing logic)
  • style (Formatting, CSS)
  • docs (Documentation)
  • chore (Configs, Build)
  • test (Testing)

Summary by CodeRabbit

  • New Features

    • Добавлен встроенный редактор Swagger/OpenAPI с переключением формата JSON/YAML, подсветкой состояния схемы и обратной связью по ошибкам и предупреждениям.
    • Появились новые элементы интерфейса: шапка, подвал, обновлённая главная страница и поддержка новых состояний кнопок.
    • Улучшена локализация: добавлены новые тексты для редактора, шапки и подвала на русском и английском.
  • Bug Fixes

    • Улучшено определение формата текста и валидация схем, чтобы корректнее показывать статус и сообщения в редакторе.

- Added @uiw/react-codemirror with JSON/YAML support
- Created reusable CodeEditor in shared/ui with readonly and transparent props
- Applied custom dark theme and syntax highlighting via SCSS and JS
- Integrated CodeEditor into SwaggerEditor widget
- Create format-converter feature to detect and convert between JSON and YAML
- Implement FormatToggle UI component with unknown state handling
- Integrate format converter logic and toggle into SwaggerEditor widget
- Add i18n support for the format converter UI
- Integrate `@stoplight/spectral-core` to parse and validate OpenAPI schemas in both JSON and YAML formats.
- Add `CodeMirror Linter` adapter to display validation errors directly in the editor with inline tooltips.
- Customize the Spectral `oas` ruleset to ignore annoying stylistic rules and focus only on structural errors.
- Add comprehensive unit tests for the schema validation utility.
- Implemented `ValidationStatus` and `ValidationFeedback` UI components to visualize schema validity and error counts.
- Added `next-intl` localization support for all new validation UI elements.
- Integrated CodeMirror's `onUpdate` listener to efficiently extract real-time lint diagnostics without causing redundant validation runs.
- Created a responsive split-view layout for the `HomePage` using Flexbox and aspect-ratio media queries.
- Assembled the main page by integrating the `SwaggerEditor` into the primary pane and adding a placeholder stub for the `SwaggerViewer`.
- Refactor SwaggerEditor to operate as a fully controlled component by removing its internal local state.
- Implement a custom useDebounce hook to optimize performance during user input.
- Lift state management up to the HomePage to track raw text and validation status.
@vercel

vercel Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
swagger-editor-app Ready Ready Preview, Comment Jul 6, 2026 1:25pm

Comment thread app/[locale]/layout.tsx Outdated

return (
<html lang={locale} className={`${ibmPlexSans.variable} ${spaceGrotesk.variable}`}>
<html lang={locale} className={`${ibmPlexSans.variable} ${spaceGrotesk.variable} ${jetBrainsMono.variable}`}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use lib for styles like classname here?

import yaml from 'yaml';

export function detectFormat(text: string): DetectedFormat {
if (!text.trim()) return 'unknown';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not a good idea use 'unknown' as a returned value. use null or at least add 'unknown' to constants


return (
<div className={styles.wrapper}>
<Badge className={styles.badge} color={isUnknown ? 'red' : 'gray'}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better use "success" | "error" | "default" | "active"
for example. just because it adds some description to value and allow you to change colors easily

but now you can leave it like it is


<Button className={styles.button} variant="tertiary" type="button" onClick={onClick} disabled={isUnknown}>
<ConvertIcon className={styles.convertIcon} />{' '}
{isUnknown ? t('cannot_convert') : t('convert_to', { format: oppositeFormat.toUpperCase() })}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's ok, but you also can wrap oppositeFormat with span and add a text transform style

Comment on lines +34 to +40
return {
from: from,
to: to,
severity: severity,
message: issue.message,
};
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return {
from: from,
to: to,
severity: severity,
message: issue.message,
};
});
return {
from,
to,
severity,
message: issue.message,
};
});

Comment thread src/pages/home-page/ui/home-page.tsx Outdated
Comment on lines +20 to +27
try {
const parsed = yaml.parse(debouncedText) as unknown;
if (typeof parsed === 'object' && parsed !== null) {
return parsed as Record<string, unknown>;
}
} catch {
// ignore this
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i saw this before. let's optimize it

Comment thread src/pages/home-page/ui/home-page.tsx Outdated
return null;
}, [debouncedText, isSchemaValid]);

console.log(parsedSchema); // ? For the time being, as there is no Swagger Viewer

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
console.log(parsedSchema); // ? For the time being, as there is no Swagger Viewer
console.log(parsedSchema); // TODO: Remove after add Swagger Viewer (<TICKET_FOR_IT>)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫡

syntaxTheme,
EditorState.readOnly.of(readonly),
];
const extensions = [props.extensions || [], ...baseExtensions];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you want smth like this?

Suggested change
const extensions = [props.extensions || [], ...baseExtensions];
const extensions = [...(props.extensions || []), ...baseExtensions];

and why props.extensions, not extensions?

Comment on lines +46 to +60
const handleEditorUpdate = useCallback((viewUpdate: ViewUpdate) => {
let errors = 0;
let warnings = 0;
forEachDiagnostic(viewUpdate.state, (diag) => {
if (diag.severity === 'error') errors++;
if (diag.severity === 'warning') warnings++;
});

setValidation((prev) => {
if (prev.errors !== errors || prev.warnings !== warnings) {
return { errors, warnings };
}
return prev;
});
}, []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const handleEditorUpdate = useCallback((viewUpdate: ViewUpdate) => {
let errors = 0;
let warnings = 0;
forEachDiagnostic(viewUpdate.state, (diag) => {
if (diag.severity === 'error') errors++;
if (diag.severity === 'warning') warnings++;
});
setValidation((prev) => {
if (prev.errors !== errors || prev.warnings !== warnings) {
return { errors, warnings };
}
return prev;
});
}, []);
const handleEditorUpdate = useCallback((viewUpdate: ViewUpdate) => {
let errors = 0;
let warnings = 0;
forEachDiagnostic(viewUpdate.state, (diag) => {
if (diag.severity === 'error') errors++;
if (diag.severity === 'warning') warnings++;
});
setErrorsCount(errors);
setWarningsCount(warnings);
}, []);

@FierceSloth

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Добавлена новая функциональность Swagger Editor: детектирование и конвертация JSON/YAML, валидация OpenAPI-схем через Spectral, CodeMirror-редактор с подсветкой и линтером, UI-компоненты статуса/фидбэка, виджет SwaggerEditor и интеграция на домашней странице. Также переименованы default-экспорты страниц, обновлены конфигурация сборки, зависимости, локализация и глобальные стили.

Changes

Функциональность Swagger Editor

Layer / File(s) Summary
Общие типы и debounce
src/shared/types/format.ts, src/shared/lib/hooks/*
Добавлены типы DataFormat/DetectedFormat и хук useDebounce с экспортом через index.
Детект и конвертация формата
src/shared/lib/parse-to-object.ts, src/features/format-converter/lib/*, src/features/format-converter/index.ts
Добавлены parseToObject, detectFormat, convertToJson/convertToYaml/convertFormat с тестами и barrel-экспортом.
Переключатель формата и тексты
src/features/format-converter/ui/format-toggle.*, messages/en.json, messages/ru.json
Добавлен компонент FormatToggle со стилями и локализованные строки SwaggerEditor/Header/Footer.
Валидация схемы OpenAPI
src/features/schema-validator/lib/*, src/features/schema-validator/index.ts
Добавлены validateSchema на базе Spectral, openapiLinter для CodeMirror и unit-тесты.
Статус и обратная связь валидации
src/features/schema-validator/ui/validation-status/*, src/features/schema-validator/ui/validation-feedback/*
Добавлены компоненты ValidationStatus и ValidationFeedback со стилями.
Общий CodeMirror-редактор
src/shared/ui/code-editor/*
Добавлен компонент CodeEditor, темы редактора и синтаксиса, стили и публичный экспорт.
Сборка SwaggerEditor
src/widgets/swagger-editor/*
Добавлен виджет SwaggerEditor, связывающий детект формата, конвертацию, редактор, линтер и статус/фидбэк.
Домашняя страница
src/pages/home-page/*, app/[locale]/home/page.tsx
Добавлен HomePage с парсингом YAML, страница home переключена на его рендер.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Инфраструктура, конфигурация и стили

Layer / File(s) Summary
Переименования страниц
app/[locale]/about/page.tsx, app/[locale]/history/page.tsx, app/[locale]/login/page.tsx, app/[locale]/register/page.tsx
Default-export функции переименованы в Page без изменения логики.
Сборка и зависимости
app/[locale]/layout.tsx, next.config.ts, package.json, .commitlintrc.json
Добавлен шрифт JetBrains Mono, webpack fallback для fs/path/url, новые зависимости, флаг сборки и правило commitlint.
Глобальные стили и токены
src/app/styles/*, src/shared/ui/arc-background/*, src/shared/ui/badge/*, src/shared/ui/button/*
Обновлены CSS-переменные, layout main, стили arc-background, badge и добавлены disabled/tertiary состояния кнопки.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SwaggerEditor
  participant CodeEditor
  participant openapiLinter
  participant validateSchema
  participant FormatToggle

  User->>CodeEditor: ввод текста
  CodeEditor->>SwaggerEditor: onEditorUpdate(viewUpdate)
  SwaggerEditor->>openapiLinter: анализ документа
  openapiLinter->>validateSchema: validateSchema(text)
  validateSchema-->>openapiLinter: диагностики (issues)
  openapiLinter-->>SwaggerEditor: Diagnostic[]
  SwaggerEditor->>SwaggerEditor: подсчёт errorsCount/warningsCount
  SwaggerEditor-->>User: ValidationStatus/ValidationFeedback

  User->>FormatToggle: клик "convert_to"
  FormatToggle->>SwaggerEditor: onToggle(newFormat)
  SwaggerEditor->>SwaggerEditor: convertFormat(value, newFormat)
  SwaggerEditor-->>CodeEditor: onChange(convertedText)
Loading

Estimated code review effort: 3 (Moderate) | ~30 minutes

Related issues: Не указаны в предоставленных данных.

Related PRs: Не указаны в предоставленных данных.

Suggested labels: feature, frontend, needs-review

Suggested reviewers: Не указаны в предоставленных данных.


🐰 В норке кроликов кипит работа,
Формат меняем — раз, и два, забота:
Валидность схем следит зоркий глаз,
Редактор код подсветит в тот же час.
Готов виджет — теперь встречай гостей! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning Описание содержит сводку и тип изменения, но отсутствует обязательный раздел Screenshots / GIFs для UI-изменений. Добавьте раздел Screenshots / GIFs с изображениями или GIF либо удалите его, если UI-изменения не требуются.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed Название краткое и соответствует основному изменению — интеграции Swagger Editor.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/swaggerEditor

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (5)
package.json (1)

5-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Дублирование fallback-конфигурации fs/path/url с next.config.ts.

Поле browser здесь и resolve.fallback в next.config.ts (Line 6-20) решают одну и ту же задачу — отключение подмешивания Node-модулей fs/path/url в клиентскую сборку. Если оставить обе настройки, есть риск рассинхронизации при последующих правках одной из них без другой.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 5 - 9, Remove the duplicated browser fallback
block from package.json and keep the Node module exclusions in a single place,
since next.config.ts already handles the fs/path/url client-bundling fallback.
Update the configuration so only one source of truth remains for disabling fs,
path, and url, and make sure any references in the build setup stay aligned with
the existing next.config.ts resolve.fallback settings.
next.config.ts (1)

6-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Замените unknown-каст на официальный тип Webpack-конфига.

Приведение config к unknown, а затем к самодельной форме { resolve?: { fallback?: ... } } отключает проверку типов для остальной части конфига. Next.js предоставляет типизированный колбэк через NextConfig['webpack'] (или тип Configuration из webpack), что безопаснее при дальнейшем расширении хука.

♻️ Пример более типобезопасного варианта
-  webpack: (config: unknown, { isServer }: { isServer: boolean }) => {
-    const webpackConfig = config as { resolve?: { fallback?: Record<string, boolean | string> } };
-    if (!isServer) {
-      if (!webpackConfig.resolve) {
-        webpackConfig.resolve = {};
-      }
-      webpackConfig.resolve.fallback = {
-        ...(webpackConfig.resolve.fallback || {}),
+  webpack: (config, { isServer }) => {
+    if (!isServer) {
+      config.resolve = config.resolve ?? {};
+      config.resolve.fallback = {
+        ...(config.resolve.fallback ?? {}),
         fs: false,
         path: false,
         url: false,
       };
     }
-    return webpackConfig;
+    return config;
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@next.config.ts` around lines 6 - 20, The webpack hook in next.config.ts is
weakening type safety by casting config through unknown and a partial fallback
shape. Update the NextConfig.webpack callback to use the official
Next.js/webpack types (for example NextConfig['webpack'] or webpack
Configuration) and remove the manual cast so the existing logic in
webpackConfig.resolve.fallback stays type-checked while still preserving the fs,
path, and url fallbacks.
src/features/format-converter/lib/convert-format.ts (1)

4-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Дублирование логики парсинга/валидации.

convertToJson и convertToYaml дублируют одинаковый блок try { yaml.parse → проверка типа }. Можно вынести общий helper для парсинга и валидации, чтобы избежать дублирования при добавлении новых форматов в будущем.

♻️ Пример рефакторинга
+function parseStructured(text: string): Record<string, unknown> | unknown[] | null {
+  try {
+    const jsObject = yaml.parse(text) as unknown;
+    if (typeof jsObject !== 'object' || jsObject === null) return null;
+    return jsObject as Record<string, unknown> | unknown[];
+  } catch {
+    return null;
+  }
+}
+
 export function convertToJson(text: string): string | null {
-  try {
-    const jsObject = yaml.parse(text) as unknown;
-    if (typeof jsObject !== 'object' || jsObject === null) return null;
-    return JSON.stringify(jsObject, null, 2);
-  } catch {
-    return null;
-  }
+  const jsObject = parseStructured(text);
+  return jsObject === null ? null : JSON.stringify(jsObject, null, 2);
 }

 export function convertToYaml(text: string): string | null {
-  try {
-    const jsObject = yaml.parse(text) as unknown;
-    if (typeof jsObject !== 'object' || jsObject === null) return null;
-    return yaml.stringify(jsObject);
-  } catch {
-    return null;
-  }
+  const jsObject = parseStructured(text);
+  return jsObject === null ? null : yaml.stringify(jsObject);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/format-converter/lib/convert-format.ts` around lines 4 - 22,
Both convertToJson and convertToYaml duplicate the same yaml.parse plus
object/null validation logic, so extract that shared parsing/validation into a
common helper in convert-format.ts and have both functions reuse it. Keep the
existing behavior and return values unchanged, but centralize the try/catch and
object check so future format converters can call the same helper instead of
repeating the block.
src/widgets/swagger-editor/ui/swagger-editor.module.scss (1)

22-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Захардкоженный цвет вместо дизайн-токена.

.editor использует rgba(0, 0, 0, 0.2) напрямую, тогда как остальные стили редактора (theme.ts, .toolbar) используют CSS-переменные var(--bg-surface-*). Стоит привести к единому подходу для консистентности темизации.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss` around lines 22 -
25, The .editor rule is using a hardcoded rgba background instead of the shared
theme token approach. Update the background-color in swagger-editor.module.scss
to use the same CSS variable pattern as the related theme.ts and .toolbar
styles, so SwaggerEditor stays consistent with the rest of the themed UI and
locates through the .editor selector.
src/widgets/swagger-editor/ui/swagger-editor.tsx (1)

40-44: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

detectFormat вызывается на каждое нажатие клавиши без debounce.

onTextChange парсит весь текст документа (JSON.parse + yaml.parse) синхронно при каждом изменении редактора. Для больших OpenAPI-спецификаций это может заметно замедлять ввод, в отличие от openapiLinter, у которого есть встроенный debounce. В кодовой базе уже есть хук useDebounce, применяемый для аналогичной задачи (YAML-парсинг) на HomePage — стоит применить его и здесь.

♻️ Пример применения debounce к определению формата
-  const onTextChange = (newText: string) => {
-    const detected = detectFormat(newText);
-    setCurrentFormat(detected);
-    onChange?.(newText);
-  };
+  const debouncedText = useDebounce(value, 300);
+
+  useEffect(() => {
+    setCurrentFormat(detectFormat(debouncedText));
+  }, [debouncedText]);
+
+  const onTextChange = (newText: string) => {
+    onChange?.(newText);
+  };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx` around lines 40 - 44, The
format detection in onTextChange is running synchronously on every keystroke and
should be debounced to avoid blocking edits on large specs. Update
swagger-editor.tsx so detectFormat is wrapped with the existing useDebounce
pattern used elsewhere in the codebase (for example, the HomePage YAML parsing
flow), and have onTextChange update currentFormat from the debounced result
while still forwarding newText through onChange?. The key symbols to adjust are
onTextChange, detectFormat, setCurrentFormat, and useDebounce.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/schema-validator/lib/validate-schema.ts`:
- Around line 6-26: The module-level Spectral instance in validateSchema is
shared across concurrent validateSchema() calls, which can cause race conditions
when setRuleset/run are used in parallel. Update validateSchema to create a
fresh Spectral instance and apply myRuleset per invocation, or otherwise
serialize access to the shared instance, so each run operates on its own
isolated configuration.

In
`@src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss`:
- Around line 1-9: Remove the empty blank line inside the .wrapper rule in
validation-feedback.module.scss so the declarations are contiguous and satisfy
stylelint’s declaration-empty-line-before rule; keep the styling in the same
.wrapper selector and eliminate the spacing before the display declaration.

In
`@src/features/schema-validator/ui/validation-status/validation-status.module.scss`:
- Around line 1-11: The .badge rule in validation-status.module.scss has an
empty line before the display declaration that violates stylelint’s
declaration-empty-line-before rule. Remove the blank line inside the .badge
block so the declarations stay contiguous, and keep the fix limited to the
.badge style block in validation-status.module.scss.

In `@src/shared/ui/arc-background/arc-background.module.scss`:
- Around line 22-65: The `.arc`, `.arc::before`, and `.arc::after` rules in
`arc-background.module.scss` contain extra blank lines before declarations that
violate `declaration-empty-line-before`. Remove the empty lines between the
related properties in these selectors, especially before `border`, `filter`, and
`box-shadow`, so the stylesheet matches the lint rule without changing the
visual styles.

In `@src/shared/ui/badge/badge.module.scss`:
- Around line 7-17: Remove the extra blank lines before the CSS declarations in
badge.module.scss so the block follows declaration-empty-line-before
consistently. Update the badge styles by keeping the declarations for
border-radius, font-family, and font-size contiguous with the surrounding
properties in the same rule.

In `@src/shared/ui/button/button.module.scss`:
- Around line 54-71: The .tertiary rule in button.module.scss has empty lines
before the border and padding declarations, which violates
declaration-empty-line-before. Remove the extra blank lines inside the .tertiary
block so the declarations are grouped consistently, keeping the existing styling
and hover rules unchanged.

In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss`:
- Around line 9-20: In the .toolbar style block of swagger-editor.module.scss,
remove the duplicated display and align-items declarations and clean up the
extra blank line left by the merge artifact. Keep a single set of layout
properties in .toolbar, preserving the intended flex layout by leaving the final
justify-content and gap settings alongside one display and one align-items
declaration.

---

Nitpick comments:
In `@next.config.ts`:
- Around line 6-20: The webpack hook in next.config.ts is weakening type safety
by casting config through unknown and a partial fallback shape. Update the
NextConfig.webpack callback to use the official Next.js/webpack types (for
example NextConfig['webpack'] or webpack Configuration) and remove the manual
cast so the existing logic in webpackConfig.resolve.fallback stays type-checked
while still preserving the fs, path, and url fallbacks.

In `@package.json`:
- Around line 5-9: Remove the duplicated browser fallback block from
package.json and keep the Node module exclusions in a single place, since
next.config.ts already handles the fs/path/url client-bundling fallback. Update
the configuration so only one source of truth remains for disabling fs, path,
and url, and make sure any references in the build setup stay aligned with the
existing next.config.ts resolve.fallback settings.

In `@src/features/format-converter/lib/convert-format.ts`:
- Around line 4-22: Both convertToJson and convertToYaml duplicate the same
yaml.parse plus object/null validation logic, so extract that shared
parsing/validation into a common helper in convert-format.ts and have both
functions reuse it. Keep the existing behavior and return values unchanged, but
centralize the try/catch and object check so future format converters can call
the same helper instead of repeating the block.

In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss`:
- Around line 22-25: The .editor rule is using a hardcoded rgba background
instead of the shared theme token approach. Update the background-color in
swagger-editor.module.scss to use the same CSS variable pattern as the related
theme.ts and .toolbar styles, so SwaggerEditor stays consistent with the rest of
the themed UI and locates through the .editor selector.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx`:
- Around line 40-44: The format detection in onTextChange is running
synchronously on every keystroke and should be debounced to avoid blocking edits
on large specs. Update swagger-editor.tsx so detectFormat is wrapped with the
existing useDebounce pattern used elsewhere in the codebase (for example, the
HomePage YAML parsing flow), and have onTextChange update currentFormat from the
debounced result while still forwarding newText through onChange?. The key
symbols to adjust are onTextChange, detectFormat, setCurrentFormat, and
useDebounce.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bb2df897-34c0-439f-9274-bc037a3fa708

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5140a and 5d80c2f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (48)
  • .commitlintrc.json
  • app/[locale]/about/page.tsx
  • app/[locale]/history/page.tsx
  • app/[locale]/home/page.tsx
  • app/[locale]/layout.tsx
  • app/[locale]/login/page.tsx
  • app/[locale]/register/page.tsx
  • messages/en.json
  • messages/ru.json
  • next.config.ts
  • package.json
  • src/app/styles/abstract/_constants.scss
  • src/features/.gitkeep
  • src/features/format-converter/index.ts
  • src/features/format-converter/lib/convert-format.test.ts
  • src/features/format-converter/lib/convert-format.ts
  • src/features/format-converter/lib/detect-format.test.ts
  • src/features/format-converter/lib/detect-format.ts
  • src/features/format-converter/ui/format-toggle.module.scss
  • src/features/format-converter/ui/format-toggle.tsx
  • src/features/schema-validator/index.ts
  • src/features/schema-validator/lib/codemirror-linter.ts
  • src/features/schema-validator/lib/validate-schema.test.ts
  • src/features/schema-validator/lib/validate-schema.ts
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.tsx
  • src/features/schema-validator/ui/validation-status/validation-status.module.scss
  • src/features/schema-validator/ui/validation-status/validation-status.tsx
  • src/pages/.gitkeep
  • src/pages/home-page/index.ts
  • src/pages/home-page/ui/home-page.module.scss
  • src/pages/home-page/ui/home-page.tsx
  • src/shared/lib/hooks/index.ts
  • src/shared/lib/hooks/use-debounce.ts
  • src/shared/types/format.ts
  • src/shared/ui/arc-background/arc-background.module.scss
  • src/shared/ui/badge/badge.module.scss
  • src/shared/ui/badge/badge.tsx
  • src/shared/ui/button/button.module.scss
  • src/shared/ui/button/button.tsx
  • src/shared/ui/code-editor/index.ts
  • src/shared/ui/code-editor/lib/theme.ts
  • src/shared/ui/code-editor/ui/code-editor.module.scss
  • src/shared/ui/code-editor/ui/code-editor.tsx
  • src/widgets/.gitkeep
  • src/widgets/swagger-editor/index.ts
  • src/widgets/swagger-editor/ui/swagger-editor.module.scss
  • src/widgets/swagger-editor/ui/swagger-editor.tsx

Comment on lines +6 to +26
const spectral = new Spectral();

const myRuleset: RulesetDefinition = {
extends: [oas as unknown as RulesetDefinition],
rules: {
'info-contact': 'off',
'info-description': 'off',
'info-license': 'off',
'license-url': 'off',
'openapi-tags': 'off',
'operation-description': 'off',
'operation-tags': 'off',
'operation-tag-defined': 'off',
'operation-operationId': 'off',
'operation-operationId-valid-in-url': 'off',
'tag-description': 'off',
'oas3-api-servers': 'off',
},
};

spectral.setRuleset(myRuleset);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is a single @stoplight/spectral-core Spectral instance safe for concurrent parallel run() calls?

💡 Result:

A single Spectral instance from @stoplight/spectral-core is not designed for concurrent parallel run calls, and utilizing it in this manner may lead to unpredictable behavior or race conditions. The Spectral class maintains internal state related to the ruleset and configuration (such as the resolver and registered formats) [1][2]. When you call run, the instance uses this internal state to process the provided document [3]. Because the instance is stateful, performing multiple concurrent linting operations on a single instance can result in internal state contention [4]. If you need to perform concurrent linting, the recommended and safe approach is to instantiate a new Spectral instance for each parallel task, or to use a pool of instances if performance overhead is a concern [1][5][6]. Each instance should be configured independently to avoid shared state issues.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and its size first
git ls-files src/features/schema-validator/lib/validate-schema.ts
wc -l src/features/schema-validator/lib/validate-schema.ts

# Inspect the target file with line numbers
cat -n src/features/schema-validator/lib/validate-schema.ts

# Find call sites / exports related to validateSchema
rg -n "validateSchema|Spectral|setRuleset|run\(" src/features -S

Repository: FierceSloth/swagger-editor-app

Length of output: 2926


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the linter integration and tests
cat -n src/features/schema-validator/lib/codemirror-linter.ts
printf '\n---\n'
cat -n src/features/schema-validator/lib/validate-schema.test.ts

# Check for any serialization / memoization around validateSchema usage
rg -n "validateSchema|linter|lint|queue|serialize|mutex|debounce|throttle|cancel" src/features/schema-validator -S

Repository: FierceSloth/swagger-editor-app

Length of output: 4972


Не переиспользовать один Spectral для параллельных run()
Spectral здесь хранится на уровне модуля, а validateSchema() вызывается асинхронно без сериализации. При одновременных запусках линтера лучше создавать Spectral/ruleset на вызов или защищать общий инстанс очередью, иначе возможны гонки и нестабильные результаты.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/schema-validator/lib/validate-schema.ts` around lines 6 - 26,
The module-level Spectral instance in validateSchema is shared across concurrent
validateSchema() calls, which can cause race conditions when setRuleset/run are
used in parallel. Update validateSchema to create a fresh Spectral instance and
apply myRuleset per invocation, or otherwise serialize access to the shared
instance, so each run operates on its own isolated configuration.

Comment on lines +1 to +9
.wrapper {
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-top: 1px solid var(--bg-surface-2);

display: flex;
align-items: center;
gap: 0.75rem;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Убрать пустую строку перед объявлением, чтобы пройти stylelint.

Static analysis сообщает об ошибке declaration-empty-line-before на строке 6.

🎨 Предложенное исправление
 .wrapper {
   padding: 0.75rem 1.5rem;
   background-color: var(--bg-surface-1);
   border-top: 1px solid var(--bg-surface-2);
-
   display: flex;
   align-items: center;
   gap: 0.75rem;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.wrapper {
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-top: 1px solid var(--bg-surface-2);
display: flex;
align-items: center;
gap: 0.75rem;
}
.wrapper {
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-top: 1px solid var(--bg-surface-2);
display: flex;
align-items: center;
gap: 0.75rem;
}
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 6-6: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss`
around lines 1 - 9, Remove the empty blank line inside the .wrapper rule in
validation-feedback.module.scss so the declarations are contiguous and satisfy
stylelint’s declaration-empty-line-before rule; keep the styling in the same
.wrapper selector and eliminate the spacing before the display declaration.

Source: Linters/SAST tools

Comment on lines +1 to +11
.badge {
font-family: var(--font-mono);
border-radius: var(--radius-pill);
font-size: 10px;
padding: 0.25rem 0.75rem;

display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Пустая строка перед объявлением нарушает правило stylelint.

Stylelint (declaration-empty-line-before) указывает на пустую строку перед display: flex; (строка 7, после пустой строки 6).

🧹 Исправление
   padding: 0.25rem 0.75rem;
-
   display: flex;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.badge {
font-family: var(--font-mono);
border-radius: var(--radius-pill);
font-size: 10px;
padding: 0.25rem 0.75rem;
display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
}
.badge {
font-family: var(--font-mono);
border-radius: var(--radius-pill);
font-size: 10px;
padding: 0.25rem 0.75rem;
display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
}
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 7-7: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/features/schema-validator/ui/validation-status/validation-status.module.scss`
around lines 1 - 11, The .badge rule in validation-status.module.scss has an
empty line before the display declaration that violates stylelint’s
declaration-empty-line-before rule. Remove the blank line inside the .badge
block so the declarations stay contiguous, and keep the fix limited to the
.badge style block in validation-status.module.scss.

Source: Linters/SAST tools

Comment on lines +22 to +65
transform: translate(-70%, -50%);
background: #000;

opacity: 0.8;

box-shadow: 0 0 150px 30px rgba(var(--fringe-rgb), 0.1);

animation: breathe 8s ease-in-out infinite alternate;
}

.arc::before {
content: "";
content: '';
position: absolute;
inset: 0;
border-radius: 60%;
opacity: 0.7;

border: 7px solid rgba(var(--core-rgb), 0.95);

filter: blur(0.5px);

box-shadow:
filter: blur(0.5px);

box-shadow:
0 0 6px 1px rgba(var(--core-rgb), 0.9),
inset 0 0 6px 1px rgba(var(--core-rgb), 0.9),

0 0 20px 10px rgba(var(--core-glow-rgb), 0.6),
inset 0 0 20px 10px rgba(var(--core-glow-rgb), 0.6),

0 0 50px 12px rgba(var(--core-glow-rgb), 0.55),
inset 0 0 50px 12px rgba(var(--core-glow-rgb), 0.55),

0 0 100px 25px rgba(var(--core-glow-rgb), 0.25),
inset 0 0 100px 25px rgba(var(--core-glow-rgb), 0.25),

0 0 200px 32px rgba(var(--core-glow-rgb), 0.15),
inset 0 0 200px 32px rgba(var(--core-glow-rgb), 0.15);
}

.arc::after {
content: "";
content: '';
position: absolute;
inset: -40px;
inset: -40px;
border-radius: 50%;

border: 1px solid rgba(var(--fringe-rgb), 0.7);
filter: blur(1px);
box-shadow:
filter: blur(1px);

box-shadow:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Лишние пустые строки перед объявлениями (stylelint).

Статический анализ фиксирует нарушение declaration-empty-line-before в нескольких местах внутри .arc, .arc::before и .arc::after (строки 22, 25, 27, 29, 39, 41, 43-53, 62).

🎨 Предлагаемое исправление
 .arc {
   ...
-  transform: translate(-70%, -50%);
-  background: `#000`;
+  transform: translate(-70%, -50%);
+  background: `#000`;

   opacity: 0.8;
-
-  box-shadow: 0 0 150px 30px rgba(var(--fringe-rgb), 0.1);
+  box-shadow: 0 0 150px 30px rgba(var(--fringe-rgb), 0.1);

-  animation: breathe 8s ease-in-out infinite alternate;
+  animation: breathe 8s ease-in-out infinite alternate;
 }

Аналогично убрать пустые строки перед border, filter, box-shadow в .arc::before и .arc::after.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 22-22: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 25-25: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 27-27: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 29-29: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 39-39: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 41-41: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 43-53: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 62-62: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/arc-background/arc-background.module.scss` around lines 22 -
65, The `.arc`, `.arc::before`, and `.arc::after` rules in
`arc-background.module.scss` contain extra blank lines before declarations that
violate `declaration-empty-line-before`. Remove the empty lines between the
related properties in these selectors, especially before `border`, `filter`, and
`box-shadow`, so the stylesheet matches the lint rule without changing the
visual styles.

Source: Linters/SAST tools

Comment on lines +7 to +17
border-radius: 4px;
border: 1px solid var(--badge-border-color);
background-color: var(--badge-color);
padding: 4px 12px;

font-family: var(--font-ui), monospace;
white-space: nowrap;
transition: color 0.3s ease;
}

.text {
color: var(--badge-text-color);
font-size: 12px;
color: var(--badge-text-color);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Лишние пустые строки перед объявлениями (stylelint).

Аналогично другим файлам, добавленные пустые строки перед border-radius (строка 7), font-family (строка 12) и font-size (строка 16) нарушают правило declaration-empty-line-before.

🎨 Предлагаемое исправление
   gap: 0.8rem;
-
   border-radius: 4px;
   border: 1px solid var(--badge-border-color);
   background-color: var(--badge-color);
   padding: 4px 12px;

-  font-family: var(--font-ui), monospace;
+  font-family: var(--font-ui), monospace;
   white-space: nowrap;
   transition: color 0.3s ease;

-  font-size: 12px;
+  font-size: 12px;
   color: var(--badge-text-color);
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 7-7: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 12-12: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 16-16: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/badge/badge.module.scss` around lines 7 - 17, Remove the extra
blank lines before the CSS declarations in badge.module.scss so the block
follows declaration-empty-line-before consistently. Update the badge styles by
keeping the declarations for border-radius, font-family, and font-size
contiguous with the surrounding properties in the same rule.

Source: Linters/SAST tools

Comment on lines +54 to +71

.tertiary {
font-family: var(--font-mono);
font-size: 12px;
font-weight: 500;
color: var(--text-primary);

border: 1px solid transparent;
border-radius: 4px;

padding: 0.25rem 0.75rem;
transition: all 0.1s;

&:hover {
background-color: var(--bg-surface-2);
border-color: var(--bg-surface-3);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Лишние пустые строки перед объявлениями (stylelint).

Пустые строки перед border (строка 61) и padding (строка 64) в .tertiary нарушают declaration-empty-line-before.

🎨 Предлагаемое исправление
   color: var(--text-primary);
-
   border: 1px solid transparent;
   border-radius: 4px;

-  padding: 0.25rem 0.75rem;
+  padding: 0.25rem 0.75rem;
   transition: all 0.1s;
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 61-61: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 64-64: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/button/button.module.scss` around lines 54 - 71, The .tertiary
rule in button.module.scss has empty lines before the border and padding
declarations, which violates declaration-empty-line-before. Remove the extra
blank lines inside the .tertiary block so the declarations are grouped
consistently, keeping the existing styling and hover rules unchanged.

Source: Linters/SAST tools

Comment on lines +9 to +20
.toolbar {
display: flex;
align-items: center;
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-bottom: 1px solid var(--bg-surface-2);

display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Дублирование свойств display и align-items в .toolbar.

Statлint фиксирует дублирование display (строки 10 и 16) и align-items (строки 11 и 17), а также лишнюю пустую строку перед объявлением (строка 16) — похоже на артефакт слияния кода.

🧹 Предложенное исправление
 .toolbar {
   display: flex;
   align-items: center;
   padding: 0.75rem 1.5rem;
   background-color: var(--bg-surface-1);
   border-bottom: 1px solid var(--bg-surface-2);
-
-  display: flex;
-  align-items: center;
   justify-content: space-between;
   gap: 0.75rem;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.toolbar {
display: flex;
align-items: center;
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-bottom: 1px solid var(--bg-surface-2);
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
}
.toolbar {
display: flex;
align-items: center;
padding: 0.75rem 1.5rem;
background-color: var(--bg-surface-1);
border-bottom: 1px solid var(--bg-surface-2);
justify-content: space-between;
gap: 0.75rem;
}
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 10-10: Duplicate property "display" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 11-11: Duplicate property "align-items" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 16-16: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss` around lines 9 -
20, In the .toolbar style block of swagger-editor.module.scss, remove the
duplicated display and align-items declarations and clean up the extra blank
line left by the merge artifact. Keep a single set of layout properties in
.toolbar, preserving the intended flex layout by leaving the final
justify-content and gap settings alongside one display and one align-items
declaration.

Source: Linters/SAST tools

- Replace 'unknown' magic string with null in DetectedFormat type
- Extract parseToObject helper to shared/lib to eliminate duplicated yaml parsing
- Replace nested ternary with getStatus function in ValidationFeedback
- Split validation object state into separate errorsCount/warningsCount states
- Derive currentFormat via useMemo with debounce instead of useState + useEffect
- Sync package-lock.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/pages/home-page/ui/home-page.tsx (1)

12-21: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Независимый повторный дебаунс дублирует и рассинхронизирует состояние с SwaggerEditor.

HomePage дебаунсит rawText с задержкой 500 мс, при этом SwaggerEditor уже дебаунсит то же значение внутри себя с задержкой 300 мс для вычисления isSchemaValid. Поскольку isSchemaValid устанавливается раньше (по факту стабилизации текста через 300 мс), а debouncedText в HomePage обновляется на 200 мс позже, между этими моментами parsedSchema может быть вычислен по устаревшему снимку текста, отличному от того, что был признан валидным. Сейчас это заметно только в console.log, но станет функциональной проблемой после интеграции реального SwaggerViewer.

Поскольку isSchemaValid уже гарантирует стабильность текста к моменту true, проще убрать локальный дебаунс в HomePage и использовать rawText напрямую.

Предлагаемая правка
   const [rawText, setRawText] = useState('');
   const [isSchemaValid, setIsSchemaValid] = useState(false);

-  const debouncedText = useDebounce(rawText, 500);
-
   const parsedSchema = useMemo(() => {
-    if (!isSchemaValid || !debouncedText) return null;
+    if (!isSchemaValid || !rawText) return null;

-    return parseToObject(debouncedText);
-  }, [debouncedText, isSchemaValid]);
+    return parseToObject(rawText);
+  }, [rawText, isSchemaValid]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/home-page/ui/home-page.tsx` around lines 12 - 21, `HomePage` is
applying a second debounce through `useDebounce`, which can make `parsedSchema`
lag behind the validation state already provided by `SwaggerEditor`. Remove the
local debounced value and derive `parsedSchema` directly from `rawText` once
`isSchemaValid` is true, keeping the `useMemo` logic in `home-page.tsx` aligned
with `SwaggerEditor`’s existing debounce. Update the `parsedSchema` computation
to use the current text state instead of `debouncedText`, and adjust the
dependency list accordingly so the parsed object always matches the validated
input.
🧹 Nitpick comments (3)
src/app/styles/style.scss (1)

11-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Вынесите 80px в CSS-переменную, связанную с высотой хедера.

Значение padding-top: 80px жёстко привязано к высоте Header, но не связано с ней явно. При изменении высоты хедера придётся синхронизировать вручную в двух местах.

♻️ Пример рефактора
+:root {
+  --header-height: 80px;
+}
+
 main {
   flex: 1;
-  padding-top: 80px;
+  padding-top: var(--header-height);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/styles/style.scss` around lines 11 - 14, The hardcoded 80px in the
main layout styles is duplicated header spacing and should be tied to the Header
height via a CSS variable. Update the styles in style.scss so main uses a shared
custom property for top padding instead of a literal value, and define or reuse
that variable where the Header height is established so changes stay in sync.
src/widgets/footer/ui/footer.tsx (1)

23-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Строка "RS School 2026" не локализована.

В отличие от остальных текстов в футере (t('about'), t('team1'), t('team2')), эта строка захардкожена. Если это осознанно (название курса/бренд), можно игнорировать, иначе стоит перенести в messages/*.json.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/footer/ui/footer.tsx` around lines 23 - 30, The footer label "RS
School 2026" in the Footer component is hardcoded while other footer texts use
localization. Update the Footer JSX to source this text through the existing
i18n/messages flow (or confirm it is intentionally a brand name and leave it
unchanged), using the Footer component and its t(...) calls as the location to
adjust.
src/widgets/swagger-editor/ui/swagger-editor.tsx (1)

60-68: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Массив extensions пересоздаётся на каждый рендер.

extensions={[openapiLinter]} создаёт новый массив при каждом рендере SwaggerEditor, а компонент ре-рендерится на каждое изменение value (то есть на каждое нажатие клавиши). Официальная документация @uiw/react-codemirror рекомендует определять extensions вне компонента или мемоизировать через useMemo, так как смена ссылки вызывает дорогостоящую переконфигурацию редактора.

Предлагаемая правка
+  const extensions = useMemo(() => [openapiLinter], []);
+
   return (
     <div className={styles.wrapper}>
       ...
       <CodeEditor
         value={value}
         height="100%"
         onChange={onChange}
         format={currentFormat ?? undefined}
         className={styles.editor}
-        extensions={[openapiLinter]}
+        extensions={extensions}
         onUpdate={onEditorUpdate}
       />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx` around lines 60 - 68, The
`SwaggerEditor` component is recreating the `extensions` array on every render,
which forces unnecessary CodeMirror reconfiguration. Update `swagger-editor.tsx`
so the `CodeEditor` call uses a stable `extensions` reference by moving the
array out of `SwaggerEditor` or memoizing it with `useMemo` around
`openapiLinter`. Keep the change localized to the `SwaggerEditor`/`CodeEditor`
props so the editor only reconfigures when the actual extension changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/checks.yml:
- Around line 14-15: The `actions/checkout@v4` step is leaving `GITHUB_TOKEN`
available to later steps via git credentials. Update the checkout configuration
to disable credential persistence by setting `persist-credentials` to false on
the Checkout step in the workflow.

In `@src/shared/ui/button-link/button-link.module.scss`:
- Around line 7-14: Remove the empty lines before the declarations in the
button-link.module.scss stylesheet so the block follows the project’s
declaration formatting rules. Adjust the declaration group around font-size,
line-height, font-weight, text-decoration, cursor, transition, and border-radius
to be contiguous, matching the expected stylelint configuration in CI.

In `@src/widgets/header/ui/header.tsx`:
- Line 3: The auth check used by Header is a stub that always returns false, so
PrivateNavigation can never render. Update isAuthenticated from
src/shared/lib/auth/is-authenticated to read real authentication state (or
remove the conditional in Header if auth is not wired yet), and make sure the
Header component uses the corrected auth source so the public/private navigation
branch can actually be reached.

In `@src/widgets/header/ui/private-navigation/private-navigation.tsx`:
- Around line 18-20: The “sign out” Button in private-navigation currently
renders without any click handler, so it does nothing when pressed. Update the
Button used for signOutLabel in private-navigation to wire in the existing
logout/sign-out action via an onClick handler, and if needed pass the handler
into this component through its props so the click can trigger the actual exit
flow.

---

Duplicate comments:
In `@src/pages/home-page/ui/home-page.tsx`:
- Around line 12-21: `HomePage` is applying a second debounce through
`useDebounce`, which can make `parsedSchema` lag behind the validation state
already provided by `SwaggerEditor`. Remove the local debounced value and derive
`parsedSchema` directly from `rawText` once `isSchemaValid` is true, keeping the
`useMemo` logic in `home-page.tsx` aligned with `SwaggerEditor`’s existing
debounce. Update the `parsedSchema` computation to use the current text state
instead of `debouncedText`, and adjust the dependency list accordingly so the
parsed object always matches the validated input.

---

Nitpick comments:
In `@src/app/styles/style.scss`:
- Around line 11-14: The hardcoded 80px in the main layout styles is duplicated
header spacing and should be tied to the Header height via a CSS variable.
Update the styles in style.scss so main uses a shared custom property for top
padding instead of a literal value, and define or reuse that variable where the
Header height is established so changes stay in sync.

In `@src/widgets/footer/ui/footer.tsx`:
- Around line 23-30: The footer label "RS School 2026" in the Footer component
is hardcoded while other footer texts use localization. Update the Footer JSX to
source this text through the existing i18n/messages flow (or confirm it is
intentionally a brand name and leave it unchanged), using the Footer component
and its t(...) calls as the location to adjust.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx`:
- Around line 60-68: The `SwaggerEditor` component is recreating the
`extensions` array on every render, which forces unnecessary CodeMirror
reconfiguration. Update `swagger-editor.tsx` so the `CodeEditor` call uses a
stable `extensions` reference by moving the array out of `SwaggerEditor` or
memoizing it with `useMemo` around `openapiLinter`. Keep the change localized to
the `SwaggerEditor`/`CodeEditor` props so the editor only reconfigures when the
actual extension changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 18f884ea-a235-48c4-bfcf-2f622baee7a2

📥 Commits

Reviewing files that changed from the base of the PR and between 5d80c2f and f3447f9.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • public/logo.png is excluded by !**/*.png
📒 Files selected for processing (40)
  • .github/workflows/checks.yml
  • app/[locale]/layout.tsx
  • messages/en.json
  • messages/ru.json
  • src/app/styles/style.scss
  • src/features/format-converter/lib/convert-format.ts
  • src/features/format-converter/lib/detect-format.test.ts
  • src/features/format-converter/lib/detect-format.ts
  • src/features/format-converter/ui/format-toggle.module.scss
  • src/features/format-converter/ui/format-toggle.tsx
  • src/features/language-switcher/index.ts
  • src/features/language-switcher/ui/language-switcher.module.scss
  • src/features/language-switcher/ui/language-switcher.tsx
  • src/features/schema-validator/lib/codemirror-linter.ts
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.tsx
  • src/pages/home-page/ui/home-page.tsx
  • src/shared/config/routes.ts
  • src/shared/lib/auth/is-authenticated.ts
  • src/shared/lib/parse-to-object.ts
  • src/shared/types/format.ts
  • src/shared/ui/button-link/button-link.module.scss
  • src/shared/ui/button-link/button-link.test.tsx
  • src/shared/ui/button-link/button-link.tsx
  • src/shared/ui/button-link/index.ts
  • src/shared/ui/code-editor/ui/code-editor.tsx
  • src/widgets/footer/index.ts
  • src/widgets/footer/ui/footer.module.scss
  • src/widgets/footer/ui/footer.tsx
  • src/widgets/header/index.ts
  • src/widgets/header/ui/header.module.scss
  • src/widgets/header/ui/header.tsx
  • src/widgets/header/ui/logo/index.ts
  • src/widgets/header/ui/logo/logo.tsx
  • src/widgets/header/ui/page-navigation/index.ts
  • src/widgets/header/ui/page-navigation/page-navigation.tsx
  • src/widgets/header/ui/private-navigation/index.ts
  • src/widgets/header/ui/private-navigation/private-navigation.tsx
  • src/widgets/header/ui/public-navigation/index.ts
  • src/widgets/header/ui/public-navigation/public-navigation.tsx
  • src/widgets/swagger-editor/ui/swagger-editor.tsx
✅ Files skipped from review due to trivial changes (11)
  • src/features/language-switcher/ui/language-switcher.tsx
  • src/shared/lib/parse-to-object.ts
  • src/shared/config/routes.ts
  • src/widgets/header/ui/logo/logo.tsx
  • src/widgets/footer/ui/footer.module.scss
  • src/features/language-switcher/index.ts
  • src/shared/lib/auth/is-authenticated.ts
  • src/widgets/header/ui/private-navigation/index.ts
  • src/features/format-converter/ui/format-toggle.module.scss
  • src/widgets/header/ui/page-navigation/index.ts
  • src/widgets/header/ui/header.module.scss
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/shared/types/format.ts
  • src/features/format-converter/ui/format-toggle.tsx
  • src/features/schema-validator/lib/codemirror-linter.ts
  • messages/ru.json
  • src/shared/ui/code-editor/ui/code-editor.tsx
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/pages/home-page/ui/home-page.tsx (1)

12-21: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Независимый повторный дебаунс дублирует и рассинхронизирует состояние с SwaggerEditor.

HomePage дебаунсит rawText с задержкой 500 мс, при этом SwaggerEditor уже дебаунсит то же значение внутри себя с задержкой 300 мс для вычисления isSchemaValid. Поскольку isSchemaValid устанавливается раньше (по факту стабилизации текста через 300 мс), а debouncedText в HomePage обновляется на 200 мс позже, между этими моментами parsedSchema может быть вычислен по устаревшему снимку текста, отличному от того, что был признан валидным. Сейчас это заметно только в console.log, но станет функциональной проблемой после интеграции реального SwaggerViewer.

Поскольку isSchemaValid уже гарантирует стабильность текста к моменту true, проще убрать локальный дебаунс в HomePage и использовать rawText напрямую.

Предлагаемая правка
   const [rawText, setRawText] = useState('');
   const [isSchemaValid, setIsSchemaValid] = useState(false);

-  const debouncedText = useDebounce(rawText, 500);
-
   const parsedSchema = useMemo(() => {
-    if (!isSchemaValid || !debouncedText) return null;
+    if (!isSchemaValid || !rawText) return null;

-    return parseToObject(debouncedText);
-  }, [debouncedText, isSchemaValid]);
+    return parseToObject(rawText);
+  }, [rawText, isSchemaValid]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/home-page/ui/home-page.tsx` around lines 12 - 21, `HomePage` is
applying a second debounce through `useDebounce`, which can make `parsedSchema`
lag behind the validation state already provided by `SwaggerEditor`. Remove the
local debounced value and derive `parsedSchema` directly from `rawText` once
`isSchemaValid` is true, keeping the `useMemo` logic in `home-page.tsx` aligned
with `SwaggerEditor`’s existing debounce. Update the `parsedSchema` computation
to use the current text state instead of `debouncedText`, and adjust the
dependency list accordingly so the parsed object always matches the validated
input.
🧹 Nitpick comments (3)
src/app/styles/style.scss (1)

11-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Вынесите 80px в CSS-переменную, связанную с высотой хедера.

Значение padding-top: 80px жёстко привязано к высоте Header, но не связано с ней явно. При изменении высоты хедера придётся синхронизировать вручную в двух местах.

♻️ Пример рефактора
+:root {
+  --header-height: 80px;
+}
+
 main {
   flex: 1;
-  padding-top: 80px;
+  padding-top: var(--header-height);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/styles/style.scss` around lines 11 - 14, The hardcoded 80px in the
main layout styles is duplicated header spacing and should be tied to the Header
height via a CSS variable. Update the styles in style.scss so main uses a shared
custom property for top padding instead of a literal value, and define or reuse
that variable where the Header height is established so changes stay in sync.
src/widgets/footer/ui/footer.tsx (1)

23-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Строка "RS School 2026" не локализована.

В отличие от остальных текстов в футере (t('about'), t('team1'), t('team2')), эта строка захардкожена. Если это осознанно (название курса/бренд), можно игнорировать, иначе стоит перенести в messages/*.json.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/footer/ui/footer.tsx` around lines 23 - 30, The footer label "RS
School 2026" in the Footer component is hardcoded while other footer texts use
localization. Update the Footer JSX to source this text through the existing
i18n/messages flow (or confirm it is intentionally a brand name and leave it
unchanged), using the Footer component and its t(...) calls as the location to
adjust.
src/widgets/swagger-editor/ui/swagger-editor.tsx (1)

60-68: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Массив extensions пересоздаётся на каждый рендер.

extensions={[openapiLinter]} создаёт новый массив при каждом рендере SwaggerEditor, а компонент ре-рендерится на каждое изменение value (то есть на каждое нажатие клавиши). Официальная документация @uiw/react-codemirror рекомендует определять extensions вне компонента или мемоизировать через useMemo, так как смена ссылки вызывает дорогостоящую переконфигурацию редактора.

Предлагаемая правка
+  const extensions = useMemo(() => [openapiLinter], []);
+
   return (
     <div className={styles.wrapper}>
       ...
       <CodeEditor
         value={value}
         height="100%"
         onChange={onChange}
         format={currentFormat ?? undefined}
         className={styles.editor}
-        extensions={[openapiLinter]}
+        extensions={extensions}
         onUpdate={onEditorUpdate}
       />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx` around lines 60 - 68, The
`SwaggerEditor` component is recreating the `extensions` array on every render,
which forces unnecessary CodeMirror reconfiguration. Update `swagger-editor.tsx`
so the `CodeEditor` call uses a stable `extensions` reference by moving the
array out of `SwaggerEditor` or memoizing it with `useMemo` around
`openapiLinter`. Keep the change localized to the `SwaggerEditor`/`CodeEditor`
props so the editor only reconfigures when the actual extension changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/checks.yml:
- Around line 14-15: The `actions/checkout@v4` step is leaving `GITHUB_TOKEN`
available to later steps via git credentials. Update the checkout configuration
to disable credential persistence by setting `persist-credentials` to false on
the Checkout step in the workflow.

In `@src/shared/ui/button-link/button-link.module.scss`:
- Around line 7-14: Remove the empty lines before the declarations in the
button-link.module.scss stylesheet so the block follows the project’s
declaration formatting rules. Adjust the declaration group around font-size,
line-height, font-weight, text-decoration, cursor, transition, and border-radius
to be contiguous, matching the expected stylelint configuration in CI.

In `@src/widgets/header/ui/header.tsx`:
- Line 3: The auth check used by Header is a stub that always returns false, so
PrivateNavigation can never render. Update isAuthenticated from
src/shared/lib/auth/is-authenticated to read real authentication state (or
remove the conditional in Header if auth is not wired yet), and make sure the
Header component uses the corrected auth source so the public/private navigation
branch can actually be reached.

In `@src/widgets/header/ui/private-navigation/private-navigation.tsx`:
- Around line 18-20: The “sign out” Button in private-navigation currently
renders without any click handler, so it does nothing when pressed. Update the
Button used for signOutLabel in private-navigation to wire in the existing
logout/sign-out action via an onClick handler, and if needed pass the handler
into this component through its props so the click can trigger the actual exit
flow.

---

Duplicate comments:
In `@src/pages/home-page/ui/home-page.tsx`:
- Around line 12-21: `HomePage` is applying a second debounce through
`useDebounce`, which can make `parsedSchema` lag behind the validation state
already provided by `SwaggerEditor`. Remove the local debounced value and derive
`parsedSchema` directly from `rawText` once `isSchemaValid` is true, keeping the
`useMemo` logic in `home-page.tsx` aligned with `SwaggerEditor`’s existing
debounce. Update the `parsedSchema` computation to use the current text state
instead of `debouncedText`, and adjust the dependency list accordingly so the
parsed object always matches the validated input.

---

Nitpick comments:
In `@src/app/styles/style.scss`:
- Around line 11-14: The hardcoded 80px in the main layout styles is duplicated
header spacing and should be tied to the Header height via a CSS variable.
Update the styles in style.scss so main uses a shared custom property for top
padding instead of a literal value, and define or reuse that variable where the
Header height is established so changes stay in sync.

In `@src/widgets/footer/ui/footer.tsx`:
- Around line 23-30: The footer label "RS School 2026" in the Footer component
is hardcoded while other footer texts use localization. Update the Footer JSX to
source this text through the existing i18n/messages flow (or confirm it is
intentionally a brand name and leave it unchanged), using the Footer component
and its t(...) calls as the location to adjust.

In `@src/widgets/swagger-editor/ui/swagger-editor.tsx`:
- Around line 60-68: The `SwaggerEditor` component is recreating the
`extensions` array on every render, which forces unnecessary CodeMirror
reconfiguration. Update `swagger-editor.tsx` so the `CodeEditor` call uses a
stable `extensions` reference by moving the array out of `SwaggerEditor` or
memoizing it with `useMemo` around `openapiLinter`. Keep the change localized to
the `SwaggerEditor`/`CodeEditor` props so the editor only reconfigures when the
actual extension changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 18f884ea-a235-48c4-bfcf-2f622baee7a2

📥 Commits

Reviewing files that changed from the base of the PR and between 5d80c2f and f3447f9.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • public/logo.png is excluded by !**/*.png
📒 Files selected for processing (40)
  • .github/workflows/checks.yml
  • app/[locale]/layout.tsx
  • messages/en.json
  • messages/ru.json
  • src/app/styles/style.scss
  • src/features/format-converter/lib/convert-format.ts
  • src/features/format-converter/lib/detect-format.test.ts
  • src/features/format-converter/lib/detect-format.ts
  • src/features/format-converter/ui/format-toggle.module.scss
  • src/features/format-converter/ui/format-toggle.tsx
  • src/features/language-switcher/index.ts
  • src/features/language-switcher/ui/language-switcher.module.scss
  • src/features/language-switcher/ui/language-switcher.tsx
  • src/features/schema-validator/lib/codemirror-linter.ts
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.tsx
  • src/pages/home-page/ui/home-page.tsx
  • src/shared/config/routes.ts
  • src/shared/lib/auth/is-authenticated.ts
  • src/shared/lib/parse-to-object.ts
  • src/shared/types/format.ts
  • src/shared/ui/button-link/button-link.module.scss
  • src/shared/ui/button-link/button-link.test.tsx
  • src/shared/ui/button-link/button-link.tsx
  • src/shared/ui/button-link/index.ts
  • src/shared/ui/code-editor/ui/code-editor.tsx
  • src/widgets/footer/index.ts
  • src/widgets/footer/ui/footer.module.scss
  • src/widgets/footer/ui/footer.tsx
  • src/widgets/header/index.ts
  • src/widgets/header/ui/header.module.scss
  • src/widgets/header/ui/header.tsx
  • src/widgets/header/ui/logo/index.ts
  • src/widgets/header/ui/logo/logo.tsx
  • src/widgets/header/ui/page-navigation/index.ts
  • src/widgets/header/ui/page-navigation/page-navigation.tsx
  • src/widgets/header/ui/private-navigation/index.ts
  • src/widgets/header/ui/private-navigation/private-navigation.tsx
  • src/widgets/header/ui/public-navigation/index.ts
  • src/widgets/header/ui/public-navigation/public-navigation.tsx
  • src/widgets/swagger-editor/ui/swagger-editor.tsx
✅ Files skipped from review due to trivial changes (11)
  • src/features/language-switcher/ui/language-switcher.tsx
  • src/shared/lib/parse-to-object.ts
  • src/shared/config/routes.ts
  • src/widgets/header/ui/logo/logo.tsx
  • src/widgets/footer/ui/footer.module.scss
  • src/features/language-switcher/index.ts
  • src/shared/lib/auth/is-authenticated.ts
  • src/widgets/header/ui/private-navigation/index.ts
  • src/features/format-converter/ui/format-toggle.module.scss
  • src/widgets/header/ui/page-navigation/index.ts
  • src/widgets/header/ui/header.module.scss
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/shared/types/format.ts
  • src/features/format-converter/ui/format-toggle.tsx
  • src/features/schema-validator/lib/codemirror-linter.ts
  • messages/ru.json
  • src/shared/ui/code-editor/ui/code-editor.tsx
  • src/features/schema-validator/ui/validation-feedback/validation-feedback.tsx
🛑 Comments failed to post (4)
.github/workflows/checks.yml (1)

14-15: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Отключить persist-credentials для checkout.

actions/checkout@v4 по умолчанию сохраняет GITHUB_TOKEN в .git/config, доступный для всех последующих шагов job (npm ci, npm run build), включая код зависимостей и их install/postinstall-скрипты. Это увеличивает поверхность атаки при supply-chain компрометации npm-пакета.

🔒️ Предлагаемый фикс
       - name: Checkout
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      - name: Checkout
        uses: actions/checkout@v4
        with:
          persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 14-15: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/checks.yml around lines 14 - 15, The `actions/checkout@v4`
step is leaving `GITHUB_TOKEN` available to later steps via git credentials.
Update the checkout configuration to disable credential persistence by setting
`persist-credentials` to false on the Checkout step in the workflow.

Source: Linters/SAST tools

src/shared/ui/button-link/button-link.module.scss (1)

7-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Уберите пустые строки перед декларациями.

Stylelint уже ругается на font-size и border-radius; в текущем виде файл не пройдет проверку стилей, если правило declaration-empty-line-before включено в CI.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 7-7: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)


[error] 14-14: Expected no empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/button-link/button-link.module.scss` around lines 7 - 14,
Remove the empty lines before the declarations in the button-link.module.scss
stylesheet so the block follows the project’s declaration formatting rules.
Adjust the declaration group around font-size, line-height, font-weight,
text-decoration, cursor, transition, and border-radius to be contiguous,
matching the expected stylelint configuration in CI.

Source: Linters/SAST tools

src/widgets/header/ui/header.tsx (1)

3-3: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files 'src/widgets/header/ui/header.tsx' 'src/shared/lib/auth/is-authenticated.ts' || true

printf '\n== outline header ==\n'
ast-grep outline src/widgets/header/ui/header.tsx --view expanded || true

printf '\n== outline auth helper ==\n'
ast-grep outline src/shared/lib/auth/is-authenticated.ts --view expanded || true

printf '\n== header contents ==\n'
cat -n src/widgets/header/ui/header.tsx

printf '\n== auth helper contents ==\n'
cat -n src/shared/lib/auth/is-authenticated.ts

printf '\n== search auth usages ==\n'
rg -n "isAuthenticated|PrivateNavigation|PublicNavigation|login|session|cookie|auth" src -g '!**/*.map' || true

Repository: FierceSloth/swagger-editor-app

Length of output: 3271


isAuthenticated всегда false, поэтому PrivateNavigation недостижим.
src/shared/lib/auth/is-authenticated.ts:1 сейчас экспортирует false, из-за чего Header всегда показывает PublicNavigation. Замените это на реальное состояние аутентификации или уберите условие, пока auth-логика не подключена.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/header/ui/header.tsx` at line 3, The auth check used by Header is
a stub that always returns false, so PrivateNavigation can never render. Update
isAuthenticated from src/shared/lib/auth/is-authenticated to read real
authentication state (or remove the conditional in Header if auth is not wired
yet), and make sure the Header component uses the corrected auth source so the
public/private navigation branch can actually be reached.
src/widgets/header/ui/private-navigation/private-navigation.tsx (1)

18-20: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and related symbols first
ast-grep outline src/widgets/header/ui/private-navigation/private-navigation.tsx --view expanded || true

# Find references to the private navigation component and sign-out handling
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  'private-navigation|signOutLabel|onSignOut|sign out|signOut|logout|log out' src . || true

Repository: FierceSloth/swagger-editor-app

Length of output: 1794


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the target file and its immediate related files if found
wc -l src/widgets/header/ui/private-navigation/private-navigation.tsx 2>/dev/null || true
cat -n src/widgets/header/ui/private-navigation/private-navigation.tsx 2>/dev/null || true

Repository: FierceSloth/swagger-editor-app

Length of output: 997


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Button component API if it is local to the repository
fd -a 'Button.*' src . 2>/dev/null || true
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  'export .*Button|function Button|const Button|type ButtonProps|interface ButtonProps' src . || true

Repository: FierceSloth/swagger-editor-app

Length of output: 1576


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the target file and locate the Button component usage context
wc -l src/widgets/header/ui/private-navigation/private-navigation.tsx
cat -n src/widgets/header/ui/private-navigation/private-navigation.tsx | sed -n '1,220p'

Repository: FierceSloth/swagger-editor-app

Length of output: 997


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Button implementation and the header context for a sign-out action
wc -l src/shared/ui/button/button.tsx src/widgets/header/ui/header.tsx src/widgets/header/ui/private-navigation/private-navigation.tsx

echo '--- button.tsx ---'
cat -n src/shared/ui/button/button.tsx | sed -n '1,220p'

echo '--- header.tsx ---'
cat -n src/widgets/header/ui/header.tsx | sed -n '1,220p'

Repository: FierceSloth/swagger-editor-app

Length of output: 2284


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for any logout/sign-out handler or auth action used in the header area
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
  'signOut|sign out|logout|log out|auth.*sign|onSignOut|handleSignOut|handleLogout|logout' src

Repository: FierceSloth/swagger-editor-app

Length of output: 615


Кнопка «Выйти» не работает

Button для signOutLabel рендерится без onClick, поэтому по клику ничего не происходит. Нужен обработчик выхода.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/widgets/header/ui/private-navigation/private-navigation.tsx` around lines
18 - 20, The “sign out” Button in private-navigation currently renders without
any click handler, so it does nothing when pressed. Update the Button used for
signOutLabel in private-navigation to wire in the existing logout/sign-out
action via an onClick handler, and if needed pass the handler into this
component through its props so the click can trigger the actual exit flow.

@a-rudak-EIS a-rudak-EIS left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

This branch was successfully deployed

1 active deployment
Preview — 8151ef56 Deployed Jul 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants