json-to-ts
Version:
Convert json object to typescript interfaces
277 lines • 11.7 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
var hash = require("hash.js");
var util_1 = require("./util");
var model_1 = require("./model");
function createTypeDescription(typeObj, isUnion) {
if (util_1.isArray(typeObj)) {
return {
id: Hash(JSON.stringify(__spreadArrays(typeObj, [isUnion]))),
arrayOfTypes: typeObj,
isUnion: isUnion,
};
}
else {
return {
id: Hash(JSON.stringify(typeObj)),
typeObj: typeObj,
};
}
}
function getIdByType(typeObj, types, isUnion) {
if (isUnion === void 0) { isUnion = false; }
var typeDesc = types.find(function (el) {
return typeObjectMatchesTypeDesc(typeObj, el, isUnion);
});
if (!typeDesc) {
typeDesc = createTypeDescription(typeObj, isUnion);
types.push(typeDesc);
}
return typeDesc.id;
}
function Hash(content) {
return hash.sha1().update(content).digest("hex");
}
function typeObjectMatchesTypeDesc(typeObj, typeDesc, isUnion) {
if (util_1.isArray(typeObj)) {
return arraysContainSameElements(typeObj, typeDesc.arrayOfTypes) && typeDesc.isUnion === isUnion;
}
else {
return objectsHaveSameEntries(typeObj, typeDesc.typeObj);
}
}
function arraysContainSameElements(arr1, arr2) {
if (arr1 === undefined || arr2 === undefined)
return false;
return arr1.sort().join("") === arr2.sort().join("");
}
function objectsHaveSameEntries(obj1, obj2) {
if (obj1 === undefined || obj2 === undefined)
return false;
var entries1 = Object.entries(obj1);
var entries2 = Object.entries(obj2);
var sameLength = entries1.length === entries2.length;
var sameTypes = entries1.every(function (_a) {
var key = _a[0], value = _a[1];
return obj2[key] === value;
});
return sameLength && sameTypes;
}
function getSimpleTypeName(value) {
if (value === null) {
return "null";
}
else if (value instanceof Date) {
return "Date";
}
else {
return typeof value;
}
}
function getTypeGroup(value) {
if (util_1.isDate(value)) {
return model_1.TypeGroup.Date;
}
else if (util_1.isArray(value)) {
return model_1.TypeGroup.Array;
}
else if (util_1.isObject(value)) {
return model_1.TypeGroup.Object;
}
else {
return model_1.TypeGroup.Primitive;
}
}
function createTypeObject(obj, types) {
return Object.entries(obj).reduce(function (typeObj, _a) {
var _b;
var key = _a[0], value = _a[1];
var rootTypeId = getTypeStructure(value, types).rootTypeId;
return __assign(__assign({}, typeObj), (_b = {}, _b[key] = rootTypeId, _b));
}, {});
}
function getMergedObjects(typesOfArray, types) {
var typeObjects = typesOfArray.map(function (typeDesc) { return typeDesc.typeObj; });
var allKeys = typeObjects
.map(function (typeObj) { return Object.keys(typeObj); })
.reduce(function (a, b) { return __spreadArrays(a, b); }, [])
.filter(util_1.onlyUnique);
var commonKeys = typeObjects.reduce(function (commonKeys, typeObj) {
var keys = Object.keys(typeObj);
return commonKeys.filter(function (key) { return keys.includes(key); });
}, allKeys);
var getKeyType = function (key) {
var typesOfKey = typeObjects
.filter(function (typeObj) {
return Object.keys(typeObj).includes(key);
})
.map(function (typeObj) { return typeObj[key]; })
.filter(util_1.onlyUnique);
if (typesOfKey.length === 1) {
return typesOfKey.pop();
}
else {
return getInnerArrayType(typesOfKey, types);
}
};
var typeObj = allKeys.reduce(function (obj, key) {
var _a;
var isMandatory = commonKeys.includes(key);
var type = getKeyType(key);
var keyValue = isMandatory ? key : toOptionalKey(key);
return __assign(__assign({}, obj), (_a = {}, _a[keyValue] = type, _a));
}, {});
return getIdByType(typeObj, types, true);
}
function toOptionalKey(key) {
return key.endsWith("--?") ? key : key + "--?";
}
function getMergedArrays(typesOfArray, types) {
var idsOfArrayTypes = typesOfArray
.map(function (typeDesc) { return typeDesc.arrayOfTypes; })
.reduce(function (a, b) { return __spreadArrays(a, b); }, [])
.filter(util_1.onlyUnique);
if (idsOfArrayTypes.length === 1) {
return getIdByType([idsOfArrayTypes.pop()], types);
}
else {
return getIdByType([getInnerArrayType(idsOfArrayTypes, types)], types);
}
}
// we merge union types example: (number | string), null -> (number | string | null)
function getMergedUnion(typesOfArray, types) {
var innerUnionsTypes = typesOfArray
.map(function (id) {
return util_1.findTypeById(id, types);
})
.filter(function (_) { return !!_ && _.isUnion; })
.map(function (_) { return _.arrayOfTypes; })
.reduce(function (a, b) { return __spreadArrays(a, b); }, []);
var primitiveTypes = typesOfArray.filter(function (id) { return !util_1.findTypeById(id, types) || !util_1.findTypeById(id, types).isUnion; }); // primitives or not union
return getIdByType(__spreadArrays(innerUnionsTypes, primitiveTypes), types, true);
}
function getInnerArrayType(typesOfArray, types) {
// return inner array type
var containsUndefined = typesOfArray.includes("undefined");
var arrayTypesDescriptions = typesOfArray.map(function (id) { return util_1.findTypeById(id, types); }).filter(function (_) { return !!_; });
var allArrayType = arrayTypesDescriptions.filter(function (typeDesc) { return util_1.getTypeDescriptionGroup(typeDesc) === model_1.TypeGroup.Array; }).length ===
typesOfArray.length;
var allArrayTypeWithUndefined = arrayTypesDescriptions.filter(function (typeDesc) { return util_1.getTypeDescriptionGroup(typeDesc) === model_1.TypeGroup.Array; }).length + 1 ===
typesOfArray.length && containsUndefined;
var allObjectTypeWithUndefined = arrayTypesDescriptions.filter(function (typeDesc) { return util_1.getTypeDescriptionGroup(typeDesc) === model_1.TypeGroup.Object; }).length + 1 ===
typesOfArray.length && containsUndefined;
var allObjectType = arrayTypesDescriptions.filter(function (typeDesc) { return util_1.getTypeDescriptionGroup(typeDesc) === model_1.TypeGroup.Object; }).length ===
typesOfArray.length;
if (typesOfArray.length === 0) {
// no types in array -> empty union type
return getIdByType([], types, true);
}
if (typesOfArray.length === 1) {
// one type in array -> that will be our inner type
return typesOfArray.pop();
}
if (typesOfArray.length > 1) {
// multiple types in merge array
// if all are object we can merge them and return merged object as inner type
if (allObjectType)
return getMergedObjects(arrayTypesDescriptions, types);
// if all are array we can merge them and return merged array as inner type
if (allArrayType)
return getMergedArrays(arrayTypesDescriptions, types);
// all array types with posibble undefined, result type = undefined | (*mergedArray*)[]
if (allArrayTypeWithUndefined) {
return getMergedUnion([getMergedArrays(arrayTypesDescriptions, types), "undefined"], types);
}
// all object types with posibble undefined, result type = undefined | *mergedObject*
if (allObjectTypeWithUndefined) {
return getMergedUnion([getMergedObjects(arrayTypesDescriptions, types), "undefined"], types);
}
// if they are mixed or all primitive we cant merge them so we return as mixed union type
return getMergedUnion(typesOfArray, types);
}
}
function getTypeStructure(targetObj, // object that we want to create types for
types) {
if (types === void 0) { types = []; }
switch (getTypeGroup(targetObj)) {
case model_1.TypeGroup.Array:
var typesOfArray = targetObj.map(function (_) { return getTypeStructure(_, types).rootTypeId; }).filter(util_1.onlyUnique);
var arrayInnerTypeId = getInnerArrayType(typesOfArray, types); // create "union type of array types"
var typeId = getIdByType([arrayInnerTypeId], types); // create type "array of union type"
return {
rootTypeId: typeId,
types: types,
};
case model_1.TypeGroup.Object:
var typeObj = createTypeObject(targetObj, types);
var objType = getIdByType(typeObj, types);
return {
rootTypeId: objType,
types: types,
};
case model_1.TypeGroup.Primitive:
return {
rootTypeId: getSimpleTypeName(targetObj),
types: types,
};
case model_1.TypeGroup.Date:
var dateType = getSimpleTypeName(targetObj);
return {
rootTypeId: dateType,
types: types,
};
}
}
exports.getTypeStructure = getTypeStructure;
function getAllUsedTypeIds(_a) {
var rootTypeId = _a.rootTypeId, types = _a.types;
var typeDesc = types.find(function (_) { return _.id === rootTypeId; });
var subTypes = function (typeDesc) {
switch (util_1.getTypeDescriptionGroup(typeDesc)) {
case model_1.TypeGroup.Array:
var arrSubTypes = typeDesc.arrayOfTypes
.filter(util_1.isHash)
.map(function (typeId) {
var typeDesc = types.find(function (_) { return _.id === typeId; });
return subTypes(typeDesc);
})
.reduce(function (a, b) { return __spreadArrays(a, b); }, []);
return __spreadArrays([typeDesc.id], arrSubTypes);
case model_1.TypeGroup.Object:
var objSubTypes = Object.values(typeDesc.typeObj)
.filter(util_1.isHash)
.map(function (typeId) {
var typeDesc = types.find(function (_) { return _.id === typeId; });
return subTypes(typeDesc);
})
.reduce(function (a, b) { return __spreadArrays(a, b); }, []);
return __spreadArrays([typeDesc.id], objSubTypes);
}
};
return subTypes(typeDesc);
}
function optimizeTypeStructure(typeStructure) {
var usedTypeIds = getAllUsedTypeIds(typeStructure);
var optimizedTypes = typeStructure.types.filter(function (typeDesc) { return usedTypeIds.includes(typeDesc.id); });
typeStructure.types = optimizedTypes;
}
exports.optimizeTypeStructure = optimizeTypeStructure;
//# sourceMappingURL=get-type-structure.js.map