dcs-git-utils 1.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/.github/workflows/pr.yml +34 -0
- package/.github/workflows/release.yml +65 -0
- package/.vscode/launch.json +23 -0
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/config.json +4 -0
- package/dist/compression.js +110 -0
- package/dist/compression.js.map +1 -0
- package/dist/config.js +140 -0
- package/dist/config.js.map +1 -0
- package/dist/fengari-wrapper.js +79 -0
- package/dist/fengari-wrapper.js.map +1 -0
- package/dist/files/file-picker.js +77 -0
- package/dist/files/file-picker.js.map +1 -0
- package/dist/files/miz-selector.js +24 -0
- package/dist/files/miz-selector.js.map +1 -0
- package/dist/lua +73 -0
- package/dist/main.js +50 -0
- package/dist/main.js.map +1 -0
- package/dist/sorting.js +144 -0
- package/dist/sorting.js.map +1 -0
- package/dist/watchers.js +83 -0
- package/dist/watchers.js.map +1 -0
- package/lua/sorter_lib.lua +73 -0
- package/package.json +62 -0
- package/src/compression.ts +88 -0
- package/src/config.ts +120 -0
- package/src/fengari-wrapper.ts +68 -0
- package/src/fengari.d.ts +1 -0
- package/src/files/file-picker.ts +64 -0
- package/src/files/miz-selector.ts +10 -0
- package/src/main.ts +49 -0
- package/src/sorting.ts +128 -0
- package/src/watchers.ts +58 -0
- package/tests/sorting.spec.ts +26 -0
- package/tsconfig.json +101 -0
- package/vitest.config.ts +10 -0
package/dist/lua
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
-- sorter_lib.lua
|
|
2
|
+
|
|
3
|
+
local global_var_name = ...
|
|
4
|
+
local target_table = _G[global_var_name]
|
|
5
|
+
|
|
6
|
+
if type(target_table) ~= "table" then
|
|
7
|
+
return nil, "Table '" .. tostring(global_var_name) .. "' not found."
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
-- CONFIGURATION
|
|
11
|
+
-- true = "key = value" (Clean, standard Lua)
|
|
12
|
+
-- false = "['key'] = value" (Verbose, preserves quotes)
|
|
13
|
+
local SIMPLIFY_KEYS = true
|
|
14
|
+
|
|
15
|
+
-- Keywords that MUST have brackets if used as keys
|
|
16
|
+
local keywords = {
|
|
17
|
+
["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, ["elseif"]=true, ["end"]=true,
|
|
18
|
+
["false"]=true, ["for"]=true, ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true,
|
|
19
|
+
["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true, ["repeat"]=true, ["return"]=true,
|
|
20
|
+
["then"]=true, ["true"]=true, ["until"]=true, ["while"]=true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
local function serialize_sorted(tbl, indent_level)
|
|
24
|
+
indent_level = indent_level or 1
|
|
25
|
+
local indent_str = string.rep(" ", indent_level)
|
|
26
|
+
local result = "{\n"
|
|
27
|
+
|
|
28
|
+
local keys = {}
|
|
29
|
+
for k in pairs(tbl) do table.insert(keys, k) end
|
|
30
|
+
|
|
31
|
+
table.sort(keys, function(a, b)
|
|
32
|
+
local ta, tb = type(a), type(b)
|
|
33
|
+
if ta ~= tb then return ta == "number" end
|
|
34
|
+
if ta == "number" then return a < b end
|
|
35
|
+
return tostring(a) < tostring(b)
|
|
36
|
+
end)
|
|
37
|
+
|
|
38
|
+
for _, k in ipairs(keys) do
|
|
39
|
+
local v = tbl[k]
|
|
40
|
+
local key_str
|
|
41
|
+
|
|
42
|
+
if type(k) == "number" then
|
|
43
|
+
key_str = "[" .. tostring(k) .. "]"
|
|
44
|
+
|
|
45
|
+
elseif type(k) == "string" then
|
|
46
|
+
-- CHECK: Do we want to simplify "['key']" to "key"?
|
|
47
|
+
if SIMPLIFY_KEYS and k:match("^[%a_][%w_]*$") and not keywords[k] then
|
|
48
|
+
key_str = k -- Output: airports =
|
|
49
|
+
else
|
|
50
|
+
key_str = '["' .. k .. '"]' -- Output: ["airports"] =
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
else
|
|
54
|
+
key_str = "[" .. tostring(k) .. "]"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
local val_str
|
|
58
|
+
if type(v) == "table" then
|
|
59
|
+
val_str = serialize_sorted(v, indent_level + 1)
|
|
60
|
+
elseif type(v) == "string" then
|
|
61
|
+
val_str = string.format("%q", v)
|
|
62
|
+
else
|
|
63
|
+
val_str = tostring(v)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
result = result .. indent_str .. key_str .. " = " .. val_str .. ",\n"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
result = result .. string.rep(" ", indent_level - 1) .. "}"
|
|
70
|
+
return result
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return global_var_name .. " = " .. serialize_sorted(target_table)
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
17
|
+
const node_fs_1 = require("node:fs");
|
|
18
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
19
|
+
const watchers_1 = require("./watchers");
|
|
20
|
+
const compression_1 = require("./compression");
|
|
21
|
+
const sorting_1 = require("./sorting");
|
|
22
|
+
const config_1 = require("./config");
|
|
23
|
+
const [_0, _1, file] = node_process_1.default.argv;
|
|
24
|
+
const backupMiz = (filepath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
if (!(filepath === null || filepath === void 0 ? void 0 : filepath.indexOf(".miz"))) {
|
|
26
|
+
throw new Error('no miz file ext');
|
|
27
|
+
}
|
|
28
|
+
const fileWithoutExt = filepath.replace(node_path_1.default.extname(filepath), "");
|
|
29
|
+
yield node_fs_1.promises.copyFile(filepath, `${fileWithoutExt}_backup_${new Date().toISOString().replace(/:/g, '-')}.miz`);
|
|
30
|
+
});
|
|
31
|
+
const initialize = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
32
|
+
const { missionPath, outDir, } = yield (0, config_1.initializeConfig)({ file });
|
|
33
|
+
backupMiz(missionPath);
|
|
34
|
+
if ((0, node_fs_1.existsSync)(outDir)) {
|
|
35
|
+
console.log('out exists, using this as source');
|
|
36
|
+
yield (0, compression_1.handleArchive)(outDir, missionPath);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.log("Initial unpack of .miz");
|
|
40
|
+
const files = yield (0, compression_1.unpackMiz)(missionPath, outDir);
|
|
41
|
+
const filePaths = files.filter(f => f.type === "file").map(f => node_path_1.default.join(outDir, f.path));
|
|
42
|
+
yield (0, sorting_1.sortFiles)(filePaths);
|
|
43
|
+
}
|
|
44
|
+
return { mizPath: missionPath, outDir };
|
|
45
|
+
});
|
|
46
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
47
|
+
const { mizPath, outDir } = yield initialize();
|
|
48
|
+
(0, watchers_1.startWatchers)(mizPath, outDir);
|
|
49
|
+
}))();
|
|
50
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAEA,gEAAmC;AACnC,qCAAqD;AACrD,0DAA4B;AAC5B,yCAA2C;AAC3C,+CAAyD;AACzD,uCAAsC;AACtC,qCAA4C;AAE5C,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,sBAAO,CAAC,IAAI,CAAC;AAEpC,MAAM,SAAS,GAAG,CAAO,QAAgB,EAAE,EAAE;IAEzC,IAAI,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,CAAC,MAAM,CAAC,CAAA,EAAE;QAC5B,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;KACtC;IAED,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IACpE,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,cAAc,WAAW,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AAC/G,CAAC,CAAA,CAAA;AAED,MAAM,UAAU,GAAG,GAAS,EAAE;IAE1B,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,MAAM,IAAA,yBAAgB,EAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAElE,SAAS,CAAC,WAAW,CAAC,CAAC;IAEvB,IAAI,IAAA,oBAAU,EAAC,MAAM,CAAC,EAAE;QACpB,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,MAAM,IAAA,2BAAa,EAAC,MAAM,EAAE,WAAW,CAAC,CAAC;KAC5C;SAAM;QACH,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,IAAA,uBAAS,EAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,mBAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3F,MAAM,IAAA,mBAAS,EAAC,SAAS,CAAC,CAAC;KAC9B;IAED,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AAC5C,CAAC,CAAA,CAAA;AAGD,CAAC,GAAS,EAAE;IAER,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,EAAE,CAAC;IAE/C,IAAA,wBAAa,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC,CAAA,CAAC,EAAE,CAAA"}
|
package/dist/sorting.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.sortFiles = exports.jsonSort = void 0;
|
|
39
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
40
|
+
const luaparse_1 = __importDefault(require("luaparse"));
|
|
41
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
42
|
+
const _ = __importStar(require("lodash"));
|
|
43
|
+
const fengari_wrapper_1 = require("./fengari-wrapper");
|
|
44
|
+
const jsonExtensions = ["json", "dtc"];
|
|
45
|
+
/**
|
|
46
|
+
* Recursively sorts the keys of an object or elements of an array.
|
|
47
|
+
* This function handles arrays, plain objects, and primitives.
|
|
48
|
+
*
|
|
49
|
+
* @param obj The data structure to sort.
|
|
50
|
+
* @returns A new structure with sorted keys/elements.
|
|
51
|
+
*/
|
|
52
|
+
function lodashSortKeysDeep(obj) {
|
|
53
|
+
if (_.isArray(obj)) {
|
|
54
|
+
// Handle Arrays: Recursively sort each element
|
|
55
|
+
return obj.map(lodashSortKeysDeep);
|
|
56
|
+
}
|
|
57
|
+
if (!_.isPlainObject(obj)) {
|
|
58
|
+
// Handle Primitives and Non-Plain Objects: Return as is
|
|
59
|
+
return obj;
|
|
60
|
+
}
|
|
61
|
+
// Handle Plain Objects: Get sorted keys and build the new object
|
|
62
|
+
return _.keys(obj)
|
|
63
|
+
.sort() // Sort the keys alphabetically
|
|
64
|
+
.reduce((sortedObj, key) => {
|
|
65
|
+
// Recursively sort the value for the current key
|
|
66
|
+
sortedObj[key] = lodashSortKeysDeep(obj[key]);
|
|
67
|
+
return sortedObj;
|
|
68
|
+
}, {});
|
|
69
|
+
}
|
|
70
|
+
const checkCharCount = (old, sorted) => {
|
|
71
|
+
return old.replace(/\s/g, "").length === sorted.replace(/\s/g, "").length;
|
|
72
|
+
};
|
|
73
|
+
const jsonSort = (filepath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
const fileString = yield promises_1.default.readFile(filepath, { encoding: 'utf-8' });
|
|
75
|
+
const useCRLF = fileString.includes("\r\n");
|
|
76
|
+
const EOL = useCRLF ? "\r\n" : "\n";
|
|
77
|
+
const obj = JSON.parse(fileString);
|
|
78
|
+
const sorted = lodashSortKeysDeep(obj);
|
|
79
|
+
const stringified = JSON.stringify(sorted);
|
|
80
|
+
if (!checkCharCount(fileString, stringified)) {
|
|
81
|
+
throw new Error(`mismatching input file char count to sorted`);
|
|
82
|
+
}
|
|
83
|
+
const resultString = stringified.replace(/\r?\n/g, EOL);
|
|
84
|
+
yield promises_1.default.writeFile(filepath, resultString, 'utf-8');
|
|
85
|
+
console.log(`Sorted JSON: ${filepath}`);
|
|
86
|
+
});
|
|
87
|
+
exports.jsonSort = jsonSort;
|
|
88
|
+
const isLuaSortable = (filepath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const filename = node_path_1.default.basename(filepath);
|
|
90
|
+
const extension = node_path_1.default.extname(filename);
|
|
91
|
+
const lua = yield promises_1.default.readFile(filepath, { encoding: 'utf-8' });
|
|
92
|
+
if (extension && extension !== "lua") {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const ast = luaparse_1.default.parse(lua);
|
|
97
|
+
if (ast.type !== 'Chunk' || !ast.body) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
for (const statement of ast.body) {
|
|
101
|
+
let isMatch = false;
|
|
102
|
+
// Check for LOCAL assignment: local Config = {...}
|
|
103
|
+
if (statement.type === 'LocalStatement') {
|
|
104
|
+
isMatch = statement.variables.some(v => v.name === filename);
|
|
105
|
+
if (isMatch)
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
// Check for GLOBAL assignment: Config = {...}
|
|
109
|
+
else if (statement.type === 'AssignmentStatement') {
|
|
110
|
+
isMatch = statement.variables.some(v => v.type === 'Identifier' && v.name === filename);
|
|
111
|
+
if (isMatch)
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (_a) {
|
|
117
|
+
console.log(`luaparse failed: ${filename}`);
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
});
|
|
121
|
+
const sortFile = (filepath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
|
+
const extension = node_path_1.default.extname(filepath);
|
|
123
|
+
try {
|
|
124
|
+
if (extension && jsonExtensions.includes(extension)) {
|
|
125
|
+
yield (0, exports.jsonSort)(filepath);
|
|
126
|
+
}
|
|
127
|
+
else if (yield isLuaSortable(filepath)) {
|
|
128
|
+
yield (0, fengari_wrapper_1.fengariSortFile)(filepath);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log(`skipping: ${filepath}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
console.error(err);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
const sortFiles = (filePaths) => __awaiter(void 0, void 0, void 0, function* () {
|
|
139
|
+
for (const filepath of filePaths) {
|
|
140
|
+
yield sortFile(filepath);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
exports.sortFiles = sortFiles;
|
|
144
|
+
//# sourceMappingURL=sorting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sorting.js","sourceRoot":"","sources":["../src/sorting.ts"],"names":[],"mappings":"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"}
|
package/dist/watchers.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.startWatchers = void 0;
|
|
39
|
+
const chokidar = __importStar(require("chokidar"));
|
|
40
|
+
const sorting_1 = require("./sorting");
|
|
41
|
+
const compression_1 = require("./compression");
|
|
42
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
43
|
+
const lodash_1 = require("lodash");
|
|
44
|
+
let locked = false;
|
|
45
|
+
const unlock = (0, lodash_1.debounce)(() => {
|
|
46
|
+
locked = false;
|
|
47
|
+
}, 3000);
|
|
48
|
+
const startWatchers = (mizPath, outDir) => {
|
|
49
|
+
chokidar.watch(mizPath, { awaitWriteFinish: true, ignoreInitial: true }).on("change", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
if (locked) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log("miz changed");
|
|
54
|
+
locked = true;
|
|
55
|
+
unlock.cancel();
|
|
56
|
+
const files = yield (0, compression_1.unpackMiz)(mizPath, outDir);
|
|
57
|
+
const filePaths = files.map(f => node_path_1.default.join(outDir, f.path));
|
|
58
|
+
yield (0, sorting_1.sortFiles)(filePaths);
|
|
59
|
+
yield (0, compression_1.handleArchive)(outDir, mizPath);
|
|
60
|
+
unlock();
|
|
61
|
+
}));
|
|
62
|
+
const outChange = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
if (locked) {
|
|
64
|
+
unlock();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log("out changed");
|
|
68
|
+
locked = true;
|
|
69
|
+
unlock.cancel();
|
|
70
|
+
yield (0, compression_1.handleArchive)(outDir, mizPath);
|
|
71
|
+
unlock();
|
|
72
|
+
});
|
|
73
|
+
chokidar.watch(outDir, { ignoreInitial: true })
|
|
74
|
+
.on("add", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
75
|
+
yield outChange();
|
|
76
|
+
})).on("addDir", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
77
|
+
yield outChange();
|
|
78
|
+
})).on("change", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
|
+
yield outChange();
|
|
80
|
+
}));
|
|
81
|
+
};
|
|
82
|
+
exports.startWatchers = startWatchers;
|
|
83
|
+
//# sourceMappingURL=watchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watchers.js","sourceRoot":"","sources":["../src/watchers.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,mDAAqC;AACrC,uCAAsC;AACtC,+CAAyD;AACzD,0DAA6B;AAC7B,mCAAkC;AAElC,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,MAAM,MAAM,GAAG,IAAA,iBAAQ,EAAC,GAAG,EAAE;IACzB,MAAM,GAAG,KAAK,CAAC;AACnB,CAAC,EAAE,IAAI,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,OAAe,EAAE,MAAc,EAAE,EAAE;IAG7D,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAS,EAAE;QAE7F,IAAI,MAAM,EAAE;YACR,OAAO;SACV;QAED,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE3B,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,MAAM,IAAA,uBAAS,EAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,mBAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5D,MAAM,IAAA,mBAAS,EAAC,SAAS,CAAC,CAAC;QAC3B,MAAM,IAAA,2BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,EAAE,CAAC;IACb,CAAC,CAAA,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,GAAS,EAAE;QAEzB,IAAI,MAAM,EAAE;YACR,MAAM,EAAE,CAAC;YACT,OAAO;SACV;QAED,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE3B,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,IAAA,2BAAa,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,EAAE,CAAC;IACb,CAAC,CAAA,CAAA;IAED,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC1C,EAAE,CAAC,KAAK,EAAE,GAAS,EAAE;QAClB,MAAM,SAAS,EAAE,CAAC;IACtB,CAAC,CAAA,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAS,EAAE;QACvB,MAAM,SAAS,EAAE,CAAC;IACtB,CAAC,CAAA,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAS,EAAE;QACvB,MAAM,SAAS,EAAE,CAAC;IACtB,CAAC,CAAA,CAAC,CAAA;AAEV,CAAC,CAAA;AA5CY,QAAA,aAAa,iBA4CzB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
-- sorter_lib.lua
|
|
2
|
+
|
|
3
|
+
local global_var_name = ...
|
|
4
|
+
local target_table = _G[global_var_name]
|
|
5
|
+
|
|
6
|
+
if type(target_table) ~= "table" then
|
|
7
|
+
return nil, "Table '" .. tostring(global_var_name) .. "' not found."
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
-- CONFIGURATION
|
|
11
|
+
-- true = "key = value" (Clean, standard Lua)
|
|
12
|
+
-- false = "['key'] = value" (Verbose, preserves quotes)
|
|
13
|
+
local SIMPLIFY_KEYS = true
|
|
14
|
+
|
|
15
|
+
-- Keywords that MUST have brackets if used as keys
|
|
16
|
+
local keywords = {
|
|
17
|
+
["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, ["elseif"]=true, ["end"]=true,
|
|
18
|
+
["false"]=true, ["for"]=true, ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true,
|
|
19
|
+
["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true, ["repeat"]=true, ["return"]=true,
|
|
20
|
+
["then"]=true, ["true"]=true, ["until"]=true, ["while"]=true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
local function serialize_sorted(tbl, indent_level)
|
|
24
|
+
indent_level = indent_level or 1
|
|
25
|
+
local indent_str = string.rep(" ", indent_level)
|
|
26
|
+
local result = "{\n"
|
|
27
|
+
|
|
28
|
+
local keys = {}
|
|
29
|
+
for k in pairs(tbl) do table.insert(keys, k) end
|
|
30
|
+
|
|
31
|
+
table.sort(keys, function(a, b)
|
|
32
|
+
local ta, tb = type(a), type(b)
|
|
33
|
+
if ta ~= tb then return ta == "number" end
|
|
34
|
+
if ta == "number" then return a < b end
|
|
35
|
+
return tostring(a) < tostring(b)
|
|
36
|
+
end)
|
|
37
|
+
|
|
38
|
+
for _, k in ipairs(keys) do
|
|
39
|
+
local v = tbl[k]
|
|
40
|
+
local key_str
|
|
41
|
+
|
|
42
|
+
if type(k) == "number" then
|
|
43
|
+
key_str = "[" .. tostring(k) .. "]"
|
|
44
|
+
|
|
45
|
+
elseif type(k) == "string" then
|
|
46
|
+
-- CHECK: Do we want to simplify "['key']" to "key"?
|
|
47
|
+
if SIMPLIFY_KEYS and k:match("^[%a_][%w_]*$") and not keywords[k] then
|
|
48
|
+
key_str = k -- Output: airports =
|
|
49
|
+
else
|
|
50
|
+
key_str = '["' .. k .. '"]' -- Output: ["airports"] =
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
else
|
|
54
|
+
key_str = "[" .. tostring(k) .. "]"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
local val_str
|
|
58
|
+
if type(v) == "table" then
|
|
59
|
+
val_str = serialize_sorted(v, indent_level + 1)
|
|
60
|
+
elseif type(v) == "string" then
|
|
61
|
+
val_str = string.format("%q", v)
|
|
62
|
+
else
|
|
63
|
+
val_str = tostring(v)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
result = result .. indent_str .. key_str .. " = " .. val_str .. ",\n"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
result = result .. string.rep(" ", indent_level - 1) .. "}"
|
|
70
|
+
return result
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
return global_var_name .. " = " .. serialize_sorted(target_table)
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dcs-git-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/main.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dcs-git-utils": "dist/main.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"prestart": "npm run compile && npm run copy-assets",
|
|
11
|
+
"clean": "shx rm -rf dist && shx rm -rf bin",
|
|
12
|
+
"compile": "tsc",
|
|
13
|
+
"build": "npm run clean && npm run compile && npm run copy-assets",
|
|
14
|
+
"copy-assets": "shx cp lua/sorter_lib.lua dist/lua",
|
|
15
|
+
"start": "node dist/main.js",
|
|
16
|
+
"package": "pkg .",
|
|
17
|
+
"test": "vitest",
|
|
18
|
+
"test:run": "vitest run",
|
|
19
|
+
"test:ci": "vitest"
|
|
20
|
+
},
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"pkg": {
|
|
24
|
+
"scripts": [
|
|
25
|
+
"dist/**/*.js",
|
|
26
|
+
"!dist/**/*.test.js",
|
|
27
|
+
"!dist/**/*.spec.js",
|
|
28
|
+
"!dist/tests/**/*",
|
|
29
|
+
"dist/**/*.js"
|
|
30
|
+
],
|
|
31
|
+
"assets": [
|
|
32
|
+
"./lua/sorter_lib.lua"
|
|
33
|
+
],
|
|
34
|
+
"targets": [
|
|
35
|
+
"node18-win-x64",
|
|
36
|
+
"node18-linux-x64"
|
|
37
|
+
],
|
|
38
|
+
"outputPath": "bin"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/archiver": "^6.0.3",
|
|
42
|
+
"@types/chokidar": "^2.1.7",
|
|
43
|
+
"@types/decompress": "^4.2.7",
|
|
44
|
+
"@types/inquirer": "^8.2.12",
|
|
45
|
+
"@types/lodash": "^4.17.20",
|
|
46
|
+
"@types/luaparse": "^0.2.13",
|
|
47
|
+
"@types/node": "^24.0.10",
|
|
48
|
+
"pkg": "^5.8.1",
|
|
49
|
+
"shx": "^0.4.0",
|
|
50
|
+
"vitest": "^4.0.14"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"archiver": "^7.0.1",
|
|
54
|
+
"chokidar": "^3.6.0",
|
|
55
|
+
"decompress": "^4.2.1",
|
|
56
|
+
"fengari": "^0.1.4",
|
|
57
|
+
"fengari-interop": "^0.1.3",
|
|
58
|
+
"inquirer": "^8.2.7",
|
|
59
|
+
"lodash": "^4.17.21",
|
|
60
|
+
"luaparse": "^0.3.1"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
|
|
2
|
+
import fs, { promises } from "node:fs";
|
|
3
|
+
import archiver from "archiver";
|
|
4
|
+
import decompress from "decompress";
|
|
5
|
+
|
|
6
|
+
export async function checkStable(
|
|
7
|
+
filePath: string,
|
|
8
|
+
stableChecks = 10, // how many *consecutive* stable reads required
|
|
9
|
+
interval = 250 // ms between checks
|
|
10
|
+
): Promise<boolean> {
|
|
11
|
+
|
|
12
|
+
let lastSize: number | null = null;
|
|
13
|
+
let stableCount = 0;
|
|
14
|
+
|
|
15
|
+
while (stableCount < stableChecks) {
|
|
16
|
+
let stat;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
stat = await promises.stat(filePath);
|
|
20
|
+
} catch {
|
|
21
|
+
// file might not exist yet – reset
|
|
22
|
+
lastSize = null;
|
|
23
|
+
stableCount = 0;
|
|
24
|
+
await new Promise((res) => setTimeout(res, interval));
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const size = stat.size;
|
|
29
|
+
|
|
30
|
+
if (lastSize !== null && size === lastSize) {
|
|
31
|
+
stableCount++;
|
|
32
|
+
} else {
|
|
33
|
+
stableCount = 0; // reset if changed
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
lastSize = size;
|
|
37
|
+
|
|
38
|
+
await new Promise((res) => setTimeout(res, interval));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return true; // stable!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const handleArchive = (dirPath: string, mizpath: string) => {
|
|
45
|
+
return new Promise<void>(async (resolve, reject) => {
|
|
46
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
47
|
+
|
|
48
|
+
const output = fs.createWriteStream(mizpath);
|
|
49
|
+
|
|
50
|
+
// Handle events
|
|
51
|
+
output.on('close', function () {
|
|
52
|
+
console.log(`Archive created successfully at ${mizpath}, total bytes: ${archive.pointer()}`);
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
archive.on('error', function (err) {
|
|
57
|
+
throw err;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Pipe archive data to the file
|
|
61
|
+
archive.pipe(output);
|
|
62
|
+
|
|
63
|
+
// Append directory
|
|
64
|
+
archive.directory(dirPath, false); // false = no root folder in zip
|
|
65
|
+
|
|
66
|
+
// Finalize the archive
|
|
67
|
+
await archive.finalize();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const unpackMiz = async (path: string, outPath: string) => {
|
|
72
|
+
try {
|
|
73
|
+
|
|
74
|
+
console.log('decompressing');
|
|
75
|
+
|
|
76
|
+
const result = await decompress(path, outPath);
|
|
77
|
+
|
|
78
|
+
if (!result.length) {
|
|
79
|
+
throw new Error('Decompression yielded no results, something is wrong with the .miz');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return result;
|
|
83
|
+
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error(err);
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
}
|