@kemdict/json-to-ts 0.1.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 +6 -0
- package/README.md +96 -0
- package/dist/get-interfaces.d.ts +6 -0
- package/dist/get-interfaces.d.ts.map +1 -0
- package/dist/get-interfaces.js +99 -0
- package/dist/get-interfaces.js.map +1 -0
- package/dist/get-names.d.ts +3 -0
- package/dist/get-names.d.ts.map +1 -0
- package/dist/get-names.js +147 -0
- package/dist/get-names.js.map +1 -0
- package/dist/get-type-structure.d.ts +5 -0
- package/dist/get-type-structure.d.ts.map +1 -0
- package/dist/get-type-structure.js +258 -0
- package/dist/get-type-structure.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +62 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/util.d.ts +11 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +49 -0
- package/dist/util.js.map +1 -0
- package/package.json +40 -0
- package/src/get-interfaces.ts +121 -0
- package/src/get-names.ts +218 -0
- package/src/get-type-structure.ts +308 -0
- package/src/index.ts +39 -0
- package/src/model.ts +65 -0
- package/src/util.ts +63 -0
- package/tsconfig.json +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Copyright 2017-2024 MariusAlch
|
|
2
|
+
Copyright 2026 Kisaragi Hiu
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and /or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
5
|
+
|
|
6
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @kemdict/json-to-ts
|
|
2
|
+
|
|
3
|
+
Fork of [MariusAlch/json-to-ts](https://github.com/MariusAlch/json-to-ts).
|
|
4
|
+
|
|
5
|
+
Convert json object to typescript interfaces
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"es7-shim": "^6.0.0",
|
|
12
|
+
"hash.js": "^1.0.3",
|
|
13
|
+
"pluralize": "^3.1.0"
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
And also to customize to my own use.
|
|
18
|
+
|
|
19
|
+
Much thanks to the original author, MariusAlch, for making this in the first
|
|
20
|
+
place. Me complaining about details is easy, but getting a project like this
|
|
21
|
+
started is the hard part which they have already graciously done.
|
|
22
|
+
|
|
23
|
+
## Changes from original
|
|
24
|
+
|
|
25
|
+
- ESM with both default export and named export
|
|
26
|
+
- Far less dependencies (from +106 to +2, mostly from removing es7-shim)
|
|
27
|
+
- Requires a Node-compatible runtime (for `hash` from `node:crypto`). (I decided
|
|
28
|
+
against
|
|
29
|
+
[`window.crypto.subtle.digest`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest)
|
|
30
|
+
since it's async.)
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
Original features:
|
|
35
|
+
|
|
36
|
+
- Array type merging
|
|
37
|
+
- Union types
|
|
38
|
+
- Duplicate type prevention
|
|
39
|
+
- Optional types
|
|
40
|
+
- Array types
|
|
41
|
+
|
|
42
|
+
Features in this version:
|
|
43
|
+
|
|
44
|
+
- Export the root object automatically in the output
|
|
45
|
+
- Root object will not be singularized
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
$ npm install @kemdict/json-to-ts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Example
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import { JsonToTS } from "@kemdict/json-to-ts";
|
|
57
|
+
|
|
58
|
+
const json = {
|
|
59
|
+
cats: [{ name: "Kittin" }, { name: "Mittin" }],
|
|
60
|
+
favoriteNumber: 42,
|
|
61
|
+
favoriteWord: "Hello",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
JsonToTS(json).forEach((typeInterface) => {
|
|
65
|
+
console.log(typeInterface);
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This prints:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
interface RootObject {
|
|
73
|
+
cats: Cat[];
|
|
74
|
+
favoriteNumber: number;
|
|
75
|
+
favoriteWord: string;
|
|
76
|
+
}
|
|
77
|
+
interface Cat {
|
|
78
|
+
name: string;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Options
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { JsonToTS } from "@kemdict/json-to-ts";
|
|
86
|
+
const value = [{ "a": 3 }, { "b": 4 }];
|
|
87
|
+
JsonToTS(value, {
|
|
88
|
+
// The name of the generated root type
|
|
89
|
+
rootName: "RootObject",
|
|
90
|
+
// Whether to use `type Foo = { ... }` instead.
|
|
91
|
+
// Default (false) is to use `interface Foo { ... }`.
|
|
92
|
+
useTypeAlias: false,
|
|
93
|
+
// Whether to export the root type
|
|
94
|
+
export: false,
|
|
95
|
+
});
|
|
96
|
+
```
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { InterfaceDescription, NameEntry, TypeStructure, State } from "./model.ts";
|
|
2
|
+
export declare function getInterfaceStringFromDescription({ name, typeMap, state, }: InterfaceDescription & {
|
|
3
|
+
state: State;
|
|
4
|
+
}): string;
|
|
5
|
+
export declare function getInterfaceDescriptions(typeStructure: TypeStructure, names: NameEntry[]): InterfaceDescription[];
|
|
6
|
+
//# sourceMappingURL=get-interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-interfaces.d.ts","sourceRoot":"","sources":["../src/get-interfaces.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,aAAa,EAAwB,KAAK,EAAE,MAAM,YAAY,CAAC;AAuF9G,wBAAgB,iCAAiC,CAAC,EAChD,IAAI,EACJ,OAAO,EACP,KAAK,GACN,EAAE,oBAAoB,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,MAAM,CAalD;AAED,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,oBAAoB,EAAE,CAajH"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { isHash, findTypeById, isNonArrayUnion } from "./util.js";
|
|
2
|
+
function isKeyNameValid(keyName) {
|
|
3
|
+
const regex = /^[a-zA-Z_][a-zA-Z\d_]*$/;
|
|
4
|
+
return regex.test(keyName);
|
|
5
|
+
}
|
|
6
|
+
function parseKeyMetaData(key) {
|
|
7
|
+
const isOptional = key.endsWith("--?");
|
|
8
|
+
if (isOptional) {
|
|
9
|
+
return {
|
|
10
|
+
isOptional,
|
|
11
|
+
keyValue: key.slice(0, -3),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return {
|
|
16
|
+
isOptional,
|
|
17
|
+
keyValue: key,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function findNameById(id, names) {
|
|
22
|
+
const foundName = names.find((_) => _.id === id);
|
|
23
|
+
if (!foundName)
|
|
24
|
+
throw new Error("Name not found");
|
|
25
|
+
return foundName.name;
|
|
26
|
+
}
|
|
27
|
+
function removeUndefinedFromUnion(unionTypeName) {
|
|
28
|
+
const typeNames = unionTypeName.split(" | ");
|
|
29
|
+
const undefinedIndex = typeNames.indexOf("undefined");
|
|
30
|
+
typeNames.splice(undefinedIndex, 1);
|
|
31
|
+
return typeNames.join(" | ");
|
|
32
|
+
}
|
|
33
|
+
function replaceTypeObjIdsWithNames(typeObj, names) {
|
|
34
|
+
return (Object.entries(typeObj)
|
|
35
|
+
// quote key if is invalid and question mark if optional from array merging
|
|
36
|
+
.map(([key, type]) => {
|
|
37
|
+
const { isOptional, keyValue } = parseKeyMetaData(key);
|
|
38
|
+
const isValid = isKeyNameValid(keyValue);
|
|
39
|
+
const validName = isValid ? keyValue : `'${keyValue}'`;
|
|
40
|
+
return isOptional ? [`${validName}?`, type, isOptional] : [validName, type, isOptional];
|
|
41
|
+
})
|
|
42
|
+
// replace hashes with names referencing the hashes
|
|
43
|
+
.map(([key, type, isOptional]) => {
|
|
44
|
+
if (!isHash(type)) {
|
|
45
|
+
return [key, type, isOptional];
|
|
46
|
+
}
|
|
47
|
+
const newType = findNameById(type, names);
|
|
48
|
+
return [key, newType, isOptional];
|
|
49
|
+
})
|
|
50
|
+
// if union has undefined, remove undefined and make type optional
|
|
51
|
+
.map(([key, type, isOptional]) => {
|
|
52
|
+
if (!(isNonArrayUnion(type) && type.includes("undefined"))) {
|
|
53
|
+
return [key, type, isOptional];
|
|
54
|
+
}
|
|
55
|
+
const newType = removeUndefinedFromUnion(type);
|
|
56
|
+
const newKey = isOptional ? key : `${key}?`; // if already optional dont add question mark
|
|
57
|
+
return [newKey, newType, isOptional];
|
|
58
|
+
})
|
|
59
|
+
// make undefined optional and set type as any
|
|
60
|
+
.map(([key, type, isOptional]) => {
|
|
61
|
+
if (type !== "undefined") {
|
|
62
|
+
return [key, type, isOptional];
|
|
63
|
+
}
|
|
64
|
+
const newType = "any";
|
|
65
|
+
const newKey = isOptional ? key : `${key}?`; // if already optional dont add question mark
|
|
66
|
+
return [newKey, newType, isOptional];
|
|
67
|
+
})
|
|
68
|
+
.reduce((agg, [key, value]) => {
|
|
69
|
+
agg[key] = value;
|
|
70
|
+
return agg;
|
|
71
|
+
}, {}));
|
|
72
|
+
}
|
|
73
|
+
export function getInterfaceStringFromDescription({ name, typeMap, state, }) {
|
|
74
|
+
const stringTypeMap = Object.entries(typeMap)
|
|
75
|
+
.map(([key, name]) => ` ${key}: ${name};\n`)
|
|
76
|
+
.reduce((a, b) => (a += b), "");
|
|
77
|
+
const useTypeAlias = state.useTypeAlias;
|
|
78
|
+
const exportKeyword = state.export && name === state.keyName ? "export " : "";
|
|
79
|
+
const declarationKeyWord = useTypeAlias ? "type" : "interface";
|
|
80
|
+
let result = `${exportKeyword}${declarationKeyWord} ${name}${useTypeAlias ? " =" : ""} {\n`;
|
|
81
|
+
result += stringTypeMap;
|
|
82
|
+
result += "}";
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
export function getInterfaceDescriptions(typeStructure, names) {
|
|
86
|
+
return names
|
|
87
|
+
.map(({ id, name }) => {
|
|
88
|
+
const typeDescription = findTypeById(id, typeStructure.types);
|
|
89
|
+
if (typeDescription?.typeObj) {
|
|
90
|
+
const typeMap = replaceTypeObjIdsWithNames(typeDescription.typeObj, names);
|
|
91
|
+
return { name, typeMap };
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
.filter((_) => _ !== null);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=get-interfaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-interfaces.js","sourceRoot":"","sources":["../src/get-interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-names.d.ts","sourceRoot":"","sources":["../src/get-names.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EAIT,KAAK,EACN,MAAM,YAAY,CAAC;AA8DpB,wBAAgB,QAAQ,CAAC,aAAa,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,EAAE,CAEhF"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import pluralize from "pluralize";
|
|
2
|
+
import { getTypeDescriptionGroup, parseKeyMetaData, findTypeById, isHash } from "./util.js";
|
|
3
|
+
function getName({ rootTypeId, types }, state, names, isInsideArray) {
|
|
4
|
+
const typeDesc = types.find((_) => _.id === rootTypeId);
|
|
5
|
+
const { group, desc } = getTypeDescriptionGroup(typeDesc);
|
|
6
|
+
switch (group) {
|
|
7
|
+
case "array":
|
|
8
|
+
desc.arrayOfTypes.forEach((typeIdOrPrimitive, i) => {
|
|
9
|
+
getName({ rootTypeId: typeIdOrPrimitive, types },
|
|
10
|
+
// to differenttiate array types
|
|
11
|
+
{
|
|
12
|
+
...state,
|
|
13
|
+
lvl: state.lvl + 1,
|
|
14
|
+
keyName: i === 0 ? state.keyName : `${state.keyName}${i + 1}`,
|
|
15
|
+
}, names, true);
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
rootName: getNameById(desc.id, state, isInsideArray, types, names),
|
|
19
|
+
names,
|
|
20
|
+
};
|
|
21
|
+
case "object":
|
|
22
|
+
Object.entries(desc.typeObj).forEach(([key, value]) => {
|
|
23
|
+
getName({ rootTypeId: value, types }, {
|
|
24
|
+
...state,
|
|
25
|
+
lvl: state.lvl + 1,
|
|
26
|
+
keyName: key,
|
|
27
|
+
}, names, false);
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
rootName: getNameById(typeDesc.id, state, isInsideArray, types, names),
|
|
31
|
+
names,
|
|
32
|
+
};
|
|
33
|
+
case "primitive":
|
|
34
|
+
// in this case rootTypeId is primitive type string (string, null, number, boolean)
|
|
35
|
+
return {
|
|
36
|
+
rootName: rootTypeId,
|
|
37
|
+
names,
|
|
38
|
+
};
|
|
39
|
+
default:
|
|
40
|
+
throw new Error("impossible");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function getNames(typeStructure, state) {
|
|
44
|
+
return getName(typeStructure, state, [], false).names.reverse();
|
|
45
|
+
}
|
|
46
|
+
function getNameById(id, state, isInsideArray, types, nameMap) {
|
|
47
|
+
let nameEntry = nameMap.find((_) => _.id === id);
|
|
48
|
+
if (nameEntry) {
|
|
49
|
+
return nameEntry.name;
|
|
50
|
+
}
|
|
51
|
+
const typeDesc = findTypeById(id, types);
|
|
52
|
+
let name;
|
|
53
|
+
const { group, desc } = getTypeDescriptionGroup(typeDesc);
|
|
54
|
+
switch (group) {
|
|
55
|
+
case "array":
|
|
56
|
+
name = desc.isUnion ? getArrayName(desc, types, nameMap, state) : formatArrayName(desc, types, nameMap, state);
|
|
57
|
+
break;
|
|
58
|
+
case "object":
|
|
59
|
+
/**
|
|
60
|
+
* picking name for type in array requires to singularize that type name,
|
|
61
|
+
* and if not then no need to singularize
|
|
62
|
+
*/
|
|
63
|
+
name = [state.keyName]
|
|
64
|
+
.map((key) => parseKeyMetaData(key).keyValue)
|
|
65
|
+
.map((name) => {
|
|
66
|
+
if (isInsideArray && state.lvl > 0) {
|
|
67
|
+
return pluralize.singular(name);
|
|
68
|
+
}
|
|
69
|
+
return name;
|
|
70
|
+
})
|
|
71
|
+
.map(pascalCase)
|
|
72
|
+
.map(normalizeInvalidTypeName)
|
|
73
|
+
.map(pascalCase) // needed because removed symbols might leave first character uncapitalized
|
|
74
|
+
.map((name) => uniqueByIncrement(name, nameMap.map(({ name }) => name)))
|
|
75
|
+
.pop();
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
if (name === undefined)
|
|
79
|
+
throw new Error("Failed to get name");
|
|
80
|
+
nameMap.push({ id, name });
|
|
81
|
+
return name;
|
|
82
|
+
}
|
|
83
|
+
function pascalCase(name) {
|
|
84
|
+
return name
|
|
85
|
+
.split(/\s+/g)
|
|
86
|
+
.filter((_) => _ !== "")
|
|
87
|
+
.map(capitalize)
|
|
88
|
+
.reduce((a, b) => a + b, "");
|
|
89
|
+
}
|
|
90
|
+
function capitalize(name) {
|
|
91
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
92
|
+
}
|
|
93
|
+
function normalizeInvalidTypeName(name) {
|
|
94
|
+
if (/^[a-zA-Z][a-zA-Z0-9]*$/.test(name)) {
|
|
95
|
+
return name;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const noSymbolsName = name.replace(/[^a-zA-Z0-9]/g, "");
|
|
99
|
+
const startsWithWordCharacter = /^[a-zA-Z]/.test(noSymbolsName);
|
|
100
|
+
return startsWithWordCharacter ? noSymbolsName : `_${noSymbolsName}`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function uniqueByIncrement(name, names) {
|
|
104
|
+
for (let i = 0; i < 1000; i++) {
|
|
105
|
+
const nameProposal = i === 0 ? name : `${name}${i + 1}`;
|
|
106
|
+
if (!names.includes(nameProposal)) {
|
|
107
|
+
return nameProposal;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw new Error("Failed to propose new name");
|
|
111
|
+
}
|
|
112
|
+
function getArrayName(typeDesc, types, nameMap, state) {
|
|
113
|
+
if (typeDesc.arrayOfTypes.length === 0) {
|
|
114
|
+
return "any";
|
|
115
|
+
}
|
|
116
|
+
else if (typeDesc.arrayOfTypes.length === 1) {
|
|
117
|
+
const [idOrPrimitive] = typeDesc.arrayOfTypes;
|
|
118
|
+
return convertToReadableType(idOrPrimitive, types, nameMap, state);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return unionToString(typeDesc, types, nameMap, state);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function convertToReadableType(idOrPrimitive, types, nameMap, state) {
|
|
125
|
+
return isHash(idOrPrimitive)
|
|
126
|
+
? // array keyName makes no difference in picking name for type
|
|
127
|
+
getNameById(idOrPrimitive, { ...state, keyName: "" }, true, types, nameMap)
|
|
128
|
+
: idOrPrimitive;
|
|
129
|
+
}
|
|
130
|
+
function unionToString(typeDesc, types, nameMap, state) {
|
|
131
|
+
return typeDesc.arrayOfTypes.reduce((acc, type, i) => {
|
|
132
|
+
const readableTypeName = convertToReadableType(type, types, nameMap, state);
|
|
133
|
+
return i === 0 ? readableTypeName : `${acc} | ${readableTypeName}`;
|
|
134
|
+
}, "");
|
|
135
|
+
}
|
|
136
|
+
function formatArrayName(typeDesc, types, nameMap, state) {
|
|
137
|
+
const innerTypeId = typeDesc.arrayOfTypes[0];
|
|
138
|
+
// const isMultipleTypeArray = findTypeById(innerTypeId, types).arrayOfTypes.length > 1
|
|
139
|
+
const isMultipleTypeArray = isHash(innerTypeId) &&
|
|
140
|
+
findTypeById(innerTypeId, types)?.isUnion &&
|
|
141
|
+
(findTypeById(innerTypeId, types)?.arrayOfTypes?.length ?? 0) > 1;
|
|
142
|
+
const readableInnerType = getArrayName(typeDesc, types, nameMap, state);
|
|
143
|
+
return isMultipleTypeArray
|
|
144
|
+
? `(${readableInnerType})[]` // add semicolons for union type
|
|
145
|
+
: `${readableInnerType}[]`;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=get-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-names.js","sourceRoot":"","sources":["../src/get-names.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TypeDescription, TypeStructure } from "./model.ts";
|
|
2
|
+
export declare function getTypeStructure(targetObj: any, // object that we want to create types for
|
|
3
|
+
types?: TypeDescription[]): TypeStructure;
|
|
4
|
+
export declare function optimizeTypeStructure(typeStructure: TypeStructure): void;
|
|
5
|
+
//# sourceMappingURL=get-type-structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-type-structure.d.ts","sourceRoot":"","sources":["../src/get-type-structure.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAa,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkO5E,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,GAAG,EAAE,0CAA0C;AAC1D,KAAK,GAAE,eAAe,EAAO,GAC5B,aAAa,CAmCf;AAmCD,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,aAAa,QAMjE"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { hash } from "node:crypto";
|
|
2
|
+
import { isHash, getTypeDescriptionGroup, findTypeById, isArray, isObject, onlyUnique, isDate } from "./util.js";
|
|
3
|
+
function createTypeDescription(typeObj, isUnion) {
|
|
4
|
+
if (isArray(typeObj)) {
|
|
5
|
+
return {
|
|
6
|
+
id: Hash(JSON.stringify([...typeObj, isUnion])),
|
|
7
|
+
arrayOfTypes: typeObj,
|
|
8
|
+
isUnion,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return {
|
|
13
|
+
id: Hash(JSON.stringify(typeObj)),
|
|
14
|
+
typeObj,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function getIdByType(typeObj, types, isUnion = false) {
|
|
19
|
+
let typeDesc = types.find((el) => {
|
|
20
|
+
return typeObjectMatchesTypeDesc(typeObj, el, isUnion);
|
|
21
|
+
});
|
|
22
|
+
if (!typeDesc) {
|
|
23
|
+
typeDesc = createTypeDescription(typeObj, isUnion);
|
|
24
|
+
types.push(typeDesc);
|
|
25
|
+
}
|
|
26
|
+
return typeDesc.id;
|
|
27
|
+
}
|
|
28
|
+
function Hash(content) {
|
|
29
|
+
return hash("sha1", content);
|
|
30
|
+
}
|
|
31
|
+
function typeObjectMatchesTypeDesc(typeObj, typeDesc, isUnion) {
|
|
32
|
+
if (isArray(typeObj)) {
|
|
33
|
+
return arraysContainSameElements(typeObj, typeDesc.arrayOfTypes) && typeDesc.isUnion === isUnion;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return objectsHaveSameEntries(typeObj, typeDesc.typeObj);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function arraysContainSameElements(arr1, arr2) {
|
|
40
|
+
if (arr1 === undefined || arr2 === undefined)
|
|
41
|
+
return false;
|
|
42
|
+
return arr1.sort().join("") === arr2.sort().join("");
|
|
43
|
+
}
|
|
44
|
+
function objectsHaveSameEntries(obj1, obj2) {
|
|
45
|
+
if (obj1 === undefined || obj2 === undefined)
|
|
46
|
+
return false;
|
|
47
|
+
const entries1 = Object.entries(obj1);
|
|
48
|
+
const entries2 = Object.entries(obj2);
|
|
49
|
+
const sameLength = entries1.length === entries2.length;
|
|
50
|
+
const sameTypes = entries1.every(([key, value]) => {
|
|
51
|
+
return obj2[key] === value;
|
|
52
|
+
});
|
|
53
|
+
return sameLength && sameTypes;
|
|
54
|
+
}
|
|
55
|
+
function getSimpleTypeName(value) {
|
|
56
|
+
if (value === null) {
|
|
57
|
+
return "null";
|
|
58
|
+
}
|
|
59
|
+
else if (value instanceof Date) {
|
|
60
|
+
return "Date";
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return typeof value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getTypeGroup(value) {
|
|
67
|
+
if (isDate(value)) {
|
|
68
|
+
return "date";
|
|
69
|
+
}
|
|
70
|
+
else if (isArray(value)) {
|
|
71
|
+
return "array";
|
|
72
|
+
}
|
|
73
|
+
else if (isObject(value)) {
|
|
74
|
+
return "object";
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return "primitive";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function createTypeObject(obj, types) {
|
|
81
|
+
return Object.entries(obj).reduce((typeObj, [key, value]) => {
|
|
82
|
+
const { rootTypeId } = getTypeStructure(value, types);
|
|
83
|
+
return {
|
|
84
|
+
...typeObj,
|
|
85
|
+
[key]: rootTypeId,
|
|
86
|
+
};
|
|
87
|
+
}, {});
|
|
88
|
+
}
|
|
89
|
+
function getMergedObjects(typesOfArray, types) {
|
|
90
|
+
const typeObjects = typesOfArray.map((typeDesc) => typeDesc.typeObj);
|
|
91
|
+
const allKeys = typeObjects
|
|
92
|
+
.map((typeObj) => Object.keys(typeObj))
|
|
93
|
+
.reduce((a, b) => [...a, ...b], [])
|
|
94
|
+
.filter(onlyUnique);
|
|
95
|
+
const commonKeys = typeObjects.reduce((commonKeys, typeObj) => {
|
|
96
|
+
const keys = Object.keys(typeObj);
|
|
97
|
+
return commonKeys.filter((key) => keys.includes(key));
|
|
98
|
+
}, allKeys);
|
|
99
|
+
const getKeyType = (key) => {
|
|
100
|
+
const typesOfKey = typeObjects
|
|
101
|
+
.filter((typeObj) => {
|
|
102
|
+
return Object.keys(typeObj).includes(key);
|
|
103
|
+
})
|
|
104
|
+
.map((typeObj) => typeObj[key])
|
|
105
|
+
.filter(onlyUnique);
|
|
106
|
+
if (typesOfKey.length === 1) {
|
|
107
|
+
return typesOfKey.pop();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return getInnerArrayType(typesOfKey, types);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const typeObj = allKeys.reduce((obj, key) => {
|
|
114
|
+
const isMandatory = commonKeys.includes(key);
|
|
115
|
+
const type = getKeyType(key);
|
|
116
|
+
const keyValue = isMandatory ? key : toOptionalKey(key);
|
|
117
|
+
return {
|
|
118
|
+
...obj,
|
|
119
|
+
[keyValue]: type,
|
|
120
|
+
};
|
|
121
|
+
}, {});
|
|
122
|
+
return getIdByType(typeObj, types, true);
|
|
123
|
+
}
|
|
124
|
+
function toOptionalKey(key) {
|
|
125
|
+
return key.endsWith("--?") ? key : `${key}--?`;
|
|
126
|
+
}
|
|
127
|
+
function getMergedArrays(typesOfArray, types) {
|
|
128
|
+
const idsOfArrayTypes = typesOfArray
|
|
129
|
+
.map((typeDesc) => typeDesc.arrayOfTypes)
|
|
130
|
+
.reduce((a, b) => [...a, ...b], [])
|
|
131
|
+
.filter(onlyUnique);
|
|
132
|
+
if (idsOfArrayTypes.length === 1) {
|
|
133
|
+
return getIdByType([idsOfArrayTypes.pop()], types);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return getIdByType([getInnerArrayType(idsOfArrayTypes, types)], types);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// we merge union types example: (number | string), null -> (number | string | null)
|
|
140
|
+
function getMergedUnion(typesOfArray, types) {
|
|
141
|
+
const innerUnionsTypes = typesOfArray
|
|
142
|
+
.map((id) => {
|
|
143
|
+
return findTypeById(id, types);
|
|
144
|
+
})
|
|
145
|
+
.filter((_) => !!_ && _.isUnion)
|
|
146
|
+
.map((_) => _.arrayOfTypes)
|
|
147
|
+
.reduce((a, b) => [...a, ...b], []);
|
|
148
|
+
const primitiveTypes = typesOfArray.filter((id) => !findTypeById(id, types) || !findTypeById(id, types)?.isUnion); // primitives or not union
|
|
149
|
+
return getIdByType([...innerUnionsTypes, ...primitiveTypes], types, true);
|
|
150
|
+
}
|
|
151
|
+
function getInnerArrayType(typesOfArray, types) {
|
|
152
|
+
// return inner array type
|
|
153
|
+
const containsUndefined = typesOfArray.includes("undefined");
|
|
154
|
+
const arrayTypesDescriptions = typesOfArray.map((id) => findTypeById(id, types)).filter((_) => !!_);
|
|
155
|
+
const allArrayType = arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc).group === "array").length ===
|
|
156
|
+
typesOfArray.length;
|
|
157
|
+
const allArrayTypeWithUndefined = arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc).group === "array").length + 1 ===
|
|
158
|
+
typesOfArray.length && containsUndefined;
|
|
159
|
+
const allObjectTypeWithUndefined = arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc).group === "object").length + 1 ===
|
|
160
|
+
typesOfArray.length && containsUndefined;
|
|
161
|
+
const allObjectType = arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc).group === "object").length ===
|
|
162
|
+
typesOfArray.length;
|
|
163
|
+
if (typesOfArray.length === 0) {
|
|
164
|
+
// no types in array -> empty union type
|
|
165
|
+
return getIdByType([], types, true);
|
|
166
|
+
}
|
|
167
|
+
if (typesOfArray.length === 1) {
|
|
168
|
+
// one type in array -> that will be our inner type
|
|
169
|
+
return typesOfArray.pop();
|
|
170
|
+
}
|
|
171
|
+
if (typesOfArray.length > 1) {
|
|
172
|
+
// multiple types in merge array
|
|
173
|
+
// if all are object we can merge them and return merged object as inner type
|
|
174
|
+
if (allObjectType)
|
|
175
|
+
return getMergedObjects(arrayTypesDescriptions, types);
|
|
176
|
+
// if all are array we can merge them and return merged array as inner type
|
|
177
|
+
if (allArrayType)
|
|
178
|
+
return getMergedArrays(arrayTypesDescriptions, types);
|
|
179
|
+
// all array types with posibble undefined, result type = undefined | (*mergedArray*)[]
|
|
180
|
+
if (allArrayTypeWithUndefined) {
|
|
181
|
+
return getMergedUnion([getMergedArrays(arrayTypesDescriptions, types), "undefined"], types);
|
|
182
|
+
}
|
|
183
|
+
// all object types with posibble undefined, result type = undefined | *mergedObject*
|
|
184
|
+
if (allObjectTypeWithUndefined) {
|
|
185
|
+
return getMergedUnion([getMergedObjects(arrayTypesDescriptions, types), "undefined"], types);
|
|
186
|
+
}
|
|
187
|
+
// if they are mixed or all primitive we cant merge them so we return as mixed union type
|
|
188
|
+
return getMergedUnion(typesOfArray, types);
|
|
189
|
+
}
|
|
190
|
+
throw new Error("Failed to get inner array type");
|
|
191
|
+
}
|
|
192
|
+
export function getTypeStructure(targetObj, // object that we want to create types for
|
|
193
|
+
types = []) {
|
|
194
|
+
switch (getTypeGroup(targetObj)) {
|
|
195
|
+
case "array":
|
|
196
|
+
const typesOfArray = targetObj.map((_) => getTypeStructure(_, types).rootTypeId).filter(onlyUnique);
|
|
197
|
+
const arrayInnerTypeId = getInnerArrayType(typesOfArray, types); // create "union type of array types"
|
|
198
|
+
const typeId = getIdByType([arrayInnerTypeId], types); // create type "array of union type"
|
|
199
|
+
return {
|
|
200
|
+
rootTypeId: typeId,
|
|
201
|
+
types,
|
|
202
|
+
};
|
|
203
|
+
case "object":
|
|
204
|
+
const typeObj = createTypeObject(targetObj, types);
|
|
205
|
+
const objType = getIdByType(typeObj, types);
|
|
206
|
+
return {
|
|
207
|
+
rootTypeId: objType,
|
|
208
|
+
types,
|
|
209
|
+
};
|
|
210
|
+
case "primitive":
|
|
211
|
+
return {
|
|
212
|
+
rootTypeId: getSimpleTypeName(targetObj),
|
|
213
|
+
types,
|
|
214
|
+
};
|
|
215
|
+
case "date":
|
|
216
|
+
const dateType = getSimpleTypeName(targetObj);
|
|
217
|
+
return {
|
|
218
|
+
rootTypeId: dateType,
|
|
219
|
+
types,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function getAllUsedTypeIds({ rootTypeId, types }) {
|
|
224
|
+
const typeDesc = types.find((_) => _.id === rootTypeId);
|
|
225
|
+
function subTypes(typeDesc) {
|
|
226
|
+
const { group, desc } = getTypeDescriptionGroup(typeDesc);
|
|
227
|
+
switch (group) {
|
|
228
|
+
case "array":
|
|
229
|
+
const arrSubTypes = desc.arrayOfTypes
|
|
230
|
+
.filter(isHash)
|
|
231
|
+
.map((typeId) => {
|
|
232
|
+
const typeDesc = types.find((_) => _.id === typeId);
|
|
233
|
+
return subTypes(typeDesc);
|
|
234
|
+
})
|
|
235
|
+
.reduce((a, b) => [...a, ...b], []);
|
|
236
|
+
return [desc.id, ...arrSubTypes];
|
|
237
|
+
case "object":
|
|
238
|
+
const objSubTypes = Object.values(desc.typeObj)
|
|
239
|
+
.filter(isHash)
|
|
240
|
+
.map((typeId) => {
|
|
241
|
+
const typeDesc = types.find((_) => _.id === typeId);
|
|
242
|
+
return subTypes(typeDesc);
|
|
243
|
+
})
|
|
244
|
+
.reduce((a, b) => [...a, ...b], []);
|
|
245
|
+
return [desc.id, ...objSubTypes];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const result = subTypes(typeDesc);
|
|
249
|
+
if (!result)
|
|
250
|
+
throw new Error("Failed to get all used type Ids");
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
export function optimizeTypeStructure(typeStructure) {
|
|
254
|
+
const usedTypeIds = getAllUsedTypeIds(typeStructure);
|
|
255
|
+
const optimizedTypes = typeStructure.types.filter((typeDesc) => usedTypeIds?.includes(typeDesc.id));
|
|
256
|
+
typeStructure.types = optimizedTypes;
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=get-type-structure.js.map
|