@automateinc/fleet-types 1.0.104 → 1.0.105

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.
@@ -8,6 +8,37 @@ import path from "node:path";
8
8
  import { loadEnvFile } from "node:process";
9
9
  import { fileURLToPath } from "node:url";
10
10
 
11
+ const SERIALIZED_OUTPUT_TYPES = `type FleetIsAny<T> = 0 extends 1 & T ? true : false;
12
+ type FleetSimplify<T> = { [TKey in keyof T]: T[TKey] } & {};
13
+ type FleetSerializeObject<T extends object> = {
14
+ \t[TKey in keyof T as FleetIsAny<T[TKey]> extends true
15
+ \t\t? TKey
16
+ \t\t: [T[TKey]] extends [undefined]
17
+ \t\t\t? never
18
+ \t\t\t: T[TKey] extends (...args: never[]) => unknown
19
+ \t\t\t\t? never
20
+ \t\t\t\t: TKey]: FleetSerializeOutput<T[TKey]>;
21
+ };
22
+ type FleetSerializeOutput<T> = FleetIsAny<T> extends true
23
+ \t? T
24
+ \t: T extends (...args: never[]) => unknown
25
+ \t\t? never
26
+ \t\t: T extends Date
27
+ \t\t\t? string
28
+ \t\t\t: T extends readonly (infer TItem)[]
29
+ \t\t\t\t? FleetSerializeOutput<TItem>[]
30
+ \t\t\t\t: T extends { toJSON(): infer TJSON }
31
+ \t\t\t\t\t? TJSON extends object
32
+ \t\t\t\t\t\t? FleetSimplify<
33
+ \t\t\t\t\t\t\t\tOmit<FleetSerializeObject<Omit<T, "toJSON">>, keyof TJSON> &
34
+ \t\t\t\t\t\t\t\t\tFleetSerializeOutput<TJSON>
35
+ \t\t\t\t\t\t\t>
36
+ \t\t\t\t\t\t: FleetSerializeOutput<TJSON>
37
+ \t\t\t\t\t: T extends object
38
+ \t\t\t\t\t\t? FleetSerializeObject<T>
39
+ \t\t\t\t\t\t: T;
40
+ type FleetProcedureOutput<T> = { toJSON(): FleetSerializeOutput<T> };`;
41
+
11
42
  const command = process.argv[2];
12
43
 
13
44
  if (!command || command === "--help" || command === "-h") {
@@ -123,7 +154,9 @@ async function generateTypes() {
123
154
 
124
155
  const emittedPath = routerSourcePath.replace(/\.ts$/, ".d.ts");
125
156
  const sourceFile = ts.createSourceFile(emittedPath, emittedDeclaration, ts.ScriptTarget.Latest, true);
126
- const statements = sourceFile.statements.filter(
157
+ const sanitizedSourceFile = sanitizeBackendTypes(ts, sourceFile);
158
+ const transformedSourceFile = transformProcedureOutputs(ts, sanitizedSourceFile);
159
+ const statements = transformedSourceFile.statements.filter(
127
160
  statement =>
128
161
  ts.isImportDeclaration(statement) ||
129
162
  ts.isImportEqualsDeclaration(statement) ||
@@ -140,14 +173,14 @@ async function generateTypes() {
140
173
 
141
174
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
142
175
  const appRouterDeclaration = statements
143
- .map(statement => printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile))
176
+ .map(statement => printer.printNode(ts.EmitHint.Unspecified, statement, transformedSourceFile))
144
177
  .join("\n")
145
178
  .replace(/^(?: {4})+/gm, indentation => "\t".repeat(indentation.length / 4));
146
179
 
147
180
  await mkdir(path.dirname(outputPath), { recursive: true });
148
181
  await writeFile(
149
182
  outputPath,
150
- `// Generated by \`npx @automateinc/fleet-types generate\`. Do not edit manually.\n${appRouterDeclaration}\n`,
183
+ `// Generated by \`npx @automateinc/fleet-types generate\`. Do not edit manually.\n${SERIALIZED_OUTPUT_TYPES}\n${appRouterDeclaration}\n`,
151
184
  );
152
185
 
153
186
  if (existsSync(biomePath)) {
@@ -166,6 +199,100 @@ async function generateTypes() {
166
199
  console.log(`Generated ${path.relative(callerRoot, outputPath)} from ${routerSourcePath}`);
167
200
  }
168
201
 
202
+ function transformProcedureOutputs(ts, sourceFile) {
203
+ const procedureTypes = new Set(["TRPCMutationProcedure", "TRPCQueryProcedure", "TRPCSubscriptionProcedure"]);
204
+ const transformation = ts.transform(sourceFile, [
205
+ context => {
206
+ const visit = node => {
207
+ if (
208
+ ts.isImportTypeNode(node) &&
209
+ ts.isIdentifier(node.qualifier) &&
210
+ procedureTypes.has(node.qualifier.text) &&
211
+ node.typeArguments?.length
212
+ ) {
213
+ const [procedureDefinition, ...remainingTypeArguments] = node.typeArguments;
214
+
215
+ if (ts.isTypeLiteralNode(procedureDefinition)) {
216
+ const members = procedureDefinition.members.map(member => {
217
+ if (
218
+ ts.isPropertySignature(member) &&
219
+ member.type &&
220
+ ts.isIdentifier(member.name) &&
221
+ member.name.text === "output"
222
+ ) {
223
+ return ts.factory.updatePropertySignature(
224
+ member,
225
+ member.modifiers,
226
+ member.name,
227
+ member.questionToken,
228
+ ts.factory.createTypeReferenceNode("FleetProcedureOutput", [member.type]),
229
+ );
230
+ }
231
+
232
+ return member;
233
+ });
234
+ const updatedDefinition = ts.factory.updateTypeLiteralNode(procedureDefinition, members);
235
+
236
+ return ts.factory.updateImportTypeNode(
237
+ node,
238
+ node.argument,
239
+ node.attributes,
240
+ node.qualifier,
241
+ [updatedDefinition, ...remainingTypeArguments],
242
+ node.isTypeOf,
243
+ );
244
+ }
245
+ }
246
+
247
+ return ts.visitEachChild(node, visit, context);
248
+ };
249
+
250
+ return rootNode => ts.visitNode(rootNode, visit);
251
+ },
252
+ ]);
253
+ const transformedSourceFile = transformation.transformed[0];
254
+
255
+ transformation.dispose();
256
+
257
+ return transformedSourceFile;
258
+ }
259
+
260
+ function sanitizeBackendTypes(ts, sourceFile) {
261
+ const transformation = ts.transform(sourceFile, [
262
+ context => {
263
+ const visit = node => {
264
+ if (ts.isTypeReferenceNode(node)) {
265
+ let typeName = node.typeName;
266
+
267
+ while (ts.isQualifiedName(typeName)) typeName = typeName.left;
268
+
269
+ if (ts.isIdentifier(typeName) && typeName.text === "PrismaJson") {
270
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
271
+ }
272
+ }
273
+
274
+ if (
275
+ ts.isImportTypeNode(node) &&
276
+ ts.isLiteralTypeNode(node.argument) &&
277
+ ts.isStringLiteral(node.argument.literal) &&
278
+ node.argument.literal.text.startsWith("@/")
279
+ ) {
280
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
281
+ }
282
+
283
+ return ts.visitEachChild(node, visit, context);
284
+ };
285
+
286
+ return rootNode => ts.visitNode(rootNode, visit);
287
+ },
288
+ ]);
289
+ const transformedSourceFile = transformation.transformed[0];
290
+
291
+ transformation.dispose();
292
+
293
+ return transformedSourceFile;
294
+ }
295
+
169
296
  function formatTypeScriptDiagnostics(ts, diagnostics, currentDirectory) {
170
297
  return ts.formatDiagnosticsWithColorAndContext(diagnostics, {
171
298
  getCanonicalFileName: fileName => fileName,
package/package.json CHANGED
@@ -57,5 +57,5 @@
57
57
  "test": "echo \"Error: no test specified\" && exit 1"
58
58
  },
59
59
  "types": "dist/types/index.d.ts",
60
- "version": "1.0.104"
60
+ "version": "1.0.105"
61
61
  }
@@ -1,61 +0,0 @@
1
- // Generated by `npx @automateinc/fleet-types generate`. Do not edit manually.
2
- export declare const appRouter: import("@trpc/server").TRPCBuiltRouter<
3
- {
4
- ctx: {
5
- client: "FLEET_WEB" | "FLEET_MOBILE" | "FLEET_MOBILE_USER" | undefined;
6
- regionId: string | undefined;
7
- request: import("express").Request<
8
- import("express-serve-static-core").ParamsDictionary,
9
- any,
10
- any,
11
- import("qs").ParsedQs,
12
- Record<string, any>
13
- >;
14
- token: string | undefined;
15
- };
16
- meta: object;
17
- errorShape: import("@trpc/server").TRPCDefaultErrorShape;
18
- transformer: false;
19
- },
20
- import("@trpc/server").TRPCDecorateCreateRouterOptions<{
21
- auth: import("@trpc/server").TRPCBuiltRouter<
22
- {
23
- ctx: {
24
- client: "FLEET_WEB" | "FLEET_MOBILE" | "FLEET_MOBILE_USER" | undefined;
25
- regionId: string | undefined;
26
- request: import("express").Request<
27
- import("express-serve-static-core").ParamsDictionary,
28
- any,
29
- any,
30
- import("qs").ParsedQs,
31
- Record<string, any>
32
- >;
33
- token: string | undefined;
34
- };
35
- meta: object;
36
- errorShape: import("@trpc/server").TRPCDefaultErrorShape;
37
- transformer: false;
38
- },
39
- import("@trpc/server").TRPCDecorateCreateRouterOptions<{
40
- login: import("@trpc/server").TRPCMutationProcedure<{
41
- input: {
42
- email: string;
43
- password: string;
44
- };
45
- output: {
46
- token: string;
47
- };
48
- meta: object;
49
- }>;
50
- refreshToken: import("@trpc/server").TRPCMutationProcedure<{
51
- input: void;
52
- output: {
53
- token: string;
54
- };
55
- meta: object;
56
- }>;
57
- }>
58
- >;
59
- }>
60
- >;
61
- export type AppRouter = typeof appRouter;