Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@xata.io/pgroll

Package Overview
Dependencies
Maintainers
2
Versions
732
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xata.io/pgroll - npm Package Compare versions

Comparing version 0.0.0-alpha.v3b575065dded71a0d48761f0f4746b1051ea2dcf to 0.0.0-alpha.v437f15e1c31cc3f66ea0a8fa88ec901bc76de821

12

CHANGELOG.md
# @xata.io/pgroll
## 0.0.0-alpha.v3b575065dded71a0d48761f0f4746b1051ea2dcf
## 0.0.0-alpha.v437f15e1c31cc3f66ea0a8fa88ec901bc76de821
### Minor Changes
### Patch Changes
- [#1250](https://github.com/xataio/client-ts/pull/1250) [`5c7f7ec8f85428c8c5de3cc6e49d95d261b340f0`](https://github.com/xataio/client-ts/commit/5c7f7ec8f85428c8c5de3cc6e49d95d261b340f0) Thanks [@SferaDev](https://github.com/SferaDev)! - Initial release
- Force canary build
## 0.4.4
### Patch Changes
- [#1250](https://github.com/xataio/client-ts/pull/1250) [`9a6af72`](https://github.com/xataio/client-ts/commit/9a6af72ba4dd7880e8196a0a57d4133930957add) Thanks [@SferaDev](https://github.com/SferaDev)! - Add new package for pgroll migrations
{
"name": "@xata.io/pgroll",
"version": "0.0.0-alpha.v3b575065dded71a0d48761f0f4746b1051ea2dcf",
"version": "0.0.0-alpha.v437f15e1c31cc3f66ea0a8fa88ec901bc76de821",
"description": "Migration tool for PostgreSQL",

@@ -29,6 +29,7 @@ "type": "module",

"zod": "^3.22.4",
"zod-to-json-schema": "^3.21.4"
"zod-to-json-schema": "^3.22.4"
},
"devDependencies": {
"tsx": "^4.1.2"
"ts-morph": "^21.0.1",
"tsx": "^4.7.0"
},

@@ -35,0 +36,0 @@ "scripts": {

@@ -1,5 +0,210 @@

import { generateJSONSchema } from '../src';
import fs from 'fs';
import fs from 'fs/promises';
import { Project, ScriptTarget, VariableDeclarationKind } from 'ts-morph';
import { z } from 'zod';
import { PGROLL_JSON_SCHEMA_URL } from '../src';
import prettier from 'prettier';
const jsonSchema = generateJSONSchema();
fs.writeFileSync('pgroll.schema.json', JSON.stringify(jsonSchema, null, 2));
type Definition =
| { type: 'string' | 'boolean' | 'number'; description?: string }
| { $ref: string; description?: string }
| {
type: 'object';
properties: Record<string, Definition>;
oneOf?: unknown[];
required?: string[];
description?: string;
additionalProperties?: boolean;
}
| { type: 'array'; items: Definition | Definition[]; description?: string }
| { anyOf: Definition[] };
const DefinitionSchema: z.ZodSchema<Definition> = z.lazy(() =>
z.union([
z.object({
type: z.enum(['string', 'boolean', 'number']),
description: z.string().optional()
}),
z.object({
$ref: z.string(),
description: z.string().optional()
}),
z.object({
type: z.literal('object'),
properties: z.record(DefinitionSchema),
// TODO: Add full support for oneOf
oneOf: z.array(z.any()).optional(),
required: z.array(z.string()).optional(),
description: z.string().optional(),
additionalProperties: z.boolean().optional()
}),
z.object({
type: z.literal('array'),
items: z.union([DefinitionSchema, z.array(DefinitionSchema)]),
description: z.string().optional()
}),
z.object({
anyOf: z.array(DefinitionSchema)
})
])
);
const JSONSchema = z.object({
$id: z.string(),
$schema: z.string(),
title: z.string(),
description: z.string(),
$defs: z.record(DefinitionSchema)
});
function buildZodSchema(definition: Definition): string {
if ('$ref' in definition) {
return definition.$ref.replace(/^#\/\$defs\//, '') + 'Definition';
}
if ('anyOf' in definition) {
const schemas = definition.anyOf.map(buildZodSchema).join(', ');
return `z.union([${schemas}])`;
}
if (definition.type === 'array') {
const itemsSchema = Array.isArray(definition.items)
? buildZodSchema(definition.items[0])
: buildZodSchema(definition.items);
return `z.array(${itemsSchema})`;
}
if (definition.type === 'object') {
const properties: string[] = [];
for (const [name, property] of Object.entries(definition.properties)) {
const optional = definition.required?.includes(name) ? '' : '.optional()';
properties.push(`${name}: ${buildZodSchema(property)}${optional}`);
}
return `z.object({ ${properties.join(', ')} })`;
}
if (definition.type === 'string') {
return 'z.string()';
}
if (definition.type === 'boolean') {
return 'z.boolean()';
}
if (definition.type === 'number') {
return 'z.number()';
}
throw new Error(`Unknown type: ${definition.type}`);
}
function getDependencies(definition: Definition): string[] {
if ('$ref' in definition) {
return [definition.$ref.replace(/^#\/\$defs\//, '')];
}
if ('anyOf' in definition) {
return definition.anyOf.flatMap(getDependencies);
}
if (definition.type === 'array') {
return Array.isArray(definition.items)
? definition.items.flatMap(getDependencies)
: getDependencies(definition.items);
}
if (definition.type === 'object') {
return Object.values(definition.properties).flatMap(getDependencies);
}
return [];
}
function topologicalSort(nodes: [string, Definition][]): [string, Definition][] {
const sorted: [string, Definition][] = [];
const visited = new Set<string>();
// Recursive function to visit nodes in a topological order
function visit(name: string) {
if (visited.has(name)) return;
visited.add(name);
const node = nodes.find(([n]) => n === name);
if (!node) throw new Error(`Unknown node: ${name}`);
// Visit dependencies before adding the current node
for (const dep of getDependencies(node[1])) {
visit(dep);
}
sorted.push(node);
}
// Visit all nodes in the graph
for (const [name] of nodes) {
visit(name);
}
return sorted;
}
async function main() {
const url = process.env.PGROLL_JSON_SCHEMA_URL ?? PGROLL_JSON_SCHEMA_URL;
const response = await fetch(url).then((response) => response.json());
const schema = JSONSchema.parse(response);
// Create a TypeScript project
const project = new Project({ compilerOptions: { target: ScriptTarget.ESNext } });
const schemaFile = project.createSourceFile('schema.ts', '', { overwrite: true });
const typesFile = project.createSourceFile('types.ts', '', { overwrite: true });
// Write the JSON schema to a file
schemaFile.addStatements(`export const schema = ${JSON.stringify(response, null, 2)} as const;`);
// Add import statements
typesFile.addImportDeclaration({ moduleSpecifier: 'zod', namedImports: ['z'] });
// Topologically sort the schema definitions
const statements = topologicalSort(Object.entries(schema.$defs)).map(([name, definition]) => [
name,
buildZodSchema(definition)
]);
// Generate TypeScript code for each definition
for (const [name, statement] of statements) {
// Add a type alias for the Zod type
typesFile.addTypeAlias({ name, type: `z.infer<typeof ${name}Definition>`, isExported: true });
// Add a variable statement for the Zod schema
typesFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [{ name: `${name}Definition`, initializer: statement }],
isExported: true
});
}
// Add a type alias for the OperationType
typesFile.addTypeAlias({
name: 'OperationType',
type: `(typeof operationTypes)[number]`,
isExported: true
});
// Extract operation types from the schema and add a variable statement
const operationTypes = (schema.$defs['PgRollOperation'] as any).anyOf.flatMap((def) => Object.keys(def.properties));
typesFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'operationTypes',
initializer: `[${operationTypes.map((name) => `'${name}'`).join(', ')}] as const`
}
],
isExported: true
});
// Write the generated TypeScript code to a file
await fs.writeFile('src/schema.ts', prettier.format(schemaFile.getFullText(), { parser: 'typescript' }));
await fs.writeFile('src/types.ts', prettier.format(typesFile.getFullText(), { parser: 'typescript' }));
}
main();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc