@socketsecurity/lib 4.4.0 → 5.0.0
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/CHANGELOG.md +67 -0
- package/dist/constants/node.js +1 -1
- package/dist/{package-default-node-range.js → constants/package-default-node-range.js} +1 -1
- package/dist/constants/packages.js +3 -3
- package/dist/{dlx-binary.d.ts → dlx/binary.d.ts} +2 -2
- package/dist/{dlx-binary.js → dlx/binary.js} +17 -17
- package/dist/dlx/cache.d.ts +25 -0
- package/dist/dlx/cache.js +32 -0
- package/dist/dlx/dir.d.ts +24 -0
- package/dist/dlx/dir.js +79 -0
- package/dist/{dlx-manifest.js → dlx/manifest.js} +7 -7
- package/dist/{dlx-package.d.ts → dlx/package.d.ts} +2 -2
- package/dist/{dlx-package.js → dlx/package.js} +16 -16
- package/dist/dlx/packages.d.ts +24 -0
- package/dist/dlx/packages.js +125 -0
- package/dist/dlx/paths.d.ts +31 -0
- package/dist/dlx/paths.js +75 -0
- package/dist/fs.d.ts +3 -3
- package/dist/fs.js +3 -3
- package/dist/json/edit.d.ts +16 -0
- package/dist/json/edit.js +217 -0
- package/dist/json/format.d.ts +140 -0
- package/dist/json/format.js +121 -0
- package/dist/json/parse.d.ts +76 -0
- package/dist/{json.js → json/parse.js} +4 -4
- package/dist/json/types.d.ts +229 -0
- package/dist/json/types.js +17 -0
- package/dist/packages/{editable.js → edit.js} +18 -32
- package/dist/packages/operations.js +3 -3
- package/dist/packages.d.ts +2 -2
- package/dist/packages.js +5 -5
- package/package.json +58 -34
- package/dist/dlx.d.ts +0 -104
- package/dist/dlx.js +0 -220
- package/dist/json.d.ts +0 -196
- /package/dist/{lifecycle-script-names.d.ts → constants/lifecycle-script-names.d.ts} +0 -0
- /package/dist/{lifecycle-script-names.js → constants/lifecycle-script-names.js} +0 -0
- /package/dist/{maintained-node-versions.d.ts → constants/maintained-node-versions.d.ts} +0 -0
- /package/dist/{maintained-node-versions.js → constants/maintained-node-versions.js} +0 -0
- /package/dist/{package-default-node-range.d.ts → constants/package-default-node-range.d.ts} +0 -0
- /package/dist/{package-default-socket-categories.d.ts → constants/package-default-socket-categories.d.ts} +0 -0
- /package/dist/{package-default-socket-categories.js → constants/package-default-socket-categories.js} +0 -0
- /package/dist/{dlx-manifest.d.ts → dlx/manifest.d.ts} +0 -0
- /package/dist/packages/{editable.d.ts → edit.d.ts} +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with esbuild */
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var paths_exports = {};
|
|
21
|
+
__export(paths_exports, {
|
|
22
|
+
getDlxInstalledPackageDir: () => getDlxInstalledPackageDir,
|
|
23
|
+
getDlxPackageDir: () => getDlxPackageDir,
|
|
24
|
+
getDlxPackageJsonPath: () => getDlxPackageJsonPath,
|
|
25
|
+
getDlxPackageNodeModulesDir: () => getDlxPackageNodeModulesDir,
|
|
26
|
+
isInSocketDlx: () => isInSocketDlx
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(paths_exports);
|
|
29
|
+
var import_normalize = require("../paths/normalize");
|
|
30
|
+
var import_socket = require("../paths/socket");
|
|
31
|
+
let _path;
|
|
32
|
+
// @__NO_SIDE_EFFECTS__
|
|
33
|
+
function getPath() {
|
|
34
|
+
if (_path === void 0) {
|
|
35
|
+
_path = require("node:path");
|
|
36
|
+
}
|
|
37
|
+
return _path;
|
|
38
|
+
}
|
|
39
|
+
function getDlxInstalledPackageDir(packageName) {
|
|
40
|
+
const path = /* @__PURE__ */ getPath();
|
|
41
|
+
return (0, import_normalize.normalizePath)(
|
|
42
|
+
path.join(getDlxPackageNodeModulesDir(packageName), packageName)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function getDlxPackageDir(packageName) {
|
|
46
|
+
const path = /* @__PURE__ */ getPath();
|
|
47
|
+
return (0, import_normalize.normalizePath)(path.join((0, import_socket.getSocketDlxDir)(), packageName));
|
|
48
|
+
}
|
|
49
|
+
function getDlxPackageJsonPath(packageName) {
|
|
50
|
+
const path = /* @__PURE__ */ getPath();
|
|
51
|
+
return (0, import_normalize.normalizePath)(
|
|
52
|
+
path.join(getDlxInstalledPackageDir(packageName), "package.json")
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function getDlxPackageNodeModulesDir(packageName) {
|
|
56
|
+
const path = /* @__PURE__ */ getPath();
|
|
57
|
+
return (0, import_normalize.normalizePath)(path.join(getDlxPackageDir(packageName), "node_modules"));
|
|
58
|
+
}
|
|
59
|
+
function isInSocketDlx(filePath) {
|
|
60
|
+
if (!filePath) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const path = /* @__PURE__ */ getPath();
|
|
64
|
+
const dlxDir = (0, import_socket.getSocketDlxDir)();
|
|
65
|
+
const absolutePath = (0, import_normalize.normalizePath)(path.resolve(filePath));
|
|
66
|
+
return absolutePath.startsWith(`${dlxDir}/`);
|
|
67
|
+
}
|
|
68
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
69
|
+
0 && (module.exports = {
|
|
70
|
+
getDlxInstalledPackageDir,
|
|
71
|
+
getDlxPackageDir,
|
|
72
|
+
getDlxPackageJsonPath,
|
|
73
|
+
getDlxPackageNodeModulesDir,
|
|
74
|
+
isInSocketDlx
|
|
75
|
+
});
|
package/dist/fs.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { Abortable } from 'events';
|
|
6
6
|
import type { MakeDirectoryOptions, ObjectEncodingOptions, OpenMode, PathLike } from 'fs';
|
|
7
|
-
import type { JsonReviver } from './json';
|
|
7
|
+
import type { JsonReviver } from './json/types';
|
|
8
8
|
import { type Remap } from './objects';
|
|
9
9
|
/**
|
|
10
10
|
* Supported text encodings for Node.js Buffers.
|
|
@@ -545,7 +545,7 @@ export declare function readFileUtf8Sync(filepath: PathLike, options?: ReadFileO
|
|
|
545
545
|
* ```
|
|
546
546
|
*/
|
|
547
547
|
/*@__NO_SIDE_EFFECTS__*/
|
|
548
|
-
export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json").JsonValue>;
|
|
548
|
+
export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json/types").JsonValue>;
|
|
549
549
|
/**
|
|
550
550
|
* Read and parse a JSON file synchronously.
|
|
551
551
|
* Reads the file as UTF-8 text and parses it as JSON.
|
|
@@ -575,7 +575,7 @@ export declare function readJson(filepath: PathLike, options?: ReadJsonOptions |
|
|
|
575
575
|
* ```
|
|
576
576
|
*/
|
|
577
577
|
/*@__NO_SIDE_EFFECTS__*/
|
|
578
|
-
export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json").JsonValue;
|
|
578
|
+
export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json/types").JsonValue;
|
|
579
579
|
/**
|
|
580
580
|
* Safely delete a file or directory asynchronously with built-in protections.
|
|
581
581
|
* Uses `del` for safer deletion that prevents removing cwd and above by default.
|
package/dist/fs.js
CHANGED
|
@@ -54,7 +54,7 @@ var import_process = require("./constants/process");
|
|
|
54
54
|
var import_arrays = require("./arrays");
|
|
55
55
|
var import_del = require("./external/del");
|
|
56
56
|
var import_globs = require("./globs");
|
|
57
|
-
var
|
|
57
|
+
var import_parse = require("./json/parse");
|
|
58
58
|
var import_objects = require("./objects");
|
|
59
59
|
var import_normalize = require("./paths/normalize");
|
|
60
60
|
var import_rewire = require("./paths/rewire");
|
|
@@ -455,7 +455,7 @@ Check file permissions or run with appropriate access.`,
|
|
|
455
455
|
}
|
|
456
456
|
return void 0;
|
|
457
457
|
}
|
|
458
|
-
return (0,
|
|
458
|
+
return (0, import_parse.jsonParse)(content, {
|
|
459
459
|
filepath: String(filepath),
|
|
460
460
|
reviver,
|
|
461
461
|
throws: shouldThrow
|
|
@@ -498,7 +498,7 @@ Check file permissions or run with appropriate access.`,
|
|
|
498
498
|
}
|
|
499
499
|
return void 0;
|
|
500
500
|
}
|
|
501
|
-
return (0,
|
|
501
|
+
return (0, import_parse.jsonParse)(content, {
|
|
502
502
|
filepath: String(filepath),
|
|
503
503
|
reviver,
|
|
504
504
|
throws: shouldThrow
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EditableJsonConstructor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Get the EditableJson class for JSON file manipulation.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { getEditableJsonClass } from '@socketsecurity/lib/json'
|
|
8
|
+
*
|
|
9
|
+
* const EditableJson = getEditableJsonClass<MyConfigType>()
|
|
10
|
+
* const config = await EditableJson.load('./config.json')
|
|
11
|
+
* config.update({ someField: 'newValue' })
|
|
12
|
+
* await config.save({ sort: true })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
16
|
+
export declare function getEditableJsonClass<T = Record<string, unknown>>(): EditableJsonConstructor<T>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with esbuild */
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var edit_exports = {};
|
|
21
|
+
__export(edit_exports, {
|
|
22
|
+
getEditableJsonClass: () => getEditableJsonClass
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(edit_exports);
|
|
25
|
+
var import_format = require("./format");
|
|
26
|
+
const identSymbol = import_format.INDENT_SYMBOL;
|
|
27
|
+
const newlineSymbol = import_format.NEWLINE_SYMBOL;
|
|
28
|
+
const JSONParse = JSON.parse;
|
|
29
|
+
let _EditableJsonClass;
|
|
30
|
+
let _fs;
|
|
31
|
+
// @__NO_SIDE_EFFECTS__
|
|
32
|
+
function getFs() {
|
|
33
|
+
if (_fs === void 0) {
|
|
34
|
+
_fs = require("node:fs");
|
|
35
|
+
}
|
|
36
|
+
return _fs;
|
|
37
|
+
}
|
|
38
|
+
async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
|
|
39
|
+
const { promises: fsPromises } = /* @__PURE__ */ getFs();
|
|
40
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
41
|
+
try {
|
|
42
|
+
await fsPromises.writeFile(filepath, content);
|
|
43
|
+
return;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const isLastAttempt = attempt === retries;
|
|
46
|
+
const isEperm = err instanceof Error && "code" in err && (err.code === "EPERM" || err.code === "EBUSY");
|
|
47
|
+
if (!isEperm || isLastAttempt) {
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
const delay = baseDelay * 2 ** attempt;
|
|
51
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function parseJson(content) {
|
|
56
|
+
return JSONParse(content);
|
|
57
|
+
}
|
|
58
|
+
async function readFile(filepath) {
|
|
59
|
+
const { promises: fsPromises } = /* @__PURE__ */ getFs();
|
|
60
|
+
return await fsPromises.readFile(filepath, "utf8");
|
|
61
|
+
}
|
|
62
|
+
// @__NO_SIDE_EFFECTS__
|
|
63
|
+
function getEditableJsonClass() {
|
|
64
|
+
if (_EditableJsonClass === void 0) {
|
|
65
|
+
_EditableJsonClass = class EditableJson {
|
|
66
|
+
_canSave = true;
|
|
67
|
+
_content = {};
|
|
68
|
+
_path = void 0;
|
|
69
|
+
_readFileContent = "";
|
|
70
|
+
_readFileJson = void 0;
|
|
71
|
+
get content() {
|
|
72
|
+
return this._content;
|
|
73
|
+
}
|
|
74
|
+
get filename() {
|
|
75
|
+
const path = this._path;
|
|
76
|
+
if (!path) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
return path;
|
|
80
|
+
}
|
|
81
|
+
get path() {
|
|
82
|
+
return this._path;
|
|
83
|
+
}
|
|
84
|
+
static async create(path, opts = {}) {
|
|
85
|
+
const instance = new EditableJson();
|
|
86
|
+
instance.create(path);
|
|
87
|
+
return opts.data ? instance.update(opts.data) : instance;
|
|
88
|
+
}
|
|
89
|
+
static async load(path, opts = {}) {
|
|
90
|
+
const instance = new EditableJson();
|
|
91
|
+
if (!opts.create) {
|
|
92
|
+
return await instance.load(path);
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
return await instance.load(path);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (!err.message.includes("ENOENT") && !err.message.includes("no such file")) {
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
return instance.create(path);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
create(path) {
|
|
104
|
+
this._path = path;
|
|
105
|
+
this._content = {};
|
|
106
|
+
this._canSave = true;
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
fromContent(data) {
|
|
110
|
+
this._content = data;
|
|
111
|
+
this._canSave = false;
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
fromJSON(data) {
|
|
115
|
+
const parsed = parseJson(data);
|
|
116
|
+
const indent = (0, import_format.detectIndent)(data);
|
|
117
|
+
const newline = (0, import_format.detectNewline)(data);
|
|
118
|
+
parsed[identSymbol] = indent;
|
|
119
|
+
parsed[newlineSymbol] = newline;
|
|
120
|
+
this._content = parsed;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
async load(path, create) {
|
|
124
|
+
this._path = path;
|
|
125
|
+
let parseErr;
|
|
126
|
+
try {
|
|
127
|
+
this._readFileContent = await readFile(this.filename);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (!create) {
|
|
130
|
+
throw err;
|
|
131
|
+
}
|
|
132
|
+
parseErr = err;
|
|
133
|
+
}
|
|
134
|
+
if (parseErr) {
|
|
135
|
+
throw parseErr;
|
|
136
|
+
}
|
|
137
|
+
this.fromJSON(this._readFileContent);
|
|
138
|
+
this._readFileJson = parseJson(this._readFileContent);
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
update(content) {
|
|
142
|
+
this._content = {
|
|
143
|
+
...this._content,
|
|
144
|
+
...content
|
|
145
|
+
};
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
async save(options) {
|
|
149
|
+
if (!this._canSave || this.content === void 0) {
|
|
150
|
+
throw new Error("No file path to save to");
|
|
151
|
+
}
|
|
152
|
+
if (!(0, import_format.shouldSave)(
|
|
153
|
+
this.content,
|
|
154
|
+
this._readFileJson,
|
|
155
|
+
this._readFileContent,
|
|
156
|
+
options
|
|
157
|
+
)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const content = (0, import_format.stripFormattingSymbols)(
|
|
161
|
+
this.content
|
|
162
|
+
);
|
|
163
|
+
const sortedContent = options?.sort ? (0, import_format.sortKeys)(content) : content;
|
|
164
|
+
const formatting = (0, import_format.getFormattingFromContent)(
|
|
165
|
+
this.content
|
|
166
|
+
);
|
|
167
|
+
const fileContent = (0, import_format.stringifyWithFormatting)(sortedContent, formatting);
|
|
168
|
+
await retryWrite(this.filename, fileContent);
|
|
169
|
+
this._readFileContent = fileContent;
|
|
170
|
+
this._readFileJson = parseJson(fileContent);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
saveSync(options) {
|
|
174
|
+
if (!this._canSave || this.content === void 0) {
|
|
175
|
+
throw new Error("No file path to save to");
|
|
176
|
+
}
|
|
177
|
+
if (!(0, import_format.shouldSave)(
|
|
178
|
+
this.content,
|
|
179
|
+
this._readFileJson,
|
|
180
|
+
this._readFileContent,
|
|
181
|
+
options
|
|
182
|
+
)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
const content = (0, import_format.stripFormattingSymbols)(
|
|
186
|
+
this.content
|
|
187
|
+
);
|
|
188
|
+
const sortedContent = options?.sort ? (0, import_format.sortKeys)(content) : content;
|
|
189
|
+
const formatting = (0, import_format.getFormattingFromContent)(
|
|
190
|
+
this.content
|
|
191
|
+
);
|
|
192
|
+
const fileContent = (0, import_format.stringifyWithFormatting)(sortedContent, formatting);
|
|
193
|
+
const fs = /* @__PURE__ */ getFs();
|
|
194
|
+
fs.writeFileSync(this.filename, fileContent);
|
|
195
|
+
this._readFileContent = fileContent;
|
|
196
|
+
this._readFileJson = parseJson(fileContent);
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
willSave(options) {
|
|
200
|
+
if (!this._canSave || this.content === void 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return (0, import_format.shouldSave)(
|
|
204
|
+
this.content,
|
|
205
|
+
this._readFileJson,
|
|
206
|
+
this._readFileContent,
|
|
207
|
+
options
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return _EditableJsonClass;
|
|
213
|
+
}
|
|
214
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
215
|
+
0 && (module.exports = {
|
|
216
|
+
getEditableJsonClass
|
|
217
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared utilities for JSON formatting preservation and manipulation.
|
|
3
|
+
* Provides functions for detecting and preserving indentation, line endings, and
|
|
4
|
+
* determining when JSON files should be saved based on content changes.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Symbols used to store formatting metadata in JSON objects.
|
|
8
|
+
*/
|
|
9
|
+
export declare const INDENT_SYMBOL: unique symbol;
|
|
10
|
+
export declare const NEWLINE_SYMBOL: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Formatting metadata for JSON files.
|
|
13
|
+
*/
|
|
14
|
+
export interface JsonFormatting {
|
|
15
|
+
indent: string | number;
|
|
16
|
+
newline: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options for determining if a save should occur.
|
|
20
|
+
*/
|
|
21
|
+
export interface ShouldSaveOptions {
|
|
22
|
+
ignoreWhitespace?: boolean;
|
|
23
|
+
sort?: boolean;
|
|
24
|
+
sortFn?: (obj: Record<string, unknown>) => Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Detect indentation from a JSON string.
|
|
28
|
+
* Supports space-based indentation (returns count) or mixed indentation (returns string).
|
|
29
|
+
*
|
|
30
|
+
* @param json - JSON string to analyze
|
|
31
|
+
* @returns Number of spaces or indentation string, defaults to 2 if not detected
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* detectIndent('{\n "key": "value"\n}') // => 2
|
|
36
|
+
* detectIndent('{\n "key": "value"\n}') // => 4
|
|
37
|
+
* detectIndent('{\n\t"key": "value"\n}') // => '\t'
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectIndent(json: string): string | number;
|
|
41
|
+
/**
|
|
42
|
+
* Detect newline character(s) from a JSON string.
|
|
43
|
+
* Supports LF (\n) and CRLF (\r\n) line endings.
|
|
44
|
+
*
|
|
45
|
+
* @param json - JSON string to analyze
|
|
46
|
+
* @returns Line ending string ('\n' or '\r\n'), defaults to '\n' if not detected
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* detectNewline('{\n "key": "value"\n}') // => '\n'
|
|
51
|
+
* detectNewline('{\r\n "key": "value"\r\n}') // => '\r\n'
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function detectNewline(json: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Extract formatting metadata from a JSON string.
|
|
57
|
+
*
|
|
58
|
+
* @param json - JSON string to analyze
|
|
59
|
+
* @returns Object containing indent and newline formatting
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const formatting = extractFormatting('{\n "key": "value"\n}')
|
|
64
|
+
* // => { indent: 2, newline: '\n' }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function extractFormatting(json: string): JsonFormatting;
|
|
68
|
+
/**
|
|
69
|
+
* Get default formatting for JSON files.
|
|
70
|
+
*
|
|
71
|
+
* @returns Default formatting (2 spaces, LF line endings)
|
|
72
|
+
*/
|
|
73
|
+
export declare function getDefaultFormatting(): JsonFormatting;
|
|
74
|
+
/**
|
|
75
|
+
* Sort object keys alphabetically.
|
|
76
|
+
* Creates a new object with sorted keys (does not mutate input).
|
|
77
|
+
*
|
|
78
|
+
* @param obj - Object to sort
|
|
79
|
+
* @returns New object with alphabetically sorted keys
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* sortKeys({ z: 3, a: 1, m: 2 })
|
|
84
|
+
* // => { a: 1, m: 2, z: 3 }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare function sortKeys(obj: Record<string, unknown>): Record<string, unknown>;
|
|
88
|
+
/**
|
|
89
|
+
* Stringify JSON with specific formatting.
|
|
90
|
+
* Applies indentation and line ending preferences.
|
|
91
|
+
*
|
|
92
|
+
* @param content - Object to stringify
|
|
93
|
+
* @param formatting - Formatting preferences (indent and newline)
|
|
94
|
+
* @returns Formatted JSON string with trailing newline
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* stringifyWithFormatting(
|
|
99
|
+
* { key: 'value' },
|
|
100
|
+
* { indent: 4, newline: '\r\n' }
|
|
101
|
+
* )
|
|
102
|
+
* // => '{\r\n "key": "value"\r\n}\r\n'
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function stringifyWithFormatting(content: Record<string, unknown>, formatting: JsonFormatting): string;
|
|
106
|
+
/**
|
|
107
|
+
* Strip formatting symbols from content object.
|
|
108
|
+
* Removes Symbol.for('indent') and Symbol.for('newline') from the object.
|
|
109
|
+
*
|
|
110
|
+
* @param content - Content object with potential symbol properties
|
|
111
|
+
* @returns Object with symbols removed
|
|
112
|
+
*/
|
|
113
|
+
export declare function stripFormattingSymbols(content: Record<string | symbol, unknown>): Record<string, unknown>;
|
|
114
|
+
/**
|
|
115
|
+
* Extract formatting from content object that has symbol-based metadata.
|
|
116
|
+
*
|
|
117
|
+
* @param content - Content object with Symbol.for('indent') and Symbol.for('newline')
|
|
118
|
+
* @returns Formatting metadata, or defaults if symbols not present
|
|
119
|
+
*/
|
|
120
|
+
export declare function getFormattingFromContent(content: Record<string | symbol, unknown>): JsonFormatting;
|
|
121
|
+
/**
|
|
122
|
+
* Determine if content should be saved based on changes and options.
|
|
123
|
+
* Compares current content with original content and respects options like
|
|
124
|
+
* ignoreWhitespace and sort.
|
|
125
|
+
*
|
|
126
|
+
* @param currentContent - Current content object (may include formatting symbols)
|
|
127
|
+
* @param originalContent - Original content for comparison (may include formatting symbols)
|
|
128
|
+
* @param originalFileContent - Original file content as string (for whitespace comparison)
|
|
129
|
+
* @param options - Options controlling save behavior
|
|
130
|
+
* @returns true if content should be saved, false otherwise
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const current = { key: 'new-value', [Symbol.for('indent')]: 2 }
|
|
135
|
+
* const original = { key: 'old-value', [Symbol.for('indent')]: 2 }
|
|
136
|
+
* shouldSave(current, original, '{\n "key": "old-value"\n}\n')
|
|
137
|
+
* // => true
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export declare function shouldSave(currentContent: Record<string | symbol, unknown>, originalContent: Record<string | symbol, unknown> | undefined, originalFileContent: string, options?: ShouldSaveOptions): boolean;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Socket Lib - Built with esbuild */
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var format_exports = {};
|
|
21
|
+
__export(format_exports, {
|
|
22
|
+
INDENT_SYMBOL: () => INDENT_SYMBOL,
|
|
23
|
+
NEWLINE_SYMBOL: () => NEWLINE_SYMBOL,
|
|
24
|
+
detectIndent: () => detectIndent,
|
|
25
|
+
detectNewline: () => detectNewline,
|
|
26
|
+
extractFormatting: () => extractFormatting,
|
|
27
|
+
getDefaultFormatting: () => getDefaultFormatting,
|
|
28
|
+
getFormattingFromContent: () => getFormattingFromContent,
|
|
29
|
+
shouldSave: () => shouldSave,
|
|
30
|
+
sortKeys: () => sortKeys,
|
|
31
|
+
stringifyWithFormatting: () => stringifyWithFormatting,
|
|
32
|
+
stripFormattingSymbols: () => stripFormattingSymbols
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(format_exports);
|
|
35
|
+
const INDENT_SYMBOL = Symbol.for("indent");
|
|
36
|
+
const NEWLINE_SYMBOL = Symbol.for("newline");
|
|
37
|
+
function detectIndent(json) {
|
|
38
|
+
const match = json.match(/^[{[][\r\n]+(\s+)/m);
|
|
39
|
+
if (!match) {
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
const indent = match[1];
|
|
43
|
+
if (/^ +$/.test(indent)) {
|
|
44
|
+
return indent.length;
|
|
45
|
+
}
|
|
46
|
+
return indent;
|
|
47
|
+
}
|
|
48
|
+
function detectNewline(json) {
|
|
49
|
+
const match = json.match(/\r?\n/);
|
|
50
|
+
return match ? match[0] : "\n";
|
|
51
|
+
}
|
|
52
|
+
function extractFormatting(json) {
|
|
53
|
+
return {
|
|
54
|
+
indent: detectIndent(json),
|
|
55
|
+
newline: detectNewline(json)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function getDefaultFormatting() {
|
|
59
|
+
return {
|
|
60
|
+
indent: 2,
|
|
61
|
+
newline: "\n"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function sortKeys(obj) {
|
|
65
|
+
const sorted = { __proto__: null };
|
|
66
|
+
const keys = Object.keys(obj).sort();
|
|
67
|
+
for (const key of keys) {
|
|
68
|
+
sorted[key] = obj[key];
|
|
69
|
+
}
|
|
70
|
+
return sorted;
|
|
71
|
+
}
|
|
72
|
+
function stringifyWithFormatting(content, formatting) {
|
|
73
|
+
const { indent, newline } = formatting;
|
|
74
|
+
const format = indent === void 0 || indent === null ? " " : indent;
|
|
75
|
+
const eol = newline === void 0 || newline === null ? "\n" : newline;
|
|
76
|
+
return `${JSON.stringify(content, void 0, format)}
|
|
77
|
+
`.replace(/\n/g, eol);
|
|
78
|
+
}
|
|
79
|
+
function stripFormattingSymbols(content) {
|
|
80
|
+
const {
|
|
81
|
+
[INDENT_SYMBOL]: _indent,
|
|
82
|
+
[NEWLINE_SYMBOL]: _newline,
|
|
83
|
+
...rest
|
|
84
|
+
} = content;
|
|
85
|
+
return rest;
|
|
86
|
+
}
|
|
87
|
+
function getFormattingFromContent(content) {
|
|
88
|
+
const indent = content[INDENT_SYMBOL];
|
|
89
|
+
const newline = content[NEWLINE_SYMBOL];
|
|
90
|
+
return {
|
|
91
|
+
indent: indent === void 0 || indent === null ? 2 : indent,
|
|
92
|
+
newline: newline === void 0 || newline === null ? "\n" : newline
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function shouldSave(currentContent, originalContent, originalFileContent, options = {}) {
|
|
96
|
+
const { ignoreWhitespace = false, sort = false, sortFn } = options;
|
|
97
|
+
const content = stripFormattingSymbols(currentContent);
|
|
98
|
+
const sortedContent = sortFn ? sortFn(content) : sort ? sortKeys(content) : content;
|
|
99
|
+
const origContent = originalContent ? stripFormattingSymbols(originalContent) : {};
|
|
100
|
+
if (ignoreWhitespace) {
|
|
101
|
+
const util = require("node:util");
|
|
102
|
+
return !util.isDeepStrictEqual(sortedContent, origContent);
|
|
103
|
+
}
|
|
104
|
+
const formatting = getFormattingFromContent(currentContent);
|
|
105
|
+
const newFileContent = stringifyWithFormatting(sortedContent, formatting);
|
|
106
|
+
return newFileContent.trim() !== originalFileContent.trim();
|
|
107
|
+
}
|
|
108
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
109
|
+
0 && (module.exports = {
|
|
110
|
+
INDENT_SYMBOL,
|
|
111
|
+
NEWLINE_SYMBOL,
|
|
112
|
+
detectIndent,
|
|
113
|
+
detectNewline,
|
|
114
|
+
extractFormatting,
|
|
115
|
+
getDefaultFormatting,
|
|
116
|
+
getFormattingFromContent,
|
|
117
|
+
shouldSave,
|
|
118
|
+
sortKeys,
|
|
119
|
+
stringifyWithFormatting,
|
|
120
|
+
stripFormattingSymbols
|
|
121
|
+
});
|