@gadgetinc/ggt 0.4.2 → 0.4.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.
package/README.md CHANGED
@@ -220,5 +220,5 @@ USAGE
220
220
 
221
221
  EXAMPLES
222
222
  $ ggt version
223
- 0.4.2
223
+ 0.4.3
224
224
  ```
package/lib/main.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { command as root } from "./commands/root.js";
2
2
  import { installErrorHandlers } from "./services/output/report.js";
3
+ import { installJsonExtensions } from "./services/util/json.js";
3
4
  installErrorHandlers();
5
+ installJsonExtensions();
4
6
  await root();
5
7
 
6
8
  //# sourceMappingURL=main.js.map
package/lib/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { command as root } from \"./commands/root.js\";\nimport { installErrorHandlers } from \"./services/output/report.js\";\n\ninstallErrorHandlers();\n\nawait root();\n"],"names":["command","root","installErrorHandlers"],"mappings":"AAAA,SAASA,WAAWC,IAAI,QAAQ,qBAAqB;AACrD,SAASC,oBAAoB,QAAQ,8BAA8B;AAEnEA;AAEA,MAAMD"}
1
+ {"version":3,"sources":["../src/main.ts"],"sourcesContent":["import { command as root } from \"./commands/root.js\";\nimport { installErrorHandlers } from \"./services/output/report.js\";\nimport { installJsonExtensions } from \"./services/util/json.js\";\n\ninstallErrorHandlers();\ninstallJsonExtensions();\n\nawait root();\n"],"names":["command","root","installErrorHandlers","installJsonExtensions"],"mappings":"AAAA,SAASA,WAAWC,IAAI,QAAQ,qBAAqB;AACrD,SAASC,oBAAoB,QAAQ,8BAA8B;AACnE,SAASC,qBAAqB,QAAQ,0BAA0B;AAEhED;AACAC;AAEA,MAAMF"}
@@ -23,7 +23,7 @@ const log = createLogger({
23
23
  if (localChange.type === "delete" && gadgetChange.type === "delete") {
24
24
  continue;
25
25
  }
26
- if ("targetHash" in localChange && "targetHash" in gadgetChange && isEqualHash(localChange.targetHash, gadgetChange.targetHash)) {
26
+ if ("targetHash" in localChange && "targetHash" in gadgetChange && isEqualHash(filepath, localChange.targetHash, gadgetChange.targetHash)) {
27
27
  continue;
28
28
  }
29
29
  // local and gadget both updated the same file with different
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/filesync/conflicts.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { ChangesWithHash, isEqualHash, type ChangeWithHash } from \"./hashes.js\";\n\nconst log = createLogger({ name: \"conflicts\" });\n\n/**\n * A map of conflicting changes made between the user's local filesystem\n * and Gadget's filesystem where the key is the path of the conflicting\n * file and the value is an object containing the conflicting changes.\n */\nexport class Conflicts extends Map<string, { localChange: ChangeWithHash; gadgetChange: ChangeWithHash }> {}\n\n/**\n * Returns the conflicting changes between the user's local filesystem\n * and Gadget's filesystem.\n */\nexport const getConflicts = ({\n localChanges,\n gadgetChanges,\n}: {\n localChanges: ChangesWithHash;\n gadgetChanges: ChangesWithHash;\n}): Conflicts => {\n const conflicts = new Conflicts();\n\n for (const [filepath, localChange] of localChanges) {\n const gadgetChange = gadgetChanges.get(filepath);\n if (!gadgetChange) {\n // gadget doesn't have this change, so there's no conflict\n continue;\n }\n\n if (localChange.type === \"delete\" && gadgetChange.type === \"delete\") {\n // local and gadget both deleted the same file\n continue;\n }\n\n if (\"targetHash\" in localChange && \"targetHash\" in gadgetChange && isEqualHash(localChange.targetHash, gadgetChange.targetHash)) {\n // local and gadget both created/updated the same file with the same content\n continue;\n }\n\n // local and gadget both updated the same file with different\n // content or one updated and the other deleted\n conflicts.set(filepath, { localChange, gadgetChange });\n }\n\n // ignore .gadget/ file conflicts and always use gadget's version\n // since gadget is the source of truth for .gadget/ files\n for (const filepath of conflicts.keys()) {\n if (filepath.startsWith(\".gadget/\")) {\n conflicts.delete(filepath);\n }\n }\n\n return conflicts;\n};\n\n/**\n * Returns a new `Changes` object that contains only the changes that do\n * not have conflicts.\n *\n * @param conflicts - The conflicts to check against.\n * @param changes - The changes to filter.\n * @returns A new `Changes` object without conflicts.\n */\nexport const withoutConflictingChanges = ({ conflicts, changes }: { conflicts: Conflicts; changes: ChangesWithHash }): ChangesWithHash => {\n const changesWithoutConflicts = new ChangesWithHash(changes);\n\n for (const [filepath] of changesWithoutConflicts) {\n if (conflicts.has(filepath)) {\n changesWithoutConflicts.delete(filepath);\n }\n }\n\n return changesWithoutConflicts;\n};\n\n/**\n * Prints a table of conflicts between local changes and gadget changes.\n */\nexport const printConflicts = ({ message, conflicts }: { message: string; conflicts: Conflicts }): void => {\n const created = chalk.greenBright(\"+ created\");\n const updated = chalk.blueBright(\"± updated\");\n const deleted = chalk.redBright(\"- deleted\");\n\n log.printTable({\n message,\n colAligns: [\"left\", \"center\", \"center\"],\n headers: [\"\", \"You\", \"Gadget\"],\n spaceY: 1,\n rows: Array.from(conflicts.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([path, { localChange, gadgetChange }]) => {\n switch (true) {\n case localChange.type === \"create\" && gadgetChange.type === \"create\":\n return [path, created, created];\n case localChange.type === \"create\" && gadgetChange.type === \"update\":\n return [path, created, updated];\n case localChange.type === \"create\" && gadgetChange.type === \"delete\":\n return [path, created, deleted];\n case localChange.type === \"update\" && gadgetChange.type === \"create\":\n return [path, updated, created];\n case localChange.type === \"update\" && gadgetChange.type === \"update\":\n return [path, updated, updated];\n case localChange.type === \"update\" && gadgetChange.type === \"delete\":\n return [path, updated, deleted];\n case localChange.type === \"delete\" && gadgetChange.type === \"create\":\n return [path, deleted, created];\n case localChange.type === \"delete\" && gadgetChange.type === \"update\":\n return [path, deleted, updated];\n default:\n throw new Error(`Unexpected conflict: ${localChange.type} vs ${gadgetChange.type}`);\n }\n }),\n });\n};\n"],"names":["chalk","createLogger","ChangesWithHash","isEqualHash","log","name","Conflicts","Map","getConflicts","localChanges","gadgetChanges","conflicts","filepath","localChange","gadgetChange","get","type","targetHash","set","keys","startsWith","delete","withoutConflictingChanges","changes","changesWithoutConflicts","has","printConflicts","message","created","greenBright","updated","blueBright","deleted","redBright","printTable","colAligns","headers","spaceY","rows","Array","from","entries","sort","a","b","localeCompare","map","path","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/services/filesync/conflicts.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { ChangesWithHash, isEqualHash, type ChangeWithHash } from \"./hashes.js\";\n\nconst log = createLogger({ name: \"conflicts\" });\n\n/**\n * A map of conflicting changes made between the user's local filesystem\n * and Gadget's filesystem where the key is the path of the conflicting\n * file and the value is an object containing the conflicting changes.\n */\nexport class Conflicts extends Map<string, { localChange: ChangeWithHash; gadgetChange: ChangeWithHash }> {}\n\n/**\n * Returns the conflicting changes between the user's local filesystem\n * and Gadget's filesystem.\n */\nexport const getConflicts = ({\n localChanges,\n gadgetChanges,\n}: {\n localChanges: ChangesWithHash;\n gadgetChanges: ChangesWithHash;\n}): Conflicts => {\n const conflicts = new Conflicts();\n\n for (const [filepath, localChange] of localChanges) {\n const gadgetChange = gadgetChanges.get(filepath);\n if (!gadgetChange) {\n // gadget doesn't have this change, so there's no conflict\n continue;\n }\n\n if (localChange.type === \"delete\" && gadgetChange.type === \"delete\") {\n // local and gadget both deleted the same file\n continue;\n }\n\n if (\n \"targetHash\" in localChange &&\n \"targetHash\" in gadgetChange &&\n isEqualHash(filepath, localChange.targetHash, gadgetChange.targetHash)\n ) {\n // local and gadget both created/updated the same file with the same content\n continue;\n }\n\n // local and gadget both updated the same file with different\n // content or one updated and the other deleted\n conflicts.set(filepath, { localChange, gadgetChange });\n }\n\n // ignore .gadget/ file conflicts and always use gadget's version\n // since gadget is the source of truth for .gadget/ files\n for (const filepath of conflicts.keys()) {\n if (filepath.startsWith(\".gadget/\")) {\n conflicts.delete(filepath);\n }\n }\n\n return conflicts;\n};\n\n/**\n * Returns a new `Changes` object that contains only the changes that do\n * not have conflicts.\n *\n * @param conflicts - The conflicts to check against.\n * @param changes - The changes to filter.\n * @returns A new `Changes` object without conflicts.\n */\nexport const withoutConflictingChanges = ({ conflicts, changes }: { conflicts: Conflicts; changes: ChangesWithHash }): ChangesWithHash => {\n const changesWithoutConflicts = new ChangesWithHash(changes);\n\n for (const [filepath] of changesWithoutConflicts) {\n if (conflicts.has(filepath)) {\n changesWithoutConflicts.delete(filepath);\n }\n }\n\n return changesWithoutConflicts;\n};\n\n/**\n * Prints a table of conflicts between local changes and gadget changes.\n */\nexport const printConflicts = ({ message, conflicts }: { message: string; conflicts: Conflicts }): void => {\n const created = chalk.greenBright(\"+ created\");\n const updated = chalk.blueBright(\"± updated\");\n const deleted = chalk.redBright(\"- deleted\");\n\n log.printTable({\n message,\n colAligns: [\"left\", \"center\", \"center\"],\n headers: [\"\", \"You\", \"Gadget\"],\n spaceY: 1,\n rows: Array.from(conflicts.entries())\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([path, { localChange, gadgetChange }]) => {\n switch (true) {\n case localChange.type === \"create\" && gadgetChange.type === \"create\":\n return [path, created, created];\n case localChange.type === \"create\" && gadgetChange.type === \"update\":\n return [path, created, updated];\n case localChange.type === \"create\" && gadgetChange.type === \"delete\":\n return [path, created, deleted];\n case localChange.type === \"update\" && gadgetChange.type === \"create\":\n return [path, updated, created];\n case localChange.type === \"update\" && gadgetChange.type === \"update\":\n return [path, updated, updated];\n case localChange.type === \"update\" && gadgetChange.type === \"delete\":\n return [path, updated, deleted];\n case localChange.type === \"delete\" && gadgetChange.type === \"create\":\n return [path, deleted, created];\n case localChange.type === \"delete\" && gadgetChange.type === \"update\":\n return [path, deleted, updated];\n default:\n throw new Error(`Unexpected conflict: ${localChange.type} vs ${gadgetChange.type}`);\n }\n }),\n });\n};\n"],"names":["chalk","createLogger","ChangesWithHash","isEqualHash","log","name","Conflicts","Map","getConflicts","localChanges","gadgetChanges","conflicts","filepath","localChange","gadgetChange","get","type","targetHash","set","keys","startsWith","delete","withoutConflictingChanges","changes","changesWithoutConflicts","has","printConflicts","message","created","greenBright","updated","blueBright","deleted","redBright","printTable","colAligns","headers","spaceY","rows","Array","from","entries","sort","a","b","localeCompare","map","path","Error"],"mappings":"AAAA,OAAOA,WAAW,QAAQ;AAC1B,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,eAAe,EAAEC,WAAW,QAA6B,cAAc;AAEhF,MAAMC,MAAMH,aAAa;IAAEI,MAAM;AAAY;AAE7C;;;;CAIC,GACD,OAAO,MAAMC,kBAAkBC;AAA4E;AAE3G;;;CAGC,GACD,OAAO,MAAMC,eAAe,CAAC,EAC3BC,YAAY,EACZC,aAAa,EAId;IACC,MAAMC,YAAY,IAAIL;IAEtB,KAAK,MAAM,CAACM,UAAUC,YAAY,IAAIJ,aAAc;QAClD,MAAMK,eAAeJ,cAAcK,GAAG,CAACH;QACvC,IAAI,CAACE,cAAc;YAEjB;QACF;QAEA,IAAID,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK,UAAU;YAEnE;QACF;QAEA,IACE,gBAAgBH,eAChB,gBAAgBC,gBAChBX,YAAYS,UAAUC,YAAYI,UAAU,EAAEH,aAAaG,UAAU,GACrE;YAEA;QACF;QAEA,6DAA6D;QAC7D,+CAA+C;QAC/CN,UAAUO,GAAG,CAACN,UAAU;YAAEC;YAAaC;QAAa;IACtD;IAEA,iEAAiE;IACjE,yDAAyD;IACzD,KAAK,MAAMF,YAAYD,UAAUQ,IAAI,GAAI;QACvC,IAAIP,SAASQ,UAAU,CAAC,aAAa;YACnCT,UAAUU,MAAM,CAACT;QACnB;IACF;IAEA,OAAOD;AACT,EAAE;AAEF;;;;;;;CAOC,GACD,OAAO,MAAMW,4BAA4B,CAAC,EAAEX,SAAS,EAAEY,OAAO,EAAsD;IAClH,MAAMC,0BAA0B,IAAItB,gBAAgBqB;IAEpD,KAAK,MAAM,CAACX,SAAS,IAAIY,wBAAyB;QAChD,IAAIb,UAAUc,GAAG,CAACb,WAAW;YAC3BY,wBAAwBH,MAAM,CAACT;QACjC;IACF;IAEA,OAAOY;AACT,EAAE;AAEF;;CAEC,GACD,OAAO,MAAME,iBAAiB,CAAC,EAAEC,OAAO,EAAEhB,SAAS,EAA6C;IAC9F,MAAMiB,UAAU5B,MAAM6B,WAAW,CAAC;IAClC,MAAMC,UAAU9B,MAAM+B,UAAU,CAAC;IACjC,MAAMC,UAAUhC,MAAMiC,SAAS,CAAC;IAEhC7B,IAAI8B,UAAU,CAAC;QACbP;QACAQ,WAAW;YAAC;YAAQ;YAAU;SAAS;QACvCC,SAAS;YAAC;YAAI;YAAO;SAAS;QAC9BC,QAAQ;QACRC,MAAMC,MAAMC,IAAI,CAAC7B,UAAU8B,OAAO,IAC/BC,IAAI,CAAC,CAACC,GAAGC,IAAMD,CAAC,CAAC,EAAE,CAACE,aAAa,CAACD,CAAC,CAAC,EAAE,GACtCE,GAAG,CAAC,CAAC,CAACC,MAAM,EAAElC,WAAW,EAAEC,YAAY,EAAE,CAAC;YACzC,OAAQ;gBACN,KAAKD,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMnB;wBAASA;qBAAQ;gBACjC,KAAKf,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMnB;wBAASE;qBAAQ;gBACjC,KAAKjB,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMnB;wBAASI;qBAAQ;gBACjC,KAAKnB,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMjB;wBAASF;qBAAQ;gBACjC,KAAKf,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMjB;wBAASA;qBAAQ;gBACjC,KAAKjB,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMjB;wBAASE;qBAAQ;gBACjC,KAAKnB,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMf;wBAASJ;qBAAQ;gBACjC,KAAKf,YAAYG,IAAI,KAAK,YAAYF,aAAaE,IAAI,KAAK;oBAC1D,OAAO;wBAAC+B;wBAAMf;wBAASF;qBAAQ;gBACjC;oBACE,MAAM,IAAIkB,MAAM,CAAC,qBAAqB,EAAEnC,YAAYG,IAAI,CAAC,IAAI,EAAEF,aAAaE,IAAI,CAAC,CAAC;YACtF;QACF;IACJ;AACF,EAAE"}
@@ -46,7 +46,7 @@ export class ChangesWithHash extends Map {
46
46
  sourceHash
47
47
  });
48
48
  }
49
- } else if (!isEqualHash(sourceHash, targetHash)) {
49
+ } else if (!isEqualHash(sourcePath, sourceHash, targetHash)) {
50
50
  // the file or directory exists in target, but has a different
51
51
  // hash, so it's been updated
52
52
  changes.set(sourcePath, {
@@ -100,7 +100,7 @@ export class ChangesWithHash extends Map {
100
100
  });
101
101
  continue;
102
102
  }
103
- if (change.type !== "delete" && existingHash && isEqualHash(change.targetHash, existingHash)) {
103
+ if (change.type !== "delete" && existingHash && isEqualHash(path, change.targetHash, existingHash)) {
104
104
  // already created or updated
105
105
  log.trace("already created or updated", {
106
106
  path,
@@ -119,13 +119,27 @@ export class ChangesWithHash extends Map {
119
119
  }
120
120
  return necessaryChanges;
121
121
  };
122
- export const isEqualHash = (a, b)=>{
123
- return a.sha1 === b.sha1 && (isNil(a.permissions) || isNil(b.permissions) || a.permissions === b.permissions);
122
+ export const isEqualHash = (path, aHash, bHash)=>{
123
+ if (aHash.sha1 !== bHash.sha1) {
124
+ // the contents are different
125
+ return false;
126
+ }
127
+ if (path.endsWith("/")) {
128
+ // it's a directory, so we don't care about permissions
129
+ return true;
130
+ }
131
+ if (isNil(aHash.permissions) || isNil(bHash.permissions)) {
132
+ // one of the filesystems doesn't support permissions, so ignore them
133
+ return true;
134
+ }
135
+ // the contents are the same, and both filesystems support permissions
136
+ // so ensure the permissions are also the same
137
+ return aHash.permissions === bHash.permissions;
124
138
  };
125
139
  export const isEqualHashes = (a, b)=>{
126
140
  for (const [aPath, aHash] of Object.entries(a)){
127
141
  const bHash = b[aPath];
128
- if (!bHash || !isEqualHash(aHash, bHash)) {
142
+ if (!bHash || !isEqualHash(aPath, aHash, bHash)) {
129
143
  log.trace("hashes are not equal", {
130
144
  path: aPath,
131
145
  aHash,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/filesync/hashes.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { isNil } from \"../util/is.js\";\nimport { type Create, type Delete, type Update } from \"./changes.js\";\nimport type { Hash, Hashes } from \"./directory.js\";\n\nconst log = createLogger({ name: \"hashes\" });\n\nexport type CreateWithHash = Create & { targetHash: Hash };\nexport type UpdateWithHash = Update & { sourceHash: Hash; targetHash: Hash };\nexport type DeleteWithHash = Delete & { sourceHash: Hash };\nexport type ChangeWithHash = CreateWithHash | UpdateWithHash | DeleteWithHash;\n\nexport class ChangesWithHash extends Map<string, ChangeWithHash> {\n created(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"create\")\n .map(([path]) => path);\n }\n\n updated(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"update\")\n .map(([path]) => path);\n }\n\n deleted(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"delete\")\n .map(([path]) => path);\n }\n}\n\n/**\n * Calculates the changes that were made to `from` to make it end up as `to`.\n *\n * If `existing` is provided, only the changes that are necessary to\n * apply to `existing` are returned.\n *\n * If `ignore` is provided, any changes that were made to a path that\n * starts with any of the `ignore` paths are skipped.\n */\nexport const getChanges = ({\n from: source,\n to: target,\n existing,\n ignore,\n}: {\n from: Hashes;\n to: Hashes;\n existing?: Hashes;\n ignore?: string[];\n}): ChangesWithHash => {\n const changes = new ChangesWithHash();\n const targetPaths = Object.keys(target);\n\n for (const [sourcePath, sourceHash] of Object.entries(source)) {\n if (ignore?.some((ignored) => sourcePath.startsWith(ignored))) {\n continue;\n }\n\n const targetHash = target[sourcePath];\n if (!targetHash) {\n if (!sourcePath.endsWith(\"/\") || !targetPaths.some((targetPath) => targetPath.startsWith(sourcePath))) {\n // sourcePath is a file and it doesn't exist in target OR\n // sourcePath is a directory and target doesn't have any\n // existing files inside it, therefor the sourcePath has been\n // deleted\n changes.set(sourcePath, { type: \"delete\", sourceHash });\n log.trace(\"file deleted\", { path: sourcePath, sourceHash });\n }\n } else if (!isEqualHash(sourceHash, targetHash)) {\n // the file or directory exists in target, but has a different\n // hash, so it's been updated\n changes.set(sourcePath, { type: \"update\", sourceHash, targetHash });\n log.trace(\"file updated\", { path: sourcePath, sourceHash, targetHash });\n }\n }\n\n for (const targetPath of targetPaths) {\n if (ignore?.some((ignored) => targetPath.startsWith(ignored))) {\n continue;\n }\n\n if (!source[targetPath]) {\n // the targetPath doesn't exist in source, so it's been created\n const targetHash = target[targetPath];\n assert(targetHash, \"targetHash should exist\");\n\n changes.set(targetPath, { type: \"create\", targetHash });\n log.trace(\"file created\", { path: targetPath, targetHash });\n }\n }\n\n if (!existing) {\n return changes;\n }\n\n return withoutUnnecessaryChanges({ changes, existing });\n};\n\n/**\n * Filters out changes that the existing filesystem already has.\n */\nexport const withoutUnnecessaryChanges = ({ changes, existing }: { changes: ChangesWithHash; existing: Hashes }): ChangesWithHash => {\n const necessaryChanges = new ChangesWithHash();\n\n for (const [path, change] of changes) {\n const existingHash = existing[path];\n if (change.type === \"delete\" && !existingHash) {\n // already deleted\n log.trace(\"already deleted\", { path });\n continue;\n }\n\n if (change.type !== \"delete\" && existingHash && isEqualHash(change.targetHash, existingHash)) {\n // already created or updated\n log.trace(\"already created or updated\", { path, existingHash, targetHash: change.targetHash });\n continue;\n }\n\n // we could do this:\n // if (change.type === \"update\" && !existingHash) {\n // change = { type: \"create\", targetHash: change.targetHash };\n // }\n // but, changing the type makes the output look confusing and it\n // doesn't change the outcome, so we just leave it as is\n\n necessaryChanges.set(path, change);\n }\n\n return necessaryChanges;\n};\n\nexport const isEqualHash = (a: Hash, b: Hash): boolean => {\n return a.sha1 === b.sha1 && (isNil(a.permissions) || isNil(b.permissions) || a.permissions === b.permissions);\n};\n\nexport const isEqualHashes = (a: Hashes, b: Hashes): boolean => {\n for (const [aPath, aHash] of Object.entries(a)) {\n const bHash = b[aPath];\n if (!bHash || !isEqualHash(aHash, bHash)) {\n log.trace(\"hashes are not equal\", { path: aPath, aHash, bHash });\n return false;\n }\n }\n\n for (const bPath of Object.keys(b)) {\n if (!a[bPath]) {\n log.trace(\"hashes are not equal\", { path: bPath, aHash: undefined, bHash: b[bPath] });\n return false;\n }\n }\n\n return true;\n};\n"],"names":["assert","createLogger","isNil","log","name","ChangesWithHash","Map","created","Array","from","entries","filter","change","type","map","path","updated","deleted","getChanges","source","to","target","existing","ignore","changes","targetPaths","Object","keys","sourcePath","sourceHash","some","ignored","startsWith","targetHash","endsWith","targetPath","set","trace","isEqualHash","withoutUnnecessaryChanges","necessaryChanges","existingHash","a","b","sha1","permissions","isEqualHashes","aPath","aHash","bHash","bPath","undefined"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,KAAK,QAAQ,gBAAgB;AAItC,MAAMC,MAAMF,aAAa;IAAEG,MAAM;AAAS;AAO1C,OAAO,MAAMC,wBAAwBC;IACnCC,UAAoB;QAClB,OAAOC,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;IAEAC,UAAoB;QAClB,OAAOR,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;IAEAE,UAAoB;QAClB,OAAOT,MAAMC,IAAI,CAAC,IAAI,CAACC,OAAO,IAC3BC,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,UACvCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA;IACrB;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,MAAMG,aAAa,CAAC,EACzBT,MAAMU,MAAM,EACZC,IAAIC,MAAM,EACVC,QAAQ,EACRC,MAAM,EAMP;IACC,MAAMC,UAAU,IAAInB;IACpB,MAAMoB,cAAcC,OAAOC,IAAI,CAACN;IAEhC,KAAK,MAAM,CAACO,YAAYC,WAAW,IAAIH,OAAOhB,OAAO,CAACS,QAAS;QAC7D,IAAII,QAAQO,KAAK,CAACC,UAAYH,WAAWI,UAAU,CAACD,WAAW;YAC7D;QACF;QAEA,MAAME,aAAaZ,MAAM,CAACO,WAAW;QACrC,IAAI,CAACK,YAAY;YACf,IAAI,CAACL,WAAWM,QAAQ,CAAC,QAAQ,CAACT,YAAYK,IAAI,CAAC,CAACK,aAAeA,WAAWH,UAAU,CAACJ,cAAc;gBACrG,yDAAyD;gBACzD,wDAAwD;gBACxD,6DAA6D;gBAC7D,UAAU;gBACVJ,QAAQY,GAAG,CAACR,YAAY;oBAAEf,MAAM;oBAAUgB;gBAAW;gBACrD1B,IAAIkC,KAAK,CAAC,gBAAgB;oBAAEtB,MAAMa;oBAAYC;gBAAW;YAC3D;QACF,OAAO,IAAI,CAACS,YAAYT,YAAYI,aAAa;YAC/C,8DAA8D;YAC9D,6BAA6B;YAC7BT,QAAQY,GAAG,CAACR,YAAY;gBAAEf,MAAM;gBAAUgB;gBAAYI;YAAW;YACjE9B,IAAIkC,KAAK,CAAC,gBAAgB;gBAAEtB,MAAMa;gBAAYC;gBAAYI;YAAW;QACvE;IACF;IAEA,KAAK,MAAME,cAAcV,YAAa;QACpC,IAAIF,QAAQO,KAAK,CAACC,UAAYI,WAAWH,UAAU,CAACD,WAAW;YAC7D;QACF;QAEA,IAAI,CAACZ,MAAM,CAACgB,WAAW,EAAE;YACvB,+DAA+D;YAC/D,MAAMF,aAAaZ,MAAM,CAACc,WAAW;YACrCnC,OAAOiC,YAAY;YAEnBT,QAAQY,GAAG,CAACD,YAAY;gBAAEtB,MAAM;gBAAUoB;YAAW;YACrD9B,IAAIkC,KAAK,CAAC,gBAAgB;gBAAEtB,MAAMoB;gBAAYF;YAAW;QAC3D;IACF;IAEA,IAAI,CAACX,UAAU;QACb,OAAOE;IACT;IAEA,OAAOe,0BAA0B;QAAEf;QAASF;IAAS;AACvD,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMiB,4BAA4B,CAAC,EAAEf,OAAO,EAAEF,QAAQ,EAAkD;IAC7G,MAAMkB,mBAAmB,IAAInC;IAE7B,KAAK,MAAM,CAACU,MAAMH,OAAO,IAAIY,QAAS;QACpC,MAAMiB,eAAenB,QAAQ,CAACP,KAAK;QACnC,IAAIH,OAAOC,IAAI,KAAK,YAAY,CAAC4B,cAAc;YAC7C,kBAAkB;YAClBtC,IAAIkC,KAAK,CAAC,mBAAmB;gBAAEtB;YAAK;YACpC;QACF;QAEA,IAAIH,OAAOC,IAAI,KAAK,YAAY4B,gBAAgBH,YAAY1B,OAAOqB,UAAU,EAAEQ,eAAe;YAC5F,6BAA6B;YAC7BtC,IAAIkC,KAAK,CAAC,8BAA8B;gBAAEtB;gBAAM0B;gBAAcR,YAAYrB,OAAOqB,UAAU;YAAC;YAC5F;QACF;QAEA,oBAAoB;QACpB,mDAAmD;QACnD,gEAAgE;QAChE,IAAI;QACJ,gEAAgE;QAChE,wDAAwD;QAExDO,iBAAiBJ,GAAG,CAACrB,MAAMH;IAC7B;IAEA,OAAO4B;AACT,EAAE;AAEF,OAAO,MAAMF,cAAc,CAACI,GAASC;IACnC,OAAOD,EAAEE,IAAI,KAAKD,EAAEC,IAAI,IAAK1C,CAAAA,MAAMwC,EAAEG,WAAW,KAAK3C,MAAMyC,EAAEE,WAAW,KAAKH,EAAEG,WAAW,KAAKF,EAAEE,WAAW,AAAD;AAC7G,EAAE;AAEF,OAAO,MAAMC,gBAAgB,CAACJ,GAAWC;IACvC,KAAK,MAAM,CAACI,OAAOC,MAAM,IAAItB,OAAOhB,OAAO,CAACgC,GAAI;QAC9C,MAAMO,QAAQN,CAAC,CAACI,MAAM;QACtB,IAAI,CAACE,SAAS,CAACX,YAAYU,OAAOC,QAAQ;YACxC9C,IAAIkC,KAAK,CAAC,wBAAwB;gBAAEtB,MAAMgC;gBAAOC;gBAAOC;YAAM;YAC9D,OAAO;QACT;IACF;IAEA,KAAK,MAAMC,SAASxB,OAAOC,IAAI,CAACgB,GAAI;QAClC,IAAI,CAACD,CAAC,CAACQ,MAAM,EAAE;YACb/C,IAAIkC,KAAK,CAAC,wBAAwB;gBAAEtB,MAAMmC;gBAAOF,OAAOG;gBAAWF,OAAON,CAAC,CAACO,MAAM;YAAC;YACnF,OAAO;QACT;IACF;IAEA,OAAO;AACT,EAAE"}
1
+ {"version":3,"sources":["../../../src/services/filesync/hashes.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport { createLogger } from \"../output/log/logger.js\";\nimport { isNil } from \"../util/is.js\";\nimport { type Create, type Delete, type Update } from \"./changes.js\";\nimport type { Hash, Hashes } from \"./directory.js\";\n\nconst log = createLogger({ name: \"hashes\" });\n\nexport type CreateWithHash = Create & { targetHash: Hash };\nexport type UpdateWithHash = Update & { sourceHash: Hash; targetHash: Hash };\nexport type DeleteWithHash = Delete & { sourceHash: Hash };\nexport type ChangeWithHash = CreateWithHash | UpdateWithHash | DeleteWithHash;\n\nexport class ChangesWithHash extends Map<string, ChangeWithHash> {\n created(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"create\")\n .map(([path]) => path);\n }\n\n updated(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"update\")\n .map(([path]) => path);\n }\n\n deleted(): string[] {\n return Array.from(this.entries())\n .filter(([, change]) => change.type === \"delete\")\n .map(([path]) => path);\n }\n}\n\n/**\n * Calculates the changes that were made to `from` to make it end up as `to`.\n *\n * If `existing` is provided, only the changes that are necessary to\n * apply to `existing` are returned.\n *\n * If `ignore` is provided, any changes that were made to a path that\n * starts with any of the `ignore` paths are skipped.\n */\nexport const getChanges = ({\n from: source,\n to: target,\n existing,\n ignore,\n}: {\n from: Hashes;\n to: Hashes;\n existing?: Hashes;\n ignore?: string[];\n}): ChangesWithHash => {\n const changes = new ChangesWithHash();\n const targetPaths = Object.keys(target);\n\n for (const [sourcePath, sourceHash] of Object.entries(source)) {\n if (ignore?.some((ignored) => sourcePath.startsWith(ignored))) {\n continue;\n }\n\n const targetHash = target[sourcePath];\n if (!targetHash) {\n if (!sourcePath.endsWith(\"/\") || !targetPaths.some((targetPath) => targetPath.startsWith(sourcePath))) {\n // sourcePath is a file and it doesn't exist in target OR\n // sourcePath is a directory and target doesn't have any\n // existing files inside it, therefor the sourcePath has been\n // deleted\n changes.set(sourcePath, { type: \"delete\", sourceHash });\n log.trace(\"file deleted\", { path: sourcePath, sourceHash });\n }\n } else if (!isEqualHash(sourcePath, sourceHash, targetHash)) {\n // the file or directory exists in target, but has a different\n // hash, so it's been updated\n changes.set(sourcePath, { type: \"update\", sourceHash, targetHash });\n log.trace(\"file updated\", { path: sourcePath, sourceHash, targetHash });\n }\n }\n\n for (const targetPath of targetPaths) {\n if (ignore?.some((ignored) => targetPath.startsWith(ignored))) {\n continue;\n }\n\n if (!source[targetPath]) {\n // the targetPath doesn't exist in source, so it's been created\n const targetHash = target[targetPath];\n assert(targetHash, \"targetHash should exist\");\n\n changes.set(targetPath, { type: \"create\", targetHash });\n log.trace(\"file created\", { path: targetPath, targetHash });\n }\n }\n\n if (!existing) {\n return changes;\n }\n\n return withoutUnnecessaryChanges({ changes, existing });\n};\n\n/**\n * Filters out changes that the existing filesystem already has.\n */\nexport const withoutUnnecessaryChanges = ({ changes, existing }: { changes: ChangesWithHash; existing: Hashes }): ChangesWithHash => {\n const necessaryChanges = new ChangesWithHash();\n\n for (const [path, change] of changes) {\n const existingHash = existing[path];\n if (change.type === \"delete\" && !existingHash) {\n // already deleted\n log.trace(\"already deleted\", { path });\n continue;\n }\n\n if (change.type !== \"delete\" && existingHash && isEqualHash(path, change.targetHash, existingHash)) {\n // already created or updated\n log.trace(\"already created or updated\", { path, existingHash, targetHash: change.targetHash });\n continue;\n }\n\n // we could do this:\n // if (change.type === \"update\" && !existingHash) {\n // change = { type: \"create\", targetHash: change.targetHash };\n // }\n // but, changing the type makes the output look confusing and it\n // doesn't change the outcome, so we just leave it as is\n\n necessaryChanges.set(path, change);\n }\n\n return necessaryChanges;\n};\n\nexport const isEqualHash = (path: string, aHash: Hash, bHash: Hash): boolean => {\n if (aHash.sha1 !== bHash.sha1) {\n // the contents are different\n return false;\n }\n\n if (path.endsWith(\"/\")) {\n // it's a directory, so we don't care about permissions\n return true;\n }\n\n if (isNil(aHash.permissions) || isNil(bHash.permissions)) {\n // one of the filesystems doesn't support permissions, so ignore them\n return true;\n }\n\n // the contents are the same, and both filesystems support permissions\n // so ensure the permissions are also the same\n return aHash.permissions === bHash.permissions;\n};\n\nexport const isEqualHashes = (a: Hashes, b: Hashes): boolean => {\n for (const [aPath, aHash] of Object.entries(a)) {\n const bHash = b[aPath];\n if (!bHash || !isEqualHash(aPath, aHash, bHash)) {\n log.trace(\"hashes are not equal\", { path: aPath, aHash, bHash });\n return false;\n }\n }\n\n for (const bPath of Object.keys(b)) {\n if (!a[bPath]) {\n log.trace(\"hashes are not equal\", { path: bPath, aHash: undefined, bHash: b[bPath] });\n return false;\n }\n }\n\n return true;\n};\n"],"names":["assert","createLogger","isNil","log","name","ChangesWithHash","Map","created","Array","from","entries","filter","change","type","map","path","updated","deleted","getChanges","source","to","target","existing","ignore","changes","targetPaths","Object","keys","sourcePath","sourceHash","some","ignored","startsWith","targetHash","endsWith","targetPath","set","trace","isEqualHash","withoutUnnecessaryChanges","necessaryChanges","existingHash","aHash","bHash","sha1","permissions","isEqualHashes","a","b","aPath","bPath","undefined"],"mappings":"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"}
@@ -1,8 +1,5 @@
1
- import assert from "node:assert";
2
1
  import stripAnsi from "strip-ansi";
3
- import { config } from "../../../config/config.js";
4
2
  import { isObject, isString } from "../../../util/is.js";
5
- import { Level } from "../level.js";
6
3
  export const formatJson = (level, name, msg, fields)=>{
7
4
  return JSON.stringify({
8
5
  level,
@@ -23,11 +20,6 @@ const serializeValue = (value)=>{
23
20
  value = Array.from(value);
24
21
  }
25
22
  if (Array.isArray(value)) {
26
- if (value.length > 10 && config.logLevel > Level.TRACE) {
27
- // truncate arrays to 10 elements when not tracing
28
- value = value.slice(0, 10);
29
- assert(Array.isArray(value));
30
- }
31
23
  return value.map(serializeValue);
32
24
  }
33
25
  if (value instanceof Map) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/services/output/log/format/json.ts"],"sourcesContent":["import assert from \"node:assert\";\nimport stripAnsi from \"strip-ansi\";\nimport { config } from \"../../../config/config.js\";\nimport { isObject, isString } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatJson: Formatter = (level, name, msg, fields) => {\n return JSON.stringify({ level, name, msg: stripAnsi(msg).trim(), fields: serializeFields(fields) }) + \"\\n\";\n};\n\nconst serializeFields = (fields: Record<string, unknown>): Record<string, unknown> => {\n const result = {} as Record<string, unknown>;\n for (const [key, value] of Object.entries(fields)) {\n result[key] = serializeValue(value);\n }\n return result;\n};\n\nconst serializeValue = (value: unknown): unknown => {\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length > 10 && config.logLevel > Level.TRACE) {\n // truncate arrays to 10 elements when not tracing\n value = value.slice(0, 10);\n assert(Array.isArray(value));\n }\n return value.map(serializeValue);\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n return serializeFields(value as Record<string, unknown>);\n }\n\n if (isString(value)) {\n return stripAnsi(value).trim();\n }\n\n return value;\n};\n"],"names":["assert","stripAnsi","config","isObject","isString","Level","formatJson","level","name","msg","fields","JSON","stringify","trim","serializeFields","result","key","value","Object","entries","serializeValue","Set","Array","from","isArray","length","logLevel","TRACE","slice","map","Map","fromEntries"],"mappings":"AAAA,OAAOA,YAAY,cAAc;AACjC,OAAOC,eAAe,aAAa;AACnC,SAASC,MAAM,QAAQ,4BAA4B;AACnD,SAASC,QAAQ,EAAEC,QAAQ,QAAQ,sBAAsB;AACzD,SAASC,KAAK,QAAQ,cAAc;AAGpC,OAAO,MAAMC,aAAwB,CAACC,OAAOC,MAAMC,KAAKC;IACtD,OAAOC,KAAKC,SAAS,CAAC;QAAEL;QAAOC;QAAMC,KAAKR,UAAUQ,KAAKI,IAAI;QAAIH,QAAQI,gBAAgBJ;IAAQ,KAAK;AACxG,EAAE;AAEF,MAAMI,kBAAkB,CAACJ;IACvB,MAAMK,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACT,QAAS;QACjDK,MAAM,CAACC,IAAI,GAAGI,eAAeH;IAC/B;IACA,OAAOF;AACT;AAEA,MAAMK,iBAAiB,CAACH;IACtB,IAAIA,iBAAiBI,KAAK;QACxBJ,QAAQK,MAAMC,IAAI,CAACN;IACrB;IAEA,IAAIK,MAAME,OAAO,CAACP,QAAQ;QACxB,IAAIA,MAAMQ,MAAM,GAAG,MAAMvB,OAAOwB,QAAQ,GAAGrB,MAAMsB,KAAK,EAAE;YACtD,kDAAkD;YAClDV,QAAQA,MAAMW,KAAK,CAAC,GAAG;YACvB5B,OAAOsB,MAAME,OAAO,CAACP;QACvB;QACA,OAAOA,MAAMY,GAAG,CAACT;IACnB;IAEA,IAAIH,iBAAiBa,KAAK;QACxBb,QAAQC,OAAOa,WAAW,CAACd,MAAME,OAAO;IAC1C;IAEA,IAAIhB,SAASc,QAAQ;QACnB,OAAOH,gBAAgBG;IACzB;IAEA,IAAIb,SAASa,QAAQ;QACnB,OAAOhB,UAAUgB,OAAOJ,IAAI;IAC9B;IAEA,OAAOI;AACT"}
1
+ {"version":3,"sources":["../../../../../src/services/output/log/format/json.ts"],"sourcesContent":["import stripAnsi from \"strip-ansi\";\nimport { isObject, isString } from \"../../../util/is.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatJson: Formatter = (level, name, msg, fields) => {\n return JSON.stringify({ level, name, msg: stripAnsi(msg).trim(), fields: serializeFields(fields) }) + \"\\n\";\n};\n\nconst serializeFields = (fields: Record<string, unknown>): Record<string, unknown> => {\n const result = {} as Record<string, unknown>;\n for (const [key, value] of Object.entries(fields)) {\n result[key] = serializeValue(value);\n }\n return result;\n};\n\nconst serializeValue = (value: unknown): unknown => {\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n return value.map(serializeValue);\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n return serializeFields(value as Record<string, unknown>);\n }\n\n if (isString(value)) {\n return stripAnsi(value).trim();\n }\n\n return value;\n};\n"],"names":["stripAnsi","isObject","isString","formatJson","level","name","msg","fields","JSON","stringify","trim","serializeFields","result","key","value","Object","entries","serializeValue","Set","Array","from","isArray","map","Map","fromEntries"],"mappings":"AAAA,OAAOA,eAAe,aAAa;AACnC,SAASC,QAAQ,EAAEC,QAAQ,QAAQ,sBAAsB;AAGzD,OAAO,MAAMC,aAAwB,CAACC,OAAOC,MAAMC,KAAKC;IACtD,OAAOC,KAAKC,SAAS,CAAC;QAAEL;QAAOC;QAAMC,KAAKN,UAAUM,KAAKI,IAAI;QAAIH,QAAQI,gBAAgBJ;IAAQ,KAAK;AACxG,EAAE;AAEF,MAAMI,kBAAkB,CAACJ;IACvB,MAAMK,SAAS,CAAC;IAChB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACT,QAAS;QACjDK,MAAM,CAACC,IAAI,GAAGI,eAAeH;IAC/B;IACA,OAAOF;AACT;AAEA,MAAMK,iBAAiB,CAACH;IACtB,IAAIA,iBAAiBI,KAAK;QACxBJ,QAAQK,MAAMC,IAAI,CAACN;IACrB;IAEA,IAAIK,MAAME,OAAO,CAACP,QAAQ;QACxB,OAAOA,MAAMQ,GAAG,CAACL;IACnB;IAEA,IAAIH,iBAAiBS,KAAK;QACxBT,QAAQC,OAAOS,WAAW,CAACV,MAAME,OAAO;IAC1C;IAEA,IAAIf,SAASa,QAAQ;QACnB,OAAOH,gBAAgBG;IACzB;IAEA,IAAIZ,SAASY,QAAQ;QACnB,OAAOd,UAAUc,OAAOJ,IAAI;IAC9B;IAEA,OAAOI;AACT"}
@@ -78,17 +78,24 @@ const formatFields = (fields, indent = 2)=>{
78
78
  buf.push(formatValue(" []", gray, indent));
79
79
  continue;
80
80
  }
81
- if (value.length > 10 && config.logLevel > Level.TRACE) {
82
- // truncate arrays to 10 elements when not tracing
83
- value = value.slice(0, 10);
84
- assert(Array.isArray(value));
85
- }
86
- value = Object.fromEntries(value.entries());
87
- }
88
- if (value instanceof Map) {
89
81
  value = Object.fromEntries(value.entries());
90
82
  }
91
- if (isObject(value)) {
83
+ if (isObject(value) || value instanceof Map) {
84
+ const entries = Object.entries(value);
85
+ if (entries.length === 0) {
86
+ buf.push(formatValue(" {}", gray, indent));
87
+ continue;
88
+ }
89
+ if (entries.length > 10 && config.logLevel > Level.TRACE) {
90
+ // truncate objects to 10 keys when not tracing
91
+ value = Object.fromEntries([
92
+ ...entries.slice(0, 10),
93
+ [
94
+ "…",
95
+ `${entries.length - 10} more`
96
+ ]
97
+ ]);
98
+ }
92
99
  buf.push(formatFields(value, indent + 2));
93
100
  continue;
94
101
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n if (value.length > 10 && config.logLevel > Level.TRACE) {\n // truncate arrays to 10 elements when not tracing\n value = value.slice(0, 10);\n assert(Array.isArray(value));\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (value instanceof Map) {\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value)) {\n buf.push(formatFields(value as Record<string, unknown>, indent + 2));\n continue;\n }\n\n buf.push(SPACE);\n\n switch (typeof value) {\n case \"string\":\n buf.push(formatValue(QUOTE + value.replaceAll(NEW_LINE, NEW_LINE + SPACE.repeat(indent + key.length)) + QUOTE, blueLight, indent));\n break;\n case \"number\":\n buf.push(formatValue(String(value), orangeLight, indent));\n break;\n case \"bigint\":\n buf.push(formatValue(String(value) + \"n\", orangeLight, indent));\n break;\n case \"boolean\":\n buf.push(formatValue(String(value), greenLight, indent));\n break;\n default:\n buf.push(formatValue(String(value), white, indent));\n break;\n }\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatTimestamp = (): string => {\n const ts = dayjs().format(\"hh:mm:ss\");\n return grayDark(ts);\n};\n\nconst formatLevel = (level: Level): string => {\n switch (level) {\n case Level.PRINT:\n return gray(\"PRINT\");\n case Level.TRACE:\n return blue(\"TRACE\");\n case Level.DEBUG:\n return orange(\"DEBUG\");\n case Level.INFO:\n return green(\"INFO\");\n case Level.WARN:\n return pink(\"WARN\");\n case Level.ERROR:\n return red(\"ERROR\");\n // case \"fatal\":\n // return red(colors.bold(level));\n }\n};\n\nconst formatName = (name: string): string => {\n return white(name);\n};\n\nconst formatMessage = (msg: string): string => {\n const lines = msg.split(NEW_LINE);\n if (lines.length === 1) {\n return SPACE + white(msg);\n }\n return NEW_LINE + lines.map((line) => SPACE + SPACE + line).join(NEW_LINE);\n};\n"],"names":["chalk","Chalk","dayjs","assert","config","env","isObject","Level","formatPretty","level","name","msg","fields","formatTimestamp","formatLevel","formatName","formatMessage","formatFields","NEW_LINE","color","testLike","logLevel","PRINT","blue","hex","blueLight","gray","grayDark","green","greenLight","orange","orangeLight","pink","red","white","EMPTY","SPACE","COLON","QUOTE","formatKey","key","indent","buf","push","i","join","formatValue","value","lines","split","length","firstLine","shift","line","Object","keys","entries","Set","Array","from","isArray","TRACE","slice","fromEntries","Map","replaceAll","repeat","String","ts","format","DEBUG","INFO","WARN","ERROR","map"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../src/services/output/log/format/pretty.ts"],"sourcesContent":["import chalk, { Chalk } from \"chalk\";\nimport dayjs from \"dayjs\";\nimport assert from \"node:assert\";\nimport { config } from \"../../../config/config.js\";\nimport { env } from \"../../../config/env.js\";\nimport { isObject } from \"../../../util/is.js\";\nimport { Level } from \"../level.js\";\nimport type { Formatter } from \"./format.js\";\n\nexport const formatPretty: Formatter = (level, name, msg, fields) => {\n return `${formatTimestamp()} ${formatLevel(level)} ${formatName(name)}:${formatMessage(msg)}${formatFields(fields)}${NEW_LINE}`;\n};\n\nconst color = new Chalk({\n // we always turn off colors in tests (FORCE_COLOR=0) so that we get\n // predictable output, but if we're running with logs enabled\n // (GGT_LOG_LEVEL=info), we still want to see colors in our logs\n level: env.testLike && config.logLevel < Level.PRINT ? 3 : chalk.level,\n});\n\nconst blue = color.hex(\"#86B5F7\");\nconst blueLight = color.hex(\"#B2D0FA\");\nconst gray = color.hex(\"#D6D6D6\");\nconst grayDark = color.hex(\"#C2C2C2\");\nconst green = color.hex(\"#9DE6A4\");\nconst greenLight = color.hex(\"#BEEEC3\");\nconst orange = color.hex(\"#EEAC78\");\nconst orangeLight = color.hex(\"#F4C7A4\");\nconst pink = color.hex(\"#FAACB5\");\nconst red = color.hex(\"#A64E4E\");\nconst white = color.hex(\"#FFFFFF\");\n\nconst EMPTY = \"\";\nconst SPACE = \" \";\nconst NEW_LINE = \"\\n\";\nconst COLON = \":\";\nconst QUOTE = \"'\";\n\nconst formatKey = (key: string, indent: number): string => {\n const color = key === \"error\" ? red : gray;\n\n const buf: string[] = [];\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n buf.push(color(key));\n buf.push(COLON);\n\n return buf.join(\"\");\n};\n\nconst formatValue = (value: string, color: (s: string) => string, indent: number): string => {\n const lines = value.split(NEW_LINE);\n if (lines.length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n const firstLine = lines.shift();\n assert(firstLine);\n buf.push(color(firstLine));\n\n // color the rest of the lines\n for (const line of lines) {\n if (!line) {\n continue;\n }\n\n buf.push(NEW_LINE);\n for (let i = 0; i < indent; i++) {\n buf.push(SPACE);\n }\n\n buf.push(color(line));\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatFields = (fields: Record<string, unknown>, indent = 2): string => {\n if (Object.keys(fields).length === 0) {\n return EMPTY;\n }\n\n const buf: string[] = [];\n for (let [key, value] of Object.entries(fields)) {\n buf.push(formatKey(key, indent));\n\n if (value instanceof Set) {\n value = Array.from(value);\n }\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n buf.push(formatValue(\" []\", gray, indent));\n continue;\n }\n\n value = Object.fromEntries(value.entries());\n }\n\n if (isObject(value) || value instanceof Map) {\n const entries = Object.entries(value);\n if (entries.length === 0) {\n buf.push(formatValue(\" {}\", gray, indent));\n continue;\n }\n\n if (entries.length > 10 && config.logLevel > Level.TRACE) {\n // truncate objects to 10 keys when not tracing\n value = Object.fromEntries([...entries.slice(0, 10), [\"…\", `${entries.length - 10} more`]]);\n }\n\n buf.push(formatFields(value as Record<string, unknown>, indent + 2));\n continue;\n }\n\n buf.push(SPACE);\n\n switch (typeof value) {\n case \"string\":\n buf.push(formatValue(QUOTE + value.replaceAll(NEW_LINE, NEW_LINE + SPACE.repeat(indent + key.length)) + QUOTE, blueLight, indent));\n break;\n case \"number\":\n buf.push(formatValue(String(value), orangeLight, indent));\n break;\n case \"bigint\":\n buf.push(formatValue(String(value) + \"n\", orangeLight, indent));\n break;\n case \"boolean\":\n buf.push(formatValue(String(value), greenLight, indent));\n break;\n default:\n buf.push(formatValue(String(value), white, indent));\n break;\n }\n }\n\n return buf.join(EMPTY);\n};\n\nconst formatTimestamp = (): string => {\n const ts = dayjs().format(\"hh:mm:ss\");\n return grayDark(ts);\n};\n\nconst formatLevel = (level: Level): string => {\n switch (level) {\n case Level.PRINT:\n return gray(\"PRINT\");\n case Level.TRACE:\n return blue(\"TRACE\");\n case Level.DEBUG:\n return orange(\"DEBUG\");\n case Level.INFO:\n return green(\"INFO\");\n case Level.WARN:\n return pink(\"WARN\");\n case Level.ERROR:\n return red(\"ERROR\");\n // case \"fatal\":\n // return red(colors.bold(level));\n }\n};\n\nconst formatName = (name: string): string => {\n return white(name);\n};\n\nconst formatMessage = (msg: string): string => {\n const lines = msg.split(NEW_LINE);\n if (lines.length === 1) {\n return SPACE + white(msg);\n }\n return NEW_LINE + lines.map((line) => SPACE + SPACE + line).join(NEW_LINE);\n};\n"],"names":["chalk","Chalk","dayjs","assert","config","env","isObject","Level","formatPretty","level","name","msg","fields","formatTimestamp","formatLevel","formatName","formatMessage","formatFields","NEW_LINE","color","testLike","logLevel","PRINT","blue","hex","blueLight","gray","grayDark","green","greenLight","orange","orangeLight","pink","red","white","EMPTY","SPACE","COLON","QUOTE","formatKey","key","indent","buf","push","i","join","formatValue","value","lines","split","length","firstLine","shift","line","Object","keys","entries","Set","Array","from","isArray","fromEntries","Map","TRACE","slice","replaceAll","repeat","String","ts","format","DEBUG","INFO","WARN","ERROR","map"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ export const installJsonExtensions = ()=>{
2
+ if (!Object.prototype.hasOwnProperty.call(BigInt, "toJSON")) {
3
+ BigInt.prototype.toJSON = function() {
4
+ return String(this);
5
+ };
6
+ }
7
+ if (!Object.prototype.hasOwnProperty.call(Map, "toJSON")) {
8
+ Map.prototype.toJSON = function() {
9
+ return Object.fromEntries(this);
10
+ };
11
+ }
12
+ if (!Object.prototype.hasOwnProperty.call(Set, "toJSON")) {
13
+ Set.prototype.toJSON = function() {
14
+ return Array.from(this);
15
+ };
16
+ }
17
+ };
18
+ export const uninstallJsonExtensions = ()=>{
19
+ if (Object.prototype.hasOwnProperty.call(BigInt, "toJSON")) {
20
+ delete BigInt.prototype.toJSON;
21
+ }
22
+ if (Object.prototype.hasOwnProperty.call(Map, "toJSON")) {
23
+ delete Map.prototype.toJSON;
24
+ }
25
+ if (Object.prototype.hasOwnProperty.call(Set, "toJSON")) {
26
+ delete Set.prototype.toJSON;
27
+ }
28
+ };
29
+
30
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/services/util/json.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/consistent-type-definitions */\n\ndeclare global {\n interface BigInt {\n toJSON?(): string;\n }\n interface Map<K, V> {\n toJSON?(): Record<string, V>;\n }\n interface Set<T> {\n toJSON?(): T[];\n }\n}\n\nexport const installJsonExtensions = (): void => {\n if (!Object.prototype.hasOwnProperty.call(BigInt, \"toJSON\")) {\n BigInt.prototype.toJSON = function () {\n return String(this);\n };\n }\n\n if (!Object.prototype.hasOwnProperty.call(Map, \"toJSON\")) {\n Map.prototype.toJSON = function () {\n return Object.fromEntries(this);\n };\n }\n\n if (!Object.prototype.hasOwnProperty.call(Set, \"toJSON\")) {\n Set.prototype.toJSON = function () {\n return Array.from(this);\n };\n }\n};\n\nexport const uninstallJsonExtensions = (): void => {\n if (Object.prototype.hasOwnProperty.call(BigInt, \"toJSON\")) {\n delete BigInt.prototype.toJSON;\n }\n\n if (Object.prototype.hasOwnProperty.call(Map, \"toJSON\")) {\n delete Map.prototype.toJSON;\n }\n\n if (Object.prototype.hasOwnProperty.call(Set, \"toJSON\")) {\n delete Set.prototype.toJSON;\n }\n};\n"],"names":["installJsonExtensions","Object","prototype","hasOwnProperty","call","BigInt","toJSON","String","Map","fromEntries","Set","Array","from","uninstallJsonExtensions"],"mappings":"AAAA,oDAAoD,GACpD,sDAAsD,GACtD,iEAAiE,GAcjE,OAAO,MAAMA,wBAAwB;IACnC,IAAI,CAACC,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACC,QAAQ,WAAW;QAC3DA,OAAOH,SAAS,CAACI,MAAM,GAAG;YACxB,OAAOC,OAAO,IAAI;QACpB;IACF;IAEA,IAAI,CAACN,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACI,KAAK,WAAW;QACxDA,IAAIN,SAAS,CAACI,MAAM,GAAG;YACrB,OAAOL,OAAOQ,WAAW,CAAC,IAAI;QAChC;IACF;IAEA,IAAI,CAACR,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACM,KAAK,WAAW;QACxDA,IAAIR,SAAS,CAACI,MAAM,GAAG;YACrB,OAAOK,MAAMC,IAAI,CAAC,IAAI;QACxB;IACF;AACF,EAAE;AAEF,OAAO,MAAMC,0BAA0B;IACrC,IAAIZ,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACC,QAAQ,WAAW;QAC1D,OAAOA,OAAOH,SAAS,CAACI,MAAM;IAChC;IAEA,IAAIL,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACI,KAAK,WAAW;QACvD,OAAOA,IAAIN,SAAS,CAACI,MAAM;IAC7B;IAEA,IAAIL,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACM,KAAK,WAAW;QACvD,OAAOA,IAAIR,SAAS,CAACI,MAAM;IAC7B;AACF,EAAE"}
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@gadgetinc/ggt",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@gadgetinc/ggt",
9
- "version": "0.4.2",
9
+ "version": "0.4.3",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@sentry/node": "^7.88.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadgetinc/ggt",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "The command-line interface for Gadget",
5
5
  "homepage": "https://github.com/gadget-inc/ggt",
6
6
  "bugs": {