@gadgetinc/ggt 0.4.7 → 0.4.8

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.
Files changed (84) hide show
  1. package/README.md +1 -1
  2. package/bin/dev.js +2 -1
  3. package/bin/run.js +3 -1
  4. package/lib/commands/deploy.js +11 -15
  5. package/lib/commands/deploy.js.map +1 -1
  6. package/lib/commands/list.js +7 -11
  7. package/lib/commands/list.js.map +1 -1
  8. package/lib/commands/login.js +8 -12
  9. package/lib/commands/login.js.map +1 -1
  10. package/lib/commands/logout.js +3 -7
  11. package/lib/commands/logout.js.map +1 -1
  12. package/lib/commands/root.js +17 -44
  13. package/lib/commands/root.js.map +1 -1
  14. package/lib/commands/sync.js +8 -27
  15. package/lib/commands/sync.js.map +1 -1
  16. package/lib/commands/version.js +2 -6
  17. package/lib/commands/version.js.map +1 -1
  18. package/lib/commands/whoami.js +5 -9
  19. package/lib/commands/whoami.js.map +1 -1
  20. package/lib/ggt.js +40 -0
  21. package/lib/ggt.js.map +1 -0
  22. package/lib/services/app/app.js +8 -6
  23. package/lib/services/app/app.js.map +1 -1
  24. package/lib/services/app/edit/client.js +176 -0
  25. package/lib/services/app/edit/client.js.map +1 -0
  26. package/lib/services/app/edit/edit.js +155 -0
  27. package/lib/services/app/edit/edit.js.map +1 -0
  28. package/lib/services/app/edit/error.js +65 -0
  29. package/lib/services/app/edit/error.js.map +1 -0
  30. package/lib/services/app/edit/operation.js +87 -0
  31. package/lib/services/app/edit/operation.js.map +1 -0
  32. package/lib/services/command/arg.js +5 -5
  33. package/lib/services/command/arg.js.map +1 -1
  34. package/lib/services/command/command.js +21 -7
  35. package/lib/services/command/command.js.map +1 -1
  36. package/lib/services/command/context.js +108 -56
  37. package/lib/services/command/context.js.map +1 -1
  38. package/lib/services/filesync/changes.js +7 -9
  39. package/lib/services/filesync/changes.js.map +1 -1
  40. package/lib/services/filesync/conflicts.js +11 -9
  41. package/lib/services/filesync/conflicts.js.map +1 -1
  42. package/lib/services/filesync/directory.js +2 -2
  43. package/lib/services/filesync/directory.js.map +1 -1
  44. package/lib/services/filesync/filesync.js +70 -42
  45. package/lib/services/filesync/filesync.js.map +1 -1
  46. package/lib/services/filesync/hashes.js +18 -15
  47. package/lib/services/filesync/hashes.js.map +1 -1
  48. package/lib/services/http/auth.js +4 -4
  49. package/lib/services/http/auth.js.map +1 -1
  50. package/lib/services/http/http.js +43 -23
  51. package/lib/services/http/http.js.map +1 -1
  52. package/lib/services/output/log/logger.js +11 -6
  53. package/lib/services/output/log/logger.js.map +1 -1
  54. package/lib/services/output/log/printer.js.map +1 -1
  55. package/lib/services/output/log/structured.js +2 -2
  56. package/lib/services/output/log/structured.js.map +1 -1
  57. package/lib/services/output/notify.js +3 -7
  58. package/lib/services/output/notify.js.map +1 -1
  59. package/lib/services/output/prompt.js +11 -11
  60. package/lib/services/output/prompt.js.map +1 -1
  61. package/lib/services/output/report.js +51 -67
  62. package/lib/services/output/report.js.map +1 -1
  63. package/lib/services/output/update.js +9 -10
  64. package/lib/services/output/update.js.map +1 -1
  65. package/lib/services/user/user.js +19 -25
  66. package/lib/services/user/user.js.map +1 -1
  67. package/lib/services/util/collection.js +1 -1
  68. package/lib/services/util/collection.js.map +1 -1
  69. package/lib/services/util/function.js +29 -11
  70. package/lib/services/util/function.js.map +1 -1
  71. package/lib/services/util/number.js +3 -3
  72. package/lib/services/util/number.js.map +1 -1
  73. package/lib/services/util/object.js +4 -4
  74. package/lib/services/util/object.js.map +1 -1
  75. package/lib/services/util/paths.js +4 -4
  76. package/lib/services/util/paths.js.map +1 -1
  77. package/lib/services/util/types.js +3 -1
  78. package/lib/services/util/types.js.map +1 -1
  79. package/npm-shrinkwrap.json +579 -411
  80. package/package.json +15 -14
  81. package/lib/main.js +0 -8
  82. package/lib/main.js.map +0 -1
  83. package/lib/services/app/edit-graphql.js +0 -392
  84. package/lib/services/app/edit-graphql.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/services/app/edit/edit.ts"],"sourcesContent":["import type { Promisable } from \"type-fest\";\nimport type { Context } from \"../../command/context.js\";\nimport { type HttpOptions } from \"../../http/http.js\";\nimport { unthunk, type Thunk } from \"../../util/function.js\";\nimport { Client } from \"./client.js\";\nimport { EditError } from \"./error.js\";\nimport type { GraphQLMutation, GraphQLQuery, GraphQLSubscription } from \"./operation.js\";\n\nexport class Edit {\n readonly ctx: Context;\n #client: Client;\n\n constructor(ctx: Context) {\n this.ctx = ctx.child({ name: \"edit\" });\n this.#client = new Client(this.ctx);\n }\n\n /**\n * Execute a GraphQL query.\n *\n * @param request - The query and variables to send to the server.\n * @param request.query - The GraphQL query to execute.\n * @param request.variables - The variables to send to the server.\n * @param request.http - {@linkcode HttpOptions} to pass to http.\n * @returns The data returned by the server.\n */\n async query<Query extends GraphQLQuery>({\n query,\n variables,\n ...options\n }: {\n query: Query;\n variables?: Thunk<Query[\"Variables\"]> | null;\n http?: HttpOptions;\n }): Promise<Query[\"Data\"]> {\n const name = query.split(/ |\\(/, 2)[1];\n const ctx = this.ctx.child({\n fields: { edit: { query: name } },\n devFields: { edit: { query: name, variables: unthunk(variables) } },\n });\n\n ctx.log.info(\"executing graphql query\");\n const response = await this.#client.execute(ctx, {\n operation: query,\n variables,\n ...options,\n http: {\n retry: {\n // queries _should_ be idempotent, so automatically retry them\n methods: [\"POST\"],\n },\n ...options.http,\n },\n });\n\n if (response.errors) {\n throw new EditError(query, response.errors);\n }\n\n if (!response.data) {\n throw new EditError(query, \"Query response did not contain data\");\n }\n\n return response.data;\n }\n\n /**\n * Execute a GraphQL mutation.\n *\n * @param request - The query and variables to send to the server.\n * @param request.mutation - The GraphQL query to execute.\n * @param request.variables - The variables to send to the server.\n * @param request.http - {@linkcode HttpOptions} to pass to http.\n * @returns The data returned by the server.\n */\n async mutate<Mutation extends GraphQLMutation>({\n mutation,\n variables,\n ...options\n }: {\n mutation: Mutation;\n variables?: Thunk<Mutation[\"Variables\"]> | null;\n http?: HttpOptions;\n }): Promise<Mutation[\"Data\"]> {\n const name = mutation.split(/ |\\(/, 2)[1];\n const ctx = this.ctx.child({\n fields: { edit: { mutation: name } },\n devFields: { edit: { mutation: name, variables: unthunk(variables) } },\n });\n\n ctx.log.info(\"executing graphql mutation\");\n const response = await this.#client.execute(ctx, { operation: mutation, variables, ...options });\n\n if (response.errors) {\n throw new EditError(mutation, response.errors);\n }\n\n if (!response.data) {\n throw new EditError(mutation, \"Mutation response did not contain data\");\n }\n\n return response.data;\n }\n\n /**\n * Subscribe to a GraphQL subscription.\n *\n * @param options - The query and variables to send to the server.\n * @param options.subscription - The GraphQL subscription to subscribe to.\n * @param options.variables - The variables to send to the server.\n * @param options.onData - A callback that will be called with the data returned by the server.\n * @param options.onError - A callback that will be called with any errors returned by the server.\n * @param options.onComplete - A callback that will be called when the subscription is complete.\n * @returns A function to unsubscribe from the subscription.\n */\n subscribe<Subscription extends GraphQLSubscription>({\n onData,\n ...options\n }: {\n subscription: Subscription;\n variables?: Thunk<Subscription[\"Variables\"]> | null;\n onData: (data: Subscription[\"Data\"]) => Promisable<void>;\n onError: (error: EditError) => Promisable<void>;\n onComplete?: () => Promisable<void>;\n }): () => void {\n const name = options.subscription.split(/ |\\(/, 2)[1];\n const ctx = this.ctx.child({\n fields: { edit: { subscription: name } },\n devFields: { edit: { subscription: name, variables: unthunk(options.variables) } },\n });\n\n ctx.log.info(\"subscribing to graphql subscription\");\n const unsubscribe = this.#client.subscribe(ctx, {\n ...options,\n onResponse: async (response) => {\n if (response.errors) {\n unsubscribe();\n await options.onError(new EditError(options.subscription, response.errors));\n return;\n }\n\n if (!response.data) {\n unsubscribe();\n await options.onError(new EditError(options.subscription, \"Subscription response did not contain data\"));\n return;\n }\n\n await onData(response.data);\n },\n });\n\n return unsubscribe;\n }\n\n /**\n * Close the client.\n */\n async dispose(): Promise<void> {\n await this.#client.dispose();\n }\n}\n"],"names":["unthunk","Client","EditError","Edit","query","variables","options","name","split","ctx","child","fields","edit","devFields","log","info","response","client","execute","operation","http","retry","methods","errors","data","mutate","mutation","subscribe","onData","subscription","unsubscribe","onResponse","onError","dispose","constructor"],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
+ import assert from "node:assert";
3
+ import pluralize from "pluralize";
4
+ import { CLIError, IsBug } from "../../output/report.js";
5
+ import { sprint } from "../../output/sprint.js";
6
+ import { uniq } from "../../util/collection.js";
7
+ import { isCloseEvent, isError, isErrorEvent, isGraphQLErrors, isString } from "../../util/is.js";
8
+ import { serializeError } from "../../util/object.js";
9
+ export class EditError extends CLIError {
10
+ render() {
11
+ let body = "";
12
+ switch(true){
13
+ case isGraphQLErrors(this.cause):
14
+ {
15
+ const errors = uniq(this.cause.map((x)=>x.message));
16
+ body = sprint`
17
+ Gadget responded with the following ${pluralize("error", errors.length, false)}:
18
+
19
+ • ${errors.join("\n • ")}
20
+ `;
21
+ break;
22
+ }
23
+ case isCloseEvent(this.cause):
24
+ body = "The connection to Gadget closed unexpectedly.";
25
+ break;
26
+ case isErrorEvent(this.cause) || isError(this.cause):
27
+ body = this.cause.message;
28
+ break;
29
+ default:
30
+ body = this.cause;
31
+ break;
32
+ }
33
+ return this.message + "\n\n" + body;
34
+ }
35
+ constructor(request, cause){
36
+ super("An error occurred while communicating with Gadget");
37
+ _define_property(this, "request", void 0);
38
+ _define_property(this, "isBug", void 0);
39
+ _define_property(this, "cause", void 0);
40
+ this.request = request;
41
+ this.isBug = IsBug.MAYBE;
42
+ // ErrorEvent and CloseEvent aren't serializable, so we reconstruct
43
+ // them into an object. We discard the `target` property because
44
+ // it's large and not that useful
45
+ if (isErrorEvent(cause)) {
46
+ this.cause = {
47
+ type: cause.type,
48
+ message: cause.message,
49
+ error: serializeError(cause.error)
50
+ };
51
+ } else if (isCloseEvent(cause)) {
52
+ this.cause = {
53
+ type: cause.type,
54
+ code: cause.code,
55
+ reason: cause.reason,
56
+ wasClean: cause.wasClean
57
+ };
58
+ } else {
59
+ assert(isString(cause) || isError(cause) || isGraphQLErrors(cause), "cause must be a string, Error, GraphQLError[], CloseEvent, or ErrorEvent");
60
+ this.cause = cause;
61
+ }
62
+ }
63
+ }
64
+
65
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/services/app/edit/error.ts"],"sourcesContent":["import type { GraphQLError } from \"graphql\";\nimport assert from \"node:assert\";\nimport pluralize from \"pluralize\";\nimport type { CloseEvent, ErrorEvent } from \"ws\";\nimport { CLIError, IsBug } from \"../../output/report.js\";\nimport { sprint } from \"../../output/sprint.js\";\nimport { uniq } from \"../../util/collection.js\";\nimport { isCloseEvent, isError, isErrorEvent, isGraphQLErrors, isString } from \"../../util/is.js\";\nimport { serializeError } from \"../../util/object.js\";\nimport type { GraphQLMutation, GraphQLQuery, GraphQLSubscription } from \"./operation.js\";\n\nexport class EditError extends CLIError {\n isBug = IsBug.MAYBE;\n\n override cause: string | Error | readonly GraphQLError[] | CloseEvent | ErrorEvent;\n\n constructor(\n readonly request: GraphQLQuery | GraphQLMutation | GraphQLSubscription,\n cause: unknown,\n ) {\n super(\"An error occurred while communicating with Gadget\");\n\n // ErrorEvent and CloseEvent aren't serializable, so we reconstruct\n // them into an object. We discard the `target` property because\n // it's large and not that useful\n if (isErrorEvent(cause)) {\n this.cause = {\n type: cause.type,\n message: cause.message,\n error: serializeError(cause.error),\n } as ErrorEvent;\n } else if (isCloseEvent(cause)) {\n this.cause = {\n type: cause.type,\n code: cause.code,\n reason: cause.reason,\n wasClean: cause.wasClean,\n } as CloseEvent;\n } else {\n assert(\n isString(cause) || isError(cause) || isGraphQLErrors(cause),\n \"cause must be a string, Error, GraphQLError[], CloseEvent, or ErrorEvent\",\n );\n this.cause = cause;\n }\n }\n\n override render(): string {\n let body = \"\";\n\n switch (true) {\n case isGraphQLErrors(this.cause): {\n const errors = uniq(this.cause.map((x) => x.message));\n body = sprint`\n Gadget responded with the following ${pluralize(\"error\", errors.length, false)}:\n\n • ${errors.join(\"\\n • \")}\n `;\n break;\n }\n case isCloseEvent(this.cause):\n body = \"The connection to Gadget closed unexpectedly.\";\n break;\n case isErrorEvent(this.cause) || isError(this.cause):\n body = this.cause.message;\n break;\n default:\n body = this.cause;\n break;\n }\n\n return this.message + \"\\n\\n\" + body;\n }\n}\n"],"names":["assert","pluralize","CLIError","IsBug","sprint","uniq","isCloseEvent","isError","isErrorEvent","isGraphQLErrors","isString","serializeError","EditError","render","body","cause","errors","map","x","message","length","join","constructor","request","isBug","MAYBE","type","error","code","reason","wasClean"],"mappings":";AACA,OAAOA,YAAY,cAAc;AACjC,OAAOC,eAAe,YAAY;AAElC,SAASC,QAAQ,EAAEC,KAAK,QAAQ,yBAAyB;AACzD,SAASC,MAAM,QAAQ,yBAAyB;AAChD,SAASC,IAAI,QAAQ,2BAA2B;AAChD,SAASC,YAAY,EAAEC,OAAO,EAAEC,YAAY,EAAEC,eAAe,EAAEC,QAAQ,QAAQ,mBAAmB;AAClG,SAASC,cAAc,QAAQ,uBAAuB;AAGtD,OAAO,MAAMC,kBAAkBV;IAoCpBW,SAAiB;QACxB,IAAIC,OAAO;QAEX,OAAQ;YACN,KAAKL,gBAAgB,IAAI,CAACM,KAAK;gBAAG;oBAChC,MAAMC,SAASX,KAAK,IAAI,CAACU,KAAK,CAACE,GAAG,CAAC,CAACC,IAAMA,EAAEC,OAAO;oBACnDL,OAAOV,MAAM,CAAC;8CACwB,EAAEH,UAAU,SAASe,OAAOI,MAAM,EAAE,OAAO;;cAE3E,EAAEJ,OAAOK,IAAI,CAAC,oBAAoB;QACxC,CAAC;oBACD;gBACF;YACA,KAAKf,aAAa,IAAI,CAACS,KAAK;gBAC1BD,OAAO;gBACP;YACF,KAAKN,aAAa,IAAI,CAACO,KAAK,KAAKR,QAAQ,IAAI,CAACQ,KAAK;gBACjDD,OAAO,IAAI,CAACC,KAAK,CAACI,OAAO;gBACzB;YACF;gBACEL,OAAO,IAAI,CAACC,KAAK;gBACjB;QACJ;QAEA,OAAO,IAAI,CAACI,OAAO,GAAG,SAASL;IACjC;IAxDAQ,YACE,AAASC,OAA6D,EACtER,KAAc,CACd;QACA,KAAK,CAAC;;QARRS,uBAAAA,SAAAA,KAAAA;QAEA,uBAAST,SAAT,KAAA;aAGWQ,UAAAA;aALXC,QAAQrB,MAAMsB,KAAK;QAUjB,mEAAmE;QACnE,gEAAgE;QAChE,iCAAiC;QACjC,IAAIjB,aAAaO,QAAQ;YACvB,IAAI,CAACA,KAAK,GAAG;gBACXW,MAAMX,MAAMW,IAAI;gBAChBP,SAASJ,MAAMI,OAAO;gBACtBQ,OAAOhB,eAAeI,MAAMY,KAAK;YACnC;QACF,OAAO,IAAIrB,aAAaS,QAAQ;YAC9B,IAAI,CAACA,KAAK,GAAG;gBACXW,MAAMX,MAAMW,IAAI;gBAChBE,MAAMb,MAAMa,IAAI;gBAChBC,QAAQd,MAAMc,MAAM;gBACpBC,UAAUf,MAAMe,QAAQ;YAC1B;QACF,OAAO;YACL9B,OACEU,SAASK,UAAUR,QAAQQ,UAAUN,gBAAgBM,QACrD;YAEF,IAAI,CAACA,KAAK,GAAGA;QACf;IACF;AA4BF"}
@@ -0,0 +1,87 @@
1
+ import { sprint } from "../../output/sprint.js";
2
+ export const REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = sprint(/* GraphQL */ `
3
+ subscription RemoteFileSyncEvents($localFilesVersion: String!) {
4
+ remoteFileSyncEvents(localFilesVersion: $localFilesVersion, encoding: base64) {
5
+ remoteFilesVersion
6
+ changed {
7
+ path
8
+ mode
9
+ content
10
+ encoding
11
+ }
12
+ deleted {
13
+ path
14
+ }
15
+ }
16
+ }
17
+ `);
18
+ export const REMOTE_FILES_VERSION_QUERY = sprint(/* GraphQL */ `
19
+ query RemoteFilesVersion {
20
+ remoteFilesVersion
21
+ }
22
+ `);
23
+ export const PUBLISH_FILE_SYNC_EVENTS_MUTATION = sprint(/* GraphQL */ `
24
+ mutation PublishFileSyncEvents($input: PublishFileSyncEventsInput!) {
25
+ publishFileSyncEvents(input: $input) {
26
+ remoteFilesVersion
27
+ }
28
+ }
29
+ `);
30
+ export const FILE_SYNC_FILES_QUERY = sprint(/* GraphQL */ `
31
+ query FileSyncFiles($paths: [String!]!, $filesVersion: String, $encoding: FileSyncEncoding) {
32
+ fileSyncFiles(paths: $paths, filesVersion: $filesVersion, encoding: $encoding) {
33
+ filesVersion
34
+ files {
35
+ path
36
+ mode
37
+ content
38
+ encoding
39
+ }
40
+ }
41
+ }
42
+ `);
43
+ export const FILE_SYNC_HASHES_QUERY = sprint(/* GraphQL */ `
44
+ query FileSyncHashes($filesVersion: String) {
45
+ fileSyncHashes(filesVersion: $filesVersion) {
46
+ filesVersion
47
+ hashes
48
+ }
49
+ }
50
+ `);
51
+ export const FILE_SYNC_COMPARISON_HASHES_QUERY = sprint(/* GraphQL */ `
52
+ query FileSyncComparisonHashes($filesVersion: String!) {
53
+ fileSyncComparisonHashes(filesVersion: $filesVersion) {
54
+ filesVersionHashes {
55
+ filesVersion
56
+ hashes
57
+ }
58
+ latestFilesVersionHashes {
59
+ filesVersion
60
+ hashes
61
+ }
62
+ }
63
+ }
64
+ `);
65
+ export const REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = sprint(/* GraphQL */ `
66
+ subscription publishStatus($localFilesVersion: String!, $force: Boolean) {
67
+ publishStatus(localFilesVersion: $localFilesVersion, force: $force) {
68
+ remoteFilesVersion
69
+ progress
70
+ issues {
71
+ severity
72
+ message
73
+ node {
74
+ type
75
+ key
76
+ apiIdentifier
77
+ name
78
+ fieldType
79
+ parentKey
80
+ parentApiIdentifier
81
+ }
82
+ }
83
+ }
84
+ }
85
+ `);
86
+
87
+ //# sourceMappingURL=operation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/services/app/edit/operation.ts"],"sourcesContent":["import type { ExecutionResult } from \"graphql-ws\";\nimport type { JsonObject } from \"type-fest\";\nimport type {\n FileSyncComparisonHashesQuery,\n FileSyncComparisonHashesQueryVariables,\n FileSyncFilesQuery,\n FileSyncFilesQueryVariables,\n FileSyncHashesQuery,\n FileSyncHashesQueryVariables,\n PublishFileSyncEventsMutation,\n PublishFileSyncEventsMutationVariables,\n PublishStatusSubscription,\n PublishStatusSubscriptionVariables,\n RemoteFileSyncEventsSubscription,\n RemoteFileSyncEventsSubscriptionVariables,\n RemoteFilesVersionQuery,\n RemoteFilesVersionQueryVariables,\n} from \"../../../__generated__/graphql.js\";\nimport { sprint } from \"../../output/sprint.js\";\n\n/**\n * A GraphQL query with its associated types.\n *\n * At runtime, this is just a string.\n */\nexport type GraphQLQuery<\n Data extends JsonObject = JsonObject,\n Variables extends JsonObject = JsonObject,\n Extensions extends JsonObject = JsonObject,\n Response extends ExecutionResult<Data, Extensions> = ExecutionResult<Data, Extensions>,\n> = string & {\n type: \"query\";\n Data: Data;\n Variables: Variables;\n Extensions: Extensions;\n Response: Response;\n};\n\n/**\n * A GraphQL mutation with its associated types.\n *\n * At runtime, this is just a string.\n */\nexport type GraphQLMutation<\n Data extends JsonObject = JsonObject,\n Variables extends JsonObject = JsonObject,\n Extensions extends JsonObject = JsonObject,\n Response extends ExecutionResult<Data, Extensions> = ExecutionResult<Data, Extensions>,\n> = string & {\n type: \"mutation\";\n Data: Data;\n Variables: Variables;\n Extensions: Extensions;\n Response: Response;\n};\n\n/**\n * A GraphQL subscription with its associated types.\n *\n * At runtime, this is just a string.\n */\nexport type GraphQLSubscription<\n Data extends JsonObject = JsonObject,\n Variables extends JsonObject = JsonObject,\n Extensions extends JsonObject = JsonObject,\n Response extends ExecutionResult<Data, Extensions> = ExecutionResult<Data, Extensions>,\n> = string & {\n type: \"subscription\";\n Data: Data;\n Variables: Variables;\n Extensions: Extensions;\n Response: Response;\n};\n\nexport const REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = sprint(/* GraphQL */ `\n subscription RemoteFileSyncEvents($localFilesVersion: String!) {\n remoteFileSyncEvents(localFilesVersion: $localFilesVersion, encoding: base64) {\n remoteFilesVersion\n changed {\n path\n mode\n content\n encoding\n }\n deleted {\n path\n }\n }\n }\n`) as GraphQLSubscription<RemoteFileSyncEventsSubscription, RemoteFileSyncEventsSubscriptionVariables>;\n\nexport type REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION = typeof REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION;\n\nexport const REMOTE_FILES_VERSION_QUERY = sprint(/* GraphQL */ `\n query RemoteFilesVersion {\n remoteFilesVersion\n }\n`) as GraphQLQuery<RemoteFilesVersionQuery, RemoteFilesVersionQueryVariables>;\n\nexport type REMOTE_FILES_VERSION_QUERY = typeof REMOTE_FILES_VERSION_QUERY;\n\nexport const PUBLISH_FILE_SYNC_EVENTS_MUTATION = sprint(/* GraphQL */ `\n mutation PublishFileSyncEvents($input: PublishFileSyncEventsInput!) {\n publishFileSyncEvents(input: $input) {\n remoteFilesVersion\n }\n }\n`) as GraphQLMutation<PublishFileSyncEventsMutation, PublishFileSyncEventsMutationVariables>;\n\nexport type PUBLISH_FILE_SYNC_EVENTS_MUTATION = typeof PUBLISH_FILE_SYNC_EVENTS_MUTATION;\n\nexport const FILE_SYNC_FILES_QUERY = sprint(/* GraphQL */ `\n query FileSyncFiles($paths: [String!]!, $filesVersion: String, $encoding: FileSyncEncoding) {\n fileSyncFiles(paths: $paths, filesVersion: $filesVersion, encoding: $encoding) {\n filesVersion\n files {\n path\n mode\n content\n encoding\n }\n }\n }\n`) as GraphQLQuery<FileSyncFilesQuery, FileSyncFilesQueryVariables>;\n\nexport type FILE_SYNC_FILES_QUERY = typeof FILE_SYNC_FILES_QUERY;\n\nexport const FILE_SYNC_HASHES_QUERY = sprint(/* GraphQL */ `\n query FileSyncHashes($filesVersion: String) {\n fileSyncHashes(filesVersion: $filesVersion) {\n filesVersion\n hashes\n }\n }\n`) as GraphQLQuery<FileSyncHashesQuery, FileSyncHashesQueryVariables>;\n\nexport type FILE_SYNC_HASHES_QUERY = typeof FILE_SYNC_HASHES_QUERY;\n\nexport const FILE_SYNC_COMPARISON_HASHES_QUERY = sprint(/* GraphQL */ `\n query FileSyncComparisonHashes($filesVersion: String!) {\n fileSyncComparisonHashes(filesVersion: $filesVersion) {\n filesVersionHashes {\n filesVersion\n hashes\n }\n latestFilesVersionHashes {\n filesVersion\n hashes\n }\n }\n }\n`) as GraphQLQuery<FileSyncComparisonHashesQuery, FileSyncComparisonHashesQueryVariables>;\n\nexport type FILE_SYNC_COMPARISON_HASHES_QUERY = typeof FILE_SYNC_COMPARISON_HASHES_QUERY;\n\nexport const REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = sprint(/* GraphQL */ `\n subscription publishStatus($localFilesVersion: String!, $force: Boolean) {\n publishStatus(localFilesVersion: $localFilesVersion, force: $force) {\n remoteFilesVersion\n progress\n issues {\n severity\n message\n node {\n type\n key\n apiIdentifier\n name\n fieldType\n parentKey\n parentApiIdentifier\n }\n }\n }\n }\n`) as GraphQLSubscription<PublishStatusSubscription, PublishStatusSubscriptionVariables>;\n\nexport type REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION = typeof REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION;\n"],"names":["sprint","REMOTE_FILE_SYNC_EVENTS_SUBSCRIPTION","REMOTE_FILES_VERSION_QUERY","PUBLISH_FILE_SYNC_EVENTS_MUTATION","FILE_SYNC_FILES_QUERY","FILE_SYNC_HASHES_QUERY","FILE_SYNC_COMPARISON_HASHES_QUERY","REMOTE_SERVER_CONTRACT_STATUS_SUBSCRIPTION"],"mappings":"AAkBA,SAASA,MAAM,QAAQ,yBAAyB;AAwDhD,OAAO,MAAMC,uCAAuCD,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;;;AAe1E,CAAC,EAAsG;AAIvG,OAAO,MAAME,6BAA6BF,OAAO,WAAW,GAAG,CAAC;;;;AAIhE,CAAC,EAA6E;AAI9E,OAAO,MAAMG,oCAAoCH,OAAO,WAAW,GAAG,CAAC;;;;;;AAMvE,CAAC,EAA4F;AAI7F,OAAO,MAAMI,wBAAwBJ,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;AAY3D,CAAC,EAAmE;AAIpE,OAAO,MAAMK,yBAAyBL,OAAO,WAAW,GAAG,CAAC;;;;;;;AAO5D,CAAC,EAAqE;AAItE,OAAO,MAAMM,oCAAoCN,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;AAavE,CAAC,EAAyF;AAI1F,OAAO,MAAMO,6CAA6CP,OAAO,WAAW,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;AAoBhF,CAAC,EAAwF"}
@@ -3,25 +3,25 @@ import arg from "arg";
3
3
  import { CLIError, IsBug, UnexpectedError } from "../output/report.js";
4
4
  import { isNil } from "../util/is.js";
5
5
  export const parseArgs = (args, options)=>{
6
- const realSpec = {};
6
+ const spec = {};
7
7
  const defaultValues = {};
8
8
  for (const [key, value] of Object.entries(args)){
9
9
  if (!("type" in value)) {
10
- realSpec[key] = value;
10
+ spec[key] = value;
11
11
  continue;
12
12
  }
13
- realSpec[key] = value.type;
13
+ spec[key] = value.type;
14
14
  defaultValues[key] = value.default;
15
15
  if (value.alias) {
16
16
  for (const alias of Array.isArray(value.alias) ? value.alias : [
17
17
  value.alias
18
18
  ]){
19
- realSpec[alias] = key;
19
+ spec[alias] = key;
20
20
  }
21
21
  }
22
22
  }
23
23
  try {
24
- const parsed = arg(realSpec, options);
24
+ const parsed = arg(spec, options);
25
25
  for (const [key, value] of Object.entries(defaultValues)){
26
26
  if (isNil(parsed[key])) {
27
27
  parsed[key] = value;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/command/arg.ts"],"sourcesContent":["import arg from \"arg\";\nimport type { Simplify } from \"type-fest\";\nimport { CLIError, IsBug, UnexpectedError } from \"../output/report.js\";\nimport { isNil } from \"../util/is.js\";\n\nexport type ArgsSpec = Record<string, ArgDefinition>;\n\ntype ArgDefinition<Handler extends arg.Handler = arg.Handler> =\n | Handler\n | {\n type: Handler;\n alias?: string | string[];\n default?: ReturnType<Handler>;\n };\n\nexport const parseArgs = <Args extends ArgsSpec>(args: Args, options?: arg.Options): ArgsSpecResult<Args> => {\n const realSpec: arg.Spec = {};\n const defaultValues: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(args)) {\n if (!(\"type\" in value)) {\n realSpec[key] = value;\n continue;\n }\n\n realSpec[key] = value.type;\n defaultValues[key] = value.default;\n\n if (value.alias) {\n for (const alias of Array.isArray(value.alias) ? value.alias : [value.alias]) {\n realSpec[alias] = key;\n }\n }\n }\n\n try {\n const parsed = arg(realSpec, options);\n for (const [key, value] of Object.entries(defaultValues)) {\n if (isNil(parsed[key])) {\n parsed[key] = value as never;\n }\n }\n return parsed as ArgsSpecResult<Args>;\n } catch (error: unknown) {\n if (error instanceof arg.ArgError) {\n // convert arg.ArgError to CLIError\n // eslint-disable-next-line no-ex-assign\n error = new ArgError(error.message);\n }\n if (error instanceof CLIError) {\n throw error;\n }\n throw new UnexpectedError(error);\n }\n};\n\nexport class ArgError extends CLIError {\n isBug = IsBug.NO;\n\n protected override render(): string {\n return this.message;\n }\n}\n\nexport type ArgsSpecResult<Spec extends ArgsSpec, Args extends keyof Spec = keyof Spec> = Simplify<{\n [Arg in Args]: Spec[Arg] extends ArgDefinition<infer Handler>\n ? Spec[Arg] extends { default: unknown }\n ? NonNullable<ReturnType<Handler>>\n : ReturnType<Handler> | undefined\n : never;\n}> & { _: string[] };\n"],"names":["arg","CLIError","IsBug","UnexpectedError","isNil","parseArgs","args","options","realSpec","defaultValues","key","value","Object","entries","type","default","alias","Array","isArray","parsed","error","ArgError","message","render","isBug","NO"],"mappings":";AAAA,OAAOA,SAAS,MAAM;AAEtB,SAASC,QAAQ,EAAEC,KAAK,EAAEC,eAAe,QAAQ,sBAAsB;AACvE,SAASC,KAAK,QAAQ,gBAAgB;AAYtC,OAAO,MAAMC,YAAY,CAAwBC,MAAYC;IAC3D,MAAMC,WAAqB,CAAC;IAC5B,MAAMC,gBAAyC,CAAC;IAEhD,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACP,MAAO;QAC/C,IAAI,CAAE,CAAA,UAAUK,KAAI,GAAI;YACtBH,QAAQ,CAACE,IAAI,GAAGC;YAChB;QACF;QAEAH,QAAQ,CAACE,IAAI,GAAGC,MAAMG,IAAI;QAC1BL,aAAa,CAACC,IAAI,GAAGC,MAAMI,OAAO;QAElC,IAAIJ,MAAMK,KAAK,EAAE;YACf,KAAK,MAAMA,SAASC,MAAMC,OAAO,CAACP,MAAMK,KAAK,IAAIL,MAAMK,KAAK,GAAG;gBAACL,MAAMK,KAAK;aAAC,CAAE;gBAC5ER,QAAQ,CAACQ,MAAM,GAAGN;YACpB;QACF;IACF;IAEA,IAAI;QACF,MAAMS,SAASnB,IAAIQ,UAAUD;QAC7B,KAAK,MAAM,CAACG,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACJ,eAAgB;YACxD,IAAIL,MAAMe,MAAM,CAACT,IAAI,GAAG;gBACtBS,MAAM,CAACT,IAAI,GAAGC;YAChB;QACF;QACA,OAAOQ;IACT,EAAE,OAAOC,OAAgB;QACvB,IAAIA,iBAAiBpB,IAAIqB,QAAQ,EAAE;YACjC,mCAAmC;YACnC,wCAAwC;YACxCD,QAAQ,IAAIC,SAASD,MAAME,OAAO;QACpC;QACA,IAAIF,iBAAiBnB,UAAU;YAC7B,MAAMmB;QACR;QACA,MAAM,IAAIjB,gBAAgBiB;IAC5B;AACF,EAAE;AAEF,OAAO,MAAMC,iBAAiBpB;IAGTsB,SAAiB;QAClC,OAAO,IAAI,CAACD,OAAO;IACrB;;;QAJAE,uBAAAA,SAAQtB,MAAMuB,EAAE;;AAKlB"}
1
+ {"version":3,"sources":["../../../src/services/command/arg.ts"],"sourcesContent":["import arg from \"arg\";\nimport type { Simplify } from \"type-fest\";\nimport { CLIError, IsBug, UnexpectedError } from \"../output/report.js\";\nimport { isNil } from \"../util/is.js\";\n\nexport type ArgsDefinition = Record<string, ArgDefinition>;\n\ntype ArgDefinition<Handler extends arg.Handler = arg.Handler> =\n | Handler\n | {\n type: Handler;\n alias?: string | string[];\n default?: ReturnType<Handler>;\n };\n\nexport type ParseArgsOptions = {\n /**\n * A list of arguments to parse.\n */\n argv?: string[];\n\n /**\n * When permissive set to `true`, arg will push any unknown arguments\n * onto the \"extra\" argument array (`ctx.args._`) instead of throwing\n * an error about an unknown flag.\n *\n * @default false\n */\n permissive?: boolean;\n\n /**\n * When stopAtPositional is set to true, context will stop parsing at\n * the first positional argument.\n *\n * @default false\n */\n stopAtPositional?: boolean;\n};\n\nexport const parseArgs = <Args extends ArgsDefinition>(args: Args, options?: arg.Options): ArgsDefinitionResult<Args> => {\n const spec: arg.Spec = {};\n const defaultValues: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(args)) {\n if (!(\"type\" in value)) {\n spec[key] = value;\n continue;\n }\n\n spec[key] = value.type;\n defaultValues[key] = value.default;\n\n if (value.alias) {\n for (const alias of Array.isArray(value.alias) ? value.alias : [value.alias]) {\n spec[alias] = key;\n }\n }\n }\n\n try {\n const parsed = arg(spec, options);\n for (const [key, value] of Object.entries(defaultValues)) {\n if (isNil(parsed[key])) {\n parsed[key] = value as never;\n }\n }\n return parsed as ArgsDefinitionResult<Args>;\n } catch (error: unknown) {\n if (error instanceof arg.ArgError) {\n // convert arg.ArgError to CLIError\n // eslint-disable-next-line no-ex-assign\n error = new ArgError(error.message);\n }\n if (error instanceof CLIError) {\n throw error;\n }\n throw new UnexpectedError(error);\n }\n};\n\nexport class ArgError extends CLIError {\n isBug = IsBug.NO;\n\n protected override render(): string {\n return this.message;\n }\n}\n\n/**\n * Turns this:\n * ```ts\n * type Args = {\n * \"--string\": { type: String; alias: \"s\" };\n * \"--number\": { type: Number; default: 42 };\n * };\n * ```\n *\n * Into this:\n * ```ts\n * type Result = {\n * \"--string\": string | undefined;\n * \"--number\": number;\n * };\n * ```\n */\nexport type ArgsDefinitionResult<Args extends ArgsDefinition, Keys extends keyof Args = keyof Args> = Simplify<{\n [Key in Keys]: Args[Key] extends ArgDefinition<infer Handler>\n ? Args[Key] extends { default: unknown }\n ? NonNullable<ReturnType<Handler>>\n : ReturnType<Handler> | undefined\n : never;\n}> & { _: string[] };\n"],"names":["arg","CLIError","IsBug","UnexpectedError","isNil","parseArgs","args","options","spec","defaultValues","key","value","Object","entries","type","default","alias","Array","isArray","parsed","error","ArgError","message","render","isBug","NO"],"mappings":";AAAA,OAAOA,SAAS,MAAM;AAEtB,SAASC,QAAQ,EAAEC,KAAK,EAAEC,eAAe,QAAQ,sBAAsB;AACvE,SAASC,KAAK,QAAQ,gBAAgB;AAoCtC,OAAO,MAAMC,YAAY,CAA8BC,MAAYC;IACjE,MAAMC,OAAiB,CAAC;IACxB,MAAMC,gBAAyC,CAAC;IAEhD,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACP,MAAO;QAC/C,IAAI,CAAE,CAAA,UAAUK,KAAI,GAAI;YACtBH,IAAI,CAACE,IAAI,GAAGC;YACZ;QACF;QAEAH,IAAI,CAACE,IAAI,GAAGC,MAAMG,IAAI;QACtBL,aAAa,CAACC,IAAI,GAAGC,MAAMI,OAAO;QAElC,IAAIJ,MAAMK,KAAK,EAAE;YACf,KAAK,MAAMA,SAASC,MAAMC,OAAO,CAACP,MAAMK,KAAK,IAAIL,MAAMK,KAAK,GAAG;gBAACL,MAAMK,KAAK;aAAC,CAAE;gBAC5ER,IAAI,CAACQ,MAAM,GAAGN;YAChB;QACF;IACF;IAEA,IAAI;QACF,MAAMS,SAASnB,IAAIQ,MAAMD;QACzB,KAAK,MAAM,CAACG,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACJ,eAAgB;YACxD,IAAIL,MAAMe,MAAM,CAACT,IAAI,GAAG;gBACtBS,MAAM,CAACT,IAAI,GAAGC;YAChB;QACF;QACA,OAAOQ;IACT,EAAE,OAAOC,OAAgB;QACvB,IAAIA,iBAAiBpB,IAAIqB,QAAQ,EAAE;YACjC,mCAAmC;YACnC,wCAAwC;YACxCD,QAAQ,IAAIC,SAASD,MAAME,OAAO;QACpC;QACA,IAAIF,iBAAiBnB,UAAU;YAC7B,MAAMmB;QACR;QACA,MAAM,IAAIjB,gBAAgBiB;IAC5B;AACF,EAAE;AAEF,OAAO,MAAMC,iBAAiBpB;IAGTsB,SAAiB;QAClC,OAAO,IAAI,CAACD,OAAO;IACrB;;;QAJAE,uBAAAA,SAAQtB,MAAMuB,EAAE;;AAKlB"}
@@ -1,8 +1,12 @@
1
- /* eslint-disable @typescript-eslint/consistent-type-imports */ import assert from "node:assert";
1
+ import assert from "node:assert";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import { config } from "../config/config.js";
4
4
  import { relativeToThisFile } from "../util/paths.js";
5
- export const AvailableCommands = [
5
+ /**
6
+ * The list of available commands.
7
+ * - Each command is a separate file in src/commands.
8
+ * - The order determines the order of commands in the README.
9
+ */ export const Commands = [
6
10
  "sync",
7
11
  "list",
8
12
  "login",
@@ -10,14 +14,24 @@ export const AvailableCommands = [
10
14
  "whoami",
11
15
  "version"
12
16
  ];
13
- // temporarily remove deploy command from available commands while we're working on it
17
+ // deploy is still in preview
14
18
  if (process.env["GGT_DEPLOY_PREVIEW"]) {
15
- AvailableCommands.push("deploy");
19
+ Commands.push("deploy");
16
20
  }
17
- export const isAvailableCommand = (command)=>{
18
- return AvailableCommands.includes(command);
21
+ /**
22
+ * Checks if a string is a valid command.
23
+ *
24
+ * @param command - The string to check
25
+ * @returns Whether the string is a valid command
26
+ */ export const isAvailableCommand = (command)=>{
27
+ return Commands.includes(command);
19
28
  };
20
- export const importCommand = async (cmd)=>{
29
+ /**
30
+ * Imports a command module.
31
+ *
32
+ * @param cmd - The command to import
33
+ * @see {@linkcode CommandModule}
34
+ */ export const importCommand = async (cmd)=>{
21
35
  assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);
22
36
  let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);
23
37
  if (config.windows) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/command/command.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/consistent-type-imports */\nimport assert from \"node:assert\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Promisable } from \"type-fest\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { config } from \"../config/config.js\";\nimport { relativeToThisFile } from \"../util/paths.js\";\nimport type { ArgsSpec } from \"./arg.js\";\nimport type { Context } from \"./context.js\";\n\nexport const AvailableCommands = [\"sync\", \"list\", \"login\", \"logout\", \"whoami\", \"version\"] as const;\n\n// temporarily remove deploy command from available commands while we're working on it\nif (process.env[\"GGT_DEPLOY_PREVIEW\"]) {\n (AvailableCommands as unknown as string[]).push(\"deploy\");\n}\n\nexport type AvailableCommand = (typeof AvailableCommands)[number];\n\nexport const isAvailableCommand = (command: string): command is AvailableCommand => {\n return AvailableCommands.includes(command as AvailableCommand);\n};\n\nexport const importCommand = async (cmd: AvailableCommand): Promise<CommandSpec> => {\n assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);\n let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);\n if (config.windows) {\n // https://github.com/nodejs/node/issues/31710\n commandPath = pathToFileURL(commandPath).toString();\n }\n return (await import(commandPath)) as CommandSpec;\n};\n\nexport type CommandSpec<Args extends ArgsSpec = ArgsSpec, ParentArgsSpec extends ArgsSpec = typeof rootArgs> = {\n args?: Args;\n usage: () => string;\n command: (ctx: Context<Args, ParentArgsSpec>) => Promisable<void>;\n};\n\nexport type Command<Spec extends ArgsSpec = ArgsSpec, ParentSpec extends ArgsSpec = typeof rootArgs> = CommandSpec<\n Spec,\n ParentSpec\n>[\"command\"];\n\nexport type Usage = CommandSpec[\"usage\"];\n"],"names":["assert","pathToFileURL","config","relativeToThisFile","AvailableCommands","process","env","push","isAvailableCommand","command","includes","importCommand","cmd","commandPath","windows","toString"],"mappings":"AAAA,6DAA6D,GAC7D,OAAOA,YAAY,cAAc;AACjC,SAASC,aAAa,QAAQ,WAAW;AAGzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,kBAAkB,QAAQ,mBAAmB;AAItD,OAAO,MAAMC,oBAAoB;IAAC;IAAQ;IAAQ;IAAS;IAAU;IAAU;CAAU,CAAU;AAEnG,sFAAsF;AACtF,IAAIC,QAAQC,GAAG,CAAC,qBAAqB,EAAE;IACpCF,kBAA0CG,IAAI,CAAC;AAClD;AAIA,OAAO,MAAMC,qBAAqB,CAACC;IACjC,OAAOL,kBAAkBM,QAAQ,CAACD;AACpC,EAAE;AAEF,OAAO,MAAME,gBAAgB,OAAOC;IAClCZ,OAAOQ,mBAAmBI,MAAM,CAAC,iBAAiB,EAAEA,IAAI,CAAC;IACzD,IAAIC,cAAcV,mBAAmB,CAAC,eAAe,EAAES,IAAI,GAAG,CAAC;IAC/D,IAAIV,OAAOY,OAAO,EAAE;QAClB,8CAA8C;QAC9CD,cAAcZ,cAAcY,aAAaE,QAAQ;IACnD;IACA,OAAQ,MAAM,MAAM,CAACF;AACvB,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/command/command.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { pathToFileURL } from \"node:url\";\nimport type { EmptyObject, Promisable } from \"type-fest\";\nimport type { RootArgs } from \"../../commands/root.js\";\nimport { config } from \"../config/config.js\";\nimport { relativeToThisFile } from \"../util/paths.js\";\nimport type { ArgsDefinition } from \"./arg.js\";\nimport type { Context } from \"./context.js\";\n\n/**\n * The list of available commands.\n * - Each command is a separate file in src/commands.\n * - The order determines the order of commands in the README.\n */\nexport const Commands = [\"sync\", \"list\", \"login\", \"logout\", \"whoami\", \"version\"] as const;\n\n// deploy is still in preview\nif (process.env[\"GGT_DEPLOY_PREVIEW\"]) {\n (Commands as unknown as string[]).push(\"deploy\");\n}\n\n/**\n * One of the commands in {@link Commands}.\n */\nexport type AvailableCommand = (typeof Commands)[number];\n\n/**\n * Checks if a string is a valid command.\n *\n * @param command - The string to check\n * @returns Whether the string is a valid command\n */\nexport const isAvailableCommand = (command: string): command is AvailableCommand => {\n return Commands.includes(command as AvailableCommand);\n};\n\n/**\n * A command module is a file in the src/commands directory.\n */\nexport type CommandModule<Args extends ArgsDefinition = EmptyObject, ParentArgs extends ArgsDefinition = RootArgs> = {\n /**\n * The command's {@link ArgsDefinition}.\n */\n args?: Args;\n\n /**\n * The command's {@link Usage}.\n */\n usage: Usage;\n\n /**\n * The command's {@link Command}.\n */\n command: Command<Args, ParentArgs>;\n};\n\n/**\n * A command's usage is a string that describes how to use the command.\n */\nexport type Usage = () => string;\n\n/**\n * The function that is run when the command is invoked.\n *\n * @param ctx - A {@linkcode Context} with the command's {@linkcode Args} and {@linkcode ParentArgs}.\n */\nexport type Command<Args extends ArgsDefinition = EmptyObject, ParentArgs extends ArgsDefinition = RootArgs> = (\n ctx: Context<Args, ParentArgs>,\n) => Promisable<void>;\n\n/**\n * Imports a command module.\n *\n * @param cmd - The command to import\n * @see {@linkcode CommandModule}\n */\nexport const importCommand = async (cmd: AvailableCommand): Promise<CommandModule> => {\n assert(isAvailableCommand(cmd), `invalid command: ${cmd}`);\n let commandPath = relativeToThisFile(`../../commands/${cmd}.js`);\n if (config.windows) {\n // https://github.com/nodejs/node/issues/31710\n commandPath = pathToFileURL(commandPath).toString();\n }\n return (await import(commandPath)) as CommandModule;\n};\n"],"names":["assert","pathToFileURL","config","relativeToThisFile","Commands","process","env","push","isAvailableCommand","command","includes","importCommand","cmd","commandPath","windows","toString"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,SAASC,aAAa,QAAQ,WAAW;AAGzC,SAASC,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,kBAAkB,QAAQ,mBAAmB;AAItD;;;;CAIC,GACD,OAAO,MAAMC,WAAW;IAAC;IAAQ;IAAQ;IAAS;IAAU;IAAU;CAAU,CAAU;AAE1F,6BAA6B;AAC7B,IAAIC,QAAQC,GAAG,CAAC,qBAAqB,EAAE;IACpCF,SAAiCG,IAAI,CAAC;AACzC;AAOA;;;;;CAKC,GACD,OAAO,MAAMC,qBAAqB,CAACC;IACjC,OAAOL,SAASM,QAAQ,CAACD;AAC3B,EAAE;AAoCF;;;;;CAKC,GACD,OAAO,MAAME,gBAAgB,OAAOC;IAClCZ,OAAOQ,mBAAmBI,MAAM,CAAC,iBAAiB,EAAEA,IAAI,CAAC;IACzD,IAAIC,cAAcV,mBAAmB,CAAC,eAAe,EAAES,IAAI,GAAG,CAAC;IAC/D,IAAIV,OAAOY,OAAO,EAAE;QAClB,8CAA8C;QAC9CD,cAAcZ,cAAcY,aAAaE,QAAQ;IACnD;IACA,OAAQ,MAAM,MAAM,CAACF;AACvB,EAAE"}
@@ -1,63 +1,105 @@
1
+ import { _ as _class_private_field_get } from "@swc/helpers/_/_class_private_field_get";
2
+ import { _ as _class_private_field_init } from "@swc/helpers/_/_class_private_field_init";
3
+ import { _ as _class_private_field_set } from "@swc/helpers/_/_class_private_field_set";
1
4
  import { _ as _define_property } from "@swc/helpers/_/_define_property";
2
5
  import assert from "node:assert";
3
6
  import { createLogger } from "../output/log/logger.js";
4
- import { isFunction } from "../util/is.js";
7
+ import { defaults, pick } from "../util/object.js";
5
8
  import { parseArgs } from "./arg.js";
9
+ var _log = /*#__PURE__*/ new WeakMap(), _parent = /*#__PURE__*/ new WeakMap(), _user = /*#__PURE__*/ new WeakMap(), _app = /*#__PURE__*/ new WeakMap();
6
10
  /**
7
11
  * Represents the context of a command-line operation.
8
12
  */ export class Context extends AbortController {
9
13
  /**
14
+ * A {@linkcode Logger} that can print to stdout and log structured
15
+ * messages to stderr.
16
+ */ get log() {
17
+ return _class_private_field_get(this, _log);
18
+ }
19
+ get user() {
20
+ return _class_private_field_get(this, _user) ?? _class_private_field_get(this, _parent)?.user;
21
+ }
22
+ set user(user) {
23
+ _class_private_field_set(this, _user, user);
24
+ if (_class_private_field_get(this, _parent)) {
25
+ _class_private_field_get(this, _parent).user = user;
26
+ }
27
+ _class_private_field_set(this, _log, _class_private_field_get(this, _log).child({
28
+ fields: {
29
+ user: pick(user, [
30
+ "id",
31
+ "name",
32
+ "email"
33
+ ])
34
+ }
35
+ }));
36
+ }
37
+ // eslint-disable-next-line @typescript-eslint/member-ordering
38
+ get app() {
39
+ return _class_private_field_get(this, _app) ?? _class_private_field_get(this, _parent)?.app;
40
+ }
41
+ set app(app) {
42
+ _class_private_field_set(this, _app, app);
43
+ if (_class_private_field_get(this, _parent)) {
44
+ _class_private_field_get(this, _parent).app = app;
45
+ }
46
+ _class_private_field_set(this, _log, _class_private_field_get(this, _log).child({
47
+ fields: {
48
+ app
49
+ }
50
+ }));
51
+ }
52
+ /**
10
53
  * Initializes a new context.
11
- */ static init({ args: spec, name, ...options }) {
12
- const args = parseArgs(spec, options);
54
+ *
55
+ * @see {@linkcode ContextInit}
56
+ */ static init({ parse: spec, ...options }) {
13
57
  return new Context({
14
- args,
15
- name
58
+ args: spec ? parseArgs(spec, pick(options, [
59
+ "argv",
60
+ "permissive",
61
+ "stopAtPositional"
62
+ ])) : {},
63
+ log: createLogger(pick(options, [
64
+ "name",
65
+ "fields",
66
+ "devFields"
67
+ ]))
16
68
  });
17
69
  }
18
70
  /**
19
- * Extends the current context with more arguments.
20
- */ extend({ args: spec, name, ...options }) {
21
- const args = {
22
- ...this.args,
23
- ...parseArgs(spec, {
24
- argv: this.args._,
25
- ...options
26
- })
27
- };
28
- const ctx = new Context({
29
- args,
30
- name
31
- });
32
- this.onAbort(()=>ctx.abort());
33
- return ctx;
34
- }
35
- /**
36
- * Clones the current context and optionally overrides its name and
37
- * arguments.
38
- */ clone({ args, name }) {
71
+ * Returns a new context that is a child of the current context.
72
+ *
73
+ * @see {@linkcode ChildContextInit}
74
+ */ child({ parse: spec, ...options }) {
39
75
  const ctx = new Context({
76
+ parent: this,
40
77
  args: {
41
- ...args,
42
- ...this.args
78
+ ...this.args,
79
+ ...options.overwrite,
80
+ ...spec ? parseArgs(spec, defaults(pick(options, [
81
+ "argv",
82
+ "permissive",
83
+ "stopAtPositional"
84
+ ]), {
85
+ argv: this.args._
86
+ })) : {}
43
87
  },
44
- name
88
+ log: this.log.child(pick(options, [
89
+ "name",
90
+ "fields",
91
+ "devFields"
92
+ ]))
45
93
  });
46
94
  this.onAbort(()=>ctx.abort());
47
95
  return ctx;
48
96
  }
49
- onAbort(callbackOrOptions, callback) {
50
- let options = {
51
- once: true
52
- };
53
- if (isFunction(callbackOrOptions)) {
54
- callback = callbackOrOptions;
55
- } else {
56
- options = {
57
- ...options,
58
- ...callbackOrOptions
59
- };
60
- }
97
+ /**
98
+ * Registers a callback that will be called when the context is
99
+ * aborted (e.g. when the user presses Ctrl+C).
100
+ *
101
+ * @param callback - The callback to call when the context is aborted.
102
+ */ onAbort(callback) {
61
103
  this.signal.addEventListener("abort", // eslint-disable-next-line @typescript-eslint/no-misused-promises
62
104
  async ()=>{
63
105
  try {
@@ -68,27 +110,37 @@ import { parseArgs } from "./arg.js";
68
110
  error
69
111
  });
70
112
  }
71
- }, options);
113
+ });
72
114
  }
73
- constructor({ args, name = "context" }){
115
+ constructor({ args, log, parent }){
74
116
  super();
75
117
  /**
76
- * The parsed command-line arguments for the current command and
77
- * any parent commands.
118
+ * The parsed command-line arguments for the current context and any
119
+ * parent contexts.
78
120
  */ _define_property(this, "args", void 0);
79
- /**
80
- * A logger instance that can be used to log messages.
81
- *
82
- * This logger's name is set the name of the command that is being
83
- * executed.
84
- */ _define_property(this, "log", void 0);
85
- this.args = args;
86
- this.log = createLogger({
87
- name,
88
- fields: {
89
- args: this.args
90
- }
121
+ _class_private_field_init(this, _log, {
122
+ writable: true,
123
+ value: void 0
91
124
  });
125
+ _class_private_field_init(this, _parent, {
126
+ writable: true,
127
+ value: void 0
128
+ });
129
+ _class_private_field_init(this, _user, {
130
+ writable: true,
131
+ value: void 0
132
+ });
133
+ _class_private_field_init(this, _app, {
134
+ writable: true,
135
+ value: void 0
136
+ });
137
+ this.args = args;
138
+ _class_private_field_set(this, _log, log);
139
+ _class_private_field_set(this, _parent, parent);
140
+ // in case this context is ...spread into another object
141
+ this.abort = this.abort.bind(this);
142
+ this.child = this.child.bind(this);
143
+ this.onAbort = this.onAbort.bind(this);
92
144
  }
93
145
  }
94
146
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/command/context.ts"],"sourcesContent":["import type arg from \"arg\";\nimport assert from \"node:assert\";\nimport type { EmptyObject } from \"type-fest\";\nimport type { rootArgs } from \"../../commands/root.js\";\nimport { createLogger, type Logger } from \"../output/log/logger.js\";\nimport type { AnyVoid } from \"../util/function.js\";\nimport { isFunction } from \"../util/is.js\";\nimport { parseArgs, type ArgsSpec, type ArgsSpecResult } from \"./arg.js\";\n\n/**\n * Represents the context of a command-line operation.\n */\nexport class Context<\n Args extends ArgsSpec = ArgsSpec,\n ParentArgs extends ArgsSpec = typeof rootArgs,\n AllArgs extends ArgsSpec = Args & ParentArgs,\n> extends AbortController {\n /**\n * The parsed command-line arguments for the current command and\n * any parent commands.\n */\n readonly args: ArgsSpecResult<AllArgs>;\n\n /**\n * A logger instance that can be used to log messages.\n *\n * This logger's name is set the name of the command that is being\n * executed.\n */\n readonly log: Logger;\n\n private constructor({ args, name = \"context\" }: { args: ArgsSpecResult<AllArgs>; name?: string }) {\n super();\n this.args = args;\n this.log = createLogger({ name, fields: { args: this.args } });\n }\n\n /**\n * Initializes a new context.\n */\n static init<Args extends ArgsSpec = ArgsSpec>({\n args: spec,\n name,\n ...options\n }: { args: Args; name?: string } & arg.Options): Context<Args, EmptyObject> {\n const args = parseArgs(spec, options);\n return new Context({ args, name });\n }\n\n /**\n * Extends the current context with more arguments.\n */\n extend<Args extends ArgsSpec>({ args: spec, name, ...options }: { args: Args; name?: string } & arg.Options): Context<Args, AllArgs> {\n const args = { ...this.args, ...parseArgs(spec, { argv: this.args._, ...options }) };\n const ctx = new Context<Args, AllArgs>({ args, name });\n this.onAbort(() => ctx.abort());\n return ctx;\n }\n\n /**\n * Clones the current context and optionally overrides its name and\n * arguments.\n */\n clone({ args, name }: { args?: Partial<ArgsSpecResult<AllArgs>>; name?: string }): Context<Args, ParentArgs, AllArgs> {\n const ctx = new Context<Args, ParentArgs, AllArgs>({ args: { ...args, ...this.args }, name });\n this.onAbort(() => ctx.abort());\n return ctx;\n }\n\n /**\n * Registers a callback that will be called when the context is\n * aborted (e.g. when the user presses Ctrl+C).\n *\n * @param callback The callback to call when the context is aborted.\n */\n onAbort(callback: OnAbort): void;\n\n /**\n * Registers a callback that will be called when the context is\n * aborted (e.g. when the user presses Ctrl+C).\n *\n * @param options.once Whether the callback should only be called once. Defaults to `true`.\n * @param callback The callback to call when the context is aborted.\n */\n onAbort(options: { once?: boolean }, callback: OnAbort): void;\n\n onAbort(callbackOrOptions: { once?: boolean } | OnAbort, callback?: OnAbort): void {\n let options = { once: true };\n if (isFunction(callbackOrOptions)) {\n callback = callbackOrOptions;\n } else {\n options = { ...options, ...callbackOrOptions };\n }\n\n this.signal.addEventListener(\n \"abort\",\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async () => {\n try {\n assert(callback, \"callback must have been provided\");\n await callback(this.signal.reason);\n } catch (error: unknown) {\n this.log.error(\"error during abort\", { error });\n }\n },\n options,\n );\n }\n}\n\n/**\n * A callback that will be called when the context is aborted.\n */\nexport type OnAbort = (reason: unknown) => AnyVoid;\n"],"names":["assert","createLogger","isFunction","parseArgs","Context","AbortController","init","args","spec","name","options","extend","argv","_","ctx","onAbort","abort","clone","callbackOrOptions","callback","once","signal","addEventListener","reason","error","log","fields"],"mappings":";AACA,OAAOA,YAAY,cAAc;AAGjC,SAASC,YAAY,QAAqB,0BAA0B;AAEpE,SAASC,UAAU,QAAQ,gBAAgB;AAC3C,SAASC,SAAS,QAA4C,WAAW;AAEzE;;CAEC,GACD,OAAO,MAAMC,gBAIHC;IAqBR;;GAEC,GACD,OAAOC,KAAuC,EAC5CC,MAAMC,IAAI,EACVC,IAAI,EACJ,GAAGC,SACyC,EAA8B;QAC1E,MAAMH,OAAOJ,UAAUK,MAAME;QAC7B,OAAO,IAAIN,QAAQ;YAAEG;YAAME;QAAK;IAClC;IAEA;;GAEC,GACDE,OAA8B,EAAEJ,MAAMC,IAAI,EAAEC,IAAI,EAAE,GAAGC,SAAsD,EAA0B;QACnI,MAAMH,OAAO;YAAE,GAAG,IAAI,CAACA,IAAI;YAAE,GAAGJ,UAAUK,MAAM;gBAAEI,MAAM,IAAI,CAACL,IAAI,CAACM,CAAC;gBAAE,GAAGH,OAAO;YAAC,EAAE;QAAC;QACnF,MAAMI,MAAM,IAAIV,QAAuB;YAAEG;YAAME;QAAK;QACpD,IAAI,CAACM,OAAO,CAAC,IAAMD,IAAIE,KAAK;QAC5B,OAAOF;IACT;IAEA;;;GAGC,GACDG,MAAM,EAAEV,IAAI,EAAEE,IAAI,EAA8D,EAAsC;QACpH,MAAMK,MAAM,IAAIV,QAAmC;YAAEG,MAAM;gBAAE,GAAGA,IAAI;gBAAE,GAAG,IAAI,CAACA,IAAI;YAAC;YAAGE;QAAK;QAC3F,IAAI,CAACM,OAAO,CAAC,IAAMD,IAAIE,KAAK;QAC5B,OAAOF;IACT;IAmBAC,QAAQG,iBAA+C,EAAEC,QAAkB,EAAQ;QACjF,IAAIT,UAAU;YAAEU,MAAM;QAAK;QAC3B,IAAIlB,WAAWgB,oBAAoB;YACjCC,WAAWD;QACb,OAAO;YACLR,UAAU;gBAAE,GAAGA,OAAO;gBAAE,GAAGQ,iBAAiB;YAAC;QAC/C;QAEA,IAAI,CAACG,MAAM,CAACC,gBAAgB,CAC1B,SACA,kEAAkE;QAClE;YACE,IAAI;gBACFtB,OAAOmB,UAAU;gBACjB,MAAMA,SAAS,IAAI,CAACE,MAAM,CAACE,MAAM;YACnC,EAAE,OAAOC,OAAgB;gBACvB,IAAI,CAACC,GAAG,CAACD,KAAK,CAAC,sBAAsB;oBAAEA;gBAAM;YAC/C;QACF,GACAd;IAEJ;IA5EA,YAAoB,EAAEH,IAAI,EAAEE,OAAO,SAAS,EAAoD,CAAE;QAChG,KAAK;QAfP;;;GAGC,GACD,uBAASF,QAAT,KAAA;QAEA;;;;;GAKC,GACD,uBAASkB,OAAT,KAAA;QAIE,IAAI,CAAClB,IAAI,GAAGA;QACZ,IAAI,CAACkB,GAAG,GAAGxB,aAAa;YAAEQ;YAAMiB,QAAQ;gBAAEnB,MAAM,IAAI,CAACA,IAAI;YAAC;QAAE;IAC9D;AAyEF"}
1
+ {"version":3,"sources":["../../../src/services/command/context.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport type { EmptyObject } from \"type-fest\";\nimport type { RootArgs } from \"../../commands/root.js\";\nimport type { App } from \"../app/app.js\";\nimport { createLogger, type Logger } from \"../output/log/logger.js\";\nimport type { StructuredLoggerOptions } from \"../output/log/structured.js\";\nimport type { User } from \"../user/user.js\";\nimport { defaults, pick } from \"../util/object.js\";\nimport type { AnyVoid } from \"../util/types.js\";\nimport { parseArgs, type ArgsDefinition, type ArgsDefinitionResult, type ParseArgsOptions } from \"./arg.js\";\n\n/**\n * Represents the options that can be passed to {@linkcode Context.init}.\n */\nexport type ContextInit<Args extends ArgsDefinition> = ParseArgsOptions &\n StructuredLoggerOptions & {\n /**\n * The {@linkcode ArgsDefinition} to use to parse the arguments (`argv`).\n */\n parse?: Args;\n };\n\n/**\n * Represents the options that can be passed to {@linkcode Context.child}.\n *\n * @see {@linkcode Context.child}\n * @see {@linkcode ContextInit}\n */\nexport type ChildContextInit<Args extends ArgsDefinition, Parsed extends ArgsDefinitionResult<ArgsDefinition>> = Partial<\n ContextInit<Args>\n> & {\n /**\n * Replaces the parsed arguments of the parent context.\n */\n overwrite?: Partial<Omit<Parsed, \"_\">>;\n};\n\n/**\n * Represents the context of a command-line operation.\n */\nexport class Context<\n Args extends ArgsDefinition = EmptyObject,\n ParentArgs extends ArgsDefinition = RootArgs,\n ThisArgs extends ArgsDefinition = ParentArgs & Args,\n> extends AbortController {\n /**\n * The parsed command-line arguments for the current context and any\n * parent contexts.\n */\n readonly args: ArgsDefinitionResult<ThisArgs>;\n\n #log: Logger;\n #parent?: Context<ArgsDefinition, ParentArgs>;\n #user?: User;\n #app?: App;\n\n private constructor({\n args,\n log,\n parent,\n }: {\n parent?: Context<ArgsDefinition, ParentArgs>;\n args: ArgsDefinitionResult<ThisArgs>;\n log: Logger;\n }) {\n super();\n this.args = args;\n this.#log = log;\n this.#parent = parent;\n\n // in case this context is ...spread into another object\n this.abort = this.abort.bind(this);\n this.child = this.child.bind(this);\n this.onAbort = this.onAbort.bind(this);\n }\n\n /**\n * A {@linkcode Logger} that can print to stdout and log structured\n * messages to stderr.\n */\n get log(): Logger {\n return this.#log;\n }\n\n get user(): User | undefined {\n return this.#user ?? this.#parent?.user;\n }\n\n set user(user: User) {\n this.#user = user;\n if (this.#parent) {\n this.#parent.user = user;\n }\n\n this.#log = this.#log.child({ fields: { user: pick(user, [\"id\", \"name\", \"email\"]) } });\n }\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n get app(): App | undefined {\n return this.#app ?? this.#parent?.app;\n }\n\n set app(app: App) {\n this.#app = app;\n if (this.#parent) {\n this.#parent.app = app;\n }\n\n this.#log = this.#log.child({ fields: { app } });\n }\n\n /**\n * Initializes a new context.\n *\n * @see {@linkcode ContextInit}\n */\n static init<Args extends ArgsDefinition = EmptyObject>({ parse: spec, ...options }: ContextInit<Args>): Context<Args> {\n return new Context({\n args: spec ? parseArgs(spec, pick(options, [\"argv\", \"permissive\", \"stopAtPositional\"])) : ({} as ArgsDefinitionResult<Args>),\n log: createLogger(pick(options, [\"name\", \"fields\", \"devFields\"])),\n });\n }\n\n /**\n * Returns a new context that is a child of the current context.\n *\n * @see {@linkcode ChildContextInit}\n */\n child<ChildArgs extends ArgsDefinition = EmptyObject>({\n parse: spec,\n ...options\n }: ChildContextInit<ChildArgs, ArgsDefinitionResult<ThisArgs>>): Context<ChildArgs, ThisArgs> {\n const ctx = new Context<ChildArgs, ThisArgs>({\n parent: this,\n args: {\n ...this.args,\n ...options.overwrite,\n ...(spec\n ? parseArgs(spec, defaults(pick(options, [\"argv\", \"permissive\", \"stopAtPositional\"]), { argv: this.args._ }))\n : ({} as ArgsDefinitionResult<ChildArgs>)),\n },\n log: this.log.child(pick(options, [\"name\", \"fields\", \"devFields\"])),\n });\n\n this.onAbort(() => ctx.abort());\n\n return ctx;\n }\n\n /**\n * Registers a callback that will be called when the context is\n * aborted (e.g. when the user presses Ctrl+C).\n *\n * @param callback - The callback to call when the context is aborted.\n */\n onAbort(callback: OnAbort): void {\n this.signal.addEventListener(\n \"abort\",\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async () => {\n try {\n assert(callback, \"callback must have been provided\");\n await callback(this.signal.reason);\n } catch (error: unknown) {\n this.log.error(\"error during abort\", { error });\n }\n },\n );\n }\n}\n\n/**\n * A callback that will be called when the context is aborted.\n */\nexport type OnAbort = (reason: unknown) => AnyVoid;\n"],"names":["assert","createLogger","defaults","pick","parseArgs","Context","AbortController","log","user","parent","child","fields","app","init","parse","spec","options","args","ctx","overwrite","argv","_","onAbort","abort","callback","signal","addEventListener","reason","error","bind"],"mappings":"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"}
@@ -2,12 +2,8 @@ import chalk from "chalk";
2
2
  import pluralize from "pluralize";
3
3
  import { config } from "../config/config.js";
4
4
  import { Level } from "../output/log/level.js";
5
- import { createLogger } from "../output/log/logger.js";
6
5
  import { sprint } from "../output/sprint.js";
7
6
  import { isNever, isString } from "../util/is.js";
8
- const log = createLogger({
9
- name: "changes"
10
- });
11
7
  export class Changes extends Map {
12
8
  created() {
13
9
  return Array.from(this.entries()).filter(([, change])=>change.type === "create").map(([path])=>path);
@@ -22,10 +18,12 @@ export class Changes extends Map {
22
18
  /**
23
19
  * Prints the changes to the console.
24
20
  *
25
- * @param changes - The changes to print.
26
- * @param tense - The tense to use for the change type.
27
- * @param limit - The maximum number of changes to print.
28
- */ export const printChanges = ({ changes, tense, limit = Infinity, ...tableOptions })=>{
21
+ * @param ctx - The current context.
22
+ * @param options - The options to use.
23
+ * @param options.changes - The changes to print.
24
+ * @param options.tense - The tense to use for the change type.
25
+ * @param options.limit - The maximum number of changes to print.
26
+ */ export const printChanges = (ctx, { changes, tense, limit = Infinity, ...tableOptions })=>{
29
27
  if (config.logLevel <= Level.TRACE) {
30
28
  // print all changes when tracing
31
29
  limit = Infinity;
@@ -87,7 +85,7 @@ export class Changes extends Map {
87
85
  footer += breakdown.join(", ");
88
86
  footer += ".";
89
87
  }
90
- log.printTable({
88
+ ctx.log.printTable({
91
89
  rows,
92
90
  footer,
93
91
  ...tableOptions