Skip to content

fix: correctly resolve json input #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import path from 'node:path';

import { describe, expect, it } from 'vitest';

import { getResolvedInput } from '../index';

describe('getResolvedInput', () => {
it('handles url', async () => {
const pathOrUrlOrSchema = 'https://foo.com';
const resolvedInput = await getResolvedInput({ pathOrUrlOrSchema });
expect(resolvedInput.type).toBe('url');
expect(resolvedInput.schema).toBeUndefined();
expect(resolvedInput.path).toBe('https://foo.com/');
});

it('handles file', async () => {
const pathOrUrlOrSchema = './path/to/openapi.json';
const resolvedInput = await getResolvedInput({ pathOrUrlOrSchema });
expect(resolvedInput.type).toBe('file');
expect(resolvedInput.schema).toBeUndefined();
expect(resolvedInput.path).toBe(path.resolve('./path/to/openapi.json'));
});

it('handles raw spec', async () => {
const pathOrUrlOrSchema = {
info: {
version: '1.0.0',
},
openapi: '3.1.0',
paths: {},
};
const resolvedInput = await getResolvedInput({ pathOrUrlOrSchema });
expect(resolvedInput.type).toBe('json');
expect(resolvedInput.schema).toEqual({
info: {
version: '1.0.0',
},
openapi: '3.1.0',
paths: {},
});
expect(resolvedInput.path).toBe('');
});
});
8 changes: 5 additions & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const getResolvedInput = ({
// So we're being generous here and doing the conversion automatically.
// This is not intended to be a 100% bulletproof solution.
// If it doesn't work for your use-case, then use a URL instead.
if (url.isFileSystemPath(resolvedInput.path)) {
if (resolvedInput.path && url.isFileSystemPath(resolvedInput.path)) {
resolvedInput.path = url.fromFileSystemPath(resolvedInput.path);
resolvedInput.type = 'file';
} else if (!resolvedInput.path && pathOrUrlOrSchema && typeof pathOrUrlOrSchema === 'object') {
Expand All @@ -54,8 +54,10 @@ export const getResolvedInput = ({
}
}

// resolve the absolute path of the schema
resolvedInput.path = url.resolve(url.cwd(), resolvedInput.path);
if (resolvedInput.type !== 'json') {
// resolve the absolute path of the schema
resolvedInput.path = url.resolve(url.cwd(), resolvedInput.path);
}

return resolvedInput;
}
Expand Down
98 changes: 49 additions & 49 deletions lib/resolvers/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,73 +14,73 @@ export const sendRequest = async ({
timeout?: number;
url: URL | string;
}): Promise<{
init?: RequestInit;
response: Response;
}> => {
url = new URL(url);
redirects.push(url.href);

try {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
const response = await fetch(url, {
signal: controller.signal,
...init,
});
clearTimeout(timeoutId);

if (response.status >= 400) {
// gracefully handle HEAD method not allowed
if (response.status === 405 && init?.method === 'HEAD') {
return { response };
}
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
const response = await fetch(url, {
signal: controller.signal,
...init,
});
clearTimeout(timeoutId);

throw ono({ status: response.status }, `HTTP ERROR ${response.status}`);
if (response.status >= 300 && response.status <= 399) {
if (redirects.length > 5) {
throw new ResolverError(
ono(
{ status: response.status },
`Error requesting ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`,
),
);
}

if (response.status >= 300) {
if (redirects.length > 5) {
throw new ResolverError(
ono(
{ status: response.status },
`Error requesting ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`,
),
);
}

if (!("location" in response.headers) || !response.headers.location) {
throw ono({ status: response.status }, `HTTP ${response.status} redirect with no location header`);
}

return sendRequest({
init,
redirects,
timeout,
url: resolve(url.href, response.headers.location as string),
});

if (!("location" in response.headers) || !response.headers.location) {
throw ono({ status: response.status }, `HTTP ${response.status} redirect with no location header`);
}

return { response };
} catch (error: any) {
throw new ResolverError(ono(error, `Error requesting ${url.href}`), url.href);
return sendRequest({
init,
redirects,
timeout,
url: resolve(url.href, response.headers.location as string),
});
}

return { init, response };
}

export const urlResolver = {
handler: async (file: FileInfo, arrayBuffer?: ArrayBuffer): Promise<void> => {
let data = arrayBuffer;

if (!data) {
const { response } = await sendRequest({
init: {
method: 'GET',
},
url: file.url,
});
data = response.body ? await response.arrayBuffer() : new ArrayBuffer(0)
try {
const { init, response } = await sendRequest({
init: {
method: 'GET',
},
url: file.url,
});

if (response.status >= 400) {
// gracefully handle HEAD method not allowed
if (response.status !== 405 || init?.method !== 'HEAD') {
throw ono({ status: response.status }, `HTTP ERROR ${response.status}`);
}

data = response.body ? await response.arrayBuffer() : new ArrayBuffer(0)
}
} catch (error: any) {
throw new ResolverError(ono(error, `Error requesting ${file.url}`), file.url);
}
}

file.data = Buffer.from(data);
file.data = Buffer.from(data!);
},
};
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hey-api/json-schema-ref-parser",
"version": "1.0.2",
"version": "1.0.3",
"description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
"homepage": "https://heyapi.dev/",
"repository": {
Expand Down Expand Up @@ -48,8 +48,8 @@
"test:browser": "cross-env BROWSER=\"true\" yarn test",
"test:node": "yarn test",
"test:update": "vitest -u",
"test:watch": "vitest -w",
"test": "vitest --coverage",
"test:watch": "vitest watch --config vitest.config.unit.ts",
"test": "vitest run --config vitest.config.unit.ts",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
Expand Down

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions test/__IGNORED__/__({[ % & $ # @ ` ~ ,)}]__/dereferenced.ts

This file was deleted.

25 changes: 0 additions & 25 deletions test/__IGNORED__/__({[ % & $ # @ ` ~ ,)}]__/parsed.ts

This file was deleted.

This file was deleted.

68 changes: 0 additions & 68 deletions test/fixtures/server.ts

This file was deleted.

Loading