typescript-json-schema
Advanced tools
Comparing version 0.47.0 to 0.48.0
@@ -25,4 +25,4 @@ "use strict"; | ||
.describe("propOrder", "Create property order definitions.") | ||
.boolean("typeOfKeyword").default("typeOfKeyword", defaultArgs.typeOfKeyword) | ||
.describe("typeOfKeyword", "Use typeOf keyword (https://goo.gl/DC6sni) for functions.") | ||
.boolean("useTypeOfKeyword").default("useTypeOfKeyword", defaultArgs.typeOfKeyword) | ||
.describe("useTypeOfKeyword", "Use typeOf keyword (https://goo.gl/DC6sni) for functions.") | ||
.boolean("required").default("required", defaultArgs.required) | ||
@@ -51,2 +51,4 @@ .describe("required", "Create required array for non-optional properties.") | ||
.describe("defaultNumberType", "Default number type.") | ||
.boolean("tsNodeRegister").default("tsNodeRegister", defaultArgs.tsNodeRegister) | ||
.describe("tsNodeRegister", "Use ts-node/register (needed for requiring typescript files).") | ||
.argv; | ||
@@ -73,2 +75,3 @@ typescript_json_schema_1.exec(args._[0], args._[1], { | ||
defaultNumberType: args.defaultNumberType, | ||
tsNodeRegister: args.tsNodeRegister, | ||
}); | ||
@@ -75,0 +78,0 @@ } |
@@ -28,2 +28,3 @@ import * as ts from "typescript"; | ||
defaultNumberType: "number" | "integer"; | ||
tsNodeRegister: boolean; | ||
}; | ||
@@ -70,2 +71,3 @@ export declare type PartialArgs = Partial<Args>; | ||
}; | ||
export declare function regexRequire(value: string): RegExpExecArray | null; | ||
export declare class JsonSchemaGenerator { | ||
@@ -72,0 +74,0 @@ private args; |
@@ -14,3 +14,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.exec = exports.programFromConfig = exports.generateSchema = exports.buildGenerator = exports.getProgramFromFiles = exports.JsonSchemaGenerator = exports.getDefaultArgs = void 0; | ||
exports.exec = exports.programFromConfig = exports.generateSchema = exports.buildGenerator = exports.getProgramFromFiles = exports.JsonSchemaGenerator = exports.regexRequire = exports.getDefaultArgs = void 0; | ||
var glob = require("glob"); | ||
@@ -26,2 +26,3 @@ var stringify = require("json-stable-stringify"); | ||
var REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; | ||
var REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/; | ||
var NUMERIC_INDEX_PATTERN = "^[0-9]+$"; | ||
@@ -49,2 +50,3 @@ function getDefaultArgs() { | ||
defaultNumberType: "number", | ||
tsNodeRegister: false, | ||
}; | ||
@@ -88,3 +90,36 @@ } | ||
} | ||
function parseValue(value) { | ||
function resolveRequiredFile(symbol, key, fileName, objectName) { | ||
var sourceFile = getSourceFile(symbol); | ||
var requiredFilePath = /^[.\/]+/.test(fileName) | ||
? fileName === "." | ||
? path.resolve(sourceFile.fileName) | ||
: path.resolve(path.dirname(sourceFile.fileName), fileName) | ||
: fileName; | ||
var requiredFile = require(requiredFilePath); | ||
if (!requiredFile) { | ||
throw Error("Required: File couldn't be loaded"); | ||
} | ||
var requiredObject = objectName ? requiredFile[objectName] : requiredFile.default; | ||
if (requiredObject === undefined) { | ||
throw Error("Required: Variable is undefined"); | ||
} | ||
if (typeof requiredObject === "function") { | ||
throw Error("Required: Can't use function as a variable"); | ||
} | ||
if (key === "examples" && !Array.isArray(requiredObject)) { | ||
throw Error("Required: Variable isn't an array"); | ||
} | ||
return requiredObject; | ||
} | ||
function regexRequire(value) { | ||
return REGEX_REQUIRE.exec(value); | ||
} | ||
exports.regexRequire = regexRequire; | ||
function parseValue(symbol, key, value) { | ||
var match = regexRequire(value); | ||
if (match) { | ||
var fileName = match[2].substr(1, match[2].length - 2).trim(); | ||
var objectName = match[4]; | ||
return resolveRequiredFile(symbol, key, fileName, objectName); | ||
} | ||
try { | ||
@@ -231,3 +266,3 @@ return JSON.parse(value); | ||
examples: true, | ||
$ref: true | ||
$ref: true, | ||
}; | ||
@@ -304,3 +339,3 @@ var subDefinitions = { | ||
var v = match[2]; | ||
definition[name] = __assign(__assign({}, definition[name]), (_a = {}, _a[k] = v ? parseValue(v) : true, _a)); | ||
definition[name] = __assign(__assign({}, definition[name]), (_a = {}, _a[k] = v ? parseValue(symbol, k, v) : true, _a)); | ||
return; | ||
@@ -312,7 +347,7 @@ } | ||
if (parts.length === 2 && subDefinitions[parts[0]]) { | ||
definition[parts[0]] = __assign(__assign({}, definition[parts[0]]), (_b = {}, _b[parts[1]] = text ? parseValue(text) : true, _b)); | ||
definition[parts[0]] = __assign(__assign({}, definition[parts[0]]), (_b = {}, _b[parts[1]] = text ? parseValue(symbol, name, text) : true, _b)); | ||
} | ||
} | ||
if (validationKeywords[name] || _this.userValidationKeywords[name]) { | ||
definition[name] = text === undefined ? "" : parseValue(text); | ||
definition[name] = text === undefined ? "" : parseValue(symbol, name, text); | ||
} | ||
@@ -1075,2 +1110,5 @@ else { | ||
} | ||
if (args.tsNodeRegister) { | ||
require("ts-node/register"); | ||
} | ||
var diagnostics = []; | ||
@@ -1077,0 +1115,0 @@ if (!args.ignoreErrors) { |
{ | ||
"name": "typescript-json-schema", | ||
"version": "0.47.0", | ||
"version": "0.48.0", | ||
"description": "typescript-json-schema generates JSON Schema files from your Typescript sources", | ||
@@ -51,2 +51,3 @@ "main": "dist/typescript-json-schema.js", | ||
"json-stable-stringify": "^1.0.1", | ||
"ts-node": "^9.1.1", | ||
"typescript": "^4.1.3", | ||
@@ -66,3 +67,2 @@ "yargs": "^16.2.0" | ||
"source-map-support": "^0.5.19", | ||
"ts-node": "^9.1.1", | ||
"tslint": "^6.1.3" | ||
@@ -69,0 +69,0 @@ }, |
195
README.md
@@ -51,2 +51,3 @@ # typescript-json-schema | ||
--defaultNumberType Default number type. [choices: "number", "integer"] [default: "number"] | ||
--tsNodeRegister Use ts-node/register (needed for require typescript files). [boolean] [default: false] | ||
``` | ||
@@ -63,3 +64,3 @@ | ||
const settings: TJS.PartialArgs = { | ||
required: true, | ||
required: true, | ||
}; | ||
@@ -69,3 +70,3 @@ | ||
const compilerOptions: TJS.CompilerOptions = { | ||
strictNullChecks: true, | ||
strictNullChecks: true, | ||
}; | ||
@@ -101,3 +102,3 @@ | ||
const settings: TJS.PartialArgs = { | ||
uniqueNames: true, | ||
uniqueNames: true, | ||
}; | ||
@@ -121,6 +122,6 @@ | ||
type SymbolRef = { | ||
name: string; | ||
typeName: string; | ||
fullyQualifiedName: string; | ||
symbol: ts.Symbol; | ||
name: string; | ||
typeName: string; | ||
fullyQualifiedName: string; | ||
symbol: ts.Symbol; | ||
}; | ||
@@ -139,9 +140,9 @@ ``` | ||
export interface Shape { | ||
/** | ||
* The size of the shape. | ||
* | ||
* @minimum 0 | ||
* @TJS-type integer | ||
*/ | ||
size: number; | ||
/** | ||
* The size of the shape. | ||
* | ||
* @minimum 0 | ||
* @TJS-type integer | ||
*/ | ||
size: number; | ||
} | ||
@@ -154,16 +155,16 @@ ``` | ||
{ | ||
"$ref": "#/definitions/Shape", | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"definitions": { | ||
"Shape": { | ||
"properties": { | ||
"size": { | ||
"description": "The size of the shape.", | ||
"minimum": 0, | ||
"type": "integer" | ||
"$ref": "#/definitions/Shape", | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"definitions": { | ||
"Shape": { | ||
"properties": { | ||
"size": { | ||
"description": "The size of the shape.", | ||
"minimum": 0, | ||
"type": "integer" | ||
} | ||
}, | ||
"type": "object" | ||
} | ||
}, | ||
"type": "object" | ||
} | ||
} | ||
} | ||
@@ -182,16 +183,16 @@ ``` | ||
export interface ShapesData { | ||
/** | ||
* Specify individual fields in items. | ||
* | ||
* @items.type integer | ||
* @items.minimum 0 | ||
*/ | ||
sizes: number[]; | ||
/** | ||
* Specify individual fields in items. | ||
* | ||
* @items.type integer | ||
* @items.minimum 0 | ||
*/ | ||
sizes: number[]; | ||
/** | ||
* Or specify a JSON spec: | ||
* | ||
* @items {"type":"string","format":"email"} | ||
*/ | ||
emails: string[]; | ||
/** | ||
* Or specify a JSON spec: | ||
* | ||
* @items {"type":"string","format":"email"} | ||
*/ | ||
emails: string[]; | ||
} | ||
@@ -204,27 +205,27 @@ ``` | ||
{ | ||
"$ref": "#/definitions/ShapesData", | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"definitions": { | ||
"Shape": { | ||
"properties": { | ||
"sizes": { | ||
"description": "Specify individual fields in items.", | ||
"items": { | ||
"minimum": 0, | ||
"type": "integer" | ||
}, | ||
"type": "array" | ||
}, | ||
"emails": { | ||
"description": "Or specify a JSON spec:", | ||
"items": { | ||
"format": "email", | ||
"type": "string" | ||
}, | ||
"type": "array" | ||
"$ref": "#/definitions/ShapesData", | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"definitions": { | ||
"Shape": { | ||
"properties": { | ||
"sizes": { | ||
"description": "Specify individual fields in items.", | ||
"items": { | ||
"minimum": 0, | ||
"type": "integer" | ||
}, | ||
"type": "array" | ||
}, | ||
"emails": { | ||
"description": "Or specify a JSON spec:", | ||
"items": { | ||
"format": "email", | ||
"type": "string" | ||
}, | ||
"type": "array" | ||
} | ||
}, | ||
"type": "object" | ||
} | ||
}, | ||
"type": "object" | ||
} | ||
} | ||
} | ||
@@ -244,3 +245,3 @@ ``` | ||
interface MyObject { | ||
n: integer; | ||
n: integer; | ||
} | ||
@@ -251,2 +252,70 @@ ``` | ||
### `require` a variable from a file | ||
(for requiring typescript files is needed to set argument `tsNodeRegister` to true) | ||
When you want to import for example an object or an array into your property defined in annotation, you can use `require`. | ||
Example: | ||
```ts | ||
export interface InnerData { | ||
age: number; | ||
name: string; | ||
free: boolean; | ||
} | ||
export interface UserData { | ||
/** | ||
* Specify required object | ||
* | ||
* @examples require("./example.ts").example | ||
*/ | ||
data: InnerData; | ||
} | ||
``` | ||
file `example.ts` | ||
```ts | ||
export const example: InnerData[] = [{ | ||
age: 30, | ||
name: "Ben", | ||
free: false | ||
}] | ||
``` | ||
Translation: | ||
```json | ||
{ | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"properties": { | ||
"data": { | ||
"description": "Specify required object", | ||
"examples": [ | ||
{ | ||
"age": 30, | ||
"name": "Ben", | ||
"free": false | ||
} | ||
], | ||
"type": "object", | ||
"properties": { | ||
"age": { "type": "number" }, | ||
"name": { "type": "string" }, | ||
"free": { "type": "boolean" } | ||
}, | ||
"required": ["age", "free", "name"] | ||
} | ||
}, | ||
"required": ["data"], | ||
"type": "object" | ||
} | ||
``` | ||
Also you can use `require(".").example`, which will try to find exported variable with name 'example' in current file. Or you can use `require("./someFile.ts")`, which will try to use default exported variable from 'someFile.ts'. | ||
Note: For `examples` a required variable must be an array. | ||
## Background | ||
@@ -253,0 +322,0 @@ |
@@ -25,4 +25,4 @@ import { exec, getDefaultArgs } from "./typescript-json-schema"; | ||
.describe("propOrder", "Create property order definitions.") | ||
.boolean("typeOfKeyword").default("typeOfKeyword", defaultArgs.typeOfKeyword) | ||
.describe("typeOfKeyword", "Use typeOf keyword (https://goo.gl/DC6sni) for functions.") | ||
.boolean("useTypeOfKeyword").default("useTypeOfKeyword", defaultArgs.typeOfKeyword) | ||
.describe("useTypeOfKeyword", "Use typeOf keyword (https://goo.gl/DC6sni) for functions.") | ||
.boolean("required").default("required", defaultArgs.required) | ||
@@ -51,2 +51,4 @@ .describe("required", "Create required array for non-optional properties.") | ||
.describe("defaultNumberType", "Default number type.") | ||
.boolean("tsNodeRegister").default("tsNodeRegister", defaultArgs.tsNodeRegister) | ||
.describe("tsNodeRegister", "Use ts-node/register (needed for requiring typescript files).") | ||
.argv; | ||
@@ -74,2 +76,3 @@ | ||
defaultNumberType: args.defaultNumberType, | ||
tsNodeRegister: args.tsNodeRegister, | ||
}); | ||
@@ -76,0 +79,0 @@ } |
@@ -15,2 +15,22 @@ import * as glob from "glob"; | ||
const REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g; | ||
/** | ||
* Resolve required file, his path and a property name, | ||
* pattern: require([file_path]).[property_name] | ||
* | ||
* the part ".[property_name]" is optional in the regex | ||
* | ||
* will match: | ||
* | ||
* require('./path.ts') | ||
* require('./path.ts').objectName | ||
* require("./path.ts") | ||
* require("./path.ts").objectName | ||
* require('@module-name') | ||
* | ||
* match[2] = file_path (a path to the file with quotes) | ||
* match[3] = (optional) property_name (a property name, exported in the file) | ||
* | ||
* for more details, see tests/require.test.ts | ||
*/ | ||
const REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/; | ||
const NUMERIC_INDEX_PATTERN = "^[0-9]+$"; | ||
@@ -39,2 +59,3 @@ | ||
defaultNumberType: "number", | ||
tsNodeRegister: false, | ||
}; | ||
@@ -67,2 +88,3 @@ } | ||
defaultNumberType: "number" | "integer"; | ||
tsNodeRegister: boolean; | ||
}; | ||
@@ -176,5 +198,42 @@ | ||
/** | ||
* Resolve required file | ||
*/ | ||
function resolveRequiredFile(symbol: ts.Symbol, key: string, fileName: string, objectName: string): any { | ||
const sourceFile = getSourceFile(symbol); | ||
const requiredFilePath = /^[.\/]+/.test(fileName) | ||
? fileName === "." | ||
? path.resolve(sourceFile.fileName) | ||
: path.resolve(path.dirname(sourceFile.fileName), fileName) | ||
: fileName; | ||
const requiredFile = require(requiredFilePath); | ||
if (!requiredFile) { | ||
throw Error("Required: File couldn't be loaded"); | ||
} | ||
const requiredObject = objectName ? requiredFile[objectName] : requiredFile.default; | ||
if (requiredObject === undefined) { | ||
throw Error("Required: Variable is undefined"); | ||
} | ||
if (typeof requiredObject === "function") { | ||
throw Error("Required: Can't use function as a variable"); | ||
} | ||
if (key === "examples" && !Array.isArray(requiredObject)) { | ||
throw Error("Required: Variable isn't an array"); | ||
} | ||
return requiredObject; | ||
} | ||
export function regexRequire(value: string) { | ||
return REGEX_REQUIRE.exec(value); | ||
} | ||
/** | ||
* Try to parse a value and returns the string if it fails. | ||
*/ | ||
function parseValue(value: string): any { | ||
function parseValue(symbol: ts.Symbol, key: string, value: string): any { | ||
const match = regexRequire(value); | ||
if (match) { | ||
const fileName = match[2].substr(1, match[2].length - 2).trim(); | ||
const objectName = match[4]; | ||
return resolveRequiredFile(symbol, key, fileName, objectName); | ||
} | ||
try { | ||
@@ -378,3 +437,3 @@ return JSON.parse(value); | ||
// A JSDoc $ref annotation can appear as a $ref. | ||
$ref: true | ||
$ref: true, | ||
}; | ||
@@ -513,3 +572,3 @@ | ||
const v = match[2]; | ||
definition[name] = { ...definition[name], [k]: v ? parseValue(v) : true }; | ||
definition[name] = { ...definition[name], [k]: v ? parseValue(symbol, k, v) : true }; | ||
return; | ||
@@ -523,3 +582,6 @@ } | ||
if (parts.length === 2 && subDefinitions[parts[0]]) { | ||
definition[parts[0]] = { ...definition[parts[0]], [parts[1]]: text ? parseValue(text) : true }; | ||
definition[parts[0]] = { | ||
...definition[parts[0]], | ||
[parts[1]]: text ? parseValue(symbol, name, text) : true, | ||
}; | ||
} | ||
@@ -529,3 +591,3 @@ } | ||
if (validationKeywords[name] || this.userValidationKeywords[name]) { | ||
definition[name] = text === undefined ? "" : parseValue(text); | ||
definition[name] = text === undefined ? "" : parseValue(symbol, name, text); | ||
} else { | ||
@@ -1447,2 +1509,6 @@ // special annotations | ||
if (args.tsNodeRegister) { | ||
require("ts-node/register"); | ||
} | ||
let diagnostics: ReadonlyArray<ts.Diagnostic> = []; | ||
@@ -1449,0 +1515,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
219184
11
3164
319
6
4
+ Addedts-node@^9.1.1
+ Addedarg@4.1.3(transitive)
+ Addedbuffer-from@1.1.2(transitive)
+ Addedcreate-require@1.1.1(transitive)
+ Addeddiff@4.0.2(transitive)
+ Addedmake-error@1.3.6(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-support@0.5.21(transitive)
+ Addedts-node@9.1.1(transitive)
+ Addedyn@3.1.1(transitive)