Skip to content

Commit beed11b

Browse files
committed
fix: resolve linting issues and prepare for CI workflow
1 parent fed644b commit beed11b

File tree

31 files changed

+9304
-5127
lines changed

31 files changed

+9304
-5127
lines changed

.github/workflows/deploy.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
9+
permissions:
10+
contents: read
11+
pages: write
12+
id-token: write
13+
14+
# Allow only one concurrent deployment
15+
concurrency:
16+
group: "pages"
17+
cancel-in-progress: true
18+
19+
jobs:
20+
build:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Node
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: "18"
30+
cache: 'npm'
31+
32+
- name: Setup Pages
33+
uses: actions/configure-pages@v4
34+
35+
- name: Install dependencies
36+
run: npm install
37+
38+
- name: Generate static API files
39+
run: npm run generate-static-api
40+
41+
- name: Build with Next.js
42+
run: npm run build
43+
44+
- name: Upload artifact
45+
uses: actions/upload-pages-artifact@v3
46+
with:
47+
path: ./out
48+
49+
deploy:
50+
environment:
51+
name: github-pages
52+
url: ${{ steps.deployment.outputs.page_url }}
53+
runs-on: ubuntu-latest
54+
needs: build
55+
steps:
56+
- name: Deploy to GitHub Pages
57+
id: deployment
58+
uses: actions/deploy-pages@v4

README.md

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@ A modern, browser-based tool for validating, editing, and ensuring compliance of
1212

1313
## ✨ Features
1414

15-
* **CSV Handling:** Upload, edit (with code editor), save, and download CSV files.
16-
* **Schema Management:** Select predefined schemas or upload custom JSON schemas.
17-
* **Live Validation:** Real-time validation using Ajv, with errors/warnings shown per row/value.
18-
* **Detailed Results:** Errors and warnings are clearly displayed, with row numbers and schema paths.
19-
* **Save & Download:** Download your edited CSV at any time.
20-
* **Auto Re-validation:** CSV is automatically re-validated shortly after edits are made in the editor.
21-
* **Human-Readable Schema Docs:** View a Markdown-rendered, human-friendly version of the selected schema.
22-
* **Responsive UI:** Smoothly resizing panels with light/dark mode support.
23-
* **Automated Checks:** Robust CI/CD pipeline with linting, testing (unit & E2E), and security scans.
15+
- **CSV Handling:** Upload, edit (with code editor), save, and download CSV files.
16+
- **Schema Management:** Select predefined schemas or upload custom JSON schemas.
17+
- **Live Validation:** Real-time validation using Ajv, with errors/warnings shown per row/value.
18+
- **Detailed Results:** Errors and warnings are clearly displayed, with row numbers and schema paths.
19+
- **Save & Download:** Download your edited CSV at any time.
20+
- **Auto Re-validation:** CSV is automatically re-validated shortly after edits are made in the editor.
21+
- **Human-Readable Schema Docs:** View a Markdown-rendered, human-friendly version of the selected schema.
22+
- **Responsive UI:** Smoothly resizing panels with light/dark mode support.
23+
- **Automated Checks:** Robust CI/CD pipeline with linting, testing (unit & E2E), and security scans.
2424

2525
---
2626

2727
## 🚀 Getting Started
2828

2929
**Prerequisites:**
3030

31-
* Node.js (v18+ recommended)
32-
* pnpm (or npm/yarn)
31+
- Node.js (v18+ recommended)
32+
- pnpm (or npm/yarn)
3333

3434
**Installation & Running Locally:**
3535

@@ -59,9 +59,9 @@ pnpm dev
5959

6060
### Managing Local Schemas
6161

62-
* **Location:** Predefined schemas are located in the `schemas/v1/` directory.
63-
* **Adding New Schemas:** To add your own schema for local validation, simply place your `.json` schema file inside the `schemas/v1/` directory. The application will automatically pick it up and list it in the schema selection dropdown after a refresh.
64-
* **Schema Naming:** Ensure your schema file has a `.json` extension.
62+
- **Location:** Predefined schemas are located in the `schemas/v1/` directory.
63+
- **Adding New Schemas:** To add your own schema for local validation, simply place your `.json` schema file inside the `schemas/v1/` directory. The application will automatically pick it up and list it in the schema selection dropdown after a refresh.
64+
- **Schema Naming:** Ensure your schema file has a `.json` extension.
6565

6666
---
6767

@@ -72,58 +72,56 @@ This project uses a layered approach for quality assurance:
7272
<details>
7373
<summary><strong>Automated Checks Workflow (Click to Expand)</strong></summary>
7474

75-
* **Pre-Commit (`lint-staged`):**
76-
* *Purpose:* Auto-formats and fixes basic lint errors on staged files.
77-
* *Benefit:* Ensures clean commit history; fast feedback.
78-
* **Pre-Push (`husky`):**
79-
* *Purpose:* Local safeguard checking lint, types (`tsc --noEmit`), and unit tests (`pnpm test:unit`) on the entire code being pushed.
80-
* *Benefit:* Prevents pushing broken code; catches issues missed by pre-commit.
81-
* **CI (`GitHub Actions`):**
82-
* *Purpose:* Definitive quality gate (lint, all tests, build, security scans) in a clean environment.
83-
* *Benefit:* Ensures merged code meets all standards; catches anything missed locally.
75+
- **Pre-Commit (`lint-staged`):**
76+
- _Purpose:_ Auto-formats and fixes basic lint errors on staged files.
77+
- _Benefit:_ Ensures clean commit history; fast feedback.
78+
- **Pre-Push (`husky`):**
79+
- _Purpose:_ Local safeguard checking lint, types (`tsc --noEmit`), and unit tests (`pnpm test:unit`) on the entire code being pushed.
80+
- _Benefit:_ Prevents pushing broken code; catches issues missed by pre-commit.
81+
- **CI (`GitHub Actions`):** \* _Purpose:_ Definitive quality gate (lint, all tests, build, security scans) in a clean environment. \* _Benefit:_ Ensures merged code meets all standards; catches anything missed locally.
8482
</details>
8583

8684
**Manual Checks:**
8785

88-
```sh
86+
```sh
8987
# Lint check
90-
pnpm lint
88+
pnpm lint
9189

9290
# Format check (Prettier)
93-
pnpm format --check
91+
pnpm format --check
9492

9593
# Run unit tests
96-
pnpm test:unit
94+
pnpm test:unit
9795

9896
# Run all tests (unit + integration)
99-
pnpm test
97+
pnpm test
10098

10199
# Run E2E tests (Playwright)
102-
pnpm e2e
103-
```
100+
pnpm e2e
101+
```
104102

105103
---
106104

107105
## ⚙️ CI/CD & Deployment
108106

109-
* **CI (`.github/workflows/CI.yml`):** Runs automatically on pushes/PRs to `main` and `develop`. Includes lint, format check, full tests (`pnpm test`), build, and E2E tests.
110-
* **CodeQL (`.github/workflows/codeql-analysis.yml`):** Performs security analysis.
111-
* **CD (`.github/workflows/CD.yml`):** Deploys the static export to GitHub Pages from the `main` branch.
112-
* **Static Export:** Generated via `pnpm build && pnpm run export` (outputs to `./out`).
113-
* **GitHub Pages:** Configure repo settings to serve from the `gh-pages` branch.
107+
- **CI (`.github/workflows/CI.yml`):** Runs automatically on pushes/PRs to `main` and `develop`. Includes lint, format check, full tests (`pnpm test`), build, and E2E tests.
108+
- **CodeQL (`.github/workflows/codeql-analysis.yml`):** Performs security analysis.
109+
- **CD (`.github/workflows/CD.yml`):** Deploys the static export to GitHub Pages from the `main` branch.
110+
- **Static Export:** Generated via `pnpm build && pnpm run export` (outputs to `./out`).
111+
- **GitHub Pages:** Configure repo settings to serve from the `gh-pages` branch.
114112

115113
---
116114

117115
## 💻 Tech Stack
118116

119-
* **Framework:** Next.js 15+ (React 19)
120-
* **Language:** TypeScript 5+
121-
* **UI:** Shadcn/ui, Radix UI, Tailwind CSS
122-
* **Validation:** Ajv
123-
* **CSV Parsing:** PapaParse
124-
* **Editor:** Monaco Editor
125-
* **Testing:** Jest (Unit), Playwright (E2E)
126-
* **CI/CD:** GitHub Actions, Husky, lint-staged
117+
- **Framework:** Next.js 15+ (React 19)
118+
- **Language:** TypeScript 5+
119+
- **UI:** Shadcn/ui, Radix UI, Tailwind CSS
120+
- **Validation:** Ajv
121+
- **CSV Parsing:** PapaParse
122+
- **Editor:** Monaco Editor
123+
- **Testing:** Jest (Unit), Playwright (E2E)
124+
- **CI/CD:** GitHub Actions, Husky, lint-staged
127125

128126
---
129127

app/api/generate-schema-doc/route.ts

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as JsonSchemaStaticDocsLib from "json-schema-static-docs"; // Use names
44
import fs from "fs/promises";
55
import path from "path";
66
import os from "os";
7-
import { createRequire } from "module"; // Import createRequire
7+
// import { createRequire } from "module"; // Import createRequire
88
import prettier from "prettier";
99
import parserTypescript from "prettier/parser-typescript";
1010
// import { DocGenerator } from "json-schema-static-docs"; // Removed
@@ -28,7 +28,9 @@ async function copyDirRecursive(src: string, dest: string) {
2828
}
2929

3030
// Helper to create a temporary file
31-
async function writeTempSchemaFile(schema: Record<string, unknown>): Promise<string> {
31+
async function writeTempSchemaFile(
32+
schema: Record<string, unknown>,
33+
): Promise<string> {
3234
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "schema-"));
3335
const tempFilePath = path.join(tempDir, "schema.json");
3436
await fs.writeFile(tempFilePath, JSON.stringify(schema, null, 2));
@@ -81,13 +83,13 @@ interface JsonSchemaStaticDocsOptions {
8183
createIndex: boolean;
8284
addFrontMatter: boolean;
8385
// Replace 'any' with 'unknown' for stricter checking
84-
[key: string]: unknown;
86+
[key: string]: unknown;
8587
}
8688

8789
interface JsonSchemaStaticDocsInstance {
8890
generate: () => Promise<void>;
8991
// Add other known methods/properties if available
90-
[key: string]: unknown;
92+
[key: string]: unknown;
9193
}
9294

9395
// Type for the constructor, assuming it's the default export or the module itself
@@ -104,30 +106,35 @@ type JsonSchemaStaticDocsModule =
104106
| { [key: string]: unknown }; // Fallback for other structures
105107

106108
// Custom Type Guard for the Constructor
107-
function isDocConstructor(obj: unknown): obj is JsonSchemaStaticDocsConstructor {
108-
return typeof obj === 'function' && obj.prototype !== undefined;
109+
function isDocConstructor(
110+
obj: unknown,
111+
): obj is JsonSchemaStaticDocsConstructor {
112+
return typeof obj === "function" && obj.prototype !== undefined;
109113
}
110114

111115
// eslint-disable-next-line @typescript-eslint/no-unused-vars
112116
async function formatMarkdown(markdown: string): Promise<string> {
113117
try {
114-
const result: string = await prettier.format(markdown, {
118+
const result: string = await prettier.format(markdown, {
115119
parser: "markdown",
116-
plugins: [parserTypescript],
120+
plugins: [parserTypescript],
117121
printWidth: 80,
118122
proseWrap: "always",
119123
});
120124
return result;
121-
} catch (error: unknown) { // Type error as unknown
125+
} catch (error: unknown) {
126+
// Type error as unknown
122127
console.warn("Could not parse error response from generate-schema-doc");
123128
// Safe access to properties
124129
let statusText = "Unknown status";
125-
if (typeof error === 'object' && error !== null && 'statusText' in error) {
126-
statusText = String((error as { statusText: unknown }).statusText);
130+
if (typeof error === "object" && error !== null && "statusText" in error) {
131+
statusText = String((error as { statusText: unknown }).statusText);
127132
}
128133
const errorDetails = `: ${statusText}`; // Use const as errorDetails is not reassigned after this block
129134
const message = error instanceof Error ? error.message : String(error);
130-
throw new Error(`Markdown formatting failed${errorDetails}. Original error: ${message}`);
135+
throw new Error(
136+
`Markdown formatting failed${errorDetails}. Original error: ${message}`,
137+
);
131138
}
132139
}
133140

@@ -138,7 +145,9 @@ export async function POST(request: Request) {
138145
const cleanupPaths: string[] = []; // Keep track of all paths to clean
139146

140147
try {
141-
const { schema } = (await request.json()) as { schema: Record<string, unknown> }; // Added type assertion
148+
const { schema } = (await request.json()) as {
149+
schema: Record<string, unknown>;
150+
}; // Added type assertion
142151

143152
if (!schema) {
144153
return NextResponse.json(
@@ -193,30 +202,47 @@ export async function POST(request: Request) {
193202

194203
// 4. Instantiate and run json-schema-static-docs
195204
// Attempt to find the constructor more safely
196-
const LibraryModule: JsonSchemaStaticDocsModule = JsonSchemaStaticDocsLib;
205+
const LibraryModule = JsonSchemaStaticDocsLib as JsonSchemaStaticDocsModule; // ADDED TYPE ASSERTION
197206
let Constructor: JsonSchemaStaticDocsConstructor | null = null;
198207

199208
// Use the type guard first for the direct constructor case
200209
if (isDocConstructor(LibraryModule)) {
201-
Constructor = LibraryModule;
202-
// Check if it's an object before checking properties
203-
} else if (LibraryModule && typeof LibraryModule === 'object') {
204-
// Use 'in' operator for safer property checking
205-
if ('default' in LibraryModule && LibraryModule.default && isDocConstructor(LibraryModule.default)) {
206-
// Add type assertion
207-
Constructor = LibraryModule.default as JsonSchemaStaticDocsConstructor;
208-
} else if ('JsonSchemaStaticDocs' in LibraryModule && LibraryModule.JsonSchemaStaticDocs && isDocConstructor(LibraryModule.JsonSchemaStaticDocs)) {
209-
// Add type assertion
210-
Constructor = LibraryModule.JsonSchemaStaticDocs as JsonSchemaStaticDocsConstructor;
211-
} else if ('DocGenerator' in LibraryModule && LibraryModule.DocGenerator && isDocConstructor(LibraryModule.DocGenerator)) {
212-
// Add type assertion
213-
Constructor = LibraryModule.DocGenerator as JsonSchemaStaticDocsConstructor;
214-
}
210+
Constructor = LibraryModule;
211+
// Check if it's an object before checking properties
212+
} else if (LibraryModule && typeof LibraryModule === "object") {
213+
// Use 'in' operator for safer property checking
214+
if (
215+
"default" in LibraryModule &&
216+
LibraryModule.default &&
217+
isDocConstructor(LibraryModule.default)
218+
) {
219+
// Add type assertion
220+
Constructor = LibraryModule.default;
221+
} else if (
222+
"JsonSchemaStaticDocs" in LibraryModule &&
223+
LibraryModule.JsonSchemaStaticDocs &&
224+
isDocConstructor(LibraryModule.JsonSchemaStaticDocs)
225+
) {
226+
// Add type assertion
227+
Constructor = LibraryModule.JsonSchemaStaticDocs;
228+
} else if (
229+
"DocGenerator" in LibraryModule &&
230+
LibraryModule.DocGenerator &&
231+
isDocConstructor(LibraryModule.DocGenerator)
232+
) {
233+
// Add type assertion
234+
Constructor = LibraryModule.DocGenerator;
235+
}
215236
}
216237

217238
if (!Constructor) {
218-
console.error("API: Could not find JsonSchemaStaticDocs constructor in the imported module.", LibraryModule);
219-
throw new Error("Failed to load the documentation generator library correctly.");
239+
console.error(
240+
"API: Could not find JsonSchemaStaticDocs constructor in the imported module.",
241+
LibraryModule,
242+
);
243+
throw new Error(
244+
"Failed to load the documentation generator library correctly.",
245+
);
220246
}
221247

222248
// Instantiate using the found constructor
@@ -238,12 +264,14 @@ export async function POST(request: Request) {
238264
// Call generate method (type safety from interface)
239265
await generator.generate();
240266
console.log("API: Generator finished.");
241-
} catch (genError: unknown) { // Ensure genError is unknown
267+
} catch (genError: unknown) {
268+
// Ensure genError is unknown
242269
console.error("API: Error during generator.generate():", genError);
243270
// Use type guard for message
244-
const message = genError instanceof Error ? genError.message : "Generator failed";
245-
246-
throw new Error(`Schema documentation generation failed: ${message}`);
271+
const message =
272+
genError instanceof Error ? genError.message : "Generator failed";
273+
274+
throw new Error(`Schema documentation generation failed: ${message}`);
247275
}
248276

249277
// 5. Read the generated Markdown file
@@ -257,7 +285,8 @@ export async function POST(request: Request) {
257285

258286
// 7. Return the Markdown content
259287
return NextResponse.json({ markdown });
260-
} catch (error: unknown) { // Changed to unknown
288+
} catch (error: unknown) {
289+
// Changed to unknown
261290
console.error("API Error generating schema doc:", error);
262291

263292
// Ensure cleanup happens even on error

0 commit comments

Comments
 (0)