@e22m4u/js-openapi 0.0.5

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 (84) hide show
  1. package/.c8rc +9 -0
  2. package/.commitlintrc +5 -0
  3. package/.editorconfig +13 -0
  4. package/.husky/commit-msg +1 -0
  5. package/.husky/pre-commit +6 -0
  6. package/.mocharc.json +4 -0
  7. package/.prettierrc +7 -0
  8. package/LICENSE +21 -0
  9. package/README.md +510 -0
  10. package/build-cjs.js +16 -0
  11. package/dist/cjs/index.cjs +2695 -0
  12. package/eslint.config.js +41 -0
  13. package/package.json +64 -0
  14. package/src/data-type/index.d.ts +1 -0
  15. package/src/data-type/index.js +1 -0
  16. package/src/data-type/infer-openapi-data-type.d.ts +30 -0
  17. package/src/data-type/infer-openapi-data-type.js +38 -0
  18. package/src/data-validation/data-format-validator-map.d.ts +13 -0
  19. package/src/data-validation/data-format-validator-map.js +36 -0
  20. package/src/data-validation/data-format-validator-map.spec.js +39 -0
  21. package/src/data-validation/data-format-validators.d.ts +84 -0
  22. package/src/data-validation/data-format-validators.js +217 -0
  23. package/src/data-validation/index.d.ts +3 -0
  24. package/src/data-validation/index.js +3 -0
  25. package/src/data-validation/validate-data-with-openapi-schema.d.ts +46 -0
  26. package/src/data-validation/validate-data-with-openapi-schema.js +1913 -0
  27. package/src/data-validation/validate-data-with-openapi-schema.spec.js +6953 -0
  28. package/src/errors/index.d.ts +1 -0
  29. package/src/errors/index.js +1 -0
  30. package/src/errors/oa-data-validation-error.d.ts +6 -0
  31. package/src/errors/oa-data-validation-error.js +6 -0
  32. package/src/errors/oa-data-validation-error.spec.js +17 -0
  33. package/src/index.d.ts +9 -0
  34. package/src/index.js +9 -0
  35. package/src/json-pointer/escape-json-pointer.d.ts +7 -0
  36. package/src/json-pointer/escape-json-pointer.js +18 -0
  37. package/src/json-pointer/escape-json-pointer.spec.js +36 -0
  38. package/src/json-pointer/index.d.ts +3 -0
  39. package/src/json-pointer/index.js +3 -0
  40. package/src/json-pointer/resolve-json-pointer.d.ts +10 -0
  41. package/src/json-pointer/resolve-json-pointer.js +83 -0
  42. package/src/json-pointer/resolve-json-pointer.spec.js +103 -0
  43. package/src/json-pointer/unescape-json-pointer.d.ts +8 -0
  44. package/src/json-pointer/unescape-json-pointer.js +18 -0
  45. package/src/json-pointer/unescape-json-pointer.spec.js +32 -0
  46. package/src/oa-document-builder.d.ts +312 -0
  47. package/src/oa-document-builder.js +450 -0
  48. package/src/oa-document-object/index.d.ts +1 -0
  49. package/src/oa-document-object/index.js +1 -0
  50. package/src/oa-document-object/validate-shallow-oa-document.d.ts +10 -0
  51. package/src/oa-document-object/validate-shallow-oa-document.js +209 -0
  52. package/src/oa-document-object/validate-shallow-oa-document.spec.js +362 -0
  53. package/src/oa-document-scope.d.ts +52 -0
  54. package/src/oa-document-scope.js +228 -0
  55. package/src/oa-reference-object/index.d.ts +3 -0
  56. package/src/oa-reference-object/index.js +3 -0
  57. package/src/oa-reference-object/is-oa-reference-object.d.ts +9 -0
  58. package/src/oa-reference-object/is-oa-reference-object.js +14 -0
  59. package/src/oa-reference-object/is-oa-reference-object.spec.js +19 -0
  60. package/src/oa-reference-object/oa-ref.d.ts +11 -0
  61. package/src/oa-reference-object/oa-ref.js +31 -0
  62. package/src/oa-reference-object/oa-ref.spec.js +56 -0
  63. package/src/oa-reference-object/resolve-oa-reference-object.d.ts +18 -0
  64. package/src/oa-reference-object/resolve-oa-reference-object.js +113 -0
  65. package/src/oa-reference-object/resolve-oa-reference-object.spec.js +233 -0
  66. package/src/oa-specification.d.ts +767 -0
  67. package/src/oa-specification.js +153 -0
  68. package/src/types.d.ts +4 -0
  69. package/src/utils/count-unicode.d.ts +11 -0
  70. package/src/utils/count-unicode.js +15 -0
  71. package/src/utils/index.d.ts +5 -0
  72. package/src/utils/index.js +5 -0
  73. package/src/utils/join-path.d.ts +6 -0
  74. package/src/utils/join-path.js +36 -0
  75. package/src/utils/join-path.spec.js +104 -0
  76. package/src/utils/normalize-path.d.ts +12 -0
  77. package/src/utils/normalize-path.js +22 -0
  78. package/src/utils/normalize-path.spec.js +56 -0
  79. package/src/utils/to-pascal-case.d.ts +6 -0
  80. package/src/utils/to-pascal-case.js +26 -0
  81. package/src/utils/to-pascal-case.spec.js +15 -0
  82. package/src/utils/to-spaced-json.d.ts +17 -0
  83. package/src/utils/to-spaced-json.js +27 -0
  84. package/tsconfig.json +14 -0
@@ -0,0 +1,153 @@
1
+ // OpenApi version 3.1.0
2
+ // https://spec.openapis.org/oas/v3.1.0
3
+
4
+ /**
5
+ * OpenAPI version.
6
+ */
7
+ export const OPENAPI_VERSION = '3.1.0';
8
+
9
+ /**
10
+ * Operation Method.
11
+ * https://spec.openapis.org/oas/v3.1.0#path-item-object
12
+ */
13
+ export const OAOperationMethod = {
14
+ GET: 'get',
15
+ PUT: 'put',
16
+ POST: 'post',
17
+ DELETE: 'delete',
18
+ OPTIONS: 'options',
19
+ HEAD: 'head',
20
+ PATCH: 'patch',
21
+ TRACE: 'trace',
22
+ };
23
+
24
+ /**
25
+ * Parameter Location.
26
+ * https://spec.openapis.org/oas/v3.1.0#parameter-locations
27
+ */
28
+ export const OAParameterLocation = {
29
+ QUERY: 'query',
30
+ HEADER: 'header',
31
+ PATH: 'path',
32
+ COOKIE: 'cookie',
33
+ };
34
+
35
+ /**
36
+ * Parameter Style.
37
+ * https://spec.openapis.org/oas/v3.1.0#style-values
38
+ */
39
+ export const OAParameterStyle = {
40
+ MATRIX: 'matrix',
41
+ LABEL: 'label',
42
+ FORM: 'form',
43
+ SIMPLE: 'simple',
44
+ SPACE_DELIMITED: 'spaceDelimited',
45
+ PIPE_DELIMITED: 'pipeDelimited',
46
+ DEEP_OBJECT: 'deepObject',
47
+ };
48
+
49
+ /**
50
+ * Data type.
51
+ * https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-00#section-4.2.1
52
+ */
53
+ export const OADataType = {
54
+ STRING: 'string',
55
+ NUMBER: 'number',
56
+ INTEGER: 'integer',
57
+ BOOLEAN: 'boolean',
58
+ OBJECT: 'object',
59
+ ARRAY: 'array',
60
+ NULL: 'null',
61
+ };
62
+
63
+ /**
64
+ * Data type list.
65
+ * https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-00#section-4.2.1
66
+ */
67
+ export const OA_DATA_TYPE_LIST = Object.values(OADataType);
68
+
69
+ /**
70
+ * Data format.
71
+ * https://spec.openapis.org/oas/v3.1.0#dataTypeFormat
72
+ */
73
+ export const OADataFormat = {
74
+ // number
75
+ INT32: 'int32',
76
+ INT64: 'int64',
77
+ FLOAT: 'float',
78
+ DOUBLE: 'double',
79
+ // date and time
80
+ DATE: 'date',
81
+ DATE_TIME: 'date-time',
82
+ TIME: 'time',
83
+ DURATION: 'duration',
84
+ // binary
85
+ BYTE: 'byte',
86
+ BINARY: 'binary',
87
+ // identifiers and network
88
+ EMAIL: 'email',
89
+ IDN_EMAIL: 'idn-email',
90
+ UUID: 'uuid',
91
+ HOSTNAME: 'hostname',
92
+ IDN_HOSTNAME: 'idn-hostname',
93
+ IPV4: 'ipv4',
94
+ IPV6: 'ipv6',
95
+ URI: 'uri',
96
+ URI_REFERENCE: 'uri-reference',
97
+ IRI: 'iri',
98
+ IRI_REFERENCE: 'iri-reference',
99
+ // extra
100
+ PASSWORD: 'password',
101
+ REGEX: 'regex',
102
+ JSON_POINTER: 'json-pointer',
103
+ RELATIVE_JSON_POINTER: 'relative-json-pointer',
104
+ };
105
+
106
+ /**
107
+ * Media type.
108
+ * https://spec.openapis.org/oas/v3.1.0#media-types
109
+ */
110
+ export const OAMediaType = {
111
+ TEXT_PLAIN: 'text/plain',
112
+ TEXT_HTML: 'text/html',
113
+ APPLICATION_XML: 'application/xml',
114
+ APPLICATION_JSON: 'application/json',
115
+ MULTIPART_FORM_DATA: 'multipart/form-data',
116
+ };
117
+
118
+ /**
119
+ * Security Scheme Type.
120
+ * https://spec.openapis.org/oas/v3.1.0#security-scheme-object
121
+ */
122
+ export const OASecuritySchemeType = {
123
+ API_KEY: 'apiKey',
124
+ HTTP: 'http',
125
+ MUTUAL_TLS: 'mutualTLS',
126
+ OAUTH_2: 'oauth2',
127
+ OPEN_ID_CONNECT: 'openIdConnect',
128
+ };
129
+
130
+ /**
131
+ * Api Key Location.
132
+ * https://spec.openapis.org/oas/v3.1.0#security-scheme-object
133
+ */
134
+ export const OAApiKeyLocation = {
135
+ QUERY: 'query',
136
+ HEADER: 'header',
137
+ COOKIE: 'cookie',
138
+ };
139
+
140
+ /**
141
+ * Access mode.
142
+ * https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-01#name-readonly-and-writeonly
143
+ */
144
+ export const OAAccessMode = {
145
+ READ: 'read',
146
+ WRITE: 'write',
147
+ };
148
+
149
+ /**
150
+ * Access mode list.
151
+ * https://datatracker.ietf.org/doc/html/draft-bhutton-json-schema-validation-01#name-readonly-and-writeonly
152
+ */
153
+ export const ACCESS_MODE_LIST = Object.values(OAAccessMode);
package/src/types.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Make specific properties optional.
3
+ */
4
+ export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Count unicode.
3
+ *
4
+ * Подсчет длины строки выполняется с учетом символов, выходящих
5
+ * за пределы BMP (Basic Multilingual Plane) например, эмодзи
6
+ * или некоторые иероглифы в JS имеют `.length === 2`,
7
+ * но должны считаться за один символ.
8
+ *
9
+ * @param data
10
+ */
11
+ export function countUnicode(data: string): number;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Count unicode.
3
+ *
4
+ * Подсчет длины строки выполняется с учетом символов, выходящих
5
+ * за пределы BMP (Basic Multilingual Plane) например, эмодзи
6
+ * или некоторые иероглифы в JS имеют `.length === 2`,
7
+ * но должны считаться за один символ.
8
+ *
9
+ * @param {string} data
10
+ * @returns {number}
11
+ */
12
+ export function countUnicode(data) {
13
+ const matchedChars = String(data).match(/[\s\S]/gu);
14
+ return Array.isArray(matchedChars) ? matchedChars.length : 0;
15
+ }
@@ -0,0 +1,5 @@
1
+ export * from './join-path.js';
2
+ export * from './count-unicode.js';
3
+ export * from './normalize-path.js';
4
+ export * from './to-spaced-json.js';
5
+ export * from './to-pascal-case.js';
@@ -0,0 +1,5 @@
1
+ export * from './join-path.js';
2
+ export * from './count-unicode.js';
3
+ export * from './normalize-path.js';
4
+ export * from './to-spaced-json.js';
5
+ export * from './to-pascal-case.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Joins URL paths.
3
+ *
4
+ * @param segments
5
+ */
6
+ export declare function joinPath(...segments: (string | number)[]): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Joins URL paths.
3
+ *
4
+ * @param {...string} segments
5
+ * @returns {string}
6
+ */
7
+ export function joinPath(...segments) {
8
+ // фильтрация пустых значений (null, undefined, "")
9
+ const parts = segments.filter(seg => seg != undefined && String(seg) !== '');
10
+ if (parts.length === 0) {
11
+ return '/';
12
+ }
13
+ // простое объединение через разделитель
14
+ // и замена множественных слешей на один
15
+ let joined = parts.join('/').replace(/\/+/g, '/');
16
+ // проверка на наличие протокола в начале строки
17
+ // RFC 3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
18
+ const protocolRegex = /^([a-z][a-z0-9+.-]*):\//i;
19
+ const protocolMatch = joined.match(protocolRegex);
20
+ if (protocolMatch) {
21
+ // если это URL (есть схема), то восстанавливается
22
+ // двойной слеш "https:/" -> "https://"
23
+ joined = joined.replace(protocolRegex, '$1://');
24
+ } else {
25
+ // если это не URL, а путь файловой системы или API,
26
+ // то гарантируется наличие слеша в начале
27
+ if (!joined.startsWith('/')) {
28
+ joined = '/' + joined;
29
+ }
30
+ }
31
+ // удаление слеша в конце, если это не корень
32
+ if (joined.length > 1 && joined.endsWith('/')) {
33
+ joined = joined.slice(0, -1);
34
+ }
35
+ return joined;
36
+ }
@@ -0,0 +1,104 @@
1
+ import {expect} from 'chai';
2
+ import {joinPath} from './join-path.js';
3
+
4
+ describe('joinPath', function () {
5
+ describe('path joining', function () {
6
+ it('should join multiple segments with a forward slash', function () {
7
+ const result = joinPath('api', 'v1', 'users');
8
+ expect(result).to.be.eq('/api/v1/users');
9
+ });
10
+
11
+ it('should always return a path starting with a single forward slash', function () {
12
+ expect(joinPath('users')).to.be.eq('/users');
13
+ expect(joinPath('/users')).to.be.eq('/users');
14
+ });
15
+
16
+ it('should remove leading slashes from segments', function () {
17
+ const result = joinPath('/api', '/v1', '/users');
18
+ expect(result).to.be.eq('/api/v1/users');
19
+ });
20
+
21
+ it('should remove trailing slashes from segments', function () {
22
+ const result = joinPath('api/', 'v1/', 'users/');
23
+ expect(result).to.be.eq('/api/v1/users');
24
+ });
25
+
26
+ it('should handle segments with both leading and trailing slashes', function () {
27
+ const result = joinPath('/api/', '/v1/', '/users/');
28
+ expect(result).to.be.eq('/api/v1/users');
29
+ });
30
+
31
+ it('should ignore empty string segments', function () {
32
+ const result = joinPath('api', '', 'v1', '', 'users');
33
+ expect(result).to.be.eq('/api/v1/users');
34
+ });
35
+
36
+ it('should ignore null and undefined segments', function () {
37
+ const result = joinPath('api', null, 'v1', undefined, 'users');
38
+ expect(result).to.be.eq('/api/v1/users');
39
+ });
40
+
41
+ it('should handle a single segment correctly', function () {
42
+ expect(joinPath('users')).to.be.eq('/users');
43
+ expect(joinPath('/users/')).to.be.eq('/users');
44
+ });
45
+
46
+ it('should return a single slash when no segments are provided', function () {
47
+ const result = joinPath();
48
+ expect(result).to.be.eq('/');
49
+ });
50
+
51
+ it('should return a single slash if all segments are empty or falsy', function () {
52
+ const result = joinPath('', null, '', undefined);
53
+ expect(result).to.be.eq('/');
54
+ });
55
+
56
+ it('should treat a single slash segment as an empty segment', function () {
57
+ const result = joinPath('api', '/', 'users');
58
+ expect(result).to.be.eq('/api/users');
59
+ });
60
+
61
+ it('should not add extra slashes if segments are already joined', function () {
62
+ const result = joinPath('api/v1', 'users');
63
+ expect(result).to.be.eq('/api/v1/users');
64
+ });
65
+
66
+ it('should convert number arguments to string segments', function () {
67
+ const result = joinPath(-10, 0, 10);
68
+ expect(result).to.be.eq('/-10/0/10');
69
+ });
70
+
71
+ it('should remove duplicate slashes', function () {
72
+ const result = joinPath('/', '//foo//', '///bar///');
73
+ expect(result).to.be.eq('/foo/bar');
74
+ });
75
+ });
76
+
77
+ describe('url joining', function () {
78
+ it('should preserve http:// protocol', function () {
79
+ const result = joinPath('http://example.com', 'api', 'v1');
80
+ expect(result).to.be.eq('http://example.com/api/v1');
81
+ });
82
+
83
+ it('should preserve https:// protocol', function () {
84
+ const result = joinPath('https://api.example.com/', '/users');
85
+ expect(result).to.be.eq('https://api.example.com/users');
86
+ });
87
+
88
+ it('should handle protocols with extra slashes in segments', function () {
89
+ const result = joinPath('https://site.com//', '//api//');
90
+ expect(result).to.be.eq('https://site.com/api');
91
+ });
92
+
93
+ it('should handle custom protocols (e.g. postgres://)', function () {
94
+ const result = joinPath('postgres://user:pass@localhost', 'db');
95
+ expect(result).to.be.eq('postgres://user:pass@localhost/db');
96
+ });
97
+
98
+ it('should not add a leading slash if a protocol is present', function () {
99
+ const result = joinPath('http://localhost');
100
+ expect(result).to.be.eq('http://localhost');
101
+ expect(result.startsWith('/')).to.be.false;
102
+ });
103
+ });
104
+ });
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Normalize path.
3
+ *
4
+ * Заменяет любые повторяющиеся слеши на один.
5
+ * Удаляет пробельные символы в начале и конце.
6
+ * Удаляет слеш в конце строки.
7
+ * Гарантирует слеш в начале строки (по умолчанию).
8
+ *
9
+ * @param value
10
+ * @param noStartingSlash
11
+ */
12
+ export function normalizePath(value: string, noStartingSlash?: boolean): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Normalize path.
3
+ *
4
+ * Заменяет любые повторяющиеся слеши на один.
5
+ * Удаляет пробельные символы в начале и конце.
6
+ * Удаляет слеш в конце строки.
7
+ * Гарантирует слеш в начале строки (по умолчанию).
8
+ *
9
+ * @param {string} value
10
+ * @param {boolean} [noStartingSlash]
11
+ * @returns {string}
12
+ */
13
+ export function normalizePath(value, noStartingSlash = false) {
14
+ if (typeof value !== 'string') {
15
+ return '/';
16
+ }
17
+ const res = value
18
+ .trim()
19
+ .replace(/\/+/g, '/')
20
+ .replace(/(^\/|\/$)/g, '');
21
+ return noStartingSlash ? res : '/' + res;
22
+ }
@@ -0,0 +1,56 @@
1
+ import {expect} from 'chai';
2
+ import {normalizePath} from './normalize-path.js';
3
+
4
+ describe('normalizePath', function () {
5
+ describe('input validation', function () {
6
+ it('should return a root path "/" if value is null', function () {
7
+ expect(normalizePath(null)).to.equal('/');
8
+ });
9
+
10
+ it('should return a root path "/" if value is undefined', function () {
11
+ expect(normalizePath(undefined)).to.equal('/');
12
+ });
13
+
14
+ it('should return a root path "/" if value is a number', function () {
15
+ expect(normalizePath(123)).to.equal('/');
16
+ });
17
+
18
+ it('should return a root path "/" if value is an object', function () {
19
+ expect(normalizePath({})).to.equal('/');
20
+ });
21
+ });
22
+
23
+ describe('path normalization', function () {
24
+ it('should replace multiple slashes with a single slash', function () {
25
+ expect(normalizePath('//api///users//')).to.equal('/api/users');
26
+ });
27
+
28
+ it('should trim a given string but preserve whitespace characters', function () {
29
+ expect(normalizePath(' /my folder/ ')).to.equal('/my folder');
30
+ expect(normalizePath('path\twith\ntabs')).to.equal('/path\twith\ntabs');
31
+ });
32
+
33
+ it('should remove leading and trailing slashes before applying the final format', function () {
34
+ expect(normalizePath('/foo/bar/')).to.equal('/foo/bar');
35
+ });
36
+
37
+ it('should handle an empty string by returning "/" by default', function () {
38
+ expect(normalizePath('')).to.equal('/');
39
+ });
40
+ });
41
+
42
+ describe('the "noStartingSlash" option', function () {
43
+ it('should always prepend a leading slash when the option is false', function () {
44
+ expect(normalizePath('foo/bar', false)).to.equal('/foo/bar');
45
+ });
46
+
47
+ it('should not prepend a leading slash when the option is true', function () {
48
+ expect(normalizePath('/foo/bar/', true)).to.equal('foo/bar');
49
+ });
50
+
51
+ it('should return an empty string if the input results in an empty path', function () {
52
+ expect(normalizePath('', true)).to.equal('');
53
+ expect(normalizePath('///', true)).to.equal('');
54
+ });
55
+ });
56
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * To pascal case.
3
+ *
4
+ * @param input
5
+ */
6
+ export declare function toPascalCase(input: string): string;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * To pascal case.
3
+ *
4
+ * @param {string} input
5
+ * @returns {string}
6
+ */
7
+ export function toPascalCase(input) {
8
+ if (!input) {
9
+ return '';
10
+ }
11
+ return (
12
+ input
13
+ // splits camelCase words into separate words
14
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
15
+ // splits numbers and words
16
+ .replace(/([0-9])([a-zA-Z])/g, '$1 $2')
17
+ // replaces dashes, underscores, and special characters with spaces
18
+ .replace(/[-_]+|[^\p{L}\p{N}]/gu, ' ')
19
+ // converts the entire string to lowercase
20
+ .toLowerCase()
21
+ // capitalizes the first letter of each word
22
+ .replace(/(?:^|\s)(\p{L})/gu, (_, letter) => letter.toUpperCase())
23
+ // removes all spaces
24
+ .replace(/\s+/g, '')
25
+ );
26
+ }
@@ -0,0 +1,15 @@
1
+ import {expect} from 'chai';
2
+ import {toPascalCase} from './to-pascal-case.js';
3
+
4
+ describe('toPascalCase', function () {
5
+ it('returns a PascalCase string', function () {
6
+ expect(toPascalCase('hello world')).to.be.eq('HelloWorld');
7
+ expect(toPascalCase('snake_case')).to.be.eq('SnakeCase');
8
+ expect(toPascalCase('kebab-case')).to.be.eq('KebabCase');
9
+ expect(toPascalCase('alreadyCamel')).to.be.eq('AlreadyCamel');
10
+ expect(toPascalCase('AlreadyPascal')).to.be.eq('AlreadyPascal');
11
+ expect(toPascalCase(' single word ')).to.be.eq('SingleWord');
12
+ expect(toPascalCase('')).to.be.eq('');
13
+ expect(toPascalCase('1number')).to.be.eq('1Number');
14
+ });
15
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * To spaced JSON options.
3
+ */
4
+ export type ToSpacedJsonOptions = {
5
+ truncate?: number;
6
+ };
7
+
8
+ /**
9
+ * Функция превращает объект в JSON с пробелами,
10
+ * но в одну строку.
11
+ *
12
+ * @param value
13
+ */
14
+ export function toSpacedJson(
15
+ value: unknown,
16
+ options?: ToSpacedJsonOptions,
17
+ ): string;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Функция превращает объект в JSON с пробелами,
3
+ * но в одну строку.
4
+ *
5
+ * @param {*} value
6
+ * @param {*} [options]
7
+ * @returns {string}
8
+ */
9
+ export function toSpacedJson(value, options = {}) {
10
+ const stringified = JSON.stringify(value, null, 1);
11
+ const res = stringified
12
+ ? stringified
13
+ .replace(/\n\s*/g, ' ')
14
+ .replace(/\[\s/g, '[')
15
+ .replace(/\s\]/g, ']')
16
+ .replace(/\{\s/g, '{')
17
+ .replace(/\s\}/g, '}')
18
+ : 'undefined';
19
+ if (
20
+ options.truncate &&
21
+ typeof options.truncate === 'number' &&
22
+ res.length > options.truncate
23
+ ) {
24
+ return res.slice(0, options.truncate) + '...';
25
+ }
26
+ return res;
27
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ "target": "es2022",
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "noEmit": true,
8
+ "allowJs": true
9
+ },
10
+ "include": [
11
+ "./src/**/*.ts",
12
+ "./src/**/*.js"
13
+ ]
14
+ }