@chubbyts/chubbyts-decode-encode 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2022 Dominik Zogg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # chubbyts-decode-encode
2
+
3
+ [![CI](https://github.com/chubbyts/chubbyts-decode-encode/workflows/CI/badge.svg?branch=master)](https://github.com/chubbyts/chubbyts-decode-encode/actions?query=workflow%3ACI)
4
+ [![Coverage Status](https://coveralls.io/repos/github/chubbyts/chubbyts-decode-encode/badge.svg?branch=master)](https://coveralls.io/github/chubbyts/chubbyts-decode-encode?branch=master)
5
+ [![Infection MSI](https://badge.stryker-mutator.io/github.com/chubbyts/chubbyts-decode-encode/master)](https://dashboard.stryker-mutator.io/reports/github.com/chubbyts/chubbyts-decode-encode/master)
6
+ [![npm-version](https://img.shields.io/npm/v/@chubbyts/chubbyts-decode-encode.svg)](https://www.npmjs.com/package/@chubbyts/chubbyts-decode-encode)
7
+
8
+ [![bugs](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=bugs)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
9
+ [![code_smells](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=code_smells)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
10
+ [![coverage](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=coverage)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
11
+ [![duplicated_lines_density](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
12
+ [![ncloc](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=ncloc)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
13
+ [![sqale_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
14
+ [![alert_status](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=alert_status)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
15
+ [![reliability_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
16
+ [![security_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=security_rating)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
17
+ [![sqale_index](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=sqale_index)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
18
+ [![vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_chubbyts-decode-encode&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=chubbyts_chubbyts-decode-encode)
19
+
20
+ ## Description
21
+
22
+ A simple decode/encode solution for json / jsonx / url-encoded / xml / yaml.
23
+
24
+ ## Requirements
25
+
26
+ * node: 14
27
+ * [fast-xml-parser][2]: ^4.0.8
28
+ * [object-path][3]: ^0.11.8
29
+ * [yaml][4]: ^2.1.1
30
+
31
+ ## Installation
32
+
33
+ Through [NPM](https://www.npmjs.com) as [@chubbyts/chubbyts-decode-encode][1].
34
+
35
+ ```ts
36
+ npm i @chubbyts/chubbyts-decode-encode@^1.0.0
37
+ ```
38
+
39
+ ## Usage
40
+
41
+ ### Decoder
42
+
43
+ #### createDecoder
44
+
45
+ ```ts
46
+ import { createDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder';
47
+ import { createJsonTypeDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder/json-type-decoder';
48
+
49
+ const decoder = createDecoder([createJsonTypeDecoder()]);
50
+ const data = decoder.decode('{"key":"value"}', 'application/json');
51
+ // data: {key: "value"}
52
+ const contentTypes = decoder.contentTypes;
53
+ // contentTypes: ['application/json']
54
+ ```
55
+
56
+ #### createJsonTypeDecoder
57
+
58
+ ```ts
59
+ import { createJsonTypeDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder/json-type-decoder';
60
+
61
+ const jsonTypeDecoder = createJsonTypeDecoder();
62
+ const data = jsonTypeDecoder.decode('{"key":"value"}');
63
+ // data: {key: "value"}
64
+ const contentType = jsonTypeDecoder.contentType;
65
+ // contentType: 'application/json'
66
+ ```
67
+
68
+ #### createJsonxTypeDecoder
69
+
70
+ ```ts
71
+ import { createJsonxTypeDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder/jsonx-type-decoder';
72
+
73
+ const jsonxTypeDecoder = createJsonxTypeDecoder();
74
+ const data = jsonxTypeDecoder.decode(`
75
+ <?xml version="1.0" encoding="UTF-8"?>
76
+ <json:object>
77
+ <json:string name="key">value</json:string>
78
+ </json:object>
79
+ `);
80
+ // data: {key: "value"}
81
+ const contentType = jsonxTypeDecoder.contentType;
82
+ // contentType: 'application/jsonx+xml'
83
+ ```
84
+
85
+ #### createUrlEncodedTypeDecoder
86
+
87
+ ```ts
88
+ import { createUrlEncodedTypeDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder/url-encoded-type-decoder';
89
+
90
+ const urlEncodedTypeDecoder = createUrlEncodedTypeDecoder();\"
91
+ const data = urlEncodedTypeDecoder.decode('key=value');
92
+ // data: {key: "value"}
93
+ const contentType = urlEncodedTypeDecoder.contentType;
94
+ // contentType: 'application/x-www-form-urlencoded'
95
+ ```
96
+
97
+ #### createYamlTypeDecoder
98
+
99
+ ```ts
100
+ import { createYamlTypeDecoder } from '@chubbyts/chubbyts-decode-encode/dist/decoder/yaml-type-decoder';
101
+
102
+ const yamlTypeDecoder = createYamlTypeDecoder();
103
+ const data = yamlTypeDecoder.decode('key: value');
104
+ // data: {key: "value"}
105
+ const contentType = yamlTypeDecoder.contentType;
106
+ // contentType: 'application/x-yaml'
107
+ ```
108
+
109
+ ### Encoder
110
+
111
+ #### createEncoder
112
+
113
+ ```ts
114
+ import { createEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder';
115
+ import { createJsonTypeEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder/json-type-encoder';
116
+
117
+ const encoder = createEncoder([createJsonTypeEncoder()]);
118
+ const encodedData = encoder.encode({key: "value"}, 'application/json');dec
119
+ // encodedData: {"key":"value"}
120
+ const contentTypes = encoder.contentTypes;
121
+ // contentTypes: ['application/json']
122
+ ```
123
+
124
+ #### createJsonTypeEncoder
125
+
126
+ ```ts
127
+ import { createJsonTypeEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder/json-type-encoder';
128
+
129
+ const jsonTypeEncoder = createJsonTypeEncoder();
130
+ const encodedData = jsonTypeEncoder.encode({key: "value"});
131
+ // encodedData: {"key":"value"}
132
+ const contentType = jsonTypeEncoder.contentType;
133
+ // contentTypes: 'application/json'
134
+ ```
135
+
136
+ #### createJsonxTypeEncoder
137
+
138
+ ```ts
139
+ import { createJsonxTypeEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder/jsonx-type-encoder';
140
+
141
+ const jsonxTypeEncoder = createJsonxTypeEncoder();
142
+ const encodedData = jsonxTypeEncoder.encode({key: "value"});
143
+ // encodedData: <?xml version="1.0" encoding="UTF-8"?>
144
+ // <json:object>
145
+ // <json:string name="key">value</json:string>
146
+ // </json:object>
147
+ const contentType = jsonxTypeEncoder.contentType;
148
+ // contentTypes: 'application/jsonx+xml'
149
+ ```
150
+
151
+ #### createUrlEncodedTypeEncoder
152
+
153
+ ```ts
154
+ import { createUrlEncodedTypeEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder/url-encoded-type-encoder';
155
+
156
+ const urlEncodedTypeEncoder = createUrlEncodedTypeEncoder();
157
+ const encodedData = urlEncodedTypeEncoder.encode({key: "value"});
158
+ // encodedData: key=value
159
+ const contentType = urlEncodedTypeEncoder.contentType;
160
+ // contentTypes: 'application/x-www-form-urlencoded'
161
+ ```
162
+
163
+ #### createYamlTypeEncoder
164
+
165
+ ```ts
166
+ import { createYamlTypeEncoder } from '@chubbyts/chubbyts-encode-encode/dist/encoder/yaml-type-encoder';
167
+
168
+ const yamlTypeEncoder = createYamlTypeEncoder();
169
+ const encodedData = yamlTypeEncoder.encode({key: "value"});
170
+ // encodedData: key: value
171
+ const contentType = yamlTypeEncoder.contentType;
172
+ // contentTypes: 'application/x-yaml'
173
+ ```
174
+
175
+ ## Copyright
176
+
177
+ Dominik Zogg 2022
178
+
179
+ [1]: https://www.npmjs.com/package/@chubbyts/chubbyts-decode-encode
180
+ [2]: https://www.npmjs.com/package/fast-xml-parser
181
+ [3]: https://www.npmjs.com/package/object-path
182
+ [4]: https://www.npmjs.com/package/yaml
@@ -0,0 +1,10 @@
1
+ import { Data } from '..';
2
+ export declare type TypeDecoder = {
3
+ decode: (encodedData: string) => Data;
4
+ contentType: string;
5
+ };
6
+ export declare type Decoder = {
7
+ decode: (encodedData: string, contentType: string) => Data;
8
+ contentTypes: Array<string>;
9
+ };
10
+ export declare const createDecoder: (decoderTypes: Array<TypeDecoder>) => Decoder;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDecoder = void 0;
4
+ const createDecoder = (decoderTypes) => {
5
+ const decoderTypeMap = new Map(decoderTypes.map((DecoderType) => [DecoderType.contentType, DecoderType]));
6
+ const contentTypes = Array.from(decoderTypeMap.keys());
7
+ return {
8
+ decode: (encodedData, contentType) => {
9
+ if (decoderTypeMap.has(contentType)) {
10
+ return decoderTypeMap.get(contentType).decode(encodedData);
11
+ }
12
+ throw new Error(`Unsupported contentType "${contentType}", supported contentTypes are "${contentTypes.join('", "')}".`);
13
+ },
14
+ contentTypes,
15
+ };
16
+ };
17
+ exports.createDecoder = createDecoder;
@@ -0,0 +1,2 @@
1
+ import { TypeDecoder } from '.';
2
+ export declare const createJsonTypeDecoder: () => TypeDecoder;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createJsonTypeDecoder = void 0;
4
+ const createJsonTypeDecoder = () => {
5
+ const decode = (encodedData) => {
6
+ return JSON.parse(encodedData);
7
+ };
8
+ const contentType = 'application/json';
9
+ return {
10
+ decode,
11
+ contentType,
12
+ };
13
+ };
14
+ exports.createJsonTypeDecoder = createJsonTypeDecoder;
@@ -0,0 +1,2 @@
1
+ import { TypeDecoder } from '.';
2
+ export declare const createJsonxTypeDecoder: () => TypeDecoder;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createJsonxTypeDecoder = void 0;
4
+ const fast_xml_parser_1 = require("fast-xml-parser");
5
+ const jsonx_datatypes_1 = require("../jsonx-datatypes");
6
+ const decodeHtmlEntities = (string) => string.replace(/&#\d+;/gm, (code) => String.fromCharCode(code.match(/\d+/)[0]));
7
+ const isWithName = (node) => typeof node === 'object' &&
8
+ null !== node &&
9
+ typeof node[':@'] === 'object' &&
10
+ node[':@'] !== null &&
11
+ typeof node[':@']['@_name'] === 'string';
12
+ const isObjectNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_OBJECT && Array.isArray(node[jsonx_datatypes_1.DATATYPE_OBJECT]);
13
+ const isArrayNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_ARRAY && Array.isArray(node[jsonx_datatypes_1.DATATYPE_ARRAY]);
14
+ const isStringNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_STRING && Array.isArray(node[jsonx_datatypes_1.DATATYPE_STRING]);
15
+ const isNumberNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_NUMBER && Array.isArray(node[jsonx_datatypes_1.DATATYPE_NUMBER]);
16
+ const isBooleanNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_BOOLEAN && Array.isArray(node[jsonx_datatypes_1.DATATYPE_BOOLEAN]);
17
+ const isNullNode = (node) => Object.keys(node)[0] === jsonx_datatypes_1.DATATYPE_NULL && Array.isArray(node[jsonx_datatypes_1.DATATYPE_NULL]);
18
+ const convertNullNode = () => {
19
+ return null;
20
+ };
21
+ const convertBooleanNode = (node) => {
22
+ return node['json:boolean'][0]['#text'];
23
+ };
24
+ const convertNumberNode = (node) => {
25
+ return node['json:number'][0]['#text'];
26
+ };
27
+ const convertStringNode = (node) => {
28
+ return decodeHtmlEntities(node['json:string'][0]['#text']);
29
+ };
30
+ const convertNode = (node) => {
31
+ if (isObjectNode(node)) {
32
+ return convertObjectNode(node);
33
+ }
34
+ else if (isArrayNode(node)) {
35
+ return convertArrayNode(node);
36
+ }
37
+ else if (isStringNode(node)) {
38
+ return convertStringNode(node);
39
+ }
40
+ else if (isNumberNode(node)) {
41
+ return convertNumberNode(node);
42
+ }
43
+ else if (isBooleanNode(node)) {
44
+ return convertBooleanNode(node);
45
+ }
46
+ else if (isNullNode(node)) {
47
+ return convertNullNode();
48
+ }
49
+ throw new Error(`Unsupported node: ${JSON.stringify(node)}`);
50
+ };
51
+ const convertArrayNode = (node) => {
52
+ return node['json:array'].map(convertNode);
53
+ };
54
+ const convertNodeWithName = (node) => {
55
+ if (isObjectNode(node) && isWithName(node)) {
56
+ return [node[':@']['@_name'], convertObjectNode(node)];
57
+ }
58
+ else if (isArrayNode(node) && isWithName(node)) {
59
+ return [node[':@']['@_name'], convertArrayNode(node)];
60
+ }
61
+ else if (isStringNode(node) && isWithName(node)) {
62
+ return [node[':@']['@_name'], convertStringNode(node)];
63
+ }
64
+ else if (isNumberNode(node) && isWithName(node)) {
65
+ return [node[':@']['@_name'], convertNumberNode(node)];
66
+ }
67
+ else if (isBooleanNode(node) && isWithName(node)) {
68
+ return [node[':@']['@_name'], convertBooleanNode(node)];
69
+ }
70
+ else if (isNullNode(node) && isWithName(node)) {
71
+ return [node[':@']['@_name'], convertNullNode()];
72
+ }
73
+ throw new Error(`Unsupported node: ${JSON.stringify(node)}`);
74
+ };
75
+ const convertObjectNode = (node) => {
76
+ return Object.fromEntries(node['json:object'].map(convertNodeWithName));
77
+ };
78
+ const createJsonxTypeDecoder = () => {
79
+ const decode = (encodedData) => {
80
+ const parser = new fast_xml_parser_1.XMLParser({ preserveOrder: true, ignoreAttributes: false, htmlEntities: false });
81
+ const parsedData = parser.parse(encodedData);
82
+ return convertNode(parsedData[1]);
83
+ };
84
+ const contentType = 'application/jsonx+xml';
85
+ return {
86
+ decode,
87
+ contentType,
88
+ };
89
+ };
90
+ exports.createJsonxTypeDecoder = createJsonxTypeDecoder;
@@ -0,0 +1,2 @@
1
+ import { TypeDecoder } from '.';
2
+ export declare const createUrlEncodedTypeDecoder: () => TypeDecoder;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createUrlEncodedTypeDecoder = void 0;
4
+ const object_path_1 = require("object-path");
5
+ const optimizeValue = (value) => {
6
+ if (value === 'null') {
7
+ return null;
8
+ }
9
+ if (value === 'true') {
10
+ return true;
11
+ }
12
+ if (value === 'false') {
13
+ return false;
14
+ }
15
+ const integer = parseInt(value, 10);
16
+ if (!isNaN(integer) && integer.toString() === value) {
17
+ return integer;
18
+ }
19
+ const float = parseFloat(value);
20
+ if (!isNaN(float) && float.toString() === value) {
21
+ return float;
22
+ }
23
+ return value;
24
+ };
25
+ const createUrlEncodedTypeDecoder = () => {
26
+ const decode = (encodedData) => {
27
+ let data = {};
28
+ encodedData.split('&').forEach((keyValue) => {
29
+ const [rawKey, rawValue] = keyValue.split('=');
30
+ const key = rawKey.replace(/\[[^\]]+\]/gm, (match) => `.${match.match(/[^\[\]]+/)[0]}`);
31
+ const value = optimizeValue(decodeURIComponent(rawValue));
32
+ (0, object_path_1.set)(data, key, value);
33
+ });
34
+ return data;
35
+ };
36
+ const contentType = 'application/x-www-form-urlencoded';
37
+ return {
38
+ decode,
39
+ contentType,
40
+ };
41
+ };
42
+ exports.createUrlEncodedTypeDecoder = createUrlEncodedTypeDecoder;
@@ -0,0 +1,2 @@
1
+ import { TypeDecoder } from '.';
2
+ export declare const createYamlTypeDecoder: () => TypeDecoder;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createYamlTypeDecoder = void 0;
4
+ const yaml_1 = require("yaml");
5
+ const createYamlTypeDecoder = () => {
6
+ const decode = (encodedData) => {
7
+ return (0, yaml_1.parse)(encodedData);
8
+ };
9
+ const contentType = 'application/x-yaml';
10
+ return {
11
+ decode,
12
+ contentType,
13
+ };
14
+ };
15
+ exports.createYamlTypeDecoder = createYamlTypeDecoder;
@@ -0,0 +1,10 @@
1
+ import { Data } from '..';
2
+ export declare type TypeEncoder = {
3
+ encode: (data: Data) => string;
4
+ contentType: string;
5
+ };
6
+ export declare type Encoder = {
7
+ encode: (data: Data, contentType: string) => string;
8
+ contentTypes: Array<string>;
9
+ };
10
+ export declare const createEncoder: (encoderTypes: Array<TypeEncoder>) => Encoder;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEncoder = void 0;
4
+ const createEncoder = (encoderTypes) => {
5
+ const encoderTypeMap = new Map(encoderTypes.map((encoderType) => [encoderType.contentType, encoderType]));
6
+ const contentTypes = Array.from(encoderTypeMap.keys());
7
+ return {
8
+ encode: (data, contentType) => {
9
+ if (encoderTypeMap.has(contentType)) {
10
+ return encoderTypeMap.get(contentType).encode(data);
11
+ }
12
+ throw new Error(`Unsupported contentType "${contentType}", supported contentTypes are "${contentTypes.join('", "')}".`);
13
+ },
14
+ contentTypes,
15
+ };
16
+ };
17
+ exports.createEncoder = createEncoder;
@@ -0,0 +1,2 @@
1
+ import { TypeEncoder } from '.';
2
+ export declare const createJsonTypeEncoder: (prettyPrint?: boolean) => TypeEncoder;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createJsonTypeEncoder = void 0;
4
+ const createJsonTypeEncoder = (prettyPrint = false) => {
5
+ const encode = (data) => JSON.stringify(data, undefined, prettyPrint ? 4 : undefined);
6
+ const contentType = 'application/json';
7
+ return {
8
+ encode,
9
+ contentType,
10
+ };
11
+ };
12
+ exports.createJsonTypeEncoder = createJsonTypeEncoder;
@@ -0,0 +1,2 @@
1
+ import { TypeEncoder } from '.';
2
+ export declare const createJsonxTypeEncoder: (prettyPrint?: boolean) => TypeEncoder;
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createJsonxTypeEncoder = void 0;
4
+ const __1 = require("..");
5
+ const jsonx_datatypes_1 = require("../jsonx-datatypes");
6
+ const fast_xml_parser_1 = require("fast-xml-parser");
7
+ const encodeHtmlEntities = (string) => string.replace(/[\u00A0-\u9999<>\&]/g, (i) => '&#' + i.charCodeAt(0) + ';');
8
+ const createXmlNode = () => {
9
+ return {
10
+ '?xml': [
11
+ {
12
+ '#text': '',
13
+ },
14
+ ],
15
+ ':@': {
16
+ '@_version': '1.0',
17
+ '@_encoding': 'UTF-8',
18
+ },
19
+ };
20
+ };
21
+ const createJsonxAttributes = () => {
22
+ return {
23
+ ':@': {
24
+ '@_xsi:schemaLocation': 'http://www.datapower.com/schemas/json jsonx.xsd',
25
+ '@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
26
+ '@_xmlns:json': 'http://www.ibm.com/xmlns/prod/2009/jsonx',
27
+ },
28
+ };
29
+ };
30
+ const createNullNode = (key = undefined) => {
31
+ const node = {
32
+ [jsonx_datatypes_1.DATATYPE_NULL]: [],
33
+ };
34
+ if (key === undefined) {
35
+ return node;
36
+ }
37
+ return {
38
+ ...node,
39
+ ':@': {
40
+ '@_name': key,
41
+ },
42
+ };
43
+ };
44
+ const createBooleanNode = (value, key = undefined) => {
45
+ const node = {
46
+ [jsonx_datatypes_1.DATATYPE_BOOLEAN]: [
47
+ {
48
+ '#text': value,
49
+ },
50
+ ],
51
+ };
52
+ if (key === undefined) {
53
+ return node;
54
+ }
55
+ return {
56
+ ...node,
57
+ ':@': {
58
+ '@_name': key,
59
+ },
60
+ };
61
+ };
62
+ const createNumberNode = (value, key = undefined) => {
63
+ const node = {
64
+ [jsonx_datatypes_1.DATATYPE_NUMBER]: [
65
+ {
66
+ '#text': value,
67
+ },
68
+ ],
69
+ };
70
+ if (key === undefined) {
71
+ return node;
72
+ }
73
+ return {
74
+ ...node,
75
+ ':@': {
76
+ '@_name': key,
77
+ },
78
+ };
79
+ };
80
+ const createStringNode = (value, key = undefined) => {
81
+ const node = {
82
+ [jsonx_datatypes_1.DATATYPE_STRING]: [
83
+ {
84
+ '#text': value === value.trim() ? encodeHtmlEntities(value) : `<![CDATA[${encodeHtmlEntities(value)}]]>`,
85
+ },
86
+ ],
87
+ };
88
+ if (key === undefined) {
89
+ return node;
90
+ }
91
+ return {
92
+ ...node,
93
+ ':@': {
94
+ '@_name': key,
95
+ },
96
+ };
97
+ };
98
+ const createNode = (value, key = undefined) => {
99
+ if ((0, __1.isObject)(value)) {
100
+ return createObjectNode(value, key);
101
+ }
102
+ else if ((0, __1.isArray)(value)) {
103
+ return createArrayNode(value, key);
104
+ }
105
+ else if ((0, __1.isString)(value)) {
106
+ return createStringNode(value, key);
107
+ }
108
+ else if ((0, __1.isNumber)(value)) {
109
+ return createNumberNode(value, key);
110
+ }
111
+ else if ((0, __1.isBoolean)(value)) {
112
+ return createBooleanNode(value, key);
113
+ }
114
+ else if ((0, __1.isNull)(value)) {
115
+ return createNullNode(key);
116
+ }
117
+ throw new Error(`Unsupported value: ${JSON.stringify(value)}`);
118
+ };
119
+ const createArrayNode = (value, key = undefined) => {
120
+ const elements = value.map((subValue) => createNode(subValue));
121
+ const node = {
122
+ [jsonx_datatypes_1.DATATYPE_ARRAY]: elements,
123
+ };
124
+ if (key === undefined) {
125
+ return node;
126
+ }
127
+ return {
128
+ ...node,
129
+ ':@': {
130
+ '@_name': key,
131
+ },
132
+ };
133
+ };
134
+ const createObjectNode = (value, key = undefined) => {
135
+ const elements = Object.entries(value).map(([subKey, subValue]) => createNode(subValue, subKey));
136
+ const node = {
137
+ [jsonx_datatypes_1.DATATYPE_OBJECT]: elements,
138
+ };
139
+ if (key === undefined) {
140
+ return node;
141
+ }
142
+ return {
143
+ ...node,
144
+ ':@': {
145
+ '@_name': key,
146
+ },
147
+ };
148
+ };
149
+ const createJsonxTypeEncoder = (prettyPrint = false) => {
150
+ const encode = (data) => {
151
+ const builder = new fast_xml_parser_1.XMLBuilder({
152
+ preserveOrder: true,
153
+ ignoreAttributes: false,
154
+ processEntities: false,
155
+ format: prettyPrint,
156
+ });
157
+ return builder.build([
158
+ createXmlNode(),
159
+ {
160
+ ...createNode(data),
161
+ ...createJsonxAttributes(),
162
+ },
163
+ ]);
164
+ };
165
+ const contentType = 'application/jsonx+xml';
166
+ return {
167
+ encode,
168
+ contentType,
169
+ };
170
+ };
171
+ exports.createJsonxTypeEncoder = createJsonxTypeEncoder;
@@ -0,0 +1,2 @@
1
+ import { TypeEncoder } from '.';
2
+ export declare const createUrlEncodedTypeEncoder: () => TypeEncoder;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createUrlEncodedTypeEncoder = void 0;
4
+ const __1 = require("..");
5
+ const getValueAsString = (value) => {
6
+ if (null === value) {
7
+ return 'null';
8
+ }
9
+ if (typeof value === 'boolean') {
10
+ return value ? 'true' : 'false';
11
+ }
12
+ if (typeof value === 'number') {
13
+ return value.toString();
14
+ }
15
+ return value;
16
+ };
17
+ const getKeyValue = (path, key, value) => {
18
+ const subPath = '' !== path ? path + '[' + key + ']' : key;
19
+ if ((0, __1.isObject)(value) || (0, __1.isArray)(value)) {
20
+ const queryPart = buildQuery(value, subPath);
21
+ return queryPart !== '' ? queryPart + '&' : '';
22
+ }
23
+ return subPath + '=' + encodeURIComponent(getValueAsString(value)) + '&';
24
+ };
25
+ const buildQuery = (data, path = '') => {
26
+ let query = '';
27
+ if ((0, __1.isObject)(data)) {
28
+ Object.keys(data).forEach((key) => {
29
+ query += getKeyValue(path, key, data[key]);
30
+ });
31
+ }
32
+ else if ((0, __1.isArray)(data)) {
33
+ data.forEach((value, i) => {
34
+ query += getKeyValue(path, i.toString(), value);
35
+ });
36
+ }
37
+ return query.substring(0, query.length - 1);
38
+ };
39
+ const createUrlEncodedTypeEncoder = () => {
40
+ const encode = (data) => {
41
+ return buildQuery(JSON.parse(JSON.stringify(data)));
42
+ };
43
+ const contentType = 'application/x-www-form-urlencoded';
44
+ return {
45
+ encode,
46
+ contentType,
47
+ };
48
+ };
49
+ exports.createUrlEncodedTypeEncoder = createUrlEncodedTypeEncoder;
@@ -0,0 +1,2 @@
1
+ import { TypeEncoder } from '.';
2
+ export declare const createYamlTypeEncoder: () => TypeEncoder;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createYamlTypeEncoder = void 0;
4
+ const yaml_1 = require("yaml");
5
+ const createYamlTypeEncoder = () => {
6
+ const encode = (data) => (0, yaml_1.stringify)(JSON.parse(JSON.stringify(data)), { indent: 4 });
7
+ const contentType = 'application/x-yaml';
8
+ return {
9
+ encode,
10
+ contentType,
11
+ };
12
+ };
13
+ exports.createYamlTypeEncoder = createYamlTypeEncoder;
@@ -0,0 +1,11 @@
1
+ export declare type Data = {
2
+ [key: string]: Data;
3
+ } | Array<Data> | string | number | boolean | null;
4
+ export declare const isNull: (value: unknown) => value is null;
5
+ export declare const isBoolean: (value: unknown) => value is boolean;
6
+ export declare const isNumber: (value: unknown) => value is number;
7
+ export declare const isString: (value: unknown) => value is string;
8
+ export declare const isArray: (value: unknown) => value is Data[];
9
+ export declare const isObject: (value: unknown) => value is {
10
+ [key: string]: Data;
11
+ };
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isObject = exports.isArray = exports.isString = exports.isNumber = exports.isBoolean = exports.isNull = void 0;
4
+ const isNull = (value) => value === null;
5
+ exports.isNull = isNull;
6
+ const isBoolean = (value) => typeof value === 'boolean';
7
+ exports.isBoolean = isBoolean;
8
+ const isNumber = (value) => typeof value === 'number';
9
+ exports.isNumber = isNumber;
10
+ const isString = (value) => typeof value === 'string';
11
+ exports.isString = isString;
12
+ const isArray = (value) => Array.isArray(value);
13
+ exports.isArray = isArray;
14
+ const isObject = (value) => value !== null && typeof value === 'object' && value.constructor.name == 'Object';
15
+ exports.isObject = isObject;
@@ -0,0 +1,36 @@
1
+ export declare const DATATYPE_OBJECT = "json:object";
2
+ export declare const DATATYPE_ARRAY = "json:array";
3
+ export declare const DATATYPE_BOOLEAN = "json:boolean";
4
+ export declare const DATATYPE_STRING = "json:string";
5
+ export declare const DATATYPE_NUMBER = "json:number";
6
+ export declare const DATATYPE_NULL = "json:null";
7
+ export declare type WithName = {
8
+ ':@': {
9
+ '@_name': string;
10
+ };
11
+ };
12
+ export declare type JsonxNullNode = {
13
+ [DATATYPE_NULL]: Array<never>;
14
+ };
15
+ export declare type JsonxBooleanNode = {
16
+ [DATATYPE_BOOLEAN]: Array<{
17
+ '#text': boolean;
18
+ }>;
19
+ };
20
+ export declare type JsonxNumberNode = {
21
+ [DATATYPE_NUMBER]: Array<{
22
+ '#text': number;
23
+ }>;
24
+ };
25
+ export declare type JsonxStringNode = {
26
+ [DATATYPE_STRING]: Array<{
27
+ '#text': string;
28
+ }>;
29
+ };
30
+ export declare type JsonxArrayNode = {
31
+ [DATATYPE_ARRAY]: Array<JsonxNullNode | JsonxBooleanNode | JsonxNumberNode | JsonxStringNode | JsonxArrayNode | JsonxObjectNode>;
32
+ };
33
+ export declare type JsonxObjectNode = {
34
+ [DATATYPE_OBJECT]: Array<JsonxNullNode | JsonxBooleanNode | JsonxNumberNode | JsonxStringNode | JsonxArrayNode | JsonxObjectNode>;
35
+ };
36
+ export declare type JsonxNode = JsonxNullNode | JsonxBooleanNode | JsonxNumberNode | JsonxStringNode | JsonxArrayNode | JsonxObjectNode;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DATATYPE_NULL = exports.DATATYPE_NUMBER = exports.DATATYPE_STRING = exports.DATATYPE_BOOLEAN = exports.DATATYPE_ARRAY = exports.DATATYPE_OBJECT = void 0;
4
+ exports.DATATYPE_OBJECT = 'json:object';
5
+ exports.DATATYPE_ARRAY = 'json:array';
6
+ exports.DATATYPE_BOOLEAN = 'json:boolean';
7
+ exports.DATATYPE_STRING = 'json:string';
8
+ exports.DATATYPE_NUMBER = 'json:number';
9
+ exports.DATATYPE_NULL = 'json:null';
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@chubbyts/chubbyts-decode-encode",
3
+ "version": "1.0.0",
4
+ "description": "A simple decode/encode solution for json / jsonx / url-encoded / xml / yaml.",
5
+ "keywords": [
6
+ "chubbyts",
7
+ "decode",
8
+ "encode",
9
+ "json",
10
+ "jsonx",
11
+ "url-encoded",
12
+ "xml",
13
+ "yaml"
14
+ ],
15
+ "author": "Dominik Zogg",
16
+ "license": "MIT",
17
+ "repository": "chubbyts/chubbyts-decode-encode",
18
+ "scripts": {
19
+ "cs-fix": "prettier --write src tests",
20
+ "cs": "prettier --check src tests",
21
+ "test": "jest",
22
+ "infection": "stryker run",
23
+ "build": "tsc",
24
+ "prepare": "rm -Rf dist && npm run build && npm run cs && npm run test"
25
+ },
26
+ "jest": {
27
+ "preset": "ts-jest",
28
+ "testEnvironment": "node",
29
+ "collectCoverageFrom": [
30
+ "src/**/*.ts"
31
+ ],
32
+ "coverageThreshold": {
33
+ "global": {
34
+ "lines": 100
35
+ }
36
+ }
37
+ },
38
+ "prettier": {
39
+ "printWidth": 120,
40
+ "tabWidth": 2,
41
+ "singleQuote": true,
42
+ "trailingComma": "all"
43
+ },
44
+ "files": [
45
+ "dist"
46
+ ],
47
+ "engines": {
48
+ "node": ">=14"
49
+ },
50
+ "dependencies": {
51
+ "fast-xml-parser": "^4.0.8",
52
+ "object-path": "^0.11.8",
53
+ "yaml": "^2.1.1"
54
+ },
55
+ "devDependencies": {
56
+ "@stryker-mutator/core": "^6.0.2",
57
+ "@stryker-mutator/jest-runner": "^6.0.2",
58
+ "@types/jest": "^27.5.1",
59
+ "@types/node": "^14",
60
+ "@types/object-path": "^0.11.1",
61
+ "jest": "^28.1.0",
62
+ "prettier": "^2.6.2",
63
+ "ts-jest": "^28.0.3",
64
+ "typescript": "^4.7.2"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ }
69
+ }