jsonschema-key-compression 1.6.1 → 2.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/CHANGELOG.md +13 -0
- package/README.md +65 -5
- package/dist/es/compress.d.ts +3 -1
- package/dist/es/compress.js +164 -26
- package/dist/es/compress.js.map +1 -1
- package/dist/es/create-compressed-json-schema.d.ts +9 -0
- package/dist/es/create-compressed-json-schema.js +136 -26
- package/dist/es/create-compressed-json-schema.js.map +1 -1
- package/dist/es/create-compression-table.d.ts +7 -1
- package/dist/es/create-compression-table.js +56 -30
- package/dist/es/create-compression-table.js.map +1 -1
- package/dist/es/decompress.js +41 -21
- package/dist/es/decompress.js.map +1 -1
- package/dist/es/enum-compression.d.ts +35 -0
- package/dist/es/enum-compression.js +217 -0
- package/dist/es/enum-compression.js.map +1 -0
- package/dist/es/index.d.ts +1 -1
- package/dist/es/index.js.map +1 -1
- package/dist/es/types.d.ts +11 -0
- package/dist/es/util.d.ts +1 -1
- package/dist/es/util.js.map +1 -1
- package/dist/lib/compress.d.ts +3 -1
- package/dist/lib/compress.js +170 -33
- package/dist/lib/compress.js.map +1 -1
- package/dist/lib/create-compressed-json-schema.d.ts +9 -0
- package/dist/lib/create-compressed-json-schema.js +136 -27
- package/dist/lib/create-compressed-json-schema.js.map +1 -1
- package/dist/lib/create-compression-table.d.ts +7 -1
- package/dist/lib/create-compression-table.js +61 -35
- package/dist/lib/create-compression-table.js.map +1 -1
- package/dist/lib/decompress.js +44 -25
- package/dist/lib/decompress.js.map +1 -1
- package/dist/lib/enum-compression.d.ts +35 -0
- package/dist/lib/enum-compression.js +223 -0
- package/dist/lib/enum-compression.js.map +1 -0
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/types.d.ts +11 -0
- package/dist/lib/util.d.ts +1 -1
- package/dist/lib/util.js +3 -3
- package/dist/lib/util.js.map +1 -1
- package/package.json +14 -12
- package/src/compress.ts +184 -34
- package/src/create-compressed-json-schema.ts +158 -35
- package/src/create-compression-table.ts +59 -31
- package/src/decompress.ts +42 -27
- package/src/enum-compression.ts +240 -0
- package/src/index.ts +1 -0
- package/src/types.d.ts +11 -0
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
numberToLetter,
|
|
8
8
|
alphabeticCompare
|
|
9
9
|
} from './util';
|
|
10
|
+
import { getEnumCompressionTable } from './enum-compression';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Compressed property-names begin with the compression-flag
|
|
@@ -16,10 +17,17 @@ import {
|
|
|
16
17
|
*/
|
|
17
18
|
export const DEFAULT_COMPRESSION_FLAG = '|';
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @param compressEnums If true, the values of string-enums are compressed
|
|
22
|
+
* into the index of the value inside of the enum.
|
|
23
|
+
* This changes the stored format, so it is opt-in
|
|
24
|
+
* to keep already compressed data readable.
|
|
25
|
+
*/
|
|
19
26
|
export function createCompressionTable(
|
|
20
27
|
schema: JsonSchema,
|
|
21
28
|
compressionFlag: string = DEFAULT_COMPRESSION_FLAG,
|
|
22
|
-
ignoreProperties: string[] = []
|
|
29
|
+
ignoreProperties: string[] = [],
|
|
30
|
+
compressEnums: boolean = false
|
|
23
31
|
): CompressionTable {
|
|
24
32
|
const table = compressedToUncompressedTable(
|
|
25
33
|
schema,
|
|
@@ -35,6 +43,20 @@ export function createCompressionTable(
|
|
|
35
43
|
compressionFlag
|
|
36
44
|
};
|
|
37
45
|
|
|
46
|
+
if (compressEnums) {
|
|
47
|
+
const enumCompression = getEnumCompressionTable(
|
|
48
|
+
schema,
|
|
49
|
+
ignoreProperties
|
|
50
|
+
);
|
|
51
|
+
/**
|
|
52
|
+
* The field stays undefined when there is nothing to compress,
|
|
53
|
+
* so that the compression does not have to look it up on each key.
|
|
54
|
+
*/
|
|
55
|
+
if (enumCompression.size > 0) {
|
|
56
|
+
compressionTable.enumCompression = enumCompression;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
38
60
|
return compressionTable;
|
|
39
61
|
}
|
|
40
62
|
|
|
@@ -44,35 +66,37 @@ export function createCompressionTable(
|
|
|
44
66
|
*/
|
|
45
67
|
export function getPropertiesOfSchema(schema: JsonSchema): Set<string> {
|
|
46
68
|
const ret: Set<string> = new Set();
|
|
69
|
+
addPropertiesOfSchema(schema, ret);
|
|
70
|
+
return ret;
|
|
71
|
+
}
|
|
47
72
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Adds all property names of the schema to the given set.
|
|
75
|
+
* Using a single accumulator set avoids creating
|
|
76
|
+
* a new set and array copy on each nesting level.
|
|
77
|
+
*/
|
|
78
|
+
function addPropertiesOfSchema(schema: JsonSchema, ret: Set<string>) {
|
|
79
|
+
const properties = schema.properties;
|
|
80
|
+
if (properties) {
|
|
54
81
|
// do not use Object.entries, it is transpiled shitty
|
|
55
|
-
Object.keys(
|
|
56
|
-
|
|
82
|
+
const propertyNames = Object.keys(properties);
|
|
83
|
+
for (let i = 0; i < propertyNames.length; i++) {
|
|
84
|
+
const property = propertyNames[i] as string;
|
|
57
85
|
ret.add(property);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
addSchema(deepSchema);
|
|
62
|
-
});
|
|
86
|
+
addPropertiesOfSchema(properties[property] as JsonSchema, ret);
|
|
87
|
+
}
|
|
63
88
|
}
|
|
64
89
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
const items = schema.items;
|
|
91
|
+
if (items) {
|
|
92
|
+
if (Array.isArray(items)) {
|
|
93
|
+
for (let i = 0; i < items.length; i++) {
|
|
94
|
+
addPropertiesOfSchema(items[i] as JsonSchema, ret);
|
|
95
|
+
}
|
|
70
96
|
} else {
|
|
71
|
-
|
|
97
|
+
addPropertiesOfSchema(items, ret);
|
|
72
98
|
}
|
|
73
99
|
}
|
|
74
|
-
|
|
75
|
-
return ret;
|
|
76
100
|
}
|
|
77
101
|
|
|
78
102
|
export function compressedToUncompressedTable(
|
|
@@ -83,13 +107,13 @@ export function compressedToUncompressedTable(
|
|
|
83
107
|
const schemaKeysSorted: string[] = Array.from(attributes).sort(alphabeticCompare);
|
|
84
108
|
const table: TableType = new Map();
|
|
85
109
|
let lastKeyNumber: number = 0;
|
|
86
|
-
schemaKeysSorted
|
|
87
|
-
|
|
88
|
-
.
|
|
89
|
-
|
|
110
|
+
for (let i = 0; i < schemaKeysSorted.length; i++) {
|
|
111
|
+
const k = schemaKeysSorted[i] as string;
|
|
112
|
+
if (k.length > 3 && !ignoreProperties.includes(k)) {
|
|
113
|
+
table.set(k, numberToLetter(lastKeyNumber));
|
|
90
114
|
lastKeyNumber++;
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
}
|
|
116
|
+
}
|
|
93
117
|
return table;
|
|
94
118
|
}
|
|
95
119
|
|
|
@@ -99,9 +123,13 @@ export function uncompressedToCompressedTable(
|
|
|
99
123
|
ignoreProperties: string[]
|
|
100
124
|
): TableType {
|
|
101
125
|
const reverseTable: TableType = new Map();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
126
|
+
table.forEach((value, key) => {
|
|
127
|
+
/**
|
|
128
|
+
* The ignored properties are property names,
|
|
129
|
+
* so they must be compared to the key and not to the
|
|
130
|
+
* compressed value which could randomly be equal to an ignored name.
|
|
131
|
+
*/
|
|
132
|
+
if (!ignoreProperties.includes(key)) {
|
|
105
133
|
reverseTable.set(compressionFlag + value, key);
|
|
106
134
|
}
|
|
107
135
|
});
|
package/src/decompress.ts
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
PlainJsonObject,
|
|
3
|
+
PlainJsonObjectNotArray,
|
|
3
4
|
CompressionTable
|
|
4
5
|
} from './types';
|
|
6
|
+
import { decompressEnumValue } from './enum-compression';
|
|
5
7
|
|
|
6
8
|
export function decompressObject(
|
|
7
9
|
table: CompressionTable,
|
|
8
10
|
obj: PlainJsonObject
|
|
9
11
|
): PlainJsonObject {
|
|
10
12
|
if (typeof obj !== 'object' || obj === null) return obj;
|
|
11
|
-
|
|
13
|
+
if (Array.isArray(obj)) {
|
|
12
14
|
// array
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
key
|
|
21
|
-
);
|
|
22
|
-
const value = decompressObject(
|
|
23
|
-
table,
|
|
24
|
-
obj[key]
|
|
25
|
-
);
|
|
26
|
-
ret[decompressed] = value;
|
|
27
|
-
});
|
|
28
|
-
return ret;
|
|
15
|
+
const retArray: PlainJsonObjectNotArray[] = new Array(obj.length);
|
|
16
|
+
for (let index = 0; index < obj.length; index++) {
|
|
17
|
+
const item = obj[index];
|
|
18
|
+
// primitives do not need a recursive call
|
|
19
|
+
retArray[index] = (typeof item === 'object' && item !== null) ? decompressObject(table, item) as any : item;
|
|
20
|
+
}
|
|
21
|
+
return retArray;
|
|
29
22
|
}
|
|
23
|
+
// object
|
|
24
|
+
const ret: PlainJsonObjectNotArray = {};
|
|
25
|
+
const keys = Object.keys(obj);
|
|
26
|
+
const enumCompression = table.enumCompression;
|
|
27
|
+
for (let index = 0; index < keys.length; index++) {
|
|
28
|
+
const key = keys[index] as string;
|
|
29
|
+
const value = (obj as PlainJsonObjectNotArray)[key];
|
|
30
|
+
const decompressed = decompressedKey(table, key);
|
|
31
|
+
const enumValues = enumCompression && enumCompression.get(decompressed);
|
|
32
|
+
if (enumValues && (typeof value === 'number' || Array.isArray(value))) {
|
|
33
|
+
ret[decompressed] = decompressEnumValue(enumValues, value);
|
|
34
|
+
} else {
|
|
35
|
+
// primitives do not need a recursive call
|
|
36
|
+
ret[decompressed] = (typeof value === 'object' && value !== null) ?
|
|
37
|
+
decompressObject(table, value) :
|
|
38
|
+
value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return ret;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
/**
|
|
@@ -57,17 +69,20 @@ export function decompressedKey(
|
|
|
57
69
|
): string {
|
|
58
70
|
|
|
59
71
|
/**
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
* keys could be array-accessors like myArray[4]
|
|
73
|
+
* so the part before the squared bracket is looked up
|
|
74
|
+
* and the bracket part is re-added.
|
|
75
|
+
* Most keys have no bracket, so the plain lookup is the fast path.
|
|
76
|
+
*/
|
|
77
|
+
const bracketIndex = key.indexOf('[');
|
|
78
|
+
if (bracketIndex === -1) {
|
|
79
|
+
const directDecompressed = table.uncompressedToCompressed.get(key);
|
|
80
|
+
return directDecompressed ? directDecompressed : key;
|
|
81
|
+
}
|
|
82
|
+
const plainKey = key.slice(0, bracketIndex);
|
|
83
|
+
const decompressed = table.uncompressedToCompressed.get(plainKey);
|
|
67
84
|
if (!decompressed) {
|
|
68
85
|
return key;
|
|
69
|
-
} else {
|
|
70
|
-
const readdSquared = splitSquaredBrackets.length ? '[' + splitSquaredBrackets.join('[') : '';
|
|
71
|
-
return decompressed + readdSquared;
|
|
72
86
|
}
|
|
87
|
+
return decompressed + key.slice(bracketIndex);
|
|
73
88
|
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EnumCompressionTable,
|
|
3
|
+
JsonSchema
|
|
4
|
+
} from './types';
|
|
5
|
+
import { alphabeticCompare } from './util';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enum-compression replaces the value of a property
|
|
9
|
+
* by the index of that value inside of the enum of the property.
|
|
10
|
+
* For example with the enum ['admin', 'editor', 'viewer']
|
|
11
|
+
* the value 'editor' is stored as the number 1.
|
|
12
|
+
*
|
|
13
|
+
* Only enums where all values are strings can be compressed:
|
|
14
|
+
* - The compressed value is a number, so a number inside of the enum
|
|
15
|
+
* could not be told apart from an index.
|
|
16
|
+
* - Strings are also where the saved space actually is.
|
|
17
|
+
*
|
|
18
|
+
* The values are sorted before the indexes are assigned, so that the order
|
|
19
|
+
* of the indexes is equal to the alphabetic order of the values.
|
|
20
|
+
* This keeps sorting and range-queries like $gt working on compressed data.
|
|
21
|
+
*/
|
|
22
|
+
export function compressibleEnumValues(values: any[]): string[] | null {
|
|
23
|
+
if (values.length === 0) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const unique: string[] = [];
|
|
27
|
+
for (let i = 0; i < values.length; i++) {
|
|
28
|
+
const value = values[i];
|
|
29
|
+
if (typeof value !== 'string') {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (!unique.includes(value)) {
|
|
33
|
+
unique.push(value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return unique.sort(alphabeticCompare);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns the enum that applies to the values which are stored
|
|
41
|
+
* at a property, or null if the property has no compressible enum.
|
|
42
|
+
* The enum can either be defined at the property itself,
|
|
43
|
+
* or at the items of an array-property.
|
|
44
|
+
*/
|
|
45
|
+
function valueEnumOfSchema(schema: JsonSchema): string[] | null {
|
|
46
|
+
if (Array.isArray(schema.enum)) {
|
|
47
|
+
return compressibleEnumValues(schema.enum);
|
|
48
|
+
}
|
|
49
|
+
const items = schema.items;
|
|
50
|
+
if (items && !Array.isArray(items) && Array.isArray(items.enum)) {
|
|
51
|
+
return compressibleEnumValues(items.enum);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function equalEnumValues(a: string[], b: string[]): boolean {
|
|
57
|
+
if (a.length !== b.length) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
for (let i = 0; i < a.length; i++) {
|
|
61
|
+
if (a[i] !== b[i]) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Collects the enum of each property name for every place
|
|
70
|
+
* where the name occurs in the schema.
|
|
71
|
+
* All sub-schema keywords are walked, not only the ones that
|
|
72
|
+
* the key-compression uses, so that a property name which is used
|
|
73
|
+
* with different enums is detected as ambiguous.
|
|
74
|
+
* @recursive
|
|
75
|
+
*/
|
|
76
|
+
function addEnumCandidates(
|
|
77
|
+
schema: JsonSchema,
|
|
78
|
+
candidates: Map<string, (string[] | null)[]>
|
|
79
|
+
) {
|
|
80
|
+
const properties = schema.properties;
|
|
81
|
+
if (properties) {
|
|
82
|
+
// do not use Object.entries, it is transpiled shitty
|
|
83
|
+
const propertyNames = Object.keys(properties);
|
|
84
|
+
for (let i = 0; i < propertyNames.length; i++) {
|
|
85
|
+
const property = propertyNames[i] as string;
|
|
86
|
+
const subSchema = properties[property] as JsonSchema;
|
|
87
|
+
let found = candidates.get(property);
|
|
88
|
+
if (!found) {
|
|
89
|
+
found = [];
|
|
90
|
+
candidates.set(property, found);
|
|
91
|
+
}
|
|
92
|
+
found.push(valueEnumOfSchema(subSchema));
|
|
93
|
+
addEnumCandidates(subSchema, candidates);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const items = schema.items;
|
|
98
|
+
if (items) {
|
|
99
|
+
if (Array.isArray(items)) {
|
|
100
|
+
for (let i = 0; i < items.length; i++) {
|
|
101
|
+
addEnumCandidates(items[i] as JsonSchema, candidates);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
addEnumCandidates(items, candidates);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (schema.additionalItems && typeof schema.additionalItems === 'object') {
|
|
108
|
+
addEnumCandidates(schema.additionalItems, candidates);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const subSchemaLists: (JsonSchema[] | undefined)[] = [schema.allOf, schema.anyOf, schema.oneOf];
|
|
112
|
+
for (let i = 0; i < subSchemaLists.length; i++) {
|
|
113
|
+
const subSchemas = subSchemaLists[i];
|
|
114
|
+
if (subSchemas) {
|
|
115
|
+
for (let j = 0; j < subSchemas.length; j++) {
|
|
116
|
+
addEnumCandidates(subSchemas[j] as JsonSchema, candidates);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (schema.not) {
|
|
121
|
+
addEnumCandidates(schema.not, candidates);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const subSchemaMaps: ({ [k: string]: JsonSchema } | undefined)[] = [schema.patternProperties, schema.definitions];
|
|
125
|
+
for (let i = 0; i < subSchemaMaps.length; i++) {
|
|
126
|
+
const schemaMap = subSchemaMaps[i];
|
|
127
|
+
if (schemaMap) {
|
|
128
|
+
Object.keys(schemaMap).forEach(key => addEnumCandidates(schemaMap[key] as JsonSchema, candidates));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const dependencies = schema.dependencies;
|
|
133
|
+
if (dependencies) {
|
|
134
|
+
Object.keys(dependencies).forEach(key => {
|
|
135
|
+
const dependency = dependencies[key] as JsonSchema | string[];
|
|
136
|
+
if (!Array.isArray(dependency)) {
|
|
137
|
+
addEnumCandidates(dependency, candidates);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates the table that maps a property name to the enum of its values.
|
|
145
|
+
* A property name is only compressed when it has the same compressible enum
|
|
146
|
+
* at every place where it occurs in the schema. Otherwise the same value
|
|
147
|
+
* could mean different things depending on where it is stored.
|
|
148
|
+
*/
|
|
149
|
+
export function getEnumCompressionTable(
|
|
150
|
+
schema: JsonSchema,
|
|
151
|
+
ignoreProperties: string[]
|
|
152
|
+
): EnumCompressionTable {
|
|
153
|
+
const candidates: Map<string, (string[] | null)[]> = new Map();
|
|
154
|
+
addEnumCandidates(schema, candidates);
|
|
155
|
+
|
|
156
|
+
const table: EnumCompressionTable = new Map();
|
|
157
|
+
const propertyNames = Array.from(candidates.keys()).sort(alphabeticCompare);
|
|
158
|
+
for (let i = 0; i < propertyNames.length; i++) {
|
|
159
|
+
const property = propertyNames[i] as string;
|
|
160
|
+
if (ignoreProperties.includes(property)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const occurrences = candidates.get(property) as (string[] | null)[];
|
|
164
|
+
const first = occurrences[0];
|
|
165
|
+
if (!first) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
let isAmbiguous = false;
|
|
169
|
+
for (let j = 1; j < occurrences.length; j++) {
|
|
170
|
+
const other = occurrences[j];
|
|
171
|
+
if (!other || !equalEnumValues(first, other)) {
|
|
172
|
+
isAmbiguous = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!isAmbiguous) {
|
|
177
|
+
table.set(property, first);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return table;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Returns true if the given number can be an index of the enum.
|
|
185
|
+
* Number.isInteger() is not used to stay usable on old runtimes.
|
|
186
|
+
*/
|
|
187
|
+
function isEnumIndex(value: number, enumValues: string[]): boolean {
|
|
188
|
+
return value >= 0 && value < enumValues.length && value % 1 === 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Replaces the enum-value by its index.
|
|
193
|
+
* Values that are not part of the enum are kept as they are,
|
|
194
|
+
* so that data which does not match the schema is not destroyed.
|
|
195
|
+
*/
|
|
196
|
+
export function compressEnumValue(
|
|
197
|
+
enumValues: string[],
|
|
198
|
+
value: any
|
|
199
|
+
): any {
|
|
200
|
+
if (typeof value === 'string') {
|
|
201
|
+
const index = enumValues.indexOf(value);
|
|
202
|
+
return index === -1 ? value : index;
|
|
203
|
+
}
|
|
204
|
+
if (Array.isArray(value)) {
|
|
205
|
+
const ret: any[] = new Array(value.length);
|
|
206
|
+
for (let i = 0; i < value.length; i++) {
|
|
207
|
+
const item = value[i];
|
|
208
|
+
if (typeof item === 'string') {
|
|
209
|
+
const index = enumValues.indexOf(item);
|
|
210
|
+
ret[i] = index === -1 ? item : index;
|
|
211
|
+
} else {
|
|
212
|
+
ret[i] = item;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return ret;
|
|
216
|
+
}
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Replaces the index by its enum-value.
|
|
222
|
+
* The exact counterpart of compressEnumValue().
|
|
223
|
+
*/
|
|
224
|
+
export function decompressEnumValue(
|
|
225
|
+
enumValues: string[],
|
|
226
|
+
value: any
|
|
227
|
+
): any {
|
|
228
|
+
if (typeof value === 'number') {
|
|
229
|
+
return isEnumIndex(value, enumValues) ? enumValues[value] : value;
|
|
230
|
+
}
|
|
231
|
+
if (Array.isArray(value)) {
|
|
232
|
+
const ret: any[] = new Array(value.length);
|
|
233
|
+
for (let i = 0; i < value.length; i++) {
|
|
234
|
+
const item = value[i];
|
|
235
|
+
ret[i] = (typeof item === 'number' && isEnumIndex(item, enumValues)) ? enumValues[item] : item;
|
|
236
|
+
}
|
|
237
|
+
return ret;
|
|
238
|
+
}
|
|
239
|
+
return value;
|
|
240
|
+
}
|
package/src/index.ts
CHANGED
package/src/types.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
export type TableType = Map<string, string>;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Maps a property name to the sorted enum-values of that property.
|
|
5
|
+
* A value is compressed by replacing it with its index in this list.
|
|
6
|
+
*/
|
|
7
|
+
export type EnumCompressionTable = Map<string, string[]>;
|
|
8
|
+
|
|
3
9
|
export type CompressionTable = {
|
|
4
10
|
compressedToUncompressed: TableType;
|
|
5
11
|
uncompressedToCompressed: TableType;
|
|
6
12
|
compressionFlag: string;
|
|
13
|
+
/**
|
|
14
|
+
* Only set when enum-compression is enabled
|
|
15
|
+
* and the schema has at least one compressible enum.
|
|
16
|
+
*/
|
|
17
|
+
enumCompression?: EnumCompressionTable;
|
|
7
18
|
};
|
|
8
19
|
|
|
9
20
|
|