diff --git a/.vscode/settings.json b/.vscode/settings.json index 24d0bfd..e5704a1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,5 +17,5 @@ "source.organizeImports.biome": "explicit" }, "conventionalCommits.scopes": ["arguments-builder", "sgmoudle-tools"], - "cSpell.words": ["iringo", "modkit", "rsbuild"] + "cSpell.words": ["iringo", "MITM", "modkit", "rsbuild"] } diff --git a/packages/modkit/core/src/cli.ts b/packages/modkit/core/src/cli.ts index f8bc5d4..af9942f 100644 --- a/packages/modkit/core/src/cli.ts +++ b/packages/modkit/core/src/cli.ts @@ -15,6 +15,8 @@ import minimist from 'minimist'; import { useRsbuild } from './rsbuild'; export async function initCommand() { + logger.greet(` ModKit v${process.env.MODKIT_VERSION}\n`); + // 清空插件管理器中的插件 manager.clear(); diff --git a/packages/modkit/core/src/exports-plugins/loon.ts b/packages/modkit/core/src/exports-plugins/loon.ts index 2657f4a..55fa2e5 100644 --- a/packages/modkit/core/src/exports-plugins/loon.ts +++ b/packages/modkit/core/src/exports-plugins/loon.ts @@ -1 +1,2 @@ export * from '@iringo/modkit-plugin-loon'; +export type * from '@iringo/modkit-plugin-loon/types'; diff --git a/packages/modkit/plugins/loon/package.json b/packages/modkit/plugins/loon/package.json index e6ca32b..cdb69eb 100644 --- a/packages/modkit/plugins/loon/package.json +++ b/packages/modkit/plugins/loon/package.json @@ -9,7 +9,7 @@ "dev": "modern build -w", "build": "modern build" }, - "files": ["dist", "CHANGELOG.md"], + "files": ["dist", "types", "CHANGELOG.md"], "dependencies": { "@iringo/modkit-shared": "workspace:^" }, diff --git a/packages/modkit/plugins/loon/src/index.ts b/packages/modkit/plugins/loon/src/index.ts index 06a091b..5f2eba0 100644 --- a/packages/modkit/plugins/loon/src/index.ts +++ b/packages/modkit/plugins/loon/src/index.ts @@ -1,10 +1,29 @@ import type { ModkitPlugin } from '@iringo/modkit-shared'; +export type LoonArgumentType = 'input' | 'select' | 'switch' | 'exclude'; + export const pluginLoon = (): ModkitPlugin => { return { name: 'loon', setup() { - return {}; + return { + configurePlatform() { + return { + extension: '.plugin', + template: process.env.TEMP || '', + }; + }, + modifySource({ source }) { + source ??= {}; + source.arguments = source.arguments?.filter((item) => { + if (typeof item.type === 'object' && item.type.loon === 'exclude') { + return false; + } + return true; + }); + return source; + }, + }; }, }; }; diff --git a/packages/modkit/plugins/loon/src/template.ts b/packages/modkit/plugins/loon/src/template.ts new file mode 100644 index 0000000..d0611b0 --- /dev/null +++ b/packages/modkit/plugins/loon/src/template.ts @@ -0,0 +1,136 @@ +import { Template, logger } from '@iringo/modkit-shared'; +import type { LoonArgumentType } from './index'; + +export class LoonTemplate extends Template { + get General() { + return this.renderKeyValuePairs(this.content.loonGeneral).trim(); + } + + get Rule() { + return this.content.rule + ?.map((rule) => { + if (typeof rule === 'string') { + return rule; + } + switch (rule.type) { + case 'RULE-SET': { + let result = `RULE-SET, ${this.utils.getFilePath(rule.assetKey)}`; + if (rule.policyName) { + result += `, ${rule.policyName}`; + } + return result; + } + default: + break; + } + }) + .join('\n') + .trim(); + } + + get Argument() { + return this.source.arguments + ?.map((arg) => { + let result = arg.key; + let type: LoonArgumentType = 'input'; + if (arg.type === 'boolean') { + type = 'switch'; + } else if (arg.options && arg.type !== 'array') { + // 只有在有选项且不是数组类型时才使用 select + type = 'select'; + } + result += ` = ${type}`; + result += `,${this.#getDefaultValue(arg.defaultValue)}`; + if (arg.options && type === 'select') { + result += ','; + result += arg.options + .filter((item) => item.key !== arg.defaultValue) + .map((option) => `${this.#getDefaultValue(option.key)}`) + .join(','); + } + if (arg.name) { + result += `,tag=${arg.name}`; + } + if (arg.description) { + result += `,desc=${arg.description}`; + } + return result; + }) + .join('\n') + .trim(); + } + + get Script() { + return this.content.script?.map((script, index) => { + let line = ''; + switch (script.type) { + case 'http-request': + case 'http-response': + line += `${script.type} ${script.pattern},`; + break; + case 'cron': + line += `${script.type} "${script.cronexp}",`; + break; + case 'generic': + line += `${script.type} `; + break; + // case 'network-changed': + case 'event': + line += 'network-changed '; + break; + case 'dns': + logger.warn('[Loon] Unsupported script type: dns'); + break; + } + line += `script-path=${this.utils.getScriptPath(script.scriptKey)},`; + line += this.objectEntries(script) + .map(([key, value]) => { + switch (key) { + case 'name': + return `tag = ${value || `Script${index}`}`; + case 'argument': + return `argument = ${value}`; + case 'injectArgument': { + if (!script.argument && value) { + return `argument = [${this.source.arguments?.map((item) => `{${item.key}}`).join(',')}]`; + } + return ''; + } + case 'type': + case 'pattern': + case 'cronexp': + case 'scriptKey': + return ''; + + default: + return `${key} = ${value}`; + } + }) + .filter(Boolean) + .join(',') + .trim(); + return line; + }); + } + + get MITM() { + return this.content.mitm?.hostname?.join(', '); + } + + #getDefaultValue(defaultValue: any): any { + switch (typeof defaultValue) { + case 'string': + return `"${defaultValue}"`; + case 'number': + case 'boolean': + return defaultValue; + case 'object': + if (Array.isArray(defaultValue) && defaultValue.length > 0) { + return this.#getDefaultValue(defaultValue[0]); + } + return '""'; + default: + return '""'; + } + } +} diff --git a/packages/modkit/plugins/loon/tsconfig.json b/packages/modkit/plugins/loon/tsconfig.json index a51e458..236d32c 100644 --- a/packages/modkit/plugins/loon/tsconfig.json +++ b/packages/modkit/plugins/loon/tsconfig.json @@ -4,5 +4,5 @@ "outDir": "./dist", "baseUrl": "./" }, - "include": ["src"] + "include": ["src", "types"] } diff --git a/packages/modkit/plugins/loon/types/index.d.ts b/packages/modkit/plugins/loon/types/index.d.ts new file mode 100644 index 0000000..b4cdfc2 --- /dev/null +++ b/packages/modkit/plugins/loon/types/index.d.ts @@ -0,0 +1,12 @@ +import '@iringo/modkit-shared'; +import type { LoonArgumentType } from '../dist/index'; + +declare module '@iringo/modkit-shared' { + interface PluginModuleContent { + loonGeneral?: Record; + } + + interface PluginArgumentType { + loon?: LoonArgumentType; + } +} diff --git a/packages/modkit/plugins/surge/src/index.ts b/packages/modkit/plugins/surge/src/index.ts index 14ebcff..f696e04 100644 --- a/packages/modkit/plugins/surge/src/index.ts +++ b/packages/modkit/plugins/surge/src/index.ts @@ -36,7 +36,7 @@ export const pluginSurge = (): ModkitPlugin => { onAfterStartDevServer({ rsbuildServer }) { const moduleRemoteUrl = `http://${appContext.ip}:${rsbuildServer.port}/${moduleName}.sgmodule`; qrcode.generate(`surge:///install-module?url=${encodeURIComponent(moduleRemoteUrl)}`, { small: true }); - api.logger.ready('Scan the QR code to install the module, or manually import:', moduleRemoteUrl); + api.logger.ready('[Surge] Scan the QR code to install the module, or manually import:', moduleRemoteUrl); }, }; }, diff --git a/packages/modkit/plugins/surge/src/template.ts b/packages/modkit/plugins/surge/src/template.ts index 1e14d9d..5d7dad0 100644 --- a/packages/modkit/plugins/surge/src/template.ts +++ b/packages/modkit/plugins/surge/src/template.ts @@ -2,7 +2,7 @@ import { Template } from '@iringo/modkit-shared'; export class SurgeTemplate extends Template { get General() { - return this.renderKeyValuePairs(this.content.general).trim(); + return this.renderKeyValuePairs(this.content.surgeGeneral).trim(); } get Host() { diff --git a/packages/modkit/plugins/surge/types/index.d.ts b/packages/modkit/plugins/surge/types/index.d.ts index aa0c43a..5ddc8fc 100644 --- a/packages/modkit/plugins/surge/types/index.d.ts +++ b/packages/modkit/plugins/surge/types/index.d.ts @@ -2,16 +2,12 @@ import '@iringo/modkit-shared'; declare module '@iringo/modkit-shared' { interface PluginModuleContent { - general?: Record; + surgeGeneral?: Record; host?: Record; - mitm?: { - hostname?: string[]; - clientSourceAddress?: string[]; - }; - urlRewrite?: string[]; - headerRewrite?: string[]; - bodyRewrite?: string[]; - mapLocal?: string[]; + } + + interface PluginModuleMITM { + clientSourceAddress?: string[]; } interface PluginArgumentType { diff --git a/packages/modkit/shared/src/config/types.ts b/packages/modkit/shared/src/config/types.ts deleted file mode 100644 index e7d4f24..0000000 --- a/packages/modkit/shared/src/config/types.ts +++ /dev/null @@ -1,134 +0,0 @@ -// @ts-nocheck -/** - * @deprecated 迁移至 ../types - */ -import type { RsbuildConfig } from '@rsbuild/core'; -import type { PluginAPI } from '../plugin/manager'; -import type { PluginModuleContent } from '../types'; - -// 三合一写法(建议用这个,因为只有surge区分Url Header Body) -// 有type没mode: BodyRewrite -// 有mode没type: UrlRewrite -// 有type有mode: HeaderRewrite -// mode是'header' | 302 | 'reject': UrlRewrite -// mode是'header-add' | 'header-del' | 'header-replace-regex': HeaderRewrite -// 没mode: BodyRewrite -export interface Rewrite { - type?: 'http-request' | 'http-response'; - pattern: string; - mode?: 'header' | 302 | 'reject' | 'header-add' | 'header-del' | 'header-replace-regex'; - content: string | Record; -} - -// 按Surge三种Rewrite分开的写法 -export interface UrlRewrite { - pattern: string; - content: string; - mode: 'header' | 302 | 'reject'; -} -export interface HeaderRewrite { - type: 'http-request' | 'http-response'; - pattern: string; - mode: 'header-add' | 'header-del' | 'header-replace-regex'; - content: string | Record; -} -export interface BodyRewrite { - type: 'http-request' | 'http-response'; - pattern: string; - content: Record; -} - -// 建议叫Mock而不是MapLocal,因为Mock是功能名 -export interface Mock { - pattern: string; - dataType: 'file' | 'text' | 'tiny-gif' | 'base64'; - data?: string | FileKey; - statusCode?: number; - headers?: Record; -} - -export interface ModuleContent extends PluginModuleContent { - script?: Script[]; - rule?: Rule[]; -} - -export interface ModkitConfig { - source?: { - /** - * 模块名称 - */ - moduleName?: string; - /** - * 模块元数据 - */ - metadata?: ModuleMetadata; - /** - * 模块参数 - */ - arguments?: ArgumentItem[]; - /** - * 模块内容 - */ - content?: ModuleContent; - /** - * 待编译的脚本 - */ - scripts?: Record; - /** - * 复制到产物的静态资源,key 为文件名,value 为文件路径 - */ - assets?: Record; - }; - dev?: { - /** - * @default 3000 - */ - port?: number; - }; - output?: { - distPath?: { - /** - * 输出目录 - * @default dist - */ - root?: string; - /** - * js 文件的输出目录 - * @default 'scripts' - */ - js?: string; - /** - * 文件的输出目录 - * @default 'static' - */ - assets?: string; - }; - /** - * 静态资源的 URL 前缀 - */ - assetPrefix?: string; - }; - tools?: { - bundlerChain?: NonNullable['bundlerChain']; - /** - * 选项用于修改 Rspack 的配置项 - * @link https://rsbuild.dev/zh/config/tools/rspack - */ - rspack?: NonNullable['rspack']; - /** - * 设置 [builtin:swc-loader](https://rspack.dev/guide/features/builtin-swc-loader) 的选项 - */ - swc?: NonNullable['swc']; - }; - - plugins?: ModkitPlugin[]; -} - -export interface ModkitPlugin { - /** - * 插件名称 - */ - name: string; - - setup: (api: PluginAPI) => PluginHooks; -} diff --git a/packages/modkit/shared/src/plugin/template.ts b/packages/modkit/shared/src/plugin/template.ts index b9e4d14..bee4b7d 100644 --- a/packages/modkit/shared/src/plugin/template.ts +++ b/packages/modkit/shared/src/plugin/template.ts @@ -32,4 +32,8 @@ export class Template { renderLines(lines?: string[]) { return (lines || []).join('\n'); } + + objectEntries>(obj: T): [keyof T, T[keyof T]][] { + return Object.entries(obj); + } } diff --git a/packages/modkit/shared/src/types/source/index.ts b/packages/modkit/shared/src/types/source/index.ts index 268dcb0..c2074cd 100644 --- a/packages/modkit/shared/src/types/source/index.ts +++ b/packages/modkit/shared/src/types/source/index.ts @@ -1,5 +1,6 @@ import type { ArgumentItem } from './argument'; import type { ModuleMetadata } from './metadata'; +import type { ModuleMITM } from './mitm'; import type { ModuleMock } from './mock'; import type { ModuleRewrite } from './rewrite'; import type { ModuleRule } from './rule'; @@ -14,6 +15,7 @@ export interface ModuleContent extends PluginModuleContent { rule?: ModuleRule[]; rewrite?: ModuleRewrite[]; mock?: ModuleMock[]; + mitm?: ModuleMITM; } export interface SourceConfig { @@ -45,6 +47,7 @@ export interface SourceConfig { export type * from './argument'; export type * from './metadata'; +export type * from './mitm'; export type * from './mock'; export type * from './rewrite'; export type * from './rule'; diff --git a/packages/modkit/shared/src/types/source/mitm.ts b/packages/modkit/shared/src/types/source/mitm.ts new file mode 100644 index 0000000..6e4a89d --- /dev/null +++ b/packages/modkit/shared/src/types/source/mitm.ts @@ -0,0 +1,7 @@ +export interface PluginModuleMITM { + [key: string]: any; +} + +export interface ModuleMITM extends PluginModuleMITM { + hostname?: string[]; +} diff --git a/packages/modkit/tests/modkit.config.ts b/packages/modkit/tests/modkit.config.ts index 2a66720..fd7df34 100644 --- a/packages/modkit/tests/modkit.config.ts +++ b/packages/modkit/tests/modkit.config.ts @@ -151,7 +151,7 @@ export default defineConfig({ scripts: { response: './src/index.ts', }, - ruleSets: { + assets: { 'rule-set.list': './src/rule.list', }, },