From ac3705b42270eeebf5cdae8fcda6facdbbf786aa Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Wed, 6 Nov 2019 10:28:53 +0800 Subject: [PATCH] fix: move scripts docs in @tarojs/taro --- build/docs-api.ts | 70 --------- build/tsconfig.json | 6 - package.json | 3 +- packages/taro/package.json | 3 +- packages/taro/scripts/docs-api.ts | 134 ++++++++++++++++++ .../taro/scripts}/parser/index.ts | 42 ++++-- {build => packages/taro/scripts}/test-file.ts | 0 packages/taro/tsconfig.json | 10 ++ .../taro/types/api/device/accelerometer.d.ts | 51 ++++--- 9 files changed, 202 insertions(+), 117 deletions(-) delete mode 100644 build/docs-api.ts delete mode 100644 build/tsconfig.json create mode 100644 packages/taro/scripts/docs-api.ts rename {build => packages/taro/scripts}/parser/index.ts (78%) rename {build => packages/taro/scripts}/test-file.ts (100%) create mode 100644 packages/taro/tsconfig.json diff --git a/build/docs-api.ts b/build/docs-api.ts deleted file mode 100644 index 1ad030f1dcf4..000000000000 --- a/build/docs-api.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as fs from "fs" -import * as path from "path" -import * as ts from "typescript" -import { generateDocumentation, DocEntry } from "./parser" - -export default function docsAPI (base: string = '.', out: string, files: string[]) { - const cwd: string = process.cwd(); - const basepath: string = path.resolve(cwd, base); - files.forEach(async s => { - compile(cwd, s, (routepath, doc) => { - console.log(routepath, doc.length) - if (doc.length < 1) return - const outpath: string = routepath - .replace(basepath, path.resolve(cwd, out)) - .replace(/(.[a-z]+)$|(.d.ts)$/ig, '') - try { - writeDoc(outpath, doc) - } catch (error) { - fs.mkdirSync(path.parse(outpath).dir, { recursive: true }) - writeDoc(outpath, doc) - } - }) - }) -} - -export function compile (p: string, n: string, callback?: (routepath: string, doc: DocEntry[]) => void) { - const route = path.resolve(p, n) - const stat = fs.statSync(route) - if (stat.isDirectory()) { - fs.readdirSync(route, { - encoding: 'utf8' - }).forEach(filename => ![ - 'node_modules', 'bin', 'templates', 'dist', '__tests__', '__mocks__', '_book', '.vscode', '.idea' - ].includes(filename) && compile(route, filename, callback)) - } else { - const docTree = generateDocumentation(route, { - target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.ESNext - }) - callback && callback(route, docTree) - } -} - -export function writeJson (routepath: string, doc: DocEntry[]) { - fs.writeFileSync( - `${routepath}.json`, - JSON.stringify(doc, undefined, 4), - {} - ) -} - -export function writeDoc (routepath: string, doc: DocEntry[]) { - const o = path.parse(routepath) - const md: string[] = ['---', `title: ${o.base}`, `sidebar_label: ${o.base}`, '---', ''] - doc.forEach(e => { - // console.log(`${routepath}/${e.name}.md`) - // if (e.name === 'Taro') { - // console.log(routepath, e) - // } - e.name !== 'Taro' && md.push(JSON.stringify(e, undefined, 2)) - }) - fs.writeFileSync( - `${routepath}.md`, - md.join('\n'), - {} - ) -} - -// docsAPI('.', process.argv[2], process.argv.slice(3)) -docsAPI('./packages/taro/types/api', 'api', ['./packages/taro/types/api/']) diff --git a/build/tsconfig.json b/build/tsconfig.json deleted file mode 100644 index 776b92721c1b..000000000000 --- a/build/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "module": "umd" - } -} diff --git a/package.json b/package.json index b7b620ed93bb..6d794c6b941d 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "release:lerna": "lerna publish --force-publish=* --exact --skip-temp-tag", "release:beta": "lerna publish --force-publish=* --exact --skip-temp-tag --preid=beta --npm-tag=beta", "release": "npm-run-all build release:lerna && npm run changelog && node ./build/docs-version.js", - "test": "lerna run --scope eslint-plugin-taro --scope @tarojs/transformer-wx test", - "test:docs": "ts-node -P ./build/tsconfig.json ./build/docs-api.ts" + "test": "lerna run --scope eslint-plugin-taro --scope @tarojs/transformer-wx test" }, "repository": { "type": "git", diff --git a/packages/taro/package.json b/packages/taro/package.json index f060f540bd17..a11ba5d06da6 100644 --- a/packages/taro/package.json +++ b/packages/taro/package.json @@ -14,7 +14,8 @@ ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "rollup -c rollup.config.js" + "build": "rollup -c rollup.config.js", + "docs": "ts-node ./scripts/docs-api.ts" }, "repository": { "type": "git", diff --git a/packages/taro/scripts/docs-api.ts b/packages/taro/scripts/docs-api.ts new file mode 100644 index 000000000000..687cee8c47ff --- /dev/null +++ b/packages/taro/scripts/docs-api.ts @@ -0,0 +1,134 @@ +import * as fs from "fs" +import * as path from "path" +import * as ts from "typescript" +import { generateDocumentation, DocEntry } from "./parser" + +// import * as h5 from '@tarojs/taro-h5' +// console.log(h5) + +interface DocNode { + fileName?: string + documentation?: string + jsTags?: { [key: string]: string } + type?: string + constructors?: DocEntry[] + parameters?: DocEntry[] + returnType?: string + members?: DocNode + exports?: DocNode + children?: DocNode +} + +export default function docsAPI (base: string = '.', out: string, files: string[]) { + const cwd: string = process.cwd(); + const basepath: string = path.resolve(cwd, base); + files.forEach(async s => { + compile(cwd, s, (routepath, doc) => { + console.log(routepath) // , doc.length) + if (doc.length < 1) return + const outpath: string = routepath + .replace(basepath, path.resolve(cwd, out)) + .replace(/(.[a-z]+)$|(.d.ts)$/ig, '') + try { + writeDoc(outpath, doc) + } catch (error) { + const _p = path.parse(outpath) + fs.mkdirSync(_p.name === 'index' ? _p.dir : outpath, { recursive: true }) + writeDoc(outpath, doc) + } + }) + }) +} + +export function compile (p: string, n: string, callback?: (routepath: string, doc: DocEntry[]) => void) { + const route = path.resolve(p, n) + const stat = fs.statSync(route) + if (stat.isDirectory()) { + fs.readdirSync(route, { + encoding: 'utf8' + }).forEach(filename => ![ + 'node_modules', 'bin', 'templates', 'dist', '__tests__', '__mocks__', '_book', '.vscode', '.idea' + ].includes(filename) && compile(route, filename, callback)) + } else { + const docTree = generateDocumentation(route, { + target: ts.ScriptTarget.ES5, + module: ts.ModuleKind.ESNext + }) + callback && callback(route, docTree) + } +} + +export function writeJson (routepath: string, doc: DocEntry[]) { + fs.writeFileSync( + `${routepath}.json`, + JSON.stringify(doc, undefined, 4), + {} + ) +} + +export function writeDoc (routepath: string, doc: DocEntry[]) { + const _p = path.parse(routepath) + const Taro = merge().Taro + + function merge (d: DocEntry[] = doc, o: any = {}) { + d.forEach(e => { + const name = e.name || 'undefined' + if (!o[name]) o[name] = {} + for (const key in e) { + if (e.hasOwnProperty(key) && e[key] && !['name', 'kind', 'flags'].includes(key)) { + if (key === 'children') { + if (!o[name].children) { + o[name].children = merge(e.children) + } + } else if (key === 'exports') { + if (!o[name].exports) { + o[name].exports = merge(e.exports) + } + } else { + o[name][key] = e[key] + } + } + } + }) + Object.values(o).forEach((e: DocNode) => { + if (e.children) { + if (!e.exports) e.exports = {}; + for (const k in e.children) { + if (e.exports[k]) { + Object.assign(e.exports[k], e.children[k]) + } else { + e.exports[k] = e.children[k] + } + } + delete e.children + } + const jsTags = {} + if (e.jsTags) { + const tags: ts.JSDocTagInfo[] = e.jsTags as unknown as [] + tags.forEach((k: ts.JSDocTagInfo) => jsTags[k.name] = k.text || '') + } + e.jsTags = jsTags + }) + return o + } + + Object.keys(Taro.exports).forEach(name => { + const e = Taro.exports[name] + const tags = e.jsTags || {} + const params = e.parameters || [] + const md: string[] = ['---', `title: Taro.${name}(${params.map(param => param.name).join(', ')})`, `sidebar_label: ${name}`, '---', ''] + e.documentation && md.push(e.documentation, '') + e.type && md.push('## 类型', '```typescript', e.type, '```', '') + tags.example && md.push('## 参数', tags.exports, '') + tags.example && md.push('## 示例代码', '', tags.example, '') + md.push(JSON.stringify(e, undefined, 2)) + fs.writeFileSync( + path.resolve(_p.name === 'index' ? _p.dir : routepath, `${name}.md`), + md.join('\n'), + {} + ) + }) +} + +// docsAPI('.', process.argv[2], process.argv.slice(3)) +docsAPI('./types/api', '../../api', ['./types/api/']) diff --git a/build/parser/index.ts b/packages/taro/scripts/parser/index.ts similarity index 78% rename from build/parser/index.ts rename to packages/taro/scripts/parser/index.ts index e42de8e115a1..8f4500725013 100644 --- a/build/parser/index.ts +++ b/packages/taro/scripts/parser/index.ts @@ -1,7 +1,9 @@ import * as ts from "typescript" export interface DocEntry { - name?: string | ts.__String + name?: string + kind?: ts.SyntaxKind + flags?: ts.SymbolFlags fileName?: string documentation?: string jsTags?: ts.JSDocTagInfo[] @@ -11,27 +13,27 @@ export interface DocEntry { returnType?: string members?: DocEntry[] exports?: DocEntry[] + children?: DocEntry[] } export function generateDocumentation( filepath: string, - options: ts.CompilerOptions + options: ts.CompilerOptions, + output: DocEntry[] = [] ): DocEntry[] { const program = ts.createProgram([filepath], options) const checker = program.getTypeChecker() - const output: DocEntry[] = [] - for (const sourceFile of program.getSourceFiles()) { // if (!sourceFile.isDeclarationFile) {} if (filepath === sourceFile.fileName) { - ts.forEachChild(sourceFile, visitAST) + ts.forEachChild(sourceFile, (n) => visitAST(n, output)) } } return output - function visitAST(node: ts.Node) { + function visitAST(node: ts.Node, o: DocEntry[]) { // Only consider exported nodes if (!isNodeExported(node as ts.Declaration) || node.kind === ts.SyntaxKind.EndOfFileToken || node.kind === ts.SyntaxKind.DeclareKeyword || ts.isImportDeclaration(node) || ts.isImportEqualsDeclaration(node) || ts.isImportClause(node) @@ -43,29 +45,38 @@ export function generateDocumentation( if (ts.isVariableDeclaration(node) || ts.isClassDeclaration(node) && node.name) { const symbol = checker.getSymbolAtLocation(node) - symbol && output.push(serializeClass(symbol)) + symbol && o.push(serializeClass(symbol)) } else if (ts.isFunctionDeclaration(node)) { const signature = checker.getSignatureFromDeclaration(node) - signature && output.push(serializeSignature(signature, node.name && ts.idText(node.name))) + signature && o.push(serializeSignature(signature, node.name && ts.idText(node.name))) } else if (ts.isInterfaceDeclaration(node)) { const symbol = checker.getTypeAtLocation(node).getSymbol() - symbol && output.push(serializeType(symbol, undefined, 'InterfaceDeclaration')) + symbol && o.push(serializeType(symbol, undefined, 'InterfaceDeclaration')) } else if (ts.isTypeAliasDeclaration(node)) { const symbol = checker.getTypeAtLocation(node).getSymbol() - symbol && output.push(serializeType(symbol, ts.idText(node.name), 'TypeAliasDeclaration')) + symbol && o.push(serializeType(symbol, ts.idText(node.name), 'TypeAliasDeclaration')) } else if (ts.isEnumDeclaration(node)) { const symbol = checker.getTypeAtLocation(node).getSymbol() - symbol && output.push(serializeType(symbol)) + symbol && o.push(serializeType(symbol)) } else if (ts.isIdentifier(node)) { const symbol = checker.getTypeAtLocation(node).getSymbol() - symbol && output.push(serializeType(symbol)) - } else if (ts.isModuleDeclaration(node) || ts.isModuleBlock(node) || ts.isVariableStatement(node)) { + symbol && o.push(serializeType(symbol)) + } else if (ts.isModuleDeclaration(node) || ts.isVariableStatement(node)) { + // This is a namespace, visitAST its children + ts.forEachChild(node, (n) => visitAST(n, o)) + } else if (ts.isModuleBlock(node)) { // This is a namespace, visitAST its children - ts.forEachChild(node, visitAST) + const out: DocEntry = { + name: ts.isIdentifier(node.parent.name) ? ts.idText(node.parent.name) : '', + kind: node.kind, + children: [] + } + ts.forEachChild(node, (n) => visitAST(n, out.children!)) + o.push(out) } else if (ts.isVariableDeclarationList(node)) { node.declarations.forEach(d => { const symbol = d['symbol'] - symbol && output.push(serializeType(symbol)) + symbol && o.push(serializeType(symbol)) }) } else { console.log(`WARN: Statement kind ${node.kind} is missing parse!\n\n${node.getText()}`) @@ -77,6 +88,7 @@ export function generateDocumentation( return { jsTags: symbol.getJsDocTags(), name: name || symbol.getName(), + flags: symbol.flags, documentation: ts.displayPartsToString(symbol.getDocumentationComment(checker)), type: type || checker.typeToString( checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!) diff --git a/build/test-file.ts b/packages/taro/scripts/test-file.ts similarity index 100% rename from build/test-file.ts rename to packages/taro/scripts/test-file.ts diff --git a/packages/taro/tsconfig.json b/packages/taro/tsconfig.json new file mode 100644 index 000000000000..77e898359fdb --- /dev/null +++ b/packages/taro/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "umd", + "resolveJsonModule": false, + "paths": { + "@tarojs/taro-h5": ["packages/taro-h5"] + } + } +} diff --git a/packages/taro/types/api/device/accelerometer.d.ts b/packages/taro/types/api/device/accelerometer.d.ts index 004d593a3c8f..5355c97168de 100644 --- a/packages/taro/types/api/device/accelerometer.d.ts +++ b/packages/taro/types/api/device/accelerometer.d.ts @@ -6,24 +6,29 @@ declare namespace Taro { * @default normal */ interval?: 'game' | 'ui' | 'normal' - // 接口调用成功的回调函数 + /** + * 接口调用成功的回调函数 + */ success?: Function - // 接口调用失败的回调函数 + /** + * 接口调用失败的回调函数 + */ fail?: Function - // 接口调用结束的回调函数(调用成功、失败都会执行) + /** + * 接口调用结束的回调函数(调用成功、失败都会执行) + */ complete?: Function } } /** * 开始监听加速度数据。 - * @name Taro.startAccelerometer(res) * @since 1.1.0 * @example - * ```javascript - * import Taro from '@tarojs/taro' - * - * Taro.startAccelerometer({ interval: 'game' }) - * ``` +```javascript +import Taro from '@tarojs/taro' + +Taro.startAccelerometer({ interval: 'game' }) +``` * @see https://developers.weixin.qq.com/miniprogram/dev/api/device/accelerometer/wx.startAccelerometer.html */ function startAccelerometer(OBJECT?: startAccelerometer.Param): Promise @@ -35,11 +40,11 @@ declare namespace Taro { * 停止监听加速度数据。 * @since 1.1.0 * @example - * ```javascript - * import Taro from '@tarojs/taro' - * - * Taro.stopAccelerometer() - * ``` +```javascript +import Taro from '@tarojs/taro' + +Taro.stopAccelerometer() +``` * @see https://developers.weixin.qq.com/miniprogram/dev/api/device/accelerometer/wx.stopAccelerometer.html */ function stopAccelerometer(OBJECT?: stopAccelerometer.Param): Promise @@ -64,15 +69,15 @@ declare namespace Taro { /** * 监听加速度数据,频率:5次/秒,接口调用后会自动开始监听,可使用 `Taro.stopAccelerometer` 停止监听。 * @example - * ```javascript - * import Taro from '@tarojs/taro' - * - * Taro.onAccelerometerChange(res => { - * console.log(res.x) - * console.log(res.y) - * console.log(res.z) - * }) - * ``` +```javascript +import Taro from '@tarojs/taro' + +Taro.onAccelerometerChange(res => { + console.log(res.x) + console.log(res.y) + console.log(res.z) +}) +``` * @see https://developers.weixin.qq.com/miniprogram/dev/api/device/accelerometer/wx.onAccelerometerChange.html */ function onAccelerometerChange(CALLBACK: onAccelerometerChange.Param): void