├── .gitignore
├── .npmignore
├── CONTRIBUTING.md
├── README.md
├── img
└── screenshot.png
├── package.json
├── rollup.config.js
├── scripts
└── getDTS.js
├── src
├── index.ts
├── lib
│ ├── LICENSE
│ └── typescript-json-schema.ts
└── vendor
│ ├── ds
│ └── createDesignSystem.d.ts
│ ├── playground.d.ts
│ ├── pluginUtils.d.ts
│ ├── sandbox.d.ts
│ ├── tsWorker.d.ts
│ ├── typescript-vfs.d.ts
│ └── utils.ts
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # dotenv environment variables file
55 | .env
56 |
57 | # gatsby files
58 | .cache/
59 | public
60 |
61 | # Mac files
62 | .DS_Store
63 |
64 | # Yarn
65 | yarn-error.log
66 | .pnp/
67 | .pnp.js
68 | # Yarn Integrity file
69 | .yarn-integrity
70 | dist
71 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | .gitignore
3 | rollup.config.jss
4 | !dist
5 | scripts
6 | .vscode
7 | yarn*
8 | tsconfig.json
9 | rollup*
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing to a TypeScript Playground Plugin
2 |
3 | ## Contributing
4 |
5 | You can use `yarn start` to set up both a copy of Rollup to generate the JS, and Serve to host it.
6 |
7 | ```sh
8 | yarn start
9 | ```
10 |
11 | Then set up the TypeScript playground to connect to a dev plugin at `http://localhost:5000/`.
12 |
13 | #### Plugin API
14 |
15 | The plugin API is documented in the [interface PlaygroundPlugin in `./src/index.ts`](src/index.ts).
16 |
17 | Roughly:
18 |
19 | - There are a set of mounting and un-mounting functions which you can use to handle your UI in the sidebar
20 | - There are `modelChanged` methods, which are shortcuts to knowing when the code in monaco editor has changed
21 |
22 | ### Sandbox
23 |
24 | The plugins are passed copies of the TypeScript sandbox, which is a high level API wrapper to the [`monaco-editor`](https://microsoft.github.io/monaco-editor/). You can learn more about the sandbox on [the TypeScript website](http://www.typescriptlang.org/v2/dev/sandbox/).
25 |
26 | #### Rollup
27 |
28 | [Rollup](https://rollupjs.org) is a JavaScript bundler, that will take all of the TypeScript + JavaScript code you reference and then create an AMD bundle for it all. AMD bundles are used in Monaco, TypeScript Sandbox and the Playground - so, this is used for consistency with the rest of the ecosystem.
29 |
30 | ## Adding a dependency
31 |
32 | Because most node_modules expect to be running in node, you might have to do some work to get the dependency working on the web.
33 |
34 | The route to handle this is via rollup:
35 |
36 | - add a new dependency via `yarn add xyz`
37 | - import it into your `index.ts`
38 | - run `yarn build` - did it provide some error messages?
39 | - If it did, you may need to edit your `rollup.config.js`.
40 | - You could probably start by taking the [rollup config from `playground-plugin-tsquery`](https://github.com/orta/playground-plugin-tsquery/blob/master/rollup.config.js) and by adding any extra externals and globals.
41 |
42 | #### Serve
43 |
44 | [Serve](https://github.com/zeit/serve) is used to make a web-server for the dist folder.
45 |
46 | ## Deployment
47 |
48 | This module should be deployed to npm when you would like the world to see it, this may mean making your code handle a staging vs production environment (because the URLs will be different.)
49 |
50 | For example, this is how you can handle getting the URL for a CSS file which is included in your `dist` folder:
51 |
52 | ```ts
53 | const isDev = document.location.host.includes("localhost")
54 | const unpkgURL = "https://unpkg.com/typescript-playground-presentation-mode@latest/dist/slideshow.css"
55 | const cssHref = isDev ? "http://localhost:5000/slideshow.css" : unpkgURL
56 | ```
57 |
58 | ### Post-Deploy
59 |
60 | Once this is deployed, you can test it on the TypeScript playground by passing in the name of your plugin on npm to the custom plugin box. This is effectively your staging environment.
61 |
62 | Once you're happy and it's polished, you can apply to have it in the default plugin list.
63 |
64 | ## Support
65 |
66 | Ask questions either on the TypeScript Website issues](https://github.com/microsoft/TypeScript-Website/issues), or in the [TypeScript Community Discord](https://discord.gg/typescript) - in the TypeScript Website channel.
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## TypeScript Playground Plugin
2 |
3 |
4 |
5 | This plugin uses a custom build of YousefED/typescript-json-schema (at commit 20a03a2 to output the JSON schema version of your exported interfaces/types from the Playground editor.
6 |
7 |
8 | ## Running this plugin
9 |
10 | - [Click this link](https://www.typescriptlang.org/play?install-plugin=playground-typescript-json-schema) to install
11 |
12 | or
13 |
14 | - Open up the TypeScript Playground
15 | - Go the "Plugins" in the sidebar
16 | - Look for "Plugins from npm"
17 | - Add "playground-typescript-json-schema"
18 | - Reload the browser
19 |
20 | Then it will show up as a tab in the sidebar.
21 |
22 | ## Contributing
23 |
24 | See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full details, however, TLDR:
25 |
26 | ```sh
27 | git clone ...
28 | yarn install
29 | yarn start
30 | ```
31 |
32 | Then tick the box for starting plugin development inside the TypeScript Playground.
33 |
--------------------------------------------------------------------------------
/img/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orta/playground-typescript-json-schema/f611a2852badf34aef7283e736bcc8431d027f32/img/screenshot.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playground-typescript-json-schema",
3 | "version": "1.0.0",
4 | "main": "dist/index.js",
5 | "description": "Convert the exported types/interfaces in the Playground to JSON Schemas",
6 | "license": "MIT",
7 | "keywords": [
8 | "playground-plugin", "json-schema", "typescript"
9 | ],
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/orta/playground-typescript-json-schema"
13 | },
14 | "scripts": {
15 | "build": "rollup -c rollup.config.js",
16 | "compile": "tsc",
17 | "bootstrap": "node scripts/getDTS.js",
18 | "start": "concurrently -p \"[{name}]\" -n \"ROLLUP,SITE\" -c \"bgBlue.bold,bgMagenta.bold\" \"yarn rollup -c rollup.config.js --watch\" \"yarn serve dist\"",
19 | "prepublish": "yarn build",
20 | "postinstall": "yarn bootstrap && yarn build"
21 | },
22 | "devDependencies": {
23 | "@rollup/plugin-commonjs": "^11.0.2",
24 | "@rollup/plugin-json": "^4.0.2",
25 | "@rollup/plugin-node-resolve": "^7.1.0",
26 | "@rollup/plugin-typescript": "^3.0.0",
27 | "@types/react": "^16.9.23",
28 | "concurrently": "^5.1.0",
29 | "monaco-editor": "^0.19.3",
30 | "node-fetch": "^2.6.0",
31 | "rollup": "^1.31.0",
32 | "rollup-plugin-external-globals": "^0.6.1",
33 | "serve": "^11.3.0",
34 | "typescript": "^4.3.5"
35 | },
36 | "dependencies": {
37 | "@types/json-stable-stringify": "^1.0.33",
38 | "crypto-browserify": "^3.12.0",
39 | "js-md5": "^0.7.3",
40 | "json-stable-stringify": "^1.0.1",
41 | "rollup-plugin-ignore": "^1.0.9",
42 | "rollup-plugin-node-builtins": "^2.1.2",
43 | "tslib": "^1.10.0",
44 | "typescript-json-schema": "^0.50.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import typescript from "@rollup/plugin-typescript";
2 | import node from "@rollup/plugin-node-resolve";
3 | import commonjs from "@rollup/plugin-commonjs";
4 | import json from "@rollup/plugin-json";
5 | import ignore from "rollup-plugin-ignore";
6 | import builtins from 'rollup-plugin-node-builtins';
7 |
8 | // You can have more root bundles by extending this array
9 | const rootFiles = ["index.ts"];
10 | import externalGlobals from "rollup-plugin-external-globals";
11 |
12 | export default rootFiles.map(name => {
13 | /** @type { import("rollup").RollupOptions } */
14 | const options = {
15 | input: `src/${name}`,
16 | external: ['typescript'],
17 | output: {
18 | paths: {
19 | "typescript":"typescript-sandbox/index",
20 | "fs.js":"typescript-sandbox/index",
21 | "path.js":"typescript-sandbox/index",
22 | },
23 | name,
24 | dir: "dist",
25 | format: "amd"
26 | },
27 | plugins: [ typescript({ tsconfig: "tsconfig.json" }), json(), ignore([ "ts-node", "fs"]) , externalGlobals({ typescript: "window.ts" }), commonjs(), node()]
28 | };
29 |
30 | return options;
31 | });
--------------------------------------------------------------------------------
/scripts/getDTS.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // Grab the DTS files from the TypeScript website
4 | // then do a bit of string manipulation in order to make it
5 | // compile without _all_ of the dependencies
6 |
7 | const nodeFetch = require("node-fetch").default
8 | const { writeFileSync, existsSync, mkdirSync } = require("fs")
9 | const { join } = require("path")
10 |
11 | const getFileAndStoreLocally = async (url, path, editFunc) => {
12 | const editingFunc = editFunc ? editFunc : text => text
13 | const packageJSON = await nodeFetch(url)
14 | const contents = await packageJSON.text()
15 | writeFileSync(join(__dirname, "..", path), editingFunc(contents), "utf8")
16 | }
17 |
18 | const go = async () => {
19 | const vendor = join("src", "vendor")
20 | const ds = join("src", "vendor", "ds")
21 |
22 | if (!existsSync(vendor)) mkdirSync(vendor)
23 | if (!existsSync(ds)) mkdirSync(ds)
24 |
25 | const host = "https://www.staging-typescript.org"
26 |
27 | // For playground-dev purposes
28 | // const host = "http://localhost:8000";
29 |
30 | // The API for the monaco typescript worker
31 | await getFileAndStoreLocally(host + "/js/sandbox/tsWorker.d.ts", join(vendor, "tsWorker.d.ts"))
32 |
33 | // The Design System DTS
34 | await getFileAndStoreLocally(
35 | host + "/js/playground/ds/createDesignSystem.d.ts",
36 | join(ds, "createDesignSystem.d.ts"),
37 | text => {
38 | const renameImport = text.replace("typescriptlang-org/static/js/sandbox", "../sandbox")
39 | return renameImport
40 | }
41 | )
42 |
43 | // Util funcs
44 | await getFileAndStoreLocally(host + "/js/playground/pluginUtils.d.ts", join(vendor, "pluginUtils.d.ts"), text => {
45 | const renameImport = text.replace('from "@typescript/sandbox"', 'from "./sandbox"')
46 | return renameImport
47 | })
48 |
49 | // TS-VFS
50 | await getFileAndStoreLocally(
51 | host + "/js/sandbox/vendor/typescript-vfs.d.ts",
52 | join(vendor, "typescript-vfs.d.ts"),
53 | text => {
54 | const removeImports = text.replace('/// ', "")
55 | const removedLZ = removeImports.replace('import("lz-string").LZStringStatic', "any")
56 | return removedLZ
57 | }
58 | )
59 |
60 | // Sandbox
61 | await getFileAndStoreLocally(host + "/js/sandbox/index.d.ts", join(vendor, "sandbox.d.ts"), text => {
62 | const removeImports = text.replace(/^import/g, "// import").replace(/\nimport/g, "\n// import")
63 | const replaceTSVFS = removeImports.replace(
64 | '// import * as tsvfs from "./vendor/typescript-vfs"',
65 | "\nimport * as tsvfs from './typescript-vfs'"
66 | )
67 | const removedLZ = replaceTSVFS.replace("lzstring: typeof lzstring", "// lzstring: typeof lzstring")
68 | const addedTsWorkerImport = 'import { TypeScriptWorker } from "./tsWorker";' + removedLZ
69 | return addedTsWorkerImport
70 | })
71 |
72 | // Playground
73 | await getFileAndStoreLocally(host + "/js/playground/index.d.ts", join(vendor, "/playground.d.ts"), text => {
74 | const replaceSandbox = text.replace('"@typescript/sandbox"', '"./sandbox"')
75 | const replaceTSVFS = replaceSandbox.replace(
76 | /typescriptlang-org\/static\/js\/sandbox\/vendor\/typescript-vfs/g,
77 | "./typescript-vfs"
78 | )
79 | const removedLZ = replaceTSVFS.replace("lzstring: typeof", "// lzstring: typeof")
80 | const removedWorker = removedLZ.replace("getWorkerProcess", "// getWorkerProcess")
81 | const removedUI = removedWorker.replace("ui:", "// ui:")
82 | return removedUI
83 | })
84 | }
85 |
86 | go()
87 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { PlaygroundPlugin, PluginUtils } from "./vendor/playground";
2 | import * as TJS from "./lib/typescript-json-schema";
3 |
4 | const makePlugin = (utils: PluginUtils) => {
5 | const customPlugin: PlaygroundPlugin = {
6 | id: "json-schema",
7 | displayName: "JSON Schema",
8 | didMount: (sandbox, container) => {
9 | // Create a design system object to handle
10 | // making DOM elements which fit the playground (and handle mobile/light/dark etc)
11 | const ds = utils.createDesignSystem(container);
12 |
13 | ds.title("TS -> JSON Schema");
14 | ds.p(
15 | "This plugin uses a custom build of YousefED/typescript-json-schema (at commit 20a03a2 to output the JSON schema version of your exported interfaces/types from the Playground editor."
16 | );
17 |
18 | const startButton = document.createElement("input");
19 | startButton.type = "button";
20 | startButton.value = "Convert to JSON Schema";
21 | container.appendChild(startButton);
22 |
23 | const div = document.createElement("div");
24 | const codeDS = utils.createDesignSystem(div);
25 | container.appendChild(div);
26 |
27 | startButton.onclick = async () => {
28 | const settings: TJS.PartialArgs = {
29 | ignoreErrors: true,
30 | };
31 |
32 | const program: any = await sandbox.createTSProgram();
33 | // We can either get the schema for one file and one type...
34 | const schema = TJS.generateSchema(program, "*", settings);
35 | codeDS.clear();
36 | codeDS.code(JSON.stringify(schema, null, " "));
37 | };
38 | },
39 |
40 | modelChangedDebounce: async (_sandbox, _model) => {
41 | // Do some work with the new text
42 | },
43 |
44 | // Gives you a chance to remove anything set up,
45 | // the container itself if wiped of children after this.
46 | didUnmount: () => {
47 | console.log("De-focusing plugin");
48 | },
49 | };
50 |
51 | return customPlugin;
52 | };
53 |
54 | export default makePlugin;
55 |
--------------------------------------------------------------------------------
/src/lib/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, typescript-json-schema contributors
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 |
8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 |
10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 |
--------------------------------------------------------------------------------
/src/lib/typescript-json-schema.ts:
--------------------------------------------------------------------------------
1 | // import * as glob from "glob";
2 | import stringify from "json-stable-stringify";
3 | // import * as path from "path";
4 | import md5 from "js-md5";
5 | import * as ts from "typescript";
6 | import type { JSONSchema7 } from "json-schema";
7 | export type { Program, CompilerOptions, Symbol } from "typescript";
8 |
9 | // const vm = require("vm");
10 |
11 | const REGEX_FILE_NAME_OR_SPACE = /(\bimport\(".*?"\)|".*?")\.| /g;
12 | const REGEX_TSCONFIG_NAME = /^.*\.json$/;
13 | const REGEX_TJS_JSDOC = /^-([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
14 | const REGEX_GROUP_JSDOC = /^[.]?([\w]+)\s+(\S|\S[\s\S]*\S)\s*$/g;
15 | /**
16 | * Resolve required file, his path and a property name,
17 | * pattern: require([file_path]).[property_name]
18 | *
19 | * the part ".[property_name]" is optional in the regex
20 | *
21 | * will match:
22 | *
23 | * require('./path.ts')
24 | * require('./path.ts').objectName
25 | * require("./path.ts")
26 | * require("./path.ts").objectName
27 | * require('@module-name')
28 | *
29 | * match[2] = file_path (a path to the file with quotes)
30 | * match[3] = (optional) property_name (a property name, exported in the file)
31 | *
32 | * for more details, see tests/require.test.ts
33 | */
34 | const REGEX_REQUIRE = /^(\s+)?require\((\'@?[a-zA-Z0-9.\/_-]+\'|\"@?[a-zA-Z0-9.\/_-]+\")\)(\.([a-zA-Z0-9_$]+))?(\s+|$)/;
35 | const NUMERIC_INDEX_PATTERN = "^[0-9]+$";
36 |
37 | export function getDefaultArgs(): Args {
38 | return {
39 | ref: true,
40 | aliasRef: false,
41 | topRef: false,
42 | titles: false,
43 | defaultProps: false,
44 | noExtraProps: false,
45 | propOrder: false,
46 | typeOfKeyword: false,
47 | required: false,
48 | strictNullChecks: false,
49 | ignoreErrors: false,
50 | out: "",
51 | validationKeywords: [],
52 | include: [],
53 | excludePrivate: false,
54 | uniqueNames: false,
55 | rejectDateType: false,
56 | id: "",
57 | defaultNumberType: "number",
58 | tsNodeRegister: false,
59 | };
60 | }
61 |
62 | export type ValidationKeywords = {
63 | [prop: string]: boolean;
64 | };
65 |
66 | export type Args = {
67 | ref: boolean;
68 | aliasRef: boolean;
69 | topRef: boolean;
70 | titles: boolean;
71 | defaultProps: boolean;
72 | noExtraProps: boolean;
73 | propOrder: boolean;
74 | typeOfKeyword: boolean;
75 | required: boolean;
76 | strictNullChecks: boolean;
77 | ignoreErrors: boolean;
78 | out: string;
79 | validationKeywords: string[];
80 | include: string[];
81 | excludePrivate: boolean;
82 | uniqueNames: boolean;
83 | rejectDateType: boolean;
84 | id: string;
85 | defaultNumberType: "number" | "integer";
86 | tsNodeRegister: boolean;
87 | };
88 |
89 | export type PartialArgs = Partial;
90 |
91 | export type PrimitiveType = number | boolean | string | null;
92 |
93 | type RedefinedFields =
94 | | "type"
95 | | "items"
96 | | "additionalItems"
97 | | "contains"
98 | | "properties"
99 | | "patternProperties"
100 | | "additionalProperties"
101 | | "dependencies"
102 | | "propertyNames"
103 | | "if"
104 | | "then"
105 | | "else"
106 | | "allOf"
107 | | "anyOf"
108 | | "oneOf"
109 | | "not"
110 | | "definitions";
111 | export type DefinitionOrBoolean = Definition | boolean;
112 | export interface Definition extends Omit {
113 | // The type field here is incompatible with the standard definition
114 | type?: string | string[];
115 |
116 | // Non-standard fields
117 | propertyOrder?: string[];
118 | defaultProperties?: string[];
119 | typeof?: "function";
120 |
121 | // Fields that must be redefined because they make use of this definition itself
122 | items?: DefinitionOrBoolean | DefinitionOrBoolean[];
123 | additionalItems?: DefinitionOrBoolean;
124 | contains?: JSONSchema7;
125 | properties?: {
126 | [key: string]: DefinitionOrBoolean;
127 | };
128 | patternProperties?: {
129 | [key: string]: DefinitionOrBoolean;
130 | };
131 | additionalProperties?: DefinitionOrBoolean;
132 | dependencies?: {
133 | [key: string]: DefinitionOrBoolean | string[];
134 | };
135 | propertyNames?: DefinitionOrBoolean;
136 | if?: DefinitionOrBoolean;
137 | then?: DefinitionOrBoolean;
138 | else?: DefinitionOrBoolean;
139 | allOf?: DefinitionOrBoolean[];
140 | anyOf?: DefinitionOrBoolean[];
141 | oneOf?: DefinitionOrBoolean[];
142 | not?: DefinitionOrBoolean;
143 | definitions?: {
144 | [key: string]: DefinitionOrBoolean;
145 | };
146 | }
147 |
148 | export type SymbolRef = {
149 | name: string;
150 | typeName: string;
151 | fullyQualifiedName: string;
152 | symbol: ts.Symbol;
153 | };
154 |
155 | function extend(target: any, ..._: any[]): any {
156 | if (target == null) {
157 | // TypeError if undefined or null
158 | throw new TypeError("Cannot convert undefined or null to object");
159 | }
160 |
161 | const to = Object(target);
162 |
163 | for (var index = 1; index < arguments.length; index++) {
164 | const nextSource = arguments[index];
165 |
166 | if (nextSource != null) {
167 | // Skip over if undefined or null
168 | for (const nextKey in nextSource) {
169 | // Avoid bugs when hasOwnProperty is shadowed
170 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
171 | to[nextKey] = nextSource[nextKey];
172 | }
173 | }
174 | }
175 | }
176 | return to;
177 | }
178 |
179 | function unique(arr: string[]): string[] {
180 | const temp = {};
181 | for (const e of arr) {
182 | temp[e] = true;
183 | }
184 | const r: string[] = [];
185 | for (const k in temp) {
186 | // Avoid bugs when hasOwnProperty is shadowed
187 | if (Object.prototype.hasOwnProperty.call(temp, k)) {
188 | r.push(k);
189 | }
190 | }
191 | return r;
192 | }
193 |
194 | /**
195 | * Resolve required file
196 | */
197 | function resolveRequiredFile(symbol: ts.Symbol, key: string, fileName: string, objectName: string): any {
198 | const sourceFile = getSourceFile(symbol);
199 | const requiredFilePath = fileName // /^[.\/]+/.test(fileName)
200 | // ? fileName === "."
201 | // ? path.resolve(sourceFile.fileName)
202 | // : path.resolve(path.dirname(sourceFile.fileName), fileName)
203 | // : fileName;
204 | const requiredFile = require(requiredFilePath);
205 | if (!requiredFile) {
206 | throw Error("Required: File couldn't be loaded");
207 | }
208 | const requiredObject = objectName ? requiredFile[objectName] : requiredFile.default;
209 | if (requiredObject === undefined) {
210 | throw Error("Required: Variable is undefined");
211 | }
212 | if (typeof requiredObject === "function") {
213 | throw Error("Required: Can't use function as a variable");
214 | }
215 | if (key === "examples" && !Array.isArray(requiredObject)) {
216 | throw Error("Required: Variable isn't an array");
217 | }
218 | return requiredObject;
219 | }
220 |
221 | export function regexRequire(value: string) {
222 | return REGEX_REQUIRE.exec(value);
223 | }
224 |
225 | /**
226 | * Try to parse a value and returns the string if it fails.
227 | */
228 | function parseValue(symbol: ts.Symbol, key: string, value: string): any {
229 | const match = regexRequire(value);
230 | if (match) {
231 | const fileName = match[2].substr(1, match[2].length - 2).trim();
232 | const objectName = match[4];
233 | return resolveRequiredFile(symbol, key, fileName, objectName);
234 | }
235 | try {
236 | return JSON.parse(value);
237 | } catch (error) {
238 | return value;
239 | }
240 | }
241 |
242 | function extractLiteralValue(typ: ts.Type): PrimitiveType | undefined {
243 | let str = (typ).value;
244 | if (str === undefined) {
245 | str = (typ as any).text;
246 | }
247 | if (typ.flags & ts.TypeFlags.StringLiteral) {
248 | return str as string;
249 | } else if (typ.flags & ts.TypeFlags.BooleanLiteral) {
250 | return (typ as any).intrinsicName === "true";
251 | } else if (typ.flags & ts.TypeFlags.EnumLiteral) {
252 | // or .text for old TS
253 | const num = parseFloat(str as string);
254 | return isNaN(num) ? (str as string) : num;
255 | } else if (typ.flags & ts.TypeFlags.NumberLiteral) {
256 | return parseFloat(str as string);
257 | }
258 | return undefined;
259 | }
260 |
261 | /**
262 | * Checks whether a type is a tuple type.
263 | */
264 | function resolveTupleType(propertyType: ts.Type): ts.TupleTypeNode | null {
265 | if (
266 | !propertyType.getSymbol() &&
267 | propertyType.getFlags() & ts.TypeFlags.Object &&
268 | (propertyType).objectFlags & ts.ObjectFlags.Reference
269 | ) {
270 | return (propertyType as ts.TypeReference).target as any;
271 | }
272 | if (
273 | !(
274 | propertyType.getFlags() & ts.TypeFlags.Object &&
275 | (propertyType).objectFlags & ts.ObjectFlags.Tuple
276 | )
277 | ) {
278 | return null;
279 | }
280 | return propertyType as any;
281 | }
282 |
283 | const simpleTypesAllowedProperties = {
284 | type: true,
285 | description: true,
286 | };
287 |
288 | function addSimpleType(def: Definition, type: string): boolean {
289 | for (const k in def) {
290 | if (!simpleTypesAllowedProperties[k]) {
291 | return false;
292 | }
293 | }
294 |
295 | if (!def.type) {
296 | def.type = type;
297 | } else if (typeof def.type !== "string") {
298 | if (
299 | !(