fix: add missing dependency typedoc

Fixes #5
This commit is contained in:
Anselm Stordeur
2019-01-09 15:17:05 +01:00
parent a2bd0d113b
commit b248d1b5e0
7 changed files with 90 additions and 87 deletions

112
package-lock.json generated
View File

@@ -14,6 +14,14 @@
"commander": "2.19.0",
"tslint": "5.12.0",
"tslint-eslint-rules": "5.4.0"
},
"dependencies": {
"@types/node": {
"version": "10.12.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz",
"integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==",
"dev": true
}
}
},
"@openstapps/logger": {
@@ -59,7 +67,6 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.4.tgz",
"integrity": "sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g==",
"dev": true,
"requires": {
"@types/node": "*"
}
@@ -75,16 +82,14 @@
}
},
"@types/handlebars": {
"version": "4.0.39",
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.39.tgz",
"integrity": "sha512-vjaS7Q0dVqFp85QhyPSZqDKnTTCemcSHNHFvDdalO1s0Ifz5KuE64jQD5xoUkfdWwF4WpqdJEl7LsWH8rzhKJA==",
"dev": true
"version": "4.0.40",
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.40.tgz",
"integrity": "sha512-sGWNtsjNrLOdKha2RV1UeF8+UbQnPSG7qbe5wwbni0mw4h2gHXyPFUMOC+xwGirIiiydM/HSqjDO4rk6NFB18w=="
},
"@types/highlight.js": {
"version": "9.12.3",
"resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz",
"integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==",
"dev": true
"integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ=="
},
"@types/humanize-string": {
"version": "1.0.0",
@@ -94,14 +99,12 @@
"@types/lodash": {
"version": "4.14.119",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.119.tgz",
"integrity": "sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw==",
"dev": true
"integrity": "sha512-Z3TNyBL8Vd/M9D9Ms2S3LmFq2sSMzahodD6rCS9V2N44HUMINb75jNkSuwAx7eo2ufqTdfOdtGQpNbieUjPQmw=="
},
"@types/marked": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz",
"integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==",
"dev": true
"integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg=="
},
"@types/minimatch": {
"version": "3.0.3",
@@ -119,9 +122,9 @@
"integrity": "sha512-RTVWV485OOf4+nO2+feurk0chzHkSjkjALiejpHltyuMf/13fGymbbNNFrSKdSSUg1TIwzszXdWsVirxgqYiFA=="
},
"@types/node": {
"version": "10.12.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz",
"integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA=="
"version": "10.12.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ=="
},
"@types/nodemailer": {
"version": "4.6.5",
@@ -136,7 +139,6 @@
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.1.tgz",
"integrity": "sha512-1lQw+48BuVgp6c1+z8EMipp18IdnV2dLh6KQGwOm+kJy9nPjEkaqRKmwbDNEYf//EKBvKcwOC6V2cDrNxVoQeQ==",
"dev": true,
"requires": {
"@types/glob": "*",
"@types/node": "*"
@@ -772,7 +774,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
@@ -1048,8 +1049,7 @@
"graceful-fs": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
"dev": true
"integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
},
"growl": {
"version": "1.10.5",
@@ -1060,7 +1060,6 @@
"version": "4.0.12",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz",
"integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==",
"dev": true,
"requires": {
"async": "^2.5.0",
"optimist": "^0.6.1",
@@ -1088,10 +1087,9 @@
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
},
"highlight.js": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz",
"integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==",
"dev": true
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
},
"hosted-git-info": {
"version": "2.7.1",
@@ -1134,10 +1132,9 @@
"dev": true
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
"dev": true
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
"integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw=="
},
"invert-kv": {
"version": "1.0.0",
@@ -1267,7 +1264,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
@@ -1380,8 +1376,7 @@
"marked": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz",
"integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==",
"dev": true
"integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw=="
},
"mem": {
"version": "1.1.0",
@@ -1577,7 +1572,6 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
@@ -1586,8 +1580,7 @@
"minimist": {
"version": "0.0.10",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
}
}
},
@@ -1667,8 +1660,7 @@
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
},
"path-type": {
"version": "3.0.0",
@@ -1733,8 +1725,7 @@
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
},
"pseudomap": {
"version": "1.0.2",
@@ -1806,7 +1797,6 @@
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"dev": true,
"requires": {
"resolve": "^1.1.6"
}
@@ -1844,18 +1834,17 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
"integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"requires": {
"glob": "^7.0.5"
"glob": "^7.1.3"
}
},
"safe-buffer": {
@@ -1891,7 +1880,6 @@
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
"integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==",
"dev": true,
"requires": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
@@ -2091,9 +2079,9 @@
"dev": true
},
"ts-json-schema-generator": {
"version": "0.37.1",
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-0.37.1.tgz",
"integrity": "sha512-fXTDJ/Saz6gHsJA7o5y6ltlVEQIfc9HOgfSn4lbuAPm+BnfLMJbce8ylQT3yCH8N9zbMqkF3ceOtcN8nxoINMA==",
"version": "0.38.1",
"resolved": "https://registry.npmjs.org/ts-json-schema-generator/-/ts-json-schema-generator-0.38.1.tgz",
"integrity": "sha512-m0yBRUU35pPBUIavL1fFN7XEgcA1xNqcuIegT5Zm7QF3wsjqXofIMqO/lCVXVGCAHYvaOcRfpsPCS63w3vvAEQ==",
"requires": {
"commander": "~2.19.0",
"glob": "~7.1.3",
@@ -2185,10 +2173,9 @@
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
},
"typedoc": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.13.0.tgz",
"integrity": "sha512-jQWtvPcV+0fiLZAXFEe70v5gqjDO6pJYJz4mlTtmGJeW2KRoIU/BEfktma6Uj8Xii7UakuZjbxFewl3UYOkU/w==",
"dev": true,
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.14.0.tgz",
"integrity": "sha512-9DOYWO6O02YGZfbNOrELtmpQF4Eba/6AfNQNt46iRuIokoEq1Axdz9Ae/XjgdoXsM2ShGlDZsAO36BwRVz/Nmw==",
"requires": {
"@types/fs-extra": "^5.0.3",
"@types/handlebars": "^4.0.38",
@@ -2199,29 +2186,20 @@
"@types/shelljs": "^0.8.0",
"fs-extra": "^7.0.0",
"handlebars": "^4.0.6",
"highlight.js": "^9.0.0",
"highlight.js": "9.12.0",
"lodash": "^4.17.10",
"marked": "^0.4.0",
"minimatch": "^3.0.0",
"progress": "^2.0.0",
"shelljs": "^0.8.2",
"typedoc-default-themes": "^0.5.0",
"typescript": "3.1.x"
},
"dependencies": {
"typescript": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz",
"integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
"dev": true
}
"typescript": "3.2.x"
}
},
"typedoc-default-themes": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz",
"integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=",
"dev": true
"integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic="
},
"typescript": {
"version": "3.2.2",
@@ -2232,7 +2210,6 @@
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"dev": true,
"optional": true,
"requires": {
"commander": "~2.17.1",
@@ -2243,7 +2220,6 @@
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"dev": true,
"optional": true
}
}
@@ -2251,8 +2227,7 @@
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"uri-js": {
"version": "4.2.2",
@@ -2300,8 +2275,7 @@
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
"dev": true
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"wrap-ansi": {
"version": "2.1.0",

View File

@@ -43,7 +43,7 @@
"@types/humanize-string": "1.0.0",
"@types/mocha": "5.2.5",
"@types/mustache": "0.8.32",
"@types/node": "10.12.15",
"@types/node": "10.12.18",
"ajv": "6.6.2",
"async": "2.6.1",
"async-pool-native": "0.1.0",
@@ -55,16 +55,16 @@
"mocha": "5.2.0",
"mocha-typescript": "1.1.17",
"mustache": "3.0.1",
"ts-json-schema-generator": "0.37.1",
"ts-node": "7.0.1"
"ts-json-schema-generator": "0.38.1",
"ts-node": "7.0.1",
"typedoc": "0.14.0"
},
"devDependencies": {
"@openstapps/configuration": "0.5.0",
"conventional-changelog-cli": "2.0.11",
"prepend-file-cli": "1.0.6",
"rimraf": "2.6.2",
"rimraf": "2.6.3",
"tslint": "5.12.0",
"typedoc": "0.13.0",
"typescript": "3.2.2"
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018-2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -129,7 +129,13 @@ export function getProjectReflection(srcPath: PathLike): ProjectReflection {
const inputFiles = app.expandInputFiles([srcPath.toString()]);
// get project reflection from input files
return app.convert(inputFiles);
const result = app.convert(inputFiles);
if (typeof result === 'undefined') {
throw new Error('Project reflection could not be generated.');
}
return result;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018-2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -29,6 +29,10 @@ import {RouteWithMetaInformation} from './common';
export async function gatherRouteInformation(reflection: ProjectReflection): Promise<RouteWithMetaInformation[]> {
const routes: RouteWithMetaInformation[] = [];
if (!Array.isArray(reflection.children)) {
throw new Error('Project reflection doesn\'t contain any modules.');
}
await asyncPool(2, reflection.children, async (module: any) => {
if (Array.isArray(module.children) && module.children.length > 0) {
await asyncPool(2, module.children, (async (node: any) => {
@@ -49,6 +53,10 @@ export async function gatherRouteInformation(reflection: ProjectReflection): Pro
}
});
if (routes.length === 0) {
throw new Error('No route information found.');
}
return routes;
}
@@ -163,6 +171,10 @@ export function generateDocumentationForRoute(routeWithInfo: RouteWithMetaInform
export function getNodeMetaInformationMap(projectReflection: ProjectReflection): NodesWithMetaInformation {
const nodes: NodesWithMetaInformation = {};
if (typeof projectReflection.children === 'undefined') {
throw new Error('Project reflection doesn\'t contain any modules.');
}
// iterate over modules
projectReflection.children.forEach((module: any) => {
if (Array.isArray(module.children) && module.children.length > 0) {

View File

@@ -108,6 +108,10 @@ export class Converter {
export function getValidatableTypesFromReflection(projectReflection: ProjectReflection): string[] {
const validatableTypes: string[] = [];
if (typeof projectReflection.children === 'undefined') {
throw new Error('Project reflection doesn\'t contain any modules.');
}
// iterate over modules
projectReflection.children.forEach((module) => {
if (Array.isArray(module.children) && module.children.length > 0) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 StApps
* Copyright (C) 2018-2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -16,18 +16,10 @@ import {Logger} from '@openstapps/logger';
import {expect} from 'chai';
import {slow, suite, test, timeout} from 'mocha-typescript';
import {join} from 'path';
import {ProjectReflection} from 'typedoc';
import {Converter, getValidatableTypesFromReflection} from '../src/schema';
const logger = new Logger();
type RecursivePartial<T> = {
[P in keyof T]?:
T[P] extends Array<infer U> ? Array<RecursivePartial<U>> :
T[P] extends object ? RecursivePartial<T[P]> :
T[P];
};
process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION', err.stack);
process.exit(1);
@@ -79,7 +71,7 @@ export class SchemaSpec {
@test
async getValidatableTypesFromReflection() {
const reflection: RecursivePartial<ProjectReflection> = {
const reflection: any = {
children: [
{
children: [

View File

@@ -1,3 +1,18 @@
/*
* Copyright (C) 2018-2019 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* @validatable
*/