@appsemble/node-utils 0.20.8 → 0.20.11
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/{dist/AppsembleError.d.ts → AppsembleError.d.ts} +1 -1
- package/{dist/AppsembleError.js → AppsembleError.js} +1 -1
- package/AppsembleError.js.map +1 -0
- package/AppsembleError.test.d.ts +1 -0
- package/AppsembleError.test.js +8 -0
- package/AppsembleError.test.js.map +1 -0
- package/AppsembleError.test.ts +6 -0
- package/AppsembleError.ts +16 -0
- package/__fixtures__/hello.txt +1 -0
- package/__fixtures__/invalid-json.json +3 -0
- package/__fixtures__/json.json +1 -0
- package/__fixtures__/test/bar.txt +0 -0
- package/__fixtures__/test/foo.txt +0 -0
- package/__fixtures__/test/z/baz.txt +0 -0
- package/__fixtures__/test/z/fooz.txt +0 -0
- package/__fixtures__/yaml.yaml +1 -0
- package/__mocks__/os.d.ts +5 -0
- package/__mocks__/os.js +8 -0
- package/__mocks__/os.js.map +1 -0
- package/__mocks__/os.ts +10 -0
- package/{dist/basicAuth.d.ts → basicAuth.d.ts} +2 -2
- package/{dist/basicAuth.js → basicAuth.js} +2 -2
- package/basicAuth.js.map +1 -0
- package/basicAuth.test.d.ts +1 -0
- package/basicAuth.test.js +8 -0
- package/basicAuth.test.js.map +1 -0
- package/basicAuth.test.ts +6 -0
- package/basicAuth.ts +10 -0
- package/changed/added/.gitkeep +0 -0
- package/changed/changed/.gitkeep +0 -0
- package/changed/deprecated/.gitkeep +0 -0
- package/changed/fixed/.gitkeep +0 -0
- package/changed/removed/.gitkeep +0 -0
- package/changed/security/.gitkeep +0 -0
- package/{dist/formData.d.ts → formData.d.ts} +1 -1
- package/{dist/formData.js → formData.js} +1 -1
- package/formData.js.map +1 -0
- package/formData.test.d.ts +1 -0
- package/formData.test.js +94 -0
- package/formData.test.js.map +1 -0
- package/formData.test.ts +113 -0
- package/formData.ts +37 -0
- package/{dist/fs.d.ts → fs.d.ts} +11 -10
- package/{dist/fs.js → fs.js} +16 -16
- package/fs.js.map +1 -0
- package/fs.test.d.ts +1 -0
- package/fs.test.js +76 -0
- package/fs.test.js.map +1 -0
- package/fs.test.ts +120 -0
- package/fs.ts +144 -0
- package/{dist/getWorkspaces.d.ts → getWorkspaces.d.ts} +1 -1
- package/{dist/getWorkspaces.js → getWorkspaces.js} +3 -3
- package/getWorkspaces.js.map +1 -0
- package/getWorkspaces.ts +23 -0
- package/{dist/handleError.d.ts → handleError.d.ts} +3 -3
- package/{dist/handleError.js → handleError.js} +3 -3
- package/handleError.js.map +1 -0
- package/handleError.test.d.ts +1 -0
- package/handleError.test.js +34 -0
- package/handleError.test.js.map +1 -0
- package/handleError.test.ts +38 -0
- package/handleError.ts +26 -0
- package/{dist/index.d.ts → index.d.ts} +0 -0
- package/{dist/index.js → index.js} +0 -0
- package/index.js.map +1 -0
- package/index.ts +11 -0
- package/{dist/interceptors.d.ts → interceptors.d.ts} +5 -5
- package/{dist/interceptors.js → interceptors.js} +5 -5
- package/interceptors.js.map +1 -0
- package/interceptors.test.d.ts +1 -0
- package/interceptors.test.js +93 -0
- package/interceptors.test.js.map +1 -0
- package/interceptors.test.ts +108 -0
- package/interceptors.ts +81 -0
- package/jest.config.js +1 -0
- package/jest.setup.d.ts +1 -0
- package/jest.setup.js +9 -0
- package/jest.setup.js.map +1 -0
- package/jest.setup.ts +7 -0
- package/{dist/logger.d.ts → logger.d.ts} +2 -2
- package/{dist/logger.js → logger.js} +6 -6
- package/logger.js.map +1 -0
- package/logger.test.d.ts +1 -0
- package/logger.test.js +38 -0
- package/logger.test.js.map +1 -0
- package/logger.test.ts +43 -0
- package/logger.ts +130 -0
- package/{dist/loggerMiddleware.d.ts → loggerMiddleware.d.ts} +0 -0
- package/{dist/loggerMiddleware.js → loggerMiddleware.js} +18 -15
- package/loggerMiddleware.js.map +1 -0
- package/loggerMiddleware.test.d.ts +1 -0
- package/loggerMiddleware.test.js +130 -0
- package/loggerMiddleware.test.js.map +1 -0
- package/loggerMiddleware.test.ts +185 -0
- package/loggerMiddleware.ts +93 -0
- package/package.json +6 -5
- package/{dist/readFileOrString.d.ts → readFileOrString.d.ts} +1 -1
- package/{dist/readFileOrString.js → readFileOrString.js} +3 -3
- package/readFileOrString.js.map +1 -0
- package/readFileOrString.test.d.ts +1 -0
- package/readFileOrString.test.js +13 -0
- package/readFileOrString.test.js.map +1 -0
- package/readFileOrString.test.ts +12 -0
- package/readFileOrString.ts +20 -0
- package/{dist/testFixtures.d.ts → testFixtures.d.ts} +6 -5
- package/{dist/testFixtures.js → testFixtures.js} +5 -4
- package/testFixtures.js.map +1 -0
- package/testFixtures.ts +58 -0
- package/tsconfig.json +6 -0
- package/dist/AppsembleError.js.map +0 -1
- package/dist/basicAuth.js.map +0 -1
- package/dist/formData.js.map +0 -1
- package/dist/fs.js.map +0 -1
- package/dist/getWorkspaces.js.map +0 -1
- package/dist/handleError.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/interceptors.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/loggerMiddleware.js.map +0 -1
- package/dist/readFileOrString.js.map +0 -1
- package/dist/testFixtures.js.map +0 -1
package/fs.test.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _1 = require(".");
|
|
4
|
+
describe('isErrno', () => {
|
|
5
|
+
it('should return false for null', () => {
|
|
6
|
+
expect((0, _1.isErrno)(null)).toBe(false);
|
|
7
|
+
});
|
|
8
|
+
it('should return false for miscellaneous objects', () => {
|
|
9
|
+
expect((0, _1.isErrno)({})).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
it('should return true if the object has a string property named code', () => {
|
|
12
|
+
expect((0, _1.isErrno)({ code: 'foo' })).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it('should return false if the object has a non-string property named code', () => {
|
|
15
|
+
expect((0, _1.isErrno)({ code: 42 })).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
it('should allow to narrow down a specific code', () => {
|
|
18
|
+
expect((0, _1.isErrno)({ code: 'ENOENT' }, 'ENOENT')).toBe(true);
|
|
19
|
+
expect((0, _1.isErrno)({ code: 'invalid' }, 'ENOENT')).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('readData', () => {
|
|
23
|
+
it('should read and parse a JSON file', async () => {
|
|
24
|
+
const content = await (0, _1.readData)((0, _1.resolveFixture)('json.json'));
|
|
25
|
+
expect(content).toStrictEqual([{ json: 'json' }, '{ "json": "json" }\n']);
|
|
26
|
+
});
|
|
27
|
+
it('should read and parse a YAML file', async () => {
|
|
28
|
+
const content = await (0, _1.readData)((0, _1.resolveFixture)('yaml.yaml'));
|
|
29
|
+
expect(content).toStrictEqual([{ yaml: 'yaml' }, 'yaml: yaml\n']);
|
|
30
|
+
});
|
|
31
|
+
it('should throw an Appsemble error if file extension is unknown', async () => {
|
|
32
|
+
const path = (0, _1.resolveFixture)('hello.txt');
|
|
33
|
+
await expect((0, _1.readData)(path)).rejects.toThrow(new _1.AppsembleError(`Unknown file extension: ${path}`));
|
|
34
|
+
});
|
|
35
|
+
it('should throw an Appsemble error if the file can’t be read', async () => {
|
|
36
|
+
await expect((0, _1.readData)('non-existent.yaml')).rejects.toThrow(new _1.AppsembleError('Error reading file non-existent.yaml'));
|
|
37
|
+
});
|
|
38
|
+
it('should throw an Appsemble error if the file can’t be parsed', async () => {
|
|
39
|
+
const path = (0, _1.resolveFixture)('invalid-json.json');
|
|
40
|
+
await expect((0, _1.readData)(path)).rejects.toThrow(_1.AppsembleError);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('opendirSafe', () => {
|
|
44
|
+
it('should read a directory', async () => {
|
|
45
|
+
const onFile = jest.fn();
|
|
46
|
+
await (0, _1.opendirSafe)((0, _1.resolveFixture)('test'), onFile);
|
|
47
|
+
expect(onFile).toHaveBeenCalledTimes(3);
|
|
48
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/bar.txt'), expect.objectContaining({ name: 'bar.txt' }));
|
|
49
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/foo.txt'), expect.objectContaining({ name: 'foo.txt' }));
|
|
50
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/z'), expect.objectContaining({ name: 'z' }));
|
|
51
|
+
});
|
|
52
|
+
it('should read a directory recursively if specified', async () => {
|
|
53
|
+
const onFile = jest.fn();
|
|
54
|
+
await (0, _1.opendirSafe)((0, _1.resolveFixture)('test'), onFile, { recursive: true });
|
|
55
|
+
expect(onFile).toHaveBeenCalledTimes(5);
|
|
56
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/bar.txt'), expect.objectContaining({ name: 'bar.txt' }));
|
|
57
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/foo.txt'), expect.objectContaining({ name: 'foo.txt' }));
|
|
58
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/z'), expect.objectContaining({ name: 'z' }));
|
|
59
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/z/baz.txt'), expect.objectContaining({ name: 'baz.txt' }));
|
|
60
|
+
expect(onFile).toHaveBeenCalledWith((0, _1.resolveFixture)('test/z/fooz.txt'), expect.objectContaining({ name: 'fooz.txt' }));
|
|
61
|
+
});
|
|
62
|
+
it('should throw if the path is not a directory', async () => {
|
|
63
|
+
const path = (0, _1.resolveFixture)('hello.txt');
|
|
64
|
+
await expect((0, _1.opendirSafe)(path, jest.fn())).rejects.toThrow(new _1.AppsembleError(`Expected ${path} to be a directory`));
|
|
65
|
+
});
|
|
66
|
+
it('should throw if the path doesn’t exist', async () => {
|
|
67
|
+
const path = (0, _1.resolveFixture)('non-existent');
|
|
68
|
+
await expect((0, _1.opendirSafe)(path, jest.fn())).rejects.toThrow(new _1.AppsembleError(`Expected ${path} to be a directory`));
|
|
69
|
+
});
|
|
70
|
+
it('should not throw if the path doesn’t exist and allowMissing is true', async () => {
|
|
71
|
+
const path = (0, _1.resolveFixture)('non-existent');
|
|
72
|
+
const result = await (0, _1.opendirSafe)(path, jest.fn(), { allowMissing: true });
|
|
73
|
+
expect(result).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=fs.test.js.map
|
package/fs.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.test.js","sourceRoot":"","sources":["fs.test.ts"],"names":[],"mappings":"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"}
|
package/fs.test.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { AppsembleError, isErrno, opendirSafe, readData, resolveFixture } from '.';
|
|
2
|
+
|
|
3
|
+
describe('isErrno', () => {
|
|
4
|
+
it('should return false for null', () => {
|
|
5
|
+
expect(isErrno(null)).toBe(false);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return false for miscellaneous objects', () => {
|
|
9
|
+
expect(isErrno({})).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return true if the object has a string property named code', () => {
|
|
13
|
+
expect(isErrno({ code: 'foo' })).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return false if the object has a non-string property named code', () => {
|
|
17
|
+
expect(isErrno({ code: 42 })).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should allow to narrow down a specific code', () => {
|
|
21
|
+
expect(isErrno({ code: 'ENOENT' }, 'ENOENT')).toBe(true);
|
|
22
|
+
expect(isErrno({ code: 'invalid' }, 'ENOENT')).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('readData', () => {
|
|
27
|
+
it('should read and parse a JSON file', async () => {
|
|
28
|
+
const content = await readData(resolveFixture('json.json'));
|
|
29
|
+
expect(content).toStrictEqual([{ json: 'json' }, '{ "json": "json" }\n']);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should read and parse a YAML file', async () => {
|
|
33
|
+
const content = await readData(resolveFixture('yaml.yaml'));
|
|
34
|
+
expect(content).toStrictEqual([{ yaml: 'yaml' }, 'yaml: yaml\n']);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should throw an Appsemble error if file extension is unknown', async () => {
|
|
38
|
+
const path = resolveFixture('hello.txt');
|
|
39
|
+
await expect(readData(path)).rejects.toThrow(
|
|
40
|
+
new AppsembleError(`Unknown file extension: ${path}`),
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should throw an Appsemble error if the file can’t be read', async () => {
|
|
45
|
+
await expect(readData('non-existent.yaml')).rejects.toThrow(
|
|
46
|
+
new AppsembleError('Error reading file non-existent.yaml'),
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should throw an Appsemble error if the file can’t be parsed', async () => {
|
|
51
|
+
const path = resolveFixture('invalid-json.json');
|
|
52
|
+
await expect(readData(path)).rejects.toThrow(AppsembleError);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('opendirSafe', () => {
|
|
57
|
+
it('should read a directory', async () => {
|
|
58
|
+
const onFile = jest.fn();
|
|
59
|
+
await opendirSafe(resolveFixture('test'), onFile);
|
|
60
|
+
expect(onFile).toHaveBeenCalledTimes(3);
|
|
61
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
62
|
+
resolveFixture('test/bar.txt'),
|
|
63
|
+
expect.objectContaining({ name: 'bar.txt' }),
|
|
64
|
+
);
|
|
65
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
66
|
+
resolveFixture('test/foo.txt'),
|
|
67
|
+
expect.objectContaining({ name: 'foo.txt' }),
|
|
68
|
+
);
|
|
69
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
70
|
+
resolveFixture('test/z'),
|
|
71
|
+
expect.objectContaining({ name: 'z' }),
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should read a directory recursively if specified', async () => {
|
|
76
|
+
const onFile = jest.fn();
|
|
77
|
+
await opendirSafe(resolveFixture('test'), onFile, { recursive: true });
|
|
78
|
+
expect(onFile).toHaveBeenCalledTimes(5);
|
|
79
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
80
|
+
resolveFixture('test/bar.txt'),
|
|
81
|
+
expect.objectContaining({ name: 'bar.txt' }),
|
|
82
|
+
);
|
|
83
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
84
|
+
resolveFixture('test/foo.txt'),
|
|
85
|
+
expect.objectContaining({ name: 'foo.txt' }),
|
|
86
|
+
);
|
|
87
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
88
|
+
resolveFixture('test/z'),
|
|
89
|
+
expect.objectContaining({ name: 'z' }),
|
|
90
|
+
);
|
|
91
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
92
|
+
resolveFixture('test/z/baz.txt'),
|
|
93
|
+
expect.objectContaining({ name: 'baz.txt' }),
|
|
94
|
+
);
|
|
95
|
+
expect(onFile).toHaveBeenCalledWith(
|
|
96
|
+
resolveFixture('test/z/fooz.txt'),
|
|
97
|
+
expect.objectContaining({ name: 'fooz.txt' }),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should throw if the path is not a directory', async () => {
|
|
102
|
+
const path = resolveFixture('hello.txt');
|
|
103
|
+
await expect(opendirSafe(path, jest.fn())).rejects.toThrow(
|
|
104
|
+
new AppsembleError(`Expected ${path} to be a directory`),
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should throw if the path doesn’t exist', async () => {
|
|
109
|
+
const path = resolveFixture('non-existent');
|
|
110
|
+
await expect(opendirSafe(path, jest.fn())).rejects.toThrow(
|
|
111
|
+
new AppsembleError(`Expected ${path} to be a directory`),
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should not throw if the path doesn’t exist and allowMissing is true', async () => {
|
|
116
|
+
const path = resolveFixture('non-existent');
|
|
117
|
+
const result = await opendirSafe(path, jest.fn(), { allowMissing: true });
|
|
118
|
+
expect(result).toBeUndefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
package/fs.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Dirent, Stats } from 'fs';
|
|
2
|
+
import { mkdir, opendir, readFile, stat, writeFile } from 'fs/promises';
|
|
3
|
+
import { dirname, extname, join } from 'path';
|
|
4
|
+
|
|
5
|
+
import { compareStrings } from '@appsemble/utils';
|
|
6
|
+
import parseJson from 'parse-json';
|
|
7
|
+
import sortKeys from 'sort-keys';
|
|
8
|
+
import { Promisable } from 'type-fest';
|
|
9
|
+
import { parse, stringify } from 'yaml';
|
|
10
|
+
|
|
11
|
+
import { AppsembleError } from '.';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Test if the error is a NodeJS errno exception.
|
|
15
|
+
*
|
|
16
|
+
* @param error The value to check
|
|
17
|
+
* @param code If specified, theck if the code matches
|
|
18
|
+
* @returns Whether or not the error is a NodeJS errno exception.
|
|
19
|
+
*/
|
|
20
|
+
export function isErrno(error: unknown, code?: string): error is NodeJS.ErrnoException {
|
|
21
|
+
if (!error || typeof error !== 'object') {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const err = error as NodeJS.ErrnoException;
|
|
25
|
+
if (code) {
|
|
26
|
+
return err.code === code;
|
|
27
|
+
}
|
|
28
|
+
return typeof err.code === 'string';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Read the content of a JSON or YAML file.
|
|
33
|
+
*
|
|
34
|
+
* @param path The path to the file to read.
|
|
35
|
+
* @returns A tuple of the parsed content and the content as a string.
|
|
36
|
+
*/
|
|
37
|
+
export async function readData<R>(path: string): Promise<[R, string]> {
|
|
38
|
+
let content: string;
|
|
39
|
+
const ext = extname(path);
|
|
40
|
+
try {
|
|
41
|
+
content = await readFile(path, 'utf8');
|
|
42
|
+
} catch {
|
|
43
|
+
throw new AppsembleError(`Error reading file ${path}`);
|
|
44
|
+
}
|
|
45
|
+
if (ext !== '.yaml' && ext !== '.yml' && ext !== '.json') {
|
|
46
|
+
throw new AppsembleError(`Unknown file extension: ${path}`);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return [
|
|
50
|
+
ext === '.json' ? parseJson(content) : (parse(content, { maxAliasCount: 10_000 }) as R),
|
|
51
|
+
content,
|
|
52
|
+
];
|
|
53
|
+
} catch (error: unknown) {
|
|
54
|
+
throw new AppsembleError(`Error parsing ${path}\n${(error as Error).message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface WriteDataOptions {
|
|
59
|
+
/**
|
|
60
|
+
* If false, don’t sort the object keys.
|
|
61
|
+
*/
|
|
62
|
+
readonly sort?: boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A comparison function to use for sorting keys.
|
|
66
|
+
*
|
|
67
|
+
* By default natural sorting will be used.
|
|
68
|
+
*/
|
|
69
|
+
readonly compare?: ((a: string, b: string) => number) | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Write data to a file serialized as JSON or YAML.
|
|
74
|
+
*
|
|
75
|
+
* If `prettier` is available, the content is also formatted.
|
|
76
|
+
*
|
|
77
|
+
* @param path The file path to write the data to.
|
|
78
|
+
* @param data The data to write to the file.
|
|
79
|
+
* @param options Additional options for processing the data.
|
|
80
|
+
* @returns The formatted content.
|
|
81
|
+
*/
|
|
82
|
+
export async function writeData(
|
|
83
|
+
path: string,
|
|
84
|
+
data: unknown,
|
|
85
|
+
{ compare = compareStrings, sort = true }: WriteDataOptions = {},
|
|
86
|
+
): Promise<string> {
|
|
87
|
+
const sorted = sort ? sortKeys(data, { deep: true, compare: compare || undefined }) : data;
|
|
88
|
+
let buffer: string;
|
|
89
|
+
try {
|
|
90
|
+
const { format, getFileInfo, resolveConfig } = await import('prettier');
|
|
91
|
+
const { inferredParser } = await getFileInfo(path, { resolveConfig: true });
|
|
92
|
+
const prettierOptions = await resolveConfig(path, { editorconfig: true });
|
|
93
|
+
prettierOptions.parser = inferredParser;
|
|
94
|
+
buffer = inferredParser === 'yaml' ? stringify(sorted) : JSON.stringify(sorted, undefined, 2);
|
|
95
|
+
buffer = format(buffer, prettierOptions);
|
|
96
|
+
} catch {
|
|
97
|
+
const ext = extname(path);
|
|
98
|
+
buffer =
|
|
99
|
+
ext === '.yml' || ext === '.yaml' ? stringify(sorted) : JSON.stringify(sorted, undefined, 2);
|
|
100
|
+
}
|
|
101
|
+
await mkdir(dirname(path), { recursive: true });
|
|
102
|
+
await writeFile(path, buffer);
|
|
103
|
+
return buffer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface OpenDirSafeOptions {
|
|
107
|
+
allowMissing?: boolean;
|
|
108
|
+
recursive?: boolean;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Read the contents of a directory.
|
|
113
|
+
*
|
|
114
|
+
* @param directory The path of the directory to open.
|
|
115
|
+
* @param onFile A callback which will get called for every file. This will be called with the full
|
|
116
|
+
* file path as its first argument and its `Dirent` object as the second argument.
|
|
117
|
+
* @param options Additional options.
|
|
118
|
+
*/
|
|
119
|
+
export async function opendirSafe(
|
|
120
|
+
directory: string,
|
|
121
|
+
onFile: (fullpath: string, stat: Dirent) => Promisable<void>,
|
|
122
|
+
options: OpenDirSafeOptions = {},
|
|
123
|
+
): Promise<void> {
|
|
124
|
+
let stats: Stats;
|
|
125
|
+
try {
|
|
126
|
+
stats = await stat(directory);
|
|
127
|
+
} catch (err: unknown) {
|
|
128
|
+
if (options.allowMissing && isErrno(err, 'ENOENT')) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
throw new AppsembleError(`Expected ${directory} to be a directory`);
|
|
132
|
+
}
|
|
133
|
+
if (!stats.isDirectory()) {
|
|
134
|
+
throw new AppsembleError(`Expected ${directory} to be a directory`);
|
|
135
|
+
}
|
|
136
|
+
const dir = await opendir(directory);
|
|
137
|
+
for await (const file of dir) {
|
|
138
|
+
const fullPath = join(directory, file.name);
|
|
139
|
+
await onFile(fullPath, file);
|
|
140
|
+
if (options.recursive && file.isDirectory()) {
|
|
141
|
+
await opendirSafe(fullPath, onFile, options);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Both Lerna and Yarn workspaces are supported.
|
|
5
5
|
*
|
|
6
|
-
* @param cwd
|
|
6
|
+
* @param cwd The project root in which to find workspaces.
|
|
7
7
|
* @returns Discovered Appsemble blocks.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getWorkspaces(cwd: string): Promise<string[]>;
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getWorkspaces = void 0;
|
|
7
|
-
const
|
|
7
|
+
const promises_1 = require("fs/promises");
|
|
8
8
|
const path_1 = require("path");
|
|
9
9
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
10
10
|
/**
|
|
@@ -12,11 +12,11 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
|
12
12
|
*
|
|
13
13
|
* Both Lerna and Yarn workspaces are supported.
|
|
14
14
|
*
|
|
15
|
-
* @param cwd
|
|
15
|
+
* @param cwd The project root in which to find workspaces.
|
|
16
16
|
* @returns Discovered Appsemble blocks.
|
|
17
17
|
*/
|
|
18
18
|
async function getWorkspaces(cwd) {
|
|
19
|
-
const { workspaces = [] } = JSON.parse(await
|
|
19
|
+
const { workspaces = [] } = JSON.parse(await (0, promises_1.readFile)((0, path_1.join)(cwd, 'package.json'), 'utf8'));
|
|
20
20
|
const dirs = await (0, fast_glob_1.default)(workspaces, {
|
|
21
21
|
cwd,
|
|
22
22
|
absolute: true,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getWorkspaces.js","sourceRoot":"","sources":["getWorkspaces.ts"],"names":[],"mappings":";;;;;;AAAA,0CAAuC;AACvC,+BAA4B;AAE5B,0DAA2B;AAE3B;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,IAAA,mBAAQ,EAAC,IAAA,WAAI,EAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,MAAM,IAAA,mBAAE,EAAC,UAAU,EAAE;QAChC,GAAG;QACH,QAAQ,EAAE,IAAI;QACd,mBAAmB,EAAE,IAAI;QACzB,eAAe,EAAE,IAAI;KACtB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AATD,sCASC"}
|
package/getWorkspaces.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
import fg from 'fast-glob';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Discover Appsemble blocks based on workspaces in a monorepo.
|
|
8
|
+
*
|
|
9
|
+
* Both Lerna and Yarn workspaces are supported.
|
|
10
|
+
*
|
|
11
|
+
* @param cwd The project root in which to find workspaces.
|
|
12
|
+
* @returns Discovered Appsemble blocks.
|
|
13
|
+
*/
|
|
14
|
+
export async function getWorkspaces(cwd: string): Promise<string[]> {
|
|
15
|
+
const { workspaces = [] } = JSON.parse(await readFile(join(cwd, 'package.json'), 'utf8'));
|
|
16
|
+
const dirs = await fg(workspaces, {
|
|
17
|
+
cwd,
|
|
18
|
+
absolute: true,
|
|
19
|
+
followSymbolicLinks: true,
|
|
20
|
+
onlyDirectories: true,
|
|
21
|
+
});
|
|
22
|
+
return dirs.sort();
|
|
23
|
+
}
|
|
@@ -4,8 +4,8 @@ import { Argv } from 'yargs';
|
|
|
4
4
|
*
|
|
5
5
|
* HTTP errors are formatted nicely. For other errors, the stack trace is logged.
|
|
6
6
|
*
|
|
7
|
-
* @param message
|
|
8
|
-
* @param error
|
|
9
|
-
* @param yargs
|
|
7
|
+
* @param message Unused.
|
|
8
|
+
* @param error The error that was thrown.
|
|
9
|
+
* @param yargs The active yargs instance.
|
|
10
10
|
*/
|
|
11
11
|
export declare function handleError(message: string, error: Error, yargs: Argv): void;
|
|
@@ -8,9 +8,9 @@ const logger_1 = require("./logger");
|
|
|
8
8
|
*
|
|
9
9
|
* HTTP errors are formatted nicely. For other errors, the stack trace is logged.
|
|
10
10
|
*
|
|
11
|
-
* @param message
|
|
12
|
-
* @param error
|
|
13
|
-
* @param yargs
|
|
11
|
+
* @param message Unused.
|
|
12
|
+
* @param error The error that was thrown.
|
|
13
|
+
* @param yargs The active yargs instance.
|
|
14
14
|
*/
|
|
15
15
|
function handleError(message, error, yargs) {
|
|
16
16
|
if (typeof message === 'string') {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handleError.js","sourceRoot":"","sources":["handleError.ts"],"names":[],"mappings":";;;AAEA,qDAAkD;AAClD,qCAAkC;AAElC;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,OAAe,EAAE,KAAY,EAAE,KAAW;IACpE,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;QAC/B,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;KACxB;SAAM,IAAI,KAAK,YAAY,+BAAc,EAAE;QAC1C,eAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;KAC7B;SAAM;QACL,eAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;KACrB;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAXD,kCAWC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const AppsembleError_1 = require("./AppsembleError");
|
|
4
|
+
const handleError_1 = require("./handleError");
|
|
5
|
+
const logger_1 = require("./logger");
|
|
6
|
+
let yargs;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
yargs = { showHelp: jest.fn() };
|
|
9
|
+
jest.spyOn(console, 'error').mockImplementation();
|
|
10
|
+
jest.spyOn(process, 'exit').mockImplementation();
|
|
11
|
+
jest.spyOn(logger_1.logger, 'error').mockImplementation();
|
|
12
|
+
});
|
|
13
|
+
it('should show the help message if it is passed a yargs message', () => {
|
|
14
|
+
(0, handleError_1.handleError)('Command foo not found', undefined, yargs);
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
expect(console.error).toHaveBeenCalledWith('Command foo not found');
|
|
17
|
+
expect(yargs.showHelp).toHaveBeenCalledWith();
|
|
18
|
+
expect(logger_1.logger.error).not.toHaveBeenCalled();
|
|
19
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
20
|
+
});
|
|
21
|
+
it('should log the message of an Appsemble error', () => {
|
|
22
|
+
(0, handleError_1.handleError)(undefined, new AppsembleError_1.AppsembleError('Oh noez!'), yargs);
|
|
23
|
+
expect(yargs.showHelp).not.toHaveBeenCalled();
|
|
24
|
+
expect(logger_1.logger.error).toHaveBeenCalledWith('Oh noez!');
|
|
25
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
26
|
+
});
|
|
27
|
+
it('should log unknown errors raw', () => {
|
|
28
|
+
const error = new Error('Oh noez!');
|
|
29
|
+
(0, handleError_1.handleError)(undefined, error, yargs);
|
|
30
|
+
expect(yargs.showHelp).not.toHaveBeenCalled();
|
|
31
|
+
expect(logger_1.logger.error).toHaveBeenCalledWith(error);
|
|
32
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=handleError.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handleError.test.js","sourceRoot":"","sources":["handleError.test.ts"],"names":[],"mappings":";;AAEA,qDAAkD;AAClD,+CAA4C;AAC5C,qCAAkC;AAElC,IAAI,KAAW,CAAC;AAEhB,UAAU,CAAC,GAAG,EAAE;IACd,KAAK,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,EAA2B,CAAC;IACzD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,EAAE,CAAC;IACjD,IAAI,CAAC,KAAK,CAAC,eAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;IACtE,IAAA,yBAAW,EAAC,uBAAuB,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACvD,sCAAsC;IACtC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,uBAAuB,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,oBAAoB,EAAE,CAAC;IAC9C,MAAM,CAAC,eAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC5C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACtD,IAAA,yBAAW,EAAC,SAAS,EAAE,IAAI,+BAAc,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC9C,MAAM,CAAC,eAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;IACvC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;IACpC,IAAA,yBAAW,EAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC9C,MAAM,CAAC,eAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Argv } from 'yargs';
|
|
2
|
+
|
|
3
|
+
import { AppsembleError } from './AppsembleError';
|
|
4
|
+
import { handleError } from './handleError';
|
|
5
|
+
import { logger } from './logger';
|
|
6
|
+
|
|
7
|
+
let yargs: Argv;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
yargs = { showHelp: jest.fn() } as Partial<Argv> as Argv;
|
|
11
|
+
jest.spyOn(console, 'error').mockImplementation();
|
|
12
|
+
jest.spyOn(process, 'exit').mockImplementation();
|
|
13
|
+
jest.spyOn(logger, 'error').mockImplementation();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should show the help message if it is passed a yargs message', () => {
|
|
17
|
+
handleError('Command foo not found', undefined, yargs);
|
|
18
|
+
// eslint-disable-next-line no-console
|
|
19
|
+
expect(console.error).toHaveBeenCalledWith('Command foo not found');
|
|
20
|
+
expect(yargs.showHelp).toHaveBeenCalledWith();
|
|
21
|
+
expect(logger.error).not.toHaveBeenCalled();
|
|
22
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should log the message of an Appsemble error', () => {
|
|
26
|
+
handleError(undefined, new AppsembleError('Oh noez!'), yargs);
|
|
27
|
+
expect(yargs.showHelp).not.toHaveBeenCalled();
|
|
28
|
+
expect(logger.error).toHaveBeenCalledWith('Oh noez!');
|
|
29
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should log unknown errors raw', () => {
|
|
33
|
+
const error = new Error('Oh noez!');
|
|
34
|
+
handleError(undefined, error, yargs);
|
|
35
|
+
expect(yargs.showHelp).not.toHaveBeenCalled();
|
|
36
|
+
expect(logger.error).toHaveBeenCalledWith(error);
|
|
37
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
38
|
+
});
|
package/handleError.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Argv } from 'yargs';
|
|
2
|
+
|
|
3
|
+
import { AppsembleError } from './AppsembleError';
|
|
4
|
+
import { logger } from './logger';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handle a fatal error.
|
|
8
|
+
*
|
|
9
|
+
* HTTP errors are formatted nicely. For other errors, the stack trace is logged.
|
|
10
|
+
*
|
|
11
|
+
* @param message Unused.
|
|
12
|
+
* @param error The error that was thrown.
|
|
13
|
+
* @param yargs The active yargs instance.
|
|
14
|
+
*/
|
|
15
|
+
export function handleError(message: string, error: Error, yargs: Argv): void {
|
|
16
|
+
if (typeof message === 'string') {
|
|
17
|
+
yargs.showHelp();
|
|
18
|
+
// eslint-disable-next-line no-console
|
|
19
|
+
console.error(message);
|
|
20
|
+
} else if (error instanceof AppsembleError) {
|
|
21
|
+
logger.error(error.message);
|
|
22
|
+
} else {
|
|
23
|
+
logger.error(error);
|
|
24
|
+
}
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
File without changes
|
|
File without changes
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,mDAAiC;AACjC,8CAA4B;AAC5B,6CAA2B;AAC3B,kDAAgC;AAChC,gDAA8B;AAC9B,iDAA+B;AAC/B,qDAAmC;AACnC,qDAAmC;AACnC,uCAAqB;AACrB,iDAA+B"}
|
package/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './logger';
|
|
2
|
+
export * from './AppsembleError';
|
|
3
|
+
export * from './basicAuth';
|
|
4
|
+
export * from './formData';
|
|
5
|
+
export * from './getWorkspaces';
|
|
6
|
+
export * from './handleError';
|
|
7
|
+
export * from './interceptors';
|
|
8
|
+
export * from './loggerMiddleware';
|
|
9
|
+
export * from './readFileOrString';
|
|
10
|
+
export * from './fs';
|
|
11
|
+
export * from './testFixtures';
|
|
@@ -11,21 +11,21 @@ declare module 'axios' {
|
|
|
11
11
|
/**
|
|
12
12
|
* An {@link axios} request interceptor to add support for {@link form-data}.
|
|
13
13
|
*
|
|
14
|
-
* @param config
|
|
14
|
+
* @param config The axios request configuration.
|
|
15
15
|
* @returns The config with additional `multipart/form-data` headers if appropriate.
|
|
16
16
|
*/
|
|
17
17
|
export declare function formData(config: AxiosRequestConfig): AxiosRequestConfig;
|
|
18
18
|
/**
|
|
19
19
|
* An {@link axios} request interceptor to log requests.
|
|
20
20
|
*
|
|
21
|
-
* @param config
|
|
21
|
+
* @param config The axios request configuration.
|
|
22
22
|
* @returns The original config.
|
|
23
23
|
*/
|
|
24
24
|
export declare function requestLogger(config: AxiosRequestConfig): AxiosRequestConfig;
|
|
25
25
|
/**
|
|
26
26
|
* An {@link axios} response interceptor to log responses.
|
|
27
27
|
*
|
|
28
|
-
* @param response
|
|
28
|
+
* @param response The axios response.
|
|
29
29
|
* @returns The original response.
|
|
30
30
|
*/
|
|
31
31
|
export declare function responseLogger(response: AxiosResponse): AxiosResponse;
|
|
@@ -34,8 +34,8 @@ export declare function responseLogger(response: AxiosResponse): AxiosResponse;
|
|
|
34
34
|
*
|
|
35
35
|
* This applies the interceptors in this modules and sets the appropriate user agent string.
|
|
36
36
|
*
|
|
37
|
-
* @param name
|
|
38
|
-
* @param version
|
|
37
|
+
* @param name A PascalCase representation of the client.
|
|
38
|
+
* @param version The version of the client to represent.
|
|
39
39
|
*/
|
|
40
40
|
export declare function configureAxios(name: string, version: string): void;
|
|
41
41
|
export {};
|
|
@@ -16,7 +16,7 @@ const id = Symbol('id');
|
|
|
16
16
|
/**
|
|
17
17
|
* An {@link axios} request interceptor to add support for {@link form-data}.
|
|
18
18
|
*
|
|
19
|
-
* @param config
|
|
19
|
+
* @param config The axios request configuration.
|
|
20
20
|
* @returns The config with additional `multipart/form-data` headers if appropriate.
|
|
21
21
|
*/
|
|
22
22
|
function formData(config) {
|
|
@@ -29,7 +29,7 @@ exports.formData = formData;
|
|
|
29
29
|
/**
|
|
30
30
|
* An {@link axios} request interceptor to log requests.
|
|
31
31
|
*
|
|
32
|
-
* @param config
|
|
32
|
+
* @param config The axios request configuration.
|
|
33
33
|
* @returns The original config.
|
|
34
34
|
*/
|
|
35
35
|
function requestLogger(config) {
|
|
@@ -45,7 +45,7 @@ exports.requestLogger = requestLogger;
|
|
|
45
45
|
/**
|
|
46
46
|
* An {@link axios} response interceptor to log responses.
|
|
47
47
|
*
|
|
48
|
-
* @param response
|
|
48
|
+
* @param response The axios response.
|
|
49
49
|
* @returns The original response.
|
|
50
50
|
*/
|
|
51
51
|
function responseLogger(response) {
|
|
@@ -60,8 +60,8 @@ exports.responseLogger = responseLogger;
|
|
|
60
60
|
*
|
|
61
61
|
* This applies the interceptors in this modules and sets the appropriate user agent string.
|
|
62
62
|
*
|
|
63
|
-
* @param name
|
|
64
|
-
* @param version
|
|
63
|
+
* @param name A PascalCase representation of the client.
|
|
64
|
+
* @param version The version of the client to represent.
|
|
65
65
|
*/
|
|
66
66
|
function configureAxios(name, version) {
|
|
67
67
|
const ua = `${name}/${version} (${(0, os_1.type)()} ${(0, os_1.arch)()}; Node ${process.version})`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors.js","sourceRoot":"","sources":["interceptors.ts"],"names":[],"mappings":";;;;;;AAAA,2BAAgC;AAEhC,kDAAiE;AACjE,iDAA0C;AAC1C,0DAAiC;AAEjC,qCAAkC;AAElC;;GAEG;AACH,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;AAQxB;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,MAA0B;IACjD,IAAI,MAAM,CAAC,IAAI,YAAY,mBAAQ,EAAE;QACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;KACzD;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AALD,4BAKC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,MAA0B;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACxB,eAAM,CAAC,OAAO,CACZ,KAAK,IAAI,IAAI,IAAA,yBAAS,EAAC,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,eAAK,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE;QACxF,QAAQ,EAAE,MAAM;KACjB,CAAC,EAAE,CACL,CAAC;IACF,6CAA6C;IAC7C,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC;AAVD,sCAUC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,QAAuB;IACpD,eAAM,CAAC,OAAO,CACZ,KAAK,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAA,yBAAS,EAAC,YAAY,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,EAAE;QAC1F,QAAQ,EAAE,MAAM;KACjB,CAAC,EAAE,CACL,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAPD,wCAOC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,OAAe;IAC1D,MAAM,EAAE,GAAG,GAAG,IAAI,IAAI,OAAO,KAAK,IAAA,SAAI,GAAE,IAAI,IAAA,SAAI,GAAE,UAAU,OAAO,CAAC,OAAO,GAAG,CAAC;IAC/E,eAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;IAEjD,eAAK,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzC,eAAK,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC9C,eAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAClD,CAAC;AAPD,wCAOC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|