1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | import * as env from './environment.js'
|
8 | import * as symbol from './symbol.js'
|
9 | import * as pair from './pair.js'
|
10 | import * as dom from './dom.js'
|
11 | import * as json from './json.js'
|
12 | import * as map from './map.js'
|
13 | import * as eventloop from './eventloop.js'
|
14 | import * as math from './math.js'
|
15 | import * as time from './time.js'
|
16 | import * as func from './function.js'
|
17 |
|
18 | export const BOLD = symbol.create()
|
19 | export const UNBOLD = symbol.create()
|
20 | export const BLUE = symbol.create()
|
21 | export const GREY = symbol.create()
|
22 | export const GREEN = symbol.create()
|
23 | export const RED = symbol.create()
|
24 | export const PURPLE = symbol.create()
|
25 | export const ORANGE = symbol.create()
|
26 | export const UNCOLOR = symbol.create()
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | const _browserStyleMap = {
|
32 | [BOLD]: pair.create('font-weight', 'bold'),
|
33 | [UNBOLD]: pair.create('font-weight', 'normal'),
|
34 | [BLUE]: pair.create('color', 'blue'),
|
35 | [GREEN]: pair.create('color', 'green'),
|
36 | [GREY]: pair.create('color', 'grey'),
|
37 | [RED]: pair.create('color', 'red'),
|
38 | [PURPLE]: pair.create('color', 'purple'),
|
39 | [ORANGE]: pair.create('color', 'orange'),
|
40 | [UNCOLOR]: pair.create('color', 'black')
|
41 | }
|
42 |
|
43 | const _nodeStyleMap = {
|
44 | [BOLD]: '\u001b[1m',
|
45 | [UNBOLD]: '\u001b[2m',
|
46 | [BLUE]: '\x1b[34m',
|
47 | [GREEN]: '\x1b[32m',
|
48 | [GREY]: '\u001b[37m',
|
49 | [RED]: '\x1b[31m',
|
50 | [PURPLE]: '\x1b[35m',
|
51 | [ORANGE]: '\x1b[38;5;208m',
|
52 | [UNCOLOR]: '\x1b[0m'
|
53 | }
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | const computeBrowserLoggingArgs = args => {
|
61 | const strBuilder = []
|
62 | const styles = []
|
63 | const currentStyle = map.create()
|
64 | |
65 |
|
66 |
|
67 | let logArgs = []
|
68 |
|
69 | let i = 0
|
70 |
|
71 | for (; i < args.length; i++) {
|
72 | const arg = args[i]
|
73 |
|
74 | const style = _browserStyleMap[arg]
|
75 | if (style !== undefined) {
|
76 | currentStyle.set(style.left, style.right)
|
77 | } else {
|
78 | if (arg.constructor === String || arg.constructor === Number) {
|
79 | const style = dom.mapToStyleString(currentStyle)
|
80 | if (i > 0 || style.length > 0) {
|
81 | strBuilder.push('%c' + arg)
|
82 | styles.push(style)
|
83 | } else {
|
84 | strBuilder.push(arg)
|
85 | }
|
86 | } else {
|
87 | break
|
88 | }
|
89 | }
|
90 | }
|
91 |
|
92 | if (i > 0) {
|
93 |
|
94 | logArgs = styles
|
95 | logArgs.unshift(strBuilder.join(''))
|
96 | }
|
97 |
|
98 | for (; i < args.length; i++) {
|
99 | const arg = args[i]
|
100 | if (!(arg instanceof Symbol)) {
|
101 | logArgs.push(arg)
|
102 | }
|
103 | }
|
104 | return logArgs
|
105 | }
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | const computeNodeLoggingArgs = args => {
|
112 | const strBuilder = []
|
113 | const logArgs = []
|
114 |
|
115 |
|
116 | let i = 0
|
117 |
|
118 | for (; i < args.length; i++) {
|
119 | const arg = args[i]
|
120 |
|
121 | const style = _nodeStyleMap[arg]
|
122 | if (style !== undefined) {
|
123 | strBuilder.push(style)
|
124 | } else {
|
125 | if (arg.constructor === String || arg.constructor === Number) {
|
126 | strBuilder.push(arg)
|
127 | } else {
|
128 | break
|
129 | }
|
130 | }
|
131 | }
|
132 | if (i > 0) {
|
133 |
|
134 | strBuilder.push('\x1b[0m')
|
135 | logArgs.push(strBuilder.join(''))
|
136 | }
|
137 |
|
138 | for (; i < args.length; i++) {
|
139 | const arg = args[i]
|
140 |
|
141 | if (!(arg instanceof Symbol)) {
|
142 | logArgs.push(arg)
|
143 | }
|
144 | }
|
145 | return logArgs
|
146 | }
|
147 |
|
148 |
|
149 | const computeLoggingArgs = env.isNode ? computeNodeLoggingArgs : computeBrowserLoggingArgs
|
150 |
|
151 |
|
152 |
|
153 |
|
154 | export const print = (...args) => {
|
155 | console.log(...computeLoggingArgs(args))
|
156 |
|
157 | vconsoles.forEach(vc => vc.print(args))
|
158 | }
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | export const warn = (...args) => {
|
165 | console.warn(...computeLoggingArgs(args))
|
166 | args.unshift(ORANGE)
|
167 | vconsoles.forEach(vc => vc.print(args))
|
168 | }
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 | export const printError = err => {
|
175 | console.error(err)
|
176 | vconsoles.forEach(vc => vc.printError(err))
|
177 | }
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 | export const printImg = (url, height) => {
|
185 | if (env.isBrowser) {
|
186 | console.log('%c ', `font-size: ${height}px; background-size: contain; background-repeat: no-repeat; background-image: url(${url})`)
|
187 |
|
188 | }
|
189 | vconsoles.forEach(vc => vc.printImg(url, height))
|
190 | }
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | export const printImgBase64 = (base64, height) => printImg(`data:image/gif;base64,${base64}`, height)
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | export const group = (...args) => {
|
203 | console.group(...computeLoggingArgs(args))
|
204 |
|
205 | vconsoles.forEach(vc => vc.group(args))
|
206 | }
|
207 |
|
208 |
|
209 |
|
210 |
|
211 | export const groupCollapsed = (...args) => {
|
212 | console.groupCollapsed(...computeLoggingArgs(args))
|
213 |
|
214 | vconsoles.forEach(vc => vc.groupCollapsed(args))
|
215 | }
|
216 |
|
217 | export const groupEnd = () => {
|
218 | console.groupEnd()
|
219 |
|
220 | vconsoles.forEach(vc => vc.groupEnd())
|
221 | }
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | export const printDom = createNode =>
|
228 | vconsoles.forEach(vc => vc.printDom(createNode()))
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | export const printCanvas = (canvas, height) => printImg(canvas.toDataURL(), height)
|
236 |
|
237 | export const vconsoles = new Set()
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 |
|
244 | const _computeLineSpans = args => {
|
245 | const spans = []
|
246 | const currentStyle = new Map()
|
247 |
|
248 | let i = 0
|
249 | for (; i < args.length; i++) {
|
250 | const arg = args[i]
|
251 |
|
252 | const style = _browserStyleMap[arg]
|
253 | if (style !== undefined) {
|
254 | currentStyle.set(style.left, style.right)
|
255 | } else {
|
256 | if (arg.constructor === String || arg.constructor === Number) {
|
257 |
|
258 | const span = dom.element('span', [pair.create('style', dom.mapToStyleString(currentStyle))], [dom.text(arg)])
|
259 | if (span.innerHTML === '') {
|
260 | span.innerHTML = ' '
|
261 | }
|
262 | spans.push(span)
|
263 | } else {
|
264 | break
|
265 | }
|
266 | }
|
267 | }
|
268 |
|
269 | for (; i < args.length; i++) {
|
270 | let content = args[i]
|
271 | if (!(content instanceof Symbol)) {
|
272 | if (content.constructor !== String && content.constructor !== Number) {
|
273 | content = ' ' + json.stringify(content) + ' '
|
274 | }
|
275 | spans.push(dom.element('span', [], [dom.text( (content))]))
|
276 | }
|
277 | }
|
278 | return spans
|
279 | }
|
280 |
|
281 | const lineStyle = 'font-family:monospace;border-bottom:1px solid #e2e2e2;padding:2px;'
|
282 |
|
283 |
|
284 | export class VConsole {
|
285 | |
286 |
|
287 |
|
288 | constructor (dom) {
|
289 | this.dom = dom
|
290 | |
291 |
|
292 |
|
293 | this.ccontainer = this.dom
|
294 | this.depth = 0
|
295 | vconsoles.add(this)
|
296 | }
|
297 |
|
298 | |
299 |
|
300 |
|
301 |
|
302 | group (args, collapsed = false) {
|
303 | eventloop.enqueue(() => {
|
304 | const triangleDown = dom.element('span', [pair.create('hidden', collapsed), pair.create('style', 'color:grey;font-size:120%;')], [dom.text('▼')])
|
305 | const triangleRight = dom.element('span', [pair.create('hidden', !collapsed), pair.create('style', 'color:grey;font-size:125%;')], [dom.text('▶')])
|
306 | const content = dom.element('div', [pair.create('style', `${lineStyle};padding-left:${this.depth * 10}px`)], [triangleDown, triangleRight, dom.text(' ')].concat(_computeLineSpans(args)))
|
307 | const nextContainer = dom.element('div', [pair.create('hidden', collapsed)])
|
308 | const nextLine = dom.element('div', [], [content, nextContainer])
|
309 | dom.append(this.ccontainer, [nextLine])
|
310 | this.ccontainer = nextContainer
|
311 | this.depth++
|
312 |
|
313 | dom.addEventListener(content, 'click', event => {
|
314 | nextContainer.toggleAttribute('hidden')
|
315 | triangleDown.toggleAttribute('hidden')
|
316 | triangleRight.toggleAttribute('hidden')
|
317 | })
|
318 | })
|
319 | }
|
320 |
|
321 | |
322 |
|
323 |
|
324 | groupCollapsed (args) {
|
325 | this.group(args, true)
|
326 | }
|
327 |
|
328 | groupEnd () {
|
329 | eventloop.enqueue(() => {
|
330 | if (this.depth > 0) {
|
331 | this.depth--
|
332 |
|
333 | this.ccontainer = this.ccontainer.parentElement.parentElement
|
334 | }
|
335 | })
|
336 | }
|
337 |
|
338 | |
339 |
|
340 |
|
341 | print (args) {
|
342 | eventloop.enqueue(() => {
|
343 | dom.append(this.ccontainer, [dom.element('div', [pair.create('style', `${lineStyle};padding-left:${this.depth * 10}px`)], _computeLineSpans(args))])
|
344 | })
|
345 | }
|
346 |
|
347 | |
348 |
|
349 |
|
350 | printError (err) {
|
351 | this.print([RED, BOLD, err.toString()])
|
352 | }
|
353 |
|
354 | |
355 |
|
356 |
|
357 |
|
358 | printImg (url, height) {
|
359 | eventloop.enqueue(() => {
|
360 | dom.append(this.ccontainer, [dom.element('img', [pair.create('src', url), pair.create('height', `${math.round(height * 1.5)}px`)])])
|
361 | })
|
362 | }
|
363 |
|
364 | |
365 |
|
366 |
|
367 | printDom (node) {
|
368 | eventloop.enqueue(() => {
|
369 | dom.append(this.ccontainer, [node])
|
370 | })
|
371 | }
|
372 |
|
373 | destroy () {
|
374 | eventloop.enqueue(() => {
|
375 | vconsoles.delete(this)
|
376 | })
|
377 | }
|
378 | }
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 | export const createVConsole = dom => new VConsole(dom)
|
385 |
|
386 | const loggingColors = [GREEN, PURPLE, ORANGE, BLUE]
|
387 | let nextColor = 0
|
388 | let lastLoggingTime = time.getUnixTime()
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 | export const createModuleLogger = moduleName => {
|
395 | const color = loggingColors[nextColor]
|
396 | const debugRegexVar = env.getVariable('log')
|
397 | const doLogging = debugRegexVar !== null && (debugRegexVar === '*' || debugRegexVar === 'true' || new RegExp(debugRegexVar, 'gi').test(moduleName))
|
398 | nextColor = (nextColor + 1) % loggingColors.length
|
399 | moduleName += ': '
|
400 |
|
401 | return !doLogging ? func.nop : (...args) => {
|
402 | const timeNow = time.getUnixTime()
|
403 | const timeDiff = timeNow - lastLoggingTime
|
404 | lastLoggingTime = timeNow
|
405 | print(color, moduleName, UNCOLOR, ...args.map(arg => (typeof arg === 'string' || typeof arg === 'symbol') ? arg : JSON.stringify(arg)), color, ' +' + timeDiff + 'ms')
|
406 | }
|
407 | }
|