@moneko/core 3.2.1-beta.0 → 3.2.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app-entry.js +32 -1
- package/lib/app.js +40 -2
- package/lib/cleanup.js +19 -1
- package/lib/common.js +248 -1
- package/lib/config.js +234 -1
- package/lib/coverage.js +33 -2
- package/lib/dev.js +89 -5
- package/lib/docs.js +120 -2
- package/lib/done.js +12 -1
- package/lib/esm.js +7 -1
- package/lib/fallback.js +6 -1
- package/lib/generate-api.d.ts +1 -1
- package/lib/generate-api.js +345 -3
- package/lib/has-pkg.js +12 -1
- package/lib/html-add-entry-attr.js +32 -10
- package/lib/html-plugin-option.js +45 -1
- package/lib/index.js +4 -1
- package/lib/locales.js +93 -3
- package/lib/merge-router.js +1 -1
- package/lib/minify.js +47 -2
- package/lib/modify-vars.js +11 -1
- package/lib/module-federation.js +46 -1
- package/lib/module.config.js +273 -3
- package/lib/net.js +33 -1
- package/lib/normalize-css.js +6 -1
- package/lib/paths.js +21 -1
- package/lib/polyfills/replace-children.js +26 -3
- package/lib/polyfills.js +15 -3
- package/lib/prefix-router.js +6 -1
- package/lib/process-env.js +33 -2
- package/lib/prod.js +65 -5
- package/lib/reactive-object.js +47 -8
- package/lib/rem.js +6 -1
- package/lib/resolver-sync.js +27 -1
- package/lib/routes.js +196 -4
- package/lib/seo.js +41 -2
- package/lib/swcrc.js +100 -2
- package/lib/tsloader.config.js +26 -2
- package/lib/utils.js +71 -7
- package/lib/virtual-module-plugin.js +49 -1
- package/lib/virtual-modules.js +37 -1
- package/lib/yarn-argv.js +9 -1
- package/package.json +6 -2
- package/typings/global.d.ts +1 -2
package/lib/dev.js
CHANGED
|
@@ -1,6 +1,90 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import FriendlyErrorsWebpackPlugin from '@soda/friendly-errors-webpack-plugin';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import webpack from 'webpack';
|
|
4
|
+
import { merge } from 'webpack-merge';
|
|
5
|
+
import { clientConfig } from './common.js';
|
|
6
|
+
import { CONFIG } from './config.js';
|
|
7
|
+
import { hasPkg } from './has-pkg.js';
|
|
8
|
+
import { getIPv4, getPort } from './net.js';
|
|
9
|
+
import { isReact } from './process-env.js';
|
|
10
|
+
import { isFunction, resolveProgramPath } from './utils.js';
|
|
11
|
+
const { HotModuleReplacementPlugin } = webpack;
|
|
12
|
+
const { yellow, green } = chalk;
|
|
13
|
+
const ip = getIPv4();
|
|
14
|
+
const oldPord = CONFIG.devServer.port || 3000;
|
|
15
|
+
const port = await getPort(oldPord, 65535, CONFIG.devServer.host);
|
|
16
|
+
const skipPort = CONFIG.devServer.port !== port;
|
|
17
|
+
const hasMockMiddlewares = hasPkg('@moneko/mock');
|
|
18
|
+
const mockMiddlewares = hasMockMiddlewares && (await import('@moneko/mock')).default;
|
|
19
|
+
const ReactRefresh = isReact && (await import('@pmmmwh/react-refresh-webpack-plugin')).default;
|
|
20
|
+
const devtool = CONFIG.devtool === false || CONFIG.devtool ? CONFIG.devtool : 'eval-cheap-module-source-map';
|
|
21
|
+
CONFIG.devServer.port = port;
|
|
22
|
+
const initRouteBase = CONFIG.basename === '/';
|
|
23
|
+
const protocol = CONFIG.devServer.https ? 'https:' : 'http:';
|
|
24
|
+
const routeBase = initRouteBase ? '' : CONFIG.basename;
|
|
25
|
+
const client = merge(clientConfig, {
|
|
26
|
+
devtool: devtool,
|
|
27
|
+
mode: 'development',
|
|
28
|
+
devServer: {
|
|
29
|
+
headers: {
|
|
30
|
+
'Access-Control-Allow-Origin': '*'
|
|
31
|
+
},
|
|
32
|
+
compress: CONFIG.devServer.compress,
|
|
33
|
+
host: '0.0.0.0',
|
|
34
|
+
port: port,
|
|
35
|
+
historyApiFallback: initRouteBase || {
|
|
36
|
+
index: routeBase.endsWith('/') ? routeBase : `${routeBase}/`,
|
|
37
|
+
disableDotRule: true
|
|
38
|
+
},
|
|
39
|
+
https: CONFIG.devServer.https,
|
|
40
|
+
proxy: CONFIG.proxy,
|
|
41
|
+
allowedHosts: CONFIG.devServer.allowedHosts,
|
|
42
|
+
client: {
|
|
43
|
+
// 在浏览器中以百分比显示编译进度。
|
|
44
|
+
progress: false,
|
|
45
|
+
logging: 'info',
|
|
46
|
+
// 当出现编译错误或警告时,在浏览器中显示全屏覆盖。
|
|
47
|
+
overlay: false
|
|
48
|
+
},
|
|
49
|
+
static: {
|
|
50
|
+
watch: {
|
|
51
|
+
ignored: (f)=>{
|
|
52
|
+
// 生成的类型定义不要监听,否则会引发全局的 reload 使 HMR 失去意义
|
|
53
|
+
return f.endsWith('.d.ts') || /\/node_modules\//.test(f);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
setupMiddlewares: (middlewares, devServer)=>{
|
|
58
|
+
if (!devServer) {
|
|
59
|
+
throw new Error('webpack-dev-server is not defined');
|
|
60
|
+
}
|
|
61
|
+
if (devServer.app && isFunction(mockMiddlewares)) {
|
|
62
|
+
mockMiddlewares(devServer.app, resolveProgramPath('mock/'));
|
|
63
|
+
}
|
|
64
|
+
return middlewares;
|
|
65
|
+
},
|
|
66
|
+
open: false,
|
|
67
|
+
hot: true
|
|
68
|
+
},
|
|
69
|
+
plugins: [
|
|
70
|
+
new HotModuleReplacementPlugin(),
|
|
71
|
+
ReactRefresh && new ReactRefresh(),
|
|
72
|
+
new FriendlyErrorsWebpackPlugin({
|
|
73
|
+
compilationSuccessInfo: {
|
|
74
|
+
messages: [
|
|
75
|
+
`You application is running here:
|
|
4
76
|
|
|
5
|
-
Local: ${
|
|
6
|
-
Network: ${
|
|
77
|
+
Local: ${chalk.cyan(`${protocol}//${CONFIG.devServer.host}:${port}${routeBase}`)}
|
|
78
|
+
Network: ${chalk.cyan(`${protocol}//${ip}:${port}${routeBase}`)}`
|
|
79
|
+
],
|
|
80
|
+
notes: skipPort ? [
|
|
81
|
+
`Port ${yellow(oldPord)} is in use, trying ${green(port)} instead`
|
|
82
|
+
] : []
|
|
83
|
+
},
|
|
84
|
+
clearConsole: true
|
|
85
|
+
})
|
|
86
|
+
].filter(Boolean)
|
|
87
|
+
});
|
|
88
|
+
export default [
|
|
89
|
+
client
|
|
90
|
+
];
|
package/lib/docs.js
CHANGED
|
@@ -1,2 +1,120 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import { stat } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { watch } from 'chokidar';
|
|
4
|
+
import { CONFIG } from './config.js';
|
|
5
|
+
import generateApi from './generate-api.js';
|
|
6
|
+
import { FRAMEWORK, FRAMEWORKNAME, createElement, isLibrary, isReact, isSolid } from './process-env.js';
|
|
7
|
+
import ReactiveObject from './reactive-object.js';
|
|
8
|
+
import { resolveProgramPath } from './utils.js';
|
|
9
|
+
const base = '@app/comment';
|
|
10
|
+
const apiEntry = '@app/docs';
|
|
11
|
+
export const docs = new ReactiveObject();
|
|
12
|
+
const cacheEnvApi = {
|
|
13
|
+
[base]: {}
|
|
14
|
+
};
|
|
15
|
+
let replaceStr = `() => ${createElement}(SuspenseComp, { comp: $1 })`;
|
|
16
|
+
let prefixStr = `import { ${createElement}${isSolid ? ',Dynamic' : ''} } from "${FRAMEWORKNAME}${isSolid ? '/web' : ''}";import SuspenseComp from "@app/suspense";`;
|
|
17
|
+
if (![
|
|
18
|
+
'react',
|
|
19
|
+
'solid'
|
|
20
|
+
].includes(FRAMEWORK)) {
|
|
21
|
+
replaceStr = '$1';
|
|
22
|
+
prefixStr = '';
|
|
23
|
+
}
|
|
24
|
+
// 要执行的函数
|
|
25
|
+
function handleFileChange(filePath, changeType) {
|
|
26
|
+
const fil = filePath.replace(new RegExp(`^${CONFIG.alias['@pkg']}`), '');
|
|
27
|
+
const __dir = dirname(fil).replace(/^\//, '');
|
|
28
|
+
const apiDir = [
|
|
29
|
+
base,
|
|
30
|
+
__dir
|
|
31
|
+
].join('/');
|
|
32
|
+
const name = fil.split('/').pop()?.replace(/\.tsx?/, '.md');
|
|
33
|
+
if (!name) return;
|
|
34
|
+
if (!cacheEnvApi[base][__dir]) {
|
|
35
|
+
cacheEnvApi[base][__dir] = {};
|
|
36
|
+
}
|
|
37
|
+
const target = join(apiDir, name);
|
|
38
|
+
function update() {
|
|
39
|
+
const basestr = {};
|
|
40
|
+
for(const k in cacheEnvApi){
|
|
41
|
+
if (Object.prototype.hasOwnProperty.call(cacheEnvApi, k)) {
|
|
42
|
+
const item = cacheEnvApi[k];
|
|
43
|
+
if (k === base) {
|
|
44
|
+
for(const kb in item){
|
|
45
|
+
if (Object.prototype.hasOwnProperty.call(item, kb)) {
|
|
46
|
+
basestr[kb] = Object.values(item[kb]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
docs.setData(k, item);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
docs.setData(apiEntry, `${prefixStr}export default ${JSON.stringify(basestr).replace(/"rr\((.+?)\)rr"/g, replaceStr)}`);
|
|
55
|
+
}
|
|
56
|
+
if (changeType === 'deleted') {
|
|
57
|
+
if (cacheEnvApi[base][__dir][name]) {
|
|
58
|
+
delete cacheEnvApi[base][__dir][name];
|
|
59
|
+
}
|
|
60
|
+
update();
|
|
61
|
+
} else {
|
|
62
|
+
generateApi(filePath, (api)=>{
|
|
63
|
+
cacheEnvApi[target] = api;
|
|
64
|
+
if (api) {
|
|
65
|
+
cacheEnvApi[base][__dir][name] = `rr(() => import(/* webpackChunkName: '${target}' */'${target}?raw').then((res) => ({default: ${isReact ? '() =>' : ''}${createElement}(${isSolid ? 'Dynamic' : "'n-md'"}, {text: res.default, ${isSolid ? "component: 'n-md', " : ''}css: 'table td a {display:inline-flex;align-items:center;gap:2px;}table td a n-img{display:inline-block;overflow:hidden;border-radius:var(--border-radius);inline-size:18px;block-size:18px;}'})})))rr`;
|
|
66
|
+
} else if (cacheEnvApi[base][__dir][name]) {
|
|
67
|
+
delete cacheEnvApi[base][__dir][name];
|
|
68
|
+
}
|
|
69
|
+
update();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function watchDirectory() {
|
|
74
|
+
const files = [];
|
|
75
|
+
const watcher = watch(resolveProgramPath('components'), {
|
|
76
|
+
ignored: [
|
|
77
|
+
/(^|\/)\../,
|
|
78
|
+
/(^|\/)__tests__(\/|$)/
|
|
79
|
+
],
|
|
80
|
+
persistent: true,
|
|
81
|
+
ignoreInitial: false
|
|
82
|
+
});
|
|
83
|
+
function isTs(path, stats) {
|
|
84
|
+
return /\.tsx?$/.test(path) && stats.isFile();
|
|
85
|
+
}
|
|
86
|
+
watcher.on('add', (path)=>{
|
|
87
|
+
stat(path, (err, stats)=>{
|
|
88
|
+
if (!err && isTs(path, stats)) {
|
|
89
|
+
handleFileChange(path, 'added');
|
|
90
|
+
files.push(path);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
watcher.on('change', (path)=>{
|
|
95
|
+
stat(path, (err, stats)=>{
|
|
96
|
+
if (!err && isTs(path, stats)) {
|
|
97
|
+
handleFileChange(path, 'change');
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
watcher.on('unlink', (path)=>{
|
|
102
|
+
stat(path, (err, stats)=>{
|
|
103
|
+
if (!err && isTs(path, stats)) {
|
|
104
|
+
handleFileChange(path, 'deleted');
|
|
105
|
+
files.splice(files.indexOf(path), 1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
watcher.on('ready', ()=>{
|
|
110
|
+
files.forEach((f)=>{
|
|
111
|
+
handleFileChange(f, 'change');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
process.on('SIGINT', function() {
|
|
115
|
+
watcher.close();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (isLibrary) {
|
|
119
|
+
watchDirectory();
|
|
120
|
+
}
|
package/lib/done.js
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
class DoneWebpackPlugin {
|
|
2
|
+
options;
|
|
3
|
+
constructor(options){
|
|
4
|
+
this.options = Object.assign({}, options);
|
|
5
|
+
}
|
|
6
|
+
apply(compiler) {
|
|
7
|
+
compiler.hooks.done.tap('DoneWebpackPlugin', ()=>{
|
|
8
|
+
this.options.done?.();
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default DoneWebpackPlugin;
|
package/lib/esm.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
export default function
|
|
1
|
+
export default function esm(templateStrings, ...substitutions) {
|
|
2
|
+
let js = templateStrings.raw[0];
|
|
3
|
+
for(let i = 0; i < substitutions.length; i++){
|
|
4
|
+
js += substitutions[i] + templateStrings.raw[i + 1];
|
|
5
|
+
}
|
|
6
|
+
return `data:text/javascript;base64,${Buffer.from(js).toString('base64')}`;
|
|
7
|
+
}
|
package/lib/fallback.js
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
import{CONFIG
|
|
1
|
+
import { CONFIG } from './config.js';
|
|
2
|
+
let fallback = 'export default null';
|
|
3
|
+
if (CONFIG.fallbackCompPath) {
|
|
4
|
+
fallback = `import Fallback from "${CONFIG.fallbackCompPath}";export default Fallback;`;
|
|
5
|
+
}
|
|
6
|
+
export default fallback;
|
package/lib/generate-api.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function generateApi(path: string):
|
|
1
|
+
export default function generateApi(path: string, call: (data: string) => void): void;
|
package/lib/generate-api.js
CHANGED
|
@@ -1,3 +1,345 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { readFile } from 'fs';
|
|
2
|
+
import { dirname } from 'path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import { CONFIG } from './config.js';
|
|
5
|
+
const { ScriptKind, ScriptTarget, SyntaxKind, createSourceFile, forEachChild, getLeadingCommentRanges, isInterfaceDeclaration, isQuestionToken, isPropertySignature, isFunctionTypeNode, isUnionTypeNode, isMethodSignature } = ts;
|
|
6
|
+
const allType = {};
|
|
7
|
+
function getPropertyComment(propertyNode) {
|
|
8
|
+
const comments = getLeadingCommentRanges(propertyNode.getSourceFile().text, propertyNode.pos);
|
|
9
|
+
if (comments) {
|
|
10
|
+
const commentText = propertyNode.getSourceFile().text.substring(comments[0].pos, comments[0].end);
|
|
11
|
+
const match = commentText.match(/\/\*\*([\s\S]*?)\*\//);
|
|
12
|
+
if (match) {
|
|
13
|
+
return match[1].replace(/^\s*\* ?/gm, '').replace(/\s+$/, '').trim();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function getDefaultValueFromComment(commentText) {
|
|
19
|
+
if (!commentText) return null;
|
|
20
|
+
const defaultValueRegex = /@default\s+([^\n]+)/;
|
|
21
|
+
const defaultValueMatch = commentText.match(defaultValueRegex);
|
|
22
|
+
return defaultValueMatch ? defaultValueMatch[1].trim() : null;
|
|
23
|
+
}
|
|
24
|
+
function getVersionFromComment(commentText) {
|
|
25
|
+
if (!commentText) return null;
|
|
26
|
+
const versionRegex = /@since\s+([^\n]+)/;
|
|
27
|
+
const versionMatch = commentText.match(versionRegex);
|
|
28
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
29
|
+
}
|
|
30
|
+
function getAuthor(commentText) {
|
|
31
|
+
if (!commentText) return null;
|
|
32
|
+
const regex = /@author (\w+)\s*(?:<([^>]+)>)?/;
|
|
33
|
+
const match = commentText.match(regex);
|
|
34
|
+
if (match?.length) {
|
|
35
|
+
const author = match[1].trim();
|
|
36
|
+
let url = match[2]?.trim();
|
|
37
|
+
const isEmail = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(url);
|
|
38
|
+
if (!url) {
|
|
39
|
+
url = `https://github.com/${author}`;
|
|
40
|
+
} else if (isEmail) {
|
|
41
|
+
url = `mailto:${url}`;
|
|
42
|
+
}
|
|
43
|
+
return `[${author}](${url})`;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function getIgnore(commentText) {
|
|
48
|
+
if (!commentText) return null;
|
|
49
|
+
const versionRegex = /@ignore\s+([^\n]+)/;
|
|
50
|
+
const versionMatch = commentText.match(versionRegex);
|
|
51
|
+
return versionMatch ? versionMatch[1].trim() : null;
|
|
52
|
+
}
|
|
53
|
+
const regex = /(?<!['"])(unknown|any|void|bigint|object|undefined|null|boolean|number|string|symbol)(?!['"])/g;
|
|
54
|
+
function getTypeText(typeText, hasColor) {
|
|
55
|
+
if (!typeText) return null;
|
|
56
|
+
let modifiedTypeText = typeText.replace(/\b([A-Z][a-zA-Z0-9]*)\b/g, (item)=>{
|
|
57
|
+
if (allType[item]) {
|
|
58
|
+
const url = `/${[
|
|
59
|
+
CONFIG.basename,
|
|
60
|
+
allType[item]
|
|
61
|
+
].join('/').split('/').filter(Boolean).join('/')}`;
|
|
62
|
+
return hasColor ? `[\\color{#009688}{${item}}](${url})` : `[${item}](${url})`;
|
|
63
|
+
}
|
|
64
|
+
return hasColor ? `\\color{#009688}{${item}}` : item;
|
|
65
|
+
});
|
|
66
|
+
if (hasColor) {
|
|
67
|
+
modifiedTypeText = modifiedTypeText.replace(regex, (match)=>{
|
|
68
|
+
return `\\color{#009688}{${match}}`;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return modifiedTypeText;
|
|
72
|
+
}
|
|
73
|
+
function getMemberValue(memberNode) {
|
|
74
|
+
const initializer = memberNode.initializer;
|
|
75
|
+
if (initializer && ts.isStringLiteral(initializer)) {
|
|
76
|
+
return ` '${initializer.text}'`;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function replacePairedSymbols(inputString) {
|
|
81
|
+
if (!inputString) return null;
|
|
82
|
+
const coloredContent = [];
|
|
83
|
+
let matches;
|
|
84
|
+
while(matches = /\\color{([^|}]*)\|?([^|}]*)\|?([^|}]*)\|?([^}]*)}{([^}]*)}/g.exec(inputString)){
|
|
85
|
+
coloredContent.push(matches[0]);
|
|
86
|
+
}
|
|
87
|
+
return inputString.replace(/[{}[\]()=>]|keyof|typeof|true|false/g, (match)=>{
|
|
88
|
+
if (coloredContent.some((content)=>content.includes(match))) {
|
|
89
|
+
return match;
|
|
90
|
+
}
|
|
91
|
+
return `\\color{#569cd6}{${match}}`;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function isFunctionTypeProperty(member) {
|
|
95
|
+
if (member.type) {
|
|
96
|
+
if (isUnionTypeNode(member.type)) {
|
|
97
|
+
for (const typeNode of member.type.types){
|
|
98
|
+
if (isFunctionTypeNode(typeNode)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
return isFunctionTypeNode(member.type);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
function replaceText(str) {
|
|
109
|
+
return replacePairedSymbols(str)?.replace(/^\s*\|\s*|\s*\|\s*$/gm, '').replace(/\n/g, '<br/>').replace(/\*/g, '\\*').replace(/\|/g, '\\|').replace(/(['"])((?:(?!\1).)*)\1/g, '\\color{#ce9178}{$1$2$1}');
|
|
110
|
+
}
|
|
111
|
+
function getBaseInterfaces(interfaceNode) {
|
|
112
|
+
const baseInterfaces = [];
|
|
113
|
+
if (interfaceNode.heritageClauses) {
|
|
114
|
+
for (const clause of interfaceNode.heritageClauses){
|
|
115
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
116
|
+
for (const typeNode of clause.types){
|
|
117
|
+
baseInterfaces.push(typeNode.getText());
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return baseInterfaces;
|
|
123
|
+
}
|
|
124
|
+
function getComment(comment) {
|
|
125
|
+
if (!comment) return null;
|
|
126
|
+
return comment.replace(/^@[a-z].+/gm, '').replace(/(\n\s+)+/g, '<br />').replace(/\n/g, '<br />').replace(/(<br \/>)$/g, '');
|
|
127
|
+
}
|
|
128
|
+
function getMethodText(member) {
|
|
129
|
+
if (isMethodSignature(member)) {
|
|
130
|
+
return `(${member.parameters.map((param)=>`${param.name.getText()}: ${param.type?.getText() || 'any'}`).join(', ')}): ${member.type?.getText() || 'any'}`;
|
|
131
|
+
}
|
|
132
|
+
return member.type?.getText() || 'any';
|
|
133
|
+
}
|
|
134
|
+
function generateInterfaceDocumentation(node) {
|
|
135
|
+
const typeName = node.name.text;
|
|
136
|
+
Object.assign(allType, {
|
|
137
|
+
[node.name.text]: dirname(node.getSourceFile().fileName).replace(CONFIG.alias['@pkg'], '')
|
|
138
|
+
});
|
|
139
|
+
const baseComment = getPropertyComment(node);
|
|
140
|
+
const vers = getVersionFromComment(baseComment);
|
|
141
|
+
const title = getComment(baseComment);
|
|
142
|
+
const ignore = getIgnore(baseComment)?.split('|') || [];
|
|
143
|
+
const ignoreComment = ignore.includes('comment');
|
|
144
|
+
const ignoreInitial = ignore.includes('initial');
|
|
145
|
+
const ignoreOptional = ignore.includes('optional');
|
|
146
|
+
const ignoreVersion = ignore.includes('version');
|
|
147
|
+
const ignoreAuthor = ignore.includes('author');
|
|
148
|
+
const subTitle = title ? `\\color{|4||0.45}{${typeName}}` : typeName;
|
|
149
|
+
const baseInterfaces = getBaseInterfaces(node)?.map((s)=>{
|
|
150
|
+
return `<n-tag color="#4c81db" css=".tag{gap:0px;}">${getTypeText(replaceText(s))}</n-tag>`;
|
|
151
|
+
});
|
|
152
|
+
const heading = [
|
|
153
|
+
title,
|
|
154
|
+
subTitle,
|
|
155
|
+
vers && `\\color{#52c11b|1||0.9}{${vers}}`,
|
|
156
|
+
baseInterfaces.length > 0 && `<sub>\`extends\`</sub> ${baseInterfaces.join(' ')}`
|
|
157
|
+
].filter(Boolean).join(' ');
|
|
158
|
+
let markdownContent = `## ${heading}`;
|
|
159
|
+
const members = node.members.filter(// 排除 never
|
|
160
|
+
(m)=>isPropertySignature(m) && m.type?.kind !== SyntaxKind.NeverKeyword || isMethodSignature(m));
|
|
161
|
+
const rowsData = [];
|
|
162
|
+
if (members.length) {
|
|
163
|
+
members.forEach((member)=>{
|
|
164
|
+
const type = getTypeText(replaceText(getMethodText(member)), true);
|
|
165
|
+
const propertyComment = getPropertyComment(member);
|
|
166
|
+
let name = replaceText(member.name.getText());
|
|
167
|
+
if (name && !name.startsWith('\\color')) {
|
|
168
|
+
if (isMethodSignature(member) || isFunctionTypeProperty(member) || type?.includes('=>')) {
|
|
169
|
+
name = `\\color{#f9a913}{${name}}`;
|
|
170
|
+
} else if (!/^["'](.+)["']$/.test(name)) {
|
|
171
|
+
name = `\\color{#4c81db}{${name}}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const isOptional = member.questionToken && isQuestionToken(member.questionToken);
|
|
175
|
+
rowsData.push([
|
|
176
|
+
name,
|
|
177
|
+
!ignoreOptional && `\\color{${isOptional ? '#f9a913' : '#52c11b'}\\|\\|\\|0.9}{${isOptional ? '✘' : '✔'}}`,
|
|
178
|
+
!ignoreComment && replaceText(getComment(propertyComment)),
|
|
179
|
+
type,
|
|
180
|
+
!ignoreInitial && replaceText(getDefaultValueFromComment(propertyComment)),
|
|
181
|
+
!ignoreVersion && replaceText(getVersionFromComment(propertyComment)),
|
|
182
|
+
!ignoreAuthor && (getAuthor(propertyComment) || getAuthor(baseComment))
|
|
183
|
+
]);
|
|
184
|
+
});
|
|
185
|
+
let hasAuthor = false, hasVersion = false, hasInitial = false, hasComment = false;
|
|
186
|
+
rowsData.forEach((row)=>{
|
|
187
|
+
if (!ignoreComment && row[2]) {
|
|
188
|
+
hasComment = true;
|
|
189
|
+
}
|
|
190
|
+
if (!ignoreInitial && row[4]) {
|
|
191
|
+
hasInitial = true;
|
|
192
|
+
}
|
|
193
|
+
if (!ignoreVersion && row[5]) {
|
|
194
|
+
hasVersion = true;
|
|
195
|
+
}
|
|
196
|
+
if (!ignoreAuthor && row[6]) {
|
|
197
|
+
hasAuthor = true;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
markdownContent += '\n';
|
|
201
|
+
const cols = [
|
|
202
|
+
'属性',
|
|
203
|
+
!ignoreOptional && '必要',
|
|
204
|
+
hasComment && '说明',
|
|
205
|
+
'类型',
|
|
206
|
+
hasInitial && '默认值',
|
|
207
|
+
hasVersion && '版本',
|
|
208
|
+
hasAuthor && '作者'
|
|
209
|
+
].filter(Boolean).join('|');
|
|
210
|
+
markdownContent += `|${cols}|`;
|
|
211
|
+
const algins = [
|
|
212
|
+
':-',
|
|
213
|
+
!ignoreOptional && ':-',
|
|
214
|
+
hasComment && ':-',
|
|
215
|
+
':-',
|
|
216
|
+
hasInitial && ':-',
|
|
217
|
+
hasVersion && ':-',
|
|
218
|
+
hasAuthor && ':-'
|
|
219
|
+
].filter(Boolean);
|
|
220
|
+
markdownContent += '\n';
|
|
221
|
+
const alignStr = algins.join('|');
|
|
222
|
+
markdownContent += `|${alignStr}|`;
|
|
223
|
+
rowsData.forEach((row)=>{
|
|
224
|
+
markdownContent += '\n';
|
|
225
|
+
const rowStr = [
|
|
226
|
+
row[0] || '-',
|
|
227
|
+
!ignoreOptional && (row[1] || '-'),
|
|
228
|
+
hasComment && (row[2] || '-'),
|
|
229
|
+
row[3] || '-',
|
|
230
|
+
hasInitial && (row[4] || '-'),
|
|
231
|
+
hasVersion && (row[5] || '-'),
|
|
232
|
+
hasAuthor && (row[6] || '-')
|
|
233
|
+
].filter(Boolean).join('|');
|
|
234
|
+
markdownContent += `|${rowStr}|`;
|
|
235
|
+
});
|
|
236
|
+
markdownContent += '\n';
|
|
237
|
+
}
|
|
238
|
+
markdownContent += '\n';
|
|
239
|
+
return markdownContent;
|
|
240
|
+
}
|
|
241
|
+
function generateEnumDocumentation(node) {
|
|
242
|
+
const enumName = node.name.text;
|
|
243
|
+
const baseComment = getPropertyComment(node);
|
|
244
|
+
const title = getComment(baseComment);
|
|
245
|
+
const vers = getVersionFromComment(baseComment);
|
|
246
|
+
Object.assign(allType, {
|
|
247
|
+
[node.name.text]: dirname(node.getSourceFile().fileName).replace(CONFIG.alias['@pkg'], '')
|
|
248
|
+
});
|
|
249
|
+
const subTitle = title ? `\\color{|4||0.45}{${enumName}}` : enumName;
|
|
250
|
+
const heading = [
|
|
251
|
+
title,
|
|
252
|
+
subTitle,
|
|
253
|
+
vers && `\\color{#52c11b|1||0.9}{${vers}}`
|
|
254
|
+
].filter(Boolean).join(' ');
|
|
255
|
+
const ignore = getIgnore(baseComment)?.split('|') || [];
|
|
256
|
+
const ignoreComment = ignore.includes('comment');
|
|
257
|
+
const ignoreVersion = ignore.includes('version');
|
|
258
|
+
const ignoreAuthor = ignore.includes('author');
|
|
259
|
+
let markdownContent = `## ${heading}`;
|
|
260
|
+
if (node.members.length) {
|
|
261
|
+
const rowsData = [];
|
|
262
|
+
node.members.forEach((member)=>{
|
|
263
|
+
let name = replaceText(member.name.getText());
|
|
264
|
+
const memberComment = getPropertyComment(member);
|
|
265
|
+
const value = replaceText(getMemberValue(member));
|
|
266
|
+
const version = replaceText(getVersionFromComment(memberComment));
|
|
267
|
+
const comment = replaceText(getComment(memberComment));
|
|
268
|
+
// markdownContent += '\n';
|
|
269
|
+
if (name && !name.startsWith('\\color') && !/^["'](.+)["']$/.test(name)) {
|
|
270
|
+
name = `\\color{#4c81db}{${name}}`;
|
|
271
|
+
}
|
|
272
|
+
rowsData.push([
|
|
273
|
+
name,
|
|
274
|
+
!ignoreComment && comment,
|
|
275
|
+
value,
|
|
276
|
+
!ignoreVersion && version,
|
|
277
|
+
!ignoreAuthor && (getAuthor(memberComment) || getAuthor(baseComment))
|
|
278
|
+
]);
|
|
279
|
+
// markdownContent += `| ${name} | ${comment} | ${value} | ${version} |`;
|
|
280
|
+
});
|
|
281
|
+
let hasAuthor = false, hasVersion = false, hasComment = false;
|
|
282
|
+
rowsData.forEach((row)=>{
|
|
283
|
+
if (!ignoreComment && row[1]) {
|
|
284
|
+
hasComment = true;
|
|
285
|
+
}
|
|
286
|
+
if (!ignoreVersion && row[3]) {
|
|
287
|
+
hasVersion = true;
|
|
288
|
+
}
|
|
289
|
+
if (!ignoreAuthor && row[4]) {
|
|
290
|
+
hasAuthor = true;
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
markdownContent += '\n';
|
|
294
|
+
const cols = [
|
|
295
|
+
'属性',
|
|
296
|
+
hasComment && '说明',
|
|
297
|
+
'值',
|
|
298
|
+
hasVersion && '版本',
|
|
299
|
+
hasAuthor && '作者'
|
|
300
|
+
].filter(Boolean).join('|');
|
|
301
|
+
markdownContent += `|${cols}|`;
|
|
302
|
+
const algins = [
|
|
303
|
+
':-',
|
|
304
|
+
hasComment && ':-',
|
|
305
|
+
':-',
|
|
306
|
+
hasVersion && ':-',
|
|
307
|
+
hasAuthor && ':-'
|
|
308
|
+
].filter(Boolean);
|
|
309
|
+
markdownContent += '\n';
|
|
310
|
+
const alignStr = algins.join('|');
|
|
311
|
+
markdownContent += `|${alignStr}|`;
|
|
312
|
+
rowsData.forEach((row)=>{
|
|
313
|
+
markdownContent += '\n';
|
|
314
|
+
const rowStr = [
|
|
315
|
+
row[0] || '-',
|
|
316
|
+
hasComment && (row[1] || '-'),
|
|
317
|
+
row[2] || '-',
|
|
318
|
+
hasVersion && (row[3] || '-'),
|
|
319
|
+
hasAuthor && (row[4] || '-')
|
|
320
|
+
].filter(Boolean).join('|');
|
|
321
|
+
markdownContent += `|${rowStr}|`;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
markdownContent += '\n';
|
|
325
|
+
markdownContent += '\n';
|
|
326
|
+
return markdownContent;
|
|
327
|
+
}
|
|
328
|
+
export default function generateApi(path, call) {
|
|
329
|
+
readFile(path, {
|
|
330
|
+
encoding: 'utf-8'
|
|
331
|
+
}, (err, content)=>{
|
|
332
|
+
if (!err) {
|
|
333
|
+
const sourceFile = createSourceFile(path, content, ScriptTarget.Latest, true, ScriptKind.TS);
|
|
334
|
+
let markdownDocumentation = '';
|
|
335
|
+
forEachChild(sourceFile, (node)=>{
|
|
336
|
+
if (isInterfaceDeclaration(node)) {
|
|
337
|
+
markdownDocumentation += generateInterfaceDocumentation(node);
|
|
338
|
+
} else if (ts.isEnumDeclaration(node)) {
|
|
339
|
+
markdownDocumentation += generateEnumDocumentation(node);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
call(markdownDocumentation);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
package/lib/has-pkg.js
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
import{accessSync
|
|
1
|
+
import { accessSync, constants } from 'fs';
|
|
2
|
+
import paths from './paths.js';
|
|
3
|
+
export function hasPkg(name) {
|
|
4
|
+
let flag;
|
|
5
|
+
try {
|
|
6
|
+
accessSync(`${paths.programPath}/node_modules/${name}/package.json`, constants.R_OK);
|
|
7
|
+
flag = true;
|
|
8
|
+
} catch (error) {
|
|
9
|
+
flag = false;
|
|
10
|
+
}
|
|
11
|
+
return flag;
|
|
12
|
+
}
|