pocketbase-zod-schema 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/cli/migrate.cjs +182 -2
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +182 -2
- package/dist/cli/migrate.js.map +1 -1
- package/dist/index.cjs +38 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +38 -17
- package/dist/index.js.map +1 -1
- package/dist/mutator.cjs +38 -17
- package/dist/mutator.cjs.map +1 -1
- package/dist/mutator.d.cts +16 -13
- package/dist/mutator.d.ts +16 -13
- package/dist/mutator.js +38 -17
- package/dist/mutator.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0](https://github.com/dastron/pocketbase-zod-schema/compare/pocketbase-zod-schema-v0.3.9...pocketbase-zod-schema-v0.4.0) (2026-01-19)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add strongly typed expand support and type generation CLI ([2ca3f39](https://github.com/dastron/pocketbase-zod-schema/commit/2ca3f39d0af6bcf92f212ed64bab20e368c1297d))
|
|
9
|
+
* add strongly typed expand support and type generation CLI ([f8a1b4b](https://github.com/dastron/pocketbase-zod-schema/commit/f8a1b4bfbe3da3fc5b98977b53bc211fb3d44f0d))
|
|
10
|
+
|
|
3
11
|
## [0.3.9](https://github.com/dastron/pocketbase-zod-schema/compare/pocketbase-zod-schema-v0.3.8...pocketbase-zod-schema-v0.3.9) (2026-01-19)
|
|
4
12
|
|
|
5
13
|
|
package/dist/cli/migrate.cjs
CHANGED
|
@@ -179,10 +179,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
179
179
|
operation;
|
|
180
180
|
code;
|
|
181
181
|
originalError;
|
|
182
|
-
constructor(message,
|
|
182
|
+
constructor(message, path8, operation, code, originalError) {
|
|
183
183
|
super(message);
|
|
184
184
|
this.name = "FileSystemError";
|
|
185
|
-
this.path =
|
|
185
|
+
this.path = path8;
|
|
186
186
|
this.operation = operation;
|
|
187
187
|
this.code = code;
|
|
188
188
|
this.originalError = originalError;
|
|
@@ -4245,6 +4245,184 @@ Examples:
|
|
|
4245
4245
|
`
|
|
4246
4246
|
).action(executeGenerate);
|
|
4247
4247
|
}
|
|
4248
|
+
|
|
4249
|
+
// src/type-gen/generator.ts
|
|
4250
|
+
var TypeGenerator = class {
|
|
4251
|
+
schema;
|
|
4252
|
+
constructor(schema) {
|
|
4253
|
+
this.schema = schema;
|
|
4254
|
+
}
|
|
4255
|
+
generate() {
|
|
4256
|
+
const lines = [];
|
|
4257
|
+
lines.push(`/**`);
|
|
4258
|
+
lines.push(` * This file was auto-generated by pocketbase-zod-schema.`);
|
|
4259
|
+
lines.push(` * Do not modify it manually.`);
|
|
4260
|
+
lines.push(` */`);
|
|
4261
|
+
lines.push(``);
|
|
4262
|
+
lines.push(`import type { RecordModel } from "pocketbase";`);
|
|
4263
|
+
lines.push(``);
|
|
4264
|
+
const collectionNames = Array.from(this.schema.collections.keys());
|
|
4265
|
+
for (const [_, collection] of this.schema.collections) {
|
|
4266
|
+
lines.push(this.generateCollectionType(collection));
|
|
4267
|
+
lines.push(``);
|
|
4268
|
+
}
|
|
4269
|
+
lines.push(`export type CollectionResponses = {`);
|
|
4270
|
+
for (const name of collectionNames) {
|
|
4271
|
+
const typeName = this.toPascalCase(name);
|
|
4272
|
+
lines.push(` ${name}: ${typeName}Response;`);
|
|
4273
|
+
}
|
|
4274
|
+
lines.push(`};`);
|
|
4275
|
+
lines.push(``);
|
|
4276
|
+
lines.push(`import PocketBase from "pocketbase";`);
|
|
4277
|
+
lines.push(`import { RecordService } from "pocketbase";`);
|
|
4278
|
+
lines.push(``);
|
|
4279
|
+
lines.push(`export interface TypedPocketBase extends PocketBase {`);
|
|
4280
|
+
lines.push(` collection(idOrName: string): RecordService;`);
|
|
4281
|
+
for (const name of collectionNames) {
|
|
4282
|
+
const typeName = this.toPascalCase(name);
|
|
4283
|
+
lines.push(` collection(idOrName: "${name}"): RecordService<${typeName}Response>;`);
|
|
4284
|
+
}
|
|
4285
|
+
lines.push(`}`);
|
|
4286
|
+
lines.push(``);
|
|
4287
|
+
return lines.join("\n");
|
|
4288
|
+
}
|
|
4289
|
+
generateCollectionType(collection) {
|
|
4290
|
+
const typeName = this.toPascalCase(collection.name);
|
|
4291
|
+
const lines = [];
|
|
4292
|
+
lines.push(`export interface ${typeName}Record {`);
|
|
4293
|
+
lines.push(` id: string;`);
|
|
4294
|
+
lines.push(` created: string;`);
|
|
4295
|
+
lines.push(` updated: string;`);
|
|
4296
|
+
lines.push(` collectionId: string;`);
|
|
4297
|
+
lines.push(` collectionName: "${collection.name}";`);
|
|
4298
|
+
for (const field of collection.fields) {
|
|
4299
|
+
if (["id", "created", "updated"].includes(field.name)) continue;
|
|
4300
|
+
const fieldType = this.getFieldType(field);
|
|
4301
|
+
const optional = !field.required ? "?" : "";
|
|
4302
|
+
lines.push(` ${field.name}${optional}: ${fieldType};`);
|
|
4303
|
+
}
|
|
4304
|
+
lines.push(`}`);
|
|
4305
|
+
lines.push(``);
|
|
4306
|
+
lines.push(`export interface ${typeName}Response extends ${typeName}Record {`);
|
|
4307
|
+
const expandFields = [];
|
|
4308
|
+
for (const field of collection.fields) {
|
|
4309
|
+
if (field.type === "relation" && field.relation) {
|
|
4310
|
+
const targetCollection = field.relation.collection;
|
|
4311
|
+
let targetType = "RecordModel";
|
|
4312
|
+
if (targetCollection.toLowerCase() === "users" && !this.schema.collections.has("users")) ;
|
|
4313
|
+
if (this.schema.collections.has(targetCollection)) {
|
|
4314
|
+
targetType = `${this.toPascalCase(targetCollection)}Response`;
|
|
4315
|
+
} else if (targetCollection === "users") {
|
|
4316
|
+
targetType = "RecordModel";
|
|
4317
|
+
}
|
|
4318
|
+
const isMultiple = (field.relation.maxSelect ?? 1) > 1;
|
|
4319
|
+
const expandType = isMultiple ? `${targetType}[]` : targetType;
|
|
4320
|
+
expandFields.push(`${field.name}?: ${expandType}`);
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
if (expandFields.length > 0) {
|
|
4324
|
+
lines.push(` expand?: {`);
|
|
4325
|
+
for (const ef of expandFields) {
|
|
4326
|
+
lines.push(` ${ef};`);
|
|
4327
|
+
}
|
|
4328
|
+
lines.push(` };`);
|
|
4329
|
+
}
|
|
4330
|
+
lines.push(`}`);
|
|
4331
|
+
return lines.join("\n");
|
|
4332
|
+
}
|
|
4333
|
+
getFieldType(field) {
|
|
4334
|
+
switch (field.type) {
|
|
4335
|
+
case "text":
|
|
4336
|
+
case "email":
|
|
4337
|
+
case "url":
|
|
4338
|
+
case "editor":
|
|
4339
|
+
case "date":
|
|
4340
|
+
case "autodate":
|
|
4341
|
+
return "string";
|
|
4342
|
+
case "number":
|
|
4343
|
+
return "number";
|
|
4344
|
+
case "bool":
|
|
4345
|
+
return "boolean";
|
|
4346
|
+
case "json":
|
|
4347
|
+
return "any";
|
|
4348
|
+
case "file":
|
|
4349
|
+
if (field.options?.maxSelect && field.options.maxSelect > 1) {
|
|
4350
|
+
return "string[]";
|
|
4351
|
+
}
|
|
4352
|
+
return "string";
|
|
4353
|
+
case "select":
|
|
4354
|
+
if (field.options?.values && Array.isArray(field.options.values) && field.options.values.length > 0) {
|
|
4355
|
+
const union = field.options.values.map((v) => `"${v}"`).join(" | ");
|
|
4356
|
+
if (field.options?.maxSelect && field.options.maxSelect > 1) {
|
|
4357
|
+
return `(${union})[]`;
|
|
4358
|
+
}
|
|
4359
|
+
return union;
|
|
4360
|
+
}
|
|
4361
|
+
if (field.options?.maxSelect && field.options.maxSelect > 1) {
|
|
4362
|
+
return "string[]";
|
|
4363
|
+
}
|
|
4364
|
+
return "string";
|
|
4365
|
+
case "relation":
|
|
4366
|
+
if (field.relation?.maxSelect && field.relation.maxSelect > 1) {
|
|
4367
|
+
return "string[]";
|
|
4368
|
+
}
|
|
4369
|
+
return "string";
|
|
4370
|
+
default:
|
|
4371
|
+
return "any";
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
toPascalCase(str) {
|
|
4375
|
+
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word) => {
|
|
4376
|
+
return word.toUpperCase();
|
|
4377
|
+
}).replace(/[\s_-]+/g, "");
|
|
4378
|
+
}
|
|
4379
|
+
};
|
|
4380
|
+
|
|
4381
|
+
// src/cli/commands/generate-types.ts
|
|
4382
|
+
async function executeGenerateTypes(options) {
|
|
4383
|
+
try {
|
|
4384
|
+
const parentOpts = options.parent?.opts?.() || {};
|
|
4385
|
+
if (parentOpts.verbose) {
|
|
4386
|
+
setVerbosity("verbose");
|
|
4387
|
+
} else if (parentOpts.quiet) {
|
|
4388
|
+
setVerbosity("quiet");
|
|
4389
|
+
}
|
|
4390
|
+
logDebug("Starting type generation...");
|
|
4391
|
+
logDebug(`Options: ${JSON.stringify(options, null, 2)}`);
|
|
4392
|
+
const config = await loadConfig(options);
|
|
4393
|
+
const schemaDir = getSchemaDirectory(config);
|
|
4394
|
+
logSection("\u{1F50D} Analyzing Schema");
|
|
4395
|
+
const analyzerConfig = {
|
|
4396
|
+
schemaDir,
|
|
4397
|
+
excludePatterns: config.schema.exclude,
|
|
4398
|
+
useCompiledFiles: false
|
|
4399
|
+
};
|
|
4400
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
4401
|
+
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
4402
|
+
logSection("\u{1F4DD} Generating Types");
|
|
4403
|
+
const generator = new TypeGenerator(currentSchema);
|
|
4404
|
+
const output = await withProgress("Generating TypeScript definitions...", () => Promise.resolve(generator.generate()));
|
|
4405
|
+
const outputPath = options.output || "pocketbase-types.ts";
|
|
4406
|
+
const resolvedPath = path5__namespace.resolve(process.cwd(), outputPath);
|
|
4407
|
+
fs5__namespace.writeFileSync(resolvedPath, output);
|
|
4408
|
+
logSuccess(`Types generated successfully at: ${outputPath}`);
|
|
4409
|
+
logSection("\u2705 Next Steps");
|
|
4410
|
+
console.log();
|
|
4411
|
+
console.log(" 1. Import types in your application:");
|
|
4412
|
+
console.log(` import { TypedPocketBase } from "./${path5__namespace.basename(outputPath).replace(/\.ts$/, "")}";`);
|
|
4413
|
+
console.log();
|
|
4414
|
+
} catch (error) {
|
|
4415
|
+
logError(`Failed to generate types: ${error}`);
|
|
4416
|
+
if (error instanceof Error && error.stack) {
|
|
4417
|
+
console.error();
|
|
4418
|
+
console.error(error.stack);
|
|
4419
|
+
}
|
|
4420
|
+
process.exit(1);
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
function createGenerateTypesCommand() {
|
|
4424
|
+
return new commander.Command("generate-types").description("Generate TypeScript definitions from Zod schemas").option("-o, --output <path>", "Output file path", "pocketbase-types.ts").option("--schema-dir <directory>", "Directory containing Zod schema files").action(executeGenerateTypes);
|
|
4425
|
+
}
|
|
4248
4426
|
function hasChanges3(diff) {
|
|
4249
4427
|
return diff.collectionsToCreate.length > 0 || diff.collectionsToDelete.length > 0 || diff.collectionsToModify.length > 0;
|
|
4250
4428
|
}
|
|
@@ -4487,6 +4665,7 @@ program.name("pocketbase-migrate").description(
|
|
|
4487
4665
|
}
|
|
4488
4666
|
});
|
|
4489
4667
|
program.addCommand(createGenerateCommand());
|
|
4668
|
+
program.addCommand(createGenerateTypesCommand());
|
|
4490
4669
|
program.addCommand(createStatusCommand());
|
|
4491
4670
|
program.addHelpText(
|
|
4492
4671
|
"after",
|
|
@@ -4494,6 +4673,7 @@ program.addHelpText(
|
|
|
4494
4673
|
${chalk__default.default.bold("Examples:")}
|
|
4495
4674
|
$ pocketbase-migrate status Check for pending schema changes
|
|
4496
4675
|
$ pocketbase-migrate generate Generate migration from schema changes
|
|
4676
|
+
$ pocketbase-migrate generate-types Generate TypeScript definitions
|
|
4497
4677
|
$ pocketbase-migrate generate --force Generate migration with destructive changes
|
|
4498
4678
|
$ pocketbase-migrate --help Show this help message
|
|
4499
4679
|
|