Skip to content
Merged
9 changes: 9 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default tseslint.config(
"**/node_modules/**",
"**/.turbo/**",
"**/coverage/**",
"**/.coverage/**",
"**/.yarn/**",
"**/.pnp.*",
"**/*.mjs",
Expand Down Expand Up @@ -48,11 +49,19 @@ export default tseslint.config(
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: "type-imports",
disallowTypeAnnotations: false,
},
],
},
},
{
files: ["**/*.{test,spec}.{ts,tsx,js,jsx}"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"no-restricted-imports": [
"error",
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"build": "turbo run build --cache-dir=.turbo",
"test": "turbo run test --cache-dir=.turbo",
"lint": "turbo run lint --cache-dir=.turbo",
"lint:fix": "turbo run lint:fix --cache-dir=.turbo",
"typecheck": "turbo run typecheck --cache-dir=.turbo",
"clean": "turbo run clean && rm -rf node_modules .turbo"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/patchlogr-cli/esbuild.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ await build({
entryPoints: [path.resolve("src/index.ts")],
outfile: "dist/index.js",
platform: "node",
bundle: true,
sourcemap: true,
banner: {
js: "#!/usr/bin/env node",
},
Expand Down
11 changes: 9 additions & 2 deletions packages/patchlogr-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@
"publishConfig": {
"access": "public"
},
"bin": {
"patchlogr": "./dist/index.js"
},
"scripts": {
"clean": "rm -rf dist",
"typecheck": "tsc -p tsconfig.json --noEmit",
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
"build:js": "node ./esbuild.mjs",
"build": "yarn clean && yarn build:types && yarn build:js",
"preview": "node dist/index.js",
"test": "vitest",
"lint": "eslint ."
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@patchlogr/core": "workspace:*"
"@patchlogr/core": "workspace:*",
"@patchlogr/oas": "workspace:*",
"commander": "^14.0.2"
},
"devDependencies": {
"@types/node": "24",
Expand Down
37 changes: 37 additions & 0 deletions packages/patchlogr-cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Command } from "commander";

export function createCLI() {
const program = new Command();

program
.name("patchlogr")
.version("0.0.0")
.description("PatchlogrCLI : changelogs from openapi specs");

program
.command("help")
.description("Display help information about patchlogr commands");

program
.command("canonicalize")
.argument("<api-docs>", "Path to the OpenAPI specification file")
.option("--canonicalize", "Canonicalize the OpenAPI specification")
.option(
"--skipValidation",
"Skip validation of the OpenAPI specification",
)
.option(
"-o, --output <file>",
"Write result to file instead of stdout (default: stdout)",
)
.action(async (apiDocs, options) => {
try {
console.log("[patchlogr] Processing:", apiDocs, options);
} catch (error) {
console.error("[patchlogr] Error:", (error as Error).message);
process.exitCode = 1;
}
});

return program;
}
11 changes: 11 additions & 0 deletions packages/patchlogr-cli/src/commands/runCanonicalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { preprocessOASDocument } from "@patchlogr/oas";
import { type OASStageOptions } from "@patchlogr/oas";

export type RunCanonicalizeOptions = OASStageOptions;

export async function runCanonicalize(
apiDocs: any,

Check warning on line 7 in packages/patchlogr-cli/src/commands/runCanonicalize.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
options: RunCanonicalizeOptions,
) {
preprocessOASDocument(apiDocs, { ...options });
}
8 changes: 8 additions & 0 deletions packages/patchlogr-cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createCLI } from "./cli";

const program = createCLI();

program.parseAsync(process.argv).catch((error) => {
console.error("[patchlogr] Error:", error);
process.exitCode = 1;
});
3 changes: 2 additions & 1 deletion packages/patchlogr-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"build:js": "node ./esbuild.mjs",
"build": "yarn clean && yarn build:types && yarn build:js",
"test": "vitest",
"lint": "eslint ."
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"@apidevtools/swagger-parser": "^12.1.0",
Expand Down
16 changes: 16 additions & 0 deletions packages/patchlogr-oas/esbuild.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { build } from "esbuild";
import pkg from "./package.json" with { type: "json" };

await build({
entryPoints: ["src/index.ts"],
outdir: "dist",
bundle: true,
platform: "node",
target: ["node18", "node20", "node24"],
format: "esm",
sourcemap: true,
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
],
});
14 changes: 13 additions & 1 deletion packages/patchlogr-oas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@
"access": "public"
},
"scripts": {
"clean": "rm -rf dist",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"test": "vitest",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
"build:js": "node ./esbuild.mjs",
"build": "yarn clean && yarn build:types && yarn build:js"
},
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"devDependencies": {
"@types/node": "24",
"esbuild": "^0.27.2",
"openapi-types": "^12.1.3",
"vitest": "^4.0.16"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from "vitest";
import { preprocessOASDocument } from "../index";
import { OpenAPIV2, OpenAPIV3 } from "openapi-types";
import type { OpenAPIV2, OpenAPIV3 } from "openapi-types";

const docV2: OpenAPIV2.Document = {
swagger: "2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OpenAPIV2 } from "openapi-types";
import type { OpenAPIV2 } from "openapi-types";

export const docV2: OpenAPIV2.Document = {
swagger: "2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3 } from "openapi-types";

export const docV3: OpenAPIV3.Document = {
openapi: "3.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test } from "vitest";
import { CanonicalSchema } from "@patchlogr/types";
import type { CanonicalSchema } from "@patchlogr/types";

import {
canonicalizeOASV3,
Expand Down
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/canonicalize/v2/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {
import type {
CanonicalOperation,
CanonicalParam,
CanonicalSpec,
Expand All @@ -9,7 +9,7 @@
CanonicalOperationDoc,
CanonicalSecurityRequirement,
} from "@patchlogr/types";
import { OpenAPIV2 } from "openapi-types";
import type { OpenAPIV2 } from "openapi-types";
import { toCanonicalSchema } from "../../utils/toCanonicalSchema";

const HTTP_METHODS = [
Expand Down Expand Up @@ -353,16 +353,16 @@
operation: OpenAPIV2.OperationObject,
formDataParams: OpenAPIV2.GeneralParameterObject[],
): CanonicalBody {
const properties: Record<string, any> = {};

Check warning on line 356 in packages/patchlogr-oas/src/canonicalize/v2/index.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
const required: string[] = [];

for (const param of formDataParams) {
const {
name,
in: inParam,

Check warning on line 362 in packages/patchlogr-oas/src/canonicalize/v2/index.ts

View workflow job for this annotation

GitHub Actions / Build & Test

'inParam' is assigned a value but never used. Allowed unused vars must match /^_/u
required: requiredParam,
description,
allowEmptyValue,

Check warning on line 365 in packages/patchlogr-oas/src/canonicalize/v2/index.ts

View workflow job for this annotation

GitHub Actions / Build & Test

'allowEmptyValue' is assigned a value but never used. Allowed unused vars must match /^_/u
items,
...schemaProps
} = param;
Expand Down
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/canonicalize/v3/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {
import type {
CanonicalOperation,
CanonicalParam,
CanonicalSpec,
Expand All @@ -9,7 +9,7 @@ import {
CanonicalOperationDoc,
CanonicalSecurityRequirement,
} from "@patchlogr/types";
import { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3 } from "openapi-types";
import { toCanonicalSchema } from "../../utils/toCanonicalSchema";

const HTTP_METHODS = [
Expand Down
2 changes: 1 addition & 1 deletion packages/patchlogr-oas/src/guards/parameterGuards.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CanonicalParam } from "@patchlogr/types";
import type { CanonicalParam } from "@patchlogr/types";

export function isValidCanonicalParamIn(
val: string,
Expand Down
2 changes: 1 addition & 1 deletion packages/patchlogr-oas/src/guards/schemaGuards.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { OpenAPIV2, OpenAPIV3 } from "openapi-types";
import type { OpenAPIV2, OpenAPIV3 } from "openapi-types";

export type OpenAPISchemaObject =
| OpenAPIV2.SchemaObject
| OpenAPIV3.SchemaObject;

export type OpenAPISchemaObjectWithItems = OpenAPISchemaObject & {
items?: any;

Check warning on line 8 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
};

export type OpenAPISchemaObjectWithCommonProps =
OpenAPISchemaObjectWithItems & {
required?: string[];
properties?: Record<string, any>;

Check warning on line 14 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
[key: string]: any;

Check warning on line 15 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
};

export function isSchemaObject(obj: any): obj is OpenAPISchemaObject {

Check warning on line 18 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
return (
typeof obj === "object" &&
obj !== null &&
Expand All @@ -25,7 +25,7 @@
}

export function isSchemaWithCommonProps(
obj: any,

Check warning on line 28 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
): obj is OpenAPISchemaObjectWithCommonProps {
return (
isSchemaObject(obj) &&
Expand All @@ -36,7 +36,7 @@
}

export function isReferenceObject(
obj: any,

Check warning on line 39 in packages/patchlogr-oas/src/guards/schemaGuards.ts

View workflow job for this annotation

GitHub Actions / Build & Test

Unexpected any. Specify a different type
): obj is OpenAPIV2.ReferenceObject | OpenAPIV3.ReferenceObject {
return (
typeof obj === "object" &&
Expand Down
26 changes: 2 additions & 24 deletions packages/patchlogr-oas/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,2 @@
import { OpenAPI } from "openapi-types";
import { PipelineExecutor } from "./pipeline/PipelineExecutor";
import { OASValidationStage } from "./pipeline/OASValidationStage";
import { OASCanonicalizeStage } from "./pipeline/OASCanonicalizeStage";
import { OASBundleStage } from "./pipeline/OASBundleStage";
import { OASStageContext, OASStageOptions } from "./pipeline/OASStageContext";
import { OASDereferenceStage } from "./pipeline/OASDereferenceStage";

export function preprocessOASDocument(
doc: OpenAPI.Document,
options: OASStageOptions = {},
) {
const pipelineExecutor = new PipelineExecutor<OASStageContext>();

pipelineExecutor.add(new OASBundleStage());
pipelineExecutor.add(new OASValidationStage());
pipelineExecutor.add(new OASDereferenceStage());
pipelineExecutor.add(new OASCanonicalizeStage());

return pipelineExecutor.run({
source: doc,
options,
});
}
export { type OASStageOptions } from "./pipeline/OASStageContext";
export { preprocessOASDocument } from "./preprocessOASDocument";
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/pipeline/OASBundleStage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwaggerParser from "@apidevtools/swagger-parser";
import { OASStageContext } from "./OASStageContext";
import { PipelineStage } from "./PipelineExecutor";
import type { OASStageContext } from "./OASStageContext";
import type { PipelineStage } from "./PipelineExecutor";

/**
* μ™ΈλΆ€ $ref, schema λ₯Ό ν¬ν•¨ν•œ λͺ¨λ“  λ¬Έμ„œλ₯Ό ν•©μΉ¨
Expand Down
6 changes: 3 additions & 3 deletions packages/patchlogr-oas/src/pipeline/OASCanonicalizeStage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CanonicalSpec } from "@patchlogr/types";
import { OASStageContext } from "./OASStageContext";
import { PipelineStage } from "./PipelineExecutor";
import type { CanonicalSpec } from "@patchlogr/types";
import type { OASStageContext } from "./OASStageContext";
import type { PipelineStage } from "./PipelineExecutor";
import { canonicalizeOASV2 } from "../canonicalize/v2";
import { canonicalizeOASV3 } from "../canonicalize/v3";
import { isOpenAPIV2, isOpenAPIV3 } from "../utils/oasVersionUtils";
Expand Down
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/pipeline/OASDereferenceStage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwaggerParser from "@apidevtools/swagger-parser";
import { OASStageContext } from "./OASStageContext";
import { PipelineStage } from "./PipelineExecutor";
import type { OASStageContext } from "./OASStageContext";
import type { PipelineStage } from "./PipelineExecutor";

/**
* OAS λ¬Έμ„œμ˜ λͺ¨λ“  $refλ₯Ό 평탄화함
Expand Down
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/pipeline/OASStageContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CanonicalSpec } from "@patchlogr/types";
import { OpenAPI } from "openapi-types";
import type { CanonicalSpec } from "@patchlogr/types";
import type { OpenAPI } from "openapi-types";

export type OASStageInput = string | OpenAPI.Document;

Expand Down
4 changes: 2 additions & 2 deletions packages/patchlogr-oas/src/pipeline/OASValidationStage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SwaggerParser from "@apidevtools/swagger-parser";

import { PipelineStage } from "./PipelineExecutor";
import { OASStageContext } from "./OASStageContext";
import type { PipelineStage } from "./PipelineExecutor";
import type { OASStageContext } from "./OASStageContext";
import { getOASVersion } from "../utils/oasVersionUtils";

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, expect, test } from "vitest";
import { OASBundleStage } from "../OASBundleStage";
import { OASStageContext } from "../OASStageContext";
import type { OASStageContext } from "../OASStageContext";
import path from "path";
import { OpenAPIV3 } from "openapi-types";
import type { OpenAPIV3 } from "openapi-types";

describe("OASBundleStage", () => {
test("should dereference external $ref correctly", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, test, expect } from "vitest";
import { OASDereferenceStage } from "../OASDereferenceStage";
import { OASStageContext } from "../OASStageContext";
import type { OASStageContext } from "../OASStageContext";

describe("OASDereferenceStage", () => {
test("should throw an error if input.oas is missing", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
import { describe, expect, test } from "vitest";
import SwaggerParser from "@apidevtools/swagger-parser";
import { OASValidationStage } from "../OASValidationStage";
import { OASStageContext } from "../OASStageContext";
import type { OASStageContext } from "../OASStageContext";

const oasFixtureV2: OpenAPIV2.Document = {
swagger: "2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, test, vitest } from "vitest";
import { PipelineExecutor, PipelineStage } from "../PipelineExecutor";
import type { PipelineStage } from "../PipelineExecutor";
import { PipelineExecutor } from "../PipelineExecutor";

describe("PipelineExecutor", () => {
test("should append stages correctly", () => {
Expand Down
27 changes: 27 additions & 0 deletions packages/patchlogr-oas/src/preprocessOASDocument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { OpenAPI } from "openapi-types";
import { OASBundleStage } from "./pipeline/OASBundleStage";
import { OASCanonicalizeStage } from "./pipeline/OASCanonicalizeStage";
import { OASDereferenceStage } from "./pipeline/OASDereferenceStage";
import type {
OASStageOptions,
OASStageContext,
} from "./pipeline/OASStageContext";
import { OASValidationStage } from "./pipeline/OASValidationStage";
import { PipelineExecutor } from "./pipeline/PipelineExecutor";

export function preprocessOASDocument(
doc: OpenAPI.Document,
options: OASStageOptions = {},
) {
const pipelineExecutor = new PipelineExecutor<OASStageContext>();

pipelineExecutor.add(new OASBundleStage());
pipelineExecutor.add(new OASValidationStage());
pipelineExecutor.add(new OASDereferenceStage());
pipelineExecutor.add(new OASCanonicalizeStage());

return pipelineExecutor.run({
source: doc,
options,
});
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, test, expect } from "vitest";
import { toCanonicalSchema } from "../toCanonicalSchema";
import { OpenAPISchemaObjectWithItems } from "../../guards/schemaGuards";
import type { OpenAPISchemaObjectWithItems } from "../../guards/schemaGuards";

describe("toCanonicalSchema", () => {
test("should normalize simple schema", () => {
Expand Down
Loading
Loading