├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── LICENSE
├── README.md
├── auto-imports.d.ts
├── build
└── postBuildPlugin.ts
├── docs
└── img1.png
├── index.html
├── logo.psd
├── package.json
├── pnpm-lock.yaml
├── public
├── logo.png
├── plugin.json
└── preload.js
├── src
├── App.vue
├── common
│ ├── directives.ts
│ ├── icons
│ │ ├── attachment.svg
│ │ ├── command.svg
│ │ ├── crosshairs-gps.svg
│ │ ├── image.svg
│ │ ├── index.ts
│ │ ├── infinity.svg
│ │ └── window.svg
│ ├── monaco
│ │ ├── addActions.ts
│ │ ├── index.ts
│ │ └── types
│ │ │ ├── electron.d.ts
│ │ │ ├── node.api.d.ts
│ │ │ └── utools.api.d.ts
│ ├── registerCallback.ts
│ ├── registerIcon.ts
│ └── symbol.ts
├── components
│ ├── CodeList.vue
│ ├── Console.vue
│ ├── Editor.vue
│ ├── SettingContent.vue
│ └── ShortCut.vue
├── hooks
│ ├── useEventBus.ts
│ ├── useEventListener.ts
│ ├── useMedia.ts
│ ├── usePageBack.ts
│ └── usePrefersTheme.ts
├── main.ts
├── preload
│ └── index.ts
├── router
│ └── index.ts
├── store
│ ├── index.ts
│ ├── useCodeStore.ts
│ ├── useHistoryStore.ts
│ ├── useScriptStore.ts
│ └── useSettingStore.ts
├── style
│ ├── border.less
│ ├── index.less
│ ├── scrollbar.less
│ └── transition.less
├── utils
│ ├── business.ts
│ ├── env.ts
│ ├── index.ts
│ ├── storage.ts
│ ├── tools.ts
│ └── utools.ts
├── views
│ ├── About.vue
│ ├── Runner.vue
│ └── Setting.vue
└── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | workflow_dispatch:
8 |
9 | jobs:
10 | BuildProject:
11 | name: Build
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Use Node.js
16 | uses: actions/setup-node@v1
17 | with:
18 | node-version: '18'
19 | - name: Install pnpm
20 | uses: pnpm/action-setup@v2.2.2
21 | id: pnpm-install
22 | with:
23 | version: 8
24 | run_install: false
25 | - name: Install dependencies
26 | run: pnpm install
27 | - name: Build
28 | run: pnpm run build
29 | - name: Deploy Github Pages
30 | uses: JamesIves/github-pages-deploy-action@releases/v4
31 | with:
32 | folder: ./dist
33 | branch: gh-pages
34 | ssh-key: ${{ secrets.DEPLOY_SSH_PRIVATE_KEY }}
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /node_modules
3 | **/.DS_Store
4 |
5 | components.d.ts
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSRunner
2 |
3 | [⭐️ 主页 | WebSite](https://ziuchen.github.io/project/JSRunner/)
4 | [🕶️ 在线体验 | Online](https://ziuchen.github.io/JSRunner/)
5 | [🚚 更新日志 | Changelog](https://ziuchen.github.io/project/JSRunner/log/)
6 |
7 | - ✅ Run JavaScript code to quickly verify code logic
8 | - ✅ Support switching NodeJS/browser operating environment
9 | - ✅ `Ctrl/Command+R` Quickly run code
10 | - ✅ `Ctrl/Command+Q` Clear the console
11 | - ✅ `Ctrl/Command+N` Create new code snippet
12 | - ✅ `Ctrl/Command+E` Toggle Lock status
13 | - ✅ `Ctrl/Command+Shift+P` Call Command Palette
14 | - ✅ `Ctrl/Command+Shift+L` List all history
15 | - ✅ Support backtracking code history. Support saving/editing code running history
16 | - ✅ Support manually triggering code execution/running code in real time
17 | - ✅ Support top-level await. Adapt to dark mode
18 |
19 | 
--------------------------------------------------------------------------------
/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by unplugin-auto-import
5 | export {}
6 | declare global {
7 | const EffectScope: typeof import('vue')['EffectScope']
8 | const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
9 | const computed: typeof import('vue')['computed']
10 | const createApp: typeof import('vue')['createApp']
11 | const createPinia: typeof import('pinia')['createPinia']
12 | const customRef: typeof import('vue')['customRef']
13 | const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
14 | const defineComponent: typeof import('vue')['defineComponent']
15 | const defineStore: typeof import('pinia')['defineStore']
16 | const effectScope: typeof import('vue')['effectScope']
17 | const getActivePinia: typeof import('pinia')['getActivePinia']
18 | const getCurrentInstance: typeof import('vue')['getCurrentInstance']
19 | const getCurrentScope: typeof import('vue')['getCurrentScope']
20 | const h: typeof import('vue')['h']
21 | const inject: typeof import('vue')['inject']
22 | const isProxy: typeof import('vue')['isProxy']
23 | const isReactive: typeof import('vue')['isReactive']
24 | const isReadonly: typeof import('vue')['isReadonly']
25 | const isRef: typeof import('vue')['isRef']
26 | const mapActions: typeof import('pinia')['mapActions']
27 | const mapGetters: typeof import('pinia')['mapGetters']
28 | const mapState: typeof import('pinia')['mapState']
29 | const mapStores: typeof import('pinia')['mapStores']
30 | const mapWritableState: typeof import('pinia')['mapWritableState']
31 | const markRaw: typeof import('vue')['markRaw']
32 | const nextTick: typeof import('vue')['nextTick']
33 | const onActivated: typeof import('vue')['onActivated']
34 | const onBeforeMount: typeof import('vue')['onBeforeMount']
35 | const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
36 | const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
37 | const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
38 | const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
39 | const onDeactivated: typeof import('vue')['onDeactivated']
40 | const onErrorCaptured: typeof import('vue')['onErrorCaptured']
41 | const onMounted: typeof import('vue')['onMounted']
42 | const onRenderTracked: typeof import('vue')['onRenderTracked']
43 | const onRenderTriggered: typeof import('vue')['onRenderTriggered']
44 | const onScopeDispose: typeof import('vue')['onScopeDispose']
45 | const onServerPrefetch: typeof import('vue')['onServerPrefetch']
46 | const onUnmounted: typeof import('vue')['onUnmounted']
47 | const onUpdated: typeof import('vue')['onUpdated']
48 | const provide: typeof import('vue')['provide']
49 | const reactive: typeof import('vue')['reactive']
50 | const readonly: typeof import('vue')['readonly']
51 | const ref: typeof import('vue')['ref']
52 | const resolveComponent: typeof import('vue')['resolveComponent']
53 | const setActivePinia: typeof import('pinia')['setActivePinia']
54 | const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
55 | const shallowReactive: typeof import('vue')['shallowReactive']
56 | const shallowReadonly: typeof import('vue')['shallowReadonly']
57 | const shallowRef: typeof import('vue')['shallowRef']
58 | const storeToRefs: typeof import('pinia')['storeToRefs']
59 | const toRaw: typeof import('vue')['toRaw']
60 | const toRef: typeof import('vue')['toRef']
61 | const toRefs: typeof import('vue')['toRefs']
62 | const triggerRef: typeof import('vue')['triggerRef']
63 | const unref: typeof import('vue')['unref']
64 | const useAttrs: typeof import('vue')['useAttrs']
65 | const useCssModule: typeof import('vue')['useCssModule']
66 | const useCssVars: typeof import('vue')['useCssVars']
67 | const useLink: typeof import('vue-router')['useLink']
68 | const useRoute: typeof import('vue-router')['useRoute']
69 | const useRouter: typeof import('vue-router')['useRouter']
70 | const useSlots: typeof import('vue')['useSlots']
71 | const watch: typeof import('vue')['watch']
72 | const watchEffect: typeof import('vue')['watchEffect']
73 | const watchPostEffect: typeof import('vue')['watchPostEffect']
74 | const watchSyncEffect: typeof import('vue')['watchSyncEffect']
75 | }
76 | // for type re-export
77 | declare global {
78 | // @ts-ignore
79 | export type { Component,ComponentPublicInstance,ComputedRef,InjectionKey,PropType,Ref,VNode } from 'vue'
80 | }
81 |
--------------------------------------------------------------------------------
/build/postBuildPlugin.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import fs from 'fs'
3 | import { Plugin, transformWithEsbuild } from 'vite'
4 | import htmlMinifier from 'html-minifier-terser'
5 |
6 | export interface postBuildPluginOptions {
7 | /**
8 | * 需要处理的文件相对于dist目录的路径
9 | */
10 | files: string[]
11 | }
12 |
13 | /**
14 | * Vite 构建后处理插件
15 | */
16 | export default function postBuildPlugin(options: postBuildPluginOptions): Plugin {
17 | let config = null
18 |
19 | return {
20 | name: 'post-build-plugin',
21 | apply: 'build',
22 |
23 | configResolved(resolvedConfig) {
24 | config = resolvedConfig
25 | },
26 |
27 | // 构建完成后 将构建后的dist目录下的文件进行最小化处理
28 | // *.html *.js *.svg *.json
29 | async closeBundle() {
30 | const files = options.files || ['index.html']
31 | const distDir = config.build.outDir
32 |
33 | for (const file of files) {
34 | const fpath = path.resolve(distDir, file)
35 | const ext = path.extname(fpath)
36 | const execMap = {
37 | '.html': async (code: string) =>
38 | htmlMinifier.minify(code, {
39 | removeComments: true,
40 | collapseWhitespace: true,
41 | collapseBooleanAttributes: true,
42 | removeAttributeQuotes: false,
43 | removeEmptyAttributes: true,
44 | minifyCSS: true,
45 | minifyJS: true,
46 | minifyURLs: true
47 | }),
48 | '.js': async (code: string) => {
49 | const res = await transformWithEsbuild(code, '', {
50 | loader: 'js',
51 | minify: true
52 | })
53 | return res.code
54 | },
55 | '.json': async (code: string) => JSON.stringify(JSON.parse(code))
56 | }
57 |
58 | if (execMap[ext]) {
59 | const code = fs.readFileSync(fpath, 'utf-8')
60 | const codeTransformed = await execMap[ext](code)
61 | fs.writeFileSync(fpath, codeTransformed)
62 | } else {
63 | console.error(`Not Supported File Type: .${ext}`)
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/docs/img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZiuChen/JSRunner/ff9c5cd00a28c01e765e4d7bc7d07a31758b2a0a/docs/img1.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ZiuChen | 超级JavaScript
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZiuChen/JSRunner/ff9c5cd00a28c01e765e4d7bc7d07a31758b2a0a/logo.psd
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "dev": "vite",
4 | "build": "vue-tsc && vite build",
5 | "preview": "vite preview"
6 | },
7 | "dependencies": {
8 | "@arco-design/web-vue": "^2.54.1",
9 | "@vueuse/core": "^10.7.1",
10 | "comment-parser": "^1.4.1",
11 | "lodash-es": "^4.17.21",
12 | "monaco-editor": "^0.37.1",
13 | "pinia": "^2.1.7",
14 | "tiny-emitter": "^2.1.0",
15 | "vue": "^3.4.5",
16 | "vue-router": "^4.2.5"
17 | },
18 | "devDependencies": {
19 | "@types/html-minifier-terser": "^7.0.2",
20 | "@types/lodash-es": "^4.17.12",
21 | "@types/node": "^20.10.6",
22 | "@vitejs/plugin-vue": "^5.0.2",
23 | "html-minifier-terser": "^7.2.0",
24 | "less": "^4.2.0",
25 | "typescript": "^4.9.5",
26 | "unplugin-auto-import": "^0.14.4",
27 | "unplugin-vue-components": "^0.24.1",
28 | "utools-api-types": "^3.0.0",
29 | "vite": "^5.0.10",
30 | "vite-plugin-style-import": "^2.0.0",
31 | "vue-tsc": "^1.8.27"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZiuChen/JSRunner/ff9c5cd00a28c01e765e4d7bc7d07a31758b2a0a/public/logo.png
--------------------------------------------------------------------------------
/public/plugin.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginName": "超级JavaScript",
3 | "description": "JavaScript运行器 支持多种运行环境",
4 | "author": "ZiuChen",
5 | "homepage": "https://github.com/ZiuChen",
6 | "main": "index.html",
7 | "preload": "preload.js",
8 | "development": {
9 | "main": "http://localhost:8084/"
10 | },
11 | "logo": "logo.png",
12 | "platform": ["win32", "darwin", "linux"],
13 | "features": [
14 | {
15 | "code": "超级JavaScript",
16 | "icon": "logo.png",
17 | "explain": "进入 JavaScript 运行器",
18 | "cmds": ["JavaScript Runner", "Super JavaScript", "Run Code", "运行代码", "超级JavaScript"]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/public/preload.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron')
2 | const { Buffer } = require('buffer')
3 | const vm = require('vm')
4 |
5 | window.preload = {
6 | electron,
7 | Buffer,
8 | require,
9 | vm
10 | }
11 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
24 |
--------------------------------------------------------------------------------
/src/common/directives.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 |
3 | export function registerDirectives(app: App) {
4 | // register a directive call v-zoom
5 | // when v-zoom is true, the element scale to 1.2 and quickly back to 1.0
6 | app.directive('zoom', (el, binding) => {
7 | if (binding.value) {
8 | el.style.transform = 'scale(1.6)'
9 | el.style.transition = 'transform 0.2s'
10 | setTimeout(() => {
11 | el.style.transform = 'scale(1.0)'
12 | }, 200)
13 | }
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/src/common/icons/attachment.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/icons/command.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/icons/crosshairs-gps.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/icons/image.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/icons/index.ts:
--------------------------------------------------------------------------------
1 | import attachment from './attachment.svg'
2 | import command from './command.svg'
3 | import crosshairsGps from './crosshairs-gps.svg'
4 | import image from './image.svg'
5 | import infinity from './infinity.svg'
6 | import window from './window.svg'
7 |
8 | // Wrap the icons as Vue components
9 | export const AttachmentIcon = wrapIcon(attachment, 'IconAttachment')
10 | export const CommandIcon = wrapIcon(command, 'IconCommand')
11 | export const CrosshairsGpsIcon = wrapIcon(crosshairsGps, 'IconCrosshairsGps')
12 | export const ImageIcon = wrapIcon(image, 'IconImage')
13 | export const InfinityIcon = wrapIcon(infinity, 'IconInfinity')
14 | export const WindowIcon = wrapIcon(window, 'IconWindow')
15 |
16 | function wrapIcon(svg: string, name: string) {
17 | return () => h(name, [h('svg', { innerHTML: svg })])
18 | }
19 |
--------------------------------------------------------------------------------
/src/common/icons/infinity.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/icons/window.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/common/monaco/addActions.ts:
--------------------------------------------------------------------------------
1 | import type { defineEmits } from 'vue'
2 | import { monaco } from '@/common/monaco'
3 | // @ts-expect-error
4 | import { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput'
5 | import { CodeHistory } from '@/store/useHistoryStore'
6 | import { useCodeStore } from '@/store'
7 |
8 | /**
9 | * 注册自定义菜单项
10 | * 并透传到组件
11 | */
12 | export function addActions(
13 | editor: monaco.editor.IStandaloneCodeEditor,
14 | emit: ReturnType
15 | ) {
16 | // Add a new command, for getting an accessor.
17 | const quickInputCommand = editor.addCommand(0, (accessor, func) => {
18 | // a hacker way to get the input service
19 | const quickInputService = accessor.get(IQuickInputService)
20 | func(quickInputService)
21 | })
22 |
23 | editor.addAction({
24 | id: 'quickInput',
25 | label: 'Quick Input',
26 | contextMenuGroupId: 'buildin-action',
27 | run: (editor, { list, callback, options }) => {
28 | editor.trigger('', quickInputCommand!, (quickInput: any) => {
29 | quickInput.pick(list, options).then((selected?: any) => {
30 | callback(selected)
31 | })
32 | })
33 | }
34 | })
35 |
36 | editor.addAction({
37 | id: 'run', // 菜单项 id
38 | label: 'Run', // 菜单项名称
39 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyR],
40 | contextMenuGroupId: 'buildin-action', // 所属菜单的分组
41 | run: () => emit('action', 'runCode') // 菜单项点击事件
42 | })
43 |
44 | editor.addAction({
45 | id: 'newCode',
46 | label: 'New Code',
47 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyN],
48 | contextMenuGroupId: 'buildin-action',
49 | run: () => emit('action', 'newCode')
50 | })
51 |
52 | editor.addAction({
53 | id: 'clearConsole',
54 | label: 'Clear Console',
55 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyQ],
56 | contextMenuGroupId: 'buildin-action',
57 | run: () => emit('action', 'clearConsole')
58 | })
59 |
60 | editor.addAction({
61 | id: 'toggleReadonly',
62 | label: 'Toggle Readonly',
63 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyE],
64 | contextMenuGroupId: 'buildin-action',
65 | run: () => emit('action', 'toggleReadonly')
66 | })
67 |
68 | editor.addAction({
69 | id: 'showCommands',
70 | label: 'Show Commands',
71 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyP],
72 | contextMenuGroupId: 'buildin-action',
73 | run: () => emit('action', 'showCommands')
74 | })
75 |
76 | editor.addAction({
77 | id: 'listHistory',
78 | label: 'List History',
79 | keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyL],
80 | contextMenuGroupId: 'buildin-action',
81 | run: () => {
82 | emit('action', 'listHistory')
83 | }
84 | })
85 | }
86 |
--------------------------------------------------------------------------------
/src/common/monaco/index.ts:
--------------------------------------------------------------------------------
1 | // accessibilityHelp
2 | import 'monaco-editor/esm/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp'
3 | // anchorSelect
4 | import 'monaco-editor/esm/vs/editor/contrib/anchorSelect/browser/anchorSelect'
5 | // bracketMatching
6 | import 'monaco-editor/esm/vs/editor/contrib/bracketMatching/browser/bracketMatching'
7 | // browser
8 | import 'monaco-editor/esm/vs/editor/browser/coreCommands'
9 | // caretOperations
10 | import 'monaco-editor/esm/vs/editor/contrib/caretOperations/browser/caretOperations'
11 | import 'monaco-editor/esm/vs/editor/contrib/caretOperations/browser/transpose'
12 | // clipboard
13 | import 'monaco-editor/esm/vs/editor/contrib/clipboard/browser/clipboard'
14 | // codeAction
15 | import 'monaco-editor/esm/vs/editor/contrib/codeAction/browser/codeActionContributions'
16 | // codelens
17 | import 'monaco-editor/esm/vs/editor/contrib/codelens/browser/codelensController'
18 | // colorPicker
19 | import 'monaco-editor/esm/vs/editor/contrib/colorPicker/browser/colorContributions'
20 | // comment
21 | import 'monaco-editor/esm/vs/editor/contrib/comment/browser/comment'
22 | // contextmenu
23 | import 'monaco-editor/esm/vs/editor/contrib/contextmenu/browser/contextmenu'
24 | // copyPaste
25 | import 'monaco-editor/esm/vs/editor/contrib/copyPaste/browser/copyPasteContribution'
26 | // cursorUndo
27 | import 'monaco-editor/esm/vs/editor/contrib/cursorUndo/browser/cursorUndo'
28 | // dnd
29 | import 'monaco-editor/esm/vs/editor/contrib/dnd/browser/dnd'
30 | // documentSymbols
31 | import 'monaco-editor/esm/vs/editor/contrib/documentSymbols/browser/documentSymbols'
32 | // dropIntoEditor
33 | import 'monaco-editor/esm/vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution'
34 | // find
35 | import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController'
36 | // folding
37 | import 'monaco-editor/esm/vs/editor/contrib/folding/browser/folding'
38 | // fontZoom
39 | import 'monaco-editor/esm/vs/editor/contrib/fontZoom/browser/fontZoom'
40 | // format
41 | import 'monaco-editor/esm/vs/editor/contrib/format/browser/formatActions'
42 | // gotoError
43 | import 'monaco-editor/esm/vs/editor/contrib/gotoError/browser/gotoError'
44 | // gotoLine
45 | import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess'
46 | // gotoSymbol
47 | import 'monaco-editor/esm/vs/editor/contrib/gotoSymbol/browser/goToCommands'
48 | import 'monaco-editor/esm/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition'
49 | // hover
50 | import 'monaco-editor/esm/vs/editor/contrib/hover/browser/hover'
51 | // iPadShowKeyboard
52 | import 'monaco-editor/esm/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard'
53 | // inPlaceReplace
54 | import 'monaco-editor/esm/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace'
55 | // indentation
56 | import 'monaco-editor/esm/vs/editor/contrib/indentation/browser/indentation'
57 | // inlayHints
58 | import 'monaco-editor/esm/vs/editor/contrib/inlayHints/browser/inlayHintsContribution'
59 | // inlineCompletions
60 | import 'monaco-editor/esm/vs/editor/contrib/inlineCompletions/browser/ghostText.contribution'
61 | // inspectTokens
62 | import 'monaco-editor/esm/vs/editor/standalone/browser/inspectTokens/inspectTokens'
63 | // lineSelection
64 | import 'monaco-editor/esm/vs/editor/contrib/lineSelection/browser/lineSelection'
65 | // linesOperations
66 | import 'monaco-editor/esm/vs/editor/contrib/linesOperations/browser/linesOperations'
67 | // linkedEditing
68 | import 'monaco-editor/esm/vs/editor/contrib/linkedEditing/browser/linkedEditing'
69 | // links
70 | import 'monaco-editor/esm/vs/editor/contrib/links/browser/links'
71 | // longLinesHelper
72 | import 'monaco-editor/esm/vs/editor/contrib/longLinesHelper/browser/longLinesHelper'
73 | // multicursor
74 | import 'monaco-editor/esm/vs/editor/contrib/multicursor/browser/multicursor'
75 | // parameterHints
76 | import 'monaco-editor/esm/vs/editor/contrib/parameterHints/browser/parameterHints'
77 | // quickCommand
78 | import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess'
79 | // quickHelp
80 | import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess'
81 | // quickOutline
82 | import 'monaco-editor/esm/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess'
83 | // readOnlyMessage
84 | import 'monaco-editor/esm/vs/editor/contrib/readOnlyMessage/browser/contribution'
85 | // referenceSearch
86 | import 'monaco-editor/esm/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch'
87 | // rename
88 | import 'monaco-editor/esm/vs/editor/contrib/rename/browser/rename'
89 | // semanticTokens
90 | import 'monaco-editor/esm/vs/editor/contrib/semanticTokens/browser/documentSemanticTokens'
91 | import 'monaco-editor/esm/vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens'
92 | // smartSelect
93 | import 'monaco-editor/esm/vs/editor/contrib/smartSelect/browser/smartSelect'
94 | // snippet
95 | import 'monaco-editor/esm/vs/editor/contrib/snippet/browser/snippetController2'
96 | // stickyScroll
97 | import 'monaco-editor/esm/vs/editor/contrib/stickyScroll/browser/stickyScrollContribution'
98 | // suggest
99 | import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestController'
100 | import 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggestInlineCompletions'
101 | // toggleHighContrast
102 | import 'monaco-editor/esm/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast'
103 | // toggleTabFocusMode
104 | import 'monaco-editor/esm/vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode'
105 | // tokenization
106 | import 'monaco-editor/esm/vs/editor/contrib/tokenization/browser/tokenization'
107 | // unicodeHighlighter
108 | import 'monaco-editor/esm/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter'
109 | // unusualLineTerminators
110 | import 'monaco-editor/esm/vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators'
111 | // wordHighlighter
112 | import 'monaco-editor/esm/vs/editor/contrib/wordHighlighter/browser/wordHighlighter'
113 | // wordOperations
114 | import 'monaco-editor/esm/vs/editor/contrib/wordOperations/browser/wordOperations'
115 | // wordPartOperations
116 | import 'monaco-editor/esm/vs/editor/contrib/wordPartOperations/browser/wordPartOperations'
117 |
118 | import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
119 | import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution'
120 | import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
121 | import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'
122 | import TSWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
123 | import JSONWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
124 | import 'monaco-editor/esm/vs/language/json/monaco.contribution'
125 |
126 | import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
127 |
128 | self.MonacoEnvironment = {
129 | getWorker(_: string, label: string) {
130 | if (label === 'typescript' || label === 'javascript') {
131 | return new TSWorker()
132 | }
133 | if (label === 'json') {
134 | return new JSONWorker()
135 | }
136 | return new EditorWorker()
137 | }
138 | }
139 |
140 | // 导入声明文件
141 | import uToolsApis from './types/utools.api.d.ts?raw'
142 | import NodeApis from './types/node.api.d.ts?raw'
143 | import ElectronApis from './types/electron.d.ts?raw'
144 |
145 | monaco.languages.typescript.javascriptDefaults.addExtraLib(uToolsApis, 'utools.api.d.ts')
146 | monaco.languages.typescript.javascriptDefaults.addExtraLib(NodeApis, 'node.api.d.ts')
147 | monaco.languages.typescript.javascriptDefaults.addExtraLib(ElectronApis, 'electron.api.d.ts')
148 |
149 | monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
150 | noSemanticValidation: true,
151 | noSyntaxValidation: false
152 | })
153 |
154 | monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
155 | target: monaco.languages.typescript.ScriptTarget.ES2016,
156 | allowNonTsExtensions: true,
157 | allowJs: true
158 | })
159 |
160 | export { monaco }
161 |
--------------------------------------------------------------------------------
/src/common/monaco/types/electron.d.ts:
--------------------------------------------------------------------------------
1 | interface Clipboard {
2 |
3 | // Docs: https://electronjs.org/docs/api/clipboard
4 |
5 | /**
6 | * An array of supported formats for the clipboard `type`.
7 | */
8 | availableFormats(type?: 'selection' | 'clipboard'): string[];
9 | /**
10 | * Clears the clipboard content.
11 | */
12 | clear(type?: 'selection' | 'clipboard'): void;
13 | /**
14 | * Whether the clipboard supports the specified `format`.
15 | *
16 | * @experimental
17 | */
18 | has(format: string, type?: 'selection' | 'clipboard'): boolean;
19 | /**
20 | * Reads `format` type from the clipboard.
21 | *
22 | * `format` should contain valid ASCII characters and have `/` separator. `a/c`,
23 | * `a/bc` are valid formats while `/abc`, `abc/`, `a/`, `/a`, `a` are not valid.
24 | *
25 | * @experimental
26 | */
27 | read(format: string): string;
28 | /**
29 | * * `title` string
30 | * * `url` string
31 | *
32 | * Returns an Object containing `title` and `url` keys representing the bookmark in
33 | * the clipboard. The `title` and `url` values will be empty strings when the
34 | * bookmark is unavailable. The `title` value will always be empty on Windows.
35 | *
36 | * @platform darwin,win32
37 | */
38 | readBookmark(): ReadBookmark;
39 | /**
40 | * Reads `format` type from the clipboard.
41 | *
42 | * @experimental
43 | */
44 | readBuffer(format: string): Buffer;
45 | /**
46 | * The text on the find pasteboard, which is the pasteboard that holds information
47 | * about the current state of the active application’s find panel.
48 | *
49 | * This method uses synchronous IPC when called from the renderer process. The
50 | * cached value is reread from the find pasteboard whenever the application is
51 | * activated.
52 | *
53 | * @platform darwin
54 | */
55 | readFindText(): string;
56 | /**
57 | * The content in the clipboard as markup.
58 | */
59 | readHTML(type?: 'selection' | 'clipboard'): string;
60 | /**
61 | * The image content in the clipboard.
62 | */
63 | readImage(type?: 'selection' | 'clipboard'): NativeImage;
64 | /**
65 | * The content in the clipboard as RTF.
66 | */
67 | readRTF(type?: 'selection' | 'clipboard'): string;
68 | /**
69 | * The content in the clipboard as plain text.
70 | */
71 | readText(type?: 'selection' | 'clipboard'): string;
72 | /**
73 | * Writes `data` to the clipboard.
74 | */
75 | write(data: Data, type?: 'selection' | 'clipboard'): void;
76 | /**
77 | * Writes the `title` (macOS only) and `url` into the clipboard as a bookmark.
78 | *
79 | * **Note:** Most apps on Windows don't support pasting bookmarks into them so you
80 | * can use `clipboard.write` to write both a bookmark and fallback text to the
81 | * clipboard.
82 | *
83 | * @platform darwin,win32
84 | */
85 | writeBookmark(title: string, url: string, type?: 'selection' | 'clipboard'): void;
86 | /**
87 | * Writes the `buffer` into the clipboard as `format`.
88 | *
89 | * @experimental
90 | */
91 | writeBuffer(format: string, buffer: Buffer, type?: 'selection' | 'clipboard'): void;
92 | /**
93 | * Writes the `text` into the find pasteboard (the pasteboard that holds
94 | * information about the current state of the active application’s find panel) as
95 | * plain text. This method uses synchronous IPC when called from the renderer
96 | * process.
97 | *
98 | * @platform darwin
99 | */
100 | writeFindText(text: string): void;
101 | /**
102 | * Writes `markup` to the clipboard.
103 | */
104 | writeHTML(markup: string, type?: 'selection' | 'clipboard'): void;
105 | /**
106 | * Writes `image` to the clipboard.
107 | */
108 | writeImage(image: NativeImage, type?: 'selection' | 'clipboard'): void;
109 | /**
110 | * Writes the `text` into the clipboard in RTF.
111 | */
112 | writeRTF(text: string, type?: 'selection' | 'clipboard'): void;
113 | /**
114 | * Writes the `text` into the clipboard as plain text.
115 | */
116 | writeText(text: string, type?: 'selection' | 'clipboard'): void;
117 | }
118 | interface ContextBridge {
119 |
120 | // Docs: https://electronjs.org/docs/api/context-bridge
121 |
122 | exposeInMainWorld(apiKey: string, api: any): void;
123 | }
124 | interface CrashReporter {
125 |
126 | // Docs: https://electronjs.org/docs/api/crash-reporter
127 |
128 | /**
129 | * Set an extra parameter to be sent with the crash report. The values specified
130 | * here will be sent in addition to any values set via the `extra` option when
131 | * `start` was called.
132 | *
133 | * Parameters added in this fashion (or via the `extra` parameter to
134 | * `crashReporter.start`) are specific to the calling process. Adding extra
135 | * parameters in the main process will not cause those parameters to be sent along
136 | * with crashes from renderer or other child processes. Similarly, adding extra
137 | * parameters in a renderer process will not result in those parameters being sent
138 | * with crashes that occur in other renderer processes or in the main process.
139 | *
140 | * **Note:** Parameters have limits on the length of the keys and values. Key names
141 | * must be no longer than 39 bytes, and values must be no longer than 20320 bytes.
142 | * Keys with names longer than the maximum will be silently ignored. Key values
143 | * longer than the maximum length will be truncated.
144 | */
145 | addExtraParameter(key: string, value: string): void;
146 | /**
147 | * The date and ID of the last crash report. Only crash reports that have been
148 | * uploaded will be returned; even if a crash report is present on disk it will not
149 | * be returned until it is uploaded. In the case that there are no uploaded
150 | * reports, `null` is returned.
151 | *
152 | * **Note:** This method is only available in the main process.
153 | */
154 | getLastCrashReport(): CrashReport;
155 | /**
156 | * The current 'extra' parameters of the crash reporter.
157 | */
158 | getParameters(): Record;
159 | /**
160 | * Returns all uploaded crash reports. Each report contains the date and uploaded
161 | * ID.
162 | *
163 | * **Note:** This method is only available in the main process.
164 | */
165 | getUploadedReports(): CrashReport[];
166 | /**
167 | * Whether reports should be submitted to the server. Set through the `start`
168 | * method or `setUploadToServer`.
169 | *
170 | * **Note:** This method is only available in the main process.
171 | */
172 | getUploadToServer(): boolean;
173 | /**
174 | * Remove an extra parameter from the current set of parameters. Future crashes
175 | * will not include this parameter.
176 | */
177 | removeExtraParameter(key: string): void;
178 | /**
179 | * This would normally be controlled by user preferences. This has no effect if
180 | * called before `start` is called.
181 | *
182 | * **Note:** This method is only available in the main process.
183 | */
184 | setUploadToServer(uploadToServer: boolean): void;
185 | /**
186 | * This method must be called before using any other `crashReporter` APIs. Once
187 | * initialized this way, the crashpad handler collects crashes from all
188 | * subsequently created processes. The crash reporter cannot be disabled once
189 | * started.
190 | *
191 | * This method should be called as early as possible in app startup, preferably
192 | * before `app.on('ready')`. If the crash reporter is not initialized at the time a
193 | * renderer process is created, then that renderer process will not be monitored by
194 | * the crash reporter.
195 | *
196 | * **Note:** You can test out the crash reporter by generating a crash using
197 | * `process.crash()`.
198 | *
199 | * **Note:** If you need to send additional/updated `extra` parameters after your
200 | * first call `start` you can call `addExtraParameter`.
201 | *
202 | * **Note:** Parameters passed in `extra`, `globalExtra` or set with
203 | * `addExtraParameter` have limits on the length of the keys and values. Key names
204 | * must be at most 39 bytes long, and values must be no longer than 127 bytes. Keys
205 | * with names longer than the maximum will be silently ignored. Key values longer
206 | * than the maximum length will be truncated.
207 | *
208 | * **Note:** This method is only available in the main process.
209 | */
210 | start(options: CrashReporterStartOptions): void;
211 | }
212 | interface IpcRenderer extends NodeJS.EventEmitter {
213 |
214 | // Docs: https://electronjs.org/docs/api/ipc-renderer
215 |
216 | /**
217 | * Resolves with the response from the main process.
218 | *
219 | * Send a message to the main process via `channel` and expect a result
220 | * asynchronously. Arguments will be serialized with the Structured Clone
221 | * Algorithm, just like `window.postMessage`, so prototype chains will not be
222 | * included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw
223 | * an exception.
224 | *
225 | * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special
226 | * Electron objects will throw an exception.
227 | *
228 | * Since the main process does not have support for DOM objects such as
229 | * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over
230 | * Electron's IPC to the main process, as the main process would have no way to
231 | * decode them. Attempting to send such objects over IPC will result in an error.
232 | *
233 | * The main process should listen for `channel` with `ipcMain.handle()`.
234 | *
235 | * For example:
236 | *
237 | * If you need to transfer a `MessagePort` to the main process, use
238 | * `ipcRenderer.postMessage`.
239 | *
240 | * If you do not need a response to the message, consider using `ipcRenderer.send`.
241 | */
242 | invoke(channel: string, ...args: any[]): Promise;
243 | /**
244 | * Listens to `channel`, when a new message arrives `listener` would be called with
245 | * `listener(event, args...)`.
246 | */
247 | on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this;
248 | /**
249 | * Adds a one time `listener` function for the event. This `listener` is invoked
250 | * only the next time a message is sent to `channel`, after which it is removed.
251 | */
252 | once(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): this;
253 | /**
254 | * Send a message to the main process, optionally transferring ownership of zero or
255 | * more `MessagePort` objects.
256 | *
257 | * The transferred `MessagePort` objects will be available in the main process as
258 | * `MessagePortMain` objects by accessing the `ports` property of the emitted
259 | * event.
260 | *
261 | * For example:
262 | *
263 | * For more information on using `MessagePort` and `MessageChannel`, see the MDN
264 | * documentation.
265 | */
266 | postMessage(channel: string, message: any, transfer?: MessagePort[]): void;
267 | /**
268 | * Removes all listeners, or those of the specified `channel`.
269 | */
270 | removeAllListeners(channel: string): this;
271 | /**
272 | * Removes the specified `listener` from the listener array for the specified
273 | * `channel`.
274 | */
275 | removeListener(channel: string, listener: (...args: any[]) => void): this;
276 | /**
277 | * Send an asynchronous message to the main process via `channel`, along with
278 | * arguments. Arguments will be serialized with the Structured Clone Algorithm,
279 | * just like `window.postMessage`, so prototype chains will not be included.
280 | * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an
281 | * exception.
282 | *
283 | * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special
284 | * Electron objects will throw an exception.
285 | *
286 | * Since the main process does not have support for DOM objects such as
287 | * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over
288 | * Electron's IPC to the main process, as the main process would have no way to
289 | * decode them. Attempting to send such objects over IPC will result in an error.
290 | *
291 | * The main process handles it by listening for `channel` with the `ipcMain`
292 | * module.
293 | *
294 | * If you need to transfer a `MessagePort` to the main process, use
295 | * `ipcRenderer.postMessage`.
296 | *
297 | * If you want to receive a single response from the main process, like the result
298 | * of a method call, consider using `ipcRenderer.invoke`.
299 | */
300 | send(channel: string, ...args: any[]): void;
301 | /**
302 | * The value sent back by the `ipcMain` handler.
303 | *
304 | * Send a message to the main process via `channel` and expect a result
305 | * synchronously. Arguments will be serialized with the Structured Clone Algorithm,
306 | * just like `window.postMessage`, so prototype chains will not be included.
307 | * Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an
308 | * exception.
309 | *
310 | * > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special
311 | * Electron objects will throw an exception.
312 | *
313 | * Since the main process does not have support for DOM objects such as
314 | * `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over
315 | * Electron's IPC to the main process, as the main process would have no way to
316 | * decode them. Attempting to send such objects over IPC will result in an error.
317 | *
318 | * The main process handles it by listening for `channel` with `ipcMain` module,
319 | * and replies by setting `event.returnValue`.
320 | *
321 | * > :warning: **WARNING**: Sending a synchronous message will block the whole
322 | * renderer process until the reply is received, so use this method only as a last
323 | * resort. It's much better to use the asynchronous version, `invoke()`.
324 | */
325 | sendSync(channel: string, ...args: any[]): any;
326 | /**
327 | * Sends a message to a window with `webContentsId` via `channel`.
328 | */
329 | sendTo(webContentsId: number, channel: string, ...args: any[]): void;
330 | /**
331 | * Like `ipcRenderer.send` but the event will be sent to the `` element in
332 | * the host page instead of the main process.
333 | */
334 | sendToHost(channel: string, ...args: any[]): void;
335 | }
336 |
337 | interface IpcRendererEvent extends Event {
338 |
339 | // Docs: https://electronjs.org/docs/api/structures/ipc-renderer-event
340 |
341 | /**
342 | * A list of MessagePorts that were transferred with this message
343 | */
344 | ports: MessagePort[];
345 | /**
346 | * The `IpcRenderer` instance that emitted the event originally
347 | */
348 | sender: IpcRenderer;
349 | /**
350 | * The `webContents.id` that sent the message, you can call
351 | * `event.sender.sendTo(event.senderId, ...)` to reply to the message, see
352 | * ipcRenderer.sendTo for more information. This only applies to messages sent from
353 | * a different renderer. Messages sent directly from the main process set
354 | * `event.senderId` to `0`.
355 | */
356 | senderId: number;
357 | }
358 | class NativeImage {
359 |
360 | // Docs: https://electronjs.org/docs/api/native-image
361 |
362 | /**
363 | * Creates an empty `NativeImage` instance.
364 | */
365 | static createEmpty(): NativeImage;
366 | /**
367 | * Creates a new `NativeImage` instance from `buffer` that contains the raw bitmap
368 | * pixel data returned by `toBitmap()`. The specific format is platform-dependent.
369 | */
370 | static createFromBitmap(buffer: Buffer, options: CreateFromBitmapOptions): NativeImage;
371 | /**
372 | * Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or
373 | * JPEG first.
374 | */
375 | static createFromBuffer(buffer: Buffer, options?: CreateFromBufferOptions): NativeImage;
376 | /**
377 | * Creates a new `NativeImage` instance from `dataURL`.
378 | */
379 | static createFromDataURL(dataURL: string): NativeImage;
380 | /**
381 | * Creates a new `NativeImage` instance from the NSImage that maps to the given
382 | * image name. See `System Icons` for a list of possible values.
383 | *
384 | * The `hslShift` is applied to the image with the following rules:
385 | *
386 | * * `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map to 0
387 | * and 360 on the hue color wheel (red).
388 | * * `hsl_shift[1]` (saturation): A saturation shift for the image, with the
389 | * following key values: 0 = remove all color. 0.5 = leave unchanged. 1 = fully
390 | * saturate the image.
391 | * * `hsl_shift[2]` (lightness): A lightness shift for the image, with the
392 | * following key values: 0 = remove all lightness (make all pixels black). 0.5 =
393 | * leave unchanged. 1 = full lightness (make all pixels white).
394 | *
395 | * This means that `[-1, 0, 1]` will make the image completely white and `[-1, 1,
396 | * 0]` will make the image completely black.
397 | *
398 | * In some cases, the `NSImageName` doesn't match its string representation; one
399 | * example of this is `NSFolderImageName`, whose string representation would
400 | * actually be `NSFolder`. Therefore, you'll need to determine the correct string
401 | * representation for your image before passing it in. This can be done with the
402 | * following:
403 | *
404 | * `echo -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME);
405 | * }' | clang -otest -x objective-c -framework Cocoa - && ./test`
406 | *
407 | * where `SYSTEM_IMAGE_NAME` should be replaced with any value from this list.
408 | *
409 | * @platform darwin
410 | */
411 | static createFromNamedImage(imageName: string, hslShift?: number[]): NativeImage;
412 | /**
413 | * Creates a new `NativeImage` instance from a file located at `path`. This method
414 | * returns an empty image if the `path` does not exist, cannot be read, or is not a
415 | * valid image.
416 | */
417 | static createFromPath(path: string): NativeImage;
418 | /**
419 | * fulfilled with the file's thumbnail preview image, which is a NativeImage.
420 | *
421 | * @platform darwin,win32
422 | */
423 | static createThumbnailFromPath(path: string, maxSize: Size): Promise;
424 | /**
425 | * Add an image representation for a specific scale factor. This can be used to
426 | * explicitly add different scale factor representations to an image. This can be
427 | * called on empty images.
428 | */
429 | addRepresentation(options: AddRepresentationOptions): void;
430 | /**
431 | * The cropped image.
432 | */
433 | crop(rect: Rectangle): NativeImage;
434 | /**
435 | * The image's aspect ratio.
436 | *
437 | * If `scaleFactor` is passed, this will return the aspect ratio corresponding to
438 | * the image representation most closely matching the passed value.
439 | */
440 | getAspectRatio(scaleFactor?: number): number;
441 | /**
442 | * A Buffer that contains the image's raw bitmap pixel data.
443 | *
444 | * The difference between `getBitmap()` and `toBitmap()` is that `getBitmap()` does
445 | * not copy the bitmap data, so you have to use the returned Buffer immediately in
446 | * current event loop tick; otherwise the data might be changed or destroyed.
447 | */
448 | getBitmap(options?: BitmapOptions): Buffer;
449 | /**
450 | * A Buffer that stores C pointer to underlying native handle of the image. On
451 | * macOS, a pointer to `NSImage` instance would be returned.
452 | *
453 | * Notice that the returned pointer is a weak pointer to the underlying native
454 | * image instead of a copy, so you _must_ ensure that the associated `nativeImage`
455 | * instance is kept around.
456 | *
457 | * @platform darwin
458 | */
459 | getNativeHandle(): Buffer;
460 | /**
461 | * An array of all scale factors corresponding to representations for a given
462 | * nativeImage.
463 | */
464 | getScaleFactors(): number[];
465 | /**
466 | * If `scaleFactor` is passed, this will return the size corresponding to the image
467 | * representation most closely matching the passed value.
468 | */
469 | getSize(scaleFactor?: number): Size;
470 | /**
471 | * Whether the image is empty.
472 | */
473 | isEmpty(): boolean;
474 | /**
475 | * Whether the image is a template image.
476 | */
477 | isTemplateImage(): boolean;
478 | /**
479 | * The resized image.
480 | *
481 | * If only the `height` or the `width` are specified then the current aspect ratio
482 | * will be preserved in the resized image.
483 | */
484 | resize(options: ResizeOptions): NativeImage;
485 | /**
486 | * Marks the image as a template image.
487 | */
488 | setTemplateImage(option: boolean): void;
489 | /**
490 | * A Buffer that contains a copy of the image's raw bitmap pixel data.
491 | */
492 | toBitmap(options?: ToBitmapOptions): Buffer;
493 | /**
494 | * The data URL of the image.
495 | */
496 | toDataURL(options?: ToDataURLOptions): string;
497 | /**
498 | * A Buffer that contains the image's `JPEG` encoded data.
499 | */
500 | toJPEG(quality: number): Buffer;
501 | /**
502 | * A Buffer that contains the image's `PNG` encoded data.
503 | */
504 | toPNG(options?: ToPNGOptions): Buffer;
505 | /**
506 | * A `boolean` property that determines whether the image is considered a template
507 | * image.
508 | *
509 | * Please note that this property only has an effect on macOS.
510 | *
511 | * @platform darwin
512 | */
513 | isMacTemplateImage: boolean;
514 | }
515 |
516 | interface Shell {
517 |
518 | // Docs: https://electronjs.org/docs/api/shell
519 |
520 | /**
521 | * Play the beep sound.
522 | */
523 | beep(): void;
524 | /**
525 | * Open the given external protocol URL in the desktop's default manner. (For
526 | * example, mailto: URLs in the user's default mail agent).
527 | */
528 | openExternal(url: string, options?: OpenExternalOptions): Promise;
529 | /**
530 | * Resolves with a string containing the error message corresponding to the failure
531 | * if a failure occurred, otherwise "".
532 | *
533 | * Open the given file in the desktop's default manner.
534 | */
535 | openPath(path: string): Promise;
536 | /**
537 | * Resolves the shortcut link at `shortcutPath`.
538 | *
539 | * An exception will be thrown when any error happens.
540 | *
541 | * @platform win32
542 | */
543 | readShortcutLink(shortcutPath: string): ShortcutDetails;
544 | /**
545 | * Show the given file in a file manager. If possible, select the file.
546 | */
547 | showItemInFolder(fullPath: string): void;
548 | /**
549 | * Resolves when the operation has been completed. Rejects if there was an error
550 | * while deleting the requested item.
551 | *
552 | * This moves a path to the OS-specific trash location (Trash on macOS, Recycle Bin
553 | * on Windows, and a desktop-environment-specific location on Linux).
554 | */
555 | trashItem(path: string): Promise;
556 | /**
557 | * Whether the shortcut was created successfully.
558 | *
559 | * Creates or updates a shortcut link at `shortcutPath`.
560 | *
561 | * @platform win32
562 | */
563 | writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutDetails): boolean;
564 | /**
565 | * Whether the shortcut was created successfully.
566 | *
567 | * Creates or updates a shortcut link at `shortcutPath`.
568 | *
569 | * @platform win32
570 | */
571 | writeShortcutLink(shortcutPath: string, options: ShortcutDetails): boolean;
572 | }
573 | interface WebFrame extends NodeJS.EventEmitter {
574 |
575 | // Docs: https://electronjs.org/docs/api/web-frame
576 |
577 | /**
578 | * Attempts to free memory that is no longer being used (like images from a
579 | * previous navigation).
580 | *
581 | * Note that blindly calling this method probably makes Electron slower since it
582 | * will have to refill these emptied caches, you should only call it if an event in
583 | * your app has occurred that makes you think your page is actually using less
584 | * memory (i.e. you have navigated from a super heavy page to a mostly empty one,
585 | * and intend to stay there).
586 | */
587 | clearCache(): void;
588 | /**
589 | * A promise that resolves with the result of the executed code or is rejected if
590 | * execution throws or results in a rejected promise.
591 | *
592 | * Evaluates `code` in page.
593 | *
594 | * In the browser window some HTML APIs like `requestFullScreen` can only be
595 | * invoked by a gesture from the user. Setting `userGesture` to `true` will remove
596 | * this limitation.
597 | */
598 | executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise;
599 | /**
600 | * A promise that resolves with the result of the executed code or is rejected if
601 | * execution could not start.
602 | *
603 | * Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
604 | *
605 | * Note that when the execution of script fails, the returned promise will not
606 | * reject and the `result` would be `undefined`. This is because Chromium does not
607 | * dispatch errors of isolated worlds to foreign worlds.
608 | */
609 | executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any, error: Error) => void): Promise;
610 | /**
611 | * A child of `webFrame` with the supplied `name`, `null` would be returned if
612 | * there's no such frame or if the frame is not in the current renderer process.
613 | */
614 | findFrameByName(name: string): WebFrame;
615 | /**
616 | * that has the supplied `routingId`, `null` if not found.
617 | */
618 | findFrameByRoutingId(routingId: number): WebFrame;
619 | /**
620 | * The frame element in `webFrame's` document selected by `selector`, `null` would
621 | * be returned if `selector` does not select a frame or if the frame is not in the
622 | * current renderer process.
623 | */
624 | getFrameForSelector(selector: string): WebFrame;
625 | /**
626 | * * `images` MemoryUsageDetails
627 | * * `scripts` MemoryUsageDetails
628 | * * `cssStyleSheets` MemoryUsageDetails
629 | * * `xslStyleSheets` MemoryUsageDetails
630 | * * `fonts` MemoryUsageDetails
631 | * * `other` MemoryUsageDetails
632 | *
633 | * Returns an object describing usage information of Blink's internal memory
634 | * caches.
635 | *
636 | * This will generate:
637 | */
638 | getResourceUsage(): ResourceUsage;
639 | /**
640 | * A list of suggested words for a given word. If the word is spelled correctly,
641 | * the result will be empty.
642 | */
643 | getWordSuggestions(word: string): string[];
644 | /**
645 | * The current zoom factor.
646 | */
647 | getZoomFactor(): number;
648 | /**
649 | * The current zoom level.
650 | */
651 | getZoomLevel(): number;
652 | /**
653 | * A key for the inserted CSS that can later be used to remove the CSS via
654 | * `webFrame.removeInsertedCSS(key)`.
655 | *
656 | * Injects CSS into the current web page and returns a unique key for the inserted
657 | * stylesheet.
658 | */
659 | insertCSS(css: string, options?: InsertCSSOptions): string;
660 | /**
661 | * Inserts `text` to the focused element.
662 | */
663 | insertText(text: string): void;
664 | /**
665 | * True if the word is misspelled according to the built in spellchecker, false
666 | * otherwise. If no dictionary is loaded, always return false.
667 | */
668 | isWordMisspelled(word: string): boolean;
669 | /**
670 | * Removes the inserted CSS from the current web page. The stylesheet is identified
671 | * by its key, which is returned from `webFrame.insertCSS(css)`.
672 | */
673 | removeInsertedCSS(key: string): void;
674 | /**
675 | * Set the security origin, content security policy and name of the isolated world.
676 | * Note: If the `csp` is specified, then the `securityOrigin` also has to be
677 | * specified.
678 | */
679 | setIsolatedWorldInfo(worldId: number, info: Info): void;
680 | setSpellCheckProvider(language: string, provider: Provider): void;
681 | /**
682 | * Sets the maximum and minimum pinch-to-zoom level.
683 | *
684 | * > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it,
685 | * call:
686 | *
687 | * > **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom
688 | * shortcuts are controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem
689 | * roles in the application Menu. To disable shortcuts, manually define the Menu
690 | * and omit zoom roles from the definition.
691 | */
692 | setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void;
693 | /**
694 | * Changes the zoom factor to the specified factor. Zoom factor is zoom percent
695 | * divided by 100, so 300% = 3.0.
696 | *
697 | * The factor must be greater than 0.0.
698 | */
699 | setZoomFactor(factor: number): void;
700 | /**
701 | * Changes the zoom level to the specified level. The original size is 0 and each
702 | * increment above or below represents zooming 20% larger or smaller to default
703 | * limits of 300% and 50% of original size, respectively.
704 | *
705 | * > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that
706 | * the zoom level for a specific domain propagates across all instances of windows
707 | * with the same domain. Differentiating the window URLs will make zoom work
708 | * per-window.
709 | */
710 | setZoomLevel(level: number): void;
711 | /**
712 | * A `WebFrame | null` representing the first child frame of `webFrame`, the
713 | * property would be `null` if `webFrame` has no children or if first child is not
714 | * in the current renderer process.
715 | *
716 | */
717 | readonly firstChild: (WebFrame) | (null);
718 | /**
719 | * A `WebFrame | null` representing next sibling frame, the property would be
720 | * `null` if `webFrame` is the last frame in its parent or if the next sibling is
721 | * not in the current renderer process.
722 | *
723 | */
724 | readonly nextSibling: (WebFrame) | (null);
725 | /**
726 | * A `WebFrame | null` representing the frame which opened `webFrame`, the property
727 | * would be `null` if there's no opener or opener is not in the current renderer
728 | * process.
729 | *
730 | */
731 | readonly opener: (WebFrame) | (null);
732 | /**
733 | * A `WebFrame | null` representing parent frame of `webFrame`, the property would
734 | * be `null` if `webFrame` is top or parent is not in the current renderer process.
735 | *
736 | */
737 | readonly parent: (WebFrame) | (null);
738 | /**
739 | * An `Integer` representing the unique frame id in the current renderer process.
740 | * Distinct WebFrame instances that refer to the same underlying frame will have
741 | * the same `routingId`.
742 | *
743 | */
744 | readonly routingId: number;
745 | /**
746 | * A `WebFrame | null` representing top frame in frame hierarchy to which
747 | * `webFrame` belongs, the property would be `null` if top frame is not in the
748 | * current renderer process.
749 | *
750 | */
751 | readonly top: (WebFrame) | (null);
752 | }
753 |
754 | declare var electron: {
755 | clipboard: Clipboard
756 | contextBridge: ContextBridge
757 | crashReporter: CrashReporter
758 | ipcRenderer: IpcRenderer
759 | nativeImage: NativeImage
760 | shell: Shell
761 | webFrame: WebFrame
762 | }
763 |
--------------------------------------------------------------------------------
/src/common/monaco/types/utools.api.d.ts:
--------------------------------------------------------------------------------
1 | interface UBrowser {
2 | /**
3 | * 设置 User-Agent
4 | */
5 | useragent(userAgent: string): this
6 | /**
7 | * 前往
8 | * @param url 链接地址,支持 http 或 file 协议
9 | * @param headers 请求头参数
10 | * @param timeout 加载超时,默认 60000 ms(60秒)
11 | */
12 | goto(url: string, headers?: { Referer: string; userAgent: string }, timeout?: number): this
13 | /**
14 | * 页面大小
15 | */
16 | viewport(width: number, height: number): this
17 | /**
18 | * 隐藏 ubrowser 窗口
19 | */
20 | hide(): this
21 | /**
22 | * 显示 ubrowser 窗口
23 | */
24 | show(): this
25 | /**
26 | * 注入样式
27 | */
28 | css(css: string): this
29 | /**
30 | * 键盘按键
31 | */
32 | press(
33 | key: string,
34 | ...modifier: ('control' | 'ctrl' | 'shift' | 'meta' | 'alt' | 'command' | 'cmd')[]
35 | ): this
36 | /**
37 | * 粘贴
38 | * @param text 如果是图片的base64编码字符串,粘贴图片,为空只执行粘贴动作
39 | */
40 | paste(text?: string): this
41 | /**
42 | * 页面截图
43 | * @param arg 1.字符串 - 要截取的DOM元素, 2.对象 - 截图位置和大小, 3.空 - 为截取整个窗口
44 | * @param savePath 截图保存路径,可以是文件夹 或 .png文件完全路径, 默认保存临时目录
45 | */
46 | screenshot(
47 | arg: string | { x: number; y: number; width: number; height: number },
48 | savePath?: string
49 | ): this
50 | /**
51 | * 保存为PDF
52 | * @param options 选项
53 | * @param savePath PDF保存路径,可以是文件夹 或 .pdf文件完全路径, 默认保存临时目录
54 | */
55 | pdf(
56 | options?: {
57 | marginsType: 0 | 1 | 2
58 | pageSize:
59 | | ('A3' | 'A4' | 'A5' | 'Legal' | 'Letter' | 'Tabloid')
60 | | { width: number; height: number }
61 | },
62 | savePath?: string
63 | ): this
64 | /**
65 | * 模拟设备
66 | */
67 | device(
68 | arg:
69 | | (
70 | | 'iPhone 11'
71 | | 'iPhone X'
72 | | 'iPad'
73 | | 'iPhone 6/7/8 Plus'
74 | | 'iPhone 6/7/8'
75 | | 'iPhone 5/SE'
76 | | 'HUAWEI Mate10'
77 | | 'HUAWEI Mate20'
78 | | 'HUAWEI Mate30'
79 | | 'HUAWEI Mate30 Pro'
80 | )
81 | | { size: { width: number; height: number }; useragent: string }
82 | ): this
83 | /**
84 | * 获取 cookie
85 | * @param name 为空获取全部cookie
86 | */
87 | cookies(name?: string): this
88 | /**
89 | * 设置Cookie
90 | */
91 | setCookies(name: string, value: string): this
92 | /**
93 | * 设置Cookie
94 | */
95 | setCookies(cookies: { name: string; value: string }[]): this
96 | /**
97 | * 删除 cookie
98 | */
99 | removeCookies(name: string): this
100 | /**
101 | * 清空cookie
102 | * @param url 在执行"goto"前执行 url参数必需
103 | */
104 | clearCookies(url?: string): this
105 | /**
106 | * 打开开发者工具
107 | */
108 | devTools(mode?: 'right' | 'bottom' | 'undocked' | 'detach'): this
109 | /**
110 | * 执行JS计算 并获得结果
111 | * @param func 在目标网页中执行
112 | * @param params 传到 func 中的参数
113 | */
114 | evaluate(func: (...params: any[]) => any, ...params: any[]): this
115 | /**
116 | * 等待时间
117 | * @param ms 毫秒
118 | */
119 | wait(ms: number): this
120 | /**
121 | * 等待元素出现
122 | * @param selector DOM元素
123 | * @param timeout 超时 默认60000 ms(60秒)
124 | */
125 | wait(selector: string, timeout?: number): this
126 | /**
127 | * 等待 JS函数 执行返回 true
128 | * @param func 执行的JS函数
129 | * @param timeout 超时 默认60000 ms(60秒)
130 | * @param params 传到 func 中的参数
131 | */
132 | wait(func: (...params: any[]) => boolean, timeout?: number, ...params: any[]): this
133 | /**
134 | * 当元素存在时执行直到碰到 end
135 | * @param selector DOM元素
136 | */
137 | when(selector: string): this
138 | /**
139 | * 当 JS函数执行返回 true 时执行直到碰到 end
140 | * @param func 执行的JS函数
141 | * @param params 传到 func 中的参数
142 | */
143 | when(func: (...params: any[]) => boolean, ...params: any[]): this
144 | /**
145 | * 配合 when 使用
146 | */
147 | end(): this
148 | /**
149 | * 单击元素
150 | */
151 | click(selector: string): this
152 | /**
153 | * 元素触发按下鼠标左键
154 | */
155 | mousedown(selector: string): this
156 | /**
157 | * 元素触发释放鼠标左键
158 | */
159 | mouseup(selector: string): this
160 | /**
161 | * 赋值 file input
162 | * @param selector 元素
163 | * @param payload 1. string - 文件路径 或 图片的base64编码,2. string[] - 文件路径集合,3. Uint8Array[]
164 | */
165 | file(selector: string, payload: string | string[] | Uint8Array): this
166 | /**
167 | * input textarea select 等元素赋值并触发 input 或 change事件
168 | */
169 | value(selector: string, value: string): this
170 | /**
171 | * checkbox radio 元素选中或取消选中
172 | */
173 | check(selector: string, checked: boolean): this
174 | /**
175 | * 元素获得焦点
176 | */
177 | focus(selector: string): this
178 | /**
179 | * 滚动到元素位置
180 | */
181 | scroll(selector: string): this
182 | /**
183 | * Y轴滚动
184 | */
185 | scroll(y: number): this
186 | /**
187 | * X轴和Y轴滚动
188 | */
189 | scroll(x: number, y: number): this
190 | /**
191 | * 运行在闲置的 ubrowser 上
192 | * @param ubrowserId utools.getIdleUBrowsers() 中获得
193 | */
194 | run(ubrowserId: number): Promise
195 | /**
196 | * 启动一个 ubrowser 运行
197 | * 当运行结束后,窗口如果为隐藏状态将自动销毁窗口
198 | * @param options
199 | */
200 | run(options: {
201 | show?: boolean
202 | width?: number
203 | height?: number
204 | x?: number
205 | y?: number
206 | center?: boolean
207 | minWidth?: number
208 | minHeight?: number
209 | maxWidth?: number
210 | maxHeight?: number
211 | resizable?: boolean
212 | movable?: boolean
213 | minimizable?: boolean
214 | maximizable?: boolean
215 | alwaysOnTop?: boolean
216 | fullscreen?: boolean
217 | fullscreenable?: boolean
218 | enableLargerThanScreen?: boolean
219 | opacity?: number
220 | }): Promise
221 | }
222 |
223 | interface Display {
224 | accelerometerSupport: 'available' | 'unavailable' | 'unknown'
225 | bounds: { x: number; y: number; width: number; height: number }
226 | colorDepth: number
227 | colorSpace: string
228 | depthPerComponent: number
229 | id: number
230 | internal: boolean
231 | monochrome: boolean
232 | rotation: number
233 | scaleFactor: number
234 | size: { width: number; height: number }
235 | touchSupport: 'available' | 'unavailable' | 'unknown'
236 | workArea: { x: number; y: number; width: number; height: number }
237 | workAreaSize: { width: number; height: number }
238 | }
239 |
240 | interface DbDoc {
241 | _id: string
242 | _rev?: string
243 | [key: string]: any
244 | }
245 |
246 | interface DbReturn {
247 | id: string
248 | rev?: string
249 | ok?: boolean
250 | error?: boolean
251 | name?: string
252 | message?: string
253 | }
254 |
255 | interface UToolsApi {
256 | /**
257 | * 插件应用进入时触发
258 | */
259 | // onPluginEnter(callback: (action: { code: string; type: string; payload: any }) => void): void
260 | /**
261 | * 插件应用隐藏后台或完全退出时触发
262 | */
263 | // onPluginOut(callback: (processExit: boolean) => void): void
264 | /**
265 | * 插件应用分离时触发
266 | */
267 | // onPluginDetach(callback: () => void): void
268 | /**
269 | * 插件应用从云端拉取到数据时触发
270 | */
271 | // onDbPull(callback: (docs: { _id: string; _rev: string }[]) => void): void
272 | /**
273 | * 隐藏主窗口
274 | * @param isRestorePreWindow 是否焦点回归到前面的活动窗口,默认 true
275 | */
276 | hideMainWindow(isRestorePreWindow?: boolean): boolean
277 | /**
278 | * 显示主窗口
279 | */
280 | showMainWindow(): boolean
281 | /**
282 | * 设置插件应用自身高度
283 | */
284 | setExpendHeight(height: number): boolean
285 | /**
286 | * 设置子输入框
287 | * @param onChange 修改时触发
288 | * @param placeholder 占位符, 默认为空
289 | * @param isFocus 是否获得焦点,默认为 true
290 | */
291 | setSubInput(onChange: (text: string) => void, placeholder?: string, isFocus?: boolean): boolean
292 | /**
293 | * 移除子输入框
294 | */
295 | removeSubInput(): boolean
296 | /**
297 | * 赋值子输入框
298 | */
299 | setSubInputValue(value: string): boolean
300 | /**
301 | * 子输入框获得焦点
302 | */
303 | subInputFocus(): boolean
304 | /**
305 | * 子输入框获得焦点并选中
306 | */
307 | subInputSelect(): boolean
308 | /**
309 | * 子输入框失去焦点,插件应用获得焦点
310 | */
311 | subInputBlur(): boolean
312 | /**
313 | * 创建独立窗口
314 | * @param url 相对路径 html 文件
315 | * @param options 参考 https://www.electronjs.org/docs/api/browser-window#new-browserwindowoptions
316 | * @param callback url 加载完成时的回调
317 | */
318 | // createBrowserWindow(
319 | // url: string,
320 | // options: { width?: number; height?: number },
321 | // callback?: () => void
322 | // ): { id: number; [key: string]: any; webContents: { id: number; [key: string]: any } }
323 | /**
324 | * 隐藏插件应用到后台
325 | */
326 | outPlugin(): boolean
327 | /**
328 | * 是否深色模式
329 | */
330 | isDarkColors(): boolean
331 | /**
332 | * 获取用户
333 | */
334 | getUser(): { avatar: string; nickname: string; type: string } | null
335 | /**
336 | * 获取用户服务端临时令牌
337 | */
338 | // fetchUserServerTemporaryToken(): Promise<{ token: string; expiredAt: number }>
339 | /**
340 | * 打开支付
341 | * @param callback 支付成功触发
342 | */
343 | // openPayment(
344 | // options: {
345 | // /**
346 | // * 商品ID,在 “uTools 开发者工具” 插件应用中创建
347 | // */
348 | // goodsId: string
349 | // /**
350 | // * 第三方服务生成的订单号(可选)
351 | // */
352 | // outOrderId?: string
353 | // /**
354 | // * 第三方服务附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用(可选)
355 | // */
356 | // attach?: string
357 | // },
358 | // callback?: () => void
359 | // ): void
360 | /**
361 | * 获取用户支付记录
362 | */
363 | // fetchUserPayments(): Promise<
364 | // {
365 | // order_id: string
366 | // total_fee: number
367 | // body: string
368 | // attach: string
369 | // goods_id: string
370 | // out_order_id: string
371 | // paid_at: string
372 | // }[]
373 | // >
374 | /**
375 | * 设置插件应用动态功能
376 | */
377 | // setFeature(feature: {
378 | // code: string
379 | // explain: string
380 | // platform: ('darwin' | 'win32' | 'linux') | Array<'darwin' | 'win32' | 'linux'>
381 | // icon?: string
382 | // cmds: (
383 | // | string
384 | // | {
385 | // type: 'img' | 'files' | 'regex' | 'over' | 'window'
386 | // label: string
387 | // }
388 | // )[]
389 | // }): boolean
390 | /**
391 | * 移除插件应用动态功能
392 | */
393 | // removeFeature(code: string): boolean
394 | /**
395 | * 获取插件应用动态功能,参数为空获取所有动态功能
396 | */
397 | // getFeatures(codes?: string[]): {
398 | // code: string
399 | // explain: string
400 | // platform: ('darwin' | 'win32' | 'linux') | Array<'darwin' | 'win32' | 'linux'>
401 | // icon?: string
402 | // cmds:
403 | // | string
404 | // | {
405 | // type: 'img' | 'files' | 'regex' | 'over' | 'window'
406 | // label: string
407 | // }[]
408 | // }[]
409 | /**
410 | * 插件应用间跳转
411 | */
412 | redirect(label: string, payload: string | { type: 'text' | 'img' | 'files'; data: any }): void
413 | /**
414 | * 获取闲置的 ubrowser
415 | */
416 | getIdleUBrowsers(): { id: number; title: string; url: string }[]
417 | /**
418 | * 设置 ubrowser 代理 https://www.electronjs.org/docs/api/session#sessetproxyconfig
419 | */
420 | setUBrowserProxy(config: {
421 | pacScript?: string
422 | proxyRules?: string
423 | proxyBypassRules?: string
424 | }): boolean
425 | /**
426 | * 清空 ubrowser 缓存
427 | */
428 | clearUBrowserCache(): boolean
429 | /**
430 | * 显示系统通知
431 | */
432 | showNotification(body: string): void
433 | /**
434 | * 弹出文件选择框
435 | */
436 | showOpenDialog(options: {
437 | title?: string
438 | defaultPath?: string
439 | buttonLabel?: string
440 | filters?: { name: string; extensions: string[] }[]
441 | properties?: Array<
442 | | 'openFile'
443 | | 'openDirectory'
444 | | 'multiSelections'
445 | | 'showHiddenFiles'
446 | | 'createDirectory'
447 | | 'promptToCreate'
448 | | 'noResolveAliases'
449 | | 'treatPackageAsDirectory'
450 | | 'dontAddToRecent'
451 | >
452 | message?: string
453 | securityScopedBookmarks?: boolean
454 | }): string[] | undefined
455 | /**
456 | * 弹出文件保存框
457 | */
458 | showSaveDialog(options: {
459 | title?: string
460 | defaultPath?: string
461 | buttonLabel?: string
462 | filters?: { name: string; extensions: string[] }[]
463 | message?: string
464 | nameFieldLabel?: string
465 | showsTagField?: string
466 | properties?: Array<
467 | | 'showHiddenFiles'
468 | | 'createDirectory'
469 | | 'treatPackageAsDirectory'
470 | | 'showOverwriteConfirmation'
471 | | 'dontAddToRecent'
472 | >
473 | securityScopedBookmarks?: boolean
474 | }): string | undefined
475 | /**
476 | * 插件应用页面中查找
477 | */
478 | findInPage(
479 | text: string,
480 | options?: {
481 | forward?: boolean
482 | findNext?: boolean
483 | matchCase?: boolean
484 | wordStart?: boolean
485 | medialCapitalAsWordStart?: boolean
486 | }
487 | ): void
488 | /**
489 | * 停止插件应用页面中查找
490 | */
491 | stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void
492 | /**
493 | * 拖拽文件
494 | */
495 | startDrag(file: string | string[]): void
496 | /**
497 | * 屏幕取色
498 | */
499 | screenColorPick(callback: (color: { hex: string; rgb: string }) => void): void
500 | /**
501 | * 屏幕截图
502 | */
503 | screenCapture(callback: (imgBase64: string) => void): void
504 | /**
505 | * 获取本地 ID
506 | */
507 | getNativeId(): string
508 | /**
509 | * 获取软件版本
510 | */
511 | getAppVersion(): string
512 | /**
513 | * 获取路径
514 | */
515 | getPath(
516 | name:
517 | | 'home'
518 | | 'appData'
519 | | 'userData'
520 | | 'cache'
521 | | 'temp'
522 | | 'exe'
523 | | 'module'
524 | | 'desktop'
525 | | 'documents'
526 | | 'downloads'
527 | | 'music'
528 | | 'pictures'
529 | | 'videos'
530 | | 'logs'
531 | | 'pepperFlashSystemPlugin'
532 | ): string
533 | /**
534 | * 获取文件图标
535 | */
536 | getFileIcon(filePath: string): string
537 | /**
538 | * 复制文件到剪贴板
539 | */
540 | copyFile(file: string | string[]): boolean
541 | /**
542 | * 复制图片到剪贴板
543 | * @param img base64、buffer、图片路径
544 | */
545 | copyImage(img: string | Uint8Array): boolean
546 | /**
547 | * 复制文本到剪贴板
548 | */
549 | copyText(text: string): boolean
550 | /**
551 | * 获取复制的文件或文件夹
552 | */
553 | getCopyedFiles(): { isFile: boolean; isDirectory: boolean; name: string; path: string }[]
554 | /**
555 | * 读取当前文件管理器路径(linux 不支持)
556 | */
557 | readCurrentFolderPath(): Promise
558 | /**
559 | * 读取当前浏览器窗口的URL(linux 不支持)
560 | * MacOs 支持浏览器 Safari、Chrome、Opera、Vivaldi、Brave
561 | * Windows 支持浏览器 Chrome、Firefox、Edge、IE、Opera、Brave
562 | * Linux 不支持
563 | */
564 | readCurrentBrowserUrl(): Promise
565 | /**
566 | * 默认方式打开给定的文件
567 | */
568 | shellOpenPath(fullPath: string): void
569 | /**
570 | * 在文件管理器中显示给定的文件
571 | */
572 | shellShowItemInFolder(fullPath: string): void
573 | /**
574 | * 系统默认的协议打开URL
575 | */
576 | shellOpenExternal(url: string): void
577 | /**
578 | * 播放哔哔声
579 | */
580 | shellBeep(): void
581 | /*
582 | * 隐藏主窗口并键入字符串
583 | */
584 | hideMainWindowTypeString(str: string): void
585 | /**
586 | * 模拟键盘按键
587 | */
588 | simulateKeyboardTap(
589 | key: string,
590 | ...modifier: ('control' | 'ctrl' | 'shift' | 'option' | 'alt' | 'command' | 'super')[]
591 | ): void
592 | /**
593 | * 模拟鼠标单击
594 | */
595 | simulateMouseClick(x?: number, y?: number): void
596 | /**
597 | * 模拟鼠标右击
598 | */
599 | simulateMouseRightClick(x?: number, y?: number): void
600 | /**
601 | * 模拟鼠标双击
602 | */
603 | simulateMouseDoubleClick(x?: number, y?: number): void
604 | /**
605 | * 模拟鼠标移动
606 | */
607 | simulateMouseMove(x: number, y: number): void
608 | /**
609 | * 获取鼠标绝对位置
610 | */
611 | getCursorScreenPoint(): { x: number; y: number }
612 | /**
613 | * 获取主显示器
614 | */
615 | getPrimaryDisplay(): Display
616 | /**
617 | * 获取所有显示器
618 | */
619 | getAllDisplays(): Display[]
620 | /**
621 | * 获取位置所在的显示器
622 | */
623 | getDisplayNearestPoint(point: { x: number; y: number }): Display
624 | /**
625 | * 获取矩形所在的显示器
626 | */
627 | getDisplayMatching(rect: { x: number; y: number; width: number; height: number }): Display
628 | /**
629 | * 录屏源
630 | */
631 | desktopCaptureSources(options: {
632 | types: string[]
633 | thumbnailSize?: { width: number; height: number }
634 | fetchWindowIcons?: boolean
635 | }): Promise<{ appIcon: {}; display_id: string; id: string; name: string; thumbnail: {} }>
636 | /**
637 | * 是否开发中
638 | */
639 | isDev(): boolean
640 | /**
641 | * 是否 MacOs 操作系统
642 | */
643 | isMacOS(): boolean
644 | /**
645 | * 是否 Windows 操作系统
646 | */
647 | isWindows(): boolean
648 | /**
649 | * 是否 Linux 操作系统
650 | */
651 | isLinux(): boolean
652 |
653 | // db: {
654 | // /**
655 | // * 创建/更新文档
656 | // */
657 | // put(doc: DbDoc): DbReturn
658 | // /**
659 | // * 获取文档
660 | // */
661 | // get(id: string): DbDoc | null
662 | // /**
663 | // * 删除文档
664 | // */
665 | // remove(doc: string | DbDoc): DbReturn
666 | // /**
667 | // * 批量操作文档(新增、修改、删除)
668 | // */
669 | // bulkDocs(docs: DbDoc[]): DbReturn[]
670 | // /**
671 | // * 获取所有文档 可根据文档id前缀查找
672 | // */
673 | // allDocs(key?: string): DbDoc[]
674 | // /**
675 | // * 存储附件到新文档
676 | // * @param docId 文档ID
677 | // * @param attachment 附件 buffer
678 | // * @param type 附件类型,示例:image/png, text/plain
679 | // */
680 | // postAttachment(docId: string, attachment: Uint8Array, type: string): DbReturn
681 | // /**
682 | // * 获取附件
683 | // * @param docId 文档ID
684 | // */
685 | // getAttachment(docId: string): Uint8Array | null
686 | // /**
687 | // * 获取附件类型
688 | // * @param docId 文档ID
689 | // */
690 | // getAttachmentType(docId: string): string | null
691 | // /**
692 | // * 云端复制数据状态 (null: 未开启数据同步、0: 已完成复制、1:复制中)
693 | // */
694 | // replicateStateFromCloud(): null | 0 | 1
695 | // /**
696 | // * 异步
697 | // */
698 | // promises: {
699 | // /**
700 | // * 创建/更新文档
701 | // */
702 | // put(doc: DbDoc): Promise
703 | // /**
704 | // * 获取文档
705 | // */
706 | // get(id: string): Promise
707 | // /**
708 | // * 删除文档
709 | // */
710 | // remove(doc: string | DbDoc): Promise
711 | // /**
712 | // * 批量操作文档(新增、修改、删除)
713 | // */
714 | // bulkDocs(docs: DbDoc[]): Promise
715 | // /**
716 | // * 获取所有文档 可根据文档id前缀查找
717 | // */
718 | // allDocs(key?: string): Promise
719 | // /**
720 | // * 存储附件到新文档
721 | // * @param docId 文档ID
722 | // * @param attachment 附件 buffer
723 | // * @param type 附件类型,示例:image/png, text/plain
724 | // */
725 | // postAttachment(docId: string, attachment: Uint8Array, type: string): Promise
726 | // /**
727 | // * 获取附件
728 | // * @param docId 文档ID
729 | // */
730 | // getAttachment(docId: string): Promise
731 | // /**
732 | // * 获取附件类型
733 | // * @param docId 文档ID
734 | // */
735 | // getAttachmentType(docId: string): Promise
736 | // /**
737 | // * 云端复制数据状态 (null: 未开启数据同步、0: 已完成复制、1:复制中)
738 | // */
739 | // replicateStateFromCloud(): Promise
740 | // }
741 | // }
742 |
743 | // dbStorage: {
744 | // /**
745 | // * 键值对存储,如果键名存在,则更新其对应的值
746 | // * @param key 键名(同时为文档ID)
747 | // * @param value 键值
748 | // */
749 | // setItem(key: string, value: any): void
750 | // /**
751 | // * 获取键名对应的值
752 | // */
753 | // getItem(key: string): any
754 | // /**
755 | // * 删除键值对(删除文档)
756 | // */
757 | // removeItem(key: string): void
758 | // }
759 |
760 | ubrowser: UBrowser
761 | }
762 |
763 | declare var utools: UToolsApi
764 |
--------------------------------------------------------------------------------
/src/common/registerCallback.ts:
--------------------------------------------------------------------------------
1 | import { Message } from '@arco-design/web-vue'
2 | import { isElectron } from '@/utils'
3 |
4 | export function registerCallback() {
5 | if (!isElectron) return
6 |
7 | if (utools.db.replicateStateFromCloud()) {
8 | Message.warning({
9 | content: '数据可能不完整,还在从云端复制中'
10 | })
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/common/registerIcon.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import {
3 | IconCopy,
4 | IconFile,
5 | IconInfoCircle,
6 | IconPlus,
7 | IconThunderbolt,
8 | IconSettings,
9 | IconCloseCircle,
10 | IconDown,
11 | IconEdit,
12 | IconCommand,
13 | IconEye,
14 | IconDelete,
15 | IconShareAlt,
16 | IconLock,
17 | IconUnlock
18 | } from '@arco-design/web-vue/es/icon'
19 |
20 | const icons = [
21 | IconCopy,
22 | IconFile,
23 | IconInfoCircle,
24 | IconPlus,
25 | IconThunderbolt,
26 | IconSettings,
27 | IconCloseCircle,
28 | IconDown,
29 | IconEdit,
30 | IconCommand,
31 | IconEye,
32 | IconDelete,
33 | IconShareAlt,
34 | IconLock,
35 | IconUnlock
36 | ]
37 |
38 | export function registerIcon(app: App) {
39 | for (const icon of icons) {
40 | app.component(icon.name, icon)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/common/symbol.ts:
--------------------------------------------------------------------------------
1 | import { InjectionKey } from 'vue'
2 |
3 | /**
4 | * Whether the current theme is dark
5 | */
6 | export const IS_DARK = Symbol('IS_DARK') as InjectionKey>
7 |
8 | /**
9 | * Event: focus editor
10 | */
11 | export const EVENT_FOCUS_EDITOR = Symbol('EVENT_FOCUS_EDITOR')
12 |
--------------------------------------------------------------------------------
/src/components/CodeList.vue:
--------------------------------------------------------------------------------
1 |
2 | v && store.loadHistorys()">
3 | 代码历史回溯 ({{ store.historys.length }})
4 |
5 |
6 |
10 |
11 |
12 |
13 | {{
14 | history?.name
15 | ? `${history?.name} ${formatTime(history.timeStamp)}`
16 | : formatTime(history.timeStamp)
17 | }}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
46 |
47 |
72 |
--------------------------------------------------------------------------------
/src/components/Console.vue:
--------------------------------------------------------------------------------
1 |
2 |