Merge pull request #7 from Code-Victor/feat/editor-fix-n-ui-updates
Feat/editor fix n UI updates
This commit is contained in:
commit
55fde2f648
@ -36,43 +36,7 @@ import { createSandbox } from "@/lib/actions"
|
|||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { Loader2 } from "lucide-react"
|
import { Loader2 } from "lucide-react"
|
||||||
import { Button } from "../ui/button"
|
import { Button } from "../ui/button"
|
||||||
|
import { projectTemplates } from "@/lib/data"
|
||||||
const data: {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
icon: string
|
|
||||||
description: string
|
|
||||||
disabled: boolean
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
id: "reactjs",
|
|
||||||
name: "React",
|
|
||||||
icon: "/project-icons/react.svg",
|
|
||||||
description: "A JavaScript library for building user interfaces",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "vanillajs",
|
|
||||||
name: "HTML/JS",
|
|
||||||
icon: "/project-icons/more.svg",
|
|
||||||
description: "More coming soon, feel free to contribute on GitHub",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "nextjs",
|
|
||||||
name: "NextJS",
|
|
||||||
icon: "/project-icons/node.svg",
|
|
||||||
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
|
||||||
disabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "streamlit",
|
|
||||||
name: "Streamlit",
|
|
||||||
icon: "/project-icons/python.svg",
|
|
||||||
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
|
||||||
disabled: false,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
name: z
|
name: z
|
||||||
@ -124,12 +88,12 @@ export default function NewProjectModal({
|
|||||||
if (!loading) setOpen(open)
|
if (!loading) setOpen(open)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogContent>
|
<DialogContent className="max-h-[95vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Create A Sandbox</DialogTitle>
|
<DialogTitle>Create A Sandbox</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="grid grid-cols-2 w-full gap-2 mt-2">
|
<div className="grid grid-cols-2 w-full gap-2 mt-2">
|
||||||
{data.map((item) => (
|
{projectTemplates.map((item) => (
|
||||||
<button
|
<button
|
||||||
disabled={item.disabled || loading}
|
disabled={item.disabled || loading}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
|
@ -8,6 +8,7 @@ import { Clock, Globe, Lock } from "lucide-react"
|
|||||||
import { Sandbox } from "@/lib/types"
|
import { Sandbox } from "@/lib/types"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
|
import { projectTemplates } from "@/lib/data"
|
||||||
|
|
||||||
export default function ProjectCard({
|
export default function ProjectCard({
|
||||||
children,
|
children,
|
||||||
@ -43,7 +44,9 @@ export default function ProjectCard({
|
|||||||
setDate(`${Math.floor(diffInMinutes / 1440)}d ago`)
|
setDate(`${Math.floor(diffInMinutes / 1440)}d ago`)
|
||||||
}
|
}
|
||||||
}, [sandbox])
|
}, [sandbox])
|
||||||
|
const projectIcon =
|
||||||
|
projectTemplates.find((p) => p.id === sandbox.type)?.icon ??
|
||||||
|
"/project-icons/node.svg"
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@ -65,16 +68,7 @@ export default function ProjectCard({
|
|||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
<div className="space-x-2 flex items-center justify-start w-full z-10">
|
<div className="space-x-2 flex items-center justify-start w-full z-10">
|
||||||
<Image
|
<Image alt="" src={projectIcon} width={20} height={20} />
|
||||||
alt=""
|
|
||||||
src={
|
|
||||||
sandbox.type === "react"
|
|
||||||
? "/project-icons/react.svg"
|
|
||||||
: "/project-icons/node.svg"
|
|
||||||
}
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
/>
|
|
||||||
<div className="font-medium static whitespace-nowrap w-full text-ellipsis overflow-hidden">
|
<div className="font-medium static whitespace-nowrap w-full text-ellipsis overflow-hidden">
|
||||||
{sandbox.name}
|
{sandbox.name}
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,6 +35,8 @@ import { PreviewProvider, usePreview } from "@/context/PreviewContext"
|
|||||||
import { useSocket } from "@/context/SocketContext"
|
import { useSocket } from "@/context/SocketContext"
|
||||||
import { Button } from "../ui/button"
|
import { Button } from "../ui/button"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
import { parseTSConfigToMonacoOptions } from "@/lib/tsconfig"
|
||||||
|
import { deepMerge } from "@/lib/utils"
|
||||||
|
|
||||||
export default function CodeEditor({
|
export default function CodeEditor({
|
||||||
userData,
|
userData,
|
||||||
@ -154,9 +156,78 @@ export default function CodeEditor({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Post-mount editor keybindings and actions
|
// Post-mount editor keybindings and actions
|
||||||
const handleEditorMount: OnMount = (editor, monaco) => {
|
const handleEditorMount: OnMount = async (editor, monaco) => {
|
||||||
setEditorRef(editor)
|
setEditorRef(editor)
|
||||||
monacoRef.current = monaco
|
monacoRef.current = monaco
|
||||||
|
/**
|
||||||
|
* Sync all the models to the worker eagerly.
|
||||||
|
* This enables intelliSense for all files without needing an `addExtraLib` call.
|
||||||
|
*/
|
||||||
|
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true)
|
||||||
|
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)
|
||||||
|
|
||||||
|
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
|
||||||
|
defaultCompilerOptions
|
||||||
|
)
|
||||||
|
monaco.languages.typescript.javascriptDefaults.setCompilerOptions(
|
||||||
|
defaultCompilerOptions
|
||||||
|
)
|
||||||
|
const fetchFileContent = (fileId: string): Promise<string> => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
socket?.emit("getFile", fileId, (content: string) => {
|
||||||
|
resolve(content)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const loadTSConfig = async (files: (TFolder | TFile)[]) => {
|
||||||
|
const tsconfigFiles = files.filter((file) =>
|
||||||
|
file.name.endsWith("tsconfig.json")
|
||||||
|
)
|
||||||
|
let mergedConfig: any = { compilerOptions: {} }
|
||||||
|
|
||||||
|
for (const file of tsconfigFiles) {
|
||||||
|
const containerId = file.id.split("/").slice(0, 2).join("/")
|
||||||
|
const content = await fetchFileContent(file.id)
|
||||||
|
|
||||||
|
try {
|
||||||
|
let tsConfig = JSON.parse(content)
|
||||||
|
|
||||||
|
// Handle references
|
||||||
|
if (tsConfig.references) {
|
||||||
|
for (const ref of tsConfig.references) {
|
||||||
|
const path = ref.path.replace("./", "")
|
||||||
|
const fileId = `${containerId}/${path}`
|
||||||
|
const refContent = await fetchFileContent(fileId)
|
||||||
|
const referenceTsConfig = JSON.parse(refContent)
|
||||||
|
|
||||||
|
// Merge configurations
|
||||||
|
mergedConfig = deepMerge(mergedConfig, referenceTsConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge current file's config
|
||||||
|
mergedConfig = deepMerge(mergedConfig, tsConfig)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing TSConfig:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Apply merged compiler options
|
||||||
|
if (mergedConfig.compilerOptions) {
|
||||||
|
const updatedOptions = parseTSConfigToMonacoOptions({
|
||||||
|
...defaultCompilerOptions,
|
||||||
|
...mergedConfig.compilerOptions,
|
||||||
|
})
|
||||||
|
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
|
||||||
|
updatedOptions
|
||||||
|
)
|
||||||
|
monaco.languages.typescript.javascriptDefaults.setCompilerOptions(
|
||||||
|
updatedOptions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function with your file structure
|
||||||
|
await loadTSConfig(files)
|
||||||
|
|
||||||
editor.onDidChangeCursorPosition((e) => {
|
editor.onDidChangeCursorPosition((e) => {
|
||||||
setIsSelected(false)
|
setIsSelected(false)
|
||||||
@ -784,11 +855,11 @@ export default function CodeEditor({
|
|||||||
const afterLineNumber = isAbove ? line - 1 : line
|
const afterLineNumber = isAbove ? line - 1 : line
|
||||||
id = changeAccessor.addZone({
|
id = changeAccessor.addZone({
|
||||||
afterLineNumber,
|
afterLineNumber,
|
||||||
heightInLines: isAbove?11: 12,
|
heightInLines: isAbove ? 11 : 12,
|
||||||
domNode: generateRef.current,
|
domNode: generateRef.current,
|
||||||
})
|
})
|
||||||
const contentWidget= generate.widget
|
const contentWidget = generate.widget
|
||||||
if (contentWidget){
|
if (contentWidget) {
|
||||||
editorRef?.layoutContentWidget(contentWidget)
|
editorRef?.layoutContentWidget(contentWidget)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -984,3 +1055,18 @@ export default function CodeEditor({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the typescript compiler to detect JSX and load type definitions
|
||||||
|
*/
|
||||||
|
const defaultCompilerOptions: monaco.languages.typescript.CompilerOptions = {
|
||||||
|
allowJs: true,
|
||||||
|
allowSyntheticDefaultImports: true,
|
||||||
|
allowNonTsExtensions: true,
|
||||||
|
resolveJsonModule: true,
|
||||||
|
|
||||||
|
jsx: monaco.languages.typescript.JsxEmit.ReactJSX,
|
||||||
|
module: monaco.languages.typescript.ModuleKind.ESNext,
|
||||||
|
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
|
||||||
|
target: monaco.languages.typescript.ScriptTarget.ESNext,
|
||||||
|
}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
"use client";
|
"use client"
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image"
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react"
|
||||||
import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js";
|
import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js"
|
||||||
import { TFile, TFolder, TTab } from "@/lib/types";
|
import { TFile, TFolder, TTab } from "@/lib/types"
|
||||||
import SidebarFile from "./file";
|
import SidebarFile from "./file"
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
ContextMenuContent,
|
ContextMenuContent,
|
||||||
ContextMenuItem,
|
ContextMenuItem,
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
} from "@/components/ui/context-menu";
|
} from "@/components/ui/context-menu"
|
||||||
import { Loader2, Pencil, Trash2 } from "lucide-react";
|
import { ChevronRight, Loader2, Pencil, Trash2 } from "lucide-react"
|
||||||
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { motion, AnimatePresence } from "framer-motion"
|
||||||
|
|
||||||
// Note: Renaming has not been implemented in the backend yet, so UI relating to renaming is commented out
|
// Note: Renaming has not been implemented in the backend yet, so UI relating to renaming is commented out
|
||||||
|
|
||||||
@ -25,27 +27,27 @@ export default function SidebarFolder({
|
|||||||
movingId,
|
movingId,
|
||||||
deletingFolderId,
|
deletingFolderId,
|
||||||
}: {
|
}: {
|
||||||
data: TFolder;
|
data: TFolder
|
||||||
selectFile: (file: TTab) => void;
|
selectFile: (file: TTab) => void
|
||||||
handleRename: (
|
handleRename: (
|
||||||
id: string,
|
id: string,
|
||||||
newName: string,
|
newName: string,
|
||||||
oldName: string,
|
oldName: string,
|
||||||
type: "file" | "folder"
|
type: "file" | "folder"
|
||||||
) => boolean;
|
) => boolean
|
||||||
handleDeleteFile: (file: TFile) => void;
|
handleDeleteFile: (file: TFile) => void
|
||||||
handleDeleteFolder: (folder: TFolder) => void;
|
handleDeleteFolder: (folder: TFolder) => void
|
||||||
movingId: string;
|
movingId: string
|
||||||
deletingFolderId: string;
|
deletingFolderId: string
|
||||||
}) {
|
}) {
|
||||||
const ref = useRef(null); // drop target
|
const ref = useRef(null) // drop target
|
||||||
const [isDraggedOver, setIsDraggedOver] = useState(false);
|
const [isDraggedOver, setIsDraggedOver] = useState(false)
|
||||||
|
|
||||||
const isDeleting =
|
const isDeleting =
|
||||||
deletingFolderId.length > 0 && data.id.startsWith(deletingFolderId);
|
deletingFolderId.length > 0 && data.id.startsWith(deletingFolderId)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = ref.current;
|
const el = ref.current
|
||||||
|
|
||||||
if (el)
|
if (el)
|
||||||
return dropTargetForElements({
|
return dropTargetForElements({
|
||||||
@ -67,17 +69,17 @@ export default function SidebarFolder({
|
|||||||
|
|
||||||
// no dropping while awaiting move
|
// no dropping while awaiting move
|
||||||
canDrop: () => {
|
canDrop: () => {
|
||||||
return !movingId;
|
return !movingId
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
const folder = isOpen
|
const folder = isOpen
|
||||||
? getIconForOpenFolder(data.name)
|
? getIconForOpenFolder(data.name)
|
||||||
: getIconForFolder(data.name);
|
: getIconForFolder(data.name)
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
// const [editing, setEditing] = useState(false);
|
// const [editing, setEditing] = useState(false);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
@ -96,6 +98,12 @@ export default function SidebarFolder({
|
|||||||
isDraggedOver ? "bg-secondary/50 rounded-t-sm" : "rounded-sm"
|
isDraggedOver ? "bg-secondary/50 rounded-t-sm" : "rounded-sm"
|
||||||
} w-full flex items-center h-7 px-1 transition-colors hover:bg-secondary cursor-pointer`}
|
} w-full flex items-center h-7 px-1 transition-colors hover:bg-secondary cursor-pointer`}
|
||||||
>
|
>
|
||||||
|
<ChevronRight
|
||||||
|
className={cn(
|
||||||
|
"min-w-3 min-h-3 mr-1 ml-auto transition-all duration-300",
|
||||||
|
isOpen ? "transform rotate-90" : ""
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Image
|
<Image
|
||||||
src={`/icons/${folder}`}
|
src={`/icons/${folder}`}
|
||||||
alt="Folder icon"
|
alt="Folder icon"
|
||||||
@ -149,48 +157,65 @@ export default function SidebarFolder({
|
|||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
disabled={isDeleting}
|
disabled={isDeleting}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleDeleteFolder(data);
|
handleDeleteFolder(data)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash2 className="w-4 h-4 mr-2" />
|
<Trash2 className="w-4 h-4 mr-2" />
|
||||||
Delete
|
Delete
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
{isOpen ? (
|
<AnimatePresence>
|
||||||
<div
|
{isOpen ? (
|
||||||
className={`flex w-full items-stretch ${
|
<motion.div
|
||||||
isDraggedOver ? "rounded-b-sm bg-secondary/50" : ""
|
className="overflow-y-hidden"
|
||||||
}`}
|
initial={{
|
||||||
>
|
height: 0,
|
||||||
<div className="w-[1px] bg-border mx-2 h-full"></div>
|
opacity: 0,
|
||||||
<div className="flex flex-col grow">
|
}}
|
||||||
{data.children.map((child) =>
|
animate={{
|
||||||
child.type === "file" ? (
|
height: "auto",
|
||||||
<SidebarFile
|
opacity: 1,
|
||||||
key={child.id}
|
}}
|
||||||
data={child}
|
exit={{
|
||||||
selectFile={selectFile}
|
height: 0,
|
||||||
handleRename={handleRename}
|
opacity: 0,
|
||||||
handleDeleteFile={handleDeleteFile}
|
}}
|
||||||
movingId={movingId}
|
>
|
||||||
deletingFolderId={deletingFolderId}
|
<div
|
||||||
/>
|
className={cn(
|
||||||
) : (
|
isDraggedOver ? "rounded-b-sm bg-secondary/50" : ""
|
||||||
<SidebarFolder
|
)}
|
||||||
key={child.id}
|
>
|
||||||
data={child}
|
<div className="flex flex-col grow ml-2 pl-2 border-l border-border">
|
||||||
selectFile={selectFile}
|
{data.children.map((child) =>
|
||||||
handleRename={handleRename}
|
child.type === "file" ? (
|
||||||
handleDeleteFile={handleDeleteFile}
|
<SidebarFile
|
||||||
handleDeleteFolder={handleDeleteFolder}
|
key={child.id}
|
||||||
movingId={movingId}
|
data={child}
|
||||||
deletingFolderId={deletingFolderId}
|
selectFile={selectFile}
|
||||||
/>
|
handleRename={handleRename}
|
||||||
)
|
handleDeleteFile={handleDeleteFile}
|
||||||
)}
|
movingId={movingId}
|
||||||
</div>
|
deletingFolderId={deletingFolderId}
|
||||||
</div>
|
/>
|
||||||
) : null}
|
) : (
|
||||||
|
<SidebarFolder
|
||||||
|
key={child.id}
|
||||||
|
data={child}
|
||||||
|
selectFile={selectFile}
|
||||||
|
handleRename={handleRename}
|
||||||
|
handleDeleteFile={handleDeleteFile}
|
||||||
|
handleDeleteFolder={handleDeleteFolder}
|
||||||
|
movingId={movingId}
|
||||||
|
deletingFolderId={deletingFolderId}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
) : null}
|
||||||
|
</AnimatePresence>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
36
frontend/lib/data/index.ts
Normal file
36
frontend/lib/data/index.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export const projectTemplates: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
description: string
|
||||||
|
disabled: boolean
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
id: "reactjs",
|
||||||
|
name: "React",
|
||||||
|
icon: "/project-icons/react.svg",
|
||||||
|
description: "A JavaScript library for building user interfaces",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "vanillajs",
|
||||||
|
name: "HTML/JS",
|
||||||
|
icon: "/project-icons/more.svg",
|
||||||
|
description: "More coming soon, feel free to contribute on GitHub",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "nextjs",
|
||||||
|
name: "NextJS",
|
||||||
|
icon: "/project-icons/node.svg",
|
||||||
|
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "streamlit",
|
||||||
|
name: "Streamlit",
|
||||||
|
icon: "/project-icons/python.svg",
|
||||||
|
description: "A JavaScript runtime built on the V8 JavaScript engine",
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
]
|
99
frontend/lib/tsconfig.ts
Normal file
99
frontend/lib/tsconfig.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import * as monaco from "monaco-editor"
|
||||||
|
|
||||||
|
export function parseTSConfigToMonacoOptions(
|
||||||
|
tsconfig: any
|
||||||
|
): monaco.languages.typescript.CompilerOptions {
|
||||||
|
const compilerOptions: monaco.languages.typescript.CompilerOptions = {}
|
||||||
|
|
||||||
|
// Map tsconfig options to Monaco CompilerOptions
|
||||||
|
if (tsconfig.strict) compilerOptions.strict = tsconfig.strict
|
||||||
|
if (tsconfig.target) compilerOptions.target = mapScriptTarget(tsconfig.target)
|
||||||
|
if (tsconfig.module) compilerOptions.module = mapModule(tsconfig.module)
|
||||||
|
if (tsconfig.lib) compilerOptions.lib = tsconfig.lib
|
||||||
|
if (tsconfig.allowJs) compilerOptions.allowJs = tsconfig.allowJs
|
||||||
|
if (tsconfig.checkJs) compilerOptions.checkJs = tsconfig.checkJs
|
||||||
|
if (tsconfig.jsx) compilerOptions.jsx = mapJSX(tsconfig.jsx)
|
||||||
|
if (tsconfig.declaration) compilerOptions.declaration = tsconfig.declaration
|
||||||
|
if (tsconfig.declarationMap)
|
||||||
|
compilerOptions.declarationMap = tsconfig.declarationMap
|
||||||
|
if (tsconfig.sourceMap) compilerOptions.sourceMap = tsconfig.sourceMap
|
||||||
|
if (tsconfig.outFile) compilerOptions.outFile = tsconfig.outFile
|
||||||
|
if (tsconfig.outDir) compilerOptions.outDir = tsconfig.outDir
|
||||||
|
if (tsconfig.removeComments)
|
||||||
|
compilerOptions.removeComments = tsconfig.removeComments
|
||||||
|
if (tsconfig.noEmit) compilerOptions.noEmit = tsconfig.noEmit
|
||||||
|
if (tsconfig.noEmitOnError)
|
||||||
|
compilerOptions.noEmitOnError = tsconfig.noEmitOnError
|
||||||
|
|
||||||
|
return compilerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapScriptTarget(
|
||||||
|
target: string
|
||||||
|
): monaco.languages.typescript.ScriptTarget {
|
||||||
|
const targetMap: { [key: string]: monaco.languages.typescript.ScriptTarget } =
|
||||||
|
{
|
||||||
|
es3: monaco.languages.typescript.ScriptTarget.ES3,
|
||||||
|
es5: monaco.languages.typescript.ScriptTarget.ES5,
|
||||||
|
es6: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
es2015: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
es2016: monaco.languages.typescript.ScriptTarget.ES2016,
|
||||||
|
es2017: monaco.languages.typescript.ScriptTarget.ES2017,
|
||||||
|
es2018: monaco.languages.typescript.ScriptTarget.ES2018,
|
||||||
|
es2019: monaco.languages.typescript.ScriptTarget.ES2019,
|
||||||
|
es2020: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||||
|
esnext: monaco.languages.typescript.ScriptTarget.ESNext,
|
||||||
|
}
|
||||||
|
if (typeof target !== "string") {
|
||||||
|
return monaco.languages.typescript.ScriptTarget.Latest
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
targetMap[target?.toLowerCase()] ||
|
||||||
|
monaco.languages.typescript.ScriptTarget.Latest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapModule(module: string): monaco.languages.typescript.ModuleKind {
|
||||||
|
const moduleMap: { [key: string]: monaco.languages.typescript.ModuleKind } = {
|
||||||
|
none: monaco.languages.typescript.ModuleKind.None,
|
||||||
|
commonjs: monaco.languages.typescript.ModuleKind.CommonJS,
|
||||||
|
amd: monaco.languages.typescript.ModuleKind.AMD,
|
||||||
|
umd: monaco.languages.typescript.ModuleKind.UMD,
|
||||||
|
system: monaco.languages.typescript.ModuleKind.System,
|
||||||
|
es6: monaco.languages.typescript.ModuleKind.ES2015,
|
||||||
|
es2015: monaco.languages.typescript.ModuleKind.ES2015,
|
||||||
|
esnext: monaco.languages.typescript.ModuleKind.ESNext,
|
||||||
|
}
|
||||||
|
if (typeof module !== "string") {
|
||||||
|
return monaco.languages.typescript.ModuleKind.ESNext
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
moduleMap[module.toLowerCase()] ||
|
||||||
|
monaco.languages.typescript.ModuleKind.ESNext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapJSX(jsx: string): monaco.languages.typescript.JsxEmit {
|
||||||
|
const jsxMap: { [key: string]: monaco.languages.typescript.JsxEmit } = {
|
||||||
|
preserve: monaco.languages.typescript.JsxEmit.Preserve,
|
||||||
|
react: monaco.languages.typescript.JsxEmit.React,
|
||||||
|
"react-native": monaco.languages.typescript.JsxEmit.ReactNative,
|
||||||
|
}
|
||||||
|
return jsxMap[jsx.toLowerCase()] || monaco.languages.typescript.JsxEmit.React
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage:
|
||||||
|
const tsconfigJSON = {
|
||||||
|
compilerOptions: {
|
||||||
|
strict: true,
|
||||||
|
target: "ES2020",
|
||||||
|
module: "ESNext",
|
||||||
|
lib: ["DOM", "ES2020"],
|
||||||
|
jsx: "react",
|
||||||
|
sourceMap: true,
|
||||||
|
outDir: "./dist",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const monacoOptions = parseTSConfigToMonacoOptions(tsconfigJSON.compilerOptions)
|
||||||
|
console.log(monacoOptions)
|
@ -75,3 +75,26 @@ export function debounce<T extends (...args: any[]) => void>(
|
|||||||
timeout = setTimeout(() => func(...args), wait)
|
timeout = setTimeout(() => func(...args), wait)
|
||||||
} as T
|
} as T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep merge utility function
|
||||||
|
export const deepMerge = (target: any, source: any) => {
|
||||||
|
const output = { ...target }
|
||||||
|
if (isObject(target) && isObject(source)) {
|
||||||
|
Object.keys(source).forEach((key) => {
|
||||||
|
if (isObject(source[key])) {
|
||||||
|
if (!(key in target)) {
|
||||||
|
Object.assign(output, { [key]: source[key] })
|
||||||
|
} else {
|
||||||
|
output[key] = deepMerge(target[key], source[key])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Object.assign(output, { [key]: source[key] })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
const isObject = (item: any) => {
|
||||||
|
return item && typeof item === "object" && !Array.isArray(item)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user