@stonyx/utils 0.0.4 → 0.1.1
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/ci.yml +31 -0
- package/README.md +5 -0
- package/package.json +3 -2
- package/src/file.js +45 -7
- package/src/object.js +19 -27
- package/.nvmrc +0 -1
- package/test/unit/object-test.js +0 -32
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- dev
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.head_ref || github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v3
|
|
20
|
+
|
|
21
|
+
- name: Set up Node.js
|
|
22
|
+
uses: actions/setup-node@v3
|
|
23
|
+
with:
|
|
24
|
+
node-version: 22.18.0
|
|
25
|
+
cache: 'npm'
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
|
|
30
|
+
- name: Run tests
|
|
31
|
+
run: npm test
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# stonyx-utils
|
|
2
2
|
|
|
3
|
+
# TODO: Generate documentation for all utils
|
|
4
|
+
|
|
3
5
|
## Running the test suite
|
|
4
6
|
```
|
|
5
7
|
npm test
|
|
@@ -27,3 +29,6 @@ The File utils wrap the `path` and `fs` library to allow consuming classes to ma
|
|
|
27
29
|
| `rawName` | **Boolean** | *false* | When set to true, `forEachFileImport` will not convert the file name to be camelCase and leave it raw instead |
|
|
28
30
|
| `ignoreAccessFailure` | **Boolean** | *false* | When set to true, failure to load directory will be ignored |
|
|
29
31
|
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
Apache — do what you want, just keep attribution.
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"keywords": [
|
|
4
4
|
"stonyx-module"
|
|
5
5
|
],
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.1.1",
|
|
7
7
|
"description": "Utils module for Stonyx Framework",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
@@ -24,5 +24,6 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"fs": "^0.0.1-security",
|
|
26
26
|
"qunit": "^2.24.1"
|
|
27
|
-
}
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {}
|
|
28
29
|
}
|
package/src/file.js
CHANGED
|
@@ -4,36 +4,64 @@ import { objToJson } from '@stonyx/utils/object';
|
|
|
4
4
|
import { promises as fsp } from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
|
|
7
|
-
export async function createFile(filePath, data, {
|
|
7
|
+
export async function createFile(filePath, data, options={}) {
|
|
8
8
|
try {
|
|
9
|
-
|
|
9
|
+
filePath = path.resolve(filePath);
|
|
10
|
+
|
|
11
|
+
await createDirectory(path.dirname(filePath));
|
|
12
|
+
await fsp.writeFile(filePath, options.json ? objToJson(data) : data, 'utf8');
|
|
10
13
|
} catch (error) {
|
|
11
14
|
throw new Error(error);
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
export async function updateFile(filePath, data, {
|
|
18
|
+
export async function updateFile(filePath, data, options={}) {
|
|
16
19
|
try {
|
|
17
20
|
await fsp.access(filePath);
|
|
18
21
|
|
|
19
22
|
const swapFile = `${filePath}.temp-${getTimestamp()}`;
|
|
20
|
-
await fsp.writeFile(swapFile, json ? objToJson(data) : data);
|
|
21
|
-
await fsp.rename(swapFile,
|
|
23
|
+
await fsp.writeFile(swapFile, options.json ? objToJson(data) : data);
|
|
24
|
+
await fsp.rename(swapFile, filePath);
|
|
22
25
|
} catch (error) {
|
|
23
26
|
|
|
24
27
|
throw new Error(error);
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
export async function
|
|
31
|
+
export async function copyFile(sourcePath, targetPath, options={}) {
|
|
32
|
+
try {
|
|
33
|
+
sourcePath = path.resolve(sourcePath);
|
|
34
|
+
targetPath = path.resolve(targetPath);
|
|
35
|
+
await fsp.access(sourcePath);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
throw new Error(error);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
await fsp.access(targetPath);
|
|
42
|
+
if (!options.overwrite) return false;
|
|
43
|
+
} catch {}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await fsp.copyFile(sourcePath, targetPath);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throw new Error(error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function readFile(filePath, options={}) {
|
|
29
55
|
try {
|
|
30
56
|
filePath = path.resolve(filePath);
|
|
31
57
|
|
|
32
58
|
await fsp.access(filePath);
|
|
33
59
|
const fileData = await fsp.readFile(filePath, 'utf8');
|
|
34
60
|
|
|
35
|
-
return json ? JSON.parse(fileData) : fileData;
|
|
61
|
+
return options.json ? JSON.parse(fileData) : fileData;
|
|
36
62
|
} catch (error) {
|
|
63
|
+
const { missingFileCallback } = options;
|
|
64
|
+
|
|
37
65
|
if (error.code === 'ENOENT' && missingFileCallback) {
|
|
38
66
|
return missingFileCallback(filePath);
|
|
39
67
|
}
|
|
@@ -90,3 +118,13 @@ export async function forEachFileImport(dir, callback, options={}) {
|
|
|
90
118
|
callback(output, { name, stats, path: filePath });
|
|
91
119
|
}
|
|
92
120
|
}
|
|
121
|
+
|
|
122
|
+
export async function fileExists(filePath) {
|
|
123
|
+
try {
|
|
124
|
+
filePath = path.resolve(filePath);
|
|
125
|
+
await fsp.access(filePath);
|
|
126
|
+
return true;
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/object.js
CHANGED
|
@@ -6,42 +6,34 @@ export function objToJson(obj) {
|
|
|
6
6
|
return JSON.stringify(obj);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function
|
|
9
|
+
export function makeArray(obj) {
|
|
10
|
+
return Array.isArray(obj) ? obj : [obj];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function mergeObject(obj1, obj2, options={}) {
|
|
10
14
|
if (Array.isArray(obj1) || Array.isArray(obj2)) throw new Error('Cannot merge arrays.');
|
|
11
|
-
|
|
12
|
-
if (typeof
|
|
15
|
+
|
|
16
|
+
if (obj1 === null || typeof obj1 !== 'object') return cloneShallow(obj2);
|
|
17
|
+
if (obj2 === null || typeof obj2 !== 'object') return cloneShallow(obj1);
|
|
13
18
|
|
|
14
19
|
const result = {};
|
|
15
|
-
const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
|
|
16
20
|
|
|
17
|
-
for (const key of keys)
|
|
21
|
+
for (const key of Object.keys(obj1)) result[key] = cloneShallow(obj1[key]);
|
|
22
|
+
for (const key of Object.keys(obj2)) {
|
|
23
|
+
if (options.ignoreNewKeys && !(key in obj1)) continue;
|
|
24
|
+
|
|
18
25
|
const val1 = obj1[key];
|
|
19
26
|
const val2 = obj2[key];
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} else if (val1 === undefined) {
|
|
24
|
-
result[key] = structuredClone(val2);
|
|
25
|
-
} else if (
|
|
26
|
-
typeof val1 === 'object' &&
|
|
27
|
-
typeof val2 === 'object' &&
|
|
28
|
-
val1 !== null &&
|
|
29
|
-
val2 !== null &&
|
|
30
|
-
!Array.isArray(val1) &&
|
|
31
|
-
!Array.isArray(val2)
|
|
32
|
-
) {
|
|
33
|
-
result[key] = mergeObject(val1, val2);
|
|
34
|
-
} else {
|
|
35
|
-
result[key] = structuredClone(val2);
|
|
36
|
-
}
|
|
27
|
+
const shouldMerge = val1 && val2 && typeof val1 === 'object' && typeof val2 === 'object' && !Array.isArray(val1) && !Array.isArray(val2);
|
|
28
|
+
result[key] = shouldMerge ? mergeObject(val1, val2, options) : cloneShallow(val2);
|
|
29
|
+
|
|
37
30
|
}
|
|
38
31
|
|
|
39
32
|
return result;
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
if (Array.isArray(value)) return value;
|
|
44
|
-
if (value
|
|
45
|
-
|
|
46
|
-
return [value];
|
|
35
|
+
function cloneShallow(value) {
|
|
36
|
+
if (Array.isArray(value)) return value.slice();
|
|
37
|
+
if (value && typeof value === 'object') return { ...value };
|
|
38
|
+
return value;
|
|
47
39
|
}
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
v22.18.0
|
package/test/unit/object-test.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import Qunit from 'qunit';
|
|
2
|
-
import { mergeObject } from '@stonyx/utils/object';
|
|
3
|
-
|
|
4
|
-
const { module, test } = Qunit;
|
|
5
|
-
|
|
6
|
-
module('[Unit] Object', function() {
|
|
7
|
-
test('mergeObject works as expected', async function(assert) {
|
|
8
|
-
assert.deepEqual(
|
|
9
|
-
mergeObject({ a: 1, b: 2 }, { c: 3 }),
|
|
10
|
-
{ a: 1, b: 2, c: 3 },
|
|
11
|
-
'New properties are added'
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
assert.deepEqual(
|
|
15
|
-
mergeObject({ a: 1, b: 2, c: 3 }, { c: 4 }),
|
|
16
|
-
{ a: 1, b: 2, c: 4 },
|
|
17
|
-
'Old properties are overwritten'
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
assert.deepEqual(
|
|
21
|
-
mergeObject({ a: 1, b: 2, c: 3 }, { a: 7, c: 23, d: { a: 1, b: 2, c: 3 } }),
|
|
22
|
-
{ a: 7, b: 2, c: 23, d: { a: 1, b: 2, c: 3 } },
|
|
23
|
-
'Objects are merged recursively'
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
mergeObject([], {});
|
|
28
|
-
} catch {
|
|
29
|
-
assert.ok(true, 'Array inputs throws error');
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
});
|