@opensumi/ide-dev-tool 2.27.3-next-1711359673.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +5 -0
- package/LICENSE +21 -0
- package/__tests__/mock-injector.test.ts +89 -0
- package/cli/commander/index.js +38 -0
- package/cli/index.js +16 -0
- package/cli/rebuild-native.js +87 -0
- package/package.json +46 -0
- package/src/ext-host.js +14 -0
- package/src/ext-host.ts +16 -0
- package/src/index.html +28 -0
- package/src/injector-editor.ts +84 -0
- package/src/injector-helper.ts +136 -0
- package/src/jest-resolver.js +16 -0
- package/src/mock-exports.js +26 -0
- package/src/mock-injector.ts +129 -0
- package/src/mock-log-service.js +22 -0
- package/src/mock-log-service.ts +24 -0
- package/src/mock-main.tsx +3 -0
- package/src/server.ts +119 -0
- package/src/webpack.js +423 -0
package/.eslintrc.js
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019-present Alibaba Group Holding Limited, Ant Group Co. Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
|
|
3
|
+
import { createBrowserInjector } from '../src/injector-helper';
|
|
4
|
+
import { createNodeInjector } from '../src/mock-injector';
|
|
5
|
+
import { MockInjector } from '../src/mock-injector';
|
|
6
|
+
|
|
7
|
+
describe('mock-injector test', () => {
|
|
8
|
+
let fn1: jest.Mock<any, any>;
|
|
9
|
+
let fn2: jest.Mock<any, any>;
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
class A {
|
|
13
|
+
log = fn1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
fn1 = jest.fn();
|
|
18
|
+
fn2 = jest.fn();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('Manually create Injector', () => {
|
|
22
|
+
let injector: MockInjector;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
injector = new MockInjector();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('Can mock a injected service', () => {
|
|
29
|
+
injector.mock(A, 'log', fn2);
|
|
30
|
+
|
|
31
|
+
const args = [1, '2', true];
|
|
32
|
+
const a = injector.get(A);
|
|
33
|
+
a.log(...args);
|
|
34
|
+
|
|
35
|
+
expect(fn1).toBeCalledTimes(0);
|
|
36
|
+
expect(fn2).toBeCalledTimes(1);
|
|
37
|
+
expect(fn2).toBeCalledWith(...args);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('Can mock a created service', () => {
|
|
41
|
+
const args = [1, '2', true];
|
|
42
|
+
const a = injector.get(A);
|
|
43
|
+
|
|
44
|
+
injector.mock(A, 'log', fn2);
|
|
45
|
+
a.log(...args);
|
|
46
|
+
|
|
47
|
+
expect(fn1).toBeCalledTimes(0);
|
|
48
|
+
expect(fn2).toBeCalledTimes(1);
|
|
49
|
+
expect(fn2).toBeCalledWith(...args);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Work as expected', () => {
|
|
53
|
+
const args = [1, '2', true];
|
|
54
|
+
const a = injector.get(A);
|
|
55
|
+
a.log(...args);
|
|
56
|
+
|
|
57
|
+
expect(fn1).toBeCalledTimes(1);
|
|
58
|
+
expect(fn1).toBeCalledWith(...args);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('User helper to create Injector', () => {
|
|
63
|
+
it('Can mock service with the Injector created by `createBrowserInjector` method', () => {
|
|
64
|
+
const injector = createBrowserInjector([]);
|
|
65
|
+
injector.mock(A, 'log', fn2);
|
|
66
|
+
|
|
67
|
+
const args = [1, '2', true];
|
|
68
|
+
const a = injector.get(A);
|
|
69
|
+
a.log(...args);
|
|
70
|
+
|
|
71
|
+
expect(fn1).toBeCalledTimes(0);
|
|
72
|
+
expect(fn2).toBeCalledTimes(1);
|
|
73
|
+
expect(fn2).toBeCalledWith(...args);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('Can mock service with the Injector created by `createNodeInjector` method', () => {
|
|
77
|
+
const injector = createNodeInjector([]);
|
|
78
|
+
injector.mock(A, 'log', fn2);
|
|
79
|
+
|
|
80
|
+
const args = [1, '2', true];
|
|
81
|
+
const a = injector.get(A);
|
|
82
|
+
a.log(...args);
|
|
83
|
+
|
|
84
|
+
expect(fn1).toBeCalledTimes(0);
|
|
85
|
+
expect(fn2).toBeCalledTimes(1);
|
|
86
|
+
expect(fn2).toBeCalledWith(...args);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const mri = require('mri');
|
|
2
|
+
|
|
3
|
+
class Commander {
|
|
4
|
+
commandMap = new Map();
|
|
5
|
+
addSubCommand(subCommand, options) {
|
|
6
|
+
this.commandMap.set(subCommand, options);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
run() {
|
|
10
|
+
const argv = mri(process.argv.slice(2));
|
|
11
|
+
|
|
12
|
+
const subCommand = argv._[0];
|
|
13
|
+
|
|
14
|
+
if (subCommand) {
|
|
15
|
+
const options = this.commandMap.get(subCommand);
|
|
16
|
+
if (options && options.handler && typeof options.handler === 'function') {
|
|
17
|
+
options.handler(argv._.slice(1), argv);
|
|
18
|
+
}
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = [];
|
|
23
|
+
for (const [name, options] of this.commandMap.entries()) {
|
|
24
|
+
result.push(` - ${name}: ${options.help}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(
|
|
28
|
+
`
|
|
29
|
+
Usage:
|
|
30
|
+
${result.join('\n')}
|
|
31
|
+
|
|
32
|
+
Good bye~
|
|
33
|
+
`.trim(),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = Commander;
|
package/cli/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const Commander = require('./commander');
|
|
4
|
+
const { rebuild } = require('./rebuild-native');
|
|
5
|
+
|
|
6
|
+
const commander = new Commander();
|
|
7
|
+
commander.addSubCommand('rebuild', {
|
|
8
|
+
handler: (_, argv) => {
|
|
9
|
+
console.log(_);
|
|
10
|
+
console.log(argv);
|
|
11
|
+
rebuild(argv);
|
|
12
|
+
},
|
|
13
|
+
help: 'rebuild current working directory native modules',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
commander.run();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const { join } = require('path');
|
|
4
|
+
|
|
5
|
+
const { pathExistsSync, copySync, removeSync } = require('fs-extra');
|
|
6
|
+
|
|
7
|
+
const nativeModules = [
|
|
8
|
+
join(process.cwd(), './node_modules/node-pty'),
|
|
9
|
+
join(process.cwd(), './node_modules/nsfw'),
|
|
10
|
+
join(process.cwd(), './node_modules/@parcel/watcher'),
|
|
11
|
+
join(process.cwd(), './node_modules/spdlog'),
|
|
12
|
+
join(process.cwd(), './node_modules/keytar'),
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
let commands;
|
|
16
|
+
|
|
17
|
+
module.exports.rebuild = (argv) => {
|
|
18
|
+
const target = argv.target || 'node';
|
|
19
|
+
const arch = argv.arch || os.arch();
|
|
20
|
+
const force = argv['force-rebuild'] || argv.force;
|
|
21
|
+
let version;
|
|
22
|
+
|
|
23
|
+
if (target === 'electron') {
|
|
24
|
+
version = argv.electronVersion || require('electron/package.json').version;
|
|
25
|
+
const distUrl = argv.distUrl || 'https://electronjs.org/headers';
|
|
26
|
+
console.log('rebuilding native for electron version ' + version);
|
|
27
|
+
commands = [
|
|
28
|
+
os.platform() === 'win32' ? 'set HOME=~/.electron-gyp' : 'HOME=~/.electron-gyp',
|
|
29
|
+
'node-gyp',
|
|
30
|
+
'rebuild',
|
|
31
|
+
'--openssl_fips=X',
|
|
32
|
+
`--target=${version}`,
|
|
33
|
+
`--arch=${arch}`,
|
|
34
|
+
`--dist-url=${distUrl}`,
|
|
35
|
+
];
|
|
36
|
+
} else if (target === 'node') {
|
|
37
|
+
console.log('rebuilding native for node version ' + process.version);
|
|
38
|
+
version = process.version;
|
|
39
|
+
commands = ['node-gyp', 'rebuild'];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function rebuildModule(modulePath, type, version, arch) {
|
|
43
|
+
const info = require(join(modulePath, './package.json'));
|
|
44
|
+
console.log(`rebuilding ${info.name}: ${info.version} for arch ${arch}`);
|
|
45
|
+
const cache = getBuildCacheDir(modulePath, type, version, arch);
|
|
46
|
+
console.log(`cache dir ${cache}`);
|
|
47
|
+
if (pathExistsSync(cache) && !force) {
|
|
48
|
+
try {
|
|
49
|
+
console.log('cache found for ' + info.name);
|
|
50
|
+
removeSync(join(modulePath, 'build'));
|
|
51
|
+
|
|
52
|
+
if (process.platform === 'linux') {
|
|
53
|
+
execSync(`cp -r ${cache} ${join(modulePath, 'build')}`);
|
|
54
|
+
} else {
|
|
55
|
+
copySync(cache, join(modulePath, 'build'), { dereference: true, recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log('cache restore error', error);
|
|
61
|
+
console.log('build from source');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
console.log(`running command ${commands.join(' ')}`);
|
|
65
|
+
execSync(commands.join(' '), {
|
|
66
|
+
cwd: modulePath,
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
});
|
|
69
|
+
removeSync(cache);
|
|
70
|
+
copySync(join(modulePath, 'build'), cache, { dereference: true, recursive: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
nativeModules.forEach((path) => {
|
|
74
|
+
rebuildModule(path, target, version, arch);
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
function getBuildCacheDir(modulePath, type, version, arch) {
|
|
79
|
+
const info = require(join(modulePath, './package.json'));
|
|
80
|
+
return join(
|
|
81
|
+
require('os').homedir(),
|
|
82
|
+
'.sumi-dev',
|
|
83
|
+
'opensumi_build_cache',
|
|
84
|
+
`${type}-${version}-${arch}`,
|
|
85
|
+
info.name + '-' + info.version,
|
|
86
|
+
);
|
|
87
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensumi/ide-dev-tool",
|
|
3
|
+
"version": "2.27.3-next-1711359673.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git@github.com:opensumi/core.git"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"sumi": "./cli/index.js"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@types/koa": "^2.14.0",
|
|
16
|
+
"@types/koa-bodyparser": "^4.3.7",
|
|
17
|
+
"@types/koa-router": "^7.4.2",
|
|
18
|
+
"copy-webpack-plugin": "^12.0.2",
|
|
19
|
+
"css-loader": "^6.9.1",
|
|
20
|
+
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
|
21
|
+
"html-webpack-plugin": "^5.6.0",
|
|
22
|
+
"koa": "^2.15.0",
|
|
23
|
+
"koa-bodyparser": "^4.3.0",
|
|
24
|
+
"koa-router": "^10.1.1",
|
|
25
|
+
"koa-static": "^5.0.0",
|
|
26
|
+
"less": "^3.9.0",
|
|
27
|
+
"less-loader": "^12.1.0",
|
|
28
|
+
"mini-css-extract-plugin": "^2.7.7",
|
|
29
|
+
"mobx": "^6.12.0",
|
|
30
|
+
"mobx-react-lite": "^4.0.5",
|
|
31
|
+
"node-notifier": "^8.0.1",
|
|
32
|
+
"null-loader": "^4.0.1",
|
|
33
|
+
"optimize-css-assets-webpack-plugin": "^6.0.1",
|
|
34
|
+
"react-dom": "^18.2.0",
|
|
35
|
+
"style-loader": "^3.3.4",
|
|
36
|
+
"ts-loader": "^9.5.1",
|
|
37
|
+
"ts-node": "^10.9.1",
|
|
38
|
+
"tsconfig-paths": "^4.2.0",
|
|
39
|
+
"tsconfig-paths-webpack-plugin": "^4.1.0",
|
|
40
|
+
"typescript": "4.9.3",
|
|
41
|
+
"webpack": "^5.90.0",
|
|
42
|
+
"webpack-cli": "^5.1.4",
|
|
43
|
+
"webpack-merge": "^5.10.0"
|
|
44
|
+
},
|
|
45
|
+
"gitHead": "4f90c6aaf6fa17ef25679ca24c879766663a2440"
|
|
46
|
+
}
|
package/src/ext-host.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
const ide_core_common_1 = require('../../../packages/core-common');
|
|
3
|
+
const ext_process_base_1 = require('../../../packages/extension/lib/hosted/ext.process-base');
|
|
4
|
+
|
|
5
|
+
const builtinCommands = [
|
|
6
|
+
{
|
|
7
|
+
id: 'test:builtinCommand:test',
|
|
8
|
+
handler: (args) => 'fake token',
|
|
9
|
+
},
|
|
10
|
+
];
|
|
11
|
+
ext_process_base_1.extProcessInit({
|
|
12
|
+
builtinCommands,
|
|
13
|
+
logLevel: ide_core_common_1.LogLevel.Info,
|
|
14
|
+
});
|
package/src/ext-host.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LogLevel } from '@opensumi/ide-core-common';
|
|
2
|
+
import { IBuiltInCommand, extProcessInit } from '@opensumi/ide-extension/lib/hosted/ext.process-base';
|
|
3
|
+
|
|
4
|
+
const builtinCommands: IBuiltInCommand[] = [
|
|
5
|
+
{
|
|
6
|
+
id: 'test:builtinCommand:test',
|
|
7
|
+
handler: {
|
|
8
|
+
handler: (args) => 'fake token',
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
extProcessInit({
|
|
14
|
+
builtinCommands,
|
|
15
|
+
logLevel: LogLevel.Info,
|
|
16
|
+
});
|
package/src/index.html
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>OpenSumi IDE</title>
|
|
6
|
+
<style>
|
|
7
|
+
html,
|
|
8
|
+
body {
|
|
9
|
+
margin: 0;
|
|
10
|
+
width: 100%;
|
|
11
|
+
height: 100%;
|
|
12
|
+
}
|
|
13
|
+
</style>
|
|
14
|
+
<script>
|
|
15
|
+
let savedColors = {};
|
|
16
|
+
try {
|
|
17
|
+
savedLayout = JSON.parse(localStorage.getItem('layout') || '{}');
|
|
18
|
+
savedColors = JSON.parse(localStorage.getItem('theme') || '{}');
|
|
19
|
+
} catch (err) {}
|
|
20
|
+
if (savedColors.editorBackground) {
|
|
21
|
+
document.getElementsByTagName('html')[0].style.backgroundColor = savedColors.editorBackground;
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<div id="main"></div>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { MonacoService } from '@opensumi/ide-core-browser/lib/monaco';
|
|
2
|
+
import {
|
|
3
|
+
EditorCollectionService,
|
|
4
|
+
EditorComponentRegistry,
|
|
5
|
+
EmptyDocCacheImpl,
|
|
6
|
+
IEditorDecorationCollectionService,
|
|
7
|
+
IEditorDocumentModelContentRegistry,
|
|
8
|
+
IEditorDocumentModelService,
|
|
9
|
+
IEditorFeatureRegistry,
|
|
10
|
+
ILanguageService,
|
|
11
|
+
ResourceService,
|
|
12
|
+
WorkbenchEditorService,
|
|
13
|
+
} from '@opensumi/ide-editor/lib/browser';
|
|
14
|
+
import { EditorComponentRegistryImpl } from '@opensumi/ide-editor/lib/browser/component';
|
|
15
|
+
import { EditorDocumentModelServiceImpl } from '@opensumi/ide-editor/lib/browser/doc-model/editor-document-model-service';
|
|
16
|
+
import { EditorDocumentModelContentRegistryImpl } from '@opensumi/ide-editor/lib/browser/doc-model/editor-document-registry';
|
|
17
|
+
import { EditorCollectionServiceImpl } from '@opensumi/ide-editor/lib/browser/editor-collection.service';
|
|
18
|
+
import { EditorDecorationCollectionService } from '@opensumi/ide-editor/lib/browser/editor.decoration.service';
|
|
19
|
+
import { EditorFeatureRegistryImpl } from '@opensumi/ide-editor/lib/browser/feature';
|
|
20
|
+
import { LanguageService } from '@opensumi/ide-editor/lib/browser/language/language.service';
|
|
21
|
+
import { ResourceServiceImpl } from '@opensumi/ide-editor/lib/browser/resource.service';
|
|
22
|
+
import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
|
|
23
|
+
import { IDocPersistentCacheProvider } from '@opensumi/ide-editor/lib/common';
|
|
24
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
25
|
+
import { MockWorkspaceService } from '@opensumi/ide-workspace/lib/common/mocks/workspace-service';
|
|
26
|
+
|
|
27
|
+
import { TestEditorDocumentProvider } from '../../../packages/editor/__tests__/browser/test-providers';
|
|
28
|
+
import { MockedMonacoService } from '../../../packages/monaco/__mocks__/monaco.service.mock';
|
|
29
|
+
|
|
30
|
+
import { MockInjector } from './mock-injector';
|
|
31
|
+
export function addEditorProviders(injector: MockInjector) {
|
|
32
|
+
injector.addProviders(
|
|
33
|
+
{
|
|
34
|
+
token: IDocPersistentCacheProvider,
|
|
35
|
+
useClass: EmptyDocCacheImpl,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
token: IEditorDocumentModelContentRegistry,
|
|
39
|
+
useClass: EditorDocumentModelContentRegistryImpl,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
token: IEditorDocumentModelService,
|
|
43
|
+
useClass: EditorDocumentModelServiceImpl,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
token: EditorCollectionService,
|
|
47
|
+
useClass: EditorCollectionServiceImpl,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
token: WorkbenchEditorService,
|
|
51
|
+
useClass: WorkbenchEditorServiceImpl,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
token: ResourceService,
|
|
55
|
+
useClass: ResourceServiceImpl,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
token: EditorComponentRegistry,
|
|
59
|
+
useClass: EditorComponentRegistryImpl,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
token: IEditorDecorationCollectionService,
|
|
63
|
+
useClass: EditorDecorationCollectionService,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
token: ILanguageService,
|
|
67
|
+
useClass: LanguageService,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
token: MonacoService,
|
|
71
|
+
useClass: MockedMonacoService,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
token: IWorkspaceService,
|
|
75
|
+
useClass: MockWorkspaceService,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
token: IEditorFeatureRegistry,
|
|
79
|
+
useClass: EditorFeatureRegistryImpl,
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
const editorDocModelRegistry: IEditorDocumentModelContentRegistry = injector.get(IEditorDocumentModelContentRegistry);
|
|
83
|
+
editorDocModelRegistry.registerEditorDocumentModelContentProvider(TestEditorDocumentProvider);
|
|
84
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { Injectable, Injector } from '@opensumi/di';
|
|
2
|
+
import { ClientApp } from '@opensumi/ide-core-browser/lib/bootstrap/app';
|
|
3
|
+
import { BrowserModule } from '@opensumi/ide-core-browser/lib/browser-module';
|
|
4
|
+
import { IContextKeyService } from '@opensumi/ide-core-browser/lib/context-key';
|
|
5
|
+
import { RecentFilesManager } from '@opensumi/ide-core-browser/lib/quick-open';
|
|
6
|
+
import {
|
|
7
|
+
CommonServerPath,
|
|
8
|
+
ConstructorOf,
|
|
9
|
+
ILogServiceManager,
|
|
10
|
+
ILogger,
|
|
11
|
+
ILoggerManagerClient,
|
|
12
|
+
LogLevel,
|
|
13
|
+
LogServiceForClientPath,
|
|
14
|
+
OS,
|
|
15
|
+
getDebugLogger,
|
|
16
|
+
} from '@opensumi/ide-core-common';
|
|
17
|
+
|
|
18
|
+
import { MockLogger, MockLoggerManageClient, MockLoggerService } from '../../../packages/core-browser/__mocks__/logger';
|
|
19
|
+
import { useMockStorage } from '../../../packages/core-browser/__mocks__/storage';
|
|
20
|
+
import { MockContextKeyService } from '../../../packages/monaco/__mocks__/monaco.context-key.service';
|
|
21
|
+
|
|
22
|
+
import { MockInjector } from './mock-injector';
|
|
23
|
+
|
|
24
|
+
@Injectable()
|
|
25
|
+
class MockMainLayout extends BrowserModule {}
|
|
26
|
+
|
|
27
|
+
export interface MockClientApp extends ClientApp {
|
|
28
|
+
injector: MockInjector;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function createBrowserApp(
|
|
32
|
+
modules: Array<ConstructorOf<BrowserModule>>,
|
|
33
|
+
inj?: MockInjector,
|
|
34
|
+
): Promise<MockClientApp> {
|
|
35
|
+
const injector = inj || new MockInjector();
|
|
36
|
+
// 需要依赖前后端模块
|
|
37
|
+
injector.addProviders(
|
|
38
|
+
{
|
|
39
|
+
token: ILoggerManagerClient,
|
|
40
|
+
useValue: {
|
|
41
|
+
getLogger() {
|
|
42
|
+
return getDebugLogger();
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
token: CommonServerPath,
|
|
48
|
+
useValue: {
|
|
49
|
+
getBackendOS: jest.fn(() => OS.Type.OSX),
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
const app = new ClientApp({
|
|
54
|
+
modules: [MockMainLayout, ...modules],
|
|
55
|
+
injector,
|
|
56
|
+
layoutConfig: {},
|
|
57
|
+
} as any) as MockClientApp;
|
|
58
|
+
await app.start(document.getElementById('main')!);
|
|
59
|
+
return app;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Injectable()
|
|
63
|
+
class MockLogServiceForClient {
|
|
64
|
+
private level: LogLevel;
|
|
65
|
+
|
|
66
|
+
hasDisposeAll = false;
|
|
67
|
+
|
|
68
|
+
async setGlobalLogLevel(level) {
|
|
69
|
+
this.level = level;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async getGlobalLogLevel() {
|
|
73
|
+
return this.level;
|
|
74
|
+
}
|
|
75
|
+
async getLevel() {
|
|
76
|
+
return this.level;
|
|
77
|
+
}
|
|
78
|
+
async setLevel(level: LogLevel) {
|
|
79
|
+
this.level = level;
|
|
80
|
+
}
|
|
81
|
+
async verbose() {
|
|
82
|
+
//
|
|
83
|
+
}
|
|
84
|
+
async debug() {}
|
|
85
|
+
async warn() {}
|
|
86
|
+
async log() {}
|
|
87
|
+
async error() {}
|
|
88
|
+
async critical() {}
|
|
89
|
+
async dispose() {}
|
|
90
|
+
async disposeAll() {
|
|
91
|
+
this.hasDisposeAll = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getBrowserMockInjector() {
|
|
96
|
+
const injector = new MockInjector();
|
|
97
|
+
useMockStorage(injector);
|
|
98
|
+
injector.addProviders(
|
|
99
|
+
{
|
|
100
|
+
token: IContextKeyService,
|
|
101
|
+
useClass: MockContextKeyService,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
token: RecentFilesManager,
|
|
105
|
+
useValue: {
|
|
106
|
+
getMostRecentlyOpenedFiles: () => [],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
token: LogServiceForClientPath,
|
|
111
|
+
useClass: MockLogServiceForClient,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
token: ILoggerManagerClient,
|
|
115
|
+
useClass: MockLoggerManageClient,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
token: ILogServiceManager,
|
|
119
|
+
useClass: MockLoggerService,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
token: ILogger,
|
|
123
|
+
useClass: MockLogger,
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
return injector;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function createBrowserInjector(modules: Array<ConstructorOf<BrowserModule>>, inj?: Injector): MockInjector {
|
|
130
|
+
const injector = inj || getBrowserMockInjector();
|
|
131
|
+
const app = new ClientApp({ modules, injector } as any);
|
|
132
|
+
afterAll(() => {
|
|
133
|
+
app.injector.disposeAll();
|
|
134
|
+
});
|
|
135
|
+
return app.injector as MockInjector;
|
|
136
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// 关于 resolver 的文档请看: https://jestjs.io/docs/configuration#resolver-string
|
|
2
|
+
|
|
3
|
+
module.exports = (path, options) =>
|
|
4
|
+
// Call the defaultResolver, so we leverage its cache, error handling, etc.
|
|
5
|
+
options.defaultResolver(path, {
|
|
6
|
+
...options,
|
|
7
|
+
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
|
|
8
|
+
packageFilter: (pkg) => {
|
|
9
|
+
if (pkg.name === 'nanoid') {
|
|
10
|
+
// 一个对于 jest@28 的 workaround,具体原因请见:https://github.com/microsoft/accessibility-insights-web/pull/5421/commits/9ad4e618019298d82732d49d00aafb846fb6bac7
|
|
11
|
+
delete pkg['exports'];
|
|
12
|
+
delete pkg['module'];
|
|
13
|
+
}
|
|
14
|
+
return pkg;
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// 会使用到的测试文件
|
|
2
|
+
// - packages/debug/__tests__/browser/debug-ansi-handle.test.ts
|
|
3
|
+
// 使用了 styles['code-bold'] 等
|
|
4
|
+
|
|
5
|
+
const idObj = new Proxy(
|
|
6
|
+
{
|
|
7
|
+
mod_selected: 'mod_selected',
|
|
8
|
+
mod_focused: 'mod_focused',
|
|
9
|
+
mod_loading: 'mod_loading',
|
|
10
|
+
mod_cut: 'mod_cut',
|
|
11
|
+
mod_dragging: 'mod_dragging',
|
|
12
|
+
mod_dragover: 'mod_dragover',
|
|
13
|
+
mod_dirty: 'mod_dirty',
|
|
14
|
+
mod_actived: 'mod_actived',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
get: function getter(target, key) {
|
|
18
|
+
if (key === '__esModule') {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return target[key] || key;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
module.exports = idObj;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { ConstructorOf, CreatorStatus, Injector, InstanceOpts, Token, TokenResult } from '@opensumi/di';
|
|
2
|
+
import { MockLoggerManageClient, MockLoggerService } from '@opensumi/ide-core-browser/__mocks__/logger';
|
|
3
|
+
import { CommandRegistry, ILogServiceManager, ILoggerManagerClient, getDebugLogger } from '@opensumi/ide-core-common';
|
|
4
|
+
import { INodeLogger, NodeModule, ServerApp } from '@opensumi/ide-core-node';
|
|
5
|
+
|
|
6
|
+
export class MockInjector extends Injector {
|
|
7
|
+
private mockMap = new Map<Token, [any, any][]>();
|
|
8
|
+
|
|
9
|
+
mock<T extends Token, K extends keyof TokenResult<T>>(token: T, method: K, value: TokenResult<T>[K]) {
|
|
10
|
+
if (this.hasCreated(token)) {
|
|
11
|
+
const instance = this.get(token);
|
|
12
|
+
Object.defineProperty(instance, method, {
|
|
13
|
+
get: () => value,
|
|
14
|
+
set: (v) => {
|
|
15
|
+
value = v;
|
|
16
|
+
},
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
const map: [any, any][] = this.mockMap.get(token) || [];
|
|
22
|
+
map.push([method, value]);
|
|
23
|
+
this.mockMap.set(token, map);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get<T extends ConstructorOf<any>>(token: T, args?: ConstructorParameters<T>, opts?: InstanceOpts): TokenResult<T>;
|
|
28
|
+
get<T extends Token>(token: T, opts?: InstanceOpts): TokenResult<T>;
|
|
29
|
+
get<T>(token: Token, opts?: InstanceOpts): T;
|
|
30
|
+
get(arg1: any, arg2?: any, arg3?: any) {
|
|
31
|
+
const instance = super.get(arg1, arg2, arg3);
|
|
32
|
+
const mockDefs = this.mockMap.get(arg1);
|
|
33
|
+
if (mockDefs) {
|
|
34
|
+
for (const mockDef of mockDefs) {
|
|
35
|
+
const method = mockDef[0];
|
|
36
|
+
let value = mockDef[1];
|
|
37
|
+
Object.defineProperty(instance, method, {
|
|
38
|
+
get: () => value,
|
|
39
|
+
set: (v) => {
|
|
40
|
+
value = v;
|
|
41
|
+
},
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
});
|
|
45
|
+
this.mockMap.delete(arg1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return instance;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private hasCreated(token: Token) {
|
|
52
|
+
const creator = this.creatorMap.get(token);
|
|
53
|
+
return creator && creator.status === CreatorStatus.done;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public mockCommand(commandId: string, fn?) {
|
|
57
|
+
const registry = this.get(CommandRegistry) as CommandRegistry;
|
|
58
|
+
if (registry.getCommand(commandId)) {
|
|
59
|
+
registry.unregisterCommand(commandId);
|
|
60
|
+
}
|
|
61
|
+
registry.registerCommand(
|
|
62
|
+
{
|
|
63
|
+
id: commandId,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
execute: (...args) => {
|
|
67
|
+
if (typeof fn === 'function') {
|
|
68
|
+
fn(...args);
|
|
69
|
+
} else if (typeof fn !== 'undefined') {
|
|
70
|
+
return fn;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public mockService(token: Token, proxyObj: any = {}) {
|
|
78
|
+
this.addProviders({
|
|
79
|
+
token,
|
|
80
|
+
useValue: mockService(proxyObj),
|
|
81
|
+
override: true,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function mockService<T = any>(target: Partial<T>): any {
|
|
87
|
+
return new Proxy(target, {
|
|
88
|
+
get: (t, p) => {
|
|
89
|
+
if (p === 'hasOwnProperty') {
|
|
90
|
+
return t[p];
|
|
91
|
+
}
|
|
92
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
93
|
+
if (!t.hasOwnProperty(p)) {
|
|
94
|
+
t[p] = jest.fn();
|
|
95
|
+
}
|
|
96
|
+
return t[p];
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getNodeMockInjector() {
|
|
102
|
+
const injector = new MockInjector();
|
|
103
|
+
injector.addProviders(
|
|
104
|
+
{
|
|
105
|
+
token: ILoggerManagerClient,
|
|
106
|
+
useClass: MockLoggerManageClient,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
token: ILogServiceManager,
|
|
110
|
+
useClass: MockLoggerService,
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
token: INodeLogger,
|
|
114
|
+
useValue: getDebugLogger(),
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
return injector;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function createNodeInjector(modules: Array<ConstructorOf<NodeModule>>, inj?: Injector): MockInjector {
|
|
121
|
+
const injector = inj || getNodeMockInjector();
|
|
122
|
+
const app = new ServerApp({ modules, injector } as any);
|
|
123
|
+
|
|
124
|
+
afterAll(() => {
|
|
125
|
+
app.injector.disposeAll();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return app.injector as MockInjector;
|
|
129
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
'use strict';
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
class LogServiceClass {
|
|
5
|
+
constructor(args) {
|
|
6
|
+
console.log('LogServiceClass args', args);
|
|
7
|
+
}
|
|
8
|
+
debug(...args) {
|
|
9
|
+
console.log('LogServiceClass debug', ...args);
|
|
10
|
+
}
|
|
11
|
+
error(...args) {
|
|
12
|
+
console.log('LogServiceClass error', ...args);
|
|
13
|
+
}
|
|
14
|
+
log(...args) {
|
|
15
|
+
console.log('LogServiceClass log', ...args);
|
|
16
|
+
}
|
|
17
|
+
warn(...args) {
|
|
18
|
+
console.log('LogServiceClass warn', ...args);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = LogServiceClass;
|
|
22
|
+
// # sourceMappingURL=mock-log-service.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { ILogServiceOptions } from '@opensumi/ide-core-common';
|
|
3
|
+
|
|
4
|
+
export default class LogServiceClass {
|
|
5
|
+
constructor(args: ILogServiceOptions) {
|
|
6
|
+
console.log('LogServiceClass args', args);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
debug(...args) {
|
|
10
|
+
console.log('LogServiceClass debug', ...args);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
error(...args) {
|
|
14
|
+
console.log('LogServiceClass error', ...args);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
log(...args) {
|
|
18
|
+
console.log('LogServiceClass log', ...args);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
warn(...args) {
|
|
22
|
+
console.log('LogServiceClass warn', ...args);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
import Koa from 'koa';
|
|
6
|
+
import KoaRouter from 'koa-router';
|
|
7
|
+
import Static from 'koa-static';
|
|
8
|
+
|
|
9
|
+
import { Injector, Provider } from '@opensumi/di';
|
|
10
|
+
import { Deferred } from '@opensumi/ide-core-common';
|
|
11
|
+
import { IServerAppOpts, NodeModule, ServerApp } from '@opensumi/ide-core-node';
|
|
12
|
+
import {
|
|
13
|
+
IExternalFileArgs,
|
|
14
|
+
IExternalUrlArgs,
|
|
15
|
+
IRemoteOpenerClient,
|
|
16
|
+
RemoteOpenerClientToken,
|
|
17
|
+
RemoteOpenerServiceToken,
|
|
18
|
+
} from '@opensumi/ide-remote-opener/lib/common';
|
|
19
|
+
import { RemoteOpenerServiceImpl } from '@opensumi/ide-remote-opener/lib/node';
|
|
20
|
+
|
|
21
|
+
export async function startServer(
|
|
22
|
+
arg1: NodeModule[] | Partial<IServerAppOpts>,
|
|
23
|
+
options?: {
|
|
24
|
+
mountStaticPath?: string;
|
|
25
|
+
injector?: Provider;
|
|
26
|
+
},
|
|
27
|
+
) {
|
|
28
|
+
const app = new Koa();
|
|
29
|
+
const router = new KoaRouter();
|
|
30
|
+
const deferred = new Deferred<http.Server>();
|
|
31
|
+
|
|
32
|
+
router.get('/open', (ctx) => {
|
|
33
|
+
const openerService: IRemoteOpenerClient = injector.get(RemoteOpenerClientToken);
|
|
34
|
+
try {
|
|
35
|
+
console.log('received open request', ctx.query);
|
|
36
|
+
openerService.openExternal(
|
|
37
|
+
ctx.query as unknown as IExternalFileArgs | IExternalUrlArgs,
|
|
38
|
+
ctx.query.clientId as unknown as string,
|
|
39
|
+
);
|
|
40
|
+
ctx.body = 'successful';
|
|
41
|
+
} catch (err: any) {
|
|
42
|
+
ctx.body = `Error: ${err.message}`;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
app.use(router.routes());
|
|
47
|
+
|
|
48
|
+
if (options && options.mountStaticPath) {
|
|
49
|
+
console.log('mount static path:', options.mountStaticPath);
|
|
50
|
+
app.use(Static(options.mountStaticPath));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const injector = new Injector([
|
|
54
|
+
{
|
|
55
|
+
token: RemoteOpenerServiceToken,
|
|
56
|
+
useClass: RemoteOpenerServiceImpl,
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const port = process.env.PORT || process.env.IDE_SERVER_PORT || 8000;
|
|
61
|
+
let opts: IServerAppOpts = {
|
|
62
|
+
webSocketHandler: [
|
|
63
|
+
// new TerminalHandler(logger),
|
|
64
|
+
],
|
|
65
|
+
injector,
|
|
66
|
+
use: app.use.bind(app),
|
|
67
|
+
marketplace: {
|
|
68
|
+
showBuiltinExtensions: true,
|
|
69
|
+
},
|
|
70
|
+
processCloseExitThreshold: 5 * 60 * 1000,
|
|
71
|
+
terminalPtyCloseThreshold: 5 * 60 * 1000,
|
|
72
|
+
staticAllowOrigin: '*',
|
|
73
|
+
staticAllowPath: [
|
|
74
|
+
path.join(__dirname, '../../../packages/extension'),
|
|
75
|
+
path.join(__dirname, '../../../tools/extensions'),
|
|
76
|
+
'/',
|
|
77
|
+
],
|
|
78
|
+
extLogServiceClassPath: path.join(__dirname, './mock-log-service.js'),
|
|
79
|
+
/**
|
|
80
|
+
* 集成时可使用自定义的 extHost 入口传入内置 command
|
|
81
|
+
* extHost: path.join(__dirname, './ext-host.js') || process.env.EXTENSION_HOST_ENTRY,
|
|
82
|
+
*/
|
|
83
|
+
extHost:
|
|
84
|
+
process.env.EXTENSION_HOST_ENTRY || path.join(__dirname, '../../../packages/extension/lib/hosted/ext.process.js'),
|
|
85
|
+
onDidCreateExtensionHostProcess: (extHostProcess) => {
|
|
86
|
+
console.log(`Extension host process ${extHostProcess.pid} created`);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (Array.isArray(arg1)) {
|
|
91
|
+
opts = {
|
|
92
|
+
...opts,
|
|
93
|
+
modulesInstances: arg1,
|
|
94
|
+
};
|
|
95
|
+
} else {
|
|
96
|
+
opts = {
|
|
97
|
+
...opts,
|
|
98
|
+
...arg1,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const serverApp = new ServerApp(opts);
|
|
103
|
+
// server 必须在 ServerApp 实例化后才能创建,因为依赖 app 里收集的中间件
|
|
104
|
+
const server = http.createServer(app.callback());
|
|
105
|
+
|
|
106
|
+
await serverApp.start(server);
|
|
107
|
+
|
|
108
|
+
server.on('error', (err) => {
|
|
109
|
+
deferred.reject(err);
|
|
110
|
+
console.error('server error: ' + err.message);
|
|
111
|
+
setTimeout(process.exit, 0, 1);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
server.listen(port, () => {
|
|
115
|
+
console.log(`server listen on http://localhost:${port}`);
|
|
116
|
+
deferred.resolve(server);
|
|
117
|
+
});
|
|
118
|
+
return deferred.promise;
|
|
119
|
+
}
|
package/src/webpack.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
6
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
7
|
+
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
|
8
|
+
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
9
|
+
const webpack = require('webpack');
|
|
10
|
+
const { merge } = require('webpack-merge');
|
|
11
|
+
|
|
12
|
+
const reactPath = path.resolve(path.join(__dirname, '../../../node_modules/react'));
|
|
13
|
+
const reactDOMPath = path.resolve(path.join(__dirname, '../../../node_modules/react-dom'));
|
|
14
|
+
const tsConfigPath = path.join(__dirname, '../../../tsconfig.json');
|
|
15
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
16
|
+
const IDE_FRONT_PORT = process.env.IDE_FRONT_PORT || 8080;
|
|
17
|
+
|
|
18
|
+
const defaultWorkspace = path.join(__dirname, '../../workspace');
|
|
19
|
+
fse.mkdirpSync(defaultWorkspace);
|
|
20
|
+
|
|
21
|
+
const withSlash = process.platform === 'win32' ? '/' : '';
|
|
22
|
+
|
|
23
|
+
const styleLoader =
|
|
24
|
+
process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : require.resolve('style-loader');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {string} dir
|
|
29
|
+
* @param {string} entry
|
|
30
|
+
* @param {import('webpack').Configuration} extraConfig
|
|
31
|
+
* @returns {import('webpack').Configuration}
|
|
32
|
+
*/
|
|
33
|
+
exports.createWebpackConfig = function (dir, entry, extraConfig) {
|
|
34
|
+
console.log('front port', IDE_FRONT_PORT);
|
|
35
|
+
|
|
36
|
+
const webpackConfig = merge(
|
|
37
|
+
{
|
|
38
|
+
entry,
|
|
39
|
+
output: {
|
|
40
|
+
filename: 'bundle.js',
|
|
41
|
+
path: dir + '/dist',
|
|
42
|
+
},
|
|
43
|
+
cache: {
|
|
44
|
+
type: 'filesystem',
|
|
45
|
+
},
|
|
46
|
+
resolve: {
|
|
47
|
+
extensions: ['.ts', '.tsx', '.js', '.json', '.less'],
|
|
48
|
+
plugins: [
|
|
49
|
+
new TsconfigPathsPlugin({
|
|
50
|
+
configFile: tsConfigPath,
|
|
51
|
+
}),
|
|
52
|
+
],
|
|
53
|
+
alias: {
|
|
54
|
+
react: reactPath,
|
|
55
|
+
'react-dom': reactDOMPath,
|
|
56
|
+
},
|
|
57
|
+
fallback: {
|
|
58
|
+
net: false,
|
|
59
|
+
path: false,
|
|
60
|
+
os: false,
|
|
61
|
+
crypto: false,
|
|
62
|
+
child_process: false,
|
|
63
|
+
url: false,
|
|
64
|
+
fs: false,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
bail: true,
|
|
68
|
+
mode: 'development',
|
|
69
|
+
devtool: 'source-map',
|
|
70
|
+
module: {
|
|
71
|
+
// https://github.com/webpack/webpack/issues/196#issuecomment-397606728
|
|
72
|
+
exprContextCritical: false,
|
|
73
|
+
rules: [
|
|
74
|
+
{
|
|
75
|
+
test: /\.tsx?$/,
|
|
76
|
+
use: [
|
|
77
|
+
{
|
|
78
|
+
loader: 'ts-loader',
|
|
79
|
+
options: {
|
|
80
|
+
happyPackMode: true,
|
|
81
|
+
transpileOnly: true,
|
|
82
|
+
configFile: tsConfigPath,
|
|
83
|
+
compilerOptions: {
|
|
84
|
+
target: 'es2015',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
test: /\.png$/,
|
|
92
|
+
type: 'asset/resource',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
test: /\.css$/,
|
|
96
|
+
use: [styleLoader, 'css-loader'],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
test: /\.module.less$/,
|
|
100
|
+
use: [
|
|
101
|
+
styleLoader,
|
|
102
|
+
{
|
|
103
|
+
loader: 'css-loader',
|
|
104
|
+
options: {
|
|
105
|
+
importLoaders: 1,
|
|
106
|
+
sourceMap: true,
|
|
107
|
+
modules: {
|
|
108
|
+
localIdentName: '[local]___[hash:base64:5]',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
loader: 'less-loader',
|
|
114
|
+
options: {
|
|
115
|
+
lessOptions: {
|
|
116
|
+
javascriptEnabled: true,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
test: /^((?!\.module).)*less$/,
|
|
124
|
+
use: [
|
|
125
|
+
styleLoader,
|
|
126
|
+
{
|
|
127
|
+
loader: 'css-loader',
|
|
128
|
+
options: {
|
|
129
|
+
importLoaders: 1,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
loader: 'less-loader',
|
|
134
|
+
options: {
|
|
135
|
+
lessOptions: {
|
|
136
|
+
javascriptEnabled: true,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
test: /\.svg$/,
|
|
144
|
+
type: 'asset/resource',
|
|
145
|
+
generator: {
|
|
146
|
+
filename: 'images/[name][ext][query]',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
|
|
151
|
+
type: 'asset/resource',
|
|
152
|
+
generator: {
|
|
153
|
+
filename: 'fonts/[name][ext][query]',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
resolveLoader: {
|
|
159
|
+
modules: [
|
|
160
|
+
path.join(__dirname, '../../../node_modules'),
|
|
161
|
+
path.join(__dirname, '../node_modules'),
|
|
162
|
+
path.resolve('node_modules'),
|
|
163
|
+
],
|
|
164
|
+
extensions: ['.ts', '.tsx', '.js', '.json', '.less'],
|
|
165
|
+
mainFields: ['loader', 'main'],
|
|
166
|
+
},
|
|
167
|
+
optimization: {
|
|
168
|
+
nodeEnv: process.env.NODE_ENV,
|
|
169
|
+
minimize: false,
|
|
170
|
+
},
|
|
171
|
+
plugins: [
|
|
172
|
+
new HtmlWebpackPlugin({
|
|
173
|
+
template: __dirname + '/index.html',
|
|
174
|
+
}),
|
|
175
|
+
new MiniCssExtractPlugin({
|
|
176
|
+
filename: '[name].[chunkhash:8].css',
|
|
177
|
+
chunkFilename: '[id].css',
|
|
178
|
+
}),
|
|
179
|
+
new webpack.DefinePlugin({
|
|
180
|
+
'process.env.IS_DEV': JSON.stringify(process.env.NODE_ENV === 'development' ? 1 : 0),
|
|
181
|
+
'process.env.WORKSPACE_DIR': JSON.stringify(process.env.MY_WORKSPACE || defaultWorkspace),
|
|
182
|
+
'process.env.SUPPORT_LOAD_WORKSPACE_BY_HASH': JSON.stringify(process.env.SUPPORT_LOAD_WORKSPACE_BY_HASH),
|
|
183
|
+
'process.env.EXTENSION_DIR': JSON.stringify(path.join(__dirname, '../../extensions')),
|
|
184
|
+
'process.env.KTLOG_SHOW_DEBUG': JSON.stringify('1'),
|
|
185
|
+
'process.env.OTHER_EXTENSION_DIR': JSON.stringify(path.join(__dirname, '../../../other')),
|
|
186
|
+
'process.env.EXTENSION_WORKER_HOST': JSON.stringify(
|
|
187
|
+
process.env.EXTENSION_WORKER_HOST ||
|
|
188
|
+
`http://${HOST}:8080/assets` +
|
|
189
|
+
withSlash +
|
|
190
|
+
path.join(__dirname, '../../../packages/extension/lib/worker-host.js'),
|
|
191
|
+
),
|
|
192
|
+
'process.env.WS_PATH': JSON.stringify(process.env.WS_PATH || `ws://${HOST}:8000`),
|
|
193
|
+
'process.env.WEBVIEW_HOST': JSON.stringify(process.env.WEBVIEW_HOST || HOST),
|
|
194
|
+
'process.env.STATIC_SERVER_PATH': JSON.stringify(process.env.STATIC_SERVER_PATH || `http://${HOST}:8000/`),
|
|
195
|
+
'process.env.HOST': JSON.stringify(process.env.HOST),
|
|
196
|
+
}),
|
|
197
|
+
!process.env.SKIP_TS_CHECKER &&
|
|
198
|
+
new ForkTsCheckerWebpackPlugin({
|
|
199
|
+
typescript: {
|
|
200
|
+
diagnosticOptions: {
|
|
201
|
+
syntactic: true,
|
|
202
|
+
},
|
|
203
|
+
configFile: tsConfigPath,
|
|
204
|
+
},
|
|
205
|
+
issue: {
|
|
206
|
+
include: (issue) => issue.file.includes('src/packages/'),
|
|
207
|
+
exclude: (issue) => issue.file.includes('__test__'),
|
|
208
|
+
},
|
|
209
|
+
}),
|
|
210
|
+
new NodePolyfillPlugin({
|
|
211
|
+
includeAliases: ['process', 'Buffer'],
|
|
212
|
+
}),
|
|
213
|
+
!process.env.CI && new webpack.ProgressPlugin(),
|
|
214
|
+
process.env.analysis && new BundleAnalyzerPlugin(),
|
|
215
|
+
].filter(Boolean),
|
|
216
|
+
devServer: {
|
|
217
|
+
static: {
|
|
218
|
+
directory: dir + '/dist',
|
|
219
|
+
},
|
|
220
|
+
host: HOST,
|
|
221
|
+
port: IDE_FRONT_PORT,
|
|
222
|
+
allowedHosts: 'all',
|
|
223
|
+
devMiddleware: {
|
|
224
|
+
stats: 'errors-only',
|
|
225
|
+
},
|
|
226
|
+
proxy: {
|
|
227
|
+
'/api': {
|
|
228
|
+
target: `http://${HOST}:8000`,
|
|
229
|
+
},
|
|
230
|
+
'/extension': {
|
|
231
|
+
target: `http://${HOST}:8000`,
|
|
232
|
+
},
|
|
233
|
+
'/assets': {
|
|
234
|
+
target: `http://${HOST}:8000`,
|
|
235
|
+
},
|
|
236
|
+
'/kaitian': {
|
|
237
|
+
target: `http://${HOST}:8000`,
|
|
238
|
+
},
|
|
239
|
+
'/socket.io': {
|
|
240
|
+
ws: true,
|
|
241
|
+
target: `ws://${HOST}:8000`,
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
open: process.env.SUMI_DEV_OPEN_BROWSER ? true : false,
|
|
245
|
+
hot: true,
|
|
246
|
+
client: {
|
|
247
|
+
overlay: {
|
|
248
|
+
errors: true,
|
|
249
|
+
warnings: false,
|
|
250
|
+
runtimeErrors: false,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
extraConfig || {},
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
return webpackConfig;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @returns {import('webpack').Configuration}
|
|
263
|
+
*/
|
|
264
|
+
exports.createWebviewWebpackConfig = (entry, dir, outputPath = '/dist') => {
|
|
265
|
+
const port = 8899;
|
|
266
|
+
return {
|
|
267
|
+
entry,
|
|
268
|
+
output: {
|
|
269
|
+
filename: 'webview.js',
|
|
270
|
+
path: dir + outputPath,
|
|
271
|
+
},
|
|
272
|
+
cache: {
|
|
273
|
+
type: 'filesystem',
|
|
274
|
+
},
|
|
275
|
+
resolve: {
|
|
276
|
+
extensions: ['.ts', '.tsx', '.js', '.json', '.less'],
|
|
277
|
+
plugins: [
|
|
278
|
+
new TsconfigPathsPlugin({
|
|
279
|
+
configFile: tsConfigPath,
|
|
280
|
+
}),
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
bail: true,
|
|
284
|
+
mode: 'development',
|
|
285
|
+
devtool: 'source-map',
|
|
286
|
+
module: {
|
|
287
|
+
// https://github.com/webpack/webpack/issues/196#issuecomment-397606728
|
|
288
|
+
exprContextCritical: false,
|
|
289
|
+
rules: [
|
|
290
|
+
{
|
|
291
|
+
test: /\.tsx?$/,
|
|
292
|
+
loader: 'ts-loader',
|
|
293
|
+
options: {
|
|
294
|
+
happyPackMode: true,
|
|
295
|
+
transpileOnly: true,
|
|
296
|
+
configFile: tsConfigPath,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
resolveLoader: {
|
|
302
|
+
modules: [
|
|
303
|
+
path.join(__dirname, '../../../node_modules'),
|
|
304
|
+
path.join(__dirname, '../node_modules'),
|
|
305
|
+
path.resolve('node_modules'),
|
|
306
|
+
],
|
|
307
|
+
extensions: ['.ts', '.tsx', '.js', '.json', '.less'],
|
|
308
|
+
mainFields: ['loader', 'main'],
|
|
309
|
+
},
|
|
310
|
+
plugins: [
|
|
311
|
+
new HtmlWebpackPlugin({
|
|
312
|
+
template: path.dirname(entry) + '/webview.html',
|
|
313
|
+
}),
|
|
314
|
+
new NodePolyfillPlugin({
|
|
315
|
+
includeAliases: ['process', 'Buffer'],
|
|
316
|
+
}),
|
|
317
|
+
],
|
|
318
|
+
devServer: {
|
|
319
|
+
static: {
|
|
320
|
+
directory: dir + '/public',
|
|
321
|
+
},
|
|
322
|
+
allowedHosts: 'all',
|
|
323
|
+
port,
|
|
324
|
+
host: HOST,
|
|
325
|
+
open: false,
|
|
326
|
+
hot: true,
|
|
327
|
+
client: {
|
|
328
|
+
overlay: {
|
|
329
|
+
errors: true,
|
|
330
|
+
warnings: false,
|
|
331
|
+
runtimeErrors: false,
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* @returns {import('webpack').Configuration}
|
|
340
|
+
*/
|
|
341
|
+
exports.createNodeWebpackConfig = (entry, distDir) => ({
|
|
342
|
+
entry,
|
|
343
|
+
target: 'node',
|
|
344
|
+
output: {
|
|
345
|
+
filename: 'server.js',
|
|
346
|
+
path: distDir,
|
|
347
|
+
},
|
|
348
|
+
node: false,
|
|
349
|
+
mode: 'production',
|
|
350
|
+
optimization: {
|
|
351
|
+
minimize: false,
|
|
352
|
+
},
|
|
353
|
+
cache: {
|
|
354
|
+
type: 'filesystem',
|
|
355
|
+
},
|
|
356
|
+
watch: false,
|
|
357
|
+
resolve: {
|
|
358
|
+
modules: [
|
|
359
|
+
path.join(__dirname, '../../../node_modules'),
|
|
360
|
+
path.join(__dirname, '../node_modules'),
|
|
361
|
+
path.resolve('node_modules'),
|
|
362
|
+
],
|
|
363
|
+
extensions: ['.ts', '.tsx', '.js', '.json'],
|
|
364
|
+
plugins: [
|
|
365
|
+
new TsconfigPathsPlugin({
|
|
366
|
+
configFile: tsConfigPath,
|
|
367
|
+
}),
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
module: {
|
|
371
|
+
exprContextCritical: false,
|
|
372
|
+
rules: [
|
|
373
|
+
{
|
|
374
|
+
test: /\.tsx?$/,
|
|
375
|
+
use: [
|
|
376
|
+
{
|
|
377
|
+
loader: 'ts-loader',
|
|
378
|
+
options: {
|
|
379
|
+
happyPackMode: true,
|
|
380
|
+
transpileOnly: true,
|
|
381
|
+
configFile: tsConfigPath,
|
|
382
|
+
compilerOptions: {
|
|
383
|
+
target: 'es2016',
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
],
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
},
|
|
391
|
+
externals: [
|
|
392
|
+
function ({ request }, callback) {
|
|
393
|
+
if (
|
|
394
|
+
[
|
|
395
|
+
'node-pty',
|
|
396
|
+
'oniguruma',
|
|
397
|
+
'@parcel/watcher',
|
|
398
|
+
'nsfw',
|
|
399
|
+
'spdlog',
|
|
400
|
+
'vm2',
|
|
401
|
+
'canvas',
|
|
402
|
+
'@opensumi/vscode-ripgrep',
|
|
403
|
+
'vertx',
|
|
404
|
+
'keytar',
|
|
405
|
+
'tsconfig-paths',
|
|
406
|
+
].indexOf(request) !== -1
|
|
407
|
+
) {
|
|
408
|
+
return callback(null, `commonjs ${request}`);
|
|
409
|
+
}
|
|
410
|
+
callback();
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
resolveLoader: {
|
|
414
|
+
extensions: ['.ts', '.tsx', '.js', '.json'],
|
|
415
|
+
mainFields: ['loader', 'main'],
|
|
416
|
+
modules: [
|
|
417
|
+
path.join(__dirname, '../../../node_modules'),
|
|
418
|
+
path.join(__dirname, '../node_modules'),
|
|
419
|
+
path.resolve('node_modules'),
|
|
420
|
+
],
|
|
421
|
+
},
|
|
422
|
+
plugins: [!process.env.CI && new webpack.ProgressPlugin()],
|
|
423
|
+
});
|