tjs-lang 0.2.8 → 0.3.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/demo/docs.json +20 -14
- package/demo/src/examples.ts +23 -83
- package/demo/src/playground-shared.ts +666 -0
- package/demo/src/tjs-playground.ts +52 -528
- package/demo/src/ts-examples.ts +5 -4
- package/demo/src/ts-playground.ts +50 -414
- package/dist/index.js +58 -23
- package/dist/index.js.map +9 -9
- package/dist/src/lang/types.d.ts +1 -1
- package/dist/src/types/Type.d.ts +3 -1
- package/dist/tjs-full.js +58 -23
- package/dist/tjs-full.js.map +9 -9
- package/dist/tjs-transpiler.js +55 -20
- package/dist/tjs-transpiler.js.map +7 -7
- package/dist/tjs-vm.js +14 -14
- package/dist/tjs-vm.js.map +5 -5
- package/docs/index.js +740 -1010
- package/docs/index.js.map +9 -8
- package/editors/codemirror/ajs-language.ts +27 -1
- package/editors/codemirror/autocomplete.test.ts +3 -3
- package/package.json +1 -1
- package/src/lang/codegen.test.ts +11 -11
- package/src/lang/emitters/from-ts.ts +1 -1
- package/src/lang/emitters/js.ts +74 -0
- package/src/lang/inference.ts +40 -8
- package/src/lang/lang.test.ts +154 -16
- package/src/lang/runtime.ts +7 -0
- package/src/lang/types.ts +2 -0
- package/src/lang/typescript-syntax.test.ts +6 -4
- package/src/types/Type.test.ts +64 -0
- package/src/types/Type.ts +22 -1
- package/src/use-cases/transpiler-integration.test.ts +10 -10
- package/src/vm/atoms/batteries.ts +2 -0
|
@@ -21,6 +21,14 @@ import { fromTS } from '../../src/lang/emitters/from-ts'
|
|
|
21
21
|
import { tjs } from '../../src/lang'
|
|
22
22
|
import { extractImports, resolveImports } from './imports'
|
|
23
23
|
import { generateDocsMarkdown } from './docs-utils'
|
|
24
|
+
import {
|
|
25
|
+
buildIframeDoc,
|
|
26
|
+
createIframeMessageHandler,
|
|
27
|
+
renderConsoleMessages,
|
|
28
|
+
renderTestResults,
|
|
29
|
+
formatExecTime,
|
|
30
|
+
sharedPlaygroundStyles,
|
|
31
|
+
} from './playground-shared'
|
|
24
32
|
|
|
25
33
|
const { div, button, span, pre, input } = elements
|
|
26
34
|
|
|
@@ -292,42 +300,11 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
292
300
|
}
|
|
293
301
|
|
|
294
302
|
private renderConsole() {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const html = this.consoleMessages
|
|
301
|
-
.map((msg) => {
|
|
302
|
-
// Escape HTML
|
|
303
|
-
const escaped = msg
|
|
304
|
-
.replace(/&/g, '&')
|
|
305
|
-
.replace(/</g, '<')
|
|
306
|
-
.replace(/>/g, '>')
|
|
307
|
-
|
|
308
|
-
// Replace line references with clickable spans
|
|
309
|
-
return escaped.replace(linePattern, (match, l1, c1, l2, c2) => {
|
|
310
|
-
const line = l1 || l2
|
|
311
|
-
const col = c1 || c2 || '1'
|
|
312
|
-
return `<span class="clickable-line" data-line="${line}" data-col="${col}">${match}</span>`
|
|
313
|
-
})
|
|
314
|
-
})
|
|
315
|
-
.join('\n')
|
|
316
|
-
|
|
317
|
-
this.parts.console.innerHTML = html
|
|
318
|
-
this.parts.console.scrollTop = this.parts.console.scrollHeight
|
|
319
|
-
|
|
320
|
-
// Add click handlers
|
|
321
|
-
this.parts.console.querySelectorAll('.clickable-line').forEach((el) => {
|
|
322
|
-
el.addEventListener('click', (e) => {
|
|
323
|
-
const target = e.currentTarget as HTMLElement
|
|
324
|
-
const line = parseInt(target.dataset.line || '0', 10)
|
|
325
|
-
const col = parseInt(target.dataset.col || '1', 10)
|
|
326
|
-
if (line > 0) {
|
|
327
|
-
this.goToSourceLine(line, col)
|
|
328
|
-
}
|
|
329
|
-
})
|
|
330
|
-
})
|
|
303
|
+
renderConsoleMessages(
|
|
304
|
+
this.consoleMessages,
|
|
305
|
+
this.parts.console,
|
|
306
|
+
(line, col) => this.goToSourceLine(line, col)
|
|
307
|
+
)
|
|
331
308
|
}
|
|
332
309
|
|
|
333
310
|
// Navigate to a specific line in the source editor
|
|
@@ -407,11 +384,9 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
407
384
|
this.updateDocs(jsResult)
|
|
408
385
|
|
|
409
386
|
// Show timing: TS->TJS + TJS->JS = total
|
|
410
|
-
|
|
411
|
-
t < 1 ? `${(t * 1000).toFixed(0)}μs` : `${t.toFixed(2)}ms`
|
|
412
|
-
this.parts.statusBar.textContent = `TS→TJS ${formatTime(
|
|
387
|
+
this.parts.statusBar.textContent = `TS→TJS ${formatExecTime(
|
|
413
388
|
this.lastTsToTjsTime
|
|
414
|
-
)} + TJS→JS ${
|
|
389
|
+
)} + TJS→JS ${formatExecTime(this.lastTjsToJsTime)} = ${formatExecTime(
|
|
415
390
|
this.lastTranspileTime
|
|
416
391
|
)}`
|
|
417
392
|
this.parts.statusBar.classList.remove('error')
|
|
@@ -456,69 +431,12 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
456
431
|
}
|
|
457
432
|
|
|
458
433
|
private updateTestResults(tests: any[]) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
this.parts.
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const passed = tests.filter((t) => t.passed).length
|
|
466
|
-
const failed = tests.filter((t) => !t.passed).length
|
|
467
|
-
|
|
468
|
-
// Set gutter markers for failed tests
|
|
469
|
-
const failedTests = tests.filter((t: any) => !t.passed && t.line)
|
|
470
|
-
if (failedTests.length > 0) {
|
|
471
|
-
this.parts.tsEditor.setMarkers(
|
|
472
|
-
failedTests.map((t: any) => ({
|
|
473
|
-
line: t.line,
|
|
474
|
-
message: t.error || t.description,
|
|
475
|
-
severity: 'error' as const,
|
|
476
|
-
}))
|
|
477
|
-
)
|
|
478
|
-
} else {
|
|
479
|
-
this.parts.tsEditor.clearMarkers()
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
let html = `<div class="test-summary">`
|
|
483
|
-
html += `<strong>${passed} passed</strong>`
|
|
484
|
-
if (failed > 0) {
|
|
485
|
-
html += `, <strong class="test-failed">${failed} failed</strong>`
|
|
486
|
-
}
|
|
487
|
-
html += `</div><ul class="test-list">`
|
|
488
|
-
|
|
489
|
-
for (const test of tests) {
|
|
490
|
-
const icon = test.passed ? '✓' : '✗'
|
|
491
|
-
const cls = test.passed ? 'test-pass' : 'test-fail'
|
|
492
|
-
const sigBadge = test.isSignatureTest
|
|
493
|
-
? ' <span class="sig-badge">signature</span>'
|
|
494
|
-
: ''
|
|
495
|
-
const dataLine = test.line ? ` data-line="${test.line}"` : ''
|
|
496
|
-
html += `<li class="${cls}"${dataLine}>${icon} ${test.description}${sigBadge}`
|
|
497
|
-
if (!test.passed && test.error) {
|
|
498
|
-
html += `<div class="test-error${
|
|
499
|
-
test.line ? ' clickable-error' : ''
|
|
500
|
-
}"${dataLine}>${test.error}</div>`
|
|
501
|
-
}
|
|
502
|
-
html += `</li>`
|
|
503
|
-
}
|
|
504
|
-
html += `</ul>`
|
|
505
|
-
|
|
506
|
-
this.parts.testsOutput.innerHTML = html
|
|
507
|
-
|
|
508
|
-
// Add click handlers for clickable errors
|
|
509
|
-
this.parts.testsOutput
|
|
510
|
-
.querySelectorAll('.clickable-error')
|
|
511
|
-
.forEach((el) => {
|
|
512
|
-
el.addEventListener('click', (e) => {
|
|
513
|
-
const line = parseInt(
|
|
514
|
-
(e.currentTarget as HTMLElement).dataset.line || '0',
|
|
515
|
-
10
|
|
516
|
-
)
|
|
517
|
-
if (line > 0) {
|
|
518
|
-
this.goToSourceLine(line)
|
|
519
|
-
}
|
|
520
|
-
})
|
|
521
|
-
})
|
|
434
|
+
renderTestResults(
|
|
435
|
+
tests,
|
|
436
|
+
this.parts.testsOutput,
|
|
437
|
+
this.parts.tsEditor,
|
|
438
|
+
(line) => this.goToSourceLine(line)
|
|
439
|
+
)
|
|
522
440
|
}
|
|
523
441
|
|
|
524
442
|
private updateDocs(result: any) {
|
|
@@ -557,6 +475,9 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
557
475
|
return
|
|
558
476
|
}
|
|
559
477
|
|
|
478
|
+
// Show JS output immediately after successful transpilation
|
|
479
|
+
this.parts.outputTabs.value = 1 // JS is second tab (index 1)
|
|
480
|
+
|
|
560
481
|
this.parts.statusBar.textContent = 'Running...'
|
|
561
482
|
|
|
562
483
|
try {
|
|
@@ -586,87 +507,30 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
586
507
|
}
|
|
587
508
|
|
|
588
509
|
// Create iframe document
|
|
589
|
-
const iframeDoc =
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
<body>
|
|
596
|
-
${htmlContent}
|
|
597
|
-
<script type="module">
|
|
598
|
-
// TJS Runtime stub for iframe execution
|
|
599
|
-
globalThis.__tjs = {
|
|
600
|
-
version: '0.0.0',
|
|
601
|
-
pushStack: () => {},
|
|
602
|
-
popStack: () => {},
|
|
603
|
-
getStack: () => [],
|
|
604
|
-
typeError: (path, expected, value) => {
|
|
605
|
-
const actual = value === null ? 'null' : typeof value;
|
|
606
|
-
const err = new Error(\`Expected \${expected} for '\${path}', got \${actual}\`);
|
|
607
|
-
err.name = 'MonadicError';
|
|
608
|
-
err.path = path;
|
|
609
|
-
err.expected = expected;
|
|
610
|
-
err.actual = actual;
|
|
611
|
-
return err;
|
|
612
|
-
},
|
|
613
|
-
createRuntime: function() { return this; },
|
|
614
|
-
Is: (a, b) => {
|
|
615
|
-
if (a === b) return true;
|
|
616
|
-
if (a === null || b === null) return a === b;
|
|
617
|
-
if (typeof a !== typeof b) return false;
|
|
618
|
-
if (typeof a !== 'object') return false;
|
|
619
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
620
|
-
if (a.length !== b.length) return false;
|
|
621
|
-
return a.every((v, i) => globalThis.__tjs.Is(v, b[i]));
|
|
622
|
-
}
|
|
623
|
-
const keysA = Object.keys(a);
|
|
624
|
-
const keysB = Object.keys(b);
|
|
625
|
-
if (keysA.length !== keysB.length) return false;
|
|
626
|
-
return keysA.every(k => globalThis.__tjs.Is(a[k], b[k]));
|
|
627
|
-
},
|
|
628
|
-
IsNot: (a, b) => !globalThis.__tjs.Is(a, b),
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
// Capture console.log
|
|
632
|
-
const _log = console.log;
|
|
633
|
-
console.log = (...args) => {
|
|
634
|
-
_log(...args);
|
|
635
|
-
parent.postMessage({ type: 'console', message: args.map(a =>
|
|
636
|
-
typeof a === 'object' ? JSON.stringify(a, null, 2) : String(a)
|
|
637
|
-
).join(' ') }, '*');
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
try {
|
|
641
|
-
const __execStart = performance.now();
|
|
642
|
-
${jsCode}
|
|
643
|
-
const __execTime = performance.now() - __execStart;
|
|
644
|
-
parent.postMessage({ type: 'timing', execTime: __execTime }, '*');
|
|
645
|
-
} catch (e) {
|
|
646
|
-
parent.postMessage({ type: 'error', message: e.message }, '*');
|
|
647
|
-
}
|
|
648
|
-
</script>
|
|
649
|
-
</body>
|
|
650
|
-
</html>`
|
|
510
|
+
const iframeDoc = buildIframeDoc({
|
|
511
|
+
cssContent,
|
|
512
|
+
htmlContent,
|
|
513
|
+
importMapScript,
|
|
514
|
+
jsCode,
|
|
515
|
+
})
|
|
651
516
|
|
|
652
517
|
// Listen for messages from iframe
|
|
653
|
-
const messageHandler = (
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
this.log(`Error: ${event.data.message}`)
|
|
518
|
+
const messageHandler = createIframeMessageHandler({
|
|
519
|
+
onConsole: (message) => this.log(message),
|
|
520
|
+
onTiming: (execTime) => {
|
|
521
|
+
this.parts.consoleHeader.textContent = `Console — executed in ${formatExecTime(
|
|
522
|
+
execTime
|
|
523
|
+
)}`
|
|
524
|
+
},
|
|
525
|
+
onPreviewContent: () => {
|
|
526
|
+
this.parts.outputTabs.value = 2 // Preview is third tab (index 2)
|
|
527
|
+
},
|
|
528
|
+
onError: (message) => {
|
|
529
|
+
this.log(`Error: ${message}`)
|
|
666
530
|
this.parts.statusBar.textContent = 'Runtime error'
|
|
667
531
|
this.parts.statusBar.classList.add('error')
|
|
668
|
-
}
|
|
669
|
-
}
|
|
532
|
+
},
|
|
533
|
+
})
|
|
670
534
|
window.addEventListener('message', messageHandler)
|
|
671
535
|
|
|
672
536
|
// Set iframe content
|
|
@@ -675,7 +539,6 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
675
539
|
// Wait a bit for execution, then clean up listener
|
|
676
540
|
setTimeout(() => {
|
|
677
541
|
window.removeEventListener('message', messageHandler)
|
|
678
|
-
// Don't overwrite status bar - keep showing transpile time
|
|
679
542
|
}, 1000)
|
|
680
543
|
} catch (e: any) {
|
|
681
544
|
this.log(`Error: ${e.message}`)
|
|
@@ -728,16 +591,9 @@ export class TSPlayground extends Component<TSPlaygroundParts> {
|
|
|
728
591
|
export const tsPlayground = TSPlayground.elementCreator({
|
|
729
592
|
tag: 'ts-playground',
|
|
730
593
|
styleSpec: {
|
|
731
|
-
|
|
732
|
-
display: 'flex',
|
|
733
|
-
flexDirection: 'column',
|
|
734
|
-
height: '100%',
|
|
735
|
-
flex: '1 1 auto',
|
|
736
|
-
background: 'var(--background, #fff)',
|
|
737
|
-
color: 'var(--text-color, #1f2937)',
|
|
738
|
-
fontFamily: 'system-ui, sans-serif',
|
|
739
|
-
},
|
|
594
|
+
...sharedPlaygroundStyles,
|
|
740
595
|
|
|
596
|
+
// TS-specific: toolbar
|
|
741
597
|
':host .ts-toolbar': {
|
|
742
598
|
display: 'flex',
|
|
743
599
|
alignItems: 'center',
|
|
@@ -747,96 +603,14 @@ export const tsPlayground = TSPlayground.elementCreator({
|
|
|
747
603
|
borderBottom: '1px solid var(--code-border, #e5e7eb)',
|
|
748
604
|
},
|
|
749
605
|
|
|
750
|
-
|
|
751
|
-
display: 'flex',
|
|
752
|
-
alignItems: 'center',
|
|
753
|
-
gap: '4px',
|
|
754
|
-
padding: '6px 12px',
|
|
755
|
-
background: 'var(--brand-color, #3178c6)', // TypeScript blue
|
|
756
|
-
color: 'var(--brand-text-color, white)',
|
|
757
|
-
border: 'none',
|
|
758
|
-
borderRadius: '6px',
|
|
759
|
-
cursor: 'pointer',
|
|
760
|
-
fontWeight: '500',
|
|
761
|
-
fontSize: '14px',
|
|
762
|
-
},
|
|
763
|
-
|
|
764
|
-
':host .run-btn:hover': {
|
|
765
|
-
filter: 'brightness(1.1)',
|
|
766
|
-
},
|
|
767
|
-
|
|
768
|
-
':host .toolbar-separator': {
|
|
769
|
-
width: '1px',
|
|
770
|
-
height: '20px',
|
|
771
|
-
background: 'var(--code-border, #d1d5db)',
|
|
772
|
-
},
|
|
773
|
-
|
|
774
|
-
':host .build-flags': {
|
|
775
|
-
display: 'flex',
|
|
776
|
-
alignItems: 'center',
|
|
777
|
-
gap: '12px',
|
|
778
|
-
},
|
|
779
|
-
|
|
780
|
-
':host .flag-label': {
|
|
781
|
-
display: 'flex',
|
|
782
|
-
alignItems: 'center',
|
|
783
|
-
gap: '4px',
|
|
784
|
-
fontSize: '13px',
|
|
785
|
-
color: 'var(--text-color, #6b7280)',
|
|
786
|
-
cursor: 'pointer',
|
|
787
|
-
userSelect: 'none',
|
|
788
|
-
},
|
|
789
|
-
|
|
790
|
-
':host .flag-label:hover': {
|
|
791
|
-
color: 'var(--text-color, #374151)',
|
|
792
|
-
},
|
|
793
|
-
|
|
606
|
+
// TS-specific: TypeScript blue brand color for checkboxes
|
|
794
607
|
':host .flag-label input[type="checkbox"]': {
|
|
795
608
|
margin: '0',
|
|
796
609
|
cursor: 'pointer',
|
|
797
610
|
accentColor: 'var(--brand-color, #3178c6)',
|
|
798
611
|
},
|
|
799
612
|
|
|
800
|
-
|
|
801
|
-
display: 'flex',
|
|
802
|
-
alignItems: 'center',
|
|
803
|
-
gap: '4px',
|
|
804
|
-
padding: '6px 12px',
|
|
805
|
-
background: 'var(--code-background, #e5e7eb)',
|
|
806
|
-
color: 'var(--text-color, #374151)',
|
|
807
|
-
border: '1px solid var(--code-border, #d1d5db)',
|
|
808
|
-
borderRadius: '6px',
|
|
809
|
-
cursor: 'pointer',
|
|
810
|
-
fontWeight: '500',
|
|
811
|
-
fontSize: '14px',
|
|
812
|
-
transition: 'opacity 0.2s',
|
|
813
|
-
},
|
|
814
|
-
|
|
815
|
-
':host .revert-btn:hover:not(:disabled)': {
|
|
816
|
-
background: '#fef3c7',
|
|
817
|
-
borderColor: '#f59e0b',
|
|
818
|
-
color: '#92400e',
|
|
819
|
-
},
|
|
820
|
-
|
|
821
|
-
':host .revert-btn:disabled': {
|
|
822
|
-
cursor: 'default',
|
|
823
|
-
},
|
|
824
|
-
|
|
825
|
-
':host .elastic': {
|
|
826
|
-
flex: '1',
|
|
827
|
-
},
|
|
828
|
-
|
|
829
|
-
':host .status-bar': {
|
|
830
|
-
fontSize: '13px',
|
|
831
|
-
color: 'var(--text-color, #6b7280)',
|
|
832
|
-
opacity: '0.7',
|
|
833
|
-
},
|
|
834
|
-
|
|
835
|
-
':host .status-bar.error': {
|
|
836
|
-
color: '#dc2626',
|
|
837
|
-
opacity: '1',
|
|
838
|
-
},
|
|
839
|
-
|
|
613
|
+
// TS-specific: layout
|
|
840
614
|
':host .ts-main': {
|
|
841
615
|
display: 'flex',
|
|
842
616
|
flex: '1 1 auto',
|
|
@@ -862,28 +636,7 @@ export const tsPlayground = TSPlayground.elementCreator({
|
|
|
862
636
|
height: '100%',
|
|
863
637
|
},
|
|
864
638
|
|
|
865
|
-
|
|
866
|
-
background: 'var(--background, #fff)',
|
|
867
|
-
color: 'var(--text-color, #1f2937)',
|
|
868
|
-
},
|
|
869
|
-
|
|
870
|
-
':host .editor-wrapper': {
|
|
871
|
-
flex: '1 1 auto',
|
|
872
|
-
height: '100%',
|
|
873
|
-
minHeight: '300px',
|
|
874
|
-
position: 'relative',
|
|
875
|
-
overflow: 'hidden',
|
|
876
|
-
},
|
|
877
|
-
|
|
878
|
-
':host .editor-wrapper code-mirror': {
|
|
879
|
-
display: 'block',
|
|
880
|
-
position: 'absolute',
|
|
881
|
-
top: '0',
|
|
882
|
-
left: '0',
|
|
883
|
-
right: '0',
|
|
884
|
-
bottom: '0',
|
|
885
|
-
},
|
|
886
|
-
|
|
639
|
+
// TS-specific: TJS output toolbar and buttons
|
|
887
640
|
':host .output-toolbar': {
|
|
888
641
|
display: 'flex',
|
|
889
642
|
gap: '8px',
|
|
@@ -926,129 +679,12 @@ export const tsPlayground = TSPlayground.elementCreator({
|
|
|
926
679
|
background: 'var(--background, #fff)',
|
|
927
680
|
},
|
|
928
681
|
|
|
929
|
-
|
|
930
|
-
width: '100%',
|
|
931
|
-
height: '100%',
|
|
932
|
-
border: 'none',
|
|
933
|
-
},
|
|
934
|
-
|
|
935
|
-
':host .docs-output': {
|
|
936
|
-
display: 'block',
|
|
937
|
-
padding: '12px 16px',
|
|
938
|
-
fontSize: '14px',
|
|
939
|
-
fontFamily: 'system-ui, sans-serif',
|
|
940
|
-
color: 'var(--text-color, inherit)',
|
|
941
|
-
background: 'var(--background, #fff)',
|
|
942
|
-
height: '100%',
|
|
943
|
-
overflow: 'auto',
|
|
944
|
-
},
|
|
945
|
-
|
|
946
|
-
':host .tests-output': {
|
|
947
|
-
padding: '12px',
|
|
948
|
-
fontSize: '14px',
|
|
949
|
-
fontFamily: 'system-ui, sans-serif',
|
|
950
|
-
color: 'var(--text-color, inherit)',
|
|
951
|
-
background: 'var(--background, #fff)',
|
|
952
|
-
height: '100%',
|
|
953
|
-
overflow: 'auto',
|
|
954
|
-
},
|
|
955
|
-
|
|
956
|
-
':host .test-summary': {
|
|
957
|
-
marginBottom: '12px',
|
|
958
|
-
paddingBottom: '8px',
|
|
959
|
-
borderBottom: '1px solid var(--code-border, #e5e7eb)',
|
|
960
|
-
},
|
|
961
|
-
|
|
962
|
-
':host .test-failed': {
|
|
963
|
-
color: '#dc2626',
|
|
964
|
-
},
|
|
965
|
-
|
|
966
|
-
':host .test-list': {
|
|
967
|
-
listStyle: 'none',
|
|
968
|
-
padding: 0,
|
|
969
|
-
margin: 0,
|
|
970
|
-
},
|
|
971
|
-
|
|
972
|
-
':host .test-list li': {
|
|
973
|
-
padding: '4px 0',
|
|
974
|
-
},
|
|
975
|
-
|
|
976
|
-
':host .test-pass': {
|
|
977
|
-
color: '#16a34a',
|
|
978
|
-
},
|
|
979
|
-
|
|
980
|
-
':host .test-fail': {
|
|
981
|
-
color: '#dc2626',
|
|
982
|
-
},
|
|
983
|
-
|
|
984
|
-
':host .test-error': {
|
|
985
|
-
marginLeft: '20px',
|
|
986
|
-
marginTop: '4px',
|
|
987
|
-
padding: '8px',
|
|
988
|
-
background: 'rgba(220, 38, 38, 0.1)',
|
|
989
|
-
borderRadius: '4px',
|
|
990
|
-
fontSize: '13px',
|
|
991
|
-
fontFamily: 'var(--font-mono, monospace)',
|
|
992
|
-
},
|
|
993
|
-
|
|
994
|
-
':host .clickable-error': {
|
|
995
|
-
cursor: 'pointer',
|
|
996
|
-
textDecoration: 'underline',
|
|
997
|
-
textDecorationStyle: 'dotted',
|
|
998
|
-
},
|
|
999
|
-
|
|
1000
|
-
':host .clickable-error:hover': {
|
|
1001
|
-
background: 'rgba(220, 38, 38, 0.2)',
|
|
1002
|
-
},
|
|
1003
|
-
|
|
1004
|
-
':host .sig-badge': {
|
|
1005
|
-
fontSize: '11px',
|
|
1006
|
-
padding: '2px 6px',
|
|
1007
|
-
marginLeft: '8px',
|
|
1008
|
-
background: 'rgba(99, 102, 241, 0.1)',
|
|
1009
|
-
color: '#6366f1',
|
|
1010
|
-
borderRadius: '4px',
|
|
1011
|
-
},
|
|
1012
|
-
|
|
682
|
+
// TS-specific: console container class name
|
|
1013
683
|
':host .ts-console': {
|
|
1014
684
|
height: '120px',
|
|
1015
685
|
borderTop: '1px solid var(--code-border, #e5e7eb)',
|
|
1016
686
|
display: 'flex',
|
|
1017
687
|
flexDirection: 'column',
|
|
1018
688
|
},
|
|
1019
|
-
|
|
1020
|
-
':host .console-header': {
|
|
1021
|
-
padding: '4px 12px',
|
|
1022
|
-
background: 'var(--code-background, #f3f4f6)',
|
|
1023
|
-
fontSize: '12px',
|
|
1024
|
-
fontWeight: '500',
|
|
1025
|
-
color: 'var(--text-color, #6b7280)',
|
|
1026
|
-
opacity: '0.7',
|
|
1027
|
-
borderBottom: '1px solid var(--code-border, #e5e7eb)',
|
|
1028
|
-
},
|
|
1029
|
-
|
|
1030
|
-
':host .console-output': {
|
|
1031
|
-
flex: '1',
|
|
1032
|
-
margin: '0',
|
|
1033
|
-
padding: '8px 12px',
|
|
1034
|
-
background: 'var(--code-background, #f3f4f6)',
|
|
1035
|
-
color: 'var(--text-color, #1f2937)',
|
|
1036
|
-
fontSize: '12px',
|
|
1037
|
-
fontFamily: 'ui-monospace, monospace',
|
|
1038
|
-
overflow: 'auto',
|
|
1039
|
-
whiteSpace: 'pre-wrap',
|
|
1040
|
-
},
|
|
1041
|
-
|
|
1042
|
-
':host .clickable-line': {
|
|
1043
|
-
cursor: 'pointer',
|
|
1044
|
-
color: '#2563eb',
|
|
1045
|
-
textDecoration: 'underline',
|
|
1046
|
-
textDecorationStyle: 'dotted',
|
|
1047
|
-
},
|
|
1048
|
-
|
|
1049
|
-
':host .clickable-line:hover': {
|
|
1050
|
-
color: '#1d4ed8',
|
|
1051
|
-
background: 'rgba(37, 99, 235, 0.1)',
|
|
1052
|
-
},
|
|
1053
689
|
},
|
|
1054
690
|
}) as ElementCreator<TSPlayground>
|