├── .gitignore ├── .npmignore ├── .prettierrc ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── README.md ├── package.json ├── src ├── get-interfaces.ts ├── get-names.ts ├── get-type-structure.ts ├── index.ts ├── model.ts └── util.ts ├── test ├── array-merging.spec.ts ├── js-integration │ └── index.js ├── multiple-interface.spec.ts ├── root-array.spec.ts ├── single-interface.spec.ts └── util │ └── index.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | build -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | yarn.lock -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120 3 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Typescript", 11 | "program": "${workspaceRoot}/src/index.ts", 12 | "cwd": "${workspaceRoot}", 13 | "preLaunchTask": "build", 14 | "outFiles": [ 15 | "${workspaceRoot}/build/**/*.js", 16 | "${workspaceRoot}/build/**/*.d.ts", 17 | "${workspaceRoot}/build/**/*.js.map" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "**/.git": true, 5 | "**/.svn": true, 6 | "**/.hg": true, 7 | "**/CVS": true, 8 | "**/.DS_Store": true, 9 | "**/build": true 10 | } 11 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "command": "npm", 6 | "tasks": [ 7 | { 8 | "label": "install", 9 | "type": "shell", 10 | "args": ["install"], 11 | "problemMatcher": [] 12 | }, 13 | { 14 | "label": "update", 15 | "type": "shell", 16 | "args": ["update"], 17 | "problemMatcher": [] 18 | }, 19 | { 20 | "label": "test", 21 | "type": "shell", 22 | "args": ["run", "test"], 23 | "problemMatcher": [] 24 | }, 25 | { 26 | "label": "build", 27 | "type": "shell", 28 | "args": ["run", "build"], 29 | "problemMatcher": [], 30 | "group": { 31 | "_id": "build", 32 | "isDefault": false 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![JSON TO TS](https://image.ibb.co/fTb60k/icon.png) 2 | 3 | # Json to TS 4 | 5 | ### Convert json object to typescript interfaces 6 | 7 | # Example 8 | 9 | ### Code 10 | 11 | ```javascript 12 | const JsonToTS = require('json-to-ts') 13 | 14 | const json = { 15 | cats: [ 16 | {name: 'Kittin'}, 17 | {name: 'Mittin'} 18 | ], 19 | favoriteNumber: 42, 20 | favoriteWord: 'Hello' 21 | } 22 | 23 | JsonToTS(json).forEach( typeInterface => { 24 | console.log(typeInterface) 25 | }) 26 | ``` 27 | 28 | ### Output: 29 | 30 | ```typescript 31 | interface RootObject { 32 | cats: Cat[]; 33 | favoriteNumber: number; 34 | favoriteWord: string; 35 | } 36 | interface Cat { 37 | name: string; 38 | } 39 | ``` 40 | 41 | ## Converter 42 | - Array type merging (**Big deal**) 43 | - Union types 44 | - Duplicate type prevention 45 | - Optional types 46 | - Array types 47 | 48 | # Setup 49 | 50 | ```sh 51 | $ npm install --save json-to-ts 52 | ``` 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-to-ts", 3 | "version": "2.1.0", 4 | "description": "Convert json object to typescript interfaces", 5 | "keywords": [ 6 | "typescript", 7 | "ts", 8 | "convert", 9 | "json", 10 | "util", 11 | "lib", 12 | "types" 13 | ], 14 | "types": "build/src/index.d.ts", 15 | "main": "build/src/index.js", 16 | "scripts": { 17 | "prepublish": "npm run build", 18 | "build": "rm -rf ./build && tsc", 19 | "start": "nodemon -e ts -w src -x 'ts-node src/index.ts'", 20 | "test": "npm run build && mocha ./test/js-integration/index.js && mocha ./build/test", 21 | "test-reload": "nodemon -e ts -w test -w src -x 'npm test'" 22 | }, 23 | "author": "https://github.com/mariusalch", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/MariusAlch/json-to-ts.git" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/MariusAlch/json-to-ts/issues" 30 | }, 31 | "license": "ISC", 32 | "dependencies": { 33 | "es7-shim": "^6.0.0", 34 | "hash.js": "^1.0.3", 35 | "pluralize": "^3.1.0" 36 | }, 37 | "devDependencies": { 38 | "@types/mocha": "2.2.40", 39 | "@types/node": "^7.0.12", 40 | "@types/pluralize": "^0.0.27", 41 | "mocha": "^6.1.4", 42 | "typescript": "^3.8.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/get-interfaces.ts: -------------------------------------------------------------------------------- 1 | import { InterfaceDescription, NameEntry, TypeStructure, KeyMetaData } from "./model"; 2 | import { isHash, findTypeById, isNonArrayUnion } from "./util"; 3 | 4 | function isKeyNameValid(keyName: string) { 5 | const regex = /^[a-zA-Z_][a-zA-Z\d_]*$/; 6 | return regex.test(keyName); 7 | } 8 | 9 | function parseKeyMetaData(key: string): KeyMetaData { 10 | const isOptional = key.endsWith("--?"); 11 | 12 | if (isOptional) { 13 | return { 14 | isOptional, 15 | keyValue: key.slice(0, -3), 16 | }; 17 | } else { 18 | return { 19 | isOptional, 20 | keyValue: key, 21 | }; 22 | } 23 | } 24 | 25 | function findNameById(id: string, names: NameEntry[]): string { 26 | return names.find((_) => _.id === id).name; 27 | } 28 | 29 | function removeUndefinedFromUnion(unionTypeName: string) { 30 | const typeNames = unionTypeName.split(" | "); 31 | const undefinedIndex = typeNames.indexOf("undefined"); 32 | typeNames.splice(undefinedIndex, 1); 33 | return typeNames.join(" | "); 34 | } 35 | 36 | function replaceTypeObjIdsWithNames(typeObj: { [index: string]: string }, names: NameEntry[]): object { 37 | return ( 38 | Object.entries(typeObj) 39 | // quote key if is invalid and question mark if optional from array merging 40 | .map(([key, type]): [string, string, boolean] => { 41 | const { isOptional, keyValue } = parseKeyMetaData(key); 42 | const isValid = isKeyNameValid(keyValue); 43 | 44 | const validName = isValid ? keyValue : `'${keyValue}'`; 45 | 46 | return isOptional ? [`${validName}?`, type, isOptional] : [validName, type, isOptional]; 47 | }) 48 | // replace hashes with names referencing the hashes 49 | .map(([key, type, isOptional]): [string, string, boolean] => { 50 | if (!isHash(type)) { 51 | return [key, type, isOptional]; 52 | } 53 | 54 | const newType = findNameById(type, names); 55 | return [key, newType, isOptional]; 56 | }) 57 | // if union has undefined, remove undefined and make type optional 58 | .map(([key, type, isOptional]): [string, string, boolean] => { 59 | if (!(isNonArrayUnion(type) && type.includes("undefined"))) { 60 | return [key, type, isOptional]; 61 | } 62 | 63 | const newType = removeUndefinedFromUnion(type); 64 | const newKey = isOptional ? key : `${key}?`; // if already optional dont add question mark 65 | return [newKey, newType, isOptional]; 66 | }) 67 | // make undefined optional and set type as any 68 | .map(([key, type, isOptional]): [string, string, boolean] => { 69 | if (type !== "undefined") { 70 | return [key, type, isOptional]; 71 | } 72 | 73 | const newType = "any"; 74 | const newKey = isOptional ? key : `${key}?`; // if already optional dont add question mark 75 | return [newKey, newType, isOptional]; 76 | }) 77 | .reduce((agg, [key, value]) => { 78 | agg[key] = value; 79 | return agg; 80 | }, {}) 81 | ); 82 | } 83 | 84 | export function getInterfaceStringFromDescription({ 85 | name, 86 | typeMap, 87 | useTypeAlias, 88 | }: InterfaceDescription & { useTypeAlias?: boolean }): string { 89 | const stringTypeMap = Object.entries(typeMap) 90 | .map(([key, name]) => ` ${key}: ${name};\n`) 91 | .reduce((a, b) => (a += b), ""); 92 | 93 | const declarationKeyWord = useTypeAlias ? "type" : "interface"; 94 | let interfaceString = `${declarationKeyWord} ${name}${useTypeAlias ? " =" : ""} {\n`; 95 | interfaceString += stringTypeMap; 96 | interfaceString += "}"; 97 | 98 | return interfaceString; 99 | } 100 | 101 | export function getInterfaceDescriptions(typeStructure: TypeStructure, names: NameEntry[]): InterfaceDescription[] { 102 | return names 103 | .map(({ id, name }) => { 104 | const typeDescription = findTypeById(id, typeStructure.types); 105 | 106 | if (typeDescription.typeObj) { 107 | const typeMap = replaceTypeObjIdsWithNames(typeDescription.typeObj, names); 108 | return { name, typeMap }; 109 | } else { 110 | return null; 111 | } 112 | }) 113 | .filter((_) => _ !== null); 114 | } 115 | -------------------------------------------------------------------------------- /src/get-names.ts: -------------------------------------------------------------------------------- 1 | import * as pluralize from "pluralize"; 2 | 3 | import { TypeStructure, NameEntry, NameStructure, TypeGroup, TypeDescription } from "./model"; 4 | import { getTypeDescriptionGroup, parseKeyMetaData, findTypeById, isHash } from "./util"; 5 | 6 | function getName( 7 | { rootTypeId, types }: TypeStructure, 8 | keyName: string, 9 | names: NameEntry[], 10 | isInsideArray: boolean 11 | ): NameStructure { 12 | const typeDesc = types.find((_) => _.id === rootTypeId); 13 | 14 | switch (getTypeDescriptionGroup(typeDesc)) { 15 | case TypeGroup.Array: 16 | typeDesc.arrayOfTypes.forEach((typeIdOrPrimitive, i) => { 17 | getName( 18 | { rootTypeId: typeIdOrPrimitive, types }, 19 | // to differenttiate array types 20 | i === 0 ? keyName : `${keyName}${i + 1}`, 21 | names, 22 | true 23 | ); 24 | }); 25 | return { 26 | rootName: getNameById(typeDesc.id, keyName, isInsideArray, types, names), 27 | names, 28 | }; 29 | 30 | case TypeGroup.Object: 31 | Object.entries(typeDesc.typeObj).forEach(([key, value]) => { 32 | getName({ rootTypeId: value, types }, key, names, false); 33 | }); 34 | return { 35 | rootName: getNameById(typeDesc.id, keyName, isInsideArray, types, names), 36 | names, 37 | }; 38 | 39 | case TypeGroup.Primitive: 40 | // in this case rootTypeId is primitive type string (string, null, number, boolean) 41 | return { 42 | rootName: rootTypeId, 43 | names, 44 | }; 45 | } 46 | } 47 | 48 | export function getNames(typeStructure: TypeStructure, rootName: string = "RootObject"): NameEntry[] { 49 | return getName(typeStructure, rootName, [], false).names.reverse(); 50 | } 51 | 52 | function getNameById( 53 | id: string, 54 | keyName: string, 55 | isInsideArray: boolean, 56 | types: TypeDescription[], 57 | nameMap: NameEntry[] 58 | ): string { 59 | let nameEntry = nameMap.find((_) => _.id === id); 60 | 61 | if (nameEntry) { 62 | return nameEntry.name; 63 | } 64 | 65 | const typeDesc = findTypeById(id, types); 66 | const group = getTypeDescriptionGroup(typeDesc); 67 | let name; 68 | 69 | switch (group) { 70 | case TypeGroup.Array: 71 | name = typeDesc.isUnion ? getArrayName(typeDesc, types, nameMap) : formatArrayName(typeDesc, types, nameMap); 72 | break; 73 | 74 | case TypeGroup.Object: 75 | /** 76 | * picking name for type in array requires to singularize that type name, 77 | * and if not then no need to singularize 78 | */ 79 | name = [keyName] 80 | .map((key) => parseKeyMetaData(key).keyValue) 81 | .map((name) => (isInsideArray ? pluralize.singular(name) : name)) 82 | .map(pascalCase) 83 | .map(normalizeInvalidTypeName) 84 | .map(pascalCase) // needed because removed symbols might leave first character uncapitalized 85 | .map((name) => 86 | uniqueByIncrement( 87 | name, 88 | nameMap.map(({ name }) => name) 89 | ) 90 | ) 91 | .pop(); 92 | break; 93 | } 94 | 95 | nameMap.push({ id, name }); 96 | return name; 97 | } 98 | 99 | function pascalCase(name: string) { 100 | return name 101 | .split(/\s+/g) 102 | .filter((_) => _ !== "") 103 | .map(capitalize) 104 | .reduce((a, b) => a + b, ""); 105 | } 106 | 107 | function capitalize(name: string) { 108 | return name.charAt(0).toUpperCase() + name.slice(1); 109 | } 110 | 111 | function normalizeInvalidTypeName(name: string): string { 112 | if (/^[a-zA-Z][a-zA-Z0-9]*$/.test(name)) { 113 | return name; 114 | } else { 115 | const noSymbolsName = name.replace(/[^a-zA-Z0-9]/g, ""); 116 | const startsWithWordCharacter = /^[a-zA-Z]/.test(noSymbolsName); 117 | return startsWithWordCharacter ? noSymbolsName : `_${noSymbolsName}`; 118 | } 119 | } 120 | 121 | function uniqueByIncrement(name: string, names: string[]): string { 122 | for (let i = 0; i < 1000; i++) { 123 | const nameProposal = i === 0 ? name : `${name}${i + 1}`; 124 | if (!names.includes(nameProposal)) { 125 | return nameProposal; 126 | } 127 | } 128 | } 129 | 130 | function getArrayName(typeDesc: TypeDescription, types: TypeDescription[], nameMap: NameEntry[]): string { 131 | if (typeDesc.arrayOfTypes.length === 0) { 132 | return "any"; 133 | } else if (typeDesc.arrayOfTypes.length === 1) { 134 | const [idOrPrimitive] = typeDesc.arrayOfTypes; 135 | return convertToReadableType(idOrPrimitive, types, nameMap); 136 | } else { 137 | return unionToString(typeDesc, types, nameMap); 138 | } 139 | } 140 | 141 | function convertToReadableType(idOrPrimitive: string, types: TypeDescription[], nameMap: NameEntry[]): string { 142 | return isHash(idOrPrimitive) 143 | ? // array keyName makes no difference in picking name for type 144 | getNameById(idOrPrimitive, null, true, types, nameMap) 145 | : idOrPrimitive; 146 | } 147 | 148 | function unionToString(typeDesc: TypeDescription, types: TypeDescription[], nameMap: NameEntry[]): string { 149 | return typeDesc.arrayOfTypes.reduce((acc, type, i) => { 150 | const readableTypeName = convertToReadableType(type, types, nameMap); 151 | return i === 0 ? readableTypeName : `${acc} | ${readableTypeName}`; 152 | }, ""); 153 | } 154 | 155 | function formatArrayName(typeDesc: TypeDescription, types: TypeDescription[], nameMap: NameEntry[]): string { 156 | const innerTypeId = typeDesc.arrayOfTypes[0]; 157 | // const isMultipleTypeArray = findTypeById(innerTypeId, types).arrayOfTypes.length > 1 158 | const isMultipleTypeArray = 159 | isHash(innerTypeId) && 160 | findTypeById(innerTypeId, types).isUnion && 161 | findTypeById(innerTypeId, types).arrayOfTypes.length > 1; 162 | 163 | const readableInnerType = getArrayName(typeDesc, types, nameMap); 164 | 165 | return isMultipleTypeArray 166 | ? `(${readableInnerType})[]` // add semicolons for union type 167 | : `${readableInnerType}[]`; 168 | } 169 | -------------------------------------------------------------------------------- /src/get-type-structure.ts: -------------------------------------------------------------------------------- 1 | import * as hash from "hash.js"; 2 | 3 | import { TypeDescription, TypeStructure } from "./model"; 4 | import { isHash, getTypeDescriptionGroup, findTypeById, isArray, isObject, onlyUnique, isDate } from "./util"; 5 | import { TypeGroup } from "./model"; 6 | 7 | function createTypeDescription(typeObj: any | string[], isUnion: boolean): TypeDescription { 8 | if (isArray(typeObj)) { 9 | return { 10 | id: Hash(JSON.stringify([...typeObj, isUnion])), 11 | arrayOfTypes: typeObj, 12 | isUnion, 13 | }; 14 | } else { 15 | return { 16 | id: Hash(JSON.stringify(typeObj)), 17 | typeObj, 18 | }; 19 | } 20 | } 21 | 22 | function getIdByType(typeObj: any | string[], types: TypeDescription[], isUnion: boolean = false): string { 23 | let typeDesc = types.find((el) => { 24 | return typeObjectMatchesTypeDesc(typeObj, el, isUnion); 25 | }); 26 | 27 | if (!typeDesc) { 28 | typeDesc = createTypeDescription(typeObj, isUnion); 29 | types.push(typeDesc); 30 | } 31 | 32 | return typeDesc.id; 33 | } 34 | 35 | function Hash(content: string): string { 36 | return (hash as any).sha1().update(content).digest("hex"); 37 | } 38 | 39 | function typeObjectMatchesTypeDesc(typeObj: any | string[], typeDesc: TypeDescription, isUnion): boolean { 40 | if (isArray(typeObj)) { 41 | return arraysContainSameElements(typeObj, typeDesc.arrayOfTypes) && typeDesc.isUnion === isUnion; 42 | } else { 43 | return objectsHaveSameEntries(typeObj, typeDesc.typeObj); 44 | } 45 | } 46 | 47 | function arraysContainSameElements(arr1: any[], arr2: any[]): boolean { 48 | if (arr1 === undefined || arr2 === undefined) return false; 49 | 50 | return arr1.sort().join("") === arr2.sort().join(""); 51 | } 52 | 53 | function objectsHaveSameEntries(obj1: any, obj2: any): boolean { 54 | if (obj1 === undefined || obj2 === undefined) return false; 55 | 56 | const entries1 = Object.entries(obj1); 57 | const entries2 = Object.entries(obj2); 58 | 59 | const sameLength = entries1.length === entries2.length; 60 | 61 | const sameTypes = entries1.every(([key, value]) => { 62 | return obj2[key] === value; 63 | }); 64 | 65 | return sameLength && sameTypes; 66 | } 67 | 68 | function getSimpleTypeName(value: any): string { 69 | if (value === null) { 70 | return "null"; 71 | } else if (value instanceof Date) { 72 | return "Date"; 73 | } else { 74 | return typeof value; 75 | } 76 | } 77 | 78 | function getTypeGroup(value: any): TypeGroup { 79 | if (isDate(value)) { 80 | return TypeGroup.Date; 81 | } else if (isArray(value)) { 82 | return TypeGroup.Array; 83 | } else if (isObject(value)) { 84 | return TypeGroup.Object; 85 | } else { 86 | return TypeGroup.Primitive; 87 | } 88 | } 89 | 90 | function createTypeObject(obj: any, types: TypeDescription[]): any { 91 | return Object.entries(obj).reduce((typeObj, [key, value]) => { 92 | const { rootTypeId } = getTypeStructure(value, types); 93 | 94 | return { 95 | ...typeObj, 96 | [key]: rootTypeId, 97 | }; 98 | }, {}); 99 | } 100 | 101 | function getMergedObjects(typesOfArray: TypeDescription[], types: TypeDescription[]): string { 102 | const typeObjects = typesOfArray.map((typeDesc) => typeDesc.typeObj); 103 | 104 | const allKeys = typeObjects 105 | .map((typeObj) => Object.keys(typeObj)) 106 | .reduce((a, b) => [...a, ...b], []) 107 | .filter(onlyUnique); 108 | 109 | const commonKeys = typeObjects.reduce((commonKeys: string[], typeObj) => { 110 | const keys = Object.keys(typeObj); 111 | return commonKeys.filter((key) => keys.includes(key)); 112 | }, allKeys) as string[]; 113 | 114 | const getKeyType = (key) => { 115 | const typesOfKey = typeObjects 116 | .filter((typeObj) => { 117 | return Object.keys(typeObj).includes(key); 118 | }) 119 | .map((typeObj) => typeObj[key]) 120 | .filter(onlyUnique); 121 | 122 | if (typesOfKey.length === 1) { 123 | return typesOfKey.pop(); 124 | } else { 125 | return getInnerArrayType(typesOfKey, types); 126 | } 127 | }; 128 | 129 | const typeObj = allKeys.reduce((obj: object, key: string) => { 130 | const isMandatory = commonKeys.includes(key); 131 | const type = getKeyType(key); 132 | 133 | const keyValue = isMandatory ? key : toOptionalKey(key); 134 | 135 | return { 136 | ...obj, 137 | [keyValue]: type, 138 | }; 139 | }, {}); 140 | return getIdByType(typeObj, types, true); 141 | } 142 | 143 | function toOptionalKey(key: string): string { 144 | return key.endsWith("--?") ? key : `${key}--?`; 145 | } 146 | 147 | function getMergedArrays(typesOfArray: TypeDescription[], types: TypeDescription[]): string { 148 | const idsOfArrayTypes = typesOfArray 149 | .map((typeDesc) => typeDesc.arrayOfTypes) 150 | .reduce((a, b) => [...a, ...b], []) 151 | .filter(onlyUnique); 152 | 153 | if (idsOfArrayTypes.length === 1) { 154 | return getIdByType([idsOfArrayTypes.pop()], types); 155 | } else { 156 | return getIdByType([getInnerArrayType(idsOfArrayTypes, types)], types); 157 | } 158 | } 159 | 160 | // we merge union types example: (number | string), null -> (number | string | null) 161 | function getMergedUnion(typesOfArray: string[], types: TypeDescription[]): string { 162 | const innerUnionsTypes = typesOfArray 163 | .map((id) => { 164 | return findTypeById(id, types); 165 | }) 166 | .filter((_) => !!_ && _.isUnion) 167 | .map((_) => _.arrayOfTypes) 168 | .reduce((a, b) => [...a, ...b], []); 169 | 170 | const primitiveTypes = typesOfArray.filter((id) => !findTypeById(id, types) || !findTypeById(id, types).isUnion); // primitives or not union 171 | return getIdByType([...innerUnionsTypes, ...primitiveTypes], types, true); 172 | } 173 | 174 | function getInnerArrayType(typesOfArray: string[], types: TypeDescription[]): string { 175 | // return inner array type 176 | 177 | const containsUndefined = typesOfArray.includes("undefined"); 178 | 179 | const arrayTypesDescriptions = typesOfArray.map((id) => findTypeById(id, types)).filter((_) => !!_); 180 | 181 | const allArrayType = 182 | arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc) === TypeGroup.Array).length === 183 | typesOfArray.length; 184 | 185 | const allArrayTypeWithUndefined = 186 | arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc) === TypeGroup.Array).length + 1 === 187 | typesOfArray.length && containsUndefined; 188 | 189 | const allObjectTypeWithUndefined = 190 | arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc) === TypeGroup.Object).length + 1 === 191 | typesOfArray.length && containsUndefined; 192 | 193 | const allObjectType = 194 | arrayTypesDescriptions.filter((typeDesc) => getTypeDescriptionGroup(typeDesc) === TypeGroup.Object).length === 195 | typesOfArray.length; 196 | 197 | if (typesOfArray.length === 0) { 198 | // no types in array -> empty union type 199 | return getIdByType([], types, true); 200 | } 201 | 202 | if (typesOfArray.length === 1) { 203 | // one type in array -> that will be our inner type 204 | return typesOfArray.pop(); 205 | } 206 | 207 | if (typesOfArray.length > 1) { 208 | // multiple types in merge array 209 | // if all are object we can merge them and return merged object as inner type 210 | if (allObjectType) return getMergedObjects(arrayTypesDescriptions, types); 211 | // if all are array we can merge them and return merged array as inner type 212 | if (allArrayType) return getMergedArrays(arrayTypesDescriptions, types); 213 | 214 | // all array types with posibble undefined, result type = undefined | (*mergedArray*)[] 215 | if (allArrayTypeWithUndefined) { 216 | return getMergedUnion([getMergedArrays(arrayTypesDescriptions, types), "undefined"], types); 217 | } 218 | 219 | // all object types with posibble undefined, result type = undefined | *mergedObject* 220 | if (allObjectTypeWithUndefined) { 221 | return getMergedUnion([getMergedObjects(arrayTypesDescriptions, types), "undefined"], types); 222 | } 223 | 224 | // if they are mixed or all primitive we cant merge them so we return as mixed union type 225 | return getMergedUnion(typesOfArray, types); 226 | } 227 | } 228 | 229 | export function getTypeStructure( 230 | targetObj: any, // object that we want to create types for 231 | types: TypeDescription[] = [] 232 | ): TypeStructure { 233 | switch (getTypeGroup(targetObj)) { 234 | case TypeGroup.Array: 235 | const typesOfArray = (targetObj).map((_) => getTypeStructure(_, types).rootTypeId).filter(onlyUnique); 236 | const arrayInnerTypeId = getInnerArrayType(typesOfArray, types); // create "union type of array types" 237 | const typeId = getIdByType([arrayInnerTypeId], types); // create type "array of union type" 238 | 239 | return { 240 | rootTypeId: typeId, 241 | types, 242 | }; 243 | 244 | case TypeGroup.Object: 245 | const typeObj = createTypeObject(targetObj, types); 246 | const objType = getIdByType(typeObj, types); 247 | 248 | return { 249 | rootTypeId: objType, 250 | types, 251 | }; 252 | 253 | case TypeGroup.Primitive: 254 | return { 255 | rootTypeId: getSimpleTypeName(targetObj), 256 | types, 257 | }; 258 | 259 | case TypeGroup.Date: 260 | const dateType = getSimpleTypeName(targetObj); 261 | 262 | return { 263 | rootTypeId: dateType, 264 | types, 265 | }; 266 | } 267 | } 268 | 269 | function getAllUsedTypeIds({ rootTypeId, types }: TypeStructure): string[] { 270 | const typeDesc = types.find((_) => _.id === rootTypeId); 271 | 272 | const subTypes = (typeDesc: TypeDescription) => { 273 | switch (getTypeDescriptionGroup(typeDesc)) { 274 | case TypeGroup.Array: 275 | const arrSubTypes = typeDesc.arrayOfTypes 276 | .filter(isHash) 277 | .map((typeId) => { 278 | const typeDesc = types.find((_) => _.id === typeId); 279 | return subTypes(typeDesc); 280 | }) 281 | .reduce((a, b) => [...a, ...b], []); 282 | return [typeDesc.id, ...arrSubTypes]; 283 | 284 | case TypeGroup.Object: 285 | const objSubTypes = Object.values(typeDesc.typeObj) 286 | .filter(isHash) 287 | .map((typeId) => { 288 | const typeDesc = types.find((_) => _.id === typeId); 289 | return subTypes(typeDesc); 290 | }) 291 | .reduce((a, b) => [...a, ...b], []); 292 | return [typeDesc.id, ...objSubTypes]; 293 | } 294 | }; 295 | 296 | return subTypes(typeDesc); 297 | } 298 | 299 | export function optimizeTypeStructure(typeStructure: TypeStructure) { 300 | const usedTypeIds = getAllUsedTypeIds(typeStructure); 301 | 302 | const optimizedTypes = typeStructure.types.filter((typeDesc) => usedTypeIds.includes(typeDesc.id)); 303 | 304 | typeStructure.types = optimizedTypes; 305 | } 306 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { getTypeStructure, optimizeTypeStructure } from "./get-type-structure"; 2 | import { Options } from "./model"; 3 | import { shim } from "es7-shim/es7-shim"; 4 | import { getInterfaceDescriptions, getInterfaceStringFromDescription } from "./get-interfaces"; 5 | import { getNames } from "./get-names"; 6 | import { isArray, isObject } from "./util"; 7 | shim(); 8 | 9 | export default function JsonToTS(json: any, userOptions?: Options): string[] { 10 | const defaultOptions: Options = { 11 | rootName: "RootObject", 12 | }; 13 | const options = { 14 | ...defaultOptions, 15 | ...userOptions, 16 | }; 17 | 18 | /** 19 | * Parsing currently works with (Objects) and (Array of Objects) not and primitive types and mixed arrays etc.. 20 | * so we shall validate, so we dont start parsing non Object type 21 | */ 22 | const isArrayOfObjects = isArray(json) && json.length > 0 && json.reduce((a, b) => a && isObject(b), true); 23 | 24 | if (!(isObject(json) || isArrayOfObjects)) { 25 | throw new Error("Only (Object) and (Array of Object) are supported"); 26 | } 27 | 28 | const typeStructure = getTypeStructure(json); 29 | /** 30 | * due to merging array types some types are switched out for merged ones 31 | * so we delete the unused ones here 32 | */ 33 | optimizeTypeStructure(typeStructure); 34 | 35 | const names = getNames(typeStructure, options.rootName); 36 | 37 | return getInterfaceDescriptions(typeStructure, names).map((description) => 38 | getInterfaceStringFromDescription({ ...description, useTypeAlias: options.useTypeAlias }) 39 | ); 40 | } 41 | 42 | (JsonToTS).default = JsonToTS; 43 | module.exports = JsonToTS; 44 | -------------------------------------------------------------------------------- /src/model.ts: -------------------------------------------------------------------------------- 1 | export enum TypeGroup { 2 | Primitive, 3 | Array, 4 | Object, 5 | Date, 6 | } 7 | 8 | export interface TypeDescription { 9 | id: string; 10 | isUnion?: boolean; 11 | typeObj?: { [index: string]: string }; 12 | arrayOfTypes?: string[]; 13 | } 14 | 15 | export interface TypeStructure { 16 | rootTypeId: string; 17 | types: TypeDescription[]; 18 | } 19 | 20 | export interface NameEntry { 21 | id: string; 22 | name: string; 23 | } 24 | 25 | export interface NameStructure { 26 | rootName: string; 27 | names: NameEntry[]; 28 | } 29 | 30 | export interface InterfaceDescription { 31 | name: string; 32 | typeMap: object; 33 | } 34 | 35 | export interface Options { 36 | rootName?: string; 37 | /** To generate using type alias instead of interface */ 38 | useTypeAlias?: boolean; 39 | } 40 | 41 | export interface KeyMetaData { 42 | keyValue: string; 43 | isOptional: boolean; 44 | } 45 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import { KeyMetaData, TypeGroup, TypeDescription } from "./model"; 2 | 3 | export function isHash(str: string) { 4 | return str.length === 40; 5 | } 6 | 7 | export function onlyUnique(value, index, self) { 8 | return self.indexOf(value) === index; 9 | } 10 | 11 | export function isArray(x) { 12 | return Object.prototype.toString.call(x) === "[object Array]"; 13 | } 14 | 15 | export function isNonArrayUnion(typeName: string) { 16 | const arrayUnionRegex = /^\(.*\)\[\]$/; 17 | 18 | return typeName.includes(" | ") && !arrayUnionRegex.test(typeName); 19 | } 20 | 21 | export function isObject(x) { 22 | return Object.prototype.toString.call(x) === "[object Object]" && x !== null; 23 | } 24 | 25 | export function isDate(x) { 26 | return x instanceof Date; 27 | } 28 | 29 | export function parseKeyMetaData(key: string): KeyMetaData { 30 | const isOptional = key.endsWith("--?"); 31 | 32 | if (isOptional) { 33 | return { 34 | isOptional, 35 | keyValue: key.slice(0, -3) 36 | }; 37 | } else { 38 | return { 39 | isOptional, 40 | keyValue: key 41 | }; 42 | } 43 | } 44 | 45 | export function getTypeDescriptionGroup(desc: TypeDescription): TypeGroup { 46 | if (desc === undefined) { 47 | return TypeGroup.Primitive; 48 | } else if (desc.arrayOfTypes !== undefined) { 49 | return TypeGroup.Array; 50 | } else { 51 | return TypeGroup.Object; 52 | } 53 | } 54 | 55 | export function findTypeById(id: string, types: TypeDescription[]): TypeDescription { 56 | return types.find(_ => _.id === id); 57 | } 58 | -------------------------------------------------------------------------------- /test/array-merging.spec.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { removeWhiteSpace } from "./util/index"; 3 | import JsonToTS from "../src/index"; 4 | 5 | describe("Array type merging", function () { 6 | it("should work with arrays with same inner types", function () { 7 | const json = { 8 | cats: [{ name: "Kittin" }, { name: "Sparkles" }], 9 | }; 10 | 11 | const expectedTypes = [ 12 | `interface RootObject { 13 | cats: Cat[]; 14 | }`, 15 | `interface Cat { 16 | name: string; 17 | }`, 18 | ].map(removeWhiteSpace); 19 | 20 | const interfaces = JsonToTS(json); 21 | 22 | interfaces.forEach((i) => { 23 | const noWhiteSpaceInterface = removeWhiteSpace(i); 24 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 25 | }); 26 | 27 | assert.strictEqual(interfaces.length, 2); 28 | }); 29 | 30 | it("union undefined type should be emited and field should be marked as optional", function () { 31 | const json = [{ age: 42 }, { age: undefined }]; 32 | 33 | const expectedTypes = [ 34 | `interface RootObject { 35 | age?: number; 36 | }`, 37 | ].map(removeWhiteSpace); 38 | 39 | const interfaces = JsonToTS(json); 40 | 41 | interfaces.forEach((i) => { 42 | const noWhiteSpaceInterface = removeWhiteSpace(i); 43 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 44 | }); 45 | 46 | assert.strictEqual(interfaces.length, 1); 47 | }); 48 | it("union null type should be emited and field should be marked as optional", function () { 49 | const json = [{ age: 42 }, { age: null }]; 50 | 51 | const expectedTypes = [ 52 | `interface RootObject { 53 | age: null | number; 54 | }`, 55 | ].map(removeWhiteSpace); 56 | 57 | const interfaces = JsonToTS(json); 58 | 59 | interfaces.forEach((i) => { 60 | const noWhiteSpaceInterface = removeWhiteSpace(i); 61 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 62 | }); 63 | 64 | assert.strictEqual(interfaces.length, 1); 65 | }); 66 | 67 | it("null should stay if it is part of array elements", function () { 68 | const json = { 69 | arr: [42, "42", null], 70 | }; 71 | 72 | const expectedTypes = [ 73 | `interface RootObject { 74 | arr: (null | number | string)[]; 75 | }`, 76 | ].map(removeWhiteSpace); 77 | 78 | const interfaces = JsonToTS(json); 79 | 80 | interfaces.forEach((i) => { 81 | const noWhiteSpaceInterface = removeWhiteSpace(i); 82 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 83 | }); 84 | 85 | assert.strictEqual(interfaces.length, 1); 86 | }); 87 | 88 | it("array types should be merge even if they are undefined", function () { 89 | const json = [ 90 | { 91 | field: ["string"], 92 | }, 93 | { 94 | field: [42], 95 | }, 96 | { 97 | field: [null], 98 | }, 99 | { 100 | field: undefined, 101 | }, 102 | { 103 | field: [new Date()], 104 | }, 105 | ]; 106 | 107 | const expectedTypes = [ 108 | `interface RootObject { 109 | field?:(Date|null|number|string)[]; 110 | }`, 111 | ].map(removeWhiteSpace); 112 | 113 | const interfaces = JsonToTS(json); 114 | 115 | interfaces.forEach((i) => { 116 | const noWhiteSpaceInterface = removeWhiteSpace(i); 117 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 118 | }); 119 | 120 | assert.strictEqual(interfaces.length, 1); 121 | }); 122 | 123 | it("object types should be merge even if they are undefined", function () { 124 | const json = [ 125 | { 126 | field: { tag: "world" }, 127 | }, 128 | { 129 | field: { tag: 42 }, 130 | }, 131 | { 132 | field: undefined, 133 | }, 134 | ]; 135 | 136 | const expectedTypes = [ 137 | `interface RootObject { 138 | field?: Field; 139 | }`, 140 | `interface Field { 141 | tag: number | string; 142 | }`, 143 | ].map(removeWhiteSpace); 144 | 145 | const interfaces = JsonToTS(json); 146 | interfaces.forEach((i) => { 147 | const noWhiteSpaceInterface = removeWhiteSpace(i); 148 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 149 | }); 150 | 151 | assert.strictEqual(interfaces.length, 2); 152 | }); 153 | 154 | it("should work with arrays with inner types that has optinal field", function () { 155 | const json = { 156 | cats: [{ name: "Kittin" }, { name: "Sparkles", age: 20 }], 157 | }; 158 | 159 | const expectedTypes = [ 160 | `interface RootObject { 161 | cats: Cat[]; 162 | }`, 163 | `interface Cat { 164 | name: string; 165 | age?: number; 166 | }`, 167 | ].map(removeWhiteSpace); 168 | 169 | const interfaces = JsonToTS(json); 170 | 171 | interfaces.forEach((i) => { 172 | const noWhiteSpaceInterface = removeWhiteSpace(i); 173 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 174 | }); 175 | 176 | assert.strictEqual(interfaces.length, 2); 177 | }); 178 | 179 | it("should work with arrays with inner types that has no common fields", function () { 180 | const json = { 181 | cats: [{ name: "Kittin" }, { age: 20 }], 182 | }; 183 | 184 | const expectedTypes = [ 185 | `interface RootObject { 186 | cats: Cat[]; 187 | }`, 188 | `interface Cat { 189 | name?: string; 190 | age?: number; 191 | }`, 192 | ].map(removeWhiteSpace); 193 | 194 | const interfaces = JsonToTS(json); 195 | 196 | interfaces.forEach((i) => { 197 | const noWhiteSpaceInterface = removeWhiteSpace(i); 198 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 199 | }); 200 | 201 | assert.strictEqual(interfaces.length, 2); 202 | }); 203 | 204 | it("should work with arrays with inner types that have common field that has different types", function () { 205 | const json = { 206 | cats: [{ age: "20" }, { age: 20 }], 207 | }; 208 | 209 | const expectedTypes = [ 210 | `interface RootObject { 211 | cats: Cat[]; 212 | }`, 213 | `interface Cat { 214 | age: number | string; 215 | }`, 216 | ].map(removeWhiteSpace); 217 | 218 | const interfaces = JsonToTS(json); 219 | 220 | interfaces.forEach((i) => { 221 | const noWhiteSpaceInterface = removeWhiteSpace(i); 222 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 223 | }); 224 | 225 | assert.strictEqual(interfaces.length, 2); 226 | }); 227 | 228 | it("should solve edge case 1", function () { 229 | const json = { 230 | cats: [{ age: [42] }, { age: ["42"] }], 231 | dads: ["hello", 42], 232 | }; 233 | 234 | const expectedTypes = [ 235 | `interface RootObject { 236 | cats: Cat[]; 237 | dads: (number | string)[]; 238 | }`, 239 | `interface Cat { 240 | age: (number | string)[]; 241 | }`, 242 | ].map(removeWhiteSpace); 243 | 244 | const interfaces = JsonToTS(json); 245 | 246 | interfaces.forEach((i) => { 247 | const noWhiteSpaceInterface = removeWhiteSpace(i); 248 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 249 | }); 250 | 251 | assert.strictEqual(interfaces.length, 2); 252 | }); 253 | 254 | it("should solve edge case 2", function () { 255 | const json = { 256 | items: [ 257 | { 258 | billables: [ 259 | { 260 | quantity: 2, 261 | price: 0, 262 | }, 263 | ], 264 | }, 265 | { 266 | billables: [ 267 | { 268 | priceCategory: { 269 | title: "Adult", 270 | minAge: 0, 271 | maxAge: 99, 272 | }, 273 | quantity: 2, 274 | price: 226, 275 | }, 276 | ], 277 | }, 278 | ], 279 | }; 280 | 281 | const expectedTypes = [ 282 | `interface RootObject { 283 | items: Item[]; 284 | }`, 285 | `interface Item { 286 | billables: Billable[]; 287 | }`, 288 | `interface Billable { 289 | quantity: number; 290 | price: number; 291 | priceCategory?: PriceCategory; 292 | }`, 293 | `interface PriceCategory { 294 | title: string; 295 | minAge: number; 296 | maxAge: number; 297 | }`, 298 | ].map(removeWhiteSpace); 299 | 300 | const interfaces = JsonToTS(json); 301 | 302 | interfaces.forEach((i) => { 303 | const noWhiteSpaceInterface = removeWhiteSpace(i); 304 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 305 | }); 306 | 307 | assert.strictEqual(interfaces.length, 4); 308 | }); 309 | 310 | it("should solve edge case 3", function () { 311 | const json = [ 312 | { 313 | nestedElements: [ 314 | { 315 | commonField: 42, 316 | optionalField: "field", 317 | }, 318 | { 319 | commonField: 42, 320 | optionalField3: "field3", 321 | }, 322 | ], 323 | }, 324 | { 325 | nestedElements: [ 326 | { 327 | commonField: "42", 328 | optionalField2: "field2", 329 | }, 330 | ], 331 | }, 332 | ]; 333 | 334 | const expectedTypes = [ 335 | `interface RootObject { 336 | nestedElements: NestedElement[]; 337 | }`, 338 | `interface NestedElement { 339 | commonField: number | string; 340 | optionalField?: string; 341 | optionalField3?: string; 342 | optionalField2?: string; 343 | }`, 344 | ].map(removeWhiteSpace); 345 | 346 | const interfaces = JsonToTS(json); 347 | 348 | interfaces.forEach((i) => { 349 | const noWhiteSpaceInterface = removeWhiteSpace(i); 350 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 351 | }); 352 | 353 | assert.strictEqual(interfaces.length, 2); 354 | }); 355 | 356 | it("should merge empty array with primitive types", function () { 357 | const json = [ 358 | { 359 | nestedElements: [], 360 | }, 361 | { 362 | nestedElements: ["kittin"], 363 | }, 364 | ]; 365 | 366 | const expectedTypes = [ 367 | `interface RootObject { 368 | nestedElements: string[]; 369 | }`, 370 | ].map(removeWhiteSpace); 371 | 372 | const interfaces = JsonToTS(json); 373 | 374 | interfaces.forEach((i) => { 375 | const noWhiteSpaceInterface = removeWhiteSpace(i); 376 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 377 | }); 378 | 379 | assert.strictEqual(interfaces.length, 1); 380 | }); 381 | 382 | it("should merge empty array with object types", function () { 383 | const json = [ 384 | { 385 | nestedElements: [], 386 | }, 387 | { 388 | nestedElements: [{ name: "kittin" }], 389 | }, 390 | ]; 391 | 392 | const expectedTypes = [ 393 | `interface RootObject { 394 | nestedElements: NestedElement[]; 395 | }`, 396 | `interface NestedElement { 397 | name: string; 398 | }`, 399 | ].map(removeWhiteSpace); 400 | 401 | const interfaces = JsonToTS(json); 402 | 403 | interfaces.forEach((i) => { 404 | const noWhiteSpaceInterface = removeWhiteSpace(i); 405 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 406 | }); 407 | 408 | assert.strictEqual(interfaces.length, 2); 409 | }); 410 | 411 | it("should merge empty array with array types", function () { 412 | const json = [ 413 | { 414 | nestedElements: [], 415 | }, 416 | { 417 | nestedElements: [["string"]], 418 | }, 419 | ]; 420 | 421 | const expectedTypes = [ 422 | `interface RootObject { 423 | nestedElements: string[][]; 424 | }`, 425 | ].map(removeWhiteSpace); 426 | 427 | const interfaces = JsonToTS(json); 428 | 429 | interfaces.forEach((i) => { 430 | const noWhiteSpaceInterface = removeWhiteSpace(i); 431 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 432 | }); 433 | 434 | assert.strictEqual(interfaces.length, 1); 435 | }); 436 | 437 | it("should merge union types with readable names ", function () { 438 | const json = [ 439 | { 440 | marius: "marius", 441 | }, 442 | { 443 | marius: [42], 444 | }, 445 | ]; 446 | 447 | const expectedTypes = [ 448 | `interface RootObject { 449 | marius: number[] | string; 450 | }`, 451 | ].map(removeWhiteSpace); 452 | 453 | const interfaces = JsonToTS(json); 454 | 455 | interfaces.forEach((i) => { 456 | const noWhiteSpaceInterface = removeWhiteSpace(i); 457 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 458 | }); 459 | 460 | assert.strictEqual(interfaces.length, 1); 461 | }); 462 | }); 463 | -------------------------------------------------------------------------------- /test/js-integration/index.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert') 2 | 3 | describe("Javascript integration", function () { 4 | 5 | it("should work with default require statement", function () { 6 | const JsonToTS = require('../../build/src/index') 7 | 8 | const expected = ` 9 | interface RootObject { 10 | cats: Cat[]; 11 | favoriteNumber: number; 12 | favoriteWord: string; 13 | } 14 | interface Cat { 15 | name: string; 16 | }` 17 | 18 | const json = { 19 | cats: [ 20 | {name: 'Kittin'}, 21 | {name: 'Mittin'}, 22 | ], 23 | favoriteNumber: 42, 24 | favoriteWord: 'Hello' 25 | } 26 | 27 | const output = JsonToTS(json) 28 | .reduce((type1, type2) => { 29 | return `${type1}\n${type2}` 30 | }) 31 | .trim() 32 | 33 | assert.strictEqual(output, expected.trim()) 34 | }) 35 | 36 | }) 37 | -------------------------------------------------------------------------------- /test/multiple-interface.spec.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { removeWhiteSpace } from "./util/index"; 3 | import JsonToTS from "../src/index"; 4 | 5 | describe("Multiple interfaces", function () { 6 | it("should create separate interface for nested objects", function () { 7 | const json = { 8 | a: { 9 | b: 42, 10 | }, 11 | }; 12 | 13 | const expectedTypes = [ 14 | `interface RootObject { 15 | a: A; 16 | }`, 17 | `interface A { 18 | b: number; 19 | }`, 20 | ].map(removeWhiteSpace); 21 | 22 | JsonToTS(json).forEach((i) => { 23 | const noWhiteSpaceInterface = removeWhiteSpace(i); 24 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 25 | }); 26 | }); 27 | 28 | it("should not create duplicate on same type object fields", function () { 29 | const json = { 30 | a: { 31 | b: 42, 32 | }, 33 | c: { 34 | b: 24, 35 | }, 36 | }; 37 | 38 | const expectedTypes = [ 39 | `interface RootObject { 40 | a: A; 41 | c: A; 42 | }`, 43 | `interface A { 44 | b: number; 45 | }`, 46 | ].map(removeWhiteSpace); 47 | 48 | const interfaces = JsonToTS(json); 49 | interfaces.forEach((i) => { 50 | const noWhiteSpaceInterface = removeWhiteSpace(i); 51 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 52 | }); 53 | 54 | assert(interfaces.length === 2); 55 | }); 56 | 57 | it("should have multi keyword interfaces created without space", function () { 58 | const json = { 59 | "hello world": { 60 | b: 42, 61 | }, 62 | }; 63 | 64 | const expectedTypes = [ 65 | `interface RootObject { 66 | 'hello world': HelloWorld; 67 | }`, 68 | `interface HelloWorld { 69 | b: number; 70 | }`, 71 | ].map((_) => _.trim()); 72 | 73 | const interfaces = JsonToTS(json); 74 | interfaces.forEach((typeInterface) => { 75 | assert(expectedTypes.includes(typeInterface)); 76 | }); 77 | }); 78 | 79 | it("should have unique names for nested objects since they ", function () { 80 | const json = { 81 | name: "Larry", 82 | parent: { 83 | name: "Garry", 84 | parent: { 85 | name: "Marry", 86 | parent: undefined, 87 | }, 88 | }, 89 | }; 90 | 91 | const expectedTypes = [ 92 | `interface RootObject { 93 | name: string; 94 | parent: Parent2; 95 | }`, 96 | `interface Parent { 97 | name: string; 98 | parent?: any; 99 | }`, 100 | `interface Parent2 { 101 | name: string; 102 | parent: Parent; 103 | }`, 104 | ].map(removeWhiteSpace); 105 | 106 | const interfaces = JsonToTS(json); 107 | interfaces.forEach((i) => { 108 | const noWhiteSpaceInterface = removeWhiteSpace(i); 109 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 110 | }); 111 | }); 112 | 113 | it("should support multi nested arrays", function () { 114 | const json = { 115 | cats: [ 116 | [{ name: "Kittin" }, { name: "Kittin" }, { name: "Kittin" }], 117 | [{ name: "Kittin" }, { name: "Kittin" }, { name: "Kittin" }], 118 | ], 119 | }; 120 | 121 | const expectedTypes = [ 122 | `interface RootObject { 123 | cats: Cat[][]; 124 | }`, 125 | `interface Cat { 126 | name: string; 127 | }`, 128 | ].map(removeWhiteSpace); 129 | 130 | JsonToTS(json).forEach((i) => { 131 | const noWhiteSpaceInterface = removeWhiteSpace(i); 132 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 133 | }); 134 | }); 135 | 136 | it("should singularize array types (dogs: [...] => dogs: Dog[] )", function () { 137 | const json = { 138 | dogs: [{ name: "sparky" }, { name: "goodboi" }], 139 | }; 140 | 141 | const expectedTypes = [ 142 | `interface RootObject { 143 | dogs: Dog[]; 144 | }`, 145 | `interface Dog { 146 | name: string; 147 | }`, 148 | ].map(removeWhiteSpace); 149 | 150 | const interfaces = JsonToTS(json); 151 | interfaces.forEach((i) => { 152 | const noWhiteSpaceInterface = removeWhiteSpace(i); 153 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 154 | }); 155 | }); 156 | 157 | it("should not singularize if not array type (dogs: {} => dogs: Dogs )", function () { 158 | const json = { 159 | cats: { 160 | popularity: "very popular", 161 | }, 162 | }; 163 | 164 | const expectedTypes = [ 165 | `interface RootObject { 166 | cats: Cats; 167 | }`, 168 | `interface Cats { 169 | popularity: string; 170 | }`, 171 | ].map(removeWhiteSpace); 172 | 173 | const interfaces = JsonToTS(json); 174 | interfaces.forEach((i) => { 175 | const noWhiteSpaceInterface = removeWhiteSpace(i); 176 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 177 | }); 178 | }); 179 | 180 | it("should capitalize interface names", function () { 181 | const json = { 182 | cat: {}, 183 | }; 184 | 185 | const expectedTypes = [ 186 | `interface RootObject { 187 | cat: Cat; 188 | }`, 189 | `interface Cat { 190 | }`, 191 | ].map(removeWhiteSpace); 192 | 193 | const interfaces = JsonToTS(json); 194 | interfaces.forEach((i) => { 195 | const noWhiteSpaceInterface = removeWhiteSpace(i); 196 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 197 | }); 198 | }); 199 | 200 | it("should start unique names increment with 2", function () { 201 | const json = { 202 | a: { 203 | human: { legs: 4 }, 204 | }, 205 | b: { 206 | human: { arms: 2 }, 207 | }, 208 | }; 209 | 210 | const expectedTypes = [ 211 | `interface RootObject { 212 | a: A; 213 | b: B; 214 | }`, 215 | `interface A { 216 | human: Human; 217 | }`, 218 | `interface B { 219 | human: Human2; 220 | }`, 221 | `interface Human { 222 | legs: number; 223 | }`, 224 | `interface Human2 { 225 | arms: number; 226 | }`, 227 | ].map(removeWhiteSpace); 228 | 229 | const interfaces = JsonToTS(json); 230 | interfaces.forEach((i) => { 231 | const noWhiteSpaceInterface = removeWhiteSpace(i); 232 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 233 | }); 234 | }); 235 | 236 | it("should normalize invalid interface names 1", function () { 237 | const json = { 238 | "#@#123#@#": { 239 | name: "dummy string", 240 | }, 241 | }; 242 | 243 | const expectedTypes = [ 244 | `interface RootObject { 245 | '#@#123#@#': _123; 246 | }`, 247 | `interface _123 { 248 | name: string; 249 | }`, 250 | ].map(removeWhiteSpace); 251 | 252 | const interfaces = JsonToTS(json); 253 | interfaces.forEach((i) => { 254 | const noWhiteSpaceInterface = removeWhiteSpace(i); 255 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 256 | }); 257 | }); 258 | 259 | it("should normalize invalid interface names 2", function () { 260 | const json = { 261 | "hello#@#123#@#": { 262 | name: "dummy string", 263 | }, 264 | }; 265 | 266 | const expectedTypes = [ 267 | `interface RootObject { 268 | 'hello#@#123#@#': Hello123; 269 | }`, 270 | `interface Hello123 { 271 | name: string; 272 | }`, 273 | ].map(removeWhiteSpace); 274 | 275 | const interfaces = JsonToTS(json); 276 | 277 | interfaces.forEach((i) => { 278 | const noWhiteSpaceInterface = removeWhiteSpace(i); 279 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 280 | }); 281 | }); 282 | 283 | it("should normalize invalid interface names to pascal case", function () { 284 | const json = { 285 | "%#hello#@#123#@#": { 286 | name: "dummy string", 287 | }, 288 | }; 289 | 290 | const expectedTypes = [ 291 | `interface RootObject { 292 | '%#hello#@#123#@#': Hello123; 293 | }`, 294 | `interface Hello123 { 295 | name: string; 296 | }`, 297 | ].map(removeWhiteSpace); 298 | 299 | const interfaces = JsonToTS(json); 300 | 301 | interfaces.forEach((i) => { 302 | const noWhiteSpaceInterface = removeWhiteSpace(i); 303 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 304 | }); 305 | }); 306 | 307 | it("should generate types instead of interfaces when useTypeAlias - option is used", function () { 308 | const json = { 309 | "%#hello#@#123#@#": { 310 | name: "dummy string", 311 | }, 312 | }; 313 | 314 | const expectedTypes = [ 315 | `type RootObject = { 316 | '%#hello#@#123#@#': Hello123; 317 | }`, 318 | `type Hello123 = { 319 | name: string; 320 | }`, 321 | ].map(removeWhiteSpace); 322 | 323 | const interfaces = JsonToTS(json, { useTypeAlias: true }); 324 | 325 | interfaces.forEach((i) => { 326 | const noWhiteSpaceInterface = removeWhiteSpace(i); 327 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 328 | }); 329 | }); 330 | 331 | it("should have question mark after optional invalid interface name", function () { 332 | const json = [{ "hello#123": "sample" }, {}]; 333 | 334 | const expectedTypes = [ 335 | `interface RootObject { 336 | 'hello#123'?: string; 337 | }`, 338 | ].map(removeWhiteSpace); 339 | 340 | const interfaces = JsonToTS(json); 341 | 342 | interfaces.forEach((i) => { 343 | const noWhiteSpaceInterface = removeWhiteSpace(i); 344 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 345 | }); 346 | }); 347 | 348 | it("should have question mark after null value invalid interface name", function () { 349 | const json = { 350 | "hello#123": undefined, 351 | }; 352 | 353 | const expectedTypes = [ 354 | `interface RootObject { 355 | 'hello#123'?: any; 356 | }`, 357 | ].map(removeWhiteSpace); 358 | 359 | const interfaces = JsonToTS(json); 360 | 361 | interfaces.forEach((i) => { 362 | const noWhiteSpaceInterface = removeWhiteSpace(i); 363 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 364 | }); 365 | }); 366 | 367 | it("should have question mark after null value invalid optional interface name", function () { 368 | const json = [{ "hello#123": undefined }, {}]; 369 | 370 | const expectedTypes = [ 371 | `interface RootObject { 372 | 'hello#123'?: any; 373 | }`, 374 | ].map(removeWhiteSpace); 375 | 376 | const interfaces = JsonToTS(json); 377 | 378 | interfaces.forEach((i) => { 379 | const noWhiteSpaceInterface = removeWhiteSpace(i); 380 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 381 | }); 382 | }); 383 | }); 384 | -------------------------------------------------------------------------------- /test/root-array.spec.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { removeWhiteSpace } from "./util/index"; 3 | import JsonToTS from "../src/index"; 4 | 5 | describe("Root array type", function() { 6 | it("should throw error on unsupprted array types", function() { 7 | const unsupportedArrays = [ 8 | ["sample string", "sample string2"], 9 | [42, 32], 10 | [true, false], 11 | [null, null], 12 | [42, "sample string"], 13 | [42, { marius: "marius" }], 14 | [] 15 | ]; 16 | 17 | const expectedMessage = "Only (Object) and (Array of Object) are supported"; 18 | 19 | unsupportedArrays.forEach(arr => { 20 | try { 21 | JsonToTS(arr); 22 | assert(false, "error should be thrown"); 23 | } catch (e) { 24 | assert.strictEqual(e.message, expectedMessage); 25 | if (e.message !== expectedMessage) throw e; 26 | } 27 | }); 28 | }); 29 | 30 | it("should handle array with single object [object]", function() { 31 | const json = [{ marius: "marius" }]; 32 | 33 | const expectedTypes = [ 34 | `interface RootObject { 35 | marius: string; 36 | }` 37 | ].map(removeWhiteSpace); 38 | 39 | const interfaces = JsonToTS(json); 40 | 41 | interfaces.forEach(i => { 42 | const noWhiteSpaceInterface = removeWhiteSpace(i); 43 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 44 | }); 45 | assert.equal(interfaces.length, 1); 46 | }); 47 | 48 | it("should handle array with multiple same objects [object, object]", function() { 49 | const json = [{ marius: "marius" }, { marius: "marius" }]; 50 | 51 | const expectedTypes = [ 52 | `interface RootObject { 53 | marius: string; 54 | }` 55 | ].map(removeWhiteSpace); 56 | 57 | const interfaces = JsonToTS(json); 58 | 59 | interfaces.forEach(i => { 60 | const noWhiteSpaceInterface = removeWhiteSpace(i); 61 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 62 | }); 63 | assert.equal(interfaces.length, 1); 64 | }); 65 | 66 | it("should handle array with multiple different objects [object1, object2]", function() { 67 | const json = [{ marius: "marius" }, { darius: "darius" }]; 68 | 69 | const expectedTypes = [ 70 | `interface RootObject { 71 | marius?: string; 72 | darius?: string; 73 | }` 74 | ].map(removeWhiteSpace); 75 | 76 | const interfaces = JsonToTS(json); 77 | 78 | interfaces.forEach(i => { 79 | const noWhiteSpaceInterface = removeWhiteSpace(i); 80 | assert(expectedTypes.includes(noWhiteSpaceInterface)); 81 | }); 82 | assert.equal(interfaces.length, 1); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/single-interface.spec.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | import { removeWhiteSpace } from "./util/index"; 3 | import JsonToTS from "../src/index"; 4 | 5 | describe("Single interface", function () { 6 | it("should work with empty objects", function () { 7 | const json = {}; 8 | 9 | const expected = ` 10 | interface RootObject { 11 | } 12 | `; 13 | const actual = JsonToTS(json).pop(); 14 | const [a, b] = [expected, actual].map(removeWhiteSpace); 15 | assert.strictEqual(a, b); 16 | }); 17 | 18 | it("should not quote underscore key names", function () { 19 | const json = { 20 | _marius: "marius", 21 | }; 22 | 23 | const expected = ` 24 | interface RootObject { 25 | _marius: string; 26 | } 27 | `; 28 | const actual = JsonToTS(json).pop(); 29 | const [a, b] = [expected, actual].map(removeWhiteSpace); 30 | assert.strictEqual(a, b); 31 | }); 32 | 33 | it("should convert Date to Date type", function () { 34 | const json = { 35 | _marius: new Date(), 36 | }; 37 | 38 | const expected = ` 39 | interface RootObject { 40 | _marius: Date; 41 | } 42 | `; 43 | const actual = JsonToTS(json).pop(); 44 | const [a, b] = [expected, actual].map(removeWhiteSpace); 45 | assert.strictEqual(a, b); 46 | }); 47 | 48 | it("should handle empty string as key", function () { 49 | const json = { 50 | "": "", 51 | }; 52 | 53 | const expected = ` 54 | interface RootObject { 55 | '': string; 56 | } 57 | `; 58 | const actual = JsonToTS(json).pop(); 59 | const [a, b] = [expected, actual].map(removeWhiteSpace); 60 | assert.strictEqual(a, b); 61 | }); 62 | 63 | it("should work with multiple key words", function () { 64 | const json = { 65 | "hello world": 42, 66 | }; 67 | 68 | const expected = ` 69 | interface RootObject { 70 | 'hello world': number; 71 | }`; 72 | const actual = JsonToTS(json).pop(); 73 | assert.strictEqual(expected.trim(), actual.trim()); 74 | }); 75 | 76 | it("should work with multiple key words and optional fields", function () { 77 | const json = { 78 | "hello world": undefined, 79 | }; 80 | 81 | const expected = ` 82 | interface RootObject { 83 | 'hello world'?: any; 84 | }`; 85 | const actual = JsonToTS(json).pop(); 86 | assert.strictEqual(expected.trim(), actual.trim()); 87 | }); 88 | 89 | it("should work with primitive types", function () { 90 | const json = { 91 | str: "this is string", 92 | num: 42, 93 | bool: true, 94 | }; 95 | 96 | const expected = ` 97 | interface RootObject { 98 | str: string; 99 | num: number; 100 | bool: boolean; 101 | } 102 | `; 103 | const interfaceStr = JsonToTS(json).pop(); 104 | const [expect, actual] = [expected, interfaceStr].map(removeWhiteSpace); 105 | assert.strictEqual(expect, actual); 106 | }); 107 | 108 | it("should keep field order", function () { 109 | const json = { 110 | c: "this is string", 111 | a: 42, 112 | b: true, 113 | }; 114 | 115 | const expected = ` 116 | interface RootObject { 117 | c: string; 118 | a: number; 119 | b: boolean; 120 | } 121 | `; 122 | const interfaceStr = JsonToTS(json).pop(); 123 | const [expect, actual] = [expected, interfaceStr].map(removeWhiteSpace); 124 | assert.strictEqual(expect, actual); 125 | }); 126 | 127 | it("should add optional field modifier on null values", function () { 128 | const json = { 129 | field: undefined, 130 | }; 131 | 132 | const expected = ` 133 | interface RootObject { 134 | field?: any; 135 | } 136 | `; 137 | const actual = JsonToTS(json).pop(); 138 | const [a, b] = [expected, actual].map(removeWhiteSpace); 139 | assert.strictEqual(a, b); 140 | }); 141 | 142 | it('should name root object interface "RootObject"', function () { 143 | const json = {}; 144 | 145 | const expected = ` 146 | interface RootObject { 147 | } 148 | `; 149 | const actual = JsonToTS(json).pop(); 150 | const [a, b] = [expected, actual].map(removeWhiteSpace); 151 | assert.strictEqual(a, b); 152 | }); 153 | 154 | it("should empty array should be any[]", function () { 155 | const json = { 156 | arr: [], 157 | }; 158 | 159 | const expected = ` 160 | interface RootObject { 161 | arr: any[]; 162 | } 163 | `; 164 | const actual = JsonToTS(json).pop(); 165 | const [a, b] = [expected, actual].map(removeWhiteSpace); 166 | assert.strictEqual(a, b); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /test/util/index.ts: -------------------------------------------------------------------------------- 1 | export const removeWhiteSpace = str => str.replace(/\s/g, '') 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "module": "commonjs", 5 | "target": "es5", 6 | "noImplicitAny": false, 7 | "sourceMap": true, 8 | "outDir": "build", 9 | "lib": [ 10 | "es2017", 11 | "dom" 12 | ] 13 | } 14 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "jsRules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "indent": [ 9 | true, 10 | "spaces" 11 | ], 12 | "no-duplicate-variable": true, 13 | "no-eval": true, 14 | "no-trailing-whitespace": true, 15 | "no-unsafe-finally": true, 16 | "one-line": [ 17 | true, 18 | "check-open-brace", 19 | "check-whitespace" 20 | ], 21 | "quotemark": [ 22 | true, 23 | "single" 24 | ], 25 | "semicolon": [ 26 | true, 27 | "never" 28 | ], 29 | "triple-equals": [ 30 | true, 31 | "allow-null-check" 32 | ], 33 | "variable-name": [ 34 | true, 35 | "ban-keywords" 36 | ], 37 | "whitespace": [ 38 | true, 39 | "check-branch", 40 | "check-decl", 41 | "check-operator", 42 | "check-separator", 43 | "check-type" 44 | ] 45 | }, 46 | "rules": { 47 | "class-name": true, 48 | "comment-format": [ 49 | true, 50 | "check-space" 51 | ], 52 | "indent": [ 53 | true, 54 | "spaces" 55 | ], 56 | "no-eval": true, 57 | "no-internal-module": true, 58 | "no-trailing-whitespace": true, 59 | "no-unsafe-finally": true, 60 | "no-var-keyword": true, 61 | "one-line": [ 62 | true, 63 | "check-open-brace", 64 | "check-whitespace" 65 | ], 66 | "quotemark": [ 67 | true, 68 | "single" 69 | ], 70 | "semicolon": [ 71 | true, 72 | "never" 73 | ], 74 | "triple-equals": [ 75 | true, 76 | "allow-null-check" 77 | ], 78 | "typedef-whitespace": [ 79 | true, 80 | { 81 | "call-signature": "nospace", 82 | "index-signature": "nospace", 83 | "parameter": "nospace", 84 | "property-declaration": "nospace", 85 | "variable-declaration": "nospace" 86 | } 87 | ], 88 | "variable-name": [ 89 | true, 90 | "ban-keywords" 91 | ], 92 | "whitespace": [ 93 | true, 94 | "check-branch", 95 | "check-decl", 96 | "check-operator", 97 | "check-separator", 98 | "check-type" 99 | ] 100 | } 101 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/mocha@2.2.40": 6 | version "2.2.40" 7 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.40.tgz#9811dd800ece544cd84b5b859917bf584a150c4c" 8 | integrity sha1-mBHdgA7OVEzYS1uFmRe/WEoVDEw= 9 | 10 | "@types/node@^7.0.12": 11 | version "7.10.6" 12 | resolved "https://registry.yarnpkg.com/@types/node/-/node-7.10.6.tgz#c42137f0f2f6458bf0c898d65f48c5f600911475" 13 | integrity sha512-d0BOAicT0tEdbdVQlLGOVul1kvg6YvbaADRCThGCz5NJ0e9r00SofcR1x69hmlCyrHuB6jd4cKzL9bMLjPnpAA== 14 | 15 | "@types/pluralize@^0.0.27": 16 | version "0.0.27" 17 | resolved "https://registry.yarnpkg.com/@types/pluralize/-/pluralize-0.0.27.tgz#087354a791ce027db1101ff399db6111fc9275f7" 18 | integrity sha1-CHNUp5HOAn2xEB/zmdthEfySdfc= 19 | 20 | ansi-colors@3.2.3: 21 | version "3.2.3" 22 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 23 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== 24 | 25 | ansi-regex@^2.0.0: 26 | version "2.1.1" 27 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 28 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 29 | 30 | ansi-regex@^3.0.0: 31 | version "3.0.0" 32 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 33 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 34 | 35 | ansi-regex@^4.1.0: 36 | version "4.1.0" 37 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 38 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 39 | 40 | ansi-styles@^3.2.1: 41 | version "3.2.1" 42 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 43 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 44 | dependencies: 45 | color-convert "^1.9.0" 46 | 47 | argparse@^1.0.7: 48 | version "1.0.10" 49 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 50 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 51 | dependencies: 52 | sprintf-js "~1.0.2" 53 | 54 | array-includes@^3.0.2: 55 | version "3.0.3" 56 | resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" 57 | integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= 58 | dependencies: 59 | define-properties "^1.1.2" 60 | es-abstract "^1.7.0" 61 | 62 | balanced-match@^1.0.0: 63 | version "1.0.0" 64 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 65 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 66 | 67 | brace-expansion@^1.1.7: 68 | version "1.1.11" 69 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 70 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 71 | dependencies: 72 | balanced-match "^1.0.0" 73 | concat-map "0.0.1" 74 | 75 | browser-stdout@1.3.1: 76 | version "1.3.1" 77 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 78 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 79 | 80 | camelcase@^5.0.0: 81 | version "5.3.1" 82 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 83 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 84 | 85 | chalk@^2.0.1: 86 | version "2.4.2" 87 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 88 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 89 | dependencies: 90 | ansi-styles "^3.2.1" 91 | escape-string-regexp "^1.0.5" 92 | supports-color "^5.3.0" 93 | 94 | cliui@^4.0.0: 95 | version "4.1.0" 96 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" 97 | integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== 98 | dependencies: 99 | string-width "^2.1.1" 100 | strip-ansi "^4.0.0" 101 | wrap-ansi "^2.0.0" 102 | 103 | code-point-at@^1.0.0: 104 | version "1.1.0" 105 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 106 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 107 | 108 | color-convert@^1.9.0: 109 | version "1.9.3" 110 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 111 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 112 | dependencies: 113 | color-name "1.1.3" 114 | 115 | color-name@1.1.3: 116 | version "1.1.3" 117 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 118 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 119 | 120 | concat-map@0.0.1: 121 | version "0.0.1" 122 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 123 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 124 | 125 | cross-spawn@^6.0.0: 126 | version "6.0.5" 127 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 128 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 129 | dependencies: 130 | nice-try "^1.0.4" 131 | path-key "^2.0.1" 132 | semver "^5.5.0" 133 | shebang-command "^1.2.0" 134 | which "^1.2.9" 135 | 136 | debug@3.2.6: 137 | version "3.2.6" 138 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 139 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 140 | dependencies: 141 | ms "^2.1.1" 142 | 143 | decamelize@^1.2.0: 144 | version "1.2.0" 145 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 146 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 147 | 148 | define-properties@^1.0.1, define-properties@^1.1.2, define-properties@^1.1.3: 149 | version "1.1.3" 150 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 151 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 152 | dependencies: 153 | object-keys "^1.0.12" 154 | 155 | diff@3.5.0: 156 | version "3.5.0" 157 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 158 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 159 | 160 | emoji-regex@^7.0.1: 161 | version "7.0.3" 162 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 163 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 164 | 165 | end-of-stream@^1.1.0: 166 | version "1.4.1" 167 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" 168 | integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== 169 | dependencies: 170 | once "^1.4.0" 171 | 172 | es-abstract@^1.12.0, es-abstract@^1.2.1, es-abstract@^1.4.3, es-abstract@^1.5.1, es-abstract@^1.7.0: 173 | version "1.13.0" 174 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" 175 | integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== 176 | dependencies: 177 | es-to-primitive "^1.2.0" 178 | function-bind "^1.1.1" 179 | has "^1.0.3" 180 | is-callable "^1.1.4" 181 | is-regex "^1.0.4" 182 | object-keys "^1.0.12" 183 | 184 | es-to-primitive@^1.2.0: 185 | version "1.2.0" 186 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" 187 | integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== 188 | dependencies: 189 | is-callable "^1.1.4" 190 | is-date-object "^1.0.1" 191 | is-symbol "^1.0.2" 192 | 193 | es7-shim@^6.0.0: 194 | version "6.0.0" 195 | resolved "https://registry.yarnpkg.com/es7-shim/-/es7-shim-6.0.0.tgz#0c430b40b8505ad15570721a8d8dd4eb0c553155" 196 | integrity sha1-DEMLQLhQWtFVcHIajY3U6wxVMVU= 197 | dependencies: 198 | array-includes "^3.0.2" 199 | object.entries "^1.0.3" 200 | object.getownpropertydescriptors "^2.0.2" 201 | object.values "^1.0.3" 202 | string-at "^1.0.1" 203 | string.prototype.padend "^3.0.0" 204 | string.prototype.padstart "^3.0.0" 205 | string.prototype.trimleft "^2.0.0" 206 | string.prototype.trimright "^2.0.0" 207 | 208 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 209 | version "1.0.5" 210 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 211 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 212 | 213 | esprima@^4.0.0: 214 | version "4.0.1" 215 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 216 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 217 | 218 | execa@^1.0.0: 219 | version "1.0.0" 220 | resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" 221 | integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== 222 | dependencies: 223 | cross-spawn "^6.0.0" 224 | get-stream "^4.0.0" 225 | is-stream "^1.1.0" 226 | npm-run-path "^2.0.0" 227 | p-finally "^1.0.0" 228 | signal-exit "^3.0.0" 229 | strip-eof "^1.0.0" 230 | 231 | find-up@3.0.0, find-up@^3.0.0: 232 | version "3.0.0" 233 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 234 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 235 | dependencies: 236 | locate-path "^3.0.0" 237 | 238 | flat@^4.1.0: 239 | version "4.1.0" 240 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" 241 | integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== 242 | dependencies: 243 | is-buffer "~2.0.3" 244 | 245 | fs.realpath@^1.0.0: 246 | version "1.0.0" 247 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 248 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 249 | 250 | function-bind@^1.0.2, function-bind@^1.1.1: 251 | version "1.1.1" 252 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 253 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 254 | 255 | get-caller-file@^1.0.1: 256 | version "1.0.3" 257 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" 258 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== 259 | 260 | get-caller-file@^2.0.1: 261 | version "2.0.5" 262 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 263 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 264 | 265 | get-stream@^4.0.0: 266 | version "4.1.0" 267 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 268 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 269 | dependencies: 270 | pump "^3.0.0" 271 | 272 | glob@7.1.3: 273 | version "7.1.3" 274 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 275 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== 276 | dependencies: 277 | fs.realpath "^1.0.0" 278 | inflight "^1.0.4" 279 | inherits "2" 280 | minimatch "^3.0.4" 281 | once "^1.3.0" 282 | path-is-absolute "^1.0.0" 283 | 284 | growl@1.10.5: 285 | version "1.10.5" 286 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 287 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 288 | 289 | has-flag@^3.0.0: 290 | version "3.0.0" 291 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 292 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 293 | 294 | has-symbols@^1.0.0: 295 | version "1.0.0" 296 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 297 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= 298 | 299 | has@^1.0.1, has@^1.0.3: 300 | version "1.0.3" 301 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 302 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 303 | dependencies: 304 | function-bind "^1.1.1" 305 | 306 | hash.js@^1.0.3: 307 | version "1.1.7" 308 | resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" 309 | integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== 310 | dependencies: 311 | inherits "^2.0.3" 312 | minimalistic-assert "^1.0.1" 313 | 314 | he@1.2.0: 315 | version "1.2.0" 316 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 317 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 318 | 319 | inflight@^1.0.4: 320 | version "1.0.6" 321 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 322 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 323 | dependencies: 324 | once "^1.3.0" 325 | wrappy "1" 326 | 327 | inherits@2, inherits@^2.0.3: 328 | version "2.0.4" 329 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 330 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 331 | 332 | invert-kv@^2.0.0: 333 | version "2.0.0" 334 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" 335 | integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== 336 | 337 | is-buffer@~2.0.3: 338 | version "2.0.3" 339 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" 340 | integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== 341 | 342 | is-callable@^1.1.4: 343 | version "1.1.4" 344 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" 345 | integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== 346 | 347 | is-date-object@^1.0.1: 348 | version "1.0.1" 349 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 350 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= 351 | 352 | is-fullwidth-code-point@^1.0.0: 353 | version "1.0.0" 354 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 355 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 356 | dependencies: 357 | number-is-nan "^1.0.0" 358 | 359 | is-fullwidth-code-point@^2.0.0: 360 | version "2.0.0" 361 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 362 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 363 | 364 | is-regex@^1.0.4: 365 | version "1.0.4" 366 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 367 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= 368 | dependencies: 369 | has "^1.0.1" 370 | 371 | is-stream@^1.1.0: 372 | version "1.1.0" 373 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 374 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 375 | 376 | is-symbol@^1.0.2: 377 | version "1.0.2" 378 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" 379 | integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== 380 | dependencies: 381 | has-symbols "^1.0.0" 382 | 383 | isexe@^2.0.0: 384 | version "2.0.0" 385 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 386 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 387 | 388 | js-yaml@3.13.1: 389 | version "3.13.1" 390 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 391 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 392 | dependencies: 393 | argparse "^1.0.7" 394 | esprima "^4.0.0" 395 | 396 | lcid@^2.0.0: 397 | version "2.0.0" 398 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" 399 | integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== 400 | dependencies: 401 | invert-kv "^2.0.0" 402 | 403 | locate-path@^3.0.0: 404 | version "3.0.0" 405 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 406 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 407 | dependencies: 408 | p-locate "^3.0.0" 409 | path-exists "^3.0.0" 410 | 411 | lodash@^4.17.11: 412 | version "4.17.15" 413 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 414 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 415 | 416 | log-symbols@2.2.0: 417 | version "2.2.0" 418 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" 419 | integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== 420 | dependencies: 421 | chalk "^2.0.1" 422 | 423 | map-age-cleaner@^0.1.1: 424 | version "0.1.3" 425 | resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" 426 | integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== 427 | dependencies: 428 | p-defer "^1.0.0" 429 | 430 | mem@^4.0.0: 431 | version "4.3.0" 432 | resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" 433 | integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== 434 | dependencies: 435 | map-age-cleaner "^0.1.1" 436 | mimic-fn "^2.0.0" 437 | p-is-promise "^2.0.0" 438 | 439 | mimic-fn@^2.0.0: 440 | version "2.1.0" 441 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" 442 | integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 443 | 444 | minimalistic-assert@^1.0.1: 445 | version "1.0.1" 446 | resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" 447 | integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== 448 | 449 | minimatch@3.0.4, minimatch@^3.0.4: 450 | version "3.0.4" 451 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 452 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 453 | dependencies: 454 | brace-expansion "^1.1.7" 455 | 456 | minimist@0.0.8: 457 | version "0.0.8" 458 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 459 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 460 | 461 | mkdirp@0.5.1: 462 | version "0.5.1" 463 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 464 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 465 | dependencies: 466 | minimist "0.0.8" 467 | 468 | mocha@^6.1.4: 469 | version "6.2.0" 470 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56" 471 | integrity sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ== 472 | dependencies: 473 | ansi-colors "3.2.3" 474 | browser-stdout "1.3.1" 475 | debug "3.2.6" 476 | diff "3.5.0" 477 | escape-string-regexp "1.0.5" 478 | find-up "3.0.0" 479 | glob "7.1.3" 480 | growl "1.10.5" 481 | he "1.2.0" 482 | js-yaml "3.13.1" 483 | log-symbols "2.2.0" 484 | minimatch "3.0.4" 485 | mkdirp "0.5.1" 486 | ms "2.1.1" 487 | node-environment-flags "1.0.5" 488 | object.assign "4.1.0" 489 | strip-json-comments "2.0.1" 490 | supports-color "6.0.0" 491 | which "1.3.1" 492 | wide-align "1.1.3" 493 | yargs "13.2.2" 494 | yargs-parser "13.0.0" 495 | yargs-unparser "1.5.0" 496 | 497 | ms@2.1.1: 498 | version "2.1.1" 499 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 500 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 501 | 502 | ms@^2.1.1: 503 | version "2.1.2" 504 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 505 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 506 | 507 | nice-try@^1.0.4: 508 | version "1.0.5" 509 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 510 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 511 | 512 | node-environment-flags@1.0.5: 513 | version "1.0.5" 514 | resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" 515 | integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== 516 | dependencies: 517 | object.getownpropertydescriptors "^2.0.3" 518 | semver "^5.7.0" 519 | 520 | npm-run-path@^2.0.0: 521 | version "2.0.2" 522 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 523 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= 524 | dependencies: 525 | path-key "^2.0.0" 526 | 527 | number-is-nan@^1.0.0: 528 | version "1.0.1" 529 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 530 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 531 | 532 | object-keys@^1.0.11, object-keys@^1.0.12: 533 | version "1.1.1" 534 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 535 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 536 | 537 | object.assign@4.1.0: 538 | version "4.1.0" 539 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 540 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 541 | dependencies: 542 | define-properties "^1.1.2" 543 | function-bind "^1.1.1" 544 | has-symbols "^1.0.0" 545 | object-keys "^1.0.11" 546 | 547 | object.entries@^1.0.3: 548 | version "1.1.0" 549 | resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" 550 | integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== 551 | dependencies: 552 | define-properties "^1.1.3" 553 | es-abstract "^1.12.0" 554 | function-bind "^1.1.1" 555 | has "^1.0.3" 556 | 557 | object.getownpropertydescriptors@^2.0.2, object.getownpropertydescriptors@^2.0.3: 558 | version "2.0.3" 559 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" 560 | integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= 561 | dependencies: 562 | define-properties "^1.1.2" 563 | es-abstract "^1.5.1" 564 | 565 | object.values@^1.0.3: 566 | version "1.1.0" 567 | resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" 568 | integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== 569 | dependencies: 570 | define-properties "^1.1.3" 571 | es-abstract "^1.12.0" 572 | function-bind "^1.1.1" 573 | has "^1.0.3" 574 | 575 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 576 | version "1.4.0" 577 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 578 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 579 | dependencies: 580 | wrappy "1" 581 | 582 | os-locale@^3.0.0, os-locale@^3.1.0: 583 | version "3.1.0" 584 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" 585 | integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== 586 | dependencies: 587 | execa "^1.0.0" 588 | lcid "^2.0.0" 589 | mem "^4.0.0" 590 | 591 | p-defer@^1.0.0: 592 | version "1.0.0" 593 | resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" 594 | integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= 595 | 596 | p-finally@^1.0.0: 597 | version "1.0.0" 598 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 599 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 600 | 601 | p-is-promise@^2.0.0: 602 | version "2.1.0" 603 | resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" 604 | integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== 605 | 606 | p-limit@^2.0.0: 607 | version "2.2.0" 608 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" 609 | integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== 610 | dependencies: 611 | p-try "^2.0.0" 612 | 613 | p-locate@^3.0.0: 614 | version "3.0.0" 615 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 616 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 617 | dependencies: 618 | p-limit "^2.0.0" 619 | 620 | p-try@^2.0.0: 621 | version "2.2.0" 622 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 623 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 624 | 625 | path-exists@^3.0.0: 626 | version "3.0.0" 627 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 628 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 629 | 630 | path-is-absolute@^1.0.0: 631 | version "1.0.1" 632 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 633 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 634 | 635 | path-key@^2.0.0, path-key@^2.0.1: 636 | version "2.0.1" 637 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 638 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 639 | 640 | pluralize@^3.1.0: 641 | version "3.1.0" 642 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-3.1.0.tgz#84213d0a12356069daa84060c559242633161368" 643 | integrity sha1-hCE9ChI1YGnaqEBgxVkkJjMWE2g= 644 | 645 | pump@^3.0.0: 646 | version "3.0.0" 647 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 648 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 649 | dependencies: 650 | end-of-stream "^1.1.0" 651 | once "^1.3.1" 652 | 653 | require-directory@^2.1.1: 654 | version "2.1.1" 655 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 656 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 657 | 658 | require-main-filename@^1.0.1: 659 | version "1.0.1" 660 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 661 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 662 | 663 | require-main-filename@^2.0.0: 664 | version "2.0.0" 665 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 666 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 667 | 668 | semver@^5.5.0, semver@^5.7.0: 669 | version "5.7.0" 670 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" 671 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== 672 | 673 | set-blocking@^2.0.0: 674 | version "2.0.0" 675 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 676 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 677 | 678 | shebang-command@^1.2.0: 679 | version "1.2.0" 680 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 681 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 682 | dependencies: 683 | shebang-regex "^1.0.0" 684 | 685 | shebang-regex@^1.0.0: 686 | version "1.0.0" 687 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 688 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 689 | 690 | signal-exit@^3.0.0: 691 | version "3.0.2" 692 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 693 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 694 | 695 | sprintf-js@~1.0.2: 696 | version "1.0.3" 697 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 698 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 699 | 700 | string-at@^1.0.1: 701 | version "1.0.1" 702 | resolved "https://registry.yarnpkg.com/string-at/-/string-at-1.0.1.tgz#73b755adbaac3e178dabe7e4d7d79de56003fb37" 703 | integrity sha1-c7dVrbqsPheNq+fk19ed5WAD+zc= 704 | dependencies: 705 | define-properties "^1.0.1" 706 | es-abstract "^1.2.1" 707 | function-bind "^1.0.2" 708 | 709 | string-width@^1.0.1: 710 | version "1.0.2" 711 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 712 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 713 | dependencies: 714 | code-point-at "^1.0.0" 715 | is-fullwidth-code-point "^1.0.0" 716 | strip-ansi "^3.0.0" 717 | 718 | "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: 719 | version "2.1.1" 720 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 721 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 722 | dependencies: 723 | is-fullwidth-code-point "^2.0.0" 724 | strip-ansi "^4.0.0" 725 | 726 | string-width@^3.0.0: 727 | version "3.1.0" 728 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 729 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 730 | dependencies: 731 | emoji-regex "^7.0.1" 732 | is-fullwidth-code-point "^2.0.0" 733 | strip-ansi "^5.1.0" 734 | 735 | string.prototype.padend@^3.0.0: 736 | version "3.0.0" 737 | resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" 738 | integrity sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA= 739 | dependencies: 740 | define-properties "^1.1.2" 741 | es-abstract "^1.4.3" 742 | function-bind "^1.0.2" 743 | 744 | string.prototype.padstart@^3.0.0: 745 | version "3.0.0" 746 | resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.0.0.tgz#5bcfad39f4649bb2d031292e19bcf0b510d4b242" 747 | integrity sha1-W8+tOfRkm7LQMSkuGbzwtRDUskI= 748 | dependencies: 749 | define-properties "^1.1.2" 750 | es-abstract "^1.4.3" 751 | function-bind "^1.0.2" 752 | 753 | string.prototype.trimleft@^2.0.0: 754 | version "2.0.0" 755 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.0.0.tgz#68b6aa8e162c6a80e76e3a8a0c2e747186e271ff" 756 | integrity sha1-aLaqjhYsaoDnbjqKDC50cYbicf8= 757 | dependencies: 758 | define-properties "^1.1.2" 759 | function-bind "^1.0.2" 760 | 761 | string.prototype.trimright@^2.0.0: 762 | version "2.0.0" 763 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.0.0.tgz#ab4a56d802a01fbe7293e11e84f24dc8164661dd" 764 | integrity sha1-q0pW2AKgH75yk+EehPJNyBZGYd0= 765 | dependencies: 766 | define-properties "^1.1.2" 767 | function-bind "^1.0.2" 768 | 769 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 770 | version "3.0.1" 771 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 772 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 773 | dependencies: 774 | ansi-regex "^2.0.0" 775 | 776 | strip-ansi@^4.0.0: 777 | version "4.0.0" 778 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 779 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 780 | dependencies: 781 | ansi-regex "^3.0.0" 782 | 783 | strip-ansi@^5.1.0: 784 | version "5.2.0" 785 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 786 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 787 | dependencies: 788 | ansi-regex "^4.1.0" 789 | 790 | strip-eof@^1.0.0: 791 | version "1.0.0" 792 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 793 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 794 | 795 | strip-json-comments@2.0.1: 796 | version "2.0.1" 797 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 798 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 799 | 800 | supports-color@6.0.0: 801 | version "6.0.0" 802 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" 803 | integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== 804 | dependencies: 805 | has-flag "^3.0.0" 806 | 807 | supports-color@^5.3.0: 808 | version "5.5.0" 809 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 810 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 811 | dependencies: 812 | has-flag "^3.0.0" 813 | 814 | typescript@^3.8.3: 815 | version "3.8.3" 816 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" 817 | integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== 818 | 819 | which-module@^2.0.0: 820 | version "2.0.0" 821 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 822 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 823 | 824 | which@1.3.1, which@^1.2.9: 825 | version "1.3.1" 826 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 827 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 828 | dependencies: 829 | isexe "^2.0.0" 830 | 831 | wide-align@1.1.3: 832 | version "1.1.3" 833 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 834 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 835 | dependencies: 836 | string-width "^1.0.2 || 2" 837 | 838 | wrap-ansi@^2.0.0: 839 | version "2.1.0" 840 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 841 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= 842 | dependencies: 843 | string-width "^1.0.1" 844 | strip-ansi "^3.0.1" 845 | 846 | wrappy@1: 847 | version "1.0.2" 848 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 849 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 850 | 851 | "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: 852 | version "4.0.0" 853 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 854 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 855 | 856 | yargs-parser@13.0.0: 857 | version "13.0.0" 858 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" 859 | integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== 860 | dependencies: 861 | camelcase "^5.0.0" 862 | decamelize "^1.2.0" 863 | 864 | yargs-parser@^11.1.1: 865 | version "11.1.1" 866 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" 867 | integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== 868 | dependencies: 869 | camelcase "^5.0.0" 870 | decamelize "^1.2.0" 871 | 872 | yargs-parser@^13.0.0: 873 | version "13.1.1" 874 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" 875 | integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== 876 | dependencies: 877 | camelcase "^5.0.0" 878 | decamelize "^1.2.0" 879 | 880 | yargs-unparser@1.5.0: 881 | version "1.5.0" 882 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" 883 | integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw== 884 | dependencies: 885 | flat "^4.1.0" 886 | lodash "^4.17.11" 887 | yargs "^12.0.5" 888 | 889 | yargs@13.2.2: 890 | version "13.2.2" 891 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" 892 | integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== 893 | dependencies: 894 | cliui "^4.0.0" 895 | find-up "^3.0.0" 896 | get-caller-file "^2.0.1" 897 | os-locale "^3.1.0" 898 | require-directory "^2.1.1" 899 | require-main-filename "^2.0.0" 900 | set-blocking "^2.0.0" 901 | string-width "^3.0.0" 902 | which-module "^2.0.0" 903 | y18n "^4.0.0" 904 | yargs-parser "^13.0.0" 905 | 906 | yargs@^12.0.5: 907 | version "12.0.5" 908 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" 909 | integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== 910 | dependencies: 911 | cliui "^4.0.0" 912 | decamelize "^1.2.0" 913 | find-up "^3.0.0" 914 | get-caller-file "^1.0.1" 915 | os-locale "^3.0.0" 916 | require-directory "^2.1.1" 917 | require-main-filename "^1.0.1" 918 | set-blocking "^2.0.0" 919 | string-width "^2.0.0" 920 | which-module "^2.0.0" 921 | y18n "^3.2.1 || ^4.0.0" 922 | yargs-parser "^11.1.1" 923 | --------------------------------------------------------------------------------