@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 +1 -1
- package/lib/main.js +2 -0
- package/lib/main.js.map +1 -1
- package/lib/services/filesync/conflicts.js +1 -1
- package/lib/services/filesync/conflicts.js.map +1 -1
- package/lib/services/filesync/hashes.js +19 -5
- package/lib/services/filesync/hashes.js.map +1 -1
- package/lib/services/output/log/format/json.js +0 -8
- package/lib/services/output/log/format/json.js.map +1 -1
- package/lib/services/output/log/format/pretty.js +16 -9
- package/lib/services/output/log/format/pretty.js.map +1 -1
- package/lib/services/util/json.js +30 -0
- package/lib/services/util/json.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
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;
|
|
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
|
|
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":"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"}
|
|
@@ -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 = (
|
|
123
|
-
|
|
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 = (
|
|
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
|
|
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
|
|
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"}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gadgetinc/ggt",
|
|
3
|
-
"version": "0.4.
|
|
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.
|
|
9
|
+
"version": "0.4.3",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@sentry/node": "^7.88.0",
|