Skip to content

Commit

Permalink
fix: support windows (#191)
Browse files Browse the repository at this point in the history
  • Loading branch information
toomuchdesign authored Mar 5, 2024
1 parent c3689cc commit a418ecb
Show file tree
Hide file tree
Showing 27 changed files with 216 additions and 91 deletions.
5 changes: 5 additions & 0 deletions .changeset/forty-ducks-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-ts-json-schema": minor
---

`PluginInput['makeRelativePath']` type renamed to `PluginInput['makeRelativeModulePath']`
5 changes: 5 additions & 0 deletions .changeset/real-keys-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-ts-json-schema": minor
---

Support Windows OS
5 changes: 5 additions & 0 deletions .changeset/wicked-carrots-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"openapi-ts-json-schema": minor
---

Remove `schemaFileName` meta data prop
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ jobs:

strategy:
matrix:
node-version: [18, 20]
os: [ubuntu-latest]
node-version: [20]
os: [ubuntu-latest, windows-latest, macOS-latest]

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.version }}
node-version: ${{ matrix.node-version }}

- run: npm ci

- uses: actions/upload-artifact@v4
if: matrix.node-version == '18'
if: matrix.node-version == '20' && matrix.os == 'ubuntu-latest'
with:
name: code-coverage
path: coverage
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ coverage
!.github
!.nvmrc
!.changeset
!.gitattributes
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ Beside generating the expected schema files under `outputPath`, `openapiToTsJson
{
schemaId: string;
// JSON schema Compound Schema Document `$id`. Eg: `"/components/schemas/MySchema"`
schemaFileName: string;
// Valid filename for given schema (without extension). Eg: `"MySchema"`
schemaAbsoluteDirName: string;
// Absolute path pointing to schema folder. Eg: `"/output/path/components/schemas"`
schemaAbsolutePath: string;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"vitest": "^1.1.0"
},
"engines": {
"node": "^18.0.0"
"node": ">=18.0.0"
},
"simple-git-hooks": {
"pre-commit": "npm run source:check && npm test -- --run"
Expand Down
4 changes: 2 additions & 2 deletions src/openapiToTsJsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
pathToRef,
formatTypeScript,
saveFile,
makeRelativePath,
makeRelativeModulePath,
} from './utils';
import type {
SchemaPatcher,
Expand Down Expand Up @@ -166,7 +166,7 @@ export async function openapiToTsJsonSchema({
for (const plugin of plugins) {
await plugin({
...returnPayload,
utils: { makeRelativePath, formatTypeScript, saveFile },
utils: { makeRelativeModulePath, formatTypeScript, saveFile },
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/fastifyIntegrationPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const fastifyIntegrationPlugin: Plugin<
.map(
({ schemaAbsoluteImportPath, schemaUniqueName, schemaId, isRef }) => {
return {
importPath: utils.makeRelativePath({
importPath: utils.makeRelativeModulePath({
fromDirectory: outputPath,
to: schemaAbsoluteImportPath,
}),
Expand Down
10 changes: 6 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ export type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7;
export type JSONSchemaWithPlaceholders = JSONSchema | string;
export type OpenApiSchema = Record<string, any>;
export type SchemaPatcher = (params: { schema: JSONSchema }) => void;
import type { makeRelativePath, formatTypeScript, saveFile } from './utils';
import type {
makeRelativeModulePath,
formatTypeScript,
saveFile,
} from './utils';

/**
* @prop `schemaFileName` - Valid filename for given schema (without extension). Eg: `"MySchema"`
* @prop `schemaAbsoluteDirName` - Absolute path pointing to schema folder. Eg: `"/output/path/components/schemas"`
* @prop `schemaAbsolutePath` - Absolute path pointing to schema file. Eg: `"/output/path/components/schemas/MySchema.ts"`
* @prop `schemaAbsoluteImportPath` - Absolute import path (without extension). Eg: `"/output/path/components/schemas/MySchema"`
Expand All @@ -16,7 +19,6 @@ import type { makeRelativePath, formatTypeScript, saveFile } from './utils';
* @prop `isRef` - True if schemas is used as `$ref`
*/
export type SchemaMetaData = {
schemaFileName: string;
schemaAbsoluteDirName: string;
schemaAbsolutePath: string;
schemaAbsoluteImportPath: string;
Expand All @@ -38,7 +40,7 @@ export type ReturnPayload = {

type PluginInput = ReturnPayload & {
utils: {
makeRelativePath: typeof makeRelativePath;
makeRelativeModulePath: typeof makeRelativeModulePath;
formatTypeScript: typeof formatTypeScript;
saveFile: typeof saveFile;
};
Expand Down
11 changes: 5 additions & 6 deletions src/utils/addSchemaToMetaData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'node:path';
// @ts-expect-error no type defs for namify
import namify from 'namify';
import { refToPath, filenamify } from '.';
import { parseRef, refToPath, filenamify } from '.';
import type { SchemaMetaDataMap, SchemaMetaData, JSONSchema } from '../types';

/*
Expand All @@ -23,8 +23,8 @@ export function addSchemaToMetaData({
}): void {
// Do not override existing meta info of inlined schemas
if (!schemaMetaDataMap.has(ref)) {
const { schemaRelativeDirName, schemaName, schemaRelativePath } =
refToPath(ref);
const refPath = parseRef(ref);
const { schemaRelativeDirName, schemaName } = refToPath(ref);
const schemaAbsoluteDirName = path.join(outputPath, schemaRelativeDirName);
const schemaFileName = filenamify(schemaName);
const schemaAbsoluteImportPath = path.join(
Expand All @@ -34,12 +34,11 @@ export function addSchemaToMetaData({

const metaInfo: SchemaMetaData = {
originalSchema: schema,
schemaId: `/${schemaRelativePath}`,
schemaFileName,
schemaId: `/${refPath}`,
schemaAbsoluteDirName,
schemaAbsoluteImportPath,
schemaAbsolutePath: schemaAbsoluteImportPath + '.ts',
schemaUniqueName: namify(schemaRelativePath),
schemaUniqueName: namify(refPath),
isRef,
};
schemaMetaDataMap.set(ref, metaInfo);
Expand Down
3 changes: 2 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { makeTsJsonSchema } from './makeTsJsonSchema';
export { convertOpenApiPathsParameters } from './convertOpenApiPathsParameters';
export { convertOpenApiToJsonSchema } from './convertOpenApiToJsonSchema';
export { makeTsJsonSchemaFiles } from './makeTsJsonSchemaFiles';
export { parseRef } from './parseRef';
export { refToPath } from './refToPath';
export { pathToRef } from './pathToRef';
export {
Expand All @@ -17,6 +18,6 @@ export { isObject } from './isObject';
export { filenamify } from './filenamify';

export { clearFolder } from './clearFolder';
export { makeRelativePath } from './makeRelativePath';
export { makeRelativeModulePath } from './makeRelativeModulePath';
export { formatTypeScript } from './formatTypeScript';
export { saveFile } from './saveFile';
17 changes: 17 additions & 0 deletions src/utils/makeRelativeModulePath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import path from 'node:path';

/**
* Evaluate the relative module path from/to 2 absolute paths.
* Accepts posix and win32 absolute urls and return a relative modules path (""./foo/bar")
*/
export function makeRelativeModulePath({
fromDirectory,
to,
}: {
fromDirectory: string;
to: string;
}): string {
return (
'./' + path.relative(fromDirectory, to).split(path.sep).join(path.posix.sep)
);
}
14 changes: 0 additions & 14 deletions src/utils/makeRelativePath.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { makeRelativePath, PLACEHOLDER_REGEX } from '..';
import { makeRelativeModulePath, PLACEHOLDER_REGEX } from '..';
import type { SchemaMetaDataMap } from '../../types';

/**
Expand Down Expand Up @@ -28,7 +28,7 @@ export function replacePlaceholdersWithImportedSchemas({
/* c8 ignore stop */

// Evaluate imported schema relative path from current schema file
const importedSchemaRelativePath = makeRelativePath({
const importedSchemaRelativePath = makeRelativeModulePath({
fromDirectory: schemaAbsoluteDirName,
to: importedSchema.schemaAbsoluteImportPath,
});
Expand Down
12 changes: 12 additions & 0 deletions src/utils/parseRef.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Parses OpenApi ref:
* "#/components/schema/Foo" --> "components/schema/Foo"
*/
export function parseRef(ref: string): string {
if (!ref.startsWith('#/')) {
throw new Error(`[openapi-ts-json-schema] Unsupported ref value: "${ref}"`);
}

const refPath = ref.replace('#/', '');
return refPath;
}
12 changes: 8 additions & 4 deletions src/utils/pathToRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { filenamify } from './';
/**
* Generate a local OpenAPI ref from a relative path and a schema name
*/
const TRALING_SLASH_REGEX = /\/$/;
export function pathToRef({
schemaRelativeDirName,
schemaName,
Expand All @@ -13,9 +14,12 @@ export function pathToRef({
}): string {
return (
'#/' +
path.join(
schemaRelativeDirName.replaceAll('.', '/'),
filenamify(schemaName),
)
path
.normalize(schemaRelativeDirName)
.replaceAll('.', '/')
.replaceAll('\\', '/')
.replace(TRALING_SLASH_REGEX, '') +
'/' +
filenamify(schemaName)
);
}
18 changes: 4 additions & 14 deletions src/utils/refToPath.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import path from 'node:path';
import { parseRef } from '.';

/**
* Parses OpenAPI local refs (#/components/schema/Foo) to the derive the expected schema output path
Expand All @@ -7,23 +8,12 @@ import path from 'node:path';
* @NOTE Remote and url refs should have been already resolved and inlined
*/
export function refToPath(ref: string): {
schemaRelativePath: string;
schemaRelativeDirName: string;
schemaName: string;
} {
/* c8 ignore start */
if (!ref.startsWith('#/')) {
throw new Error(`[openapi-ts-json-schema] Unsupported ref value: "${ref}"`);
}
/* c8 ignore stop */

const refPath = ref.replace('#/', '');
const schemaName = path.basename(refPath);
const schemaRelativeDirName = path.dirname(refPath);

const refPath = parseRef(ref);
return {
schemaRelativePath: path.join(schemaRelativeDirName, schemaName),
schemaRelativeDirName,
schemaName,
schemaRelativeDirName: path.dirname(refPath),
schemaName: path.basename(refPath),
};
}
24 changes: 16 additions & 8 deletions test/metaData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,29 @@ describe('Returned "metaData"', async () => {
}

const expectedAnswerMetaData: SchemaMetaData = {
schemaFileName: 'Answer',
schemaAbsoluteDirName: `${outputPath}/components/schemas`,
schemaAbsolutePath: `${outputPath}/components/schemas/Answer.ts`,
schemaAbsoluteImportPath: `${outputPath}/components/schemas/Answer`,
schemaAbsoluteDirName: `${outputPath}/components/schemas`.replaceAll(
'/',
path.sep,
),
schemaAbsolutePath:
`${outputPath}/components/schemas/Answer.ts`.replaceAll('/', path.sep),
schemaAbsoluteImportPath:
`${outputPath}/components/schemas/Answer`.replaceAll('/', path.sep),
schemaUniqueName: 'componentsSchemasAnswer',
schemaId: '/components/schemas/Answer',
originalSchema: expect.any(Object),
isRef: true,
};

const expectedJanuaryMetaData: SchemaMetaData = {
schemaFileName: 'January',
schemaAbsoluteDirName: `${outputPath}/components/months`,
schemaAbsolutePath: `${outputPath}/components/months/January.ts`,
schemaAbsoluteImportPath: `${outputPath}/components/months/January`,
schemaAbsoluteDirName: `${outputPath}/components/months`.replaceAll(
'/',
path.sep,
),
schemaAbsolutePath:
`${outputPath}/components/months/January.ts`.replaceAll('/', path.sep),
schemaAbsoluteImportPath:
`${outputPath}/components/months/January`.replaceAll('/', path.sep),
schemaUniqueName: 'componentsMonthsJanuary',
schemaId: '/components/months/January',
originalSchema: expect.any(Object),
Expand Down
2 changes: 1 addition & 1 deletion test/test-utils/makeTestOutputPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import { fixtures } from './fixtures';
* Generate output paths in the fixtures folder
* as a schemas-autogenerated-* folder
*/
export function makeTestOutputPath(id: string = 'no-id'): string {
export function makeTestOutputPath(id: string): string {
return path.resolve(fixtures, `schemas-autogenerated-${id}-${Date.now()}`);
}
48 changes: 48 additions & 0 deletions test/unit/addSchemaToMetaData.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import path from 'node:path';
import { addSchemaToMetaData } from '../../src/utils';
import type { SchemaMetaData } from '../../src/types';

describe('addSchemaToMetaData', () => {
it('generates expected metadata', () => {
const ref = '#/components/schemas/Foo';
const schemaMetaDataMap = new Map();
const outputPath = path.normalize('/absolute/output/path');
const schema = {
description: 'Schema description',
type: 'object' as const,
required: ['bar'],
properties: { bar: { type: 'string' } } as const,
};

addSchemaToMetaData({
ref,
schemaMetaDataMap,
schema,
outputPath,
isRef: true,
});

const actual = schemaMetaDataMap.get(ref);
const expected: SchemaMetaData = {
isRef: true,
originalSchema: schema,
schemaAbsoluteDirName:
'/absolute/output/path/components/schemas'.replaceAll('/', path.sep),
schemaAbsoluteImportPath:
'/absolute/output/path/components/schemas/Foo'.replaceAll(
'/',
path.sep,
),
schemaAbsolutePath:
'/absolute/output/path/components/schemas/Foo.ts'.replaceAll(
'/',
path.sep,
),
schemaId: '/components/schemas/Foo',
schemaUniqueName: 'componentsSchemasFoo',
};

expect(actual).toEqual(expected);
});
});
Loading

0 comments on commit a418ecb

Please sign in to comment.