@appsemble/node-utils 0.20.10 → 0.20.13

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.
Files changed (122) hide show
  1. package/{dist/AppsembleError.d.ts → AppsembleError.d.ts} +1 -1
  2. package/{dist/AppsembleError.js → AppsembleError.js} +1 -1
  3. package/AppsembleError.js.map +1 -0
  4. package/AppsembleError.test.d.ts +1 -0
  5. package/AppsembleError.test.js +8 -0
  6. package/AppsembleError.test.js.map +1 -0
  7. package/AppsembleError.test.ts +6 -0
  8. package/AppsembleError.ts +16 -0
  9. package/README.md +4 -4
  10. package/__fixtures__/hello.txt +1 -0
  11. package/__fixtures__/invalid-json.json +3 -0
  12. package/__fixtures__/json.json +1 -0
  13. package/__fixtures__/test/bar.txt +0 -0
  14. package/__fixtures__/test/foo.txt +0 -0
  15. package/__fixtures__/test/z/baz.txt +0 -0
  16. package/__fixtures__/test/z/fooz.txt +0 -0
  17. package/__fixtures__/yaml.yaml +1 -0
  18. package/__mocks__/os.d.ts +5 -0
  19. package/__mocks__/os.js +8 -0
  20. package/__mocks__/os.js.map +1 -0
  21. package/__mocks__/os.ts +10 -0
  22. package/{dist/basicAuth.d.ts → basicAuth.d.ts} +2 -2
  23. package/{dist/basicAuth.js → basicAuth.js} +2 -2
  24. package/basicAuth.js.map +1 -0
  25. package/basicAuth.test.d.ts +1 -0
  26. package/basicAuth.test.js +8 -0
  27. package/basicAuth.test.js.map +1 -0
  28. package/basicAuth.test.ts +6 -0
  29. package/basicAuth.ts +10 -0
  30. package/changed/added/.gitkeep +0 -0
  31. package/changed/changed/.gitkeep +0 -0
  32. package/changed/deprecated/.gitkeep +0 -0
  33. package/changed/fixed/.gitkeep +0 -0
  34. package/changed/removed/.gitkeep +0 -0
  35. package/changed/security/.gitkeep +0 -0
  36. package/{dist/formData.d.ts → formData.d.ts} +1 -1
  37. package/{dist/formData.js → formData.js} +1 -1
  38. package/formData.js.map +1 -0
  39. package/formData.test.d.ts +1 -0
  40. package/formData.test.js +94 -0
  41. package/formData.test.js.map +1 -0
  42. package/formData.test.ts +113 -0
  43. package/formData.ts +37 -0
  44. package/{dist/fs.d.ts → fs.d.ts} +10 -10
  45. package/{dist/fs.js → fs.js} +16 -16
  46. package/fs.js.map +1 -0
  47. package/fs.test.d.ts +1 -0
  48. package/fs.test.js +76 -0
  49. package/fs.test.js.map +1 -0
  50. package/fs.test.ts +120 -0
  51. package/fs.ts +144 -0
  52. package/{dist/getWorkspaces.d.ts → getWorkspaces.d.ts} +1 -1
  53. package/{dist/getWorkspaces.js → getWorkspaces.js} +3 -3
  54. package/getWorkspaces.js.map +1 -0
  55. package/getWorkspaces.ts +23 -0
  56. package/{dist/handleError.d.ts → handleError.d.ts} +3 -3
  57. package/{dist/handleError.js → handleError.js} +3 -3
  58. package/handleError.js.map +1 -0
  59. package/handleError.test.d.ts +1 -0
  60. package/handleError.test.js +34 -0
  61. package/handleError.test.js.map +1 -0
  62. package/handleError.test.ts +38 -0
  63. package/handleError.ts +26 -0
  64. package/{dist/index.d.ts → index.d.ts} +0 -0
  65. package/{dist/index.js → index.js} +0 -0
  66. package/index.js.map +1 -0
  67. package/index.ts +11 -0
  68. package/{dist/interceptors.d.ts → interceptors.d.ts} +5 -5
  69. package/{dist/interceptors.js → interceptors.js} +5 -5
  70. package/interceptors.js.map +1 -0
  71. package/interceptors.test.d.ts +1 -0
  72. package/interceptors.test.js +93 -0
  73. package/interceptors.test.js.map +1 -0
  74. package/interceptors.test.ts +108 -0
  75. package/interceptors.ts +81 -0
  76. package/jest.config.js +1 -0
  77. package/jest.setup.d.ts +1 -0
  78. package/jest.setup.js +9 -0
  79. package/jest.setup.js.map +1 -0
  80. package/jest.setup.ts +7 -0
  81. package/{dist/logger.d.ts → logger.d.ts} +2 -2
  82. package/{dist/logger.js → logger.js} +6 -6
  83. package/logger.js.map +1 -0
  84. package/logger.test.d.ts +1 -0
  85. package/logger.test.js +38 -0
  86. package/logger.test.js.map +1 -0
  87. package/logger.test.ts +43 -0
  88. package/logger.ts +130 -0
  89. package/{dist/loggerMiddleware.d.ts → loggerMiddleware.d.ts} +0 -0
  90. package/{dist/loggerMiddleware.js → loggerMiddleware.js} +18 -15
  91. package/loggerMiddleware.js.map +1 -0
  92. package/loggerMiddleware.test.d.ts +1 -0
  93. package/loggerMiddleware.test.js +130 -0
  94. package/loggerMiddleware.test.js.map +1 -0
  95. package/loggerMiddleware.test.ts +185 -0
  96. package/loggerMiddleware.ts +93 -0
  97. package/package.json +7 -6
  98. package/{dist/readFileOrString.d.ts → readFileOrString.d.ts} +1 -1
  99. package/{dist/readFileOrString.js → readFileOrString.js} +3 -3
  100. package/readFileOrString.js.map +1 -0
  101. package/readFileOrString.test.d.ts +1 -0
  102. package/readFileOrString.test.js +13 -0
  103. package/readFileOrString.test.js.map +1 -0
  104. package/readFileOrString.test.ts +12 -0
  105. package/readFileOrString.ts +20 -0
  106. package/{dist/testFixtures.d.ts → testFixtures.d.ts} +5 -5
  107. package/{dist/testFixtures.js → testFixtures.js} +5 -4
  108. package/testFixtures.js.map +1 -0
  109. package/testFixtures.ts +58 -0
  110. package/tsconfig.json +6 -0
  111. package/dist/AppsembleError.js.map +0 -1
  112. package/dist/basicAuth.js.map +0 -1
  113. package/dist/formData.js.map +0 -1
  114. package/dist/fs.js.map +0 -1
  115. package/dist/getWorkspaces.js.map +0 -1
  116. package/dist/handleError.js.map +0 -1
  117. package/dist/index.js.map +0 -1
  118. package/dist/interceptors.js.map +0 -1
  119. package/dist/logger.js.map +0 -1
  120. package/dist/loggerMiddleware.js.map +0 -1
  121. package/dist/readFileOrString.js.map +0 -1
  122. package/dist/testFixtures.js.map +0 -1
package/fs.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["fs.ts"],"names":[],"mappings":"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"}
package/fs.test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
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":";;AAAA,wBAAmF;AAEnF,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,IAAA,UAAO,EAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,IAAA,UAAO,EAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,IAAA,UAAO,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,CAAC,IAAA,UAAO,EAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,IAAA,UAAO,EAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,CAAC,IAAA,UAAO,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,OAAO,GAAG,MAAM,IAAA,WAAQ,EAAC,IAAA,iBAAc,EAAC,WAAW,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,OAAO,GAAG,MAAM,IAAA,WAAQ,EAAC,IAAA,iBAAc,EAAC,WAAW,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,IAAI,GAAG,IAAA,iBAAc,EAAC,WAAW,CAAC,CAAC;QACzC,MAAM,MAAM,CAAC,IAAA,WAAQ,EAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC1C,IAAI,iBAAc,CAAC,2BAA2B,IAAI,EAAE,CAAC,CACtD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,MAAM,CAAC,IAAA,WAAQ,EAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACzD,IAAI,iBAAc,CAAC,sCAAsC,CAAC,CAC3D,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,IAAI,GAAG,IAAA,iBAAc,EAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,MAAM,CAAC,IAAA,WAAQ,EAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAc,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,IAAA,cAAW,EAAC,IAAA,iBAAc,EAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,cAAc,CAAC,EAC9B,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,cAAc,CAAC,EAC9B,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,QAAQ,CAAC,EACxB,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CACvC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACzB,MAAM,IAAA,cAAW,EAAC,IAAA,iBAAc,EAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,cAAc,CAAC,EAC9B,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,cAAc,CAAC,EAC9B,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,QAAQ,CAAC,EACxB,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CACvC,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,gBAAgB,CAAC,EAChC,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAC7C,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CACjC,IAAA,iBAAc,EAAC,iBAAiB,CAAC,EACjC,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAC9C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,IAAI,GAAG,IAAA,iBAAc,EAAC,WAAW,CAAC,CAAC;QACzC,MAAM,MAAM,CAAC,IAAA,cAAW,EAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACxD,IAAI,iBAAc,CAAC,YAAY,IAAI,oBAAoB,CAAC,CACzD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,IAAI,GAAG,IAAA,iBAAc,EAAC,cAAc,CAAC,CAAC;QAC5C,MAAM,MAAM,CAAC,IAAA,cAAW,EAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACxD,IAAI,iBAAc,CAAC,YAAY,IAAI,oBAAoB,CAAC,CACzD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,IAAI,GAAG,IAAA,iBAAc,EAAC,cAAc,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAA,cAAW,EAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
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 - The project root in which to find workspaces.
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 fs_1 = require("fs");
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 - The project root in which to find workspaces.
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 fs_1.promises.readFile((0, path_1.join)(cwd, 'package.json'), 'utf8'));
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"}
@@ -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 - Unused.
8
- * @param error - The error that was thrown.
9
- * @param yargs - The active yargs instance.
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 - Unused.
12
- * @param error - The error that was thrown.
13
- * @param yargs - The active yargs instance.
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 - The axios request configuration.
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 - The axios request configuration.
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 - The axios 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 - A PascalCase representation of the client.
38
- * @param version - The version of the client to represent.
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 {};