├── .eslintrc ├── .gitignore ├── .stylelintrc.json ├── README.md ├── doc.js ├── index.html ├── misc ├── comment-parse.js ├── doxxx.js ├── microsoft-tsdoc.js ├── package-lock.json ├── package.json ├── react-parser │ ├── README.md │ ├── index.js │ ├── loader.js │ ├── package-lock.json │ ├── package.json │ └── test.js └── typescript-parse.js ├── package-lock.json ├── package.json ├── parser-test.js ├── parser.js ├── pnpm-lock.yaml ├── postcss.config.js ├── scripts └── getdocs.js ├── src ├── 0.1_Button_PropTypes_Function │ └── index.jsx ├── 0_Button_PropTypes_Class │ └── index.jsx ├── 0_Button_PropTypes_Function │ └── index.jsx ├── 1_Button_JSDoc_Simple │ └── index.jsx ├── 2.1_Button_JSDoc_Function_Extend │ └── index.jsx ├── 2.2_Button_JSDoc_Function_Ref │ └── index.jsx ├── 2.2_Button_JSDoc_Hooks │ └── index.jsx ├── 2_Button_JSDoc_TypeDef_Function │ └── index.jsx ├── 3_Button_JSDoc_TypeDef_Class │ └── index.jsx ├── 4_Button_JSDoc_ImportedTypes │ ├── index.jsx │ ├── large.ts │ └── tiny.ts ├── 5_Button_JSDoc_ImportedTypes_React │ ├── index.jsx │ └── usefulTypes.ts ├── 6_List_TypeScript │ └── index.tsx ├── 7_Context │ └── index.tsx ├── 8_PolymorphicComponent │ └── index.tsx ├── App.css ├── App.tsx ├── Card │ └── index.jsx ├── TodoList │ ├── index.tsx │ └── xyz.module.css ├── __generated │ └── .gitkeep ├── __tests__ │ ├── index.test.js │ ├── misc │ │ ├── _initJSDom.js │ │ ├── _setup-tests.js │ │ └── utils.js │ ├── simple │ │ └── x.test.js │ └── withJsDom │ │ └── y.test.js ├── favicon.svg ├── index.css ├── logo.svg ├── main.tsx ├── utils │ ├── 0_@author.js │ ├── 0_@default.js │ ├── 0_@deprecated.js │ ├── 0_@description.js │ ├── 0_@example.js │ ├── 0_@extends.js │ ├── 0_@license.js │ ├── 0_@link.js │ ├── 0_@module.js │ ├── 0_@module2.js │ ├── 0_@name.js │ ├── 0_@namespace.js │ ├── 0_@param.js │ ├── 0_@remarks.js │ ├── 0_@schema.js │ ├── 0_@see.js │ ├── 0_@summary.js │ ├── 0_@template.js │ ├── 0_@this.js │ ├── 0_@type.js │ ├── 0_@typedef.js │ ├── 0__other_tags.js │ ├── 0_captions.js │ ├── 0_images.js │ ├── 0_primatives.js │ ├── 0_typeof.js │ ├── 1_array.js │ ├── 1_class.js │ ├── 1_enum.js │ ├── 1_functions.js │ ├── 1_htmlNodes.js │ ├── 1_map.js │ ├── 1_object.js │ ├── 1_objectz-shorthand.js │ ├── 1_set.js │ ├── 2_buffer.js │ ├── 2_event-listener.js │ ├── 2_imports-commonJS.js │ ├── 2_imports-ts.js │ ├── 2_imports-ts2-refs.js │ ├── 2_overload.js │ ├── 2_overload.ts │ ├── 2_typecasting.js │ ├── 2_typeof-reference.js │ ├── 2_union.js │ ├── asserts.js │ ├── balena.js │ ├── calculator.js │ ├── camel-case.js │ ├── class-extend.js │ ├── class-private-func.js │ ├── class-private-proto.js │ ├── constants.js │ ├── contentful-types.ts │ ├── contentful.js │ ├── example-three.js │ ├── examples-two.js │ ├── examples.js │ ├── examples │ │ ├── auth.js │ │ ├── example-klasa.js │ │ ├── f-ck.js │ │ ├── http-headers.ts │ │ ├── import-defs │ │ │ ├── api-type-definitions-usage.js │ │ │ ├── api-type-definitions.js │ │ │ ├── import-example-usage-five.js │ │ │ ├── import-example-usage-four.js │ │ │ ├── import-example-usage-seven.js │ │ │ ├── import-example-usage-six.js │ │ │ ├── import-example-usage-three.js │ │ │ ├── import-example-usage-two.js │ │ │ ├── import-example-usage.js │ │ │ ├── import-example-with-export.js │ │ │ ├── import-example-with-module-exports.js │ │ │ ├── import-example-with-no-export.js │ │ │ └── import-example.js │ │ ├── inferred-param.ts │ │ ├── inline.js │ │ ├── json-types.ts │ │ ├── oauth │ │ │ ├── oauth.js │ │ │ └── types.js │ │ ├── open-api.ts │ │ ├── rbac │ │ │ └── index.ts │ │ ├── react-class.js │ │ ├── react-render-props.js │ │ ├── reverse-record.js │ │ ├── snakecase.js │ │ ├── split.js │ │ ├── ts-json.ts │ │ ├── webapp.js │ │ └── xyz │ │ │ ├── types.js │ │ │ └── xyz.js │ ├── generics.js │ ├── ignore-example.js │ ├── imports │ │ ├── my-js-file.js │ │ ├── my.d.ts │ │ └── ts-types.ts │ ├── invert.ts │ ├── jsdoc-module.js │ ├── simple-jsdoc-generics.js │ ├── type-examples │ │ ├── dot-notation.ts │ │ └── tyoe-utils.ts │ ├── typedef-div-extend.js │ ├── typedef-extend.js │ ├── types.d.ts │ ├── xyz.js │ └── zpegasus.js ├── vite-env.d.ts └── zod │ ├── autozod.ts │ ├── example-js.js │ ├── example.ts │ └── types.d.ts ├── ts-to-zod.config.js ├── tsconfig.json ├── typedoc.json └── vite.config.ts /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "ecmaVersion": 2020, 5 | "sourceType": "module", 6 | "ecmaFeatures": { 7 | "jsx": true 8 | } 9 | }, 10 | "env": { 11 | "es6": true 12 | }, 13 | "plugins": [ 14 | "jsdoc" 15 | ], 16 | "extends": [], 17 | "rules": {} 18 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | _misc 9 | misc/structured-types 10 | docs 11 | # Auto generated zod files 12 | src/__generated/**/** 13 | src/**/**/*.validate.js 14 | 15 | # Ignore auto generated json schema files 16 | src/**/**/*.schema.json 17 | 18 | # Ignore Auto generated types, except types.d.ts files 19 | src/**/**/*.d.ts 20 | !src/**/**/types.d.ts 21 | !src/utils/imports/my.d.ts 22 | 23 | # Ignore Auto generated CSS types 24 | src/**/**/*.css.d.ts 25 | src/**/**/*.module.css.d.ts 26 | 27 | coverage-ts 28 | dist 29 | 30 | # Runtime data 31 | pids 32 | *.pid 33 | *.seed 34 | *.pid.lock 35 | 36 | # Directory for instrumented libs generated by jscoverage/JSCover 37 | lib-cov 38 | 39 | # Coverage directory used by tools like istanbul 40 | coverage 41 | 42 | # nyc test coverage 43 | .nyc_output 44 | 45 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 46 | .grunt 47 | 48 | # Bower dependency directory (https://bower.io/) 49 | bower_components 50 | 51 | # node-waf configuration 52 | .lock-wscript 53 | 54 | # Compiled binary addons (https://nodejs.org/api/addons.html) 55 | build/Release 56 | 57 | # Dependency directories 58 | node_modules/ 59 | jspm_packages/ 60 | 61 | # TypeScript v1 declaration files 62 | typings/ 63 | 64 | # Optional npm cache directory 65 | .npm 66 | 67 | # Optional eslint cache 68 | .eslintcache 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variables file 80 | .env 81 | .env.test 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | 86 | # next.js build output 87 | .next 88 | 89 | # nuxt.js build output 90 | .nuxt 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # General 105 | .DS_Store 106 | .AppleDouble 107 | .LSOverride 108 | 109 | # Icon must end with two \r 110 | Icon 111 | 112 | 113 | # Thumbnails 114 | ._* 115 | 116 | # Files that might appear in the root of a volume 117 | .DocumentRevisions-V100 118 | .fseventsd 119 | .Spotlight-V100 120 | .TemporaryItems 121 | .Trashes 122 | .VolumeIcon.icns 123 | .com.apple.timemachine.donotpresent 124 | 125 | # Directories potentially created on remote AFP share 126 | .AppleDB 127 | .AppleDesktop 128 | Network Trash Folder 129 | Temporary Items 130 | .apdisk -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "plugins": [ 4 | "stylelint-no-unused-selectors" 5 | ], 6 | "rules": { 7 | "declaration-no-important": true, 8 | "color-hex-case": "upper", 9 | "indentation": 2, 10 | "plugin/no-unused-selectors": [ true, { "severity": "warning" }], 11 | "no-eol-whitespace": null, 12 | "no-missing-end-of-source-newline": null 13 | } 14 | } -------------------------------------------------------------------------------- /doc.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const dox = require('doxxx') 4 | 5 | 6 | // const filePath = path.resolve(__dirname, 'src/1_Button_JSDoc_Simple/index.jsx') 7 | // const filePath = path.resolve(__dirname, 'src/2_Button_JSDoc_TypeDef_Function/index.jsx') 8 | // const filePath = path.resolve(__dirname, 'src/2.1_Button_JSDoc_Function_Extend/index.jsx') 9 | // const filePath = path.resolve(__dirname, 'src/3_Button_JSDoc_TypeDef_Class/index.jsx') 10 | // const filePath = path.resolve(__dirname, 'src/4_Button_JSDoc_ImportedTypes/index.jsx') 11 | const filePath = path.resolve(__dirname, 'src/5_Button_JSDoc_ImportedTypes_React/index.jsx') 12 | 13 | const fileCode = fs.readFileSync(filePath, 'utf-8') 14 | const obj = dox.parseComments(fileCode) 15 | const { inspect } = require('util') 16 | console.log('result') 17 | console.log(inspect(obj, {showHidden: false, depth: null})) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /misc/comment-parse.js: -------------------------------------------------------------------------------- 1 | const { parse, tokenizers } = require('comment-parser/lib') 2 | 3 | // const source = ` 4 | // /** 5 | // * Description may go 6 | // * over few lines followed by @tags 7 | // * @param {string} name the name parameter 8 | // * @param {any} value the value of any type 9 | // */` 10 | 11 | const source = ` 12 | /** 13 | * Renders a 25 | */ 26 | export default function Button(props = {}) { 27 | return ( 28 | 29 | ) 30 | }` 31 | 32 | const parsed = parse(source, { 33 | spacing: 'preserve', 34 | tokenizers: [tokenizers.tag(), tokenizers.description('preserve')], 35 | trim: false 36 | }) 37 | 38 | const { inspect } = require('util') 39 | console.log(inspect(parsed, {showHidden: false, depth: null})) -------------------------------------------------------------------------------- /misc/doxxx.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const dox = require('doxxx') 4 | 5 | var code = ` 6 | /** 7 | * tester 8 | * @template T 9 | * @extends {Set} 10 | * @example 11 | * lol() 12 | * console.log('hi') 13 | */ 14 | class SortableSet extends Set { 15 | // ... 16 | } 17 | 18 | 19 | /** 20 | * Does xyz 21 | * @returns {Promise<{ 22 | * pass: number, 23 | * fail: number 24 | * }>} 25 | */ 26 | async function run() { 27 | return Promise.resolve({ 28 | pass: 1, 29 | fail: 3 30 | }) 31 | } 32 | 33 | 34 | /** 35 | * Renders a 47 | */ 48 | export default function Button(props = {}) { 49 | return ( 50 | 51 | ) 52 | } 53 | `; 54 | 55 | var codeTwo = ` 56 | interface User { 57 | name: string; 58 | id: number; 59 | } 60 | 61 | /** 62 | * Renders a 95 | ) 96 | ` 97 | 98 | // const filePath = path.resolve(__dirname, '../src/1_Button_SimpleJSdoc/index.jsx') 99 | // const fileCode = fs.readFileSync(filePath, 'utf-8') 100 | const obj = dox.parseComments(code); 101 | const { inspect } = require('util') 102 | console.log('result') 103 | console.log(inspect(obj, {showHidden: false, depth: null})) -------------------------------------------------------------------------------- /misc/microsoft-tsdoc.js: -------------------------------------------------------------------------------- 1 | const { TSDocParser, ParserContext, DocComment, DocNode, DocExcerpt } = require('@microsoft/tsdoc'); 2 | 3 | 4 | const fs = require('fs') 5 | const path = require('path') 6 | const os = require('os') 7 | 8 | const inputFilename = path.resolve(__dirname, '../src/6_List_TSProps/index.tsx') 9 | const code = fs.readFileSync(inputFilename, 'utf-8') 10 | 11 | const tsdocParser = new TSDocParser(); 12 | const parserContext = tsdocParser.parseString(code); 13 | 14 | 15 | /** 16 | * This is a simplistic solution until we implement proper DocNode rendering APIs. 17 | */ 18 | class Formatter { 19 | static renderDocNode(docNode) { 20 | let result = ''; 21 | if (docNode) { 22 | if (docNode instanceof DocExcerpt) { 23 | result += docNode.content.toString(); 24 | } 25 | for (const childNode of docNode.getChildNodes()) { 26 | result += Formatter.renderDocNode(childNode); 27 | } 28 | } 29 | return result; 30 | } 31 | 32 | static renderDocNodes(docNodes){ 33 | let result = ''; 34 | for (const docNode of docNodes) { 35 | result += Formatter.renderDocNode(docNode); 36 | } 37 | return result; 38 | } 39 | } 40 | 41 | const colors = { 42 | green: (d) => d, 43 | cyan: (d) => d 44 | } 45 | 46 | console.log(os.EOL + colors.green('Extracted Lines:') + os.EOL); 47 | console.log( 48 | JSON.stringify( 49 | parserContext.lines.map((x) => x.toString()), 50 | undefined, 51 | ' ' 52 | ) 53 | ); 54 | 55 | console.log(os.EOL + colors.green('Parser Log Messages:') + os.EOL); 56 | 57 | if (parserContext.log.messages.length === 0) { 58 | console.log('No errors or warnings.'); 59 | } else { 60 | for (const message of parserContext.log.messages) { 61 | console.log(inputFilename + message.toString()); 62 | } 63 | } 64 | 65 | console.log(os.EOL + colors.green('DocComment parts:') + os.EOL); 66 | 67 | const docComment = parserContext.docComment; 68 | 69 | console.log(colors.cyan('Summary: ') + JSON.stringify(Formatter.renderDocNode(docComment.summarySection))); 70 | 71 | if (docComment.remarksBlock) { 72 | console.log( 73 | colors.cyan('Remarks: ') + JSON.stringify(Formatter.renderDocNode(docComment.remarksBlock.content)) 74 | ); 75 | } 76 | 77 | for (const paramBlock of docComment.params.blocks) { 78 | console.log( 79 | colors.cyan(`Parameter "${paramBlock.parameterName}": `) + 80 | JSON.stringify(Formatter.renderDocNode(paramBlock.content)) 81 | ); 82 | } 83 | 84 | if (docComment.returnsBlock) { 85 | console.log( 86 | colors.cyan('Returns: ') + JSON.stringify(Formatter.renderDocNode(docComment.returnsBlock.content)) 87 | ); 88 | } 89 | 90 | console.log(colors.cyan('Modifiers: ') + docComment.modifierTagSet.nodes.map((x) => x.tagName).join(', ')); 91 | const { inspect } = require('util') 92 | // console.log('result') 93 | // console.log(inspect(parserContext, {showHidden: false, depth: null})) 94 | -------------------------------------------------------------------------------- /misc/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comment-parser-tests", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@microsoft/tsdoc": { 8 | "version": "0.13.2", 9 | "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", 10 | "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", 11 | "dev": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /misc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comment-parser-tests", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "DavidWells", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@microsoft/tsdoc": "^0.13.2", 15 | "@types/react": "^17.0.9", 16 | "@types/react-dom": "^17.0.6", 17 | "comment-parser": "^1.1.5", 18 | "doxxx": "^1.0.0", 19 | "ts-to-zod": "^1.3.0", 20 | "type-coverage": "^2.17.5", 21 | "type-fest": "^1.2.2", 22 | "typescript": "^4.3.2", 23 | "typescript-coverage-report": "^0.6.0", 24 | "typescript-json-schema": "^0.50.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /misc/react-parser/README.md: -------------------------------------------------------------------------------- 1 | Prop type parser. 2 | 3 | - [x] Handles propTypes 4 | - [x] Handles typescript types 5 | - [ ] Doesn't handle JSdocs 6 | -------------------------------------------------------------------------------- /misc/react-parser/index.js: -------------------------------------------------------------------------------- 1 | // const ts = require('typescript') 2 | const ReactDocGen = require('react-docgen') 3 | const ReactDocGenTS = require('react-docgen-typescript') 4 | const doctrine = require('doctrine') 5 | const fs = require('fs') 6 | const path = require('path') 7 | const deIndent = require('de-indent') 8 | 9 | /** 10 | * Parse JSDoc from prop description. 11 | * 12 | * @param {Prop} prop 13 | * @returns {Prop} 14 | */ 15 | function prepareProp(prop) { 16 | if (prop.description) { 17 | const meta = doctrine.parse(prop.description) 18 | 19 | prop.description = meta.description 20 | 21 | meta.tags.forEach(({ title, description, ...tag }) => { 22 | prop[title] = description || true 23 | }) 24 | } 25 | 26 | delete prop.parent 27 | 28 | return prop 29 | } 30 | 31 | function parseTS(file, source) { 32 | return ReactDocGenTS.withDefaultConfig({ 33 | propFilter: { 34 | skipPropsWithName: ['className'], 35 | }, 36 | componentNameResolver(exp, src) { 37 | if (exp.name === 'default') { 38 | return path 39 | .basename(file) 40 | .replace(/\.tsx/, '') 41 | .replace(/(?:^|-)([a-z])/g, (_, c) => c.toUpperCase()) 42 | } 43 | }, 44 | }).parse(file)[0] 45 | } 46 | 47 | function parseJS(file, source) { 48 | return ReactDocGen.parse(source) 49 | } 50 | 51 | /** 52 | * Parse file to JSDoc Meta 53 | * @argument {string} filename 54 | * @argument {string=} source 55 | * @returns {JSDocMeta} 56 | */ 57 | module.exports = function parse(file, source, root = process.cwd()) { 58 | const isTS = /\.tsx$/.test(file) 59 | source = source || fs.readFileSync(file) 60 | 61 | const meta = isTS ? parseTS(file, source) : parseJS(file, source) 62 | 63 | if (!meta) throw new Error('Failed to parse ' + file) 64 | 65 | const docs = doctrine.parse(meta.description) 66 | 67 | meta.description = docs.description 68 | 69 | docs.tags.forEach((tag) => { 70 | if (tag.title === 'example') { 71 | meta[tag.title] = meta[tag.title] || [] 72 | meta[tag.title].push(deIndent(tag.description)) 73 | } else meta[tag.title] = tag.description 74 | }) 75 | 76 | if (meta.methods) { 77 | meta.methods.forEach((method) => { 78 | const doc = doctrine.parse(method.docblock || '') 79 | delete method.docblock 80 | method.private = !doc.tags.some((tag) => tag.title === 'public') 81 | }) 82 | } 83 | 84 | meta.props = Object.entries(meta.props || {}).reduce( 85 | (acc, [name, prop]) => acc.concat([{ name, ...prepareProp(prop) }]), 86 | [] 87 | ) 88 | meta.name = 89 | meta.displayName || meta.name || path.basename(file).replace(/\.jsx?$/, '') 90 | meta.file = path.relative(root, file) 91 | 92 | return meta 93 | } 94 | 95 | /** @typedef {{value: string, computed: boolean}} PropValue */ 96 | /** @typedef {{name: string, value?: any, raw?: string}} PropType */ 97 | /** @typedef {{name: string, type: PropType, defaultValue?: PropValue, required: boolean, description: string?, private?: boolean}} Prop */ 98 | /** @typedef {{name: string, description: string?, version: string, status: string, props: Array}} JSDocMeta */ 99 | -------------------------------------------------------------------------------- /misc/react-parser/loader.js: -------------------------------------------------------------------------------- 1 | const { getOptions } = require('loader-utils') 2 | 3 | const docgen = require('./index') 4 | 5 | const EXPORT = /export\s+default\s+(?:class\s+|function\s*|)([A-Za-z0-9]+)/ 6 | 7 | module.exports = async function DocGenLoader(source) { 8 | const callback = this.async() 9 | const { resourcePath } = this 10 | const options = { 11 | test: /./, 12 | root: process.cwd(), 13 | ...getOptions(this), 14 | } 15 | 16 | if (/\.(jsx|tsx)$/.test(resourcePath) && options.test.test(resourcePath)) { 17 | try { 18 | const meta = docgen(resourcePath, source, options.root) 19 | const docs = `\nconst __docs__ = ${JSON.stringify( 20 | meta, 21 | null, 22 | 2 23 | )}`.replace( 24 | /"--\{computed\}-->(.*)<--\{computed\}--"/g, 25 | (_, code) => code 26 | ) 27 | 28 | const matches = EXPORT.exec(source) 29 | 30 | if (matches) { 31 | source = source + docs + `\n${matches[1]}.__docs = __docs__\n` 32 | } 33 | } catch (error) { 34 | this.emitError(new Error(resourcePath + ' in ' + error.message)) 35 | } 36 | } 37 | 38 | callback(null, source) 39 | } 40 | -------------------------------------------------------------------------------- /misc/react-parser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-docgen", 3 | "version": "0.0.1", 4 | "license": "MIT", 5 | "main": "src/index.js", 6 | "module": "dist/docgen.esm.js", 7 | "sideEffects": false, 8 | "types": "dist/index.d.ts", 9 | "dependencies": { 10 | "de-indent": "^1.0.2", 11 | "doctrine": "^2.1.0", 12 | "loader-utils": "^1.2.3", 13 | "lodash.camelcase": "^4.3.0", 14 | "react-docgen": "^2.20.1", 15 | "react-docgen-typescript": "^1.12.3", 16 | "typescript": "^3.3.3333" 17 | }, 18 | "files": [ 19 | "src/", 20 | "dist/", 21 | "bin/", 22 | "loader.js" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /misc/react-parser/test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const parse = require('./index') 4 | 5 | let file 6 | file = path.resolve(__dirname, '../../src/0_Button_PropTypes_Class/index.jsx') 7 | file = path.resolve(__dirname, '../../src/0_Button_PropTypes_Function/index.jsx') 8 | 9 | 10 | // file = path.resolve(__dirname, '../../src/1_Button_JSDoc_Simple/index.jsx') 11 | // file = path.resolve(__dirname, '../../src/2_Button_JSDoc_TypeDef_Function/index.jsx') 12 | // file = path.resolve(__dirname, '../../src/2.1_Button_JSDoc_Function_Extend/index.jsx') 13 | // file = path.resolve(__dirname, '../../src/3_Button_JSDoc_TypeDef_Class/index.jsx') 14 | // file = path.resolve(__dirname, '../../src/4_Button_JSDoc_ImportedTypes/index.jsx') 15 | // file = path.resolve(__dirname, '../../src/5_Button_JSDoc_ImportedTypes_React/index.jsx') 16 | // file = path.resolve(__dirname, '../../src/6_List_TypeScript/index.tsx') 17 | 18 | const x = parse(file) 19 | console.log('x', x) -------------------------------------------------------------------------------- /misc/typescript-parse.js: -------------------------------------------------------------------------------- 1 | const ts = require('typescript'); 2 | 3 | const PROPERTY_TYPES = { 4 | any: ts.SyntaxKind.AnyKeyword, 5 | boolean: ts.SyntaxKind.BooleanKeyword, 6 | number: ts.SyntaxKind.NumberKeyword, 7 | string: ts.SyntaxKind.StringKeyword, 8 | }; 9 | class TSNode { 10 | constructor(name, type) { 11 | this.children = []; 12 | this.addChildren = (name, type) => { 13 | let node = new TSNode(name, type); 14 | this.children.push(node); 15 | return node; 16 | }; 17 | this.getType = () => this.type; 18 | this.getObject = () => { 19 | let map = {}; 20 | map[this.name] = this.children.length 21 | ? this.children 22 | .map(child => child.getObject()) 23 | .reduce((pv, child) => { 24 | for (let key in child) { 25 | if (pv.hasOwnProperty(key) || key in pv) { 26 | Object.assign(pv[key], child[key]); 27 | } else { 28 | pv[key] = child[key]; 29 | } 30 | } 31 | return pv; 32 | }, {}) 33 | : this.type; 34 | return map; 35 | }; 36 | this.name = name; 37 | this.type = type; 38 | } 39 | } 40 | let visit = parent => node => { 41 | switch (node.kind) { 42 | case ts.SyntaxKind.ModuleDeclaration: 43 | let moduleName = node.name.text; 44 | ts.forEachChild(node, visit(parent.addChildren(moduleName))); 45 | break; 46 | case ts.SyntaxKind.ModuleBlock: 47 | ts.forEachChild(node, visit(parent)); 48 | break; 49 | case ts.SyntaxKind.InterfaceDeclaration: 50 | let interfaceName = node.name.text; 51 | parent[interfaceName] = {}; 52 | // console.log('interface'); 53 | ts.forEachChild(node, visit(parent.addChildren(interfaceName))); 54 | break; 55 | case ts.SyntaxKind.PropertySignature: 56 | let propertyName = node.name; 57 | let propertyType = node.type; 58 | let arrayDeep = 0; 59 | let realPropertyName = 60 | 'string' !== typeof propertyName && 'text' in propertyName 61 | ? propertyName.text 62 | : propertyName; 63 | while (propertyType.kind === ts.SyntaxKind.ArrayType) { 64 | arrayDeep++; 65 | propertyType = propertyType.elementType; 66 | } 67 | if (propertyType.kind === ts.SyntaxKind.TypeReference) { 68 | let realPropertyType = propertyType.typeName; 69 | parent.addChildren( 70 | realPropertyName, 71 | 'Array<'.repeat(arrayDeep) + 72 | (realPropertyType.kind === ts.SyntaxKind.QualifiedName 73 | ? realPropertyType.getText() 74 | : 'text' in realPropertyType 75 | ? realPropertyType.text 76 | : realPropertyType) + 77 | '>'.repeat(arrayDeep) 78 | ); 79 | } else { 80 | for (let type in PROPERTY_TYPES) { 81 | if (propertyType.kind === PROPERTY_TYPES[type]) { 82 | parent.addChildren(realPropertyName, type); 83 | break; 84 | } 85 | } 86 | } 87 | break; 88 | default: 89 | } 90 | }; 91 | 92 | function tsParse(filename, options) { 93 | const ROOT_NAME = 'root'; 94 | const node = new TSNode(ROOT_NAME); 95 | 96 | let program = ts.createProgram([filename], options); 97 | let checker = program.getTypeChecker(); 98 | let sourceFile = program.getSourceFiles()[1]; 99 | 100 | ts.forEachChild(sourceFile, visit(node)); 101 | 102 | return node.getObject()[ROOT_NAME]; 103 | }; 104 | 105 | 106 | const fs = require('fs') 107 | const path = require('path') 108 | 109 | const inputFilename = path.resolve(__dirname, '../src/6_List_TSProps/index.tsx') 110 | 111 | const x = tsParse(inputFilename, {}) 112 | console.log('x', x) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "scripts": { 4 | "start": "concurrently 'npm:watch:*' 'npm:vite'", 5 | "watch:css": "npm run types:css -- --watch", 6 | "watch:zod": "npm run types:zod -- --watch", 7 | "vite": "vite", 8 | "prebuild": "npm run generate", 9 | "build": "tsc && vite build", 10 | "build-no-types": "vite build", 11 | "build:types": "tcm src --camelCase", 12 | "build:vite": "tsc && vite build", 13 | "serve": "vite preview", 14 | "test": "uvu -r @swc-node/register -r global-jsdom/register -r mock-css-modules --ignore misc src/__tests__", 15 | "test2": "uvu -r @swc-node/register -r mock-css-modules --ignore misc src/__tests__", 16 | "test3": "uvu -r @swc-node/register -r global-jsdom/register -r mock-css-modules --ignore misc src/__tests__/simple", 17 | "test4": "uvu -r @swc-node/register -r mock-css-modules --ignore misc src/__tests__/withJsDom", 18 | "type-coverage": "type-coverage --detail --strict --at-least 90 --ignore-files 'test/*'", 19 | "ts-coverage": "typescript-coverage-report", 20 | "types": "concurrently 'npm:types:*'", 21 | "types:dts": "tsc --noEmit false --emitDeclarationOnly true", 22 | "types:css": "tcm src --camelCase", 23 | "types:zod": "ts-to-zod --all --keepComments", 24 | "types-schema": "typescript-json-schema --ignoreErrors 'src/1_Button_JSDoc_Simple/index.d.ts' '*'", 25 | "emitx": "tsc --noEmit false --outDir dist/components", 26 | "generate": "concurrently 'npm:generate:*'", 27 | "generate:json": "typescript-json-schema --ignoreErrors \"./src/zod/autozod.ts\" '*' -o ./src/zod/autozod.schema.json", 28 | "generate:json-schema": "typescript-json-schema --ignoreErrors \"./src/zod/types.d.ts\" '*' -o ./src/zod/types.schema.json", 29 | "generate:json-dir": "typescript-json-schema --ignoreErrors \"./src/zod/**.ts\" '*' -o ./src/zod/dir.schema.json", 30 | "generate:predicates": "type-predicates-generator -f 'src/utils/types.d.ts' -o src/__generated/predicates.ts -a", 31 | "typedoc": "typedoc" 32 | }, 33 | "dependencies": { 34 | "@analytics/listener-utils": "^0.2.4", 35 | "@casl/ability": "^5.4.3", 36 | "@mantine/core": "^2.1.4", 37 | "@mantine/hooks": "^2.1.4", 38 | "@modulz/radix-icons": "^4.0.0", 39 | "analytics": "^0.7.11", 40 | "prop-types": "^15.7.2", 41 | "react": "^17.0.2", 42 | "react-dom": "^17.0.2", 43 | "react-jss": "^10.7.1", 44 | "zod": "^3.5.1" 45 | }, 46 | "devDependencies": { 47 | "@davidwells/config-postcss": "0.0.21", 48 | "@structured-types/api": "^3.40.9", 49 | "@structured-types/prop-types-plugin": "^3.40.9", 50 | "@structured-types/react-plugin": "^3.40.9", 51 | "@swc-node/register": "^1.3.3", 52 | "@testing-library/react": "^12.0.0", 53 | "@types/react": "^17.0.15", 54 | "@types/react-dom": "^17.0.9", 55 | "@typescript-eslint/parser": "^4.28.5", 56 | "@vitejs/plugin-react-refresh": "^1.3.6", 57 | "concurrently": "^6.2.0", 58 | "doxxx": "^1.0.0", 59 | "eslint": "^7.31.0", 60 | "eslint-plugin-jsdoc": "^36.0.6", 61 | "getdocs-ts": "^0.1.0", 62 | "global-jsdom": "^8.2.0", 63 | "inspx": "0.0.1-alpha.6", 64 | "jsdom": "^17.0.0", 65 | "mock-css-modules": "^2.0.0", 66 | "stylelint": "^13.13.1", 67 | "stylelint-config-standard": "^22.0.0", 68 | "stylelint-no-unused-selectors": "^1.0.39", 69 | "ts-node": "^10.2.1", 70 | "ts-to-jsdoc": "^1.1.2", 71 | "ts-to-zod": "^1.4.0", 72 | "type-coverage": "^2.18.0", 73 | "type-fest": "^1.2.3", 74 | "type-predicates-generator": "^0.3.1", 75 | "typed-css-modules": "^0.7.0", 76 | "typedoc": "^0.22.11", 77 | "typescript": "^4.5.2", 78 | "typescript-coverage-report": "^0.6.0", 79 | "typescript-json-schema": "^0.50.1", 80 | "uvu": "^0.5.1", 81 | "vite": "^2.4.4" 82 | }, 83 | "useful": { 84 | "esm": "^3.2.25", 85 | "jsdom": "^16.7.0" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /parser-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sum api function 3 | * @remarks 4 | * Unlike the summary, the remarks block may contain lengthy documentation content. 5 | * The remarks should not restate information from the summary, since the summary section 6 | * will always be displayed wherever the remarks section appears. Other sections 7 | * (e.g. an `@example` block) will be shown after the remarks section. 8 | * 9 | * @param {number} a first parameter to add 10 | * @param {number} b second parameter to add 11 | * @returns {number} the sum of the two parameters 12 | * 13 | * @example 14 | * 15 | * ```js 16 | * import { sum } from './sum'; 17 | * 18 | * expect(sum(1, 2)).toMatchObject({ a: 1, b: 2, result: 3}); 19 | * ``` 20 | */ 21 | export const sum = (a, b = 1) => ({ a, b, result: a + b }); -------------------------------------------------------------------------------- /parser.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const { inspect } = require('util') 4 | const { parseFiles } = require('@structured-types/api'); 5 | const propTypesPlugin = require('@structured-types/prop-types-plugin') 6 | const reactPlugin = require('@structured-types/react-plugin'); 7 | 8 | let filePath 9 | // filePath = './parser-test.js' 10 | filePath = path.resolve(__dirname, 'src/0_Button_PropTypes_Class/index.jsx') 11 | filePath = path.resolve(__dirname, 'src/0_Button_PropTypes_Function/index.jsx') 12 | // filePath = path.resolve(__dirname, 'src/1_Button_JSDoc_Simple/index.jsx') 13 | // filePath = path.resolve(__dirname, 'src/2_Button_JSDoc_TypeDef_Function/index.jsx') 14 | // filePath = path.resolve(__dirname, 'src/2.1_Button_JSDoc_Function_Extend/index.jsx') 15 | // filePath = path.resolve(__dirname, 'src/3_Button_JSDoc_TypeDef_Class/index.jsx') 16 | // filePath = path.resolve(__dirname, 'src/4_Button_JSDoc_ImportedTypes/index.jsx') 17 | // filePath = path.resolve(__dirname, 'src/5_Button_JSDoc_ImportedTypes_React/index.jsx') 18 | 19 | // https://github.com/ccontrols/structured-types/blob/a65a732f24de298bbde48d27ee9f17c94ba985b5/packages/api/src/types.ts#L34 20 | const PropKind = { 21 | 'String': 1, 22 | 'Number': 2, 23 | 'Boolean': 3, 24 | 'Union': 4, 25 | 'Enum': 5, 26 | 'Tuple': 6, 27 | 'Rest': 7, 28 | 'Undefined': 8, 29 | 'Unknown': 9, 30 | 'Null': 10, 31 | 'Function': 11, 32 | 'Void': 12, 33 | 'Class': 13, 34 | 'Interface': 14, 35 | 'Type': 15, 36 | 'Array': 16, 37 | 'Any': 17, 38 | 'Index': 20, 39 | 'Constructor': 21, 40 | 'Getter': 22, 41 | 'Setter': 23, 42 | 'BigInt': 24, 43 | 'Component': 25, 44 | 'Object': 26, 45 | 'Namespace': 27, 46 | 'RegEx': 28, 47 | } 48 | 49 | const kindMap = Object.keys(PropKind).reduce((acc, key) => { 50 | acc[PropKind[key]] = key 51 | return acc 52 | }, {}) 53 | console.log('kindMap', kindMap) 54 | 55 | const kindEntries = Object.entries(PropKind) 56 | console.log('kindEntries', kindEntries) 57 | 58 | function mapper(obj) { 59 | if (obj && typeof obj === 'object' && obj.kind) { 60 | obj.kindType = obj.kind 61 | obj.kind = kindMap[obj.kind] 62 | if (obj.properties) { 63 | obj.properties = obj.properties.map((prop) => { 64 | return mapper(prop) 65 | }) 66 | } 67 | if (obj.parameters) { 68 | obj.parameters = obj.parameters.map((prop) => { 69 | return mapper(prop) 70 | }) 71 | } 72 | if (obj.returns) { 73 | obj.returns = mapper(obj.returns) 74 | } 75 | } 76 | return obj 77 | } 78 | 79 | console.log(fs.readFileSync(filePath, 'utf-8')) 80 | 81 | const rawDocs = parseFiles([filePath], { 82 | plugins: [ 83 | { ...propTypesPlugin, filter: undefined }, 84 | reactPlugin 85 | ], 86 | }) 87 | 88 | // console.log('rawDocs') 89 | // console.log(inspect(rawDocs, {showHidden: false, depth: null})) 90 | 91 | const docs = Object.keys(rawDocs).map((key) => { 92 | return mapper(rawDocs[key]) 93 | }) 94 | 95 | console.log('docs') 96 | // console.log(docs[0].parameters[0].properties) 97 | console.log(inspect(docs, {showHidden: false, depth: null})) 98 | 99 | /* Log them */ 100 | docs.forEach((doc) => { 101 | console.log(`${doc.name}`) 102 | console.log('doc', doc); 103 | (doc.parameters || doc.properties).forEach((param) => { 104 | console.log(`param "${param.name}" properties`, param.properties) 105 | }) 106 | }) 107 | 108 | 109 | const getKindByNumber = (kind) => { 110 | return kindMap[kind] 111 | } 112 | 113 | const getKindName = (kind) => { 114 | const strKind = kind ? kind.toString() : 'unknown'; 115 | console.log('strKind', strKind) 116 | const found = kindEntries.find(([_, v]) => { 117 | console.log('v', v) 118 | return v.toString() === strKind; 119 | }) 120 | return found ? found[0] : undefined; 121 | } 122 | 123 | // console.log(getKindName(1)) 124 | // console.log(getKindByNumber(1)) 125 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const { getPostCSSConfig } = require('@davidwells/config-postcss') 2 | // const variable = require('./src/_variables') 3 | // const mixins = require('./src/_mixins') 4 | 5 | const defaultPlugins = getPostCSSConfig({ 6 | isNext: true, 7 | variables: { 8 | blue: 'red', 9 | nice: 'yellow', 10 | }, 11 | // mixins: mixins 12 | }) 13 | 14 | module.exports = { 15 | plugins: { 16 | ...defaultPlugins, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /scripts/getdocs.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const {gather} = require("getdocs-ts") 3 | 4 | let items = gather({ 5 | filename: path.resolve(__dirname, "../src/utils/examples/rbac/index.ts") 6 | }) 7 | 8 | const { inspect } = require('util') 9 | console.log('Extracted types:') 10 | console.log(inspect(items, {showHidden: false, depth: null})) -------------------------------------------------------------------------------- /src/0.1_Button_PropTypes_Function/index.jsx: -------------------------------------------------------------------------------- 1 | // https://www.inkoop.io/blog/a-guide-to-js-docs-for-react-js/ 2 | import React from "react" 3 | import PropTypes from "prop-types" 4 | 5 | /** 6 | * Component for showing details of the user. 7 | * @param {object} props - User props 8 | * @param {string} [props.name] - User's name 9 | * @param {number} [props.age] - User's age 10 | * @component 11 | * @example 12 | * const age = 21 13 | * const name = 'Jitendra Nirnejak' 14 | * return ( 15 | * 16 | * ) 17 | */ 18 | const User = props => { 19 | const { name, age } = props 20 | return ( 21 |

22 | {name} is {age} years old. 23 |

24 | ) 25 | } 26 | 27 | User.propTypes = { 28 | /** 29 | * User's name 30 | */ 31 | name: PropTypes.string.isRequired, 32 | /** 33 | * User's age 34 | */ 35 | age: PropTypes.number, 36 | } 37 | 38 | User.defaultProps = { 39 | text: "Jitendra Nirnejak", 40 | age: 21, 41 | } 42 | 43 | export default User -------------------------------------------------------------------------------- /src/0_Button_PropTypes_Class/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | /** 5 | * General component description in JSDoc format. Markdown is *supported*. 6 | */ 7 | export default class ButtonClassWithPropTypes extends React.Component { 8 | static propTypes = { 9 | /** Description of prop "children". */ 10 | children: PropTypes.element, 11 | /** Description of prop "foo". */ 12 | foo: PropTypes.number, 13 | /** Description of prop "baz". */ 14 | baz: PropTypes.oneOfType([ 15 | PropTypes.number, 16 | PropTypes.string 17 | ]) 18 | } 19 | static defaultProps = { 20 | foo: 42 21 | } 22 | 23 | render() { 24 | const { children, className } = this.props 25 | return ( 26 |
27 | {children} 28 |
29 | ) 30 | } 31 | } -------------------------------------------------------------------------------- /src/0_Button_PropTypes_Function/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const propTypes = { 5 | /** Description of prop "children". */ 6 | children: PropTypes.element, 7 | /** Description of prop "foo". */ 8 | foo: PropTypes.number, 9 | /** Description of prop "baz". */ 10 | baz: PropTypes.oneOfType([ 11 | PropTypes.number, 12 | PropTypes.string 13 | ]) 14 | } 15 | 16 | const defaultProps = { 17 | foo: 42 18 | } 19 | 20 | export default function ButtonWithPropTypes({ children }) { 21 | return ( 22 | 25 | ) 26 | } 27 | 28 | ButtonWithPropTypes.propTypes = propTypes 29 | ButtonWithPropTypes.defaultProps = defaultProps -------------------------------------------------------------------------------- /src/1_Button_JSDoc_Simple/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * Renders a 16 | */ 17 | export default function Button(props = {}) { 18 | return ( 19 | 23 | ) 24 | } 25 | 26 | /* https://www.javascriptjanuary.com/blog/autocomplete-in-react-using-jsdoc */ 27 | 28 | /** 29 | * Renders a component 30 | * @param {Object} props 31 | * @param {String} props.textColor - the color of the text in the button 32 | * @param {String} props.bgColor - the background color of the button 33 | * @param {React.ReactNode} [props.children] - component children; 34 | * @param {React.CSSProperties} props.overrideStyles - used to set the CSS of the button 35 | * @return {React.ReactElement} - React component 36 | */ 37 | export const ButtonTwo = ({ children, textColor, bgColor, overrideStyles = {} }) => ( 38 | 47 | ) 48 | 49 | 50 | /** 51 | * Renders a component 52 | * @param {Object} buttonProps 53 | * @param {String} buttonProps.textColor - the color of the text in the button 54 | * @param {String} buttonProps.bgColor - the background color of the button 55 | * @param {React.ReactNode} [buttonProps.children] - component children; 56 | * @param {React.CSSProperties} buttonProps.overrideStyles - used to set the CSS of the button 57 | * @return {React.ReactElement} - React component 58 | */ 59 | export function ButtonThree (buttonProps) { 60 | const { children, textColor, bgColor, overrideStyles = {} } = buttonProps 61 | return ( 62 | 71 | ) 72 | } 73 | 74 | /** 75 | * Foobar function 76 | * @param {number} a - does thing 77 | * @param {number} b - xyz 78 | * @returns 79 | */ 80 | export function fooBar(a, b) { 81 | return a + b 82 | } -------------------------------------------------------------------------------- /src/2.1_Button_JSDoc_Function_Extend/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * @typedef CustomProps 5 | * @prop {string} [text] - My button 6 | */ 7 | 8 | /** 9 | * HTML div attributes + custom props 10 | * @typedef {React.HTMLAttributes & CustomProps} Props 11 | */ 12 | 13 | /** 14 | * Renders a component 15 | * @param {Props} props 16 | * @return {React.ReactElement} - React component 17 | * @example 18 | 19 | Words 20 | 21 | */ 22 | export default function MyDivComponent({ 23 | text = 'my div', 24 | ...props 25 | }) { 26 | return ( 27 |
28 | {text} 29 |
30 | ) 31 | } -------------------------------------------------------------------------------- /src/2.2_Button_JSDoc_Function_Ref/index.jsx: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/66553490/how-do-i-annotate-react-forwardref-with-jsdoc-comments-so-that-intellisense-can 2 | import React, { forwardRef } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | 5 | /** 6 | * @typedef {Object} ButtonPropTypes 7 | * @property {string} text 8 | * @property {string} icon 9 | */ 10 | 11 | /** 12 | * @type React.FC 13 | */ 14 | const Button = forwardRef(({ text, icon }, ref) => ( 15 | 16 | )) 17 | 18 | const ButtonPropTypes = { 19 | text: PropTypes.string.isRequired, 20 | icon: PropTypes.string.isRequired, 21 | } 22 | 23 | Button.propTypes = ButtonPropTypes -------------------------------------------------------------------------------- /src/2.2_Button_JSDoc_Hooks/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, Component } from 'react' 2 | 3 | /** 4 | * @typedef {Object} AppUser 5 | * @property {string} given_name 6 | * @property {string} family_name 7 | * @property {string} [favorite_movie] 8 | * @property {string} favorite_book 9 | * @property {Array} [friends] 10 | * @property {Record | null} [stuff] 11 | */ 12 | 13 | /** 14 | * @typedef {Boolean} LoadingState — documentation for isLoading 15 | * @description Additional doc 16 | */ 17 | /** 18 | * @typedef {Function} LoadingStateSetter — documentation for setIsLoading 19 | */ 20 | 21 | export default function MyDivComponent() { 22 | // Inline def 23 | const [state, setState] = useState(/** @type {{name: string?, age: number?}} */({})) 24 | 25 | // Inline def reference to typedefs 26 | const [appUser, setAppUser] = useState(/** @type {AppUser | null} */(null)) 27 | 28 | // Reference to typedefs 29 | /** @type {[LoadingState, LoadingStateSetter]} Loading */ 30 | const [isLoading, setIsLoading] = React.useState(true); 31 | const isLive = useMyHook({ disabled: true }) 32 | 33 | return ( 34 |
35 | text 36 |
37 | ) 38 | } 39 | 40 | /** 41 | * A hook to do something 42 | * 43 | * @param {object} params 44 | * @param {boolean} [params.disabled] Disable the thing 45 | * @returns {boolean} 46 | */ 47 | const useMyHook = (params) => { 48 | const [isUsing, setUsing] = useState(false) 49 | // Some logic here to invoke setUsing() 50 | return isUsing; 51 | }; -------------------------------------------------------------------------------- /src/2_Button_JSDoc_TypeDef_Function/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | /** 4 | * @typedef AdditionalType 5 | * @prop {string} [xyz] - XYZ prop 6 | * @prop {string} [abc] - ABC prop 7 | * @prop {string} bcd - BCD prop 8 | */ 9 | 10 | /** 11 | * @typedef Props 12 | * @prop {string} [text] - My button 13 | * @prop {string} [textColor] - the color of the text in the button 14 | * @prop {string} [bgColor] - the background color of the button 15 | * @prop {React.CSSProperties} [overrideStyles] - used to set the CSS of the button 16 | * @prop {() => void} [onLogin] - Login handler 17 | * @prop {AdditionalType} [example] - example ref 18 | */ 19 | 20 | /** 21 | * Renders a 28 | ) 29 | } -------------------------------------------------------------------------------- /src/3_Button_JSDoc_TypeDef_Class/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | /** 4 | * @typedef Props 5 | * @prop {string} [textColor] 6 | * @prop {React.ReactNode} [desc] 7 | */ 8 | 9 | /** 10 | * @typedef State 11 | * @prop {boolean} isDrawerOpen 12 | */ 13 | 14 | /** 15 | * @extends Component 16 | */ 17 | export default class ButtonClass extends Component { 18 | /** @type {State} */ 19 | state = { 20 | isDrawerOpen: false, 21 | } 22 | 23 | constructor(props) { 24 | super(props) 25 | } 26 | 27 | render() { 28 | // This is an error: 29 | // console.log(this.state.lol) 30 | return ( 31 | 32 | Button class {this.state.isDrawerOpen} 33 | 34 | ) 35 | } 36 | } -------------------------------------------------------------------------------- /src/4_Button_JSDoc_ImportedTypes/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | /** 4 | * Renders a component with imported types 5 | * @param { import("./tiny").TinyProps } props 6 | * @return {React.ReactElement} - React component 7 | */ 8 | export default function ButtonImport(props) { 9 | return ( 10 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/4_Button_JSDoc_ImportedTypes/large.ts: -------------------------------------------------------------------------------- 1 | // Via https://github.com/typescript-cheatsheets/react#basic-prop-types-examples 2 | 3 | export type AppProps = { 4 | message: string; 5 | count: number; 6 | disabled: boolean; 7 | /** array of a type! */ 8 | names: string[]; 9 | /** string literals to specify exact string values, with a union type to join them together */ 10 | status: "waiting" | "success"; 11 | /** any object as long as you dont use its properties (NOT COMMON but useful as placeholder) */ 12 | obj: object; 13 | obj2: {}; // almost the same as `object`, exactly the same as `Object` 14 | /** an object with any number of properties (PREFERRED) */ 15 | obj3: { 16 | id: string; 17 | title: string; 18 | }; 19 | /** array of objects! (common) */ 20 | objArr: { 21 | id: string; 22 | title: string; 23 | }[]; 24 | /** a dict object with any number of properties of the same type */ 25 | dict1: { 26 | [key: string]: string; 27 | }; 28 | dict2: Record; // equivalent to dict1 29 | /** any function as long as you don't invoke it (not recommended) */ 30 | onSomething: Function; 31 | /** function that doesn't take or return anything (VERY COMMON) */ 32 | onFakeFunc: () => void; 33 | /** function with named prop (VERY COMMON) */ 34 | onChange: (id: number) => void; 35 | /** alternative function type syntax that takes an event (VERY COMMON) */ 36 | onClick(event: React.MouseEvent): void; 37 | /** an optional prop (VERY COMMON!) */ 38 | optional?: string; 39 | }; -------------------------------------------------------------------------------- /src/4_Button_JSDoc_ImportedTypes/tiny.ts: -------------------------------------------------------------------------------- 1 | export type TinyProps = { 2 | message: string; 3 | count: number; 4 | disabled: boolean; 5 | }; -------------------------------------------------------------------------------- /src/5_Button_JSDoc_ImportedTypes_React/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * Renders a component with useful react types 5 | * @param { import("./usefulTypes").AppProps } props 6 | * @return {React.ReactElement} - React component 7 | */ 8 | export default function ButtonReactTypes(props) { 9 | return ( 10 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/5_Button_JSDoc_ImportedTypes_React/usefulTypes.ts: -------------------------------------------------------------------------------- 1 | // Via https://github.com/typescript-cheatsheets/react#basic-prop-types-examples 2 | 3 | export declare interface AppProps { 4 | children1: JSX.Element; // bad, doesnt account for arrays 5 | children2?: JSX.Element | JSX.Element[]; // meh, doesn't accept strings 6 | children3?: React.ReactChildren; // despite the name, not at all an appropriate type; it is a utility 7 | children4?: React.ReactChild[]; // better, accepts array children 8 | children?: React.ReactNode; // best, accepts everything (see edge case below) 9 | functionChildren?: (name: string) => React.ReactNode; // recommended function as a child render prop type 10 | style?: React.CSSProperties; // to pass through style props 11 | onChange?: React.FormEventHandler; // form events! the generic parameter is the type of event.target 12 | // // more info: https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#wrappingmirroring 13 | // props: Props & React.ComponentPropsWithoutRef<"button">; // to impersonate all the props of a button element and explicitly not forwarding its ref 14 | // props2: Props & React.ComponentPropsWithRef; // to impersonate all the props of MyButtonForwardedRef and explicitly forwarding its ref 15 | } -------------------------------------------------------------------------------- /src/6_List_TypeScript/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | type Props = { 4 | message: string; 5 | count?: number; 6 | disabled?: boolean; 7 | /** array of a type! */ 8 | names?: string[]; 9 | /** string literals to specify exact string values, with a union type to join them together */ 10 | status?: "waiting" | "success"; 11 | /** any object as long as you dont use its properties (NOT COMMON but useful as placeholder) */ 12 | obj?: object; 13 | obj2?: {}; // almost the same as `object`, exactly the same as `Object` 14 | /** an object with any number of properties (PREFERRED) */ 15 | obj3?: { 16 | id: string; 17 | title: string; 18 | }; 19 | /** array of objects! (common) */ 20 | objArr?: { 21 | id: string; 22 | title: string; 23 | }[]; 24 | /** any function as long as you don't invoke it (not recommended) */ 25 | onSomething?: Function; 26 | /** function with named prop (VERY COMMON) */ 27 | onChange?: (id: number) => void; 28 | /** alternative function type syntax that takes an event (VERY COMMON) */ 29 | onClick?(event: React.MouseEvent): void; 30 | }; 31 | 32 | export default function List(props: Props) { 33 | return ( 34 |
35 | List component 36 |
37 | ) 38 | } -------------------------------------------------------------------------------- /src/7_Context/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Context } from 'react' 2 | 3 | /** 4 | * React context example 5 | * @typedef FooBar 6 | * @property {object} competitionState 7 | * @property {'finished' | 'inprogress'} status 8 | * @property {Array} notificationActions 9 | */ 10 | 11 | // Import style 12 | 13 | /** @type {import('react').Context} */ 14 | export const MyThemeContext = React.createContext({ 15 | competitionState: {}, 16 | notificationActions: [], 17 | status: 'finished' 18 | }); 19 | 20 | 21 | // Imported type style 22 | 23 | /** @type {Context} */ 24 | export const MyThemeContextTwo = React.createContext({ 25 | competitionState: {}, 26 | notificationActions: [], 27 | status: 'finished' 28 | }); 29 | -------------------------------------------------------------------------------- /src/8_PolymorphicComponent/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import classNames from 'clsx' 3 | 4 | // The `Props` interface becomes a simple interface of the main props 5 | interface Props { 6 | children: React.ReactNode 7 | color?: string 8 | font?: 'thin' | 'regular' | 'heavy' 9 | size?: '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' 10 | } 11 | 12 | // `TextProps` now uses `PolymorphicComponentProps` to add the `as` prop 13 | // and inherit its prop 14 | type TextProps = PolymorphicComponentProps< 15 | C, 16 | Props 17 | > 18 | 19 | export const Text = ({ 20 | as, 21 | children, 22 | font = 'regular', 23 | size = '4', 24 | color = 'gray-40', 25 | ...other 26 | }: TextProps) => { 27 | const classes = classNames({ font, size, color }) 28 | const Component = as || 'span' 29 | 30 | return ( 31 | 32 | {children} 33 | 34 | ) 35 | } 36 | 37 | /** 38 | * Usage example 39 | */ 40 | export const LOL = () => xyz -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | 40 | button { 41 | font-size: calc(10px + 2vmin); 42 | } 43 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useRef } from "react" 2 | import TodoList from './TodoList' 3 | import Button from './1_Button_JSDoc_Simple' 4 | import ButtonTwo from './2_Button_JSDoc_TypeDef_Function' 5 | import ButtonClass from './3_Button_JSDoc_TypeDef_Class' 6 | import ButtonImportedTypes from './4_Button_JSDoc_ImportedTypes' 7 | import ButtonReactTypes from './5_Button_JSDoc_ImportedTypes_React' 8 | import List from './6_List_TypeScript' 9 | import Card from './Card' 10 | import Analytics from 'analytics' 11 | import { addListener } from '@analytics/listener-utils' 12 | 13 | const analytics = Analytics({ 14 | app: 'xyz', 15 | }) 16 | 17 | 18 | console.log('Analytics lib', Analytics) 19 | console.log('analytics instance', analytics) 20 | 21 | export default function App() { 22 | const divRef = useRef(null) 23 | useEffect(() => { 24 | addListener(divRef.current, 'click', () => { 25 | console.log('do thing') 26 | }) 27 | }) 28 | return ( 29 |
30 | 31 | 32 | hi 33 | 34 | 40 | 44 | 47 | 52 | bold} 54 | > 55 |

cool

56 |
57 | 58 |
59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /src/Card/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * @typedef Props 5 | * @prop {React.ReactNode} [children] 6 | * @prop {React.ReactNode} [desc] 7 | * @prop {React.ReactNode} [selectFlightPrompt] 8 | * @prop {()=>void} [onLogin] 9 | */ 10 | 11 | /** 12 | * @param {Props} props 13 | */ 14 | export default function Card({ children }) { 15 | return ( 16 |
17 | {children} 18 |
19 | ) 20 | } -------------------------------------------------------------------------------- /src/TodoList/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react" 2 | import { useListState } from "@mantine/hooks" 3 | import { Cross1Icon, PlusIcon } from "@modulz/radix-icons" 4 | import { 5 | Title, 6 | Text, 7 | Checkbox, 8 | TextInput, 9 | ActionIcon, 10 | Container, 11 | useMantineTheme, 12 | } from "@mantine/core" 13 | 14 | import styles from './xyz.module.css' 15 | 16 | function randomId() { 17 | return Math.random().toString(36).substr(2, 9) 18 | } 19 | 20 | const INITIAL_STATE = [ 21 | { value: "Buy 23 RTX 3080 cards", completed: false, key: randomId() }, 22 | { value: "Mine Ethereum", completed: false, key: randomId() }, 23 | { 24 | value: "Complain about miners on internet to prove innocence", 25 | completed: false, 26 | key: randomId(), 27 | }, 28 | { 29 | value: "Sell broken cards on ebay to gamers", 30 | completed: false, 31 | key: randomId(), 32 | }, 33 | { 34 | value: "Spend received money on new video cards", 35 | completed: false, 36 | key: randomId(), 37 | }, 38 | { value: "Repeat the cycle", completed: false, key: randomId() }, 39 | ] 40 | 41 | export default function TodoList() { 42 | const theme = useMantineTheme() 43 | const [newItem, setNewItem] = useState("") 44 | const [state, handlers] = useListState(INITIAL_STATE) 45 | 46 | const items = state.reduce( 47 | (acc, item, index) => { 48 | acc[item.completed ? "completed" : "current"].push( 49 | // @ts-ignore 50 |
59 | 60 | tester 61 | 62 | { 67 | handlers.setItemProp( 68 | index, 69 | "completed", 70 | event.currentTarget.checked 71 | ) 72 | if (event.currentTarget.checked) { 73 | handlers.reorder({ from: index, to: state.length - 1 }) 74 | } 75 | }} 76 | /> 77 | 78 | 83 | handlers.setItemProp(index, "value", event.currentTarget.value) 84 | } 85 | /> 86 | 87 | handlers.remove(index)} 91 | > 92 | 93 | 94 |
95 | ) 96 | 97 | return acc 98 | }, 99 | { completed: [], current: [] } 100 | ) 101 | 102 | return ( 103 | 104 | 105 | Business Plan 106 | 107 | 108 | {items.current} 109 | 110 | {items.completed.length > 0 && ( 111 | 112 | Completed 113 | 114 | )} 115 | {items.completed} 116 | 117 | setNewItem(event.currentTarget.value)} 122 | icon={} 123 | placeholder="Add business plan task" 124 | onKeyDown={(event) => { 125 | if ( 126 | event.nativeEvent.code === "Enter" && 127 | event.currentTarget.value.trim().length > 0 128 | ) { 129 | handlers.append({ 130 | value: event.currentTarget.value, 131 | completed: false, 132 | key: randomId(), 133 | }) 134 | setNewItem("") 135 | } 136 | }} 137 | /> 138 | 139 | ) 140 | } 141 | -------------------------------------------------------------------------------- /src/TodoList/xyz.module.css: -------------------------------------------------------------------------------- 1 | .test { 2 | background: blue; 3 | 4 | .other { 5 | background: green; 6 | } 7 | } 8 | 9 | .coolBean { 10 | color: purple; 11 | } 12 | 13 | .no { 14 | color: blue; 15 | } -------------------------------------------------------------------------------- /src/__generated/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidWells/types-with-jsdocs/3c03e4aa9ef5d784305ef2919d461a55a5847a32/src/__generated/.gitkeep -------------------------------------------------------------------------------- /src/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | /* initialize JSDOM */ 2 | // import './misc/_setup-tests.js' // with jsdom pkh // OR -r global-jsdom/register 3 | // import { setupJSDOM } from './misc/_initJSDom' 4 | import { test } from 'uvu' 5 | import * as assert from 'uvu/assert' 6 | import React from 'react' 7 | import { fireEvent, render } from "@testing-library/react" 8 | import Button from '../0_Button_PropTypes_Class' 9 | /* Ignoring CSS modules https://github.com/avajs/ava/issues/2038#issuecomment-864300925 */ 10 | import TodoList from '../TodoList' 11 | import { itSupportsClassName } from './misc/utils' 12 | 13 | /* 14 | https://github.com/modosc/global-jsdom 15 | https://www.npmjs.com/package/mock-css-modules 16 | */ 17 | 18 | test('Tests run', async () => { 19 | assert.is(true, true) 20 | }) 21 | 22 | test("Renders component in test", async () => { 23 | const MyComponent = () => { 24 | return ( 25 | <> 26 |
27 | inside 28 | another 29 |
30 |
outside
31 | 32 | ); 33 | }; 34 | 35 | const result = render() 36 | assert.ok(result) 37 | // console.log('result.container.innerHTML', result.container.innerHTML) 38 | assert.match(result.container.innerHTML, 'inside') 39 | }) 40 | 41 | test("Class component renders", async () => { 42 | // Ensure it supports classes 43 | assert.ok(itSupportsClassName(Button)) 44 | 45 | const result = render() 46 | assert.ok(result) 47 | console.log('result.container.innerHTML', result.container.innerHTML) 48 | // assert.match(result.container.innerHTML, 'inside') 49 | 50 | }) 51 | 52 | test("component with css modules renders", async () => { 53 | const result = render() 54 | assert.ok(result) 55 | // console.log('result.container.innerHTML', result.container.innerHTML) 56 | assert.match(result.container.innerHTML, 'Complain about miners') 57 | }) 58 | 59 | // Needed to exit process once tests finish 60 | // @ts-ignore 61 | test.after(() => setTimeout(() => process.exit(0), 300)) 62 | 63 | test.run() -------------------------------------------------------------------------------- /src/__tests__/misc/_initJSDom.js: -------------------------------------------------------------------------------- 1 | import { JSDOM } from "jsdom" 2 | 3 | const baseUrl = "http://www.example.org"; 4 | 5 | // @ts-ignore 6 | export const setupJSDOM = ({ url, ...options } = {}) => { 7 | const dom = new JSDOM("", { 8 | // pretendToBeVisual is enabled so that react works, see 9 | // https://github.com/jsdom/jsdom#pretending-to-be-a-visual-browser 10 | pretendToBeVisual: true, 11 | url: baseUrl + url, 12 | ...options, 13 | }); 14 | // @ts-ignore 15 | global.window = dom.window; 16 | // @ts-ignore 17 | global.document = dom.window.document; 18 | 19 | // cleanup func 20 | return () => { 21 | // @ts-ignore 22 | delete global.window; 23 | // @ts-ignore 24 | delete global.document; 25 | }; 26 | }; -------------------------------------------------------------------------------- /src/__tests__/misc/_setup-tests.js: -------------------------------------------------------------------------------- 1 | // import { ConstructorOptions, JSDOM } from "jsdom"; 2 | const { ConstructorOptions, JSDOM } = require('jsdom') 3 | process.env.NODE_ENV = 'test' 4 | 5 | const jsdom = new JSDOM('') 6 | const {window} = jsdom 7 | 8 | /** 9 | * @param {Object} src 10 | * @param {Object} target 11 | */ 12 | function copyProps(src, target) { 13 | Object.defineProperties(target, { 14 | ...Object.getOwnPropertyDescriptors(src), 15 | ...Object.getOwnPropertyDescriptors(target), 16 | }) 17 | } 18 | 19 | 20 | global.window = window 21 | global.document = window.document 22 | // @ts-ignore 23 | global.navigator = { userAgent: 'node.js' } 24 | global.requestAnimationFrame = callback => setTimeout(callback, 0) 25 | global.cancelAnimationFrame = id => clearTimeout(id) 26 | copyProps(window, global) -------------------------------------------------------------------------------- /src/__tests__/misc/utils.js: -------------------------------------------------------------------------------- 1 | // https://github.com/mantinedev/mantine/blob/master/src/mantine-tests/src/it-supports-classname.tsx 2 | import React from 'react' 3 | import { render } from '@testing-library/react' 4 | 5 | /** 6 | * @callback TestUtil 7 | * @param {React.ElementType} Component 8 | * @param {Record} requiredProps 9 | */ 10 | 11 | /** 12 | * 13 | * @param {React.ElementType} Component 14 | * @param {Record} requiredProps 15 | */ 16 | export function itSupportsClassName(Component, requiredProps = {}) { 17 | const { container } = render() 18 | return container.querySelector('.test-class-name') 19 | } 20 | 21 | 22 | /** @type {TestUtil} */ 23 | export function itRendersChildren(Component, requiredProps) { 24 | const { container } = render( 25 | 26 | test-children 27 | 28 | ) 29 | return container.querySelector('.test-children') 30 | } -------------------------------------------------------------------------------- /src/__tests__/simple/x.test.js: -------------------------------------------------------------------------------- 1 | /* initialize JSDOM */ 2 | // import './misc/_setup-tests.js' // with jsdom pkh // OR -r global-jsdom/register 3 | // import { setupJSDOM } from './misc/_initJSDom' 4 | import { test } from 'uvu' 5 | import * as assert from 'uvu/assert' 6 | import React from 'react' 7 | import { render } from "@testing-library/react" 8 | 9 | test('Tests run', async () => { 10 | assert.is(true, true) 11 | }) 12 | 13 | test("Renders component in test", async () => { 14 | const MyComponent = () => { 15 | return ( 16 | <> 17 |
18 | inside 19 | another 20 |
21 |
outside
22 | 23 | ); 24 | }; 25 | 26 | const result = render() 27 | assert.ok(result) 28 | console.log('result.container.innerHTML', result.container.innerHTML) 29 | assert.match(result.container.innerHTML, 'inside') 30 | }) 31 | 32 | // Needed to exit process once tests finish 33 | // @ts-ignore 34 | test.after(() => setTimeout(() => process.exit(0), 300)) 35 | 36 | test.run() -------------------------------------------------------------------------------- /src/__tests__/withJsDom/y.test.js: -------------------------------------------------------------------------------- 1 | /* initialize JSDOM */ 2 | import '../misc/_setup-tests.js' // with jsdom pkh // OR -r global-jsdom/register 3 | import { test } from 'uvu' 4 | import * as assert from 'uvu/assert' 5 | import React from 'react' 6 | import { fireEvent, render } from "@testing-library/react" 7 | import Button from '../../0_Button_PropTypes_Class' 8 | /* Ignoring CSS modules https://github.com/avajs/ava/issues/2038#issuecomment-864300925 */ 9 | import TodoList from '../../TodoList' 10 | import { itSupportsClassName } from '../misc/utils' 11 | 12 | /* 13 | https://github.com/modosc/global-jsdom 14 | https://www.npmjs.com/package/mock-css-modules 15 | */ 16 | 17 | 18 | test('Tests run', async () => { 19 | assert.is(true, true) 20 | }) 21 | 22 | test("Renders component in test", async () => { 23 | const MyComponent = () => { 24 | return ( 25 | <> 26 |
27 | inside 28 | another 29 |
30 |
outside
31 | 32 | ); 33 | }; 34 | 35 | const result = render() 36 | assert.ok(result) 37 | // console.log('result.container.innerHTML', result.container.innerHTML) 38 | assert.match(result.container.innerHTML, 'inside') 39 | }) 40 | 41 | test("Class component renders", async () => { 42 | // Ensure it supports classes 43 | assert.ok(itSupportsClassName(Button)) 44 | 45 | const result = render() 46 | assert.ok(result) 47 | console.log('result.container.innerHTML', result.container.innerHTML) 48 | // assert.match(result.container.innerHTML, 'inside') 49 | 50 | }) 51 | 52 | test("component with css modules renders", async () => { 53 | const result = render() 54 | assert.ok(result) 55 | // console.log('result.container.innerHTML', result.container.innerHTML) 56 | assert.match(result.container.innerHTML, 'Complain about miners') 57 | }) 58 | 59 | // Needed to exit process once tests finish 60 | // @ts-ignore 61 | test.after(() => setTimeout(() => process.exit(0), 300)) 62 | 63 | test.run() -------------------------------------------------------------------------------- /src/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import Inspect from 'inspx' 4 | import './index.css' 5 | import App from './App' 6 | 7 | ReactDOM.render( 8 | 9 | 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ) 15 | -------------------------------------------------------------------------------- /src/utils/0_@author.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param {Object.} f 4 | * @author David Wells 5 | */ 6 | function foo(f) { 7 | 8 | } 9 | 10 | 11 | /** 12 | * @param {Object.} f 13 | * @author David Wells 14 | */ 15 | function bar(f) { 16 | 17 | } 18 | 19 | 20 | /** 21 | * Welcome to awesome.ts 22 | * @author Ian Awesome 23 | */ 24 | export class Awesome { 25 | constructor() { 26 | console.log('awesome'); 27 | } 28 | } 29 | 30 | const awesome = new Awesome(); -------------------------------------------------------------------------------- /src/utils/0_@default.js: -------------------------------------------------------------------------------- 1 | // Mark constant value with default 2 | 3 | /** 4 | * @constant 5 | * @default 'xyz' 6 | */ 7 | const MY_VALUE = 'xyz'; -------------------------------------------------------------------------------- /src/utils/0_@deprecated.js: -------------------------------------------------------------------------------- 1 | // Mark function as deprecated 2 | 3 | /** 4 | * @deprecated 5 | */ 6 | function brokenFunction() { 7 | throw new Error('this is broken') 8 | } -------------------------------------------------------------------------------- /src/utils/0_@description.js: -------------------------------------------------------------------------------- 1 | // @description tag 2 | 3 | /** 4 | * Add two numbers. 5 | */ 6 | export function add(a, b) { 7 | return a + b; 8 | } 9 | 10 | /** 11 | * @desc Add two numbers. 12 | */ 13 | export function addTwo(a, b) { 14 | return a + b; 15 | } 16 | 17 | /** 18 | * @description Add two numbers. 19 | */ 20 | export function addThree(a, b) { 21 | return a + b; 22 | } 23 | -------------------------------------------------------------------------------- /src/utils/0_@example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Adds two numbers 3 | * 4 | * @param {number} a number one 5 | * @param {number} b number two 6 | * @returns {number} sum of number one and number two 7 | * 8 | * @example Add 1 and 3. If answer is >0, sums result and 5. 9 | * ``` 10 | * const answer = sum(1, 3); // returns 4 11 | * 12 | * if (answer > 0) { 13 | * sum(answer, 5) 14 | * } 15 | * ``` 16 | */ 17 | function sum(a, b) { 18 | return a + b 19 | } 20 | 21 | 22 | // ─────────────────────── 23 | // https://github.com/yamadapc/jsdoctest/blob/master/test/test-file-captioned.js 24 | 25 | /** 26 | * @example Integers 27 | * addMoreStuff(1, 2) 28 | * // => 3 29 | * addMoreStuff(3, 2) 30 | * // => 5 31 | * 32 | * @example Doubles 33 | * addMoreStuff(1.5, 2.5) 34 | * // => 4 35 | */ 36 | 37 | function addMoreStuff(x, y) { 38 | return x + y; 39 | } 40 | 41 | // ─────────────────────── 42 | // https://github.com/jaydenseric/jsdoc-md#example-content 43 | 44 | /** 45 | * Displays a message in a native popup window. 46 | * @kind function 47 | * @name popup 48 | * @param {string} message Message text. 49 | * @example Say `Hello!` to the user. 50 | * This usage: 51 | * 52 | * ```js 53 | * popup('Hello!'); 54 | * ``` 55 | * 56 | * Displays like this on macOS: 57 | * 58 | * ![Screenshot](https://octodex.github.com/images/yaktocat.png) 59 | */ 60 | const popup = (message) => alert(message); -------------------------------------------------------------------------------- /src/utils/0_@extends.js: -------------------------------------------------------------------------------- 1 | // The @augments or @extends tag indicates that a symbol inherits from, and potentially adds to, a parent symbol. 2 | // You can use this tag to document both class-based and prototype-based inheritance. 3 | 4 | /** 5 | * @constructor 6 | */ 7 | function AnimalTwo() { 8 | /** Is this animal alive? */ 9 | this.alive = true; 10 | } 11 | 12 | /** 13 | * @constructor 14 | * @augments AnimalTwo 15 | */ 16 | class DuckTwo extends AnimalTwo { 17 | quack(stuff) { 18 | console.log(`Doing some pretty crazy stuff with ${stuff}`); 19 | } 20 | } 21 | 22 | /** What do ducks say? */ 23 | DuckTwo.prototype.speak = function() { 24 | if (this.alive) { 25 | alert('Quack!'); 26 | } 27 | }; 28 | 29 | var d = new DuckTwo(); 30 | console.log('d', d) 31 | d.speak(); // Quack! 32 | d.alive = false; 33 | d.speak(); // (nothing) -------------------------------------------------------------------------------- /src/utils/0_@license.js: -------------------------------------------------------------------------------- 1 | // Short license 2 | 3 | /** 4 | * Utility functions for the foo package. 5 | * @module foo/util 6 | * @license Apache-2.0 7 | */ 8 | export const util = () => ''; 9 | 10 | // Verbose license 11 | 12 | /** 13 | * @license 14 | * Copyright (c) 2015 Example Corporation Inc. 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a copy 17 | * of this software and associated documentation files (the "Software"), to deal 18 | * in the Software without restriction, including without limitation the rights 19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | * copies of the Software, and to permit persons to whom the Software is 21 | * furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in all 24 | * copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | * SOFTWARE. 33 | */ 34 | 35 | export const utilTwo = () => ''; 36 | -------------------------------------------------------------------------------- /src/utils/0_@link.js: -------------------------------------------------------------------------------- 1 | /** 2 | * See {@link MyClass} and [MyClass's foo property](MyClass#foo). 3 | * Also, check out {@link http://www.google.com|Google} and 4 | * {@link https://github.com GitHub}. 5 | */ 6 | export function myFunction() {} 7 | -------------------------------------------------------------------------------- /src/utils/0_@module.js: -------------------------------------------------------------------------------- 1 | /** @module User */ 2 | 3 | const defaultUserName = "bob"; 4 | 5 | /** 6 | * Hello function 7 | * @param {string} name - person name 8 | */ 9 | function sayHello(name) { 10 | alert("hello " + name || defaultUserName); 11 | } -------------------------------------------------------------------------------- /src/utils/0_@module2.js: -------------------------------------------------------------------------------- 1 | // https://github.com/rlwi440/JS-Docs/blob/master/src/calculator.js 2 | 3 | /** 4 | * Calculator module - See {@tutorial calculator-tutorial} 5 | * @module calculator 6 | */ 7 | 8 | /** 9 | * Add two numbers 10 | * @param {number} n1 - First number 11 | * @param {number} n2 - Second number 12 | * @returns {number} - Sum of n1 and n2 13 | */ 14 | exports.add = (n1, n2) => n1 + n2; 15 | 16 | /** 17 | * Multiply two numbers 18 | * @param {number} n1 - First number 19 | * @param {number} n2 - Second number 20 | * @returns {number} - Product of n1 and n2 21 | */ 22 | exports.multiply = (n1, n2) => n1 * n2; 23 | 24 | /** 25 | * Subtract two numbers 26 | * @param {number} n1 - First number 27 | * @param {number} n2 - Second number 28 | * @returns {number} - Difference of n1 and n2 29 | */ 30 | exports.subtract = (n1, n2) => n1 - n2; 31 | 32 | /** 33 | * Divide two numbers 34 | * @param {number} n1 - First number 35 | * @param {number} n2 - Second number 36 | * @returns {number} - Quotient of n1 and n2 37 | */ 38 | exports.divide = (n1, n2) => n1 / n2; -------------------------------------------------------------------------------- /src/utils/0_@name.js: -------------------------------------------------------------------------------- 1 | // https://github.com/onury/jsdoc-x/blob/master/test/input-parse/name-test.js 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | // NOTE: symbol descriptions should be unique 7 | 8 | /** 9 | * foo 10 | * @class 11 | */ 12 | var foo = {}; 13 | 14 | /** 15 | * foo.bar 16 | * @name foo.bar 17 | * @function 18 | */ 19 | 20 | /** 21 | * foo.baz 22 | * @name foo.baz 23 | * @alias foo.bazAlias 24 | * @function 25 | */ 26 | 27 | /** 28 | * foo.qux 29 | */ 30 | foo.qux = function () {}; 31 | 32 | foo.ns = {}; 33 | 34 | /** 35 | * foo.ns.m1 36 | * @alias m1alias 37 | */ 38 | foo.ns.m1 = function () {}; 39 | 40 | /** 41 | * foo.ns.m2 42 | * @memberof foo.ns 43 | * @name mx 44 | * @alias ns.m2alias 45 | */ 46 | foo.ns.m2 = function () {}; 47 | 48 | /** 49 | * foo.ns.m3 50 | * @name m3name 51 | * @function 52 | */ 53 | foo.ns.m3 = function () {}; 54 | 55 | /** 56 | * foo.ns.m4 57 | * @name ns.m4name 58 | * @function 59 | */ 60 | foo.ns.m4 = function () {}; 61 | 62 | /** 63 | * m5 64 | * @memberof foo.ns 65 | */ 66 | function m5() {} 67 | 68 | /** 69 | * m6 70 | * @memberof foo.ns 71 | * @alias m6alias 72 | */ 73 | function m6() {} 74 | 75 | /** 76 | * Some name space. 77 | * @memberof foo 78 | * @type {Object} 79 | */ 80 | var o = {}; 81 | 82 | /** 83 | * m7 84 | * @memberof foo 85 | * @alias m7alias 86 | */ 87 | o.m7 = function () {}; 88 | 89 | /** 90 | * m8 91 | * @memberof foo.o 92 | * @alias m8alias 93 | */ 94 | o.m8 = function () {}; 95 | 96 | /** 97 | * m9 98 | * @memberof foo.o 99 | * @alias m9alias 100 | */ 101 | foo.o.m9 = function () {}; 102 | 103 | /** 104 | * foo.o.mx 105 | * @memberof foo.o 106 | * @alias m9alias 107 | */ 108 | foo.o.mx = function () {}; 109 | 110 | })(); -------------------------------------------------------------------------------- /src/utils/0_@namespace.js: -------------------------------------------------------------------------------- 1 | // https://github.com/onury/jsdoc-x/blob/master/test/input-parse/test3.es5.js 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | /** 7 | * Test namespace properties. 8 | * @namespace 9 | * @global 10 | * @name namespace 11 | * @type {Object} 12 | */ 13 | var namespace = {}; 14 | 15 | /** 16 | * Similar to `window.location` but with differences and additional 17 | * information. 18 | * 19 | * @name namespace.location 20 | * @type {Object} 21 | * @readonly 22 | * 23 | * @property {String} pathname - Gets the path and filename of the current URL, without the base. 24 | * @property {String} query - Gets the querystring part of the current URL, without `?` prefix. 25 | * @property {String} origin - Gets the protocol, hostname and port number of the current URL. 26 | * @property {String} hostname - Gets the domain name of the web host. 27 | * @property {String} host - Gets the host. 28 | * @property {String} href - Gets the href (URL) of the current location. 29 | * @property {String} path - Gets the path, filename and query-string of the current URL, without the base. 30 | * @property {String} hash - Gets the anchor `#` of the current URL, without `#` prefix. 31 | * @property {Function} getQuery() - Gets the value of the given querystring parameter. 32 | * @property {String} protocol - Gets the web protocol used, including `:` suffix. 33 | */ 34 | Object.defineProperty(namespace, 'location', { 35 | configurable: false, 36 | get: function () { 37 | return { 38 | host: window.location.host, 39 | hostname: window.location.hostname, 40 | origin: window.location.origin, 41 | port: window.location.port, 42 | protocol: window.location.protocol, 43 | hash: (window.location.hash || '').replace(/^#/, ''), 44 | query: (window.location.search || '').replace(/^\?/, ''), 45 | href: window.location.href, 46 | pathname: window.location.pathname, 47 | path: window.location.pathname + (window.location.search || ''), 48 | getQuery: function () { 49 | return ''; 50 | } 51 | 52 | }; 53 | } 54 | }); 55 | 56 | })(); 57 | 58 | // ─────────────────────── 59 | // https://jsdoc.app/about-namepaths.html 60 | // IDK why you'd use this .shrug 61 | 62 | /** @namespace */ 63 | var chat = { 64 | /** 65 | * Refer to this by chat."#channel" 66 | * @namespace 67 | */ 68 | "#channel": { 69 | /** 70 | * Refer to this by chat."#channel".open 71 | * @type {boolean} 72 | * @defaultvalue 73 | */ 74 | open: true, 75 | /** 76 | * Internal quotes have to be escaped by backslash. This is 77 | * {@link chat.channel.say-\"hello\"}. 78 | */ 79 | 'say-"hello"': function (msg) {} 80 | } 81 | }; -------------------------------------------------------------------------------- /src/utils/0_@param.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Different types of param styles 3 | */ 4 | 5 | // default-numeric 6 | 7 | /** @param {number} [x=1] d4 damage */ 8 | export function m(x) {} 9 | 10 | // default-string 11 | 12 | /** 13 | * @param {string} [somebody="John Doe"] - Somebody's name. 14 | */ 15 | export function sayHello(somebody) { 16 | if (!somebody) { 17 | somebody = 'John Doe'; 18 | } 19 | alert('Hello ' + somebody); 20 | } 21 | 22 | // just-param 23 | 24 | /** 25 | * @param somebody 26 | */ 27 | export function sayBye(somebody) { 28 | alert('Bye ' + somebody); 29 | } 30 | 31 | 32 | // name-type-description 33 | 34 | /** 35 | * @param {string} somebody Somebody's name. 36 | */ 37 | export function sayYo(somebody) { 38 | alert('Yo ' + somebody); 39 | } 40 | 41 | // name-type 42 | 43 | /** 44 | * @param {string} somebody 45 | */ 46 | export function sayNo(somebody) { 47 | alert('No ' + somebody); 48 | } 49 | 50 | // optional 51 | 52 | /** 53 | * An optional parameter (using JSDoc syntax) 54 | * @param {string} [somebody] - Somebody's name. 55 | */ 56 | export function sayWoo(somebody) { 57 | if (!somebody) { 58 | somebody = 'John Doe'; 59 | } 60 | alert('Woo ' + somebody); 61 | } 62 | 63 | // with-hyphen-description 64 | 65 | /** 66 | * @param {string} somebody - Somebody's name. 67 | */ 68 | export function sayWhat(somebody) { 69 | alert('What ' + somebody); 70 | } 71 | -------------------------------------------------------------------------------- /src/utils/0_@remarks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sum api function 3 | * @remarks 4 | * Unlike the summary, the remarks block may contain lengthy documentation content. 5 | * The remarks should not restate information from the summary, since the summary section 6 | * will always be displayed wherever the remarks section appears. Other sections 7 | * (e.g. an `@example` block) will be shown after the remarks section. 8 | * 9 | * @param {number} a first parameter to add 10 | * @param {number} b second parameter to add 11 | * @returns {number} the sum of the two parameters 12 | * 13 | * @example 14 | * 15 | * ```js 16 | * import { sum } from './sum'; 17 | * 18 | * expect(sum(1, 2)).toMatchObject({ a: 1, b: 2, result: 3}); 19 | * ``` 20 | */ 21 | export const sum = (a, b = 1) => { 22 | return a + b 23 | } -------------------------------------------------------------------------------- /src/utils/0_@schema.js: -------------------------------------------------------------------------------- 1 | // https://github.com/john-doherty/jsdoc-to-json-schema#input-singleton 2 | 3 | /** 4 | * @schema.name Person 5 | * @schema.description This is an example Person object marked up with JSON schema tags to allow schema generation 6 | */ 7 | var Person = { 8 | 9 | /** 10 | * @schema.title Name 11 | * @schema.description Please enter your full name 12 | * @schema.type string 13 | * @schema.maxLength 30 14 | * @schema.minLength 1 15 | * @schema.required true 16 | */ 17 | name: '', 18 | 19 | /** 20 | * @schema.title Job Title 21 | * @schema.type string 22 | */ 23 | jobTitle: '', 24 | 25 | /** 26 | * @schema.title Telephone Number 27 | * @schema.description Please enter telephone number including country code 28 | * @schema.type string 29 | * @schema.required true 30 | */ 31 | telephone: '', 32 | 33 | /** 34 | * @schema.type string 35 | * @schema.required true 36 | */ 37 | dateOfBirth: '' 38 | }; 39 | 40 | /* 41 | Output 42 | { 43 | "name": "Person", 44 | "description": "This is an example Person object marked up with JSON schema tags to allow schema generation", 45 | "properties": { 46 | "name": { 47 | "title": "Name", 48 | "description": "Please enter your full name", 49 | "type": "string", 50 | "maxLength": 30, 51 | "minLength": 1, 52 | "required": true 53 | }, 54 | "jobTitle": { 55 | "title": "Job Title", 56 | "type": "string" 57 | }, 58 | "telephone": { 59 | "title": "Telephone Number", 60 | "description": "Please enter telephone number including country code", 61 | "type": "string", 62 | "required": true 63 | }, 64 | "dateOfBirth": { 65 | "type": "string", 66 | "required": true 67 | }, 68 | "address": { 69 | "type": "object" 70 | } 71 | } 72 | } 73 | */ 74 | 75 | // ─────────────────────── 76 | 77 | 78 | /** 79 | * @schema.name Product 80 | * @schema.description An example product marked up with json schema comments 81 | */ 82 | function Product(){ 83 | 84 | } 85 | 86 | /** 87 | * @schema.type array 88 | * @schema.minItems 3 89 | * @schema.maxItems 6 90 | * @schema.required true 91 | */ 92 | Product.prototype.types = function(){ 93 | 94 | } -------------------------------------------------------------------------------- /src/utils/0_@see.js: -------------------------------------------------------------------------------- 1 | // Inline link 2 | 3 | /** 4 | * @see {@link foo} for further information. 5 | * @see {@link https://github.com|GitHub} 6 | */ 7 | export function bar() {} 8 | 9 | // Internal link 10 | 11 | /** 12 | * Both of these will link to the bar function. 13 | * @see {@link bar} 14 | * @see bar 15 | */ 16 | export function foo() {} 17 | 18 | 19 | // Pure http link 20 | 21 | /** 22 | * external link documentation 23 | * @see https://reactjs.org/docs/context.html 24 | */ 25 | 26 | export const barTwo = () => ''; 27 | -------------------------------------------------------------------------------- /src/utils/0_@summary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A very long, verbose, wordy, long-winded, tedious, verbacious, tautological, 3 | * profuse, expansive, enthusiastic, redundant, flowery, eloquent, articulate, 4 | * loquacious, garrulous, chatty, extended, babbling description. 5 | * @summary A concise summary. 6 | */ 7 | export function bloviate() {} 8 | -------------------------------------------------------------------------------- /src/utils/0_@template.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | // https://github.com/voxpelli/types-in-js/discussions/17 4 | 5 | /** @template [T=undefined] */ 6 | class ErrorWithCause extends Error { 7 | /** 8 | * @param {string} message 9 | * @param {{ cause?: T }} [options] 10 | */ 11 | constructor (message, { cause } = {}) { 12 | if (cause) { 13 | /** @type {T} */ 14 | this.cause = cause; 15 | } 16 | // ... 17 | } 18 | } 19 | 20 | 21 | // ─────────────────────── 22 | // https://github.com/microsoft/TypeScript/pull/45483 23 | 24 | /** 25 | * @template {string} [T="hello"] 26 | * @typedef {T} Foo 27 | */ -------------------------------------------------------------------------------- /src/utils/0_@this.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @this {HTMLElement} 3 | * @param {*} e 4 | */ 5 | function callbackForLater(e) { 6 | console.log(this.clientHeight, e) 7 | } -------------------------------------------------------------------------------- /src/utils/0_@type.js: -------------------------------------------------------------------------------- 1 | // Using @type tag 2 | 3 | /** @type {string} */ 4 | const myvar = 'string'; 5 | 6 | /** 7 | * @type { "small" | "medium" | "large" } 8 | */ 9 | const myvarTwo = 'small' 10 | 11 | // See primatives 12 | 13 | // ─────────────────────── 14 | // Imported JSON type 15 | 16 | // import importedIcons from './icons.json'; 17 | 18 | // /** 19 | // * @type {import('@iconify/types').IconifyJSON} 20 | // */ 21 | // const icons = importedIcons; -------------------------------------------------------------------------------- /src/utils/0_@typedef.js: -------------------------------------------------------------------------------- 1 | /** 2 | * First name & last name 3 | * @typedef {{firstName: string, lastName: string}} BrokenName 4 | */ 5 | 6 | /** 7 | * @param {string} name 8 | * @returns {BrokenName} 9 | */ 10 | function breakName(name) { 11 | const [first, ...rest] = name.split(' ') 12 | 13 | return { 14 | firstName: first, 15 | lastName: rest.join(' ') 16 | } 17 | } 18 | 19 | // ─────────────────────── 20 | // Combining typedefs https://github.com/microsoft/TypeScript/issues/42048 21 | 22 | /** @typedef {{ name: string, age: number }} Bar - A Bar thing of sorts. */ // <-- This is for documentation tooling, and TS understand it. 23 | 24 | /** @typedef {Bar & { color: string }} ExtendBar - A Foo type of thing. */ // <-- This is for documentation tooling, and TS understand it. 25 | 26 | /** @type {ExtendBar} */ 27 | const combinedBar = { name: 'bob', age: 21, color: 'purple' } 28 | 29 | 30 | // ─────────────────────── 31 | // https://github.com/jsdoc/jsdoc/issues/1890#issuecomment-774715480 32 | 33 | /** 34 | * @typedef {object} Employee 35 | * @property {string} name - The name of an employee. 36 | * @property {string} department - The employee's department. 37 | */ 38 | /** 39 | * @typedef {object} Company 40 | * @property {string} name - The name of the company. 41 | * @property {Employee[]} employees - The employees who are responsible for the project. 42 | */ 43 | /** 44 | * Assign the project to a list of employees of the given company. 45 | * @param {Company} company - The company this project has been contracted to. 46 | */ 47 | function testFunc(company) { } 48 | 49 | 50 | // ─────────────────────── 51 | 52 | /** 53 | * @typedef FieldType 54 | * @property {string} Text "text" 55 | * @property {string} Date "date" 56 | * @property {string} DateTime "datetime" 57 | * @property {string} Number "number" 58 | * @property {string} Currency "currency" 59 | * @property {string} CheckBox "checkbox" 60 | * @property {string} ComboBox "combobox" 61 | * @property {string} Dropdownlist "dropdownlist" 62 | * @property {string} Label "label" 63 | * @property {string} TextArea "textarea" 64 | * @property {string} JsonEditor "jsoneditor" 65 | * @property {string} NoteEditor "noteeditor" 66 | * @property {string} ScriptEditor "scripteditor" 67 | * @property {string} SqlEditor "sqleditor" 68 | */ 69 | 70 | /** @type {FieldType} */ 71 | const fieldtype = { 72 | Text: "text", 73 | Date: "date", 74 | DateTime: "datetime", 75 | Number: "number", 76 | Currency: "currency", 77 | CheckBox: "checkbox", 78 | ComboBox: "combobox", 79 | Dropdownlist: "dropdownlist", 80 | Label: "label", 81 | TextArea: "textarea", 82 | JsonEditor: "jsoneditor", 83 | NoteEditor: "noteeditor", 84 | ScriptEditor: "scripteditor", 85 | SqlEditor: "sqleditor", 86 | } 87 | 88 | 89 | // ─────────────────────── 90 | // https://github.com/n3ps/json-schema-to-jsdoc/blob/master/test.js#L803 91 | 92 | /** 93 | * @typedef {object} 94 | * @property {string} [aStringProp] 95 | * @property {object} [anObjectProp] 96 | * @property {boolean} [anObjectProp.aNestedProp] Boolean desc. 97 | * @property {array} [anObjectProp.aNestedArrayProp] Array desc. 98 | * @property {number} anObjectProp.aNestedArrayProp 99 | * @property {?string} [nullableType] 100 | * @property {string|number} [multipleTypes] 101 | * @property {"hello"|"there"|"world"} [enumStringProp] 102 | */ 103 | 104 | // ─────────────────────── 105 | // https://github.com/artdecocode/typal 106 | 107 | /** 108 | * @typedef {Object} SessionConfig Description of Session Config. 109 | * @prop {string} key The cookie key. 110 | * @prop {number|'session'} [maxAge=86400000] maxAge in ms. Default is 1 day. 111 | * @prop {boolean} [overwrite] Can overwrite or not. Default `true`. 112 | * @prop {boolean} [httpOnly] httpOnly or not or not. Default `true`. 113 | * @prop {boolean} [signed=false] Signed or not. Default `false`. 114 | * @prop {boolean} [rolling] Force a session identifier cookie to be set. 115 | * @prop {boolean} [renew] Renew session when session is nearly expired. 116 | */ 117 | 118 | 119 | // ─────────────────────── 120 | // https://github.com/homer0/jsdoc-ts-utils/blob/main/src/typedef.js#L26 121 | 122 | /** 123 | * @typedef {Object} TSUtilsOptions 124 | * @property {boolean} typedefImports 125 | * Whether or not to enable the feature that removes `typedef` statements that use 126 | * `import`. 127 | * Default `true`. 128 | * @property {boolean} typeOfTypes 129 | * Whether or not to enable the feature that replaces `{typeof T}` with `{Class.}`. 130 | * Default `true`. 131 | * @property {boolean} extendTypes 132 | * Whether or not to enable the feature that allows intersections to be reformatted. 133 | * Default `true`. 134 | * @property {boolean} modulesOnMemberOf 135 | * Whether or not to enable the feature that fixes modules' paths on `memeberof` so they 136 | * can use dot notation. Default `true`. 137 | * @property {boolean} modulesTypesShortName 138 | * Whether or not to register modules types without the module path too. Default `true`. 139 | * @property {boolean} parentTag 140 | * Whether or not to transform all `parent` tags into `memberof`. Default `true`. 141 | * @property {boolean} typeScriptUtilityTypes 142 | * Whether or not to add the external utility types from TypeScript. Default `true`. 143 | * @property {?Object.} tagsReplacement 144 | * A dictionary of tags to replace, they keys are the tags being used and the values the 145 | * tag that should be used. Default `null`. 146 | */ -------------------------------------------------------------------------------- /src/utils/0__other_tags.js: -------------------------------------------------------------------------------- 1 | // https://www.webdoclabs.com/guides/tags/tags.html 2 | -------------------------------------------------------------------------------- /src/utils/0_captions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Some function 3 | * @param {number} a 4 | * @param {number} b 5 | * @param {number} c 6 | * 7 | * @example Add two numbers 8 | * add(2, 4) 9 | * // returns 6 10 | * 11 | * @example Add three numbers 12 | * add(2, 4, 6) 13 | * // returns 12 14 | */ 15 | function addThreeNumbers(a, b, c = 0) { 16 | return a + b + c 17 | } -------------------------------------------------------------------------------- /src/utils/0_images.js: -------------------------------------------------------------------------------- 1 | // Using images in JSdoc 2 | 3 | /** 4 | * this is how it works ![Image of Yaktocat](https://octodex.github.com/images/yaktocat.png) 5 | */ 6 | class MyClass { 7 | 8 | } -------------------------------------------------------------------------------- /src/utils/0_primatives.js: -------------------------------------------------------------------------------- 1 | /** @type {string} */ 2 | const str = 'string'; 3 | 4 | /** @type {number} */ 5 | const num = 123; 6 | 7 | /** @type {boolean} */ 8 | const bool = true; 9 | 10 | /** @type {null} */ 11 | const nul = null; 12 | 13 | /** @type {undefined} */ 14 | const und = undefined; 15 | 16 | /** @type {symbol} */ 17 | const sym = Symbol('foo'); 18 | 19 | /** @type {*} */ 20 | const jsDocAny = 'any value'; 21 | 22 | /** @type {any} */ 23 | const tsAny = 'any value'; 24 | 25 | /** @type {unknown} */ 26 | const tsUnknown = 'unknown value'; 27 | 28 | /** @type {PromiseLike} */ 29 | var promisedString = Promise.resolve('hi') 30 | 31 | // Enum into Array 32 | // https://medium.com/@antonkrinitsyn/jsdoc-frequent-patterns-436dad6dbee1 33 | /** 34 | * @typedef {'ally' | 'enemy'} PlayerType 35 | * 36 | * @typedef Player 37 | * @property {PlayerType} type 38 | */ 39 | 40 | /** @type {Player[]} */ 41 | const players = [ 42 | { 43 | type: 'ally', 44 | } 45 | ] -------------------------------------------------------------------------------- /src/utils/0_typeof.js: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------- typeof 2 | // https://github.com/chunjin666/jsdoc-learning/blob/master/src/01-types/04-%40type-advanced.js#L19 3 | // When the type of a value is more complicated and cumbersome to write, you can use `typeof` to get its type. 4 | 5 | const userAccountDefault = { 6 | id: 1, 7 | username: 'name1', 8 | account: 'account', 9 | age: 18, 10 | isLogin : false , 11 | }; 12 | 13 | /** 14 | * 15 | * @param {typeof userAccountDefault} account 16 | */ 17 | export function setAccount(account) { 18 | console.log(account.id) 19 | } 20 | 21 | setAccount({ 22 | id: 2, 23 | username: 'name2', 24 | account: 'account2', 25 | age: 22, 26 | isLogin : true, 27 | }) -------------------------------------------------------------------------------- /src/utils/1_array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSDoc style 3 | * @typedef {object} RgbColors 4 | * @property {number} red 5 | * @property {number} green 6 | * @property {number} blue 7 | */ 8 | 9 | 10 | /** 11 | * JSDoc style with primative 12 | * @type {Array} 13 | */ 14 | const gradesXyz = [98, 97.7, 76, 89]; 15 | 16 | /** 17 | * JSDoc style with primative 18 | * @type {Array} 19 | */ 20 | const grades = [98, 97.7, 76, 89]; 21 | 22 | /** 23 | * JSDoc style 24 | * @type {Array.} 25 | */ 26 | const colors1 = [{ red: 0, green: 0, blue: 0 }]; 27 | 28 | /** 29 | * TypeScript style 30 | * @type {Array} 31 | */ 32 | const color3 = [{ red: 255, green: 255, blue: 255 }]; 33 | 34 | /** 35 | * JSDoc type bracket 36 | * @type {String[]} 37 | */ 38 | const arrayOfStrings = ['a', 'b']; 39 | 40 | /** 41 | * @type {Number[]} 42 | */ 43 | const arrayOfNumbers = [1, 2, 3]; 44 | 45 | /** 46 | * @type {Boolean[]} 47 | */ 48 | const arrayOfBools = [true, false, true]; 49 | 50 | /** 51 | * @type {Array.} 52 | */ 53 | const arrayOfStringOrBools = ['true', false, 'true']; 54 | 55 | /** 56 | * TypeScript style 57 | * @type {RgbColors[]} 58 | */ 59 | const color2 = [{ red: 111, green: 111, blue: 111 }]; 60 | 61 | /** 62 | * TypeScript style array of objects 63 | * @type Array<{localPath:string, fullPath: string}> 64 | */ 65 | let filePaths = [{ localPath: 'xyz', fullPath: 'abc' }]; 66 | 67 | // Array with any type 68 | /** @type {Array} */ 69 | var myArrayOfAnyType = ["children", true, 1, {}]; 70 | 71 | /** 72 | * @typedef MyType 73 | * @type {Object} 74 | * @property {string} userId 75 | */ 76 | /** 77 | * @typedef MyTypeArray 78 | * @type {Array.} 79 | */ 80 | /** @type {MyTypeArray} */ 81 | var xyzArray = [{ userId: '123'}, { userId: 'hehehe' }]; 82 | // ────── Function returning an array of objects ───────────────── 83 | 84 | /** 85 | * @typedef AwesomeObject 86 | * @type {Object} 87 | * @property {string} name 88 | * @property {boolean} next 89 | * @property {string} test 90 | */ 91 | 92 | /** 93 | * @param {Array.} awesomeObjects Awesome objects. 94 | */ 95 | function totalAmount(awesomeObjects) { 96 | return awesomeObjects.map((d) => d) 97 | } 98 | 99 | // ────── Function returning an array of objects shorthand ───────────────── 100 | 101 | /** 102 | * @typedef {Object} Article 103 | * @property {number} price 104 | * @property {number} vat 105 | * @property {string} string 106 | * @property {boolean=} sold 107 | */ 108 | 109 | /** 110 | * Now we can use Article as a proper type 111 | * @param {[Article]} articles 112 | */ 113 | function totalAmount(articles) { 114 | return articles.reduce((total, article) => { 115 | return total + addVAT(article) 116 | }, 0) 117 | } 118 | /** 119 | * @param {Article} article 120 | */ 121 | function addVAT(article) { 122 | return article.price + 1 123 | } 124 | 125 | // ─────────────────────── 126 | // an array of objects with some known and some unknown properties. 127 | // https://twitter.com/Stegosource/status/1395421390698733570 128 | 129 | /** 130 | * @typedef {Array<{ 131 | * known: number 132 | * yep: boolean 133 | * defo: string 134 | * } 135 | * & 136 | * Record 137 | * > 138 | * } MyCustomArray 139 | */ 140 | 141 | /** @type {MyCustomArray} */ 142 | const myArray = [{ known: 2, yep: true, defo: 'yay', xyz: '123' }] 143 | 144 | 145 | // ───────Array of arrays──────────────── 146 | // https://stackoverflow.com/questions/66912667/whats-the-best-way-to-document-an-array-of-arrays-of-arrays-using-jsdoc 147 | 148 | /** @typedef {[string, number, string]} MyTuple */ 149 | 150 | /** @type {MyTuple} */ 151 | const single = ['aqua-160', 160, 'PreCleaning'] 152 | 153 | /** @type {Array>} */ 154 | const arrayOfArrays = [[1, 2], [3, 4]]; 155 | 156 | /** @type {number[][]} */ 157 | const arrayOfArraysDiffSyntax = [[1, 2], [3, 4]]; 158 | 159 | /** @type {Array>} */ 160 | const nestedArrays = [ 161 | [ 162 | ['aqua-160', 160, 'PreCleaning'], 163 | ['aqua-260', 260, 'PreCleaning']], 164 | [ 165 | ['aqua-360', 360, 'PostCleaning'] 166 | ] 167 | ]; 168 | 169 | // ────────Conditional pair tuple ─────────────── 170 | // https://github.com/jsdoc/jsdoc/issues/1703#issuecomment-898203535 171 | 172 | /** 173 | * @template IType 174 | * @template FnReturnType 175 | * @typedef {[IType, FnReturnType]} ConditionPair 176 | */ 177 | 178 | const state = 'foo' 179 | function set_state() {} 180 | 181 | /** @type ConditionPair */ 182 | const tuple = [state, set_state] 183 | 184 | /** @type ConditionPair */ 185 | const tupleTwo = [state, 1] 186 | 187 | 188 | // ─────────────────────── 189 | // Read only array https://discord.com/channels/508357248330760243/813896878058897458/875389849547444265 190 | 191 | /** 192 | * @param {TemplateStringsArray} strings 193 | * @param {...string[]} expr 194 | */ 195 | const xyzThing = (strings, ...expr) => { 196 | // strings.push('x') will error 197 | return strings.map((x) => { 198 | return x 199 | }) 200 | } -------------------------------------------------------------------------------- /src/utils/1_class.js: -------------------------------------------------------------------------------- 1 | 2 | // ─────────────────────── 3 | // https://github.com/giltayar/jsdoc-typing/blob/master/src/class.js 4 | 5 | class PersonClass { 6 | /**@type {string}*/ 7 | firstName 8 | /**@type {string}*/ 9 | lastName 10 | 11 | /** 12 | * @param {string} firstName 13 | * @param {string} lastName 14 | */ 15 | constructor(firstName, lastName) { 16 | this.firstName = firstName 17 | this.lastName = lastName 18 | } 19 | 20 | /** 21 | * @returns {string} 22 | */ 23 | fullName() { 24 | return `${this.firstName} ${this.lastName}` 25 | } 26 | } 27 | 28 | const person = new PersonClass('bob', 'smith') 29 | 30 | // https://fettblog.eu/typescript-jsdoc-superpowers/ 31 | 32 | /** 33 | * Creates a new Person. 34 | * @class 35 | */ 36 | export function Person() { 37 | 38 | } 39 | 40 | // ─────────────────────── 41 | // https://ics.media/entry/6789/ 42 | 43 | /** 44 | * Count Manager class 45 | * @constructor 46 | */ 47 | function CountManager() { 48 | /** 49 | * Current count 50 | * @type {Number} 51 | */ 52 | this._count = 0; 53 | 54 | /** 55 | * Add to count 56 | */ 57 | this.addCount = function() { 58 | this._count++; 59 | }; 60 | 61 | /** 62 | * Get current count 63 | * @return {Number} current count 64 | */ 65 | this.getCount = function() { 66 | return this._count; 67 | }; 68 | } 69 | 70 | // ─────────────────────── 71 | 72 | 73 | /** 74 | * this is BaseClass. 75 | */ 76 | export class BaseClass { 77 | /** 78 | * this is a method of BaseClass. 79 | * @returns {string} a greeting. 80 | */ 81 | baseMethod(){ 82 | return 'this is base method'; 83 | } 84 | } 85 | 86 | /** 87 | * this is MyClass. 88 | */ 89 | export default class MyClass extends BaseClass { 90 | /** 91 | * creates a instance of MyClass. 92 | * @param {number} value - initial value. 93 | */ 94 | constructor(value){ 95 | /** 96 | * this is property of MyClass. 97 | * @type {number} 98 | * @private 99 | */ 100 | super() 101 | this._property = value; 102 | } 103 | 104 | /** 105 | * this is method of MyClass. 106 | * @param {number} a - this is a 1st number value. 107 | * @param {number} b - this is a 2nd number value. 108 | * @returns {string} repeated Hello 109 | */ 110 | method(a, b){ 111 | return 'Hello'.repeat((a + b) * this._property); 112 | } 113 | } 114 | 115 | // ─────────────────────── 116 | // https://github.com/joelday/vscode-docthis/blob/master/test/largeFile.ts 117 | 118 | /** 119 | * This description was written from the 120 | * 121 | * @class SomeClass 122 | */ 123 | class SomeClass { 124 | /** 125 | * Testing a property. 126 | * 127 | * @memberOf SomeClass 128 | */someProperty = true; 129 | 130 | /** 131 | * This description was written from the Ctrl+Alt+D D shortcut. 132 | * 133 | * @param {string} someParam1 134 | * @param {number} someParam2 135 | * @returns {boolean} 136 | * 137 | * @memberOf SomeClass 138 | */ 139 | someFunction1(someParam1, someParam2) { 140 | return true; 141 | } 142 | 143 | /** 144 | * This is a test of the enableJumpToDescriptionLocation setting set to true. 145 | * 146 | * @param {string} someParam1 147 | * @param {number} someParam2 148 | * @returns {boolean} 149 | * 150 | * @memberOf SomeClass 151 | */ 152 | someFunction2(someParam1, someParam2) { 153 | return true; 154 | } 155 | 156 | /** 157 | * This one was a successful test with the setting off 158 | * 159 | * @param {string} someParam1 160 | * @param {number} someParam2 161 | * @returns {boolean} 162 | * 163 | * @memberOf SomeClass 164 | */ 165 | someFunction3(someParam1, someParam2) { 166 | return true; 167 | } 168 | 169 | /** 170 | * Test with private. 171 | * 172 | * @private 173 | * @param {string} someParam1 174 | * @param {number} someParam2 175 | * @returns {boolean} 176 | * 177 | * @memberOf SomeClass 178 | */ 179 | someFunction4(someParam1, someParam2) { 180 | return true; 181 | } 182 | 183 | /** 184 | * Test with public. 185 | * 186 | * @param {string} someParam1 187 | * @param {number} someParam2 188 | * @returns {boolean} 189 | * 190 | * @memberOf SomeClass 191 | */ 192 | someFunction5(someParam1, someParam2) { 193 | // Suppress unused function error 194 | this.someFunction4('string', 2); 195 | return true; 196 | } 197 | 198 | /** 199 | * Test with static. 200 | * 201 | * @static 202 | * @param {string} someParam1 203 | * @param {number} someParam2 204 | * @returns {boolean} 205 | * 206 | * @memberOf SomeClass 207 | */ 208 | static someFunction6(someParam1, someParam2) { 209 | return true; 210 | } 211 | 212 | /** 213 | * Testing with docthis.includeMemberOfOnClassMembers set to false 214 | * 215 | * @param {string} someParam1 216 | * @param {number} someParam2 217 | * @returns {boolean} 218 | */ 219 | someFunction7(someParam1, someParam2) { 220 | return true; 221 | } 222 | } 223 | 224 | 225 | // ─────────────────────── 226 | // https://github.com/discordjs/docgen/blob/master/test/src/SomeClass.js 227 | 228 | const EventEmitter = require('events').EventEmitter; 229 | 230 | /** 231 | * A very classy class with lots of class 232 | * @extends EventEmitter 233 | */ 234 | class ClassyClass extends EventEmitter { 235 | /** 236 | * Constructs a thing. 237 | */ 238 | constructor() { 239 | super(); 240 | 241 | /** 242 | * Just some thing 243 | * @type {?number} 244 | */ 245 | this.thing = 42; 246 | } 247 | 248 | /** 249 | * Does stuff. 250 | * @param {?string} stuff Stuff to do 251 | * @param {StuffDoer} doer Callback to do the stuff 252 | * @returns {?number} A thing 253 | */ 254 | doStuff(stuff, doer) { 255 | console.log(`Doing some pretty crazy stuff with ${stuff}`); 256 | doer(stuff); 257 | return this.thing; 258 | } 259 | 260 | /** 261 | * Who knows what this does. 262 | * @emits ClassyClass#thingDone 263 | */ 264 | hmm() { 265 | console.log('Hmmmm..'); 266 | 267 | /** 268 | * Emitted when a thing is done 269 | * @event ClassyClass#thingDone 270 | * @param {SomeThing} thingy Thing 271 | */ 272 | this.emit('thingDone', 4242424242); 273 | } 274 | } 275 | 276 | /** 277 | * Just some thing 278 | * @typedef {Object} SomeThing 279 | * @property {number} someNumber A really cool number 280 | */ 281 | 282 | /** 283 | * Does some stuff with some other stuff. 284 | * @callback StuffDoer 285 | * @param {?string} stuff Stuff to use to do stuff 286 | */ 287 | 288 | /** 289 | * @external ClientOptions 290 | * @see {@link http://hydrabolt.github.io/discord.js/#!/docs/tag/master/typedef/ClientOptions} 291 | */ -------------------------------------------------------------------------------- /src/utils/1_functions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSDoc style named function type 3 | * @callback AddStuff 4 | * @param {number} x 5 | * @param {number} y 6 | * @returns {number} 7 | */ 8 | 9 | /** @type {AddStuff} */ 10 | const addStuff = (x, y) => x + y; 11 | 12 | /** 13 | * TypeScript style inline function type 14 | * @typedef {(x: number, y: number) => number} TsAdd 15 | */ 16 | 17 | /** @type {TsAdd} */ 18 | const tsAdd = (x, y) => x + y; 19 | 20 | /** 21 | * JSDoc style type function with function declaration 22 | * @param {number} x 23 | * @param {number} y 24 | * @returns {number} 25 | */ 26 | function addDec(x, y) { 27 | return x + y; 28 | } 29 | 30 | 31 | 32 | /** 33 | * JSDoc style optional parameter 34 | * @param {number} [x] optional 35 | * @param {number=} y number or undefined 36 | * @param {number} [z=1] optional with default (default not show in type hint) 37 | */ 38 | function jsDocOptional(x, y, z = 1) {} 39 | 40 | 41 | /** 42 | * JSDoc style rest parameter 43 | * @param {...number} num 44 | * @returns {number} 45 | */ 46 | function sum(...num) { 47 | return num.reduce((s, v) => s + v, 0); 48 | } 49 | 50 | /** 51 | * TypeScript style rest parameter 52 | * @param {number[]} num 53 | */ 54 | function tsSum(...num) { 55 | return num.reduce((s, v) => s + v, 0); 56 | } 57 | 58 | /** 59 | * No explicit return value 60 | * @returns {void} 61 | */ 62 | function noReturn() { 63 | console.log('no explicit return'); 64 | } 65 | 66 | /** 67 | * Function never return 68 | * @returns {never} 69 | */ 70 | function neverReturn() { 71 | throw Error('ERRORRRRR'); 72 | } 73 | 74 | /** 75 | * @param {string} prefix 76 | * @returns {(baseStr: string) => string} 77 | */ 78 | const prependPrefix = (prefix) => (baseStr)=> `${prefix}${baseStr}`; 79 | 80 | /** 81 | * Function no returrn value https://fettblog.eu/typescript-jsdoc-superpowers/ 82 | * @param {string} url 83 | * @param {(status: number, response?: string) => void} cb 84 | */ 85 | function loadData(url, cb) { 86 | const xhr = new XMLHttpRequest(); 87 | xhr.open('GET', url) 88 | xhr.onload = () => { 89 | cb(xhr.status, xhr.responseText) 90 | } 91 | } 92 | 93 | 94 | /** 95 | * Default numeric param 96 | * @param {number} [x=1] d4 damage 97 | */ 98 | export function m(x) { 99 | return x 100 | } 101 | 102 | /** 103 | * Default string param 104 | * @param {string} [somebody="John Doe"] - Somebody's name. 105 | */ 106 | export function sayHello(somebody) { 107 | if (!somebody) { 108 | somebody = 'John Doe'; 109 | } 110 | alert('Hello ' + somebody); 111 | } 112 | 113 | /** 114 | * Just params 115 | * @param somebody 116 | */ 117 | export function sayBye(somebody) { 118 | alert('Bye ' + somebody); 119 | } 120 | 121 | 122 | /** 123 | * @typedef {Object} Toast 124 | * @property {string} id 125 | * @property {boolean} closed - Indicates whether user has close the toast. 126 | * @property {Date} generatedOn - Indicates when the toast was generated. 127 | * @property {string} message - toast content. 128 | * @property {"warn" | "info"} type - Indicates type of toast. 129 | * Also useful to show different icons. 130 | */ 131 | 132 | /** 133 | * A function for showing toast 134 | * @param {Toast} toast - {@link toast} object 135 | * containing all components of the toast. 136 | */ 137 | export function showToast(toast) {} 138 | 139 | // ─────────────────────── 140 | // https://twitter.com/jbscript/status/1415553540823535627/photo/1 141 | 142 | /** 143 | * @param {string} selector 144 | * @param {{ 145 | * name?: string 146 | * stopIf?: () => boolean 147 | * context?: Document | HTMLElement 148 | * timeout?: number 149 | * }} options 150 | * @returns {Promise} 151 | */ 152 | function getElement(selector, { 153 | name = '', 154 | stopIf = () => true, 155 | context = document, 156 | timeout = Infinity, 157 | } = {}) { 158 | return new Promise((resolve) => { 159 | 160 | }) 161 | } 162 | 163 | 164 | // ─────────────────────── 165 | // https://github.com/aminya/jsdoc2flow/blob/master/test/fixtures/annotated/test2.js#L5 166 | 167 | /** 168 | * Function 1 169 | * 170 | * @param {object} obj 171 | * @param {string} obj.a 172 | * @param {string} obj.b 173 | * @param {object} obj.c 174 | * @param {object=} obj.d 175 | * @param {object=} obj.e 176 | * @returns {number} 177 | */ 178 | const fn1 = ({ a, b, c, d, e }) => { 179 | return 1 180 | } 181 | 182 | 183 | // ─────────────────────── 184 | // https://github.com/andreidmt/tpl-ts-jsdoc/blob/master/src/hello-world.js#L6 185 | 186 | /** 187 | * @typedef {Object} SayHelloFnReturn 188 | * 189 | * @property {string} beep 190 | * @property {string} boop 191 | */ 192 | 193 | /** 194 | * Function with types infered from docs, 2 birds in hand. 195 | * 196 | * @param {Object} [props={}] 197 | * @param {"lorem"|"dolor"} [props.foo="lorem"] 198 | * @param {string} [props.bar="ipsum"] 199 | * 200 | * @returns {SayHelloFnReturn} 201 | */ 202 | const sayOy = ({ foo = "lorem", bar = "ipsum" } = {}) => ({ 203 | beep: `oy ${foo}`, 204 | boop: `oy ${bar}`, 205 | }) 206 | 207 | const robotSays = sayOy({ foo: "dolor" }) 208 | 209 | 210 | // ─────────────────────── 211 | // https://github.com/homer0/parserror/blob/c12b20e3a321e1e01f41178eceb1d3210991d40f/src/parserror.js#L240 212 | 213 | 214 | /** 215 | * An object with a signature similar to an {@link Error} that {@link Parserror} can 216 | * parse. 217 | * 218 | * @typedef {Object} ParserrorErrorObject 219 | * @property {string} message The error message. 220 | */ 221 | 222 | /** 223 | * The options that can be used to customize how {@link Parserror#parse} works. 224 | * 225 | * @typedef {Object} ParserrorParseOptions 226 | * @property {string[]} cases A list of specific cases it should validated against. 227 | * @property {string[]} scopes A list of specific scopes it should use to valdiate the 228 | * error. 229 | * @property {?string} fallback A fallback message in case the error can't be parsed. 230 | * If not specified, the returned error will maintain the 231 | * original message. 232 | */ 233 | 234 | /** 235 | * A custom version of `Error` so the Parserror can store the parsing parameters and some 236 | * context information. 237 | * 238 | * @augments Error 239 | */ 240 | class FormattedError extends Error { 241 | /** 242 | * @param {string} message 243 | * The error message. 244 | * @param {Object. | string[]} [params={}] 245 | * The parsed parameters Parserror. When parsing a case that uses named groups, the 246 | * parameters are stored on an `object`; otherwise, they'll be an `array`. 247 | * @param {?Object} [context=null] 248 | * Any extra context information for the error. 249 | */ 250 | constructor(message, params = {}, context = null) { 251 | super(message); 252 | /** 253 | * The parsed parameters Parserror found. When parsing a case that uses named groups, 254 | * the parameters are stored on an `object`; otherwise, they'll be an `array`. 255 | * 256 | * @type {Object. | string[]} 257 | * @todo Remove `Object.freeze`. 258 | */ 259 | this.params = params; 260 | /** 261 | * Any extra context information for the error. 262 | * 263 | * @type {Object} 264 | * @todo Remove `Object.freeze`. 265 | */ 266 | this.context = Object.freeze(context || {}); 267 | 268 | if (Error.captureStackTrace) { 269 | Error.captureStackTrace(this, this.constructor); 270 | } 271 | } 272 | } 273 | 274 | /** 275 | * Parses and formats an error. 276 | * 277 | * @param {Error | string | ParserrorErrorObject} error 278 | * The error to parse. 279 | * @param {Partial} [options={}] 280 | * Options to customize how the parsing is done. 281 | * @returns {FormattedError} 282 | * @throws {TypeError} 283 | * If `error` is not an {@link Error}, a string or a {@link ParserrorErrorObject}. 284 | */ 285 | function parse(error, options = {}) { 286 | const useOptions = { 287 | cases: [], 288 | scopes: [], 289 | fallback: null, 290 | ...options, 291 | }; 292 | return new FormattedError('foobar', {}, { original: true }); 293 | } 294 | 295 | parse('lol', { 296 | cases: ['cool'], 297 | }) 298 | -------------------------------------------------------------------------------- /src/utils/1_htmlNodes.js: -------------------------------------------------------------------------------- 1 | // https://zenn.dev/asama/articles/0c66573e488b22 2 | 3 | /** @type {HTMLElement|null} */ 4 | const myElement = document.querySelector('.my-div'); 5 | if (myElement) { 6 | myElement.dataset.myData = ""; 7 | } 8 | 9 | /** @type {Window} */ 10 | var win; -------------------------------------------------------------------------------- /src/utils/1_map.js: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/hrdtbs/f7e567c0738725a16a9de7326dc11127 2 | 3 | /** @type Map. */ 4 | const elephant = new Map() 5 | 6 | /** @type Map */ 7 | const elephantMap = new Map() 8 | 9 | /** 10 | * The child values of this Type 11 | * @since 0.5.0 12 | * @type {Map} 13 | * @private 14 | */ 15 | const birdBox = new Map(); -------------------------------------------------------------------------------- /src/utils/1_object.js: -------------------------------------------------------------------------------- 1 | // Object with optional property 2 | 3 | /** 4 | * User type definition 5 | * @typedef {Object} User 6 | * @property {string} email 7 | * @property {string} [nickName] 8 | */ 9 | export const user = { 10 | email: 's', 11 | } 12 | 13 | // Object with nested values 14 | 15 | /** 16 | * @typedef Config 17 | * @property {object} defaults - The default values for parties. 18 | * @property {number} defaults.players - The default number of players. 19 | * @property {string} defaults.level - The default level for the party. 20 | * @property {object} defaults.treasure - The default treasure. 21 | * @property {number} defaults.treasure.gold - How much gold the party starts with. 22 | */ 23 | export const config = { 24 | defaults: { 25 | players: 1, 26 | level: 'beginner', 27 | treasure: { 28 | gold: 0, 29 | }, 30 | }, 31 | } 32 | 33 | // Using typedefs 34 | 35 | /** 36 | * JSDoc style 37 | * @typedef {object} Rgb 38 | * @property {number} red 39 | * @property {number} green 40 | * @property {number} blue 41 | */ 42 | 43 | /** @type {Rgb} */ 44 | const color = { red: 255, green: 255, blue: 255 }; 45 | 46 | /** 47 | * TypeScript style 48 | * @typedef {{ brand: string; color: Rgb }} Vehicle 49 | */ 50 | 51 | /** @type {Vehicle} */ 52 | const car = { 53 | brand: 'Some Brand', 54 | color: { red: 255, green: 255, blue: 255 }, 55 | }; 56 | 57 | // Object with unknown number of keys 58 | 59 | /** 60 | * Object with unknown keys 61 | * @type {{[key: string]: string}} 62 | */ 63 | const obj = {}; 64 | obj.a = 'foo'; 65 | obj.b = 'bar'; 66 | 67 | 68 | // ──────Object with Date──────── 69 | 70 | /** 71 | * @typedef Thing 72 | * @property {string} id 73 | * @property {number} index 74 | * @property {Date} expires 75 | * @property {function} callback 76 | */ 77 | 78 | /** @type Thing */ 79 | let thing = { 80 | id: 'id', 81 | index: 1, 82 | expires: new Date(), 83 | callback: function () {} 84 | } 85 | 86 | // ────────How to define a hashmap / dictionary / plain object─────────────── 87 | /** 88 | * @typedef ThingTwo 89 | * @property {Record} stuff 90 | */ 91 | 92 | /** @type ThingTwo */ 93 | let thingTwo = { 94 | stuff: { 95 | xyz: 'abc', 96 | } 97 | } 98 | 99 | // ───────Object overload─────── 100 | // https://github.com/BeyondCodeBootcamp/jsdoc-typescript-starter 101 | 102 | /** 103 | * @typedef Foo 104 | * @property {string} foo 105 | */ 106 | 107 | /** 108 | * @typedef Bar 109 | * @property {string} bar 110 | */ 111 | 112 | /** @type {Foo & Bar} */ 113 | var foobar = { foo: "foo", bar: "bar" }; 114 | 115 | /** @typedef {Foo & Bar} FooBar */ 116 | /** @type {FooBar} */ 117 | var zaz = { foo: "foo", bar: "bar" }; 118 | 119 | // ─────────────────────── 120 | 121 | // Function with TypeScript style shorthand with optional values 122 | 123 | /** 124 | * @param {string} selector 125 | * @param {{ 126 | * name?: string 127 | * stopIf?: () => boolean 128 | * context?: Document | HTMLElement 129 | * timeout?: number 130 | * }} options 131 | * @returns {Promise} 132 | */ 133 | function getElement(selector, { 134 | name = '', 135 | stopIf = () => true, 136 | context = document, 137 | timeout = Infinity, 138 | } = {}){ 139 | return new Promise((resolve) => { 140 | 141 | }) 142 | } 143 | 144 | getElement('test') 145 | /* // type errors 146 | getElement('test', { unexpected: true }) 147 | getElement('test', { timeout: '123' }) 148 | /** */ 149 | 150 | 151 | // ────── Recursive property ──────── 152 | 153 | // https://github.com/BeyondCodeBootcamp/jsdoc-typescript-starter/blob/38fb9ff20940f7127724578530e3ae823fd07d5f/types.js#L15 154 | 155 | /** 156 | * @typedef {Object} AppUser 157 | * @property {string} given_name 158 | * @property {string} family_name 159 | * @property {string} [favorite_movie] 160 | * @property {string} favorite_book 161 | * @property {Array} [friends] 162 | * @property {Record | null} [stuff] 163 | */ 164 | 165 | /** @type AppUser */ 166 | const appUser = { 167 | given_name: 'bob', 168 | family_name: 'smith', 169 | favorite_book: 'harry potter', 170 | stuff: { 171 | hi: 'there' 172 | }, 173 | friends: [{ 174 | given_name: 'bob', 175 | family_name: 'smith', 176 | favorite_book: 'harry potter', 177 | }], 178 | } 179 | 180 | 181 | // ─────────────────────── 182 | // https://gist.github.com/hrdtbs/f7e567c0738725a16a9de7326dc11127 183 | 184 | /** 185 | * @typedef {Object} TestProps 186 | */ 187 | /** 188 | * @type {TestProps} 189 | */ 190 | const x = { 191 | foobar: 1, 192 | no: 2 193 | } 194 | 195 | 196 | // ─────────────────────── 197 | // Partial object with optional keys via {Partial} 198 | 199 | /** 200 | * My object 201 | * 202 | * @typedef {Object} MyObjectWithOptionalParams 203 | * @property {string[]} cases A list of specific cases it should validated against. 204 | * @property {string[]} scopes A list of specific scopes it should use to valdiate the error. 205 | * @property {?string} fallback A fallback message in case the error can't be parsed. If not specified, the returned error will maintain the original message. 206 | */ 207 | 208 | /** @type {Partial} */ 209 | const objectWithOptionalKeys = { 210 | cases: ['xyz'] 211 | } 212 | 213 | 214 | // ─────────────────────── 215 | // https://dev.to/samuel-braun/boost-your-javascript-with-jsdoc-typing-3hb3 216 | 217 | // Type aliasing 218 | /** @typedef {number} Age */ 219 | /** @typedef {string} Name */ 220 | /** @typedef {{ name: Name; age: Age }} MyUser */ 221 | 222 | /** @type {MyUser} */ 223 | const userThing = { name: 'John Doe', age: 25 }; 224 | -------------------------------------------------------------------------------- /src/utils/1_objectz-shorthand.js: -------------------------------------------------------------------------------- 1 | /* 2 | Example of object shorthand with optional 3 | */ 4 | 5 | /** 6 | * @param {string} selector 7 | * @param {{ 8 | * name?: string 9 | * stopIf?: () => boolean 10 | * context?: Document | HTMLElement 11 | * timeout?: number 12 | * }} options 13 | * @returns {Promise} 14 | */ 15 | function getElement(selector, { 16 | name = '', 17 | stopIf = () => true, 18 | context = document, 19 | timeout = Infinity, 20 | } = {}){ 21 | return new Promise((resolve) => { 22 | 23 | }) 24 | } 25 | 26 | getElement('test') 27 | /* // type errors 28 | getElement('test', { unexpected: true }) 29 | getElement('test', { timeout: '123' }) 30 | /** */ -------------------------------------------------------------------------------- /src/utils/1_set.js: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/hrdtbs/f7e567c0738725a16a9de7326dc11127 2 | 3 | /** @type Set. */ 4 | /** @type Set */ -------------------------------------------------------------------------------- /src/utils/2_buffer.js: -------------------------------------------------------------------------------- 1 | // https://github.com/Beatso/ScalePixelArt/blob/main/index.js 2 | /** 3 | * 4 | * @param {*} str 5 | * @returns {*} 6 | */ 7 | function sharp(str) {} 8 | 9 | /** 10 | * Resizes an image with nearest neighbour interpolation. 11 | * @param {Buffer | Uint8Array | Uint8ClampedArray | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array | string} input - The image to resize. 12 | * @param {number} scale - How many times bigger the image should be. Can be negative to shrink the image. 13 | * @returns {Promise} - The resized image. 14 | */ 15 | const scaleImage = async (input, scale) => { 16 | 17 | try { 18 | const image = sharp(input) 19 | const metadata = await image.metadata() 20 | const output = await image 21 | .resize ( metadata.width * scale, null, { kernel: "nearest" }) 22 | .toBuffer() 23 | return output 24 | } 25 | 26 | catch (error) { 27 | throw error 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/utils/2_event-listener.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * Element selector 5 | * @typedef {(string|Node|NodeList|EventTarget|null)} Selector 6 | */ 7 | 8 | /** 9 | * Event to listen to 10 | * @typedef {(string|string[])} EventType 11 | */ 12 | 13 | /** 14 | * @typedef {Object} MyOptions 15 | * @prop {boolean} [once] 16 | */ 17 | 18 | /** 19 | * Cleanup event listener 20 | * @callback RemoveListener 21 | * @returns {AttachListener} 22 | */ 23 | 24 | /** 25 | * ReAttach event listener 26 | * @callback AttachListener 27 | * @returns {RemoveListener} 28 | */ 29 | 30 | /** 31 | * Add an event listener 32 | * @callback AddEventListener 33 | * @param {Selector} elements - Element(s) to attach event(s) to. 34 | * @param {EventType} eventType - Event(s) to listen to 35 | * @param {Function} handler - Function to fire 36 | * @param {MyOptions} [options] - Event listener options 37 | * @returns {RemoveListener} 38 | */ 39 | 40 | /** @type {AddEventListener} */ 41 | function add(elements, eventType, handler, options = {}) { 42 | /** @type RemoveListener */ 43 | const remove = () => { 44 | // clean up 45 | return () => { 46 | // reattach 47 | /** @type AttachListener */ 48 | return add(elements, eventType, handler, options) 49 | } 50 | } 51 | return remove 52 | } 53 | 54 | const x = add('button', 'click', () => { 55 | console.log('yay') 56 | }) -------------------------------------------------------------------------------- /src/utils/2_imports-commonJS.js: -------------------------------------------------------------------------------- 1 | // via https://docs.joshuatz.com/cheatsheets/js/jsdoc/ 2 | 3 | // Use `import(FILE_PATH)['EXPORTED_THING']` instead of `import(FILE_PATH).EXPORTED_THING 4 | 5 | /** 6 | * @typedef {typeof import('./imports/my-js-file')['myExportedFunc']} MyFunc 7 | */ 8 | 9 | /** 10 | * Example of common js import ad type 11 | * @param {MyFunc} xyz 12 | * @returns {{total: number, adjustedTotal: number, avgWeight: number}} totals 13 | */ 14 | function myFunc(xyz) { 15 | // implementation details omitted 16 | return { 17 | total: 2, 18 | adjustedTotal: 3, 19 | avgWeight: 4, 20 | // @ts-ignore-start 21 | lol: true 22 | } 23 | } -------------------------------------------------------------------------------- /src/utils/2_imports-ts.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * Renders a component with imported types 5 | * @param { import("./imports/ts-types").TinyProps } props 6 | * @return {React.ReactElement} - React component 7 | */ 8 | export default function ButtonImport(props) { 9 | return ( 10 | 13 | ) 14 | } -------------------------------------------------------------------------------- /src/utils/2_imports-ts2-refs.js: -------------------------------------------------------------------------------- 1 | // https://twitter.com/dr_sensor/status/1723468421722210367 2 | 3 | /* 4 | Import a d.ts file and reference exported types 5 | 6 | my.d.ts contains: 7 | export function myFun(a: string, b: string, c: string): number; 8 | 9 | myFun is referenced via @type $["myFun"] 10 | */ 11 | 12 | /** 13 | * @typedef {import("./imports/my.d.ts")} $ 14 | */ 15 | 16 | /** @type $["myFun"] */ 17 | export function fun(a, b, c) { 18 | return 1 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/2_overload.js: -------------------------------------------------------------------------------- 1 | // ───────Object overload─────── 2 | // https://github.com/BeyondCodeBootcamp/jsdoc-typescript-starter 3 | 4 | /** 5 | * @typedef Foo 6 | * @property {string} foo 7 | */ 8 | 9 | /** 10 | * @typedef Bar 11 | * @property {string} bar 12 | */ 13 | 14 | /** @type {Foo & Bar} */ 15 | var foobar = { foo: "foo", bar: "bar" }; 16 | 17 | /** @typedef {Foo & Bar} FooBar */ 18 | /** @type {FooBar} */ 19 | var foobar = { foo: "foo", bar: "bar" }; 20 | 21 | 22 | // ─────────────────────── 23 | // https://austingil.com/typescript-function-overloads-with-jsdoc/ 24 | 25 | // A Naive Solution 26 | /** 27 | * @param {string | number} input 28 | * @returns {string | number} 29 | */ 30 | function double(input) { 31 | if (typeof input === 'number') { 32 | return input * 2 33 | } 34 | return input + input 35 | } 36 | 37 | // /** 38 | // * @type {{ 39 | // * (input: number) => number; 40 | // * (input: string) => string; 41 | // * }} 42 | // */ 43 | // const doubleTwo = (input) => { 44 | // if (typeof input === 'number') { 45 | // return input * 2 46 | // } 47 | // return input + input 48 | // } 49 | 50 | // ─────────────────────── 51 | 52 | // via https://github.com/microsoft/TypeScript/issues/25590#issuecomment-942782630 53 | /** 54 | * This function takes a number and a string. 55 | * @callback signatureA 56 | * @param {number} num 57 | * @param {string} str 58 | */ 59 | 60 | /** 61 | * This function takes a boolean and an object 62 | * @callback signatureB 63 | * @param {boolean} bool 64 | * @param {Object} obj 65 | */ 66 | 67 | /** 68 | * This function takes a boolean and an object 69 | * @callback signatureC 70 | * @param {Person} person 71 | * @param {boolean} bool 72 | */ 73 | 74 | /** 75 | * @param {Parameters | Parameters | Parameters} args 76 | */ 77 | function overloaded(...args) { 78 | 79 | } 80 | 81 | overloaded(1, '2') 82 | overloaded(true, {}) 83 | overloaded({ name: 'bob', age: 11 }, true) 84 | 85 | 86 | 87 | 88 | 89 | // https://github.com/microsoft/TypeScript/issues/25590#issuecomment-790713772 90 | 91 | /** 92 | @typedef {{ 93 | (s: string): 0 | 1 94 | (b: boolean): 2 | 3 95 | [k:string]: any 96 | }} Gioconda 97 | */ 98 | 99 | // /** @type {Gioconda} */ 100 | // const monaLisa = ( 101 | // /** @param {string|boolean} sb */ 102 | // (sb) => { 103 | // return typeof sb === 'string' ? 1 : 2; 104 | // }); 105 | 106 | // const obj = { 107 | // /** @type {Gioconda} */ 108 | // monaLisa: ( 109 | // /** @param {string|boolean} sb */ 110 | // (sb) => { 111 | // return typeof sb === 'string' ? 1 : 2; 112 | // }) 113 | // }; 114 | 115 | // class MonaLisa { 116 | // /** @type {Gioconda} */ 117 | // monaLisa = ( 118 | // /** @param {string|boolean} sb */ 119 | // (sb) => { 120 | // return typeof sb === 'string' ? 1 : 2; 121 | // }) 122 | // } 123 | 124 | // /** @type {2 | 3} - call resolve to (b: boolean) => 2 | 3 */ 125 | // var twothree = monaLisa(false); 126 | // /** @type {2 | 3} - call resolve to (b: boolean) => 2 | 3 */ 127 | // var twothreeObj = obj.monaLisa(false); 128 | // /** @type {2 | 3} - call resolve to (b: boolean) => 2 | 3 */ 129 | // var twothreeClass = new MonaLisa().monaLisa(false); 130 | 131 | // // js special property assignment should still be allowed 132 | // monaLisa.overdrive = true; 133 | // obj.monaLisa.overdrive = true; 134 | // MonaLisa.prototype.monaLisa.overdrive = true; 135 | 136 | /** 137 | * 138 | */ 139 | 140 | // ─────────────────────── 141 | // https://github.com/micromark/micromark/blob/2b1fafb5f3ad0d1c9329ffbc80be1cbd411f5468/packages/micromark/dev/index.js#L12-L30 142 | 143 | /** 144 | * @typedef {'ascii'|'utf8'|'utf-8'|'utf16le'|'ucs2'|'ucs-2'|'base64'|'latin1'|'binary'|'hex'} Encoding 145 | * Encodings supported by the buffer class. 146 | * This is a copy of the typing from Node, copied to prevent Node globals from 147 | * being needed. 148 | * Copied from: 149 | * 150 | * @typedef {string|Uint8Array} Value 151 | * Contents of the file. 152 | * Can either be text, or a `Buffer` like structure. 153 | */ 154 | 155 | /** 156 | * @typedef {Record>} Extension 157 | * A syntax extension changes how markdown is tokenized. 158 | * See: 159 | */ 160 | 161 | /** 162 | * @typedef ParseOptions 163 | * Parse options. 164 | * @property {Extension[]} [extensions] Array of syntax extensions 165 | */ 166 | 167 | /** 168 | * @typedef CompileOptions 169 | * Compile options 170 | * @property {'\r'|'\n'|'\r\n'} [defaultLineEnding] 171 | * Value to use for line endings not in `doc` (`string`, default: first line 172 | * ending or `'\n'`). 173 | * @property {boolean} [allowDangerousHtml=false] 174 | * Whether to allow embedded HTML (`boolean`, default: `false`). 175 | * @property {boolean} [allowDangerousProtocol=false] 176 | */ 177 | 178 | /** 179 | * @typedef {ParseOptions & CompileOptions} Options 180 | */ 181 | 182 | /** 183 | * @param value Markdown to parse (`string` or `Buffer`). 184 | * @param [encoding] Character encoding to understand `value` as when it’s a `Buffer` (`string`, default: `'utf8'`). 185 | * @param [options] Configuration 186 | */ 187 | export const micromark = 188 | /** 189 | * @type {( 190 | * ((value: Value, encoding: Encoding, options?: Options) => string) & 191 | * ((value: Value, options?: Options) => string) 192 | * )} 193 | */ 194 | ( 195 | /** 196 | * @param {Value} value 197 | * @param {Encoding} [encoding] 198 | * @param {Options} [options] 199 | */ 200 | function (value, encoding, options) { 201 | if (typeof encoding !== 'string') { 202 | options = encoding 203 | encoding = undefined 204 | } 205 | 206 | return value 207 | } 208 | ) 209 | 210 | // ─────────────────────── 211 | 212 | // /** 213 | // * Does something 214 | // * @callback foo_overload1 215 | // * @param {number} arg1 Something 216 | // */ 217 | 218 | // /** 219 | // * Does something else 220 | // * @callback foo_overload2 221 | // * @param {string} arg1 Something else 222 | // * @param {number} arg2 Something 223 | // */ 224 | 225 | // /** @type { foo_overload1 | foo_overload2 } */ 226 | // function fooBarFunc(arg1, arg2) { 227 | 228 | // } 229 | 230 | 231 | // ------------------------------------------------------------------------------ 232 | // JSDoc implements function overloading 233 | // https://github.com/microsoft/TypeScript/issues/25590 234 | // ------------------------------------------------------------------------------ 235 | // https://github.com/chunjin666/jsdoc-learning/blob/master/src/01-types/07-function-overload.js 236 | // ------------------------------------------------------------------------------ 237 | // method one: 238 | // ------------------------------------------------------------------------------ 239 | /** 240 | * @param {number} acc 241 | * @param {number} cur 242 | */ 243 | const sumReducer = (acc, cur) => acc + cur 244 | 245 | /** 246 | * @type {{ 247 | * (nums: number[]): number 248 | * (...nums: number[]): number 249 | * }} 250 | */ 251 | const sum = (...nums) => { 252 | if (Array.isArray(nums[0])) { 253 | return nums[0].reduce(sumReducer, 0) 254 | } 255 | return /** @type {number[]} */ (nums).reduce(sumReducer, 0) 256 | }; 257 | 258 | sum(1, 2, 3) 259 | sum([1, 2, 3]) -------------------------------------------------------------------------------- /src/utils/2_overload.ts: -------------------------------------------------------------------------------- 1 | // ----Function overload─────── 2 | // https://twitter.com/steveruizok/status/1495328409613918210?s=11 3 | 4 | export const greet: { 5 | (name: string): string 6 | (hellos: number): string 7 | (arg: string | number): string 8 | } = (arg) => { 9 | if (typeof arg === 'string') { 10 | return `Hello ${arg}!` 11 | } 12 | return Array.from(Array(arg)) 13 | .map(() => `Hello`) 14 | .join(' ') 15 | } 16 | 17 | // greet('c') 18 | // greet(1) -------------------------------------------------------------------------------- /src/utils/2_typecasting.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | 3 | // https://gist.github.com/hrdtbs/f7e567c0738725a16a9de7326dc11127 4 | const btn = document.createElement("button"); 5 | /** @type {Element} */ (btn).setAttribute("disabled", "true") 6 | 7 | 8 | /** 9 | * First name & last name 10 | * @typedef {{firstName: string, lastName: string}} CoolType 11 | */ 12 | 13 | const qwerty = /** @type {CoolType} */({ firstName: 'y', lastName: 'x'}) 14 | 15 | // ─────────────────────── 16 | // https://twitter.com/karlhorky/status/1409074665209925632 17 | // Inline useState typecast 18 | 19 | /** 20 | * User 21 | * @typedef {{name: string, lastName?: string}} ExampleUser 22 | */ 23 | 24 | function C() { 25 | const [u, setU] = useState(/** @type {ExampleUser | null} */ (null)) 26 | setU({ name: '' }) 27 | } 28 | 29 | // https://github.com/JacobParis/cloudfool/pull/2 30 | // broken 31 | // export default function Component(props) { 32 | // /** @type [ExampleUser, React.Dispatch] */ 33 | // const [user, setUser] = useState(null) 34 | // console.log('user', user) 35 | // setUser({ name: 'hi' }) 36 | // } -------------------------------------------------------------------------------- /src/utils/2_typeof-reference.js: -------------------------------------------------------------------------------- 1 | 2 | // https://fettblog.eu/typescript-jsdoc-superpowers/ 3 | // Using typeof referrence to defaultCallback 4 | 5 | /** 6 | * @param {number} status The status code as a number 7 | * @param {string} data The data to work with 8 | */ 9 | function defaultCallback(status, data) { 10 | if(status === 200) { 11 | document.body.innerHTML = data 12 | } 13 | } 14 | 15 | /** 16 | * @param {string} url the URL to load data from 17 | * @param {typeof defaultCallback} cb what to do afterwards 18 | */ 19 | function loadData(url, cb) { 20 | const xhr = new XMLHttpRequest(); 21 | xhr.open('GET', url) 22 | xhr.onload = () => { 23 | cb(xhr.status, xhr.responseText) 24 | } 25 | } -------------------------------------------------------------------------------- /src/utils/2_union.js: -------------------------------------------------------------------------------- 1 | /** @type {(string|Array)} */ 2 | export var foo; 3 | -------------------------------------------------------------------------------- /src/utils/asserts.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * https://github.com/voxpelli/types-in-js/discussions/8 5 | * @param {any} value 6 | * @returns {value is Iterable<*>} 7 | */ 8 | const isIterable = (value) => Boolean(value && value[Symbol.iterator]); -------------------------------------------------------------------------------- /src/utils/balena.js: -------------------------------------------------------------------------------- 1 | // https://www.balena.io/blog/open-source-guide-1-documentation-and-jsdoc/ 2 | 3 | // Public Function 4 | 5 | /** 6 | * @summary Sum two numbers 7 | * @function 8 | * @public 9 | * 10 | * @param {Number} x - first number 11 | * @param {Number} y - second number 12 | * @returns {Number} the sum of the two numbers 13 | * 14 | * @example 15 | * const result = math.sum(5, 3); 16 | * console.log(result); 17 | * > 8 18 | */ 19 | exports.sum = (x, y) => { 20 | return x + y; 21 | }; 22 | 23 | // Private Function 24 | 25 | /** 26 | * @summary Check if a variable is a string 27 | * @function 28 | * @private 29 | * 30 | * @param {*} x - variable 31 | * @returns {Boolean} whether the variable is a string 32 | * 33 | * @example 34 | * if (isString('foo')) { 35 | * console.log('The variable is a string'); 36 | * } 37 | */ 38 | const isString = (x) => { 39 | return typeof x === 'string' || x instanceof String; 40 | }; 41 | 42 | // Constant Variable 43 | 44 | /** 45 | * @summary Default size 46 | * @type Number 47 | * @constant 48 | * @private 49 | */ 50 | const DEFAULT_SIZE = 16; 51 | 52 | // Object 53 | 54 | /** 55 | * @summary Exit codes 56 | * @namespace EXIT_CODES 57 | * @private 58 | */ 59 | const EXIT_CODES = { 60 | 61 | /** 62 | * @property {Number} SUCCESS 63 | * @memberof EXIT_CODES 64 | * 65 | * @description 66 | * This exit code is used to represent a successful exit status. 67 | */ 68 | SUCCESS: 0, 69 | 70 | /** 71 | * @property {Number} ERROR 72 | * @memberof EXIT_CODES 73 | * 74 | * @description 75 | * This exit code is used to represent an erroneous exit status. 76 | */ 77 | ERROR: 1 78 | 79 | }; 80 | 81 | // Optional Parameter 82 | 83 | /** 84 | * @summary Split a string 85 | * @function 86 | * @public 87 | * 88 | * @param {String} string - input string 89 | * @param {String} [delimiter=' '] - delimiter 90 | * @returns {String[]} splitted string 91 | * 92 | * @example 93 | * const result = utils.split('foo bar baz'); 94 | * console.log(result); 95 | * > [ 'foo', 'bar', 'baz' ] 96 | * 97 | * @example 98 | * const result = utils.split('hello_world', '_'); 99 | * console.log(result); 100 | * > [ 'hello', 'world' ] 101 | */ 102 | exports.split = (string, delimiter = ' ') => { 103 | return string.split(delimiter); 104 | }; 105 | 106 | // Object Parameter 107 | 108 | /** 109 | * @summary Tail a string 110 | * @function 111 | * @private 112 | * 113 | * @param {String} string - input string 114 | * @param {Object} [options={}] - options 115 | * @param {String} [options.delimiter='\n'] - string delimiter 116 | * @param {Number} [options.lines=10] - number of lines to show 117 | * @returns {String[]} tailed string 118 | * 119 | * @example 120 | * const result = tail('foo\nbar\nbaz', { 121 | * delimiter: '\n', 122 | * lines: 2 123 | * }); 124 | * 125 | * console.log(result); 126 | * > 'bar\nbaz' 127 | */ 128 | const tail = (string, options = {}) => { 129 | const delimiter = options.delimiter || '\n'; 130 | const lines = options.lines || 10; 131 | 132 | return string 133 | .split(delimiter) 134 | .slice(lines) 135 | }; 136 | 137 | // Promise 138 | 139 | /** 140 | * @summary Get a promise that resolves a value 141 | * @function 142 | * @private 143 | * 144 | * @param {*} value - value 145 | * @fulfil {*} - value 146 | * @returns {Promise} 147 | * 148 | * @example 149 | * resolve(5).then((value) => { 150 | * console.log(value); 151 | * }); 152 | * > 5 153 | */ 154 | const resolve = (value) => { 155 | return Promise.resolve(value); 156 | }; 157 | 158 | // Class 159 | 160 | 161 | /** 162 | * @summary Create an instance of Person 163 | * @name Person 164 | * @class 165 | * @public 166 | * 167 | * @param {String} name - person name 168 | * @returns {Person} Person instance 169 | * 170 | * @example 171 | * const person = new Person('Juan Cruz Viotti'); 172 | */ 173 | export class Person { 174 | constructor(name) { 175 | this.name = name; 176 | } 177 | 178 | /** 179 | * @summary Greet 180 | * @method 181 | * @public 182 | * 183 | * @example 184 | * const person = new Person('Juan Cruz Viotti'); 185 | * person.greet(); 186 | * // Hi, my name is Juan Cruz Viotti 187 | */ 188 | greet() { 189 | console.log(`Hi, my name is ${this.name}`); 190 | } 191 | 192 | } -------------------------------------------------------------------------------- /src/utils/calculator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Calculator module - See {@tutorial calculator-tutorial} 3 | * @module calculator 4 | */ 5 | 6 | /** 7 | * Add two numbers 8 | * @param {number} n1 - First number 9 | * @param {number} n2 - Second number 10 | * @returns {number} - Sum of n1 and n2 11 | */ 12 | exports.add = (n1, n2) => n1 + n2; 13 | 14 | /** 15 | * Multiply two numbers 16 | * @param {number} n1 - First number 17 | * @param {number} n2 - Second number 18 | * @returns {number} - Product of n1 and n2 19 | */ 20 | exports.multiply = (n1, n2) => n1 * n2; 21 | 22 | /** 23 | * Subtract two numbers 24 | * @param {number} n1 - First number 25 | * @param {number} n2 - Second number 26 | * @returns {number} - Difference of n1 and n2 27 | */ 28 | exports.subtract = (n1, n2) => n1 - n2; 29 | 30 | /** 31 | * Divide two numbers 32 | * @param {number} n1 - First number 33 | * @param {number} n2 - Second number 34 | * @returns {number} - Quotient of n1 and n2 35 | */ 36 | exports.divide = (n1, n2) => n1 / n2; -------------------------------------------------------------------------------- /src/utils/camel-case.js: -------------------------------------------------------------------------------- 1 | import * as TypeFest from 'type-fest' 2 | 3 | /** 4 | * @template T 5 | * @typedef { { [K in keyof T as TypeFest.CamelCase]: T[K] }} CamelCasedProps 6 | */ 7 | 8 | /** 9 | * @typedef DbResult 10 | * @property {string} full_name 11 | * @property {string} street_address 12 | * @property {SomethingGlobal} [something] 13 | */ 14 | 15 | /** @type {CamelCasedProps} */ 16 | const person = { 17 | fullName: 'Bob Bobson', 18 | streetAddress: 'Infinite loop 1', 19 | something: 'value2' 20 | }; 21 | 22 | 23 | /** @type {CamelCasedPropsGlobal} */ 24 | const personTwo = { 25 | fullName: 'Bob Bobson', 26 | streetAddress: 'Infinite loop 1', 27 | something: 'value' 28 | }; -------------------------------------------------------------------------------- /src/utils/class-extend.js: -------------------------------------------------------------------------------- 1 | // https://fettblog.eu/typescript-jsdoc-superpowers/ 2 | 3 | /** 4 | * @template T 5 | * @extends {Set} 6 | */ 7 | class SortableSet extends Set { 8 | // ... 9 | } 10 | 11 | 12 | /** 13 | * @augments {Set} 14 | */ 15 | class StringSet extends Set { 16 | // ... 17 | } -------------------------------------------------------------------------------- /src/utils/class-private-func.js: -------------------------------------------------------------------------------- 1 | // https://github.com/microsoft/TypeScript/issues/13206#issuecomment-869194939 2 | 3 | /** The parent object. 4 | * @constructor 5 | * @param {*} arg - A parameter that has to be passed in on construction. */ 6 | function Parent(arg) { 7 | /** Public function. In the documentation, this description will carry 8 | * over to the child object. In the IDE, only typechecking will. 9 | * @param {string} name - User's name. 10 | * @returns {string} string **/ 11 | this.hello = function(name) { 12 | return "Hello " + name; 13 | } 14 | } 15 | 16 | /** The child object. 'augments' is what jsdocs uses to detect inheritance. 17 | * 'augments' creates an IDE error, which the ts-ignore flag suppresses. 18 | * @constructor 19 | * @param {*} arg - A parameter that has to be passed in on construction. 20 | * @augments Parent 21 | * @ts-ignore */ 22 | function Child(arg) { 23 | Parent.call(this, arg); 24 | 25 | // Dummy section to initialize properties from superclass 26 | 27 | // eslint-disable-next-line 28 | if (true) { 29 | // @ts-ignore 30 | var dummy = new Parent(null); 31 | this.hello = dummy.hello; 32 | } 33 | 34 | // New code goes below . . . 35 | 36 | this.hello("abc"); // This will trigger: TS2722: Cannot invoke an object which is possibly 'undefined' 37 | 38 | this.anotherFunction = function() { 39 | this.hello("def"); // This triggers no warning and has correct type/Intellisense comment 40 | } 41 | } -------------------------------------------------------------------------------- /src/utils/class-private-proto.js: -------------------------------------------------------------------------------- 1 | // https://github.com/englercj/tsd-jsdoc/issues/105#issue-524233914 2 | 3 | /** 4 | * @constructor 5 | * @name Animal 6 | * @classdesc An animal. 7 | * @description Creates a new animal. 8 | */ 9 | function Animal() { 10 | this.x = 0; 11 | this.y = 0; 12 | } 13 | 14 | /** 15 | * @function 16 | * @name Animal#move 17 | * @description Move the animal to the specified location. 18 | * @param {Number} x - X-coordinate. 19 | * @param {Number} y - Y-coordinate. 20 | */ 21 | Animal.prototype.move = function (x, y) { 22 | this.x = x; 23 | this.y = y; 24 | } 25 | 26 | // /** 27 | // * @private 28 | // * @constructor 29 | // * @name Dog 30 | // * @extends Animal 31 | // * @classdesc A dog. 32 | // * @description Creates a new dog. 33 | // */ 34 | // function Dog() {} 35 | 36 | // Dog.prototype = Object.create(Animal.prototype); 37 | // Dog.prototype.constructor = Dog; 38 | 39 | // /** 40 | // * @private 41 | // * @function 42 | // * @name Dog#bark 43 | // * @description The dog barks. 44 | // */ 45 | // Dog.prototype.bark = function () { 46 | // console.log('Woof!'); 47 | // } -------------------------------------------------------------------------------- /src/utils/constants.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck til 4.5.0 2 | // https://github.com/microsoft/TypeScript/issues/30445#issuecomment-571422490 3 | 4 | /** 5 | * @constant 6 | * @type {string} 7 | * @default 8 | */ 9 | const RED = 'FF0000'; 10 | 11 | /** @constant {number} */ 12 | var ONE = 1; 13 | 14 | // ONE = 'x' // fails 15 | 16 | const isConst = /** @type {const} */ ({ 17 | hello: "world, not string" 18 | }) 19 | 20 | var asConst1 = /** @type {const} */(1); 21 | var asConst2 = /** @type {const} */({ 22 | x: 1 23 | }); 24 | 25 | // ─────────────────────── 26 | // https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#jsdoc-const-and-type-arg-defaults 27 | 28 | // type is { prop: string } 29 | let a = { prop: "hello" }; 30 | 31 | // type is { readonly prop: "hello" } 32 | let b = /** @type {const} */ ({ prop: "hello" }); 33 | -------------------------------------------------------------------------------- /src/utils/contentful-types.ts: -------------------------------------------------------------------------------- 1 | export interface AxiosProxyConfig { 2 | host: string; 3 | port?: number; 4 | auth?: { 5 | username: string; 6 | password: string; 7 | }; 8 | } 9 | 10 | export type ClientLogLevel = 'error' | 'warning' | 'info'; 11 | 12 | export interface CreateClientParams { 13 | space: string; 14 | accessToken: string; 15 | environment?: string; 16 | insecure?: boolean; 17 | host?: string; 18 | basePath?: string; 19 | httpAgent?: any; 20 | httpsAgent?: any; 21 | proxy?: AxiosProxyConfig; 22 | headers?: any; 23 | adapter?: any; 24 | application?: string; 25 | integration?: string; 26 | resolveLinks?: boolean; 27 | removeUnresolved?: boolean; 28 | retryOnError?: boolean; 29 | logHandler?: (level: ClientLogLevel, data?: any) => void; 30 | timeout?: number; 31 | retryLimit?: number; 32 | } 33 | 34 | export interface ContentfulClientApi { 35 | getAsset(id: string, query?: any): Promise; 36 | getAssets(query?: any): Promise; 37 | getContentType(id: string): Promise; 38 | getContentTypes(query?: any): Promise; 39 | getEntries(query?: any): Promise>; 40 | getEntry(id: string, query?: any): Promise>; 41 | getSpace(): Promise; 42 | getLocales(): Promise; 43 | getTag(id: string): Promise; 44 | getTags(query?: any): Promise; 45 | parseEntries(raw: any): Promise>; 46 | sync(query: any): Promise; 47 | } 48 | 49 | export interface Asset { 50 | sys: Sys; 51 | fields: { 52 | title: string; 53 | description: string; 54 | file: { 55 | url: string; 56 | details: { 57 | size: number; 58 | image?: { 59 | width: number; 60 | height: number; 61 | }; 62 | }; 63 | fileName: string; 64 | contentType: string; 65 | }; 66 | }; 67 | metadata: Metadata; 68 | toPlainObject(): object; 69 | } 70 | 71 | export interface ContentfulCollection { 72 | total: number; 73 | skip: number; 74 | limit: number; 75 | items: Array; 76 | toPlainObject(): object; 77 | } 78 | 79 | export type AssetCollection = ContentfulCollection 80 | 81 | export interface Entry { 82 | sys: Sys; 83 | fields: T; 84 | metadata: Metadata; 85 | toPlainObject(): object; 86 | update(): Promise>; 87 | } 88 | 89 | export interface EntryCollection extends ContentfulCollection> { 90 | errors?: Array; 91 | includes?: any; 92 | stringifySafe(replacer?: any, space?: any): string; 93 | } 94 | 95 | export interface ContentType { 96 | sys: Sys; 97 | name: string; 98 | description: string; 99 | displayField: string; 100 | fields: Array; 101 | toPlainObject(): object; 102 | } 103 | 104 | export type ContentTypeCollection = ContentfulCollection; 105 | 106 | export interface Space { 107 | sys: Sys; 108 | name: string; 109 | locales: Array; 110 | toPlainObject(): object; 111 | } 112 | 113 | export interface Locale { 114 | code: string 115 | name: string 116 | default: boolean 117 | fallbackCode: string | null 118 | sys: { 119 | id: string 120 | type: 'Locale' 121 | version: number 122 | } 123 | } 124 | 125 | export type LocaleCollection = ContentfulCollection; 126 | 127 | export interface Tag { 128 | name: string 129 | sys: { 130 | id: string 131 | type: 'Tag' 132 | version: number 133 | visibility: 'public' 134 | } 135 | } 136 | 137 | export type TagCollection = ContentfulCollection; 138 | 139 | export interface SyncCollection { 140 | entries: Array>; 141 | assets: Array; 142 | deletedEntries: Array>; 143 | deletedAssets: Array; 144 | nextSyncToken: string; 145 | toPlainObject(): object; 146 | stringifySafe(replacer?: any, space?: any): string; 147 | } 148 | 149 | export interface Sys { 150 | type: string; 151 | id: string; 152 | createdAt: string; 153 | updatedAt: string; 154 | locale: string; 155 | revision?: number; 156 | space?: { 157 | sys: SpaceLink; 158 | }; 159 | contentType: { 160 | sys: ContentTypeLink; 161 | }; 162 | } 163 | 164 | export interface SpaceLink { 165 | type: 'Link'; 166 | linkType: 'Space'; 167 | id: string; 168 | } 169 | 170 | export interface ContentTypeLink { 171 | type: 'Link'; 172 | linkType: 'ContentType'; 173 | id: string; 174 | } 175 | 176 | export interface Field { 177 | disabled: boolean; 178 | id: string; 179 | linkType?: string; 180 | localized: boolean; 181 | name: string; 182 | omitted: boolean; 183 | required: boolean; 184 | type: FieldType; 185 | validations: FieldValidation[]; 186 | items?: FieldItem; 187 | } 188 | 189 | export type FieldType = 'Symbol' | 'Text' | 'Integer' | 'Number' | 'Date' | 'Boolean' | 'Location' | 'Link' | 'Array' | 'Object' | 'RichText'; 190 | 191 | export interface FieldValidation { 192 | unique?: boolean; 193 | size?: { 194 | min?: number; 195 | max?: number; 196 | }; 197 | regexp?: { 198 | pattern: string; 199 | }; 200 | linkMimetypeGroup?: string[]; 201 | in?: string[]; 202 | linkContentType?: string[]; 203 | message?: string; 204 | nodes?: { 205 | 'entry-hyperlink'?: FieldValidation[]; 206 | 'embedded-entry-block'?: FieldValidation[]; 207 | 'embedded-entry-inline'?: FieldValidation[]; 208 | }; 209 | enabledNodeTypes?: string[]; 210 | } 211 | 212 | export interface FieldItem { 213 | type: 'Link' | 'Symbol'; 214 | validations: FieldValidation[]; 215 | linkType?: 'Entry' | 'Asset'; 216 | } 217 | 218 | // @ts-ignore 219 | export function createClient(params: CreateClientParams): ContentfulClientApi; 220 | 221 | /** 222 | * Types of fields found in an Entry 223 | */ 224 | export namespace EntryFields { 225 | export type Symbol = string; 226 | export type Text = string; 227 | export type Integer = number; 228 | export type Number = number; 229 | export type Date = string; 230 | export type Boolean = boolean; 231 | export interface Location { 232 | lat: string; 233 | lon: string; 234 | } 235 | export type Link = Asset | Entry; 236 | export type Array = Symbol[] | Entry[] | Asset[]; 237 | export type Object = T; 238 | export interface RichText { 239 | data:{}; 240 | content: RichTextContent[]; 241 | nodeType: 'document'; 242 | } 243 | } 244 | 245 | interface RichTextDataTarget { 246 | sys: { 247 | id: string; 248 | type: "Link"; 249 | "linkType": 'Entry' | 'Asset'; 250 | }; 251 | } 252 | 253 | interface RichTextData { 254 | uri?: string; 255 | target?: RichTextDataTarget; 256 | } 257 | 258 | type RichTextNodeType = 'text' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading-5' 259 | | 'heading-6' | 'paragraph' | 'hyperlink' | 'entry-hyperlink' | 'asset-hyperlink' 260 | | 'unordered-list' | 'ordered-list' | 'list-item' | 'blockquote' | 'hr' | 'embedded-entry-block' 261 | | 'embedded-entry-inline'; 262 | 263 | interface RichTextContent { 264 | data: RichTextData; 265 | content?: RichTextContent[] 266 | marks: {type: ('bold' | 'underline' | 'code' | 'italic')}[]; 267 | value?: string; 268 | nodeType: RichTextNodeType; 269 | } 270 | 271 | interface TagLink { 272 | sys: { 273 | type: 'Link'; 274 | linkType: 'Tag'; 275 | id: string; 276 | } 277 | } 278 | 279 | interface Metadata { 280 | tags: TagLink[]; 281 | } -------------------------------------------------------------------------------- /src/utils/contentful.js: -------------------------------------------------------------------------------- 1 | // https://github.com/contentful/contentful.js/blob/2276d9381387be0fb68943d6231b528385244c7c/lib/contentful.js 2 | 3 | /** 4 | * Contentful Delivery API SDK. Allows you to create instances of a client 5 | * with access to the Contentful Content Delivery API. 6 | * @namespace contentful 7 | * @see ContentfulClientAPI 8 | */ 9 | 10 | /** 11 | * Create a client instance 12 | * @func 13 | * @name createClient 14 | * @memberof contentful 15 | * @param {Object} params - Client initialization parameters 16 | * @prop {string} params.space - Space ID 17 | * @prop {string} params.accessToken - Contentful CDA Access Token 18 | * @prop {string} [params.environment="master"] - Contentful Environment ID 19 | * @prop {boolean=} params.insecure - Requests will be made over http instead of the default https (default: true) 20 | * @prop {string=} params.host - API host (default: cdn.contentful.com). Also usable with preview.contentful.com. 21 | * @prop {string=} params.basePath - Path appended to the host to support gateways/proxies with custom urls. 22 | * @prop {Object=} params.httpAgent - Optional Node.js HTTP agent for proxying (see Node.js docs and https-proxy-agent) 23 | * @prop {Object=} params.httpsAgent - Optional Node.js HTTP agent for proxying (see Node.js docs and https-proxy-agent) 24 | * @prop {Object=} params.proxy - Optional Axios proxy (see axios docs ) 25 | * @prop {Object=} params.headers - Optional additional headers 26 | * @prop {function=} params.adapter - Optional axios request adapter (see axios docs ) 27 | * @prop {boolean=?} params.resolveLinks - If we should resolve links between entries (default: true) 28 | * @prop {boolean=?} params.removeUnresolved - If we should remove links to entries which could not be resolved (default: false) 29 | * @prop {boolean=?} params.retryOnError - If we should retry on errors and 429 rate limit exceptions (default: true) 30 | * @prop {function=} params.logHandler - A log handler function to process given log messages & errors. Receives the log level (error, warning & info) and the actual log data (Error object or string). (The default can be found at: https://github.com/contentful/contentful-sdk-core/blob/master/src/create-http-client.ts) 31 | * @prop {string=?} params.application - Application name and version e.g myApp/version 32 | * @prop {string=?} params.integration - Integration name and version e.g react/version 33 | * @prop {number=} params.timeout in milliseconds - connection timeout (default:30000) 34 | * @prop {number=} params.retryLimit - Optional number of retries before failure. Default is 5 35 | * @returns { import("./contentful-types").ContentfulClientApi } 36 | * @example 37 | * const contentful = require('contentful') 38 | * const client = contentful.createClient({ 39 | * accessToken: 'myAccessToken', 40 | * space: 'mySpaceId' 41 | * }) 42 | */ 43 | 44 | export function createClient (params) { 45 | return { 46 | // @ts-ignore 47 | getAsset: (id, query) => {}, 48 | // @ts-ignore 49 | getAssets: (query) => {}, 50 | // @ts-ignore 51 | getContentType: (id) => {}, 52 | // @ts-ignore 53 | getContentTypes: (query) => {}, 54 | // @ts-ignore 55 | getEntries: (query) => {}, 56 | // @ts-ignore 57 | getEntry: (id, query) => {}, 58 | // @ts-ignore 59 | getSpace: () => {}, 60 | // @ts-ignore 61 | getLocales: () => {}, 62 | // @ts-ignore 63 | getTag: (id) => {}, 64 | // @ts-ignore 65 | getTags: (query) => {}, 66 | // @ts-ignore 67 | parseEntries: (raw) => {}, 68 | // @ts-ignore 69 | sync: (query) => {} 70 | } 71 | } -------------------------------------------------------------------------------- /src/utils/example-three.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const { add, subtract, divide, multiply } = require('./calculator'); 3 | 4 | /** 5 | * @file index.js is the root file for this example app 6 | * @author Brad Traversy 7 | * @link Traversy Media 8 | */ 9 | 10 | /** 11 | * Student Name 12 | * @type {string} 13 | */ 14 | const studentName = 'John Doe'; 15 | 16 | /** 17 | * Array of grades 18 | * @type {Array} 19 | */ 20 | const grades = [98, 97.7, 76, 89]; 21 | 22 | /** 23 | * Todo object 24 | * @type {{id: number|string, text: string}} 25 | */ 26 | const todo = { 27 | id: '1', 28 | text: 'Hello' 29 | }; 30 | 31 | /** 32 | * Calculate tax 33 | * @param {number} amount - Total amount 34 | * @param {number} tax - Tax percentage 35 | * @returns {string} - Total with a dollar sign 36 | */ 37 | const calculateTax = (amount, tax) => { 38 | return `$${amount + tax * amount}`; 39 | }; 40 | 41 | /** 42 | * A student 43 | * @typedef {Object} Student 44 | * @property {number} id - Student ID 45 | * @property {string} name - Student name 46 | * @property {string|number} [age] - Student age (optional) 47 | * @property {boolean} isActive - Student is active 48 | */ 49 | 50 | /** 51 | * @type {Student} 52 | */ 53 | const student = { 54 | id: 1, 55 | name: 'John Doe', 56 | age: 20, 57 | isActive: true 58 | }; 59 | 60 | /** 61 | * Class to create a person object 62 | */ 63 | class Person { 64 | /** 65 | * 66 | * @param {Object} personInfo Information about the person 67 | */ 68 | constructor(personInfo) { 69 | /** 70 | * @property {string} name Persons name 71 | */ 72 | this.name = personInfo.name; 73 | /** 74 | * @property {string} age Persons age 75 | */ 76 | this.age = personInfo.age; 77 | } 78 | 79 | /** 80 | * @property {Function} greet A greeting with the name and age 81 | * @returns void 82 | */ 83 | greet() { 84 | console.log(`Hello, my name is ${this.name} and I am ${this.age}`); 85 | } 86 | } 87 | 88 | /** 89 | * See {@link Person} 90 | */ 91 | const person1 = new Person({ 92 | name: 'John Doe', 93 | age: 30 94 | }); 95 | 96 | console.log(add(20, 30)); -------------------------------------------------------------------------------- /src/utils/examples-two.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | function xyz(pred, actual, expected, msg, msgtwo) { 6 | 7 | } 8 | 9 | /** 10 | * @param {unknown} actual 11 | * @param {unknown} expected 12 | * @param {string} [msg] 13 | * @returns {void} 14 | */ 15 | function notEqual(actual, expected, msg) { 16 | xyz(actual !== expected, actual, expected, msg || 'should not be equal', 'notEqual') 17 | } 18 | 19 | notEqual(false, 'whatever', 'woowowow') 20 | 21 | /** 22 | * Does xyz 23 | * @returns {Promise<{ 24 | * pass: number, 25 | * fail: number 26 | * }>} 27 | */ 28 | async function run() { 29 | return Promise.resolve({ 30 | pass: 1, 31 | fail: 3 32 | }) 33 | } 34 | 35 | /** 36 | * @param {Error} e 37 | * @returns {string} 38 | */ 39 | function findAtLineFromError (e) { 40 | return 'lol' 41 | } 42 | 43 | /** 44 | * @param {Error | null} err 45 | * @param {string} [msg] 46 | * @returns {void} 47 | */ 48 | function ifError(err, msg) { 49 | xyz(!err, err, 'no error', msg || String(err), 'ifError') 50 | } 51 | 52 | 53 | /** 54 | * Description about the function 55 | * @param {string[]} a - description about a 56 | * @return {Promise} n - Promise fulfilled by array of strings 57 | */ 58 | function example(a) { 59 | return Promise.resolve(a.map((x) => `_${x}`)) 60 | } 61 | example(['one', 'two', 'three']).then((newArray) => { 62 | console.log(newArray) 63 | }) -------------------------------------------------------------------------------- /src/utils/examples/auth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef Auth 3 | * @property {string} username 4 | * @property {string} password 5 | */ 6 | /** 7 | * @typedef Token 8 | * @property {String} access_token 9 | */ 10 | /** 11 | * @param {Auth} auth 12 | * 13 | * @returns {Promise} 14 | */ 15 | async function login(auth) { 16 | return authenticateWithThirdPartyService(auth) 17 | } 18 | 19 | async function authenticateWithThirdPartyService(auth) { 20 | return { 21 | access_token: 'hi' 22 | } 23 | } -------------------------------------------------------------------------------- /src/utils/examples/f-ck.js: -------------------------------------------------------------------------------- 1 | // https://github.com/wooorm/f-ck/blob/main/index.js 2 | // https://github.com/wooorm/f-ck/blob/main/package.json 3 | /* 4 | "scripts": { 5 | "prepublishOnly": "npm run build && npm run format", 6 | "build": "rimraf \"*.d.ts\" && tsc && type-coverage", 7 | "format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", 8 | "test-api": "node --conditions development test.js", 9 | "test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api", 10 | "test": "npm run build && npm run format && npm run test-coverage" 11 | }, 12 | */ 13 | /** 14 | * `butt` > `b*tt` 15 | * 16 | * @param {string} value 17 | * @param {string} [character='*'] 18 | * @returns {string} 19 | */ 20 | export function vowel(value, character) { 21 | return value.replace(/[aeiouy]/g, character || '*') 22 | } 23 | 24 | /** 25 | * `butt` > `b**t` 26 | * 27 | * @param {string} value 28 | * @param {string} [character='*'] 29 | * @returns {string} 30 | */ 31 | export function inner(value, character) { 32 | if (value.length <= 2) { 33 | return value 34 | } 35 | 36 | return ( 37 | value.charAt(0) + 38 | (character || '*').repeat(value.length - 2) + 39 | value.charAt(value.length - 1) 40 | ) 41 | } 42 | 43 | /** 44 | * `butt` > `@#$%` 45 | * 46 | * @param {number|string} value 47 | * @param {string} [pattern='@#$%!&?'] 48 | * @returns {string} 49 | */ 50 | export function grawlix(value, pattern = '@#$%!&?') { 51 | const length = typeof value === 'number' ? value : value.length 52 | return ( 53 | pattern.repeat(Math.floor(length / pattern.length)) + 54 | pattern.slice(0, length % pattern.length) 55 | ) 56 | } -------------------------------------------------------------------------------- /src/utils/examples/http-headers.ts: -------------------------------------------------------------------------------- 1 | export interface HTTPRequest { 2 | headers?: { [k: string]: any }; 3 | params?: { [k: string]: any }; 4 | query?: { [k: string]: any }; 5 | body?: any; 6 | } -------------------------------------------------------------------------------- /src/utils/examples/import-defs/api-type-definitions-usage.js: -------------------------------------------------------------------------------- 1 | const { OPTIONS } = require('./api-type-definitions.js') 2 | 3 | /** 4 | * Creates OS based shortcuts for files, folders, urls, and applications. 5 | * 6 | * @param {OPTIONS} options Options object for each OS, and global options 7 | * @return {boolean} True = success, false = failed to create the icon or set its permissions (Linux). 8 | */ 9 | function createDesktopShortcut (options) { 10 | console.log(options) 11 | // the library code 12 | return false 13 | } 14 | 15 | createDesktopShortcut({ 16 | verbose: true, 17 | uglify: true, 18 | input: 'body { color: red; }' 19 | }) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/api-type-definitions.js: -------------------------------------------------------------------------------- 1 | // https://github.com/red-perfume/red-perfume-css/blob/main/api-type-definitions.js 2 | // https://stackoverflow.com/questions/49836644/how-to-import-a-typedef-from-one-file-to-another-in-jsdoc-using-vs-code 3 | 4 | /** 5 | * @file Type definitions for the API and reusable functions/objects 6 | * @author TheJaredWilcurt 7 | */ 8 | 9 | /** 10 | * OPTIONAL: console.error is called by default if verbose: true. 11 | * 12 | * Your own custom logging function called with helpful warning/error 13 | * messages from the internal validators. Only used if verbose: true. 14 | * 15 | * @callback {Function} CUSTOMLOGGER 16 | * @param {string} message The human readable warning/error message 17 | * @param {object} [error] Sometimes an error or options object is passed 18 | * @return {void} 19 | */ 20 | 21 | /** 22 | * @typedef {object} OPTIONS 23 | * @property {boolean} [verbose=true] Logs out helpful warnings/errors using `customLogger` or console.error. 24 | * @property {boolean} [uglify=false] If `false` atomized classes are long (`.rp__padding__--COLOR12px`). If `true` they are short (`.rp__b5p`). 25 | * @property {string} [input=''] A string of any valid CSS to be atomized 26 | */ 27 | 28 | /** 29 | * @typedef {object} CLASSMAP 30 | * @property {{[key: string]: string[]}} classMapEntry The key is the original classname, the value is an array of strings of atomized classes 31 | */ 32 | 33 | /** 34 | * @typedef {object} SELECTORCHUNK 35 | * @property {string} type The type of selector ('tag', 'attribute', 'pseudo') 36 | * @property {string} name Selector name ('class', 'hover') 37 | * @property {string} [action] Action ('element') 38 | * @property {string} [value] Actual selector value ('cow') 39 | * @property {boolean} [ignoreCase] If casing should be ignored (false) 40 | * @property {string} [namespace] Not sure what this is (null) 41 | * @property {string} [data] Not sure what this is (null) 42 | * @property {string} [original] The original value for this selector ('.cow') 43 | */ 44 | 45 | /** 46 | * @typedef {SELECTORCHUNK[]} SELECTOR 47 | */ 48 | 49 | /** 50 | * @typedef {SELECTOR[]} SELECTORS 51 | */ 52 | 53 | /** 54 | * @typedef {object} DECLARATION 55 | * @property {string} type The type of AST ('declaration') 56 | * @property {string} property The CSS property name ('background', 'width') 57 | * @property {string} value The CSS value ('#F00', '100px') 58 | */ 59 | 60 | /** 61 | * @typedef {DECLARATION[]} DECLARATIONS 62 | */ 63 | 64 | /** 65 | * @typedef {object} RULE 66 | * @property {string} type The type of the AST ('rule') 67 | * @property {SELECTORS} selectors Array of arrays containing AST objects for each part of the CSS Selector 68 | * @property {DECLARATIONS} declarations Array of declaration objects for each property/value pair 69 | */ 70 | 71 | /** 72 | * @typedef {object} STYLESHEET 73 | * @property {string} [source] Not sure what this is (undefined) 74 | * @property {RULE[]} rules Array of all rules in the the stylesheet 75 | * @property {Array} parsingErrors Not sure what this is (empty array) 76 | */ 77 | 78 | /** 79 | * @typedef {object} STYLESHEETAST 80 | * @property {string} type The type of the AST ('stylesheet') 81 | * @property {STYLESHEET} stylesheet Object containing the Rules AST 82 | */ 83 | 84 | /** 85 | * @typedef {object} UGLIFYRESULT 86 | * @property {string} name An uglified class name ('.rp__b5z2') 87 | * @property {number} index The index number used (520958) 88 | */ 89 | 90 | /** 91 | * @typedef {object} OUTPUT 92 | * @property {CLASSMAP} classMap Example: { '.cow': ['.rp__0', '.rp__1'], '.moo': ['.rp__2', '.rp__1'] } 93 | * @property {string} atomizedCss A string of atomized CSS styles 94 | * @property {string[]} styleErrors Array of strings of errors that occurred, or empty array if no errors occurred 95 | */ 96 | 97 | /** 98 | * @type {OPTIONS} 99 | */ 100 | let OPTIONS; 101 | 102 | /** 103 | * @type {CLASSMAP} 104 | */ 105 | let CLASSMAP; 106 | 107 | /** 108 | * @type {SELECTORCHUNK} 109 | */ 110 | let SELECTORCHUNK; 111 | 112 | /** 113 | * @type {SELECTOR} 114 | */ 115 | let SELECTOR; 116 | 117 | /** 118 | * @type {SELECTORS} 119 | */ 120 | let SELECTORS; 121 | 122 | /** 123 | * @type {DECLARATION} 124 | */ 125 | let DECLARATION; 126 | 127 | /** 128 | * @type {DECLARATIONS} 129 | */ 130 | let DECLARATIONS; 131 | 132 | /** 133 | * @type {RULE} 134 | */ 135 | let RULE; 136 | 137 | /** 138 | * @type {STYLESHEET} 139 | */ 140 | let STYLESHEET; 141 | 142 | /** 143 | * @type {STYLESHEETAST} 144 | */ 145 | let STYLESHEETAST; 146 | 147 | /** 148 | * @type {UGLIFYRESULT} 149 | */ 150 | let UGLIFYRESULT; 151 | 152 | /** 153 | * @type {OUTPUT} 154 | */ 155 | let OUTPUT; 156 | 157 | module.exports = { 158 | OPTIONS, 159 | CLASSMAP, 160 | SELECTORCHUNK, 161 | SELECTOR, 162 | SELECTORS, 163 | DECLARATION, 164 | DECLARATIONS, 165 | RULE, 166 | STYLESHEET, 167 | STYLESHEETAST, 168 | UGLIFYRESULT, 169 | OUTPUT 170 | }; -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-five.js: -------------------------------------------------------------------------------- 1 | import Types from "./import-example-with-export.js" 2 | 3 | /** @type {typeof Types.MyType} */ 4 | const myVar = { 5 | name : 'Roy', 6 | description : 'abc123', 7 | // age: 25, 8 | } 9 | console.log(myVar) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-four.js: -------------------------------------------------------------------------------- 1 | 2 | /** @type {import('./import-example.js').MyType} */ 3 | const myVarY = { 4 | name : 'Roy', 5 | description : 'abc123', 6 | // age: 25, 7 | } 8 | console.log(myVarY) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-seven.js: -------------------------------------------------------------------------------- 1 | 2 | /** @type {MyTypeFromNoExport} */ 3 | const myVar = { 4 | name : 'Roy', 5 | description : 'abc123', 6 | // age: 25, 7 | } 8 | console.log(myVar) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-six.js: -------------------------------------------------------------------------------- 1 | const { MyTypeHere } = require('./import-example-with-module-exports.js') 2 | 3 | /** @type {MyTypeHere} */ 4 | const myVar = { 5 | name : 'Roy', 6 | description : 'abc123', 7 | // age: 25, 8 | } 9 | console.log(myVar) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-three.js: -------------------------------------------------------------------------------- 1 | const Types = require('./import-example.js') 2 | 3 | /** @type {Types.MyType} */ 4 | const myVar = { 5 | name : 'Roy', 6 | description : 'abc123', 7 | // age: 25, 8 | } 9 | console.log(myVar) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage-two.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('./import-example.js').MyType} XYZ 3 | */ 4 | 5 | /** @type {XYZ} */ 6 | const myVarX = { 7 | name : 'Roy', 8 | description : 'abc123', 9 | // age: 25, 10 | } 11 | console.log(myVarX) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-usage.js: -------------------------------------------------------------------------------- 1 | import * as Types from "./import-example" 2 | 3 | /** @type {Types.MyType} */ 4 | const myVar = { 5 | name : 'Roy', 6 | description : 'abc123', 7 | // age: 25, 8 | } 9 | console.log(myVar) -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-with-export.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/49836644/how-to-import-a-typedef-from-one-file-to-another-in-jsdoc-using-vs-code 2 | 3 | /** 4 | * @typedef MyType 5 | * @prop {string} name 6 | * @prop {string} description 7 | */ 8 | 9 | /** @type {MyType} */ 10 | let MyType 11 | 12 | export default { 13 | MyType 14 | } -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-with-module-exports.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/49836644/how-to-import-a-typedef-from-one-file-to-another-in-jsdoc-using-vs-code 2 | 3 | /** 4 | * @typedef MyTypeHere 5 | * @prop {string} name 6 | * @prop {string} description 7 | */ 8 | 9 | /** 10 | * @type {MyTypeHere} 11 | */ 12 | let MyTypeHere; 13 | 14 | module.exports = { 15 | MyTypeHere, 16 | } -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example-with-no-export.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/49836644/how-to-import-a-typedef-from-one-file-to-another-in-jsdoc-using-vs-code 2 | 3 | /** 4 | * @typedef MyTypeFromNoExport 5 | * @prop {string} name 6 | * @prop {string} description 7 | */ 8 | -------------------------------------------------------------------------------- /src/utils/examples/import-defs/import-example.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/49836644/how-to-import-a-typedef-from-one-file-to-another-in-jsdoc-using-vs-code 2 | 3 | /** 4 | * @typedef MyType 5 | * @prop {string} name 6 | * @prop {string} description 7 | */ 8 | 9 | export const Types = {} -------------------------------------------------------------------------------- /src/utils/examples/inferred-param.ts: -------------------------------------------------------------------------------- 1 | // https://www.typescriptlang.org/play?#code/C4TwDgpgBA0hIHkBGArAPAFQHxQLxQG8AoKKAbRigEsA7KAa3gHsAzKDAXQC4oAKGgIYBbCDxgBKPDgBuTKgBMiAXwDcRIiwCuNAMbAqTOkIGM4iVJigQAHsAg15AZ1jxk6bFl5NUPDON+EJFAAThDAmsF03ihQAs4CNCDK6jqGjsBQ0XhQxqauqLzEpAI8-MIQkrg4RaRQAPR1UAB6APxBpKk0jkwANhAAdD1MAOZlIuJBSgA0QUilguNSgbX1ja3tUJ3dfYMjYxWTM0riQA 2 | // https://twitter.com/PettengillAaron/status/1608208857867632641 3 | type KeyObj = { 4 | [K in keyof T]: (name: K) => void 5 | }; 6 | 7 | function makeKeyObj>(obj: T): T { 8 | return obj as any 9 | } 10 | 11 | const obj = makeKeyObj({ 12 | a: (name) => { 13 | // ^? 14 | console.log(name) 15 | }, 16 | b: (name) => { 17 | // ^? 18 | console.log(name) 19 | }, 20 | }) -------------------------------------------------------------------------------- /src/utils/examples/inline.js: -------------------------------------------------------------------------------- 1 | // https://whistlr.info/2021/check-js-with-ts/ 2 | 3 | /** @type {number[]} */ 4 | const x2 = []; // otherwise TS thinks this is 'any[]' 5 | 6 | /** 7 | * @param {Element} bar 8 | * @param {?Element} barOrNull 9 | * @return {Promise} 10 | */ 11 | async function fooMethod(bar, barOrNull) { 12 | // do something with bar/barOrNull 13 | } 14 | 15 | /** @type {(arg: number) => string} */ 16 | const fn = (arg) => { 17 | /* ... */ 18 | return 'done'; 19 | }; 20 | 21 | // this is a _cast_, not a declaration: you need to wrap in parens () 22 | const nowIsNumberType = /** @type {number} */ (window['someExternalAny']); -------------------------------------------------------------------------------- /src/utils/examples/json-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A type representing all allowed JSON primitive values. 3 | * 4 | * @public 5 | */ 6 | export type JsonPrimitive = number | string | boolean | null; 7 | 8 | /** 9 | * A type representing all allowed JSON object values. 10 | * 11 | * @public 12 | */ 13 | export type JsonObject = { [key in string]?: JsonValue }; 14 | 15 | /** 16 | * A type representing all allowed JSON array values. 17 | * 18 | * @public 19 | */ 20 | export interface JsonArray extends Array {} 21 | 22 | /** 23 | * A type representing all allowed JSON values. 24 | * 25 | * @public 26 | */ 27 | export type JsonValue = JsonObject | JsonArray | JsonPrimitive; -------------------------------------------------------------------------------- /src/utils/examples/oauth/oauth.js: -------------------------------------------------------------------------------- 1 | // https://www.codejam.info/2021/10/jsdoc-typescript-inside-javascript.html 2 | const crypto = require('crypto') 3 | 4 | /** 5 | * @typedef {Object} SyncOAuthChallengeImpl 6 | * @property {crypto.KeyPairKeyObjectResult} keyPair 7 | * @typedef {SyncOAuthChallengeImpl} SyncOAuthChallenge 8 | */ 9 | 10 | /** 11 | * @param {SyncOAuthChallenge} challenge 12 | * @param {Object} [options] 13 | * @param {string} [options.clientId] - OAuth client ID. 14 | * @param {string} [options.scope] - OAuth scope. 15 | * @param {string} [options.tokenEndpoint] - OAuth token endpoint. 16 | * @param {string} [options.tokenServerUrl] - TokenServer URL. 17 | * @returns {Promise} 18 | */ 19 | async function complete (challenge, result, options) { 20 | // Actual code. 21 | return { 22 | oauthToken: { 23 | access_token: 'string', 24 | scope: 'string', 25 | expires_in: 1, 26 | }, 27 | syncKeyBundle: { 28 | encryptionKey: 'string', 29 | hmacKey: 'string', 30 | kid: 'string', 31 | }, 32 | token: { 33 | id: 'string', 34 | key: 'string', 35 | }, 36 | tokenIssuedAt: 1, 37 | } 38 | } 39 | 40 | module.exports = { complete } -------------------------------------------------------------------------------- /src/utils/examples/oauth/types.js: -------------------------------------------------------------------------------- 1 | // https://www.codejam.info/2021/10/jsdoc-typescript-inside-javascript.html 2 | 3 | /** 4 | * @typedef {Object} SyncOptions 5 | * @property {string} [authServerUrl] 6 | * @property {string} [authorizationUrl] 7 | * @property {string} [tokenEndpoint] 8 | * @property {string} [tokenServerUrl] 9 | * @property {Object} [oauthOptions] 10 | * 11 | * @typedef {Object} OAuthToken 12 | * @property {string} access_token 13 | * @property {string} scope 14 | * @property {number} expires_in 15 | * 16 | * @typedef {Object} SyncToken 17 | * @property {string} id 18 | * @property {string} key 19 | * 20 | * @typedef {Object} SyncKeyBundle 21 | * @property {string} encryptionKey 22 | * @property {string} hmacKey 23 | * @property {string} kid 24 | * 25 | * @typedef {Object} SyncCredentials 26 | * @property {OAuthToken} oauthToken - The OAuth token required to authenticate to the TokenServer. 27 | * @property {SyncKeyBundle} syncKeyBundle - The Sync key bundle required to decrypt the collection keys. 28 | * @property {SyncToken} token - The token object required to call the Firefox Sync API. 29 | * @property {number} tokenIssuedAt - Timestamp in milliseconds of when the token was issued to preemptively refresh it. 30 | */ 31 | 32 | // Does nothing but required for TypeScript to import this file. 33 | module.exports = {} -------------------------------------------------------------------------------- /src/utils/examples/rbac/index.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/stalniy/casl-examples/blob/19c2dbd1c3dc9fb855ed24108b4481a4eafca5ba/packages/react-blog/src/services/ability.ts 2 | import { Ability, AbilityClass } from '@casl/ability' 3 | 4 | export interface User { 5 | email: string 6 | } 7 | 8 | interface Article { 9 | id: string 10 | title: string 11 | body: string 12 | published: boolean 13 | createdAt: string 14 | author: string 15 | createdBy: User 16 | } 17 | 18 | type Actions = 'manage' | 'create' | 'read' | 'update' | 'delete' | 'publish'; 19 | type Subjects = 'article' | Article | 'all' | 'release'; 20 | 21 | export type AppAbility = Ability<[Actions, Subjects]>; 22 | export const AppAbility = Ability as AbilityClass; 23 | 24 | function createAbility() { 25 | const ability = new AppAbility() 26 | ability.can = ability.can.bind(ability) 27 | ability.cannot = ability.cannot.bind(ability) 28 | 29 | return ability; 30 | } 31 | 32 | const xyz = createAbility() 33 | xyz 34 | xyz.can('create', 'article') 35 | 36 | const art: Article = { 37 | id: 'string', 38 | title: 'string', 39 | body: 'string', 40 | published: false, 41 | createdAt: 'string', 42 | author: 'string', 43 | createdBy: { 44 | email: 'foo' 45 | }, 46 | } -------------------------------------------------------------------------------- /src/utils/examples/react-class.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/43768915/how-to-use-typescript-jsdoc-annotations-for-react-proptypes 2 | import React, { Component } from "react"; 3 | 4 | /** 5 | * @typedef {object} Props 6 | * @prop {string} className 7 | * @prop {number} numberProp 8 | * 9 | * @extends {Component} 10 | */ 11 | export default class SomeComponent extends Component { 12 | render() { 13 | return ( 14 |
15 | {this.props.numberProp} 16 |
17 | ); 18 | } 19 | } -------------------------------------------------------------------------------- /src/utils/examples/react-render-props.js: -------------------------------------------------------------------------------- 1 | // https://medium.com/geekculture/using-jsdoc-to-enable-intellisense-for-render-props-in-vscode-e655ae4e64c1 2 | // https://forums.expo.dev/t/registerrootcomponent-typescript-whats-the-correct-parameter-type/52799 3 | 4 | import React, { useState } from "react"; 5 | import PropTypes from "prop-types"; 6 | 7 | /** 8 | * @callback ChildrenFn 9 | * @param {{ open: boolean }} props - whether the toggle is open or not 10 | * @returns {React.ReactNode} 11 | */ 12 | 13 | /** 14 | * @param {Object} props 15 | * @param {ChildrenFn} props.children 16 | * @returns {React.ReactElement} 17 | */ 18 | function Toggle(props) { 19 | const [open, setOpen] = useState(false); 20 | return ( 21 |
22 | 25 | {props.children({ open })} 26 |
27 | ) 28 | } 29 | 30 | Toggle.propTypes = { 31 | children: PropTypes.func.isRequired 32 | } 33 | 34 | 35 | function usage() { 36 | return ( 37 | 38 | {({ open }) => { 39 | return open ?
xyz
: null 40 | }} 41 |
42 | ) 43 | } 44 | 45 | export default Toggle; -------------------------------------------------------------------------------- /src/utils/examples/reverse-record.js: -------------------------------------------------------------------------------- 1 | // https://www.jacobparis.com/blog/jsdoc-cheatsheet#type-parameters 2 | /** 3 | * @template {PropertyKey} T 4 | * @template {PropertyKey} U 5 | * 6 | * @param {Record} input 7 | * @returns {Record} 8 | */ 9 | function reverseRecord(input) { 10 | const entries = Object.entries( 11 | input, 12 | ).map(([key, value]) => [value, key]) 13 | return Object.fromEntries(entries) 14 | } 15 | 16 | reverseRecord({ foo: 'bar'}) -------------------------------------------------------------------------------- /src/utils/examples/snakecase.js: -------------------------------------------------------------------------------- 1 | // https://twitter.com/anuraghazru/status/1444712390759575556 2 | /** 3 | * @typedef {object} CardColors 4 | * @property {string} titleColor 5 | * @property {string} textColor 6 | * @property {string} iconColor 7 | */ 8 | 9 | /** 10 | * CamelToSnakeCase 11 | * @template S {string} 12 | * @typedef {S extends `${infer T}${infer U}` 13 | * ? `${T extends Capitalize ? "_" : ""}${Lowercase}${CamelToSnakeCase}` 14 | * : S 15 | * } CamelToSnakeCase 16 | */ 17 | 18 | /** 19 | * Snakifies object properties 20 | * @template T 21 | * @typedef {{[K in keyof T as CamelToSnakeCase]: T[K]}} Snakify 22 | */ 23 | 24 | /** 25 | * returns theme based colors with proper overrides and defaults 26 | * @param {Snakify & { fallbackTheme: string; theme: string }} options 27 | * @returns {CardColors} 28 | */ 29 | function getCardColors(options) { 30 | console.log(options); 31 | 32 | return { 33 | titleColor: "", 34 | iconColor: "", 35 | textColor: "", 36 | }; 37 | } 38 | 39 | getCardColors({ 40 | title_color: 'cool', 41 | text_color: 'nice', 42 | icon_color: 'red', 43 | fallbackTheme: 'blue', 44 | theme: 'custom' 45 | }); 46 | -------------------------------------------------------------------------------- /src/utils/examples/split.js: -------------------------------------------------------------------------------- 1 | // https://twitter.com/anuraghazru/status/1444712396673613824 2 | 3 | /** 4 | * @template T {string} 5 | * @template K {string} 6 | * @typedef {T extends `${infer P1}${K & string}${infer P2}` 7 | * ? [P1, ...Split] 8 | * : [T] 9 | * } Split 10 | */ 11 | 12 | 13 | /** 14 | * Hover over `prop` 15 | * @typedef {Split<'Hello World', ' '>} prop 16 | */ -------------------------------------------------------------------------------- /src/utils/examples/ts-json.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/samchon/typescript-json/tree/master#json-schema-generation 2 | // https://github.com/samchon/typescript-json/tree/master#comment-tags 3 | export interface TagExample { 4 | /* ----------------------------------------------------------- 5 | ARRAYS 6 | ----------------------------------------------------------- */ 7 | /** 8 | * You can limit array length like below. 9 | * 10 | * @minItems 3 11 | * @maxItems 10 12 | * 13 | * Also, you can use `@items` tag instead. 14 | * 15 | * @items (5, 10] --> 5 < length <= 10 16 | * @items [7 --> 7 <= length 17 | * @items 12) --> length < 12 18 | * 19 | * Furthermore, you can use additional tags for each item. 20 | * 21 | * @type uint 22 | * @format uuid 23 | */ 24 | array: Array; 25 | 26 | /** 27 | * If two-dimensional array comes, length limit would work for 28 | * both 1st and 2nd level arraies. Also using additional tags 29 | * for each item (string) would still work. 30 | * 31 | * @items (5, 10) 32 | * @format url 33 | */ 34 | matrix: string[][]; 35 | 36 | /* ----------------------------------------------------------- 37 | NUMBERS 38 | ----------------------------------------------------------- */ 39 | /** 40 | * Type of number. 41 | * 42 | * It must be one of integer or unsigned integer. 43 | * 44 | * @type int 45 | * @type uint 46 | */ 47 | type: number; 48 | 49 | /** 50 | * You can limit range of numeric value like below. 51 | * 52 | * @minimum 5 53 | * @maximum 10 54 | * 55 | * Also, you can use `@range` tag instead. 56 | * 57 | * @range (5, 10] --> 5 < x <= 10 58 | * @range [7 --> 7 <= x 59 | * @range 12) --> x < 12 60 | */ 61 | range: number; 62 | 63 | /** 64 | * Step tag requires minimum or exclusiveMinimum tag. 65 | * 66 | * 3, 13, 23, 33, ... 67 | * 68 | * @step 10 69 | * @exclusiveMinimum 3 70 | * @range [3 71 | */ 72 | step: number; 73 | 74 | /** 75 | * Value must be multiple of the given number. 76 | * 77 | * -5, 0, 5, 10, 15, ... 78 | * 79 | * @multipleOf 5 80 | */ 81 | multipleOf: number; 82 | 83 | /* ----------------------------------------------------------- 84 | STRINGS 85 | ----------------------------------------------------------- */ 86 | /** 87 | * You can limit string length like below. 88 | * 89 | * @minLength 3 90 | * @maxLength 10 91 | * 92 | * Also, you can use `@length` tag instead. 93 | * 94 | * @length 10 --> length = 10 95 | * @length [3, 7] --> 3 <= length && length <= 7 96 | * @length (5, 10) --> 5 < length && length < 10 97 | * @length [4 --> 4 < length 98 | * @length 7) --> length < 7 99 | */ 100 | length: string; 101 | 102 | /** 103 | * Mobile number composed by only numbers. 104 | * 105 | * Note that, `typescript-json` does not support flag of regex, 106 | * because JSON schema definition does not support it either. 107 | * Therefore, write regex pattern without `/` characters and flag. 108 | * 109 | * @pattern ^0[0-9]{7,16} 110 | * -> RegExp(/[0-9]{7,16}/).test("01012345678") 111 | */ 112 | mobile: string; 113 | 114 | /** 115 | * E-mail address. 116 | * 117 | * @format email 118 | */ 119 | email: string; 120 | 121 | /** 122 | * UUID value. 123 | * 124 | * @format uuid 125 | */ 126 | uuid: string; 127 | 128 | /** 129 | * URL address. 130 | * 131 | * @format url 132 | */ 133 | url: string; 134 | 135 | /** 136 | * IPv4 address. 137 | * 138 | * @format ipv4 139 | */ 140 | ipv4: string; 141 | 142 | /** 143 | * IPv6 address. 144 | * 145 | * @format ipv6 146 | */ 147 | ipv6: string; 148 | } -------------------------------------------------------------------------------- /src/utils/examples/webapp.js: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/Meshida/22096d72ccfbc03998c7f5f5caf02f24 2 | 3 | /** 4 | * @typedef {Object} PostData 5 | * @prop {Object} postData 6 | * An object of data for the received POST requests. 7 | * @prop {number} postData.length 8 | * The same as contentLength of ReqParams 9 | * @prop {string} postData.type 10 | * The MIME type of the POST body 11 | * @prop {string} postData.contents 12 | * The content text of the POST body 13 | * @prop {string} postData.name 14 | * Always the value "postData" 15 | */ 16 | 17 | /** 18 | * @typedef {Object} ReqParams 19 | * @prop {string} queryString 20 | * The value of the query string portion of the URL, or null if no query string is specified 21 | * @prop {Object.} parameter 22 | * An object of key/value pairs that correspond to the request parameters. Only the first value is returned for parameters that have multiple values. 23 | * @prop {Object.>} parameters 24 | * An object of key/value pairs that correspond to the request parameters. All the values of each key are in an array. 25 | * @prop {number} contentLength 26 | * The length of the request body for POST requests, or -1 for GET requests. 27 | */ 28 | 29 | /** 30 | * @param {ReqParams} e An data of the GET request 31 | */ 32 | function doGet(e) { 33 | } 34 | 35 | /** 36 | * @param {ReqParams & PostData} e An data of the POST request 37 | */ 38 | function doPost(e) { 39 | } -------------------------------------------------------------------------------- /src/utils/examples/xyz/types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef FeaturedObject 3 | * @property {number} id 4 | * @property {string} title 5 | * @property {string} description 6 | * @property {string} image 7 | * @property {object} [button] 8 | * @property {string} button.name 9 | * @property {string} button.href 10 | */ 11 | 12 | // Does nothing but required for TypeScript to import this file. 13 | module.exports = {} -------------------------------------------------------------------------------- /src/utils/examples/xyz/xyz.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {object} props 3 | * @param {import('./types').FeaturedObject[]} props.items 4 | * @param {boolean} [props.breadcrumb] 5 | * @returns 6 | */ 7 | export default function FeaturedSlideshow(props) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/generics.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | // https://fettblog.eu/typescript-jsdoc-superpowers/ 3 | 4 | /** 5 | * @template T 6 | * @param {T} obj 7 | * @param {(keyof T)[]} params 8 | */ 9 | function pluck(obj, ...params) { 10 | return params.map(el => obj[el]) 11 | } 12 | 13 | /** @type { (obj: T, params: K[]) => Array} */ 14 | function values(obj, ...params) { 15 | return params.map(el => obj[el]) 16 | } 17 | 18 | const article = {} 19 | 20 | const numbers = values(article, 'price', 'vat') 21 | const strings = values(article, 'title') 22 | const mixed = values(article, 'title', 'vat') 23 | 24 | // ─────────────────────── 25 | // https://github.com/homer0/packages/blob/main/packages/public/prettier-plugin-jsdoc/src/fns/utils.js#L8 26 | 27 | /** 28 | * Ensures a given object is an array. 29 | * 30 | * @param {T | T[]} obj The object to validate. 31 | * @returns {T[]} 32 | * @template T 33 | */ 34 | const ensureArray = (obj) => { 35 | if (Array.isArray(obj)) return obj 36 | return [obj] 37 | } 38 | 39 | const arr1 = ensureArray('foo') 40 | const arr2 = ensureArray(true) 41 | 42 | 43 | // ─────────────────────── 44 | // https://zenn.dev/asama/articles/0c66573e488b22 45 | 46 | /** 47 | * @template T 48 | * @param {T} x - 戻り値に流用するジェネリクスパラメータ 49 | * @return {T} 50 | */ 51 | function id(x) { 52 | return x; 53 | } 54 | 55 | const a = id("string"); 56 | const b = id(123); 57 | const c = id({}); 58 | 59 | 60 | 61 | // ─────────────────────── 62 | // https://github.com/giltayar/jsdoc-typing/blob/master/src/map-values.js 63 | 64 | /** 65 | * @template {string|number|symbol} K 66 | * @template T 67 | * @template W 68 | * @param {Record} object 69 | * @param {(t: T) => W} mapFunction 70 | * 71 | * @returns {Record} 72 | */ 73 | function mapValues(object, mapFunction) { 74 | return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, mapFunction(value)])) 75 | } 76 | 77 | 78 | // ─────────────────────── 79 | // https://twitter.com/techytacos/status/1419767168305033232 80 | 81 | 82 | /** 83 | * @typedef {{ 84 | * data : { 85 | * foo: string 86 | * } 87 | * }} Foo 88 | */ 89 | 90 | /** 91 | * @param {CustomEvent} e 92 | */ 93 | function coolio(e) { 94 | console.log(e.detail.data.foo) 95 | } 96 | 97 | // ─────────────────────── 98 | // https://stackoverflow.com/questions/59243543/jsdoc-type-variables/59253145#59253145 99 | 100 | /** 101 | * @template A 102 | * @param {A} x 103 | * @return {A} 104 | */ 105 | const idTwo = (x) => x; 106 | 107 | /** @type {string} */ 108 | let strtwo = ''; 109 | 110 | /** @type {number} */ 111 | let numtwo = 1; 112 | 113 | strtwo = idTwo(true); // Type warning. 114 | 115 | strtwo = idTwo('string'); // Type safe. 116 | 117 | strtwo = idTwo(1234); // Type warning. 118 | 119 | numtwo = idTwo(true); // Type warning. 120 | 121 | numtwo = idTwo('string'); // Type warning. 122 | 123 | numtwo = idTwo(1234); // Type safe. 124 | 125 | // https://twitter.com/DerekNguyen10/status/1404307885635477507/photo/1 126 | 127 | 128 | // ─────────────────────── 129 | // https://github.com/chunjin666/jsdoc-learning/blob/master/src/01-types/06-%40template.js 130 | 131 | // You can use the @template tag to declare a type parameter, which can make the function, class, and type generic 132 | 133 | /** 134 | * @template T 135 | * @param { T } x-a generic parameter that flows to the return type 136 | * @return {T} 137 | */ 138 | function id(x) { 139 | return x; 140 | } 141 | 142 | const ta = id('string'); 143 | const tb = id(123); 144 | const tc = id({}); 145 | 146 | // You can use multiple tags to declare multiple type parameters 147 | 148 | /** 149 | * @template T,U,V 150 | * @template W,X 151 | */ 152 | 153 | // You can specify a type restriction before the type parameter name 154 | 155 | /** 156 | * @template {string} K - must be a string or character literal 157 | * @template {{ execute(s: string): string }} Executable - there must be an execute function, the parameters and return values ​​are strings 158 | * @param { K } key 159 | * @param {Executable} executable 160 | */ 161 | function execute(key, executable) { 162 | executable.execute(key); 163 | } 164 | 165 | // Another example of specifying type restrictions. 166 | /** 167 | * @typedef {{a: string, b: number}} BaseOption 168 | */ 169 | /** 170 | * @template {{c: boolean}} T 171 | * @typedef {BaseOption & T} MergeOption 172 | */ 173 | 174 | /** 175 | * @type {MergeOption<{c: boolean, d: number}>} 176 | */ 177 | const option = { }; 178 | option.c 179 | option.d 180 | 181 | // You can assign a default value to the type parameter in this way, which is not supported by the editor. . . 182 | 183 | /** @template [T=object] */ 184 | class CustomCache { 185 | /** @param {T} initial */ 186 | constructor(T) {} 187 | } 188 | let c = new CustomCache(); -------------------------------------------------------------------------------- /src/utils/ignore-example.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | 3 | class Baz {} 4 | // @ts-ignore 5 | const foo = {} 6 | // without block ignore 7 | // @ts-ignore 8 | foo.bar = new Baz({ someUntypedParameter: true }) 9 | // @ts-ignore 10 | foo.bar2 = new Baz({ someUntypedParameter: true }) 11 | // @ts-ignore 12 | foo.bar3 = new Baz({ someUntypedParameter: true }) 13 | // @ts-ignore 14 | foo.bar4 = new Baz({ someUntypedParameter: true }) 15 | 16 | // @ts-ignore 17 | foo.bar = new Baz({ someUntypedParameter: true }) 18 | // @ts-ignore 19 | foo.bar2 = new Baz({ someUntypedParameter: true }) 20 | // @ts-ignore 21 | foo.bar3 = new Baz({ someUntypedParameter: true }) 22 | foo.bar4 = new Baz({ someUntypedParameter: true }) 23 | 24 | 25 | /** 26 | * Example of @ts-ignore-start + @ts-ignore-end 27 | * @param {MyFunc} xyz 28 | * @returns {{total: number, adjustedTotal: number, avgWeight: number}} totals 29 | */ 30 | function myFunc(xyz) { 31 | // implementation details omitted 32 | return { 33 | total: 2, 34 | adjustedTotal: 3, 35 | avgWeight: 4, 36 | // @ts-ignore-start 37 | lol: true, 38 | haha: true 39 | // @ts-ignore-end 40 | // what: 'no' <- broken 41 | } 42 | } -------------------------------------------------------------------------------- /src/utils/imports/my-js-file.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /** 4 | * myExportedFunc from common js 5 | * @param {number} [x] optional 6 | * @param {number=} y number or undefined 7 | * @param {number} [z=1] optional with default (default not show in type hint) 8 | */ 9 | function myExportedFunc(x, y, z = 1) { 10 | 11 | } 12 | 13 | module.exports = { 14 | myExportedFunc 15 | } -------------------------------------------------------------------------------- /src/utils/imports/my.d.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | export function myFun(a: string, b: string, c: string): number; 5 | -------------------------------------------------------------------------------- /src/utils/imports/ts-types.ts: -------------------------------------------------------------------------------- 1 | export type TinyProps = { 2 | message: string; 3 | count: number; 4 | disabled: boolean; 5 | }; -------------------------------------------------------------------------------- /src/utils/invert.ts: -------------------------------------------------------------------------------- 1 | // https://twitter.com/buildsghost/status/1498540615658721283/photo/1 2 | /* 3 | export type InvertObject = { 4 | [K in keyof T as T[K]]: K 5 | } 6 | 7 | const fooToBar = { 8 | foo1 : 'bar1', 9 | foo2: 'bar2', 10 | } as const 11 | 12 | const barToFoo: InvertObject = { 13 | boo1: 'foo1', // Object literal may only specify known properties.. 14 | bar2: 'foo2', // Type '"boo2"‘ is not assignable to type '"foo2"'. 15 | } 16 | */ -------------------------------------------------------------------------------- /src/utils/jsdoc-module.js: -------------------------------------------------------------------------------- 1 | // Links are incorrect 2 | 3 | /** @module Example */ 4 | 5 | /** 6 | * @class module:Example.Car 7 | * @property {Function} start {@link module:Example.Car#start} 8 | * @property {Function} stop {@link module:Example.Car#stop} 9 | * 10 | */ 11 | class Car { 12 | /** 13 | * @method module:Example.Car#start 14 | * 15 | */ 16 | start () { /* function body */ } 17 | 18 | /** 19 | * @description You could use various other tags here, 20 | * and JSDoc will still auto-assign the following namepath 21 | * "module:Example.Car#stop" to this method 22 | * 23 | */ 24 | stop () { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/utils/simple-jsdoc-generics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @function 3 | * @template A 4 | * @param {A} val 5 | * @returns {Promise} 6 | */ 7 | function selfResolved(val) { 8 | return Promise.resolve(val) 9 | } -------------------------------------------------------------------------------- /src/utils/type-examples/dot-notation.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/ghoullier/awesome-template-literal-types#dot-notation-string-type-safe 2 | 3 | type PathImpl = 4 | Key extends string 5 | ? T[Key] extends Record 6 | ? | `${Key}.${PathImpl> & string}` 7 | | `${Key}.${Exclude & string}` 8 | : never 9 | : never; 10 | 11 | type PathImpl2 = PathImpl | keyof T; 12 | 13 | type Path = PathImpl2 extends string | keyof T ? PathImpl2 : keyof T; 14 | 15 | type PathValue> = 16 | P extends `${infer Key}.${infer Rest}` 17 | ? Key extends keyof T 18 | ? Rest extends Path 19 | ? PathValue 20 | : never 21 | : never 22 | : P extends keyof T 23 | ? T[P] 24 | : never; 25 | 26 | declare function get>(obj: T, path: P): PathValue; 27 | 28 | const object = { 29 | firstName: "Diego", 30 | lastName: "Haz", 31 | age: 30, 32 | cool: { thing: { wow: 'nice' }}, 33 | 34 | projects: [ 35 | { name: "Reakit", contributors: 68 }, 36 | { name: "Constate", contributors: 12 }, 37 | ] 38 | } as const; 39 | 40 | get(object, "cool.thing.wow"); 41 | 42 | export {} -------------------------------------------------------------------------------- /src/utils/type-examples/tyoe-utils.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/shm-open/utilities/blob/master/src/types.ts 2 | 3 | /** 4 | * Make a Partial type with all its field types as partial - recursively 5 | */ 6 | export type RecursivePartial = { 7 | [P in keyof T]?: T[P] extends (infer U)[] 8 | ? RecursivePartial[] 9 | : 10 | T[P] extends object 11 | ? RecursivePartial 12 | : T[P]; 13 | }; 14 | 15 | /** 16 | * Nullable could be T or undefined or null 17 | */ 18 | export type Nullable = T | undefined | null; 19 | 20 | /** 21 | * Extract the type of object property 22 | */ 23 | export type PropertyType = T[K]; 24 | 25 | /** 26 | * Extract the type of array item 27 | */ 28 | export type ArrayItemType = T[number]; 29 | 30 | /** 31 | * Extract the types array of function parameters 32 | * @deprecated please use ts built-in Parameters instead. 33 | */ 34 | export type ParametersTypes = T extends (...args: infer P) => unknown ? P : []; 35 | 36 | /** 37 | * Convert interface to type, so it can be used to work with Record 38 | * check out this thread for details 39 | * https://github.com/microsoft/TypeScript/issues/15300#issuecomment-760165845 40 | * @example foo as Typify 41 | */ 42 | export type Typify = { [K in keyof T]: T[K] }; 43 | 44 | /** 45 | * convert object into typified instance, it's nothing more than `as Typify` 46 | * just works as an shorthand of explicit cast. 47 | * @param target interface type object 48 | * @returns the target itself, typified 49 | */ 50 | export function typify(target: T): Typify { 51 | return target; 52 | } 53 | 54 | /** 55 | * Covert type T to Promise except for Promises 56 | */ 57 | export type Promisify = T extends Promise 58 | ? T 59 | : T extends boolean 60 | ? Promise 61 | : Promise; -------------------------------------------------------------------------------- /src/utils/typedef-div-extend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {React.HTMLAttributes} DOMDiv 3 | */ 4 | 5 | /** 6 | * @typedef {Object} Props 7 | * @prop {string} [myprop] 8 | */ 9 | 10 | /** 11 | * @typedef {DOMDiv & Props} Thing 12 | */ 13 | 14 | /** 15 | * @type {Thing} 16 | */ 17 | const bozo = { 18 | myprop: 'clown', 19 | } 20 | 21 | /** 22 | * @type {DOMDiv & Props} 23 | */ 24 | const bozoz = { 25 | myprop: 'Bozo the Clown', 26 | id: 'xyxyx', 27 | } -------------------------------------------------------------------------------- /src/utils/typedef-extend.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Person object 3 | * @typedef {Object} Person 4 | * @prop {string} name 5 | * @prop {number} age 6 | */ 7 | 8 | /** 9 | * @typedef {Object} Job 10 | * @prop {string} [job] 11 | */ 12 | 13 | /** 14 | * Person with optional job 15 | * @typedef {Person & Job} Bozo 16 | */ 17 | 18 | /** 19 | * @type {Person} 20 | */ 21 | const personNoJob = { 22 | name: 'Bozo the Clown', 23 | age: 50, 24 | } 25 | 26 | /** 27 | * @type {Bozo} 28 | */ 29 | const bozo1 = { 30 | name: 'Bozo the Clown', 31 | age: 50, 32 | job: 'clown' 33 | } 34 | 35 | /** 36 | * @type {Bozo} 37 | */ 38 | const bozo2 = { 39 | name: 'Bozo the Clown', 40 | age: 50, 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/types.d.ts: -------------------------------------------------------------------------------- 1 | import * as TypeFest from 'type-fest' 2 | 3 | export type Pet = { 4 | name: string, 5 | }; 6 | 7 | /* Export global types to avoid imports */ 8 | declare global { 9 | type SomethingGlobal = 'value' | 'value2' 10 | type CamelCasedPropsGlobal = { [K in keyof T as TypeFest.CamelCase]: T[K] }; 11 | // ────────────see enumns─────────── 12 | type Values = T[keyof T]; 13 | type RuneTierE = { 14 | COMMON: 1; 15 | SEMIRARE: 2; 16 | RARE: 3; 17 | }; 18 | type RuneTier = Values; 19 | // https://gist.github.com/nicolashery/b30d0464dbd016aa3978129652aa1385 20 | namespace Models { 21 | type ProductTag = "popular" | "featured" | "sale"; 22 | interface ProductTagEnum { 23 | Popular: "popular"; 24 | Featured: "featured"; 25 | Sale: "sale"; 26 | } 27 | 28 | interface Product { 29 | id: string; 30 | name: string; 31 | tags: Array; 32 | } 33 | } 34 | /* https://www.benmvp.com/blog/polymorphic-react-components-typescript/ */ 35 | // Source: https://github.com/emotion-js/emotion/blob/master/packages/styled-base/types/helper.d.ts 36 | // A more precise version of just React.ComponentPropsWithoutRef on its own 37 | type PropsOf< 38 | C extends keyof JSX.IntrinsicElements | React.JSXElementConstructor 39 | > = JSX.LibraryManagedAttributes> 40 | 41 | type AsProp = { 42 | /** 43 | * An override of the default HTML tag. 44 | * Can also be another React component. 45 | */ 46 | as?: C 47 | } 48 | /** 49 | * Allows for extending a set of props (`ExtendedProps`) by an overriding set of props 50 | * (`OverrideProps`), ensuring that any duplicates are overridden by the overriding 51 | * set of props. 52 | */ 53 | type ExtendableProps< 54 | ExtendedProps = {}, 55 | OverrideProps = {} 56 | > = OverrideProps & Omit 57 | /** 58 | * Allows for inheriting the props from the specified element type so that 59 | * props like children, className & style work, as well as element-specific 60 | * attributes like aria roles. The component (`C`) must be passed in. 61 | */ 62 | type InheritableElementProps< 63 | C extends React.ElementType, 64 | Props = {} 65 | > = ExtendableProps, Props> 66 | /** 67 | * A more sophisticated version of `InheritableElementProps` where 68 | * the passed in `as` prop will determine which props can be included 69 | */ 70 | type PolymorphicComponentProps< 71 | C extends React.ElementType, 72 | Props = {} 73 | > = InheritableElementProps> 74 | } 75 | -------------------------------------------------------------------------------- /src/utils/xyz.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line spaced-comment 2 | 3 | // https://github.com/Agoric/agoric-sdk/blob/20c4ff00adbffff067858c3c5702ae7a9e0522b8/packages/pegasus/package.json#L53 4 | 5 | /** 6 | * @typedef {string} DenomUri 7 | * @typedef {string} Denom 8 | * @typedef {string} DepositAddress 9 | * @typedef {string} TransferProtocol 10 | * @typedef {string} Brand 11 | * @typedef {string} ZCFSeat 12 | 13 | * 14 | * @typedef {Object} Peg 15 | * @property {() => string} getAllegedName get the debug name 16 | * @property {() => Brand} getLocalBrand get the brand associated with the peg 17 | * @property {() => DenomUri} getDenomUri get the denomination identifier 18 | */ 19 | 20 | /** 21 | * @typedef {Object} BoardDepositFacet a registry for depositAddresses 22 | * @property {(id: string) => any} getValue return the corresponding DepositFacet 23 | */ 24 | 25 | /** 26 | * @typedef {Object} FungibleTransferPacket 27 | * @property {string} amount The extent of the amount 28 | * @property {Denom} denom The denomination of the amount 29 | * @property {string} [sender] The sender address 30 | * @property {DepositAddress} receiver The receiver deposit address 31 | */ 32 | 33 | /** 34 | * @typedef {(zcfSeat: ZCFSeat, depositAddress: DepositAddress) => Promise} Sender 35 | * Successive transfers are not guaranteed to be processed in the order in which they were sent. 36 | * @typedef {(packet: FungibleTransferPacket) => Promise} Receiver 37 | * @typedef {Object} Courier 38 | * @property {Sender} send 39 | * @property {Receiver} receive 40 | */ -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/zod/autozod.ts: -------------------------------------------------------------------------------- 1 | export interface Enemy { 2 | name: string; 3 | powers: string[]; 4 | inPrison: boolean; 5 | } 6 | export interface Superman { 7 | name: "superman" | "clark kent" | "kal-l"; 8 | enemies: Record; 9 | age: number; 10 | underKryptonite?: boolean; 11 | } 12 | export interface Villain { 13 | name: string; 14 | powers: string[]; 15 | friends: Villain[]; 16 | } 17 | export interface EvilPlan { 18 | owner: Villain; 19 | description: string; 20 | details: EvilPlanDetails; 21 | } 22 | export interface EvilPlanDetails { 23 | parent: EvilPlan; 24 | steps: string[]; 25 | } 26 | export declare type Story = [subject: string, problems: string[]]; 27 | export declare type KrytonResponse = Promise; 28 | export declare type KillSuperman = (withKryptonite: boolean, method: string) => Promise; 29 | export interface WithDefaults { 30 | /** 31 | * @default 42 32 | */ 33 | theAnswerToTheUltimateQuestionOfLife: number; 34 | /** 35 | * @default false 36 | */ 37 | isVulnerable: boolean; 38 | /** 39 | * @default clark 40 | */ 41 | name: "clark" | "superman" | "kal-l"; 42 | /** 43 | * @default The Answer to the Ultimate Question of Life 44 | */ 45 | theMeaningOf42: string; 46 | /** 47 | * @default "" 48 | */ 49 | emptyString?: string; 50 | /** 51 | * @default "true" 52 | */ 53 | booleanAsString: string; 54 | } 55 | interface NonExported { 56 | name: string; 57 | } 58 | export interface Exported { 59 | a: NonExported; 60 | b: string; 61 | } 62 | export {}; 63 | -------------------------------------------------------------------------------- /src/zod/example-js.js: -------------------------------------------------------------------------------- 1 | import { supermanSchema } from './autozod.validate' 2 | 3 | /** 4 | * @type { import("./autozod").Superman } Superman 5 | */ 6 | const superman = { 7 | name: 'superman', 8 | age: 12, 9 | underKryptonite: false, 10 | enemies: { 11 | bill: { 12 | name: 'bill', 13 | powers: ['flys'], 14 | inPrison: false 15 | } 16 | } 17 | } 18 | 19 | supermanSchema.parse(superman) 20 | -------------------------------------------------------------------------------- /src/zod/example.ts: -------------------------------------------------------------------------------- 1 | import { Superman } from './autozod' 2 | import { supermanSchema } from './autozod.validate' 3 | 4 | const superman: Superman = { 5 | name: 'superman', 6 | age: 12, 7 | underKryptonite: false, 8 | enemies: { 9 | bill: { 10 | name: 'bill', 11 | powers: ['flys'], 12 | inPrison: false 13 | } 14 | } 15 | } 16 | 17 | supermanSchema.parse(superman) 18 | -------------------------------------------------------------------------------- /src/zod/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface Funky { 2 | name: string; 3 | powers: string[]; 4 | inPrison: boolean; 5 | } 6 | 7 | export interface Fancy { 8 | name: "superman" | "clark kent" | "kal-l"; 9 | age: number; 10 | underKryptonite?: boolean; 11 | } -------------------------------------------------------------------------------- /ts-to-zod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: "example", 4 | input: "./src/zod/autozod.ts", 5 | output: "./src/zod/autozod.validate.js", 6 | }, 7 | // { 8 | // name: "config", 9 | // input: "src/config.ts", 10 | // output: "src/config.zod.ts" 11 | // }, 12 | ]; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 5 | "allowJs": true, 6 | "checkJs": true, 7 | "skipLibCheck": false, 8 | "noImplicitAny": false, 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "strictNullChecks": false, 14 | "module": "ESNext", 15 | "moduleResolution": "Node", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "noEmit": true, 19 | "declaration": true, 20 | "jsx": "react" 21 | }, 22 | "include": ["./src"], 23 | "exclude": [ 24 | "**/*.d.ts", 25 | "dist", 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://typedoc.org/schema.json", 3 | "entryPoints": ["./src/utils/examples.js"], 4 | "sort": ["source-order"], 5 | "media": "media" 6 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import reactRefresh from '@vitejs/plugin-react-refresh' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [reactRefresh()], 7 | css: { 8 | modules: { 9 | localsConvention: 'camelCaseOnly', 10 | }, 11 | } 12 | }) 13 | --------------------------------------------------------------------------------