@postxl/generator 0.47.1 → 0.48.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/dist/generator.js CHANGED
@@ -77,6 +77,7 @@ const stub_generator_1 = require("./generators/models/stub.generator");
77
77
  const types_generator_3 = require("./generators/models/types.generator");
78
78
  const meta_1 = require("./lib/meta");
79
79
  const types_1 = require("./lib/schema/types");
80
+ const skip_generator_1 = require("./lib/skip-generator");
80
81
  const vfs_1 = require("./lib/vfs");
81
82
  const client_path_1 = require("./prisma/client-path");
82
83
  const parse_1 = require("./prisma/parse");
@@ -165,7 +166,9 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
165
166
  // Types
166
167
  generated.write(`/${meta.types.filePath}.ts`, (0, types_generator_3.generateModelTypes)({ model, meta }));
167
168
  // Seed
168
- generated.write(`/${meta.seed.filePath}.ts`, (0, seed_generator_1.generateSeedModel)({ model, itemCount: 5, meta }));
169
+ if (!(0, skip_generator_1.skipDecoder)({ model, generatorName: 'seed' })) {
170
+ generated.write(`/${meta.seed.filePath}.ts`, (0, seed_generator_1.generateSeedModel)({ model, itemCount: 5, meta, models }));
171
+ }
169
172
  // Data
170
173
  generated.write(`/${meta.data.stubFilePath}.ts`, (0, stub_generator_1.generateStub)({ model, meta }));
171
174
  generated.write(`/${meta.data.repository.filePath}.ts`, (0, repository_generator_1.generateRepository)({ model, meta }));
@@ -179,8 +182,15 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
179
182
  // Routes
180
183
  generated.write(`/${meta.trpc.routerFilePath}.ts`, (0, route_generator_1.generateRoute)({ model, meta }));
181
184
  // React
182
- yield generated.copy((0, react_generator_2.generateReactComponentsForModel)({ model, meta }), meta.react.folderPath);
183
- logger.log(`- ${model.name} processed`);
185
+ if (!(0, skip_generator_1.skipDecoder)({ model, generatorName: 'react' })) {
186
+ yield generated.copy((0, react_generator_2.generateReactComponentsForModel)({ model, meta }), meta.react.folderPath);
187
+ }
188
+ if (model.attributes.skipGenerators.size === 0) {
189
+ logger.log(`- ${model.name} processed`);
190
+ }
191
+ else {
192
+ logger.log(`- ${model.name} processed (skipped generators for: ${[...model.attributes.skipGenerators].join(', ')})`);
193
+ }
184
194
  }
185
195
  // Generate Enums
186
196
  for (const enumerator of enums.values()) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateSeedMigration = void 0;
4
4
  const imports_1 = require("../../lib/imports");
5
5
  const meta_1 = require("../../lib/meta");
6
+ const skip_generator_1 = require("../../lib/skip-generator");
6
7
  /**
7
8
  * Generates the initial migration based on the generated seed data.
8
9
  */
@@ -10,12 +11,15 @@ function generateSeedMigration({ models, meta }) {
10
11
  const imports = imports_1.ImportsGenerator.from(meta.seedData.initialMigrationFilePath);
11
12
  const modelTypes = [];
12
13
  for (const model of models) {
14
+ if ((0, skip_generator_1.skipDecoder)({ model, generatorName: 'seed' })) {
15
+ continue;
16
+ }
13
17
  const modelMeta = (0, meta_1.getModelMetadata)({ model });
14
- imports.addImport({
15
- items: [modelMeta.seed.constantName],
16
- from: modelMeta.seed.filePath,
18
+ imports.addImports({
19
+ [modelMeta.seed.filePath]: [modelMeta.seed.constantName],
20
+ [meta.importExport.importPath]: [meta.importExport.converterFunctions.importedDataToBulkMutations],
17
21
  });
18
- modelTypes.push(`${modelMeta.seed.constantName}: { create: ${modelMeta.seed.constantName} }`);
22
+ modelTypes.push(`${modelMeta.seed.constantName}`);
19
23
  }
20
24
  return /* ts */ `
21
25
  import { createActionSeedData } from '${meta.seed.importPath}'
@@ -24,11 +28,10 @@ ${imports.generate()}
24
28
  export const MIGRATION_001_BASEDATA = createActionSeedData({
25
29
  name: 'Base data',
26
30
  order: 1,
27
- data: [
28
- {
31
+ data: ${meta.importExport.converterFunctions.importedDataToBulkMutations}({
29
32
  ${modelTypes.join(',\n')}
30
33
  },
31
- ],
34
+ ),
32
35
  })
33
36
  `;
34
37
  }
@@ -3,10 +3,11 @@ import { Model, SchemaConfig } from '../../lib/schema/schema';
3
3
  /**
4
4
  * Creates a seed file for a given model.
5
5
  */
6
- export declare function generateSeedModel({ model, itemCount, meta, }: {
6
+ export declare function generateSeedModel({ model, itemCount, meta, models, }: {
7
7
  model: Model;
8
8
  itemCount: number;
9
9
  meta: ModelMetaData;
10
+ models: Model[];
10
11
  }): string;
11
12
  /**
12
13
  * Creates the seed file that exposes all seed data as single object.
@@ -12,11 +12,15 @@ const string_1 = require("../../lib/utils/string");
12
12
  /**
13
13
  * Creates a seed file for a given model.
14
14
  */
15
- function generateSeedModel({ model, itemCount, meta, }) {
15
+ function generateSeedModel({ model, itemCount, meta, models, }) {
16
16
  var _a;
17
17
  // NOTE: We seed `faker` independently for each model.
18
18
  // This way changes to another model or to the ordering of models in the schema doesn't impact the generated values.
19
19
  faker_1.faker.seed((_a = model.attributes.randomSeed) !== null && _a !== void 0 ? _a : 0);
20
+ const modelMap = new Map();
21
+ for (const model of models) {
22
+ modelMap.set(model.name, model);
23
+ }
20
24
  const imports = imports_1.ImportsGenerator.from(meta.seed.filePath).addImport({
21
25
  items: [(0, types_1.toAnnotatedTypeName)(model.typeName), meta.types.toBrandedIdTypeFnName],
22
26
  from: meta.types.importPath,
@@ -33,7 +37,7 @@ function generateSeedModel({ model, itemCount, meta, }) {
33
37
  const mode = getExampleMode({ model, maxItemCount: itemCount });
34
38
  const examples = [];
35
39
  for (let i = 1; i <= mode.itemCount; i++) {
36
- examples.push(generateExample({ model, index: i, mode }));
40
+ examples.push(generateExample({ model, index: i, mode, models: modelMap }));
37
41
  }
38
42
  return `
39
43
  ${imports.generate()}
@@ -57,7 +61,7 @@ function getExampleMode({ model, maxItemCount }) {
57
61
  field.attributes.examples.length > 0) {
58
62
  if (numberOfExamplesPerField === undefined) {
59
63
  numberOfExamplesPerField = field.attributes.examples.length;
60
- numberOfAllPossiblePermutations = 1;
64
+ numberOfAllPossiblePermutations = field.attributes.examples.length;
61
65
  }
62
66
  else if (numberOfExamplesPerField !== field.attributes.examples.length) {
63
67
  sameNumberOfExamplesPerField = false;
@@ -73,23 +77,23 @@ function getExampleMode({ model, maxItemCount }) {
73
77
  }
74
78
  return { kind: 'Permutations', itemCount: Math.min(numberOfAllPossiblePermutations, maxItemCount) };
75
79
  }
76
- function generateExample({ model, index, mode }) {
80
+ function generateExample({ model, index, mode, models, }) {
77
81
  const data = new serializer_1.Serializer();
78
82
  data.append('{');
79
83
  for (const field of model.fields.values()) {
80
- data.append(`${field.name}: ${generateFieldData({ field, model, index, mode })},`);
84
+ data.append(`${field.name}: ${generateFieldData({ field, model, index, mode, models })},`);
81
85
  }
82
86
  data.append('}');
83
87
  return data.print();
84
88
  }
85
- function generateFieldData({ field, model, index, mode, }) {
89
+ function generateFieldData({ field, model, index, mode, models, }) {
86
90
  switch (field.kind) {
87
91
  case 'id':
88
92
  return generateIdFieldExample({ field, model, index, mode });
89
93
  case 'scalar':
90
94
  return generateScalarFieldExample({ field, model, index, mode });
91
95
  case 'relation':
92
- return generateRelationFieldExample({ field, model, index, mode });
96
+ return generateRelationFieldExample({ field, model, index, mode, models });
93
97
  case 'enum':
94
98
  return generateEnumFieldExample({ field, mode, index });
95
99
  default:
@@ -215,14 +219,24 @@ function generateMockDate() {
215
219
  d.setUTCHours(0, 0, 0, 0);
216
220
  return `new Date('${d.toISOString()}')`;
217
221
  }
218
- function generateRelationFieldExample({ field, index, model, mode, }) {
222
+ function generateRelationFieldExample({ field, index, model, mode, models, }) {
219
223
  if (!field.isRequired) {
220
224
  return 'null';
221
225
  }
222
- const referenceId = faker_1.faker.datatype.number({ min: 1, max: mode.itemCount });
223
- const refModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
226
+ const refModel = models.get(field.relationToModel.name);
227
+ if (!refModel) {
228
+ throw new Error(`Could not find model ${field.relationToModel.name}`);
229
+ }
230
+ const refModelMeta = (0, meta_1.getModelMetadata)({ model: refModel });
231
+ const refModelExampleMode = getExampleMode({ model: refModel, maxItemCount: mode.itemCount });
232
+ const referenceId = faker_1.faker.datatype.number({ min: 1, max: refModelExampleMode.itemCount });
224
233
  const brandingFn = refModelMeta.types.toBrandedIdTypeFnName;
225
- const { hasExample, example } = generateFieldExample({ field, model, index, mode });
234
+ const { hasExample, example } = generateFieldExample({
235
+ field: refModel.idField,
236
+ model: refModel,
237
+ index,
238
+ mode: refModelExampleMode,
239
+ });
226
240
  if (field.unbrandedTypeName === 'string') {
227
241
  if (hasExample && typeof example === 'string') {
228
242
  return `${brandingFn}('${quoteSingleQuote(example)}')`;
@@ -1,3 +1,4 @@
1
+ import { GeneratorName } from './skip-generator';
1
2
  export type AttributeValue = unknown;
2
3
  export type Attributes = Record<string, AttributeValue>;
3
4
  export type ModelAttributes = {
@@ -36,6 +37,11 @@ export type ModelAttributes = {
36
37
  * The user that is used for system actions.
37
38
  */
38
39
  systemUser?: object;
40
+ /**
41
+ * Set of generators that should be skipped for this model.
42
+ * Schema tag: ´@@Skip("seed", "react")`
43
+ */
44
+ skipGenerators: Set<GeneratorName>;
39
45
  };
40
46
  export type FieldAttributes = {
41
47
  /**
@@ -0,0 +1,18 @@
1
+ import * as z from 'zod';
2
+ import { ModelCore } from './schema/schema';
3
+ /**
4
+ * Identifiers of generators that can be skipped.
5
+ */
6
+ export type GeneratorName = 'seed' | 'react';
7
+ /**
8
+ * Decoder to convert a list of generator names to a Set of generator names.
9
+ */
10
+ export declare const skipAttributeDecoder: z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"seed">, z.ZodLiteral<"react">]>, "many">>, Set<"seed" | "react">, ("seed" | "react")[] | undefined>;
11
+ export type SkipAttribute = z.infer<typeof skipAttributeDecoder>;
12
+ /**
13
+ * Returns true if the given generator should be skipped.
14
+ */
15
+ export declare function skipDecoder({ model, generatorName }: {
16
+ model: ModelCore;
17
+ generatorName: GeneratorName;
18
+ }): boolean;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.skipDecoder = exports.skipAttributeDecoder = void 0;
27
+ const z = __importStar(require("zod"));
28
+ /**
29
+ * Decoder to convert a list of generator names to a Set of generator names.
30
+ */
31
+ exports.skipAttributeDecoder = z
32
+ .array(z.union([z.literal('seed'), z.literal('react')]))
33
+ .optional()
34
+ .transform((t) => new Set(t));
35
+ /**
36
+ * Returns true if the given generator should be skipped.
37
+ */
38
+ function skipDecoder({ model, generatorName }) {
39
+ return model.attributes.skipGenerators.has(generatorName);
40
+ }
41
+ exports.skipDecoder = skipDecoder;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getFieldAttributes = exports.getEnumAttributes = exports.getModelAttributes = exports.parseArgumentToStringOrStringArray = exports.parseAttributesFromDocumentation = void 0;
7
7
  const zod_1 = __importDefault(require("zod"));
8
+ const skip_generator_1 = require("../lib/skip-generator");
8
9
  const string_1 = require("../lib/utils/string");
9
10
  /**
10
11
  * Parses attributes from a given string using provided prefix.
@@ -74,6 +75,7 @@ function getModelAttributes(model) {
74
75
  schema: zod_1.default.string().optional(),
75
76
  index: zod_1.default.array(zod_1.default.string()).optional(),
76
77
  seed: zod_1.default.string().optional(),
78
+ skip: skip_generator_1.skipAttributeDecoder,
77
79
  systemUser: zod_1.default
78
80
  .string()
79
81
  .transform((t) => JSON.parse(t))
@@ -85,6 +87,7 @@ function getModelAttributes(model) {
85
87
  description: obj.description,
86
88
  databaseSchema: obj.schema,
87
89
  index: obj.index,
90
+ skipGenerators: obj.skip,
88
91
  systemUser: obj.systemUser,
89
92
  randomSeed: obj.seed !== undefined ? parseInt(obj.seed, 10) : undefined,
90
93
  }));
@@ -158,6 +158,8 @@ function parseModel({ dmmfModel, enums, models, config, }) {
158
158
  if (dmmfField.relationOnDelete && dmmfField.relationOnDelete !== 'NoAction') {
159
159
  (0, error_1.throwError)(`Investigate model ${highlight(dmmfModel.name)}: "onDelete" attribute for relationship ${highlight(dmmfField.relationName)} must be "NoAction": any deletes must be handled in the application layer, e.g. to update repository and search caches!`);
160
160
  }
161
+ // Note: At this point, we only have the `ModelCore`. After all models are parsed, we need to updated
162
+ // the relations with the full `Model`. This is done in the `linkModels` function.
161
163
  relations[dmmfField.relationFromFields[0]] = referencedModel;
162
164
  }
163
165
  const relationFields = dmmfModel.fields
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.47.1",
3
+ "version": "0.48.0",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {