@rvoh/psychic 3.1.1 → 3.1.3

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.
@@ -128,6 +128,16 @@ export class OpenApiSpecDiff {
128
128
  return errorOutput;
129
129
  }
130
130
  }
131
+ /**
132
+ * Detects oasdiff output that indicates no reportable changes for the
133
+ * given subcommand. Newer oasdiff versions print informational messages
134
+ * like "No changes detected" or "No changes to report, but the specs are
135
+ * different" to stdout rather than returning empty output.
136
+ */
137
+ isNoChangesOutput(output) {
138
+ const trimmed = output.trim();
139
+ return trimmed === 'No changes detected' || trimmed.startsWith('No changes to report');
140
+ }
131
141
  /**
132
142
  * Compares two OpenAPI files using oasdiff
133
143
  */
@@ -137,10 +147,14 @@ export class OpenApiSpecDiff {
137
147
  }
138
148
  const breakingChanges = this.runOasDiffCommand('breaking', mainFilePath, currentFilePath);
139
149
  const changelogChanges = this.runOasDiffCommand('changelog', mainFilePath, currentFilePath);
140
- const breaking = breakingChanges && !breakingChanges.includes('Command failed')
150
+ const breaking = breakingChanges &&
151
+ !breakingChanges.includes('Command failed') &&
152
+ !this.isNoChangesOutput(breakingChanges)
141
153
  ? breakingChanges.split('\n').filter(line => line.trim())
142
154
  : [];
143
- const changelog = changelogChanges && !changelogChanges.includes('Command failed')
155
+ const changelog = changelogChanges &&
156
+ !changelogChanges.includes('Command failed') &&
157
+ !this.isNoChangesOutput(changelogChanges)
144
158
  ? changelogChanges.split('\n').filter(line => line.trim())
145
159
  : [];
146
160
  const failedToCompare = breakingChanges.includes('Command failed')
@@ -105,7 +105,7 @@ ${INDENT} pnpm psy g:resource --singular v1/profile User/Profile User:belongs_t
105
105
  ${INDENT} pnpm psy g:resource --singular --owning-model=Candidate internal/candidates/\\{\\}/linkedin Candidate/Linkedin Candidate:belongs_to url:string`, false)
106
106
  .option('--only <onlyActions>', `comma separated list of resourceful endpoints to generate (omitted actions will not have controller methods, specs, or routes).
107
107
  ${INDENT}
108
- ${INDENT}Available actions: index, create, show, update, delete
108
+ ${INDENT}Available actions: index, create, show, update, destroy
109
109
  ${INDENT}
110
110
  ${INDENT}Examples:
111
111
  ${INDENT} --only=index,create,show # create and view only (e.g., form submissions)
@@ -140,6 +140,7 @@ ${INDENT}
140
140
  ${INDENT}Example:
141
141
  ${INDENT} pnpm psy g:resource --model-name=GroupDanceLesson v1/lessons/dance/groups Lesson/Dance/Group
142
142
  ${INDENT} # model is named GroupDanceLesson instead of LessonDanceGroup`)
143
+ .option('--no-soft-delete', `skip generating the @SoftDelete() decorator and the corresponding nullable \`deleted_at\` column. By default, generated models use soft-delete semantics (rows are marked deleted via \`deleted_at\` instead of being removed from the database). Pass this flag when you want records to be hard-deleted.`)
143
144
  .argument('<path>', `The URL path for this resource's routes, relative to the root domain. Use \`\\{\\}\` as a placeholder for a parent resource's ID parameter when nesting.
144
145
  ${INDENT}
145
146
  ${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "admin" and "internal" remove the \`currentUser\` scoping of queries (\`--owning-model\` may be provided to apply query scoping). Each segment maps to a directory level in the controllers folder.
@@ -29,6 +29,7 @@ export default async function generateResource({ route, fullyQualifiedModelName,
29
29
  connectionName: options.connectionName,
30
30
  tableName: options.tableName,
31
31
  modelName: options.modelName,
32
+ softDelete: options.softDelete,
32
33
  },
33
34
  });
34
35
  await generateController({
@@ -450,7 +450,7 @@ The following values will be allowed:
450
450
  }
451
451
  serializableStatement(bodySegment) {
452
452
  const serializableRef = bodySegment;
453
- const key = serializableRef.key || 'default';
453
+ const key = serializableRef.$serializableSerializerKey || serializableRef.key || 'default';
454
454
  const serializer = DreamApp.system.inferSerializerFromDreamOrViewModel(serializableRef.$serializable.prototype, key);
455
455
  if (!serializer)
456
456
  throw new Error(`Failed to locate serializers getter from: ${serializableRef.$serializable.name} using key: ${key}`);
@@ -128,6 +128,16 @@ export class OpenApiSpecDiff {
128
128
  return errorOutput;
129
129
  }
130
130
  }
131
+ /**
132
+ * Detects oasdiff output that indicates no reportable changes for the
133
+ * given subcommand. Newer oasdiff versions print informational messages
134
+ * like "No changes detected" or "No changes to report, but the specs are
135
+ * different" to stdout rather than returning empty output.
136
+ */
137
+ isNoChangesOutput(output) {
138
+ const trimmed = output.trim();
139
+ return trimmed === 'No changes detected' || trimmed.startsWith('No changes to report');
140
+ }
131
141
  /**
132
142
  * Compares two OpenAPI files using oasdiff
133
143
  */
@@ -137,10 +147,14 @@ export class OpenApiSpecDiff {
137
147
  }
138
148
  const breakingChanges = this.runOasDiffCommand('breaking', mainFilePath, currentFilePath);
139
149
  const changelogChanges = this.runOasDiffCommand('changelog', mainFilePath, currentFilePath);
140
- const breaking = breakingChanges && !breakingChanges.includes('Command failed')
150
+ const breaking = breakingChanges &&
151
+ !breakingChanges.includes('Command failed') &&
152
+ !this.isNoChangesOutput(breakingChanges)
141
153
  ? breakingChanges.split('\n').filter(line => line.trim())
142
154
  : [];
143
- const changelog = changelogChanges && !changelogChanges.includes('Command failed')
155
+ const changelog = changelogChanges &&
156
+ !changelogChanges.includes('Command failed') &&
157
+ !this.isNoChangesOutput(changelogChanges)
144
158
  ? changelogChanges.split('\n').filter(line => line.trim())
145
159
  : [];
146
160
  const failedToCompare = breakingChanges.includes('Command failed')
@@ -105,7 +105,7 @@ ${INDENT} pnpm psy g:resource --singular v1/profile User/Profile User:belongs_t
105
105
  ${INDENT} pnpm psy g:resource --singular --owning-model=Candidate internal/candidates/\\{\\}/linkedin Candidate/Linkedin Candidate:belongs_to url:string`, false)
106
106
  .option('--only <onlyActions>', `comma separated list of resourceful endpoints to generate (omitted actions will not have controller methods, specs, or routes).
107
107
  ${INDENT}
108
- ${INDENT}Available actions: index, create, show, update, delete
108
+ ${INDENT}Available actions: index, create, show, update, destroy
109
109
  ${INDENT}
110
110
  ${INDENT}Examples:
111
111
  ${INDENT} --only=index,create,show # create and view only (e.g., form submissions)
@@ -140,6 +140,7 @@ ${INDENT}
140
140
  ${INDENT}Example:
141
141
  ${INDENT} pnpm psy g:resource --model-name=GroupDanceLesson v1/lessons/dance/groups Lesson/Dance/Group
142
142
  ${INDENT} # model is named GroupDanceLesson instead of LessonDanceGroup`)
143
+ .option('--no-soft-delete', `skip generating the @SoftDelete() decorator and the corresponding nullable \`deleted_at\` column. By default, generated models use soft-delete semantics (rows are marked deleted via \`deleted_at\` instead of being removed from the database). Pass this flag when you want records to be hard-deleted.`)
143
144
  .argument('<path>', `The URL path for this resource's routes, relative to the root domain. Use \`\\{\\}\` as a placeholder for a parent resource's ID parameter when nesting.
144
145
  ${INDENT}
145
146
  ${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "admin" and "internal" remove the \`currentUser\` scoping of queries (\`--owning-model\` may be provided to apply query scoping). Each segment maps to a directory level in the controllers folder.
@@ -29,6 +29,7 @@ export default async function generateResource({ route, fullyQualifiedModelName,
29
29
  connectionName: options.connectionName,
30
30
  tableName: options.tableName,
31
31
  modelName: options.modelName,
32
+ softDelete: options.softDelete,
32
33
  },
33
34
  });
34
35
  await generateController({
@@ -450,7 +450,7 @@ The following values will be allowed:
450
450
  }
451
451
  serializableStatement(bodySegment) {
452
452
  const serializableRef = bodySegment;
453
- const key = serializableRef.key || 'default';
453
+ const key = serializableRef.$serializableSerializerKey || serializableRef.key || 'default';
454
454
  const serializer = DreamApp.system.inferSerializerFromDreamOrViewModel(serializableRef.$serializable.prototype, key);
455
455
  if (!serializer)
456
456
  throw new Error(`Failed to locate serializers getter from: ${serializableRef.$serializable.name} using key: ${key}`);
@@ -78,6 +78,13 @@ export declare class OpenApiSpecDiff {
78
78
  * Runs oasdiff command and returns the output
79
79
  */
80
80
  private runOasDiffCommand;
81
+ /**
82
+ * Detects oasdiff output that indicates no reportable changes for the
83
+ * given subcommand. Newer oasdiff versions print informational messages
84
+ * like "No changes detected" or "No changes to report, but the specs are
85
+ * different" to stdout rather than returning empty output.
86
+ */
87
+ private isNoChangesOutput;
81
88
  /**
82
89
  * Compares two OpenAPI files using oasdiff
83
90
  */
@@ -8,6 +8,8 @@ export default class PsychicBin {
8
8
  owningModel?: string;
9
9
  connectionName: string;
10
10
  modelName?: string;
11
+ tableName?: string;
12
+ softDelete: boolean;
11
13
  }): Promise<void>;
12
14
  static printRoutes(): void;
13
15
  static printControllerHierarchy(controllersPath?: string): void;
@@ -31,6 +31,7 @@ export default class PsychicCLI {
31
31
  connectionName: string;
32
32
  tableName?: string;
33
33
  modelName?: string;
34
+ softDelete: boolean;
34
35
  };
35
36
  columnsWithTypes: string[];
36
37
  }): Promise<void>;
@@ -11,6 +11,7 @@ export default function generateResource({ route, fullyQualifiedModelName, optio
11
11
  connectionName: string;
12
12
  tableName?: string;
13
13
  modelName?: string;
14
+ softDelete: boolean;
14
15
  };
15
16
  columnsWithTypes: string[];
16
17
  }): Promise<void>;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@rvoh/psychic",
4
4
  "description": "Typescript web framework",
5
- "version": "3.1.1",
5
+ "version": "3.1.3",
6
6
  "author": "RVOHealth",
7
7
  "repository": {
8
8
  "type": "git",
@@ -75,7 +75,7 @@
75
75
  "@koa/cors": "^5.0.0",
76
76
  "@koa/etag": "^5.0.2",
77
77
  "@koa/router": "^15.3.0",
78
- "@rvoh/dream": "^2.6.0",
78
+ "@rvoh/dream": "^2.7.0",
79
79
  "@types/koa": "^3.0.1",
80
80
  "@types/koa-bodyparser": "^4.3.12",
81
81
  "@types/koa-conditional-get": "^2.0.3",
@@ -92,7 +92,7 @@
92
92
  "@koa/cors": "^5.0.0",
93
93
  "@koa/etag": "^5.0.2",
94
94
  "@koa/router": "^15.3.1",
95
- "@rvoh/dream": "^2.6.0",
95
+ "@rvoh/dream": "^2.7.0",
96
96
  "@rvoh/dream-spec-helpers": "^2.1.1",
97
97
  "@rvoh/psychic-spec-helpers": "3.0.0",
98
98
  "@types/koa": "^3.0.1",