Skip to content

Commit

Permalink
Merge pull request #3 from p10ns11y/fix-bundling-and-make-utils-isomo…
Browse files Browse the repository at this point in the history
…rphic

fix: Bundling and make utils isomorphic
  • Loading branch information
p10ns11y authored Nov 11, 2024
2 parents 6ca47ae + 8ce24f8 commit ba89d86
Show file tree
Hide file tree
Showing 18 changed files with 681 additions and 149 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

build

ssr-build

# Logs
logs
*.log
Expand Down
2 changes: 1 addition & 1 deletion coverage-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/bundling-third-party-dep-issue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/coverage-report.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions jest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ export default {
},
extensionsToTreatAsEsm: ['.ts', '.tsx'],
coverageReporters: ['json-summary'],
// moduleNameMapper: {
// '^@adaptate/utils/(.*)$': '<rootDir>/packages/utils/src/$1',
// },
};
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "adaptate",
"version": "0.0.10-rc",
"version": "0.1.0",
"author": {
"name": "Peramanathan Sathyamoorthy",
"url": "https://github.com/p10ns11y/adaptate.git"
Expand All @@ -24,15 +24,18 @@
"README.md"
],
"scripts": {
"test": "node --experimental-vm-modules --no-warnings node_modules/jest/bin/jest.js --coverage",
"build": "turbo run build"
"test": "vitest --coverage",
"build": "turbo run build",
"coveragebadge": "npx make-coverage-badge --output-path ./coverage-badge.svg"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^22.9.0",
"@vitest/coverage-v8": "^2.1.4",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"turbo": "^2.2.3"
"turbo": "^2.2.3",
"vitest": "^2.1.4"
},
"description": "Dynamic and Adaptable Model Validator Using Zod, Interoperable with OpenAPI",
"keywords": [
Expand Down
8 changes: 4 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adaptate/core",
"version": "0.0.10-rc",
"version": "0.1.0",
"author": {
"name": "Peramanathan Sathyamoorthy",
"url": "https://github.com/p10ns11y/adaptate.git"
Expand Down Expand Up @@ -38,9 +38,9 @@
"README.md"
],
"exports": {
".": {
"types": "./src/index.ts",
"default": "./build/index.es.js"
"./*": {
"types": "./src/*.ts",
"default": "./build/*.es.js"
}
},
"description": "Dynamic and Adaptable Model Validator Using Zod, Interoperable with OpenAPI",
Expand Down
29 changes: 24 additions & 5 deletions packages/core/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { describe, it, expect } from 'vitest';

import { z } from 'zod';

import {
getDereferencedOpenAPIDocument,
openAPISchemaToZod,
Expand Down Expand Up @@ -82,7 +85,7 @@ describe('makeSchemaRequired', () => {

expect(() => transformedSchema.parse(invalidDataMissingName))
.toThrowErrorMatchingInlineSnapshot(`
"[
[ZodError: [
{
"code": "invalid_type",
"expected": "string",
Expand All @@ -105,7 +108,7 @@ describe('makeSchemaRequired', () => {
],
"message": "Required"
}
]"
]]
`);

// Re transforming the schema with different config
Expand All @@ -129,7 +132,7 @@ describe('makeSchemaRequired', () => {
expect(() => baseSchema.parse(invalidDataItems)).toThrow();
expect(() => transformedSchema.parse(invalidDataItems))
.toThrowErrorMatchingInlineSnapshot(`
"[
[ZodError: [
{
"code": "invalid_type",
"expected": "string",
Expand All @@ -152,7 +155,7 @@ describe('makeSchemaRequired', () => {
],
"message": "Expected array, received string"
}
]"
]]
`);

// TODO: Update code after evaluating the case of list of objects at top level
Expand Down Expand Up @@ -215,6 +218,22 @@ describe('makeSchemaRequired', () => {
dereferencedOpenAPIDocument['components']['schemas']['Category']
);

try {
// Intentionally not mocking the fetch call
let dereferencedOpenAPIDocumentFromWeb =
await getDereferencedOpenAPIDocument(
'https://raw.githubusercontent.com/p10ns11y/adaptate/refs/heads/main/packages/core/src/fixtures/base-schema.yml',
'',
'browser'
);

expect(dereferencedOpenAPIDocumentFromWeb).toEqual(
dereferencedOpenAPIDocument
);
} catch (e) {
console.log('Network failure or', (e as any)?.message);
}

let yetAnotherTransformedSchema = makeSchemaRequired(dataZodSchema, config);

expect(() =>
Expand Down Expand Up @@ -315,7 +334,7 @@ describe('makeSchemaRequired', () => {
expect(() =>
makeSchemaRequired(invalidSchema, config)
).toThrowErrorMatchingInlineSnapshot(
`"The given schema must be a Zod object."`
`[Error: The given schema must be a Zod object.]`
);
});

Expand Down
1 change: 1 addition & 0 deletions packages/core/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default defineConfig({
build: {
target: 'esnext',
outDir: 'build',
sourcemap: true,
lib: {
entry: ['src/index.ts', 'src/mutate-model.ts'],
formats: ['es'],
Expand Down
Binary file added packages/utils/images/import-fix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 28 additions & 14 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adaptate/utils",
"version": "0.0.10-rc",
"version": "0.1.0",
"author": {
"name": "Peramanathan Sathyamoorthy",
"url": "https://github.com/p10ns11y/adaptate.git"
Expand All @@ -17,18 +17,23 @@
"type": "module",
"source": "./src/index.ts",
"main": "./build/index.es.js",
"browser": "./build/index.es.js",
"module": "./build/index.es.js",
"jsnext:main": "./build/index.es.js",
"jsnext": "./build/index.es.js",
"types": "./build/index.d.ts",
"scripts": {
"build": "vite build",
"build": "vite build && vite build --ssr",
"build:ssr": "vite build --ssr",
"check-types": "tsc --noEmit"
},
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^11.7.2",
"js-yaml": "^4.1.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"@types/js-yaml": "^4.0.9",
"js-yaml": "^4.1.0",
"vite": "^5.4.10"
},
"peerDependencies": {
Expand All @@ -41,20 +46,29 @@
],
"exports": {
".": {
"types": "./src/index.ts",
"types": "./src/index",
"import": "./build/index.es.js",
"default": "./build/index.es.js"
},
"./openapi": {
"import": {
"types": "./src/openapi.ts",
"default": "./src/openapi.ts"
},
"require": {
"types": "./src/openapi.ts",
"default": "./build/openapi.es.js"
},
"types": "./src/openapi.ts",
"default": "./build/openapi.es.js"
"import": "./ssr-build/openapi.js",
"default": "./ssr-build/openapi.js"
},
"./*": {
"types": "./src/*.ts",
"import": "./build/*.es.js",
"default": "./build/*.es.js"
},
"./ssr": {
"types": "./src/index",
"import": "./ssr-build/index.js",
"default": "./ssr-build/index.js"
},
"./ssr/*": {
"types": "./src/index",
"import": "./ssr-build/*.js",
"default": "./ssr-build/*.js"
}
},
"description": "Dynamic and Adaptable Model Validator Using Zod, Interoperable with OpenAPI",
Expand Down
14 changes: 8 additions & 6 deletions packages/utils/src/__tests__/openapi.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { describe, it, expect } from 'vitest';

import { z } from 'zod';

import {
Expand Down Expand Up @@ -316,11 +318,11 @@ describe('getDereferencedOpenAPIDocument', () => {
},
}
`);
});

expect(() =>
getDereferencedOpenAPIDocument(import.meta.url, '../fixtures/unknown.yml')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error reading OpenAPI document: ENOENT: no such file or directory, open '/Users/peram/code/adaptate/packages/utils/src/fixtures/unknown.yml'"`
);
await expect(() =>
getDereferencedOpenAPIDocument(import.meta.url, '../fixtures/unknown.yml')
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Error reading OpenAPI document: ENOENT: no such file or directory, open '/Users/peram/code/adaptate/packages/utils/src/fixtures/unknown.yml']`
);
});
});
14 changes: 8 additions & 6 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export {
getDereferencedOpenAPIDocument,
// Features such as max, min, minLength, maxLength, pattern are missing
openAPISchemaToZod as simple_OpenAPISchemaToZod,
zodToOpenAPISchema as simple_ZodToOpenAPISchema,
openAPISchemaToZod as partial_OpenAPISchemaToZod,
zodToOpenAPISchema as partial_ZodToOpenAPISchema,
openAPISchemaToZod as incomplete_OpenAPISchemaToZod,
zodToOpenAPISchema as incomplete_ZodToOpenAPISchema,
// Check: https://github.com/StefanTerdell/json-schema-to-zod
// And zod-to-json-schema
openAPISchemaToZod as simple_openAPISchemaToZod,
openAPISchemaToZod as incomplete_openAPISchemaToZod,
openAPISchemaToZod as partial_openAPISchemaToZod,
zodToOpenAPISchema as simple_zodToOpenAPISchema,
zodToOpenAPISchema as incomplete_zodToOpenAPISchema,
zodToOpenAPISchema as partial_zodToOpenAPISchema,
} from './openapi';
16 changes: 16 additions & 0 deletions packages/utils/src/load-yaml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import yaml from 'js-yaml';

export async function getYamlContent(fileURL: string, relativePath: string) {
let fs = await import('node:fs');
let path = await import('node:path');
let { fileURLToPath } = await import('node:url');
let { dirname } = path;
let fileURLPath = fileURLToPath(fileURL);
let callerDirectoryName = dirname(fileURLPath);
let yamlFilePath = path.resolve(callerDirectoryName, relativePath);
let openapiDocument = yaml.load(
fs.readFileSync(yamlFilePath, 'utf8')
) as string;

return openapiDocument;
}
56 changes: 40 additions & 16 deletions packages/utils/src/openapi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import SwaggerParser from '@apidevtools/swagger-parser';
import yaml from 'js-yaml';

import { z, ZodTypeAny, ZodArray, ZodObject } from 'zod';
Expand Down Expand Up @@ -30,9 +29,11 @@ export function openAPISchemaToZod(
return required.includes(propertyKey) ? zodSchema : zodSchema.optional();
// Handle array type
} else if (schema.type === 'array') {
const itemsSchema = schema.items
? openAPISchemaToZod(schema.items, propertyKey, required)
: z.any();
let itemsSchema = z.any();
if (schema.items) {
// @ts-ignore
itemsSchema = openAPISchemaToZod(schema.items, propertyKey, required);
}

return required.includes(propertyKey)
? z.array(itemsSchema)
Expand Down Expand Up @@ -79,23 +80,46 @@ export function zodToOpenAPISchema(schema: ZodTypeAny): any {
return {};
}

async function fetchYamlContent(fileURL: string, relativePath: string) {
let fileURLPath = fileURL + relativePath;
let response = await globalThis.fetch(fileURLPath, {
headers: {
'Content-Type': 'text/yaml',
},
});
let openapiDocument = yaml.load(await response.text());

return openapiDocument;
}

export async function getDereferencedOpenAPIDocument(
fileURL: string,
relativePath: string
relativePath: string = '',
environment: 'server' | 'browser' = 'server'
) {
let openapiDocument = JSON.stringify({});

let isNode = globalThis.process?.versions?.node || environment === 'server';
let isBrowser = globalThis?.window?.document || environment === 'browser';

try {
let fs = await import('node:fs');
let path = await import('node:path');
let { fileURLToPath } = await import('node:url');
let { dirname } = path;
let fileURLPath = fileURLToPath(fileURL);
let callerDirectoryName = dirname(fileURLPath);
let yamlFilePath = path.resolve(callerDirectoryName, relativePath);
const openapiDocument = yaml.load(
fs.readFileSync(yamlFilePath, 'utf8')
) as string;
if (isBrowser) {
openapiDocument = (await fetchYamlContent(
fileURL,
relativePath
)) as string;
} else if (isNode) {
let { getYamlContent } = await import('./load-yaml.ts');

openapiDocument = await getYamlContent(fileURL, relativePath);
}
// https://github.com/APIDevTools/json-schema-reader/blob/main/src/index.ts#L21
// let SwaggerParser = await import('@apidevtools/swagger-parser');
let SwaggerParser = await import('@apidevtools/json-schema-ref-parser');

const dereferenced = await SwaggerParser.dereference(openapiDocument);
const dereferenced = await SwaggerParser.default.dereference(
openapiDocument
);

return dereferenced;
} catch (error) {
Expand Down
Loading

0 comments on commit ba89d86

Please sign in to comment.