-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathcompilerOptions.ts
198 lines (164 loc) · 6.38 KB
/
compilerOptions.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import { SandboxConfig } from "."
type CompilerOptions = import("monaco-editor").languages.typescript.CompilerOptions
type Monaco = typeof import("monaco-editor")
/**
* These are the defaults, but they also act as the list of all compiler options
* which are parsed in the query params.
*/
export function getDefaultSandboxCompilerOptions(config: SandboxConfig, monaco: Monaco) {
const useJavaScript = config.filetype === "js"
const settings: CompilerOptions = {
strict: true,
noImplicitAny: true,
strictNullChecks: !useJavaScript,
strictFunctionTypes: true,
strictPropertyInitialization: true,
strictBindCallApply: true,
noImplicitThis: true,
noImplicitReturns: true,
noUncheckedIndexedAccess: false,
// 3.7 off, 3.8 on I think
useDefineForClassFields: false,
alwaysStrict: true,
allowUnreachableCode: false,
allowUnusedLabels: false,
downlevelIteration: false,
noEmitHelpers: false,
noLib: false,
noStrictGenericChecks: false,
noUnusedLocals: false,
noUnusedParameters: false,
esModuleInterop: true,
preserveConstEnums: false,
removeComments: false,
skipLibCheck: false,
checkJs: useJavaScript,
allowJs: useJavaScript,
declaration: true,
importHelpers: false,
experimentalDecorators: true,
emitDecoratorMetadata: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
target: monaco.languages.typescript.ScriptTarget.ES2017,
jsx: monaco.languages.typescript.JsxEmit.React,
module: monaco.languages.typescript.ModuleKind.ESNext,
}
return { ...settings, ...config.compilerOptions }
}
/**
* Loop through all of the entries in the existing compiler options then compare them with the
* query params and return an object which is the changed settings via the query params
*/
export const getCompilerOptionsFromParams = (
playgroundDefaults: CompilerOptions,
ts: typeof import("typescript"),
params: URLSearchParams
): CompilerOptions => {
const returnedOptions: CompilerOptions = {}
params.forEach((val, key) => {
// First use the defaults object to drop compiler flags which are already set to the default
if (playgroundDefaults[key]) {
let toSet = undefined
if (val === "true" && playgroundDefaults[key] !== true) {
toSet = true
} else if (val === "false" && playgroundDefaults[key] !== false) {
toSet = false
} else if (!isNaN(parseInt(val, 10)) && playgroundDefaults[key] !== parseInt(val, 10)) {
toSet = parseInt(val, 10)
}
if (toSet !== undefined) returnedOptions[key] = toSet
} else {
// If that doesn't work, double check that the flag exists and allow it through
// @ts-ignore
const flagExists = ts.optionDeclarations.find(opt => opt.name === key)
if (flagExists) {
let realValue: number | boolean = true
if (val === "false") realValue = false
if (!isNaN(parseInt(val, 10))) realValue = parseInt(val, 10)
returnedOptions[key] = realValue
}
}
})
return returnedOptions
}
// Can't set sandbox to be the right type because the param would contain this function
/** Gets a query string representation (hash + queries) */
export const createURLQueryWithCompilerOptions = (_sandbox: any, paramOverrides?: any): string => {
const sandbox = _sandbox as import("./index").Sandbox
const initialOptions = new URLSearchParams(document.location.search)
const compilerOptions = sandbox.getCompilerOptions()
const compilerDefaults = sandbox.compilerDefaults
const diff = Object.entries(compilerOptions).reduce((acc, [key, value]) => {
if (value !== compilerDefaults[key]) {
// @ts-ignore
acc[key] = compilerOptions[key]
}
return acc
}, {})
// The text of the TS/JS as the hash
const hash = `code/${sandbox.lzstring.compressToEncodedURIComponent(sandbox.getText())}`
let urlParams: any = Object.assign({}, diff)
for (const param of ["lib", "ts"]) {
const params = new URLSearchParams(location.search)
if (params.has(param)) {
// Special case the nightly where it uses the TS version to hardcode
// the nightly build
if (param === "ts" && (params.get(param) === "Nightly" || params.get(param) === "next")) {
urlParams["ts"] = sandbox.ts.version
} else {
urlParams["ts"] = params.get(param)
}
}
}
// Support sending the selection, but only if there is a selection, and it's not the whole thing
const s = sandbox.editor.getSelection()
const isNotEmpty =
(s && s.selectionStartLineNumber !== s.positionLineNumber) || (s && s.selectionStartColumn !== s.positionColumn)
const range = sandbox.editor.getModel()!.getFullModelRange()
const isFull =
s &&
s.selectionStartLineNumber === range.startLineNumber &&
s.selectionStartColumn === range.startColumn &&
s.positionColumn === range.endColumn &&
s.positionLineNumber === range.endLineNumber
if (s && isNotEmpty && !isFull) {
urlParams["ssl"] = s.selectionStartLineNumber
urlParams["ssc"] = s.selectionStartColumn
urlParams["pln"] = s.positionLineNumber
urlParams["pc"] = s.positionColumn
} else {
urlParams["ssl"] = undefined
urlParams["ssc"] = undefined
urlParams["pln"] = undefined
urlParams["pc"] = undefined
}
if (sandbox.config.filetype !== "ts") urlParams["filetype"] = sandbox.config.filetype
if (paramOverrides) {
urlParams = { ...urlParams, ...paramOverrides }
}
// @ts-ignore - this is in MDN but not libdom
const hasInitialOpts = initialOptions.keys().length > 0
if (Object.keys(urlParams).length > 0 || hasInitialOpts) {
let queryString = Object.entries(urlParams)
.filter(([_k, v]) => v !== undefined)
.filter(([_k, v]) => v !== null)
.map(([key, value]) => {
return `${key}=${encodeURIComponent(value as string)}`
})
.join("&")
// We want to keep around custom query variables, which
// are usually used by playground plugins, with the exception
// being the install-plugin param and any compiler options
// which have a default value
initialOptions.forEach((value, key) => {
const skip = ["ssl", "ssc", "pln", "pc"]
if (skip.includes(key)) return
if (queryString.includes(key)) return
if (compilerOptions[key]) return
queryString += `&${key}=${value}`
})
return `?${queryString}#${hash}`
} else {
return `#${hash}`
}
}