@ttsc/playground 0.14.0-dev.20250530.1

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.
Files changed (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/lib/src/compiler/DEFAULT_ENTRY_FILE.d.ts +2 -0
  4. package/lib/src/compiler/DEFAULT_ENTRY_FILE.js +6 -0
  5. package/lib/src/compiler/DEFAULT_ENTRY_FILE.js.map +1 -0
  6. package/lib/src/compiler/DEFAULT_LINT_PLUGIN_NAME.d.ts +5 -0
  7. package/lib/src/compiler/DEFAULT_LINT_PLUGIN_NAME.js +9 -0
  8. package/lib/src/compiler/DEFAULT_LINT_PLUGIN_NAME.js.map +1 -0
  9. package/lib/src/compiler/DEFAULT_PLAYGROUND_COMPILER_OPTIONS.d.ts +19 -0
  10. package/lib/src/compiler/DEFAULT_PLAYGROUND_COMPILER_OPTIONS.js +23 -0
  11. package/lib/src/compiler/DEFAULT_PLAYGROUND_COMPILER_OPTIONS.js.map +1 -0
  12. package/lib/src/compiler/DEFAULT_TSCONFIG_PATH.d.ts +2 -0
  13. package/lib/src/compiler/DEFAULT_TSCONFIG_PATH.js +6 -0
  14. package/lib/src/compiler/DEFAULT_TSCONFIG_PATH.js.map +1 -0
  15. package/lib/src/compiler/DEFAULT_TYPIA_PLUGIN_NAME.d.ts +6 -0
  16. package/lib/src/compiler/DEFAULT_TYPIA_PLUGIN_NAME.js +10 -0
  17. package/lib/src/compiler/DEFAULT_TYPIA_PLUGIN_NAME.js.map +1 -0
  18. package/lib/src/compiler/DEFAULT_WORK_DIR.d.ts +2 -0
  19. package/lib/src/compiler/DEFAULT_WORK_DIR.js +6 -0
  20. package/lib/src/compiler/DEFAULT_WORK_DIR.js.map +1 -0
  21. package/lib/src/compiler/buildTsconfigJSON.d.ts +9 -0
  22. package/lib/src/compiler/buildTsconfigJSON.js +24 -0
  23. package/lib/src/compiler/buildTsconfigJSON.js.map +1 -0
  24. package/lib/src/compiler/createTypiaSourcePackMount.d.ts +11 -0
  25. package/lib/src/compiler/createTypiaSourcePackMount.js +29 -0
  26. package/lib/src/compiler/createTypiaSourcePackMount.js.map +1 -0
  27. package/lib/src/compiler/createWorkerCompiler.d.ts +25 -0
  28. package/lib/src/compiler/createWorkerCompiler.js +227 -0
  29. package/lib/src/compiler/createWorkerCompiler.js.map +1 -0
  30. package/lib/src/compiler/installDependenciesIntoMemFS.d.ts +12 -0
  31. package/lib/src/compiler/installDependenciesIntoMemFS.js +25 -0
  32. package/lib/src/compiler/installDependenciesIntoMemFS.js.map +1 -0
  33. package/lib/src/compiler/installTypiaSourcePack.d.ts +11 -0
  34. package/lib/src/compiler/installTypiaSourcePack.js +21 -0
  35. package/lib/src/compiler/installTypiaSourcePack.js.map +1 -0
  36. package/lib/src/compiler/internal/joinUnder.d.ts +5 -0
  37. package/lib/src/compiler/internal/joinUnder.js +13 -0
  38. package/lib/src/compiler/internal/joinUnder.js.map +1 -0
  39. package/lib/src/compiler/internal/parseLintDiagnostics.d.ts +6 -0
  40. package/lib/src/compiler/internal/parseLintDiagnostics.js +57 -0
  41. package/lib/src/compiler/internal/parseLintDiagnostics.js.map +1 -0
  42. package/lib/src/compiler/internal/safeParseTypiaTransform.d.ts +11 -0
  43. package/lib/src/compiler/internal/safeParseTypiaTransform.js +21 -0
  44. package/lib/src/compiler/internal/safeParseTypiaTransform.js.map +1 -0
  45. package/lib/src/compiler/lineColumnOf.d.ts +5 -0
  46. package/lib/src/compiler/lineColumnOf.js +15 -0
  47. package/lib/src/compiler/lineColumnOf.js.map +1 -0
  48. package/lib/src/compiler/loadTypiaSourcePack.d.ts +8 -0
  49. package/lib/src/compiler/loadTypiaSourcePack.js +33 -0
  50. package/lib/src/compiler/loadTypiaSourcePack.js.map +1 -0
  51. package/lib/src/compiler/mapDiagnostic.d.ts +9 -0
  52. package/lib/src/compiler/mapDiagnostic.js +22 -0
  53. package/lib/src/compiler/mapDiagnostic.js.map +1 -0
  54. package/lib/src/compiler/normalizeError.d.ts +2 -0
  55. package/lib/src/compiler/normalizeError.js +14 -0
  56. package/lib/src/compiler/normalizeError.js.map +1 -0
  57. package/lib/src/compiler/normalizeNodeModulePath.d.ts +8 -0
  58. package/lib/src/compiler/normalizeNodeModulePath.js +19 -0
  59. package/lib/src/compiler/normalizeNodeModulePath.js.map +1 -0
  60. package/lib/src/compiler/pickEmittedJS.d.ts +6 -0
  61. package/lib/src/compiler/pickEmittedJS.js +21 -0
  62. package/lib/src/compiler/pickEmittedJS.js.map +1 -0
  63. package/lib/src/index.d.ts +47 -0
  64. package/lib/src/index.js +104 -0
  65. package/lib/src/index.js.map +1 -0
  66. package/lib/src/npm/BUILT_IN_PLAYGROUND_PACKAGES.d.ts +6 -0
  67. package/lib/src/npm/BUILT_IN_PLAYGROUND_PACKAGES.js +15 -0
  68. package/lib/src/npm/BUILT_IN_PLAYGROUND_PACKAGES.js.map +1 -0
  69. package/lib/src/npm/collectExternalPackageNames.d.ts +5 -0
  70. package/lib/src/npm/collectExternalPackageNames.js +34 -0
  71. package/lib/src/npm/collectExternalPackageNames.js.map +1 -0
  72. package/lib/src/npm/installPlaygroundDependencies.d.ts +13 -0
  73. package/lib/src/npm/installPlaygroundDependencies.js +121 -0
  74. package/lib/src/npm/installPlaygroundDependencies.js.map +1 -0
  75. package/lib/src/npm/internal/npmRegistry.d.ts +57 -0
  76. package/lib/src/npm/internal/npmRegistry.js +216 -0
  77. package/lib/src/npm/internal/npmRegistry.js.map +1 -0
  78. package/lib/src/npm/packageNameFromSpecifier.d.ts +7 -0
  79. package/lib/src/npm/packageNameFromSpecifier.js +66 -0
  80. package/lib/src/npm/packageNameFromSpecifier.js.map +1 -0
  81. package/lib/src/react/ConsoleViewer.d.ts +7 -0
  82. package/lib/src/react/ConsoleViewer.js +57 -0
  83. package/lib/src/react/ConsoleViewer.js.map +1 -0
  84. package/lib/src/react/DEFAULT_OPTION_TOGGLES.d.ts +3 -0
  85. package/lib/src/react/DEFAULT_OPTION_TOGGLES.js +17 -0
  86. package/lib/src/react/DEFAULT_OPTION_TOGGLES.js.map +1 -0
  87. package/lib/src/react/DependencyProgressModal.d.ts +7 -0
  88. package/lib/src/react/DependencyProgressModal.js +16 -0
  89. package/lib/src/react/DependencyProgressModal.js.map +1 -0
  90. package/lib/src/react/DiagnosticsPanel.d.ts +4 -0
  91. package/lib/src/react/DiagnosticsPanel.js +15 -0
  92. package/lib/src/react/DiagnosticsPanel.js.map +1 -0
  93. package/lib/src/react/ExamplePicker.d.ts +9 -0
  94. package/lib/src/react/ExamplePicker.js +43 -0
  95. package/lib/src/react/ExamplePicker.js.map +1 -0
  96. package/lib/src/react/LintPane.d.ts +9 -0
  97. package/lib/src/react/LintPane.js +17 -0
  98. package/lib/src/react/LintPane.js.map +1 -0
  99. package/lib/src/react/OptionsPanel.d.ts +13 -0
  100. package/lib/src/react/OptionsPanel.js +43 -0
  101. package/lib/src/react/OptionsPanel.js.map +1 -0
  102. package/lib/src/react/PlaygroundShell.d.ts +2 -0
  103. package/lib/src/react/PlaygroundShell.js +609 -0
  104. package/lib/src/react/PlaygroundShell.js.map +1 -0
  105. package/lib/src/react/ResultViewer.d.ts +10 -0
  106. package/lib/src/react/ResultViewer.js +49 -0
  107. package/lib/src/react/ResultViewer.js.map +1 -0
  108. package/lib/src/react/SourceEditor.d.ts +2 -0
  109. package/lib/src/react/SourceEditor.js +74 -0
  110. package/lib/src/react/SourceEditor.js.map +1 -0
  111. package/lib/src/react/createCompilerClient.d.ts +14 -0
  112. package/lib/src/react/createCompilerClient.js +77 -0
  113. package/lib/src/react/createCompilerClient.js.map +1 -0
  114. package/lib/src/sandbox/createSandboxRequire.d.ts +11 -0
  115. package/lib/src/sandbox/createSandboxRequire.js +211 -0
  116. package/lib/src/sandbox/createSandboxRequire.js.map +1 -0
  117. package/lib/src/sandbox/loadTypiaRuntimePack.d.ts +7 -0
  118. package/lib/src/sandbox/loadTypiaRuntimePack.js +35 -0
  119. package/lib/src/sandbox/loadTypiaRuntimePack.js.map +1 -0
  120. package/lib/src/structures/IBuildTsconfigOptions.d.ts +19 -0
  121. package/lib/src/structures/IBuildTsconfigOptions.js +3 -0
  122. package/lib/src/structures/IBuildTsconfigOptions.js.map +1 -0
  123. package/lib/src/structures/ICompilerService.d.ts +84 -0
  124. package/lib/src/structures/ICompilerService.js +3 -0
  125. package/lib/src/structures/ICompilerService.js.map +1 -0
  126. package/lib/src/structures/IConsoleMessage.d.ts +10 -0
  127. package/lib/src/structures/IConsoleMessage.js +3 -0
  128. package/lib/src/structures/IConsoleMessage.js.map +1 -0
  129. package/lib/src/structures/ICreateCompilerClientOptions.d.ts +13 -0
  130. package/lib/src/structures/ICreateCompilerClientOptions.js +3 -0
  131. package/lib/src/structures/ICreateCompilerClientOptions.js.map +1 -0
  132. package/lib/src/structures/ICreateWorkerCompilerOptions.d.ts +35 -0
  133. package/lib/src/structures/ICreateWorkerCompilerOptions.js +3 -0
  134. package/lib/src/structures/ICreateWorkerCompilerOptions.js.map +1 -0
  135. package/lib/src/structures/IInstallTypiaSourcePackOptions.d.ts +18 -0
  136. package/lib/src/structures/IInstallTypiaSourcePackOptions.js +3 -0
  137. package/lib/src/structures/IInstallTypiaSourcePackOptions.js.map +1 -0
  138. package/lib/src/structures/ILintPluginConfig.d.ts +5 -0
  139. package/lib/src/structures/ILintPluginConfig.js +3 -0
  140. package/lib/src/structures/ILintPluginConfig.js.map +1 -0
  141. package/lib/src/structures/IOptionToggle.d.ts +12 -0
  142. package/lib/src/structures/IOptionToggle.js +3 -0
  143. package/lib/src/structures/IOptionToggle.js.map +1 -0
  144. package/lib/src/structures/IPlaygroundDependencyInstallOptions.d.ts +16 -0
  145. package/lib/src/structures/IPlaygroundDependencyInstallOptions.js +3 -0
  146. package/lib/src/structures/IPlaygroundDependencyInstallOptions.js.map +1 -0
  147. package/lib/src/structures/IPlaygroundDependencyInstallResult.d.ts +20 -0
  148. package/lib/src/structures/IPlaygroundDependencyInstallResult.js +3 -0
  149. package/lib/src/structures/IPlaygroundDependencyInstallResult.js.map +1 -0
  150. package/lib/src/structures/IPlaygroundDependencyPackage.d.ts +8 -0
  151. package/lib/src/structures/IPlaygroundDependencyPackage.js +3 -0
  152. package/lib/src/structures/IPlaygroundDependencyPackage.js.map +1 -0
  153. package/lib/src/structures/IPlaygroundDependencyProgress.d.ts +10 -0
  154. package/lib/src/structures/IPlaygroundDependencyProgress.js +3 -0
  155. package/lib/src/structures/IPlaygroundDependencyProgress.js.map +1 -0
  156. package/lib/src/structures/IPlaygroundDependencyProgressPhase.d.ts +5 -0
  157. package/lib/src/structures/IPlaygroundDependencyProgressPhase.js +3 -0
  158. package/lib/src/structures/IPlaygroundDependencyProgressPhase.js.map +1 -0
  159. package/lib/src/structures/IPlaygroundExample.d.ts +16 -0
  160. package/lib/src/structures/IPlaygroundExample.js +3 -0
  161. package/lib/src/structures/IPlaygroundExample.js.map +1 -0
  162. package/lib/src/structures/IPlaygroundShellProps.d.ts +70 -0
  163. package/lib/src/structures/IPlaygroundShellProps.js +3 -0
  164. package/lib/src/structures/IPlaygroundShellProps.js.map +1 -0
  165. package/lib/src/structures/ISourceEditorProps.d.ts +18 -0
  166. package/lib/src/structures/ISourceEditorProps.js +3 -0
  167. package/lib/src/structures/ISourceEditorProps.js.map +1 -0
  168. package/lib/src/structures/ITransformOptions.d.ts +15 -0
  169. package/lib/src/structures/ITransformOptions.js +3 -0
  170. package/lib/src/structures/ITransformOptions.js.map +1 -0
  171. package/lib/src/structures/ITypiaPluginConfig.d.ts +19 -0
  172. package/lib/src/structures/ITypiaPluginConfig.js +3 -0
  173. package/lib/src/structures/ITypiaPluginConfig.js.map +1 -0
  174. package/lib/src/structures/index.d.ts +18 -0
  175. package/lib/src/structures/index.js +35 -0
  176. package/lib/src/structures/index.js.map +1 -0
  177. package/package.json +66 -0
  178. package/src/compiler/DEFAULT_ENTRY_FILE.ts +2 -0
  179. package/src/compiler/DEFAULT_LINT_PLUGIN_NAME.ts +5 -0
  180. package/src/compiler/DEFAULT_PLAYGROUND_COMPILER_OPTIONS.ts +19 -0
  181. package/src/compiler/DEFAULT_TSCONFIG_PATH.ts +2 -0
  182. package/src/compiler/DEFAULT_TYPIA_PLUGIN_NAME.ts +6 -0
  183. package/src/compiler/DEFAULT_WORK_DIR.ts +2 -0
  184. package/src/compiler/buildTsconfigJSON.ts +22 -0
  185. package/src/compiler/createTypiaSourcePackMount.ts +32 -0
  186. package/src/compiler/createWorkerCompiler.ts +273 -0
  187. package/src/compiler/installDependenciesIntoMemFS.ts +28 -0
  188. package/src/compiler/installTypiaSourcePack.ts +24 -0
  189. package/src/compiler/internal/joinUnder.ts +8 -0
  190. package/src/compiler/internal/parseLintDiagnostics.ts +61 -0
  191. package/src/compiler/internal/safeParseTypiaTransform.ts +24 -0
  192. package/src/compiler/lineColumnOf.ts +14 -0
  193. package/src/compiler/loadTypiaSourcePack.ts +37 -0
  194. package/src/compiler/mapDiagnostic.ts +26 -0
  195. package/src/compiler/normalizeError.ts +12 -0
  196. package/src/compiler/normalizeNodeModulePath.ts +13 -0
  197. package/src/compiler/pickEmittedJS.ts +18 -0
  198. package/src/index.ts +57 -0
  199. package/src/npm/BUILT_IN_PLAYGROUND_PACKAGES.ts +11 -0
  200. package/src/npm/collectExternalPackageNames.ts +34 -0
  201. package/src/npm/installPlaygroundDependencies.ts +163 -0
  202. package/src/npm/internal/npmRegistry.ts +292 -0
  203. package/src/npm/packageNameFromSpecifier.ts +61 -0
  204. package/src/react/ConsoleViewer.tsx +121 -0
  205. package/src/react/DEFAULT_OPTION_TOGGLES.ts +15 -0
  206. package/src/react/DependencyProgressModal.tsx +73 -0
  207. package/src/react/DiagnosticsPanel.tsx +74 -0
  208. package/src/react/ExamplePicker.tsx +93 -0
  209. package/src/react/LintPane.tsx +58 -0
  210. package/src/react/OptionsPanel.tsx +132 -0
  211. package/src/react/PlaygroundShell.tsx +864 -0
  212. package/src/react/ResultViewer.tsx +75 -0
  213. package/src/react/SourceEditor.tsx +96 -0
  214. package/src/react/createCompilerClient.ts +80 -0
  215. package/src/sandbox/createSandboxRequire.ts +275 -0
  216. package/src/sandbox/loadTypiaRuntimePack.ts +36 -0
  217. package/src/structures/IBuildTsconfigOptions.ts +19 -0
  218. package/src/structures/ICompilerService.ts +96 -0
  219. package/src/structures/IConsoleMessage.ts +10 -0
  220. package/src/structures/ICreateCompilerClientOptions.ts +13 -0
  221. package/src/structures/ICreateWorkerCompilerOptions.ts +40 -0
  222. package/src/structures/IInstallTypiaSourcePackOptions.ts +18 -0
  223. package/src/structures/ILintPluginConfig.ts +5 -0
  224. package/src/structures/IOptionToggle.ts +12 -0
  225. package/src/structures/IPlaygroundDependencyInstallOptions.ts +17 -0
  226. package/src/structures/IPlaygroundDependencyInstallResult.ts +21 -0
  227. package/src/structures/IPlaygroundDependencyPackage.ts +8 -0
  228. package/src/structures/IPlaygroundDependencyProgress.ts +11 -0
  229. package/src/structures/IPlaygroundDependencyProgressPhase.ts +12 -0
  230. package/src/structures/IPlaygroundExample.ts +16 -0
  231. package/src/structures/IPlaygroundShellProps.ts +83 -0
  232. package/src/structures/ISourceEditorProps.ts +18 -0
  233. package/src/structures/ITransformOptions.ts +15 -0
  234. package/src/structures/ITypiaPluginConfig.ts +20 -0
  235. package/src/structures/index.ts +18 -0
@@ -0,0 +1,75 @@
1
+ "use client";
2
+
3
+ import Editor from "@monaco-editor/react";
4
+ import { useEffect, useRef, useState } from "react";
5
+
6
+ interface ResultViewerProps {
7
+ language: "typescript" | "javascript" | "json";
8
+ value: string;
9
+ }
10
+
11
+ /**
12
+ * Read-only Monaco pane used to render the compiled / transformed output
13
+ * with a copy button. Wraps `<Editor readOnly>` and adds the toast UI.
14
+ */
15
+ export function ResultViewer({ language, value }: ResultViewerProps) {
16
+ const [copied, setCopied] = useState(false);
17
+ const copiedTimer = useRef<number | null>(null);
18
+
19
+ useEffect(
20
+ () => () => {
21
+ if (copiedTimer.current !== null)
22
+ window.clearTimeout(copiedTimer.current);
23
+ },
24
+ [],
25
+ );
26
+
27
+ const onCopy = () => {
28
+ void navigator.clipboard.writeText(value);
29
+ setCopied(true);
30
+ if (copiedTimer.current !== null) window.clearTimeout(copiedTimer.current);
31
+ copiedTimer.current = window.setTimeout(() => {
32
+ setCopied(false);
33
+ copiedTimer.current = null;
34
+ }, 1500);
35
+ };
36
+
37
+ return (
38
+ <div className="relative h-full w-full">
39
+ {value && (
40
+ <button
41
+ onClick={onCopy}
42
+ className="absolute top-2 right-3 z-10 px-2 py-1 text-[10px] font-mono text-neutral-300 bg-neutral-900/80 border border-neutral-700 rounded-md hover:bg-neutral-800 transition-colors"
43
+ >
44
+ {copied ? "Copied ✓" : "Copy"}
45
+ </button>
46
+ )}
47
+ <Editor
48
+ height="100%"
49
+ language={language}
50
+ theme="vs-dark"
51
+ value={value}
52
+ path={`output.${
53
+ language === "typescript"
54
+ ? "ts"
55
+ : language === "javascript"
56
+ ? "js"
57
+ : "json"
58
+ }`}
59
+ options={{
60
+ readOnly: true,
61
+ tabSize: 2,
62
+ minimap: { enabled: false },
63
+ padding: { top: 12, bottom: 12 },
64
+ fontSize: 13,
65
+ fontFamily:
66
+ "ui-monospace, SFMono-Regular, 'JetBrains Mono', 'Fira Code', Consolas, monospace",
67
+ smoothScrolling: true,
68
+ scrollBeyondLastLine: false,
69
+ renderLineHighlight: "none",
70
+ wordWrap: "on",
71
+ }}
72
+ />
73
+ </div>
74
+ );
75
+ }
@@ -0,0 +1,96 @@
1
+ "use client";
2
+
3
+ import Editor, { type Monaco } from "@monaco-editor/react";
4
+ import { useCallback, useEffect, useMemo, useRef } from "react";
5
+
6
+ import { DEFAULT_PLAYGROUND_COMPILER_OPTIONS } from "../compiler/DEFAULT_PLAYGROUND_COMPILER_OPTIONS";
7
+ import type { ISourceEditorProps } from "../structures/ISourceEditorProps";
8
+
9
+ export function SourceEditor({
10
+ value,
11
+ onChange,
12
+ extraLibs,
13
+ path = "file:///src/playground.ts",
14
+ }: ISourceEditorProps) {
15
+ const monacoRef = useRef<Monaco | null>(null);
16
+ const libDisposables = useRef<{ dispose(): void }[]>([]);
17
+ const allExtraLibs = useMemo(
18
+ () => (extraLibs ? Object.entries(extraLibs) : []),
19
+ [extraLibs],
20
+ );
21
+
22
+ const installExtraLibs = useCallback(
23
+ (monaco: Monaco) => {
24
+ for (const disposable of libDisposables.current) disposable.dispose();
25
+ libDisposables.current = [];
26
+ const tsd = monaco.languages.typescript.typescriptDefaults;
27
+ for (const [file, content] of allExtraLibs) {
28
+ libDisposables.current.push(tsd.addExtraLib(content, file));
29
+ }
30
+ },
31
+ [allExtraLibs],
32
+ );
33
+
34
+ useEffect(() => {
35
+ if (monacoRef.current) installExtraLibs(monacoRef.current);
36
+ return () => {
37
+ for (const disposable of libDisposables.current) disposable.dispose();
38
+ libDisposables.current = [];
39
+ };
40
+ }, [installExtraLibs]);
41
+
42
+ const handleMount = (_editor: unknown, monaco: Monaco) => {
43
+ monacoRef.current = monaco;
44
+ const tsd = monaco.languages.typescript.typescriptDefaults;
45
+ tsd.setCompilerOptions({
46
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
47
+ module: monaco.languages.typescript.ModuleKind.ESNext,
48
+ moduleResolution:
49
+ monaco.languages.typescript.ModuleResolutionKind.NodeJs,
50
+ esModuleInterop: DEFAULT_PLAYGROUND_COMPILER_OPTIONS.esModuleInterop,
51
+ strict: DEFAULT_PLAYGROUND_COMPILER_OPTIONS.strict,
52
+ experimentalDecorators:
53
+ DEFAULT_PLAYGROUND_COMPILER_OPTIONS.experimentalDecorators,
54
+ allowNonTsExtensions: true,
55
+ // External .d.ts packs (typia, etc.) routinely reference transitive types
56
+ // Monaco cannot reach (deep paths in JSDoc, optional peers). skipLibCheck
57
+ // keeps the editor lean by not type-checking the lib pack.
58
+ skipLibCheck: true,
59
+ });
60
+ tsd.setDiagnosticsOptions({
61
+ noSemanticValidation: false,
62
+ noSyntaxValidation: false,
63
+ diagnosticCodesToIgnore: [
64
+ // 2307: Cannot find module — JSDoc-only stubbed deps still occasionally
65
+ // leak through Monaco's module resolution.
66
+ 2307,
67
+ ],
68
+ });
69
+ installExtraLibs(monaco);
70
+ };
71
+
72
+ return (
73
+ <Editor
74
+ height="100%"
75
+ defaultLanguage="typescript"
76
+ theme="vs-dark"
77
+ value={value}
78
+ onChange={(v) => onChange(v ?? "")}
79
+ onMount={handleMount}
80
+ path={path}
81
+ options={{
82
+ tabSize: 2,
83
+ minimap: { enabled: false },
84
+ padding: { top: 12, bottom: 12 },
85
+ fontSize: 13,
86
+ fontFamily:
87
+ "ui-monospace, SFMono-Regular, 'JetBrains Mono', 'Fira Code', Consolas, monospace",
88
+ smoothScrolling: true,
89
+ cursorBlinking: "smooth",
90
+ scrollBeyondLastLine: false,
91
+ renderLineHighlight: "line",
92
+ wordWrap: "on",
93
+ }}
94
+ />
95
+ );
96
+ }
@@ -0,0 +1,80 @@
1
+ "use client";
2
+
3
+ import { WorkerConnector } from "tgrid";
4
+
5
+ import type { ICompilerService } from "../structures/ICompilerService";
6
+ import type { ICreateCompilerClientOptions } from "../structures/ICreateCompilerClientOptions";
7
+
8
+ /**
9
+ * UI-side singleton: connect to the playground worker over tgrid and return the
10
+ * typed `ICompilerService` driver.
11
+ *
12
+ * The promise is cached; the first call boots, every subsequent call shares the
13
+ * same connection. If the boot rejects the cache is cleared so the next call
14
+ * retries — otherwise every retry would resolve to the same rejection.
15
+ */
16
+ export function createCompilerClient(options: ICreateCompilerClientOptions): {
17
+ connect(): Promise<ICompilerService>;
18
+ reset(): Promise<void>;
19
+ } {
20
+ let connectionPromise: Promise<ICompilerService> | null = null;
21
+ // Track the active connector AND the in-flight connector promise so
22
+ // reset() can dispose either one — disposing only the resolved
23
+ // `activeConnector` leaks the connector when reset() is called during
24
+ // an in-flight `await connector.connect(...)` (the connector reference
25
+ // exists but isn't yet assigned to activeConnector).
26
+ let activeConnector: WorkerConnector<null, null, null> | null = null;
27
+ let pendingConnector: Promise<WorkerConnector<null, null, null>> | null =
28
+ null;
29
+
30
+ return {
31
+ connect(): Promise<ICompilerService> {
32
+ if (connectionPromise) return connectionPromise;
33
+ const connector: WorkerConnector<null, null, null> = new WorkerConnector(
34
+ null,
35
+ null,
36
+ );
37
+ const connectPromise = connector
38
+ .connect(options.workerUrl)
39
+ .then(() => connector);
40
+ pendingConnector = connectPromise;
41
+ connectionPromise = (async () => {
42
+ try {
43
+ await connectPromise;
44
+ } catch (err) {
45
+ connectionPromise = null;
46
+ if (pendingConnector === connectPromise) pendingConnector = null;
47
+ throw err;
48
+ }
49
+ if (pendingConnector === connectPromise) pendingConnector = null;
50
+ activeConnector = connector;
51
+ return connector.getDriver() as unknown as ICompilerService;
52
+ })();
53
+ return connectionPromise;
54
+ },
55
+ async reset(): Promise<void> {
56
+ const inflight = pendingConnector;
57
+ const active = activeConnector;
58
+ connectionPromise = null;
59
+ pendingConnector = null;
60
+ activeConnector = null;
61
+ // Swallow close errors: the worker is already being torn down,
62
+ // and a Retry that fails to close cleanly should not block the
63
+ // next connect attempt. Cover both code paths — the in-flight
64
+ // connector (await it first, then close) and the resolved active
65
+ // connector. Either may be null; both may be the same instance
66
+ // after a successful connect().
67
+ if (inflight) {
68
+ try {
69
+ const c = await inflight;
70
+ if (c !== active) await c.close().catch(() => {});
71
+ } catch {
72
+ // connect() rejected — nothing to close.
73
+ }
74
+ }
75
+ if (active) {
76
+ await active.close().catch(() => {});
77
+ }
78
+ },
79
+ };
80
+ }
@@ -0,0 +1,275 @@
1
+ // CJS-flavored sandbox `require` over an in-memory pack of `.js` / `.json`
2
+ // modules. Used by the playground Execute lane to run compiled JS in the
3
+ // browser without round-tripping through a CDN.
4
+ //
5
+ // Resolution algorithm (minimal):
6
+ // - Bare specifier `typia/lib/X`:
7
+ // try `typia/lib/X.js`, then `typia/lib/X/index.js`, then honor the
8
+ // package's `exports` / `main` (read from <pkg>/package.json) before
9
+ // giving up.
10
+ // - Relative `./Y` / `../Y` (encountered when one pack module requires a
11
+ // sibling): resolved against the caller's pack key.
12
+ // - Bare `name` (no subpath): honors the package `main` field, falling back
13
+ // to `name/index.js`.
14
+ //
15
+ // Every successful load is cached so cyclic graphs settle. Module evaluation
16
+ // wraps the source text in the standard CJS wrapper:
17
+ // (function(require, module, exports, __dirname, __filename, console) {...})
18
+
19
+ interface IPackJson {
20
+ name?: string;
21
+ main?: string;
22
+ exports?: unknown;
23
+ }
24
+
25
+ interface ISandboxRequireOptions {
26
+ /** Console replacement injected into every sandbox module. */
27
+ console:
28
+ | Console
29
+ | typeof globalThis.console
30
+ | Record<string, (...args: unknown[]) => void>;
31
+ }
32
+
33
+ /**
34
+ * Build a sandboxed `require` function over a runtime pack. Resolves typia /
35
+ * `@typia/*` / randexp specifiers from the pack; throws on anything else so the
36
+ * caller sees the unsupported dependency.
37
+ */
38
+ export function createSandboxRequire(
39
+ pack: Record<string, string>,
40
+ opts: ISandboxRequireOptions,
41
+ ): (specifier: string) => unknown {
42
+ type ModuleObj = { exports: unknown };
43
+ const cache = new Map<string, ModuleObj>();
44
+
45
+ const has = (key: string): boolean =>
46
+ Object.prototype.hasOwnProperty.call(pack, key);
47
+
48
+ const tryPaths = (...candidates: string[]): string | null => {
49
+ for (const c of candidates) if (has(c)) return c;
50
+ return null;
51
+ };
52
+
53
+ // Read package.json from pack and resolve via main/exports.
54
+ const resolvePackageEntry = (
55
+ pkg: string,
56
+ subpath: string | null,
57
+ ): string | null => {
58
+ const pjKey = `${pkg}/package.json`;
59
+ if (!has(pjKey)) return null;
60
+ let pj: IPackJson;
61
+ try {
62
+ pj = JSON.parse(pack[pjKey]!) as IPackJson;
63
+ } catch {
64
+ return null;
65
+ }
66
+ if (subpath === null) {
67
+ // bare "name": honor exports["."] → string, else main, else index.
68
+ const exportsAny = pj.exports;
69
+ if (typeof exportsAny === "object" && exportsAny !== null) {
70
+ const root = (exportsAny as Record<string, unknown>)["."];
71
+ const r = pickConditionalExport(root);
72
+ if (r) {
73
+ const resolved = `${pkg}/${stripDotSlash(r)}`;
74
+ return has(resolved) ? resolved : null;
75
+ }
76
+ }
77
+ if (typeof pj.main === "string") {
78
+ return tryPaths(
79
+ `${pkg}/${stripDotSlash(pj.main)}`,
80
+ `${pkg}/${stripDotSlash(pj.main)}.js`,
81
+ `${pkg}/${stripDotSlash(pj.main)}.cjs`,
82
+ `${pkg}/${stripDotSlash(pj.main)}.mjs`,
83
+ `${pkg}/${stripDotSlash(pj.main)}.json`,
84
+ `${pkg}/${stripDotSlash(pj.main)}/index.js`,
85
+ `${pkg}/${stripDotSlash(pj.main)}/index.cjs`,
86
+ );
87
+ }
88
+ return tryPaths(`${pkg}/index.js`, `${pkg}/index.cjs`);
89
+ }
90
+ // Subpath: honor exports["./subpath"] or exports["./subpath/*"] patterns.
91
+ const exportsAny = pj.exports;
92
+ if (typeof exportsAny === "object" && exportsAny !== null) {
93
+ const entries = exportsAny as Record<string, unknown>;
94
+ // Exact match first.
95
+ const exact = entries[`./${subpath}`];
96
+ const ex = pickConditionalExport(exact);
97
+ if (ex) {
98
+ const resolved = `${pkg}/${stripDotSlash(ex)}`;
99
+ if (has(resolved)) return resolved;
100
+ }
101
+ // Wildcard match.
102
+ for (const [pattern, target] of Object.entries(entries)) {
103
+ if (!pattern.endsWith("/*")) continue;
104
+ const prefix = pattern.slice(2, -1); // strip "./" and trailing "*"
105
+ if (!subpath.startsWith(prefix)) continue;
106
+ const rest = subpath.slice(prefix.length);
107
+ const targetStr = pickConditionalExport(target);
108
+ if (!targetStr) continue;
109
+ const resolved = `${pkg}/${stripDotSlash(targetStr.replace("*", rest))}`;
110
+ if (has(resolved)) return resolved;
111
+ }
112
+ }
113
+ return null;
114
+ };
115
+
116
+ // Resolve a specifier (with optional `fromKey` for relative imports) to a
117
+ // pack key, or null if unknown.
118
+ const resolveSpecifier = (
119
+ specifier: string,
120
+ fromKey: string | null,
121
+ ): string | null => {
122
+ if (specifier.startsWith("./") || specifier.startsWith("../")) {
123
+ if (!fromKey) return null;
124
+ const baseDir = dirname(fromKey);
125
+ const joined = posixJoin(baseDir, specifier);
126
+ return tryPaths(
127
+ joined,
128
+ `${joined}.js`,
129
+ `${joined}.cjs`,
130
+ `${joined}.mjs`,
131
+ `${joined}.json`,
132
+ `${joined}/index.js`,
133
+ `${joined}/index.cjs`,
134
+ );
135
+ }
136
+ // Bare specifier. Split into package name + subpath.
137
+ const { pkg, subpath } = splitBareSpecifier(specifier);
138
+ if (subpath === null) {
139
+ return resolvePackageEntry(pkg, null);
140
+ }
141
+ // First try direct paths (covers the common typia/lib/internal/X case).
142
+ const direct = tryPaths(
143
+ `${pkg}/${subpath}`,
144
+ `${pkg}/${subpath}.js`,
145
+ `${pkg}/${subpath}.cjs`,
146
+ `${pkg}/${subpath}.mjs`,
147
+ `${pkg}/${subpath}.json`,
148
+ `${pkg}/${subpath}/index.js`,
149
+ `${pkg}/${subpath}/index.cjs`,
150
+ );
151
+ if (direct) return direct;
152
+ // Fall back to package.json exports map.
153
+ return resolvePackageEntry(pkg, subpath);
154
+ };
155
+
156
+ const evaluate = (key: string): ModuleObj => {
157
+ const cached = cache.get(key);
158
+ if (cached) return cached;
159
+ const code = pack[key]!;
160
+ const mod: ModuleObj = { exports: {} };
161
+ // Cache before evaluation so cyclic requires see the partial exports.
162
+ cache.set(key, mod);
163
+ if (key.endsWith(".json")) {
164
+ mod.exports = JSON.parse(code) as unknown;
165
+ return mod;
166
+ }
167
+ const localRequire = (specifier: string): unknown => {
168
+ const resolved = resolveSpecifier(specifier, key);
169
+ if (!resolved) {
170
+ throw new Error(
171
+ `require("${specifier}") is not available in the playground sandbox (from ${key})`,
172
+ );
173
+ }
174
+ return evaluate(resolved).exports;
175
+ };
176
+ const filename = "/sandbox/" + key;
177
+ const dir = "/sandbox/" + dirname(key);
178
+ try {
179
+ const factory = new Function(
180
+ "require",
181
+ "module",
182
+ "exports",
183
+ "__dirname",
184
+ "__filename",
185
+ "console",
186
+ code,
187
+ ) as (
188
+ req: (s: string) => unknown,
189
+ m: ModuleObj,
190
+ e: Record<string, unknown>,
191
+ d: string,
192
+ f: string,
193
+ c: unknown,
194
+ ) => void;
195
+ factory(
196
+ localRequire,
197
+ mod,
198
+ mod.exports as Record<string, unknown>,
199
+ dir,
200
+ filename,
201
+ opts.console,
202
+ );
203
+ } catch (err) {
204
+ // Surface eval-time errors with context so debugging the sandbox is
205
+ // easier when typia ships a module that depends on something missing.
206
+ const message = err instanceof Error ? err.message : String(err);
207
+ throw new Error(`evaluating ${key}: ${message}`);
208
+ }
209
+ return mod;
210
+ };
211
+
212
+ return (specifier: string): unknown => {
213
+ const resolved = resolveSpecifier(specifier, null);
214
+ if (!resolved) {
215
+ throw new Error(
216
+ `require("${specifier}") is not available in the playground sandbox`,
217
+ );
218
+ }
219
+ return evaluate(resolved).exports;
220
+ };
221
+ }
222
+
223
+ function pickConditionalExport(value: unknown): string | null {
224
+ if (typeof value === "string") return value;
225
+ if (value && typeof value === "object") {
226
+ const obj = value as Record<string, unknown>;
227
+ // Prefer require (CJS) > default > node.
228
+ const pick = obj.require ?? obj.default ?? obj.node;
229
+ if (typeof pick === "string") return pick;
230
+ if (pick && typeof pick === "object") return pickConditionalExport(pick);
231
+ }
232
+ return null;
233
+ }
234
+
235
+ function stripDotSlash(p: string): string {
236
+ return p.startsWith("./") ? p.slice(2) : p;
237
+ }
238
+
239
+ function dirname(p: string): string {
240
+ const i = p.lastIndexOf("/");
241
+ return i < 0 ? "" : p.slice(0, i);
242
+ }
243
+
244
+ function posixJoin(base: string, rel: string): string {
245
+ const baseParts = base.split("/").filter(Boolean);
246
+ for (const seg of rel.split("/")) {
247
+ if (seg === "" || seg === ".") continue;
248
+ if (seg === "..") baseParts.pop();
249
+ else baseParts.push(seg);
250
+ }
251
+ return baseParts.join("/");
252
+ }
253
+
254
+ function splitBareSpecifier(specifier: string): {
255
+ pkg: string;
256
+ subpath: string | null;
257
+ } {
258
+ // Handle @scope/name[/subpath]
259
+ if (specifier.startsWith("@")) {
260
+ const slash1 = specifier.indexOf("/");
261
+ if (slash1 < 0) return { pkg: specifier, subpath: null };
262
+ const slash2 = specifier.indexOf("/", slash1 + 1);
263
+ if (slash2 < 0) return { pkg: specifier, subpath: null };
264
+ return {
265
+ pkg: specifier.slice(0, slash2),
266
+ subpath: specifier.slice(slash2 + 1),
267
+ };
268
+ }
269
+ const slash = specifier.indexOf("/");
270
+ if (slash < 0) return { pkg: specifier, subpath: null };
271
+ return {
272
+ pkg: specifier.slice(0, slash),
273
+ subpath: specifier.slice(slash + 1),
274
+ };
275
+ }
@@ -0,0 +1,36 @@
1
+ // Loads a CommonJS-style runtime pack for the playground's Execute sandbox.
2
+ //
3
+ // The pack JSON itself is built by the site (e.g. `pack-typia-runtime.cjs`
4
+ // in the ttsc website) and served at a site-chosen URL. It mirrors the
5
+ // layout the typia transform's emit references — `typia/lib/internal/*`,
6
+ // `@typia/utils/lib/*`, etc. — so a bundle's `require("typia/lib/internal/X")`
7
+ // resolves to the matching pack entry.
8
+
9
+ const packCache = new Map<string, Promise<Record<string, string>>>();
10
+
11
+ /**
12
+ * Fetches the prebuilt runtime pack once per URL. Re-entrant on the same
13
+ * in-flight promise. On rejection the cache entry is cleared so the next call
14
+ * retries — otherwise a transient fetch failure (CDN blip, offline at first
15
+ * Execute) would permanently break every later Execute attempt.
16
+ */
17
+ export async function loadTypiaRuntimePack(
18
+ url: string,
19
+ ): Promise<Record<string, string>> {
20
+ const cached = packCache.get(url);
21
+ if (cached) return cached;
22
+ const promise = (async () => {
23
+ const response = await fetch(url);
24
+ if (!response.ok) {
25
+ throw new Error(
26
+ `loadTypiaRuntimePack: failed to fetch ${url}: ${response.status}`,
27
+ );
28
+ }
29
+ return (await response.json()) as Record<string, string>;
30
+ })().catch((err) => {
31
+ packCache.delete(url);
32
+ throw err;
33
+ });
34
+ packCache.set(url, promise);
35
+ return promise;
36
+ }
@@ -0,0 +1,19 @@
1
+ /** Options accepted by {@link buildTsconfigJSON}. */
2
+ export interface IBuildTsconfigOptions {
3
+ /**
4
+ * Module emit shape. Sites preview-render ESM, then re-run as CommonJS for
5
+ * the in-page `new Function` sandbox.
6
+ */
7
+ module: "ESNext" | "CommonJS";
8
+ /** Output directory relative to project root. Defaults to `"dist"`. */
9
+ outDir?: string;
10
+ /** Source root relative to project root. Defaults to `"src"`. */
11
+ rootDir?: string;
12
+ /**
13
+ * Extra entries spliced into `compilerOptions`. Use for plugins, paths, lib
14
+ * overrides, etc.
15
+ */
16
+ compilerOptions?: Record<string, unknown>;
17
+ /** Project `include` globs. Defaults to `["src"]`. */
18
+ include?: readonly string[];
19
+ }
@@ -0,0 +1,96 @@
1
+ import type { ITransformOptions } from "./ITransformOptions";
2
+
3
+ /**
4
+ * Worker ↔ UI RPC contract for the playground compiler service.
5
+ *
6
+ * `createWorkerCompiler` (worker side) implements this. `createCompilerClient`
7
+ * (UI side) returns a tgrid Driver bound to this shape. Sites that need an
8
+ * `extraTabs` lane should layer additional verbs over this base interface in
9
+ * their own ICompilerService subtype.
10
+ */
11
+ export interface ICompilerService {
12
+ /**
13
+ * Mount external npm package files into the worker's MemFS under
14
+ * `node_modules/`. Driven by the dependency installer in
15
+ * `@ttsc/playground/npm`.
16
+ */
17
+ installDependencies(
18
+ props: ICompilerService.IInstallDependenciesProps,
19
+ ): Promise<ICompilerService.IInstallDependenciesResult>;
20
+
21
+ /**
22
+ * Compile the user's source into JavaScript with diagnostics. Plugin
23
+ * transforms (typia, when enabled in options) run first; the result is the
24
+ * post-transform emit.
25
+ */
26
+ compile(props: ICompilerService.IProps): Promise<ICompilerService.IResult>;
27
+
28
+ /**
29
+ * Same pipeline as `compile`, but using the bundle-flavored tsconfig
30
+ * (typically `module: "CommonJS"` for in-page `new Function` sandboxing).
31
+ * Sites that don't run user code may treat this identically to `compile`.
32
+ */
33
+ bundle(props: ICompilerService.IProps): Promise<ICompilerService.IResult>;
34
+
35
+ /**
36
+ * Run the lint plugin and parse its findings into the same diagnostic shape
37
+ * as `compile`. Returns an empty list when no lint plugin is wired into the
38
+ * worker.
39
+ */
40
+ lint(props: ICompilerService.IProps): Promise<ICompilerService.ILintResult>;
41
+ }
42
+
43
+ export namespace ICompilerService {
44
+ export interface IProps {
45
+ source: string;
46
+ options?: ITransformOptions;
47
+ }
48
+
49
+ export interface IInstallDependenciesProps {
50
+ /** Node_modules-relative paths to text content. */
51
+ files: Record<string, string>;
52
+ /** Metadata for the packages whose files are in `files`. */
53
+ packages: IInstalledPackage[];
54
+ }
55
+
56
+ export interface IInstalledPackage {
57
+ name: string;
58
+ version: string;
59
+ }
60
+
61
+ export interface IInstallDependenciesResult {
62
+ installed: IInstalledPackage[];
63
+ fileCount: number;
64
+ }
65
+
66
+ export type IResult = ISuccess | IFailure | IError;
67
+
68
+ export interface ISuccess extends IBase<"success", string> {}
69
+ export interface IFailure extends IBase<"failure", string> {
70
+ diagnostics: IDiagnostic[];
71
+ }
72
+ export interface IError extends IBase<"error", unknown> {}
73
+
74
+ interface IBase<Type extends string, Value> {
75
+ type: Type;
76
+ target: "javascript";
77
+ value: Value;
78
+ }
79
+
80
+ export interface IDiagnostic {
81
+ /** 1-based line number. */
82
+ line: number;
83
+ /** 1-based column number. */
84
+ column: number;
85
+ /** Length of the span in source characters; at least 1. */
86
+ length: number;
87
+ severity: "error" | "warning";
88
+ message: string;
89
+ /** Diagnostic code, e.g. `"TS2322"` or a lint rule id. */
90
+ code?: string;
91
+ }
92
+
93
+ export interface ILintResult {
94
+ diagnostics: IDiagnostic[];
95
+ }
96
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * One captured `console.*` invocation. `value` is the argv (the spread of
3
+ * `console.log(...args)`), so `console.log("user:", user)` shows up as a single
4
+ * row with both pieces rendered inline, separated by a space — same as a real
5
+ * DevTools console.
6
+ */
7
+ export interface IConsoleMessage {
8
+ type: "debug" | "dir" | "error" | "info" | "log" | "table" | "warn";
9
+ value: unknown[];
10
+ }