/
useSandboxServices.ts
121 lines (103 loc) · 3.38 KB
/
useSandboxServices.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { useEffect, useState } from 'react';
import type Monaco from 'monaco-editor';
import type { TSESLint } from '@typescript-eslint/utils';
import type { RuleDetails } from '../types';
import type {
createTypeScriptSandbox,
SandboxConfig,
} from '../../vendor/sandbox';
import { WebLinter } from '../linter/WebLinter';
import { sandboxSingleton } from './loadSandbox';
import { editorEmbedId } from './EditorEmbed';
import { useColorMode } from '@docusaurus/theme-common';
import { createCompilerOptions } from '@site/src/components/editor/config';
export interface SandboxServicesProps {
readonly jsx?: boolean;
readonly onLoaded: (
ruleDetails: RuleDetails[],
tsVersions: readonly string[],
) => void;
readonly ts: string;
}
export type SandboxInstance = ReturnType<typeof createTypeScriptSandbox>;
export interface SandboxServices {
fixes: Map<string, TSESLint.Linter.LintMessage>;
main: typeof Monaco;
sandboxInstance: SandboxInstance;
webLinter: WebLinter;
}
export const useSandboxServices = (
props: SandboxServicesProps,
): Error | SandboxServices | undefined => {
const [services, setServices] = useState<Error | SandboxServices>();
const [loadedTs, setLoadedTs] = useState<string>(props.ts);
const { colorMode } = useColorMode();
useEffect(() => {
if (props.ts !== loadedTs) {
window.location.reload();
}
}, [props.ts, loadedTs]);
useEffect(() => {
const fixes = new Map<string, TSESLint.Linter.LintMessage>();
let sandboxInstance: SandboxInstance | undefined;
setLoadedTs(props.ts);
sandboxSingleton(props.ts)
.then(async ({ main, sandboxFactory, ts, lintUtils }) => {
const compilerOptions = createCompilerOptions(props.jsx);
const sandboxConfig: Partial<SandboxConfig> = {
text: '',
monacoSettings: {
minimap: { enabled: false },
fontSize: 13,
wordWrap: 'off',
scrollBeyondLastLine: false,
smoothScrolling: true,
},
compilerOptions: compilerOptions,
domID: editorEmbedId,
};
sandboxInstance = sandboxFactory.createTypeScriptSandbox(
sandboxConfig,
main,
ts,
);
sandboxInstance.monaco.editor.setTheme(
colorMode === 'dark' ? 'vs-dark' : 'vs-light',
);
const libMap = await sandboxInstance.tsvfs.createDefaultMapFromCDN(
sandboxInstance.getCompilerOptions(),
props.ts,
true,
window.ts,
);
const system = sandboxInstance.tsvfs.createSystem(libMap);
const webLinter = new WebLinter(system, compilerOptions, lintUtils);
props.onLoaded(webLinter.ruleNames, sandboxInstance.supportedVersions);
setServices({
fixes,
main,
sandboxInstance,
webLinter,
});
})
.catch(setServices);
return (): void => {
if (!sandboxInstance) {
return;
}
const editorModel = sandboxInstance.editor.getModel()!;
sandboxInstance.monaco.editor.setModelMarkers(
editorModel,
sandboxInstance.editor.getId(),
[],
);
sandboxInstance.editor.dispose();
editorModel.dispose();
const models = sandboxInstance.monaco.editor.getModels();
for (const model of models) {
model.dispose();
}
};
}, [props.ts]);
return services;
};