├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── new-framework-support.md
└── workflows
│ └── ci.yaml
├── .gitignore
├── LICENSE
├── README.md
├── all-in-one
├── .eslintrc.json
├── .gitignore
├── .vscode
│ └── settings.json
├── README.md
├── bootstrap_projects
│ └── react
│ │ ├── .gitignore
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── public
│ │ └── vite.svg
│ │ ├── src
│ │ ├── App.css
│ │ ├── App.tsx
│ │ ├── assets
│ │ │ └── react.svg
│ │ ├── index.css
│ │ ├── main.tsx
│ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
├── next.config.js
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── public
│ ├── next.svg
│ ├── thirteen.svg
│ └── vercel.svg
├── src
│ ├── app
│ │ ├── api
│ │ │ └── bootfs
│ │ │ │ └── route.ts
│ │ ├── bootWebContainer.ts
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ └── page.tsx
│ └── components
│ │ ├── Editor
│ │ ├── Editor.tsx
│ │ ├── FileTree.tsx
│ │ ├── Terminal.css
│ │ ├── Terminal.tsx
│ │ ├── svelte-sfc.ts
│ │ └── vue-sfc.ts
│ │ ├── Select
│ │ └── Select.tsx
│ │ └── TopPanel
│ │ └── TopPanel.tsx
├── tailwind.config.js
├── tsconfig.json
├── typings.d.ts
└── vercel.json
├── kotlin-repl
├── .gitignore
├── HELP.md
├── README.md
├── _samples
│ ├── .gitignore
│ ├── Dependencies.main.kts
│ ├── Kotless.main.kts
│ ├── KotlessKtor.main.kts
│ ├── KotlessKtor2.main.kts
│ ├── KotlessSpring.main.kts
│ ├── README.md
│ ├── TwoClasses.kts
│ └── local-test.ipynb
├── build.gradle.kts
├── docs
│ └── jupyter-kotlin.md
├── gradle.properties
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── resources
│ └── application.properties
├── settings.gradle.kts
└── src
│ ├── main
│ ├── kotlin
│ │ └── org
│ │ │ └── clickprompt
│ │ │ └── unitserver
│ │ │ ├── UnitServerApplication.kt
│ │ │ ├── interpreter
│ │ │ ├── KotlinInterpreter.kt
│ │ │ ├── api
│ │ │ │ ├── InterpreterContext.kt
│ │ │ │ └── InterpreterRequest.kt
│ │ │ └── compiler
│ │ │ │ ├── CustomLibraryResolver.kt
│ │ │ │ ├── ExtendLibraries.kt
│ │ │ │ ├── KotlinReplWrapper.kt
│ │ │ │ └── SimpleLibraryDefinition.kt
│ │ │ ├── magic
│ │ │ ├── LangCodeWrapper.kt
│ │ │ ├── SimpleMagicMatcher.kt
│ │ │ └── lang
│ │ │ │ ├── KtorLangBuilder.kt
│ │ │ │ ├── LangBuilder.kt
│ │ │ │ └── SpringLangBuilder.kt
│ │ │ ├── messaging
│ │ │ ├── Message.kt
│ │ │ └── MessageType.kt
│ │ │ └── socket
│ │ │ ├── UnitServerSocketHandler.kt
│ │ │ └── WebsocketConfig.kt
│ └── resources
│ │ └── application.properties
│ └── test
│ └── kotlin
│ └── org
│ └── clickprompt
│ └── unitserver
│ ├── UnitServerApplicationTests.kt
│ ├── interpreter
│ └── KotlinInterpreterTest.kt
│ └── magic
│ ├── LangCodeWrapperTest.kt
│ └── SimpleMagicMatcherTest.kt
├── react-repl
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
│ └── settings.json
├── README.md
├── common
│ ├── compile.ts
│ └── unit.types.ts
├── next.config.js
├── nodemon.json
├── package-lock.json
├── package.json
├── public
│ ├── next.svg
│ ├── thirteen.svg
│ └── vercel.svg
├── server.ts
├── src
│ └── app
│ │ ├── api
│ │ └── hello
│ │ │ └── route.ts
│ │ ├── components
│ │ └── editor
│ │ │ ├── CodeEditor.tsx
│ │ │ ├── UseCodeEditor.tsx
│ │ │ ├── UseCodeMirror.tsx
│ │ │ └── editor.types.ts
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.module.css
│ │ └── page.tsx
├── tsconfig.json
└── tsconfig.server.json
├── rust-wasm
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── src
│ └── main.rs
└── typescript-repl
├── README.md
├── deno.json
├── deno.lock
├── flowrepl
├── TypescriptInterpreter.ts
├── api
│ ├── InterpreterContext.ts
│ ├── InterpreterRequest.ts
│ └── InterpreterService.ts
└── messaging
│ └── Message.ts
├── logger.ts
├── main.ts
└── ws
└── flowReplHander.ts
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Env (please complete the following information):**
14 | - OS: [e.g. iOS]
15 | - Env: Docker compose? Local dev?
16 | - Browser [e.g. chrome, safari]
17 | - Version [e.g. 22]
18 |
19 |
20 | **To Reproduce**
21 | Steps to reproduce the behavior:
22 | 1. Go to '...'
23 | 2. Click on '....'
24 | 3. Scroll down to '....'
25 | 4. See error
26 |
27 | **Expected behavior**
28 | A clear and concise description of what you expected to happen.
29 |
30 | **Screenshots**
31 | If applicable, add screenshots to help explain your problem.
32 |
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new-framework-support.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: New framework support
3 | about: new framework support
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Which language would you to support**
11 | xxx
12 |
13 | **Example of this language HTTP API syntax**
14 | xxx
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ push ]
4 |
5 | jobs:
6 | build:
7 | strategy:
8 | matrix:
9 | os: [ macos-latest, ubuntu-latest, windows-latest ]
10 | runs-on: ${{ matrix.os }}
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-java@v3
15 | with:
16 | distribution: 'zulu'
17 | java-version: '17'
18 |
19 | - name: Setup Gradle
20 | uses: gradle/gradle-build-action@v2
21 | with:
22 | arguments: build
23 | build-root-directory: kotlin-repl
24 |
25 | - name: Execute Gradle build
26 | run: ./gradlew build
27 | working-directory: kotlin-repl
28 |
29 | - name: Execute Gradle Coverage
30 | run: ./gradlew check
31 | working-directory: kotlin-repl
32 |
33 | - name: Execute Gradle Coverage
34 | if: runner.os == 'macOS'
35 | run: bash <(curl -s https://codecov.io/bash)
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022~ ArchGuard Org.
4 | Copyright (c) 2023~ ClickPrompt Org.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unit Runtime
2 |
3 | [](https://github.com/prompt-engineering/unit-runtime/actions/workflows/ci.yaml)
4 |
5 | > Unit Runtime is an efficient and user-friendly AI code execution environment that allows for one-click startup and real-time interaction, helping you quickly build and test AI code.
6 |
7 | Workflow:
8 |
9 | ```mermaid
10 | sequenceDiagram
11 | participant Human
12 | participant LLM/ChatGPT
13 | participant Unit Runtime
14 | participant Language REPL
15 |
16 | Human->>+LLM/ChatGPT: Provide prompt for generated code
17 | LLM/ChatGPT->>+Unit Runtime: Provide code snippets/units
18 | Unit Runtime->>+Language REPL: Compile and return
19 | Language REPL-->>-Unit Runtime: Output result
20 | Unit Runtime-->>-LLM/ChatGPT: Display processing result
21 | LLM/ChatGPT-->>-Human: Verify/modify code
22 | ```
23 |
24 | For examples:
25 |
26 | 1. generate a "Hello, world" and send to Kotlin Repl
27 |
28 | ```kotlin
29 | @RestController
30 | object Pages {
31 | @GetMapping("/")
32 | fun main() = "Hello World!"
33 | }
34 | ```
35 |
36 | 2. will start a server like: [http://localhost:10043](http://localhost:10043) , you can test and verify it.
37 |
38 | ## Websocket API
39 |
40 | server: `ws://localhost:8080/repl`
41 |
42 | input:
43 |
44 | ```kotlin
45 | @Serializable
46 | data class InterpreterRequest(
47 | var id: Int = -1,
48 | val code: String,
49 | val language: String = "kotlin",
50 | val framework: String = "spring",
51 | val history: Boolean = false
52 | )
53 | ```
54 |
55 | output:
56 |
57 | ```kotlin
58 | @Serializable
59 | data class Message(
60 | var id: Int = -1,
61 | var resultValue: String,
62 | var className: String = "",
63 | var msgType: MessageType = MessageType.NONE,
64 | var content: MessageContent? = null,
65 | )
66 | ```
67 |
68 | ## Todos
69 |
70 | - Backend
71 | - [x] Kotlin
72 | - [x] basic REPL
73 | - [ ] Spring Boot framework based on [https://github.com/JetBrains/kotless](https://github.com/JetBrains/kotless)
74 | - [x] Ktor framework based on [https://github.com/JetBrains/kotless](https://github.com/JetBrains/kotless)
75 | - [x] TypeScript
76 | - [x] basic REPL
77 | - [x] Deno with Hono
78 | - [ ] Java
79 | - [ ] Python
80 | - [x] Frontend
81 | - [x] React with TypeScript and Babel
82 | - [ ] Vue
83 | - [ ]Angular
84 |
85 | ## Development
86 |
87 | 1. git clone `https://github.com/prompt-engineering/unit-runtime`
88 | 2. `./gradlew bootRun`
89 |
90 | API:
91 |
92 |
93 | ## LICENSE
94 |
95 | This code is distributed under the MIT license. See [LICENSE](./LICENSE) in this directory.
96 |
--------------------------------------------------------------------------------
/all-in-one/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/all-in-one/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/all-in-one/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "[typescript]": {
3 | "editor.defaultFormatter": "esbenp.prettier-vscode"
4 | },
5 | "[typescriptreact]": {
6 | "editor.defaultFormatter": "esbenp.prettier-vscode"
7 | },
8 | "editor.formatOnSave": true,
9 | "typescript.tsdk": "node_modules\\typescript\\lib",
10 | "typescript.enablePromptUseWorkspaceTsdk": true
11 | }
--------------------------------------------------------------------------------
/all-in-one/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
18 |
19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20 |
21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22 |
23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24 |
25 | ## Learn More
26 |
27 | To learn more about Next.js, take a look at the following resources:
28 |
29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 |
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33 |
34 | ## Deploy on Vercel
35 |
36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37 |
38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
39 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootfs__react",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0"
14 | },
15 | "devDependencies": {
16 | "@types/react": "^18.0.28",
17 | "@types/react-dom": "^18.0.11",
18 | "@vitejs/plugin-react": "^3.1.0",
19 | "typescript": "^4.9.3",
20 | "vite": "^4.2.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import reactLogo from "./assets/react.svg";
3 | import viteLogo from "/vite.svg";
4 | import "./App.css";
5 |
6 | function App() {
7 | const [count, setCount] = useState(0);
8 |
9 | return (
10 |
11 |
19 |
Vite + React
20 |
21 |
24 |
25 | Edit src/App.tsx
and save to test HMR
26 |
27 |
28 |
29 | Click on the Vite and React logos to learn more
30 |
31 |
32 | );
33 | }
34 |
35 | export default App;
36 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | -webkit-text-size-adjust: 100%;
15 | }
16 |
17 | a {
18 | font-weight: 500;
19 | color: #646cff;
20 | text-decoration: inherit;
21 | }
22 | a:hover {
23 | color: #535bf2;
24 | }
25 |
26 | body {
27 | margin: 0;
28 | display: flex;
29 | place-items: center;
30 | min-width: 320px;
31 | min-height: 100vh;
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | }
38 |
39 | button {
40 | border-radius: 8px;
41 | border: 1px solid transparent;
42 | padding: 0.6em 1.2em;
43 | font-size: 1em;
44 | font-weight: 500;
45 | font-family: inherit;
46 | background-color: #1a1a1a;
47 | cursor: pointer;
48 | transition: border-color 0.25s;
49 | }
50 | button:hover {
51 | border-color: #646cff;
52 | }
53 | button:focus,
54 | button:focus-visible {
55 | outline: 4px auto -webkit-focus-ring-color;
56 | }
57 |
58 | @media (prefers-color-scheme: light) {
59 | :root {
60 | color: #213547;
61 | background-color: #ffffff;
62 | }
63 | a:hover {
64 | color: #747bff;
65 | }
66 | button {
67 | background-color: #f9f9f9;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/all-in-one/bootstrap_projects/react/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/all-in-one/next.config.js:
--------------------------------------------------------------------------------
1 | const { DefinePlugin } = require("webpack");
2 |
3 |
4 | /** @type {import('next').NextConfig} */
5 | const nextConfig = {
6 | experimental: {
7 | appDir: true,
8 | },
9 | headers: async () => {
10 | return[
11 | {
12 | "source": "/(.*)",
13 | "headers": [
14 | {
15 | "key": "Cross-Origin-Embedder-Policy",
16 | "value": "require-corp"
17 | },
18 | {
19 | "key": "Cross-Origin-Opener-Policy",
20 | "value": "same-origin"
21 | }
22 | ]
23 | }
24 | ]
25 | },
26 |
27 | webpack(config) {
28 | config.plugins.push(
29 | new DefinePlugin({
30 | "__PROJ_ROOT__": JSON.stringify(__dirname),
31 | })
32 | );
33 |
34 | return config;
35 | }
36 |
37 | // https://github.com/vercel/next.js/issues/33863#issuecomment-1140518693
38 |
39 | }
40 |
41 | module.exports = nextConfig
42 |
--------------------------------------------------------------------------------
/all-in-one/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "all-in-one",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "preinstall": "npx only-allow pnpm",
7 | "dev": "next dev",
8 | "build": "next build",
9 | "start": "next start",
10 | "lint": "next lint",
11 | "format": "prettier --write -u ./src"
12 | },
13 | "dependencies": {
14 | "@emotion/react": "^11.10.6",
15 | "@emotion/styled": "^11.10.6",
16 | "@fortawesome/fontawesome-svg-core": "^6.4.0",
17 | "@fortawesome/free-regular-svg-icons": "^6.4.0",
18 | "@fortawesome/free-solid-svg-icons": "^6.4.0",
19 | "@fortawesome/react-fontawesome": "^0.2.0",
20 | "@monaco-editor/react": "^4.5.0-beta.0",
21 | "@mui/lab": "5.0.0-alpha.124",
22 | "@mui/material": "^5.11.15",
23 | "@webcontainer/api": "^1.1.0",
24 | "client-only": "^0.0.1",
25 | "monaco-editor": "^0.36.1",
26 | "next": "13.2.4",
27 | "react": "18.2.0",
28 | "react-dom": "18.2.0",
29 | "server-only": "^0.0.1",
30 | "typescript": "5.0.2",
31 | "webpack": "^5.77.0",
32 | "xterm": "^5.1.0",
33 | "xterm-addon-fit": "^0.7.0"
34 | },
35 | "devDependencies": {
36 | "@types/node": "18.15.11",
37 | "@types/react": "18.0.31",
38 | "@types/react-dom": "18.0.11",
39 | "autoprefixer": "^10.4.14",
40 | "eslint": "8.37.0",
41 | "eslint-config-next": "13.2.4",
42 | "postcss": "^8.4.21",
43 | "prettier": "^2.8.7",
44 | "tailwindcss": "^3.3.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/all-in-one/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/all-in-one/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/all-in-one/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/all-in-one/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/all-in-one/src/app/api/bootfs/route.ts:
--------------------------------------------------------------------------------
1 | const SUPPORTED_FRAMEWORK = ["react", "vue", "svelte"] as const;
2 |
3 | export async function GET(request: Request) {
4 | const url = new URL(request.url);
5 | const framework = url.searchParams.get("framework");
6 | if (!SUPPORTED_FRAMEWORK.includes(framework as any)) {
7 | return new Response("wrong param", { status: 400 });
8 | }
9 |
10 | const result = await getBootstrapContents(framework as any);
11 | return new Response(JSON.stringify(result));
12 | }
13 |
14 | import { relative, resolve, normalize } from "node:path";
15 | import { readdir, readFile } from "node:fs/promises";
16 |
17 | async function getBootstrapContents(ty: (typeof SUPPORTED_FRAMEWORK)[number]) {
18 | if (!SUPPORTED_FRAMEWORK.includes(ty)) {
19 | throw new Error("unsupported framework");
20 | }
21 |
22 | const contentRoot = resolve(__PROJ_ROOT__, "bootstrap_projects", ty);
23 |
24 | // read the directory recursively and get all the files's content
25 | async function getContentsRecursively(dir: string) {
26 | let result: any = {};
27 |
28 | const files = await readdir(dir, { encoding: "utf8", withFileTypes: true });
29 | for (const file of files) {
30 | if (file.isDirectory()) {
31 | result[file.name] = {
32 | ...(await getContentsRecursively(resolve(dir, file.name))),
33 | _$__Ty__: "dir",
34 | path: normalize(
35 | relative(contentRoot, resolve(dir, file.name))
36 | ).replaceAll("\\", "/"),
37 | };
38 | } else {
39 | result[file.name] = {
40 | _$__Ty__: "file",
41 | path: normalize(
42 | relative(contentRoot, resolve(dir, file.name))
43 | ).replaceAll("\\", "/"),
44 | content: await readFile(resolve(dir, file.name), {
45 | encoding: "utf8",
46 | }),
47 | };
48 | }
49 | }
50 |
51 | return result;
52 | }
53 |
54 | return getContentsRecursively(contentRoot);
55 | }
56 |
--------------------------------------------------------------------------------
/all-in-one/src/app/bootWebContainer.ts:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import "client-only";
4 |
5 | import { WebContainer } from "@webcontainer/api";
6 | import { resolve } from "path";
7 |
8 | let __webcontainerInstance: WebContainer | null;
9 |
10 | async function init(container: WebContainer): Promise {
11 | await container.fs.mkdir("/tmp");
12 |
13 | // init fs
14 | await container.mount({}, { mountPoint: "/tmp" });
15 |
16 | container.on("server-ready", (port, url) => {
17 | console.log("server ready", port, url);
18 | });
19 | return container;
20 | }
21 |
22 | export async function initFs(
23 | container: WebContainer,
24 | bootfs: any,
25 | clean = true
26 | ) {
27 | const root = "/tmp/scratch";
28 |
29 | if (clean) {
30 | try {
31 | await container.fs.rm(root, { recursive: true });
32 | } catch {
33 | } finally {
34 | await container.fs.mkdir(root, { recursive: true });
35 | }
36 | }
37 |
38 | if (typeof bootfs !== "object") {
39 | throw new Error("invalid bootfs");
40 | }
41 |
42 | if (Object.keys(bootfs).length === 0) {
43 | throw new Error("empty bootfs");
44 | }
45 |
46 | for (const [key, value] of Object.entries(bootfs)) {
47 | if (key === "_$__Ty__") {
48 | continue;
49 | }
50 |
51 | if ((value as any)._$__Ty__ === "file") {
52 | await container.fs.writeFile(
53 | resolve(root, (value as any).path),
54 | (value as any).content
55 | );
56 | } else if ((value as any)._$__Ty__ === "dir") {
57 | await container.fs.mkdir(resolve(root, (value as any).path), {
58 | recursive: true,
59 | });
60 | await initFs(container, value, false);
61 | } else if (key === "path") {
62 | /** ignore */
63 | } else {
64 | throw new Error("invalid bootfs");
65 | }
66 | }
67 | }
68 |
69 | export const initInstance = async () => {
70 | if (!__webcontainerInstance) {
71 | __webcontainerInstance = await new Promise((resolve, reject) => {
72 | console.log("booting webcontainer");
73 | WebContainer.boot()
74 | .then((it) => {
75 | console.log("webcontainer booted");
76 | return resolve(init(it));
77 | })
78 | .catch((err) => reject(err));
79 | });
80 | }
81 |
82 | return __webcontainerInstance!;
83 | };
84 |
85 | export const destroyInstance = () => {
86 | __webcontainerInstance?.teardown();
87 | __webcontainerInstance = null;
88 | };
89 |
90 | const getInstance = async () => {
91 | return __webcontainerInstance;
92 | };
93 | export type GetInstance = typeof getInstance;
94 | export default getInstance;
95 |
--------------------------------------------------------------------------------
/all-in-one/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/unit-mesh/unit-runtime/7768bde4283e09269a0e7475e8144fd19fe3b760/all-in-one/src/app/favicon.ico
--------------------------------------------------------------------------------
/all-in-one/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
6 | html, body {
7 | width: 100%;
8 | height: 100%;
9 | margin: 0;
10 | padding: 0;
11 | box-sizing: border-box;
12 | }
--------------------------------------------------------------------------------
/all-in-one/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import "./globals.css";
2 |
3 | export const metadata = {
4 | title: "Create Next App",
5 | description: "Generated by create next app",
6 | };
7 |
8 | export default function RootLayout({
9 | children,
10 | }: {
11 | children: React.ReactNode;
12 | }) {
13 | return (
14 |
15 | {children}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/all-in-one/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import "client-only";
3 |
4 | import TopPanel from "@/components/TopPanel/TopPanel";
5 | import Editor from "@/components/Editor/Editor";
6 | import { useEffect, useState } from "react";
7 |
8 | import getInstance, {
9 | initFs,
10 | destroyInstance,
11 | initInstance,
12 | } from "./bootWebContainer";
13 | import FileTree from "@/components/Editor/FileTree";
14 | import { WebContainer, WebContainerProcess } from "@webcontainer/api";
15 |
16 | const languageMap = new Map([
17 | ["html", "html"],
18 | ["css", "css"],
19 | ["js", "javascript"],
20 | ["ts", "typescript"],
21 | ["vue", "vue-sfc"],
22 | ["svelte", "svelte-sfc"],
23 | ["jsx", "javascript"],
24 | ["tsx", "typescript"],
25 | ]);
26 |
27 | export default function Home() {
28 | const [webcontainer, setWebcontainer] = useState(null);
29 | const [framework, setFramework] = useState("React");
30 |
31 | const [files, setFiles] = useState([]);
32 | const [currentFile, setCurrentFile] = useState(null);
33 | const [currentLanguage, setCurrentLanguage] = useState("javascript");
34 |
35 | useEffect(() => {
36 | initInstance()
37 | .then((webcontainer) => {
38 | setWebcontainer(webcontainer);
39 | })
40 | .catch((e) => {});
41 | }, []);
42 |
43 | const [input, setInput] = useState("");
44 | useEffect(() => {
45 | console.log("input changed", input);
46 | }, [input]);
47 |
48 | useEffect(() => {
49 | (async () => {
50 | if (!webcontainer) return;
51 |
52 | console.log("framework changed", framework);
53 | const result = await fetch(
54 | "/api/bootfs?framework=" + framework.toLowerCase()
55 | ).then((it) => it.json());
56 |
57 | console.log("??", webcontainer);
58 | if (webcontainer) {
59 | console.log("init fs");
60 | await initFs(webcontainer, result);
61 | setFiles(await refreshTree());
62 | }
63 | })();
64 | }, [framework, webcontainer]);
65 |
66 | return (
67 |
68 |
69 |
70 | {
73 | refreshTree().then(setFiles);
74 | }}
75 | downloadDeps={() => installDeps()}
76 | onSelected={(item) => {
77 | if (item.type === "file") {
78 | webcontainer?.fs.readFile(item.path, "utf-8").then(setInput);
79 | setCurrentFile(item);
80 |
81 | const file = item.name;
82 | for (const [ext, lang] of languageMap) {
83 | if (file.endsWith("." + ext)) {
84 | setCurrentLanguage(lang);
85 | break;
86 | }
87 | }
88 | }
89 | }}
90 | />
91 |
98 |
99 |
100 | );
101 | }
102 |
103 | import type { FileTreeItem } from "@/components/Editor/FileTree";
104 | async function refreshTree(): Promise {
105 | const webcontainer = await getInstance();
106 | if (!webcontainer) return [];
107 |
108 | const listDir: (path: string) => Promise = async (
109 | path: string
110 | ) => {
111 | const r = await webcontainer?.fs.readdir(path, {
112 | withFileTypes: true,
113 | });
114 |
115 | if (!r) return [];
116 |
117 | return Promise.all(
118 | r.map(async (it) => {
119 | const fullPath = path + "/" + it.name;
120 | if (it.isDirectory()) {
121 | return {
122 | path: fullPath,
123 | name: it.name,
124 | type: "folder",
125 | children: await listDir(fullPath),
126 | };
127 | } else {
128 | return {
129 | path: fullPath,
130 | name: it.name,
131 | type: "file",
132 | };
133 | }
134 | })
135 | );
136 | };
137 | const result = await listDir("/tmp/scratch");
138 | console.log("listDir result", result);
139 | return result;
140 | }
141 |
142 | async function installDeps() {
143 | const webcontainer = await getInstance();
144 |
145 | const x = async (
146 | webcontainer: WebContainer,
147 | command: string,
148 | args: string[] = []
149 | ) => {
150 | console.log("running", command, args);
151 | const process = await webcontainer.spawn(command, args, {
152 | output: true,
153 | terminal: {
154 | cols: 80,
155 | rows: 32,
156 | },
157 | });
158 | const reader = process.output.pipeTo(
159 | new WritableStream({
160 | write(chunk) {
161 | console.log("[Output] ", chunk);
162 | },
163 | })
164 | );
165 |
166 | await process.kill();
167 | };
168 |
169 | console.log("starting install deps");
170 |
171 | if (!webcontainer) return;
172 |
173 | await x(webcontainer, "cd", ["./tmp/scratch"]);
174 | await x(webcontainer, "ls", ["/usr/local/bin"]);
175 |
176 | // await x(webcontainer, "ls");
177 | // await x(webcontainer, "npm", ["install"]);
178 | }
179 |
--------------------------------------------------------------------------------
/all-in-one/src/components/Editor/Editor.tsx:
--------------------------------------------------------------------------------
1 | import MonacoEditor from "@monaco-editor/react";
2 | import type { editor } from "monaco-editor";
3 | import type { Monaco } from "@monaco-editor/react";
4 |
5 | import { useEffect, useRef } from "react";
6 |
7 | import Terminal from "./Terminal";
8 |
9 | import { vueSfc } from "./vue-sfc";
10 | import { svelteSfc } from "./svelte-sfc";
11 | import getInstance from "@/app/bootWebContainer";
12 | import { WebContainer } from "@webcontainer/api";
13 | import type { FileTreeItem } from "./FileTree";
14 |
15 | export type EditorProps = {
16 | input: string;
17 | language: string;
18 | file: FileTreeItem | null;
19 | webcontainer: WebContainer | null;
20 | onChange: (value: string) => void;
21 | };
22 | export default function Editor({
23 | input = "",
24 | language = "javascript",
25 | file,
26 | webcontainer,
27 | onChange = () => {},
28 | }: EditorProps) {
29 | const monaco$ = useRef(null);
30 | const editor$ = useRef(null);
31 |
32 | useEffect(() => {
33 | if (monaco$.current && editor$.current) {
34 | const model = monaco$.current.editor.createModel(
35 | input,
36 | language,
37 | monaco$.current.Uri.parse(file?.name ?? "")
38 | );
39 |
40 | editor$.current.setModel(model);
41 |
42 | if (file?.name.endsWith(".jsx") || file?.name.endsWith(".tsx")) {
43 | monaco$.current.languages.typescript.typescriptDefaults.setCompilerOptions(
44 | {
45 | jsx: monaco$.current.languages.typescript.JsxEmit.React,
46 | }
47 | );
48 | }
49 | }
50 | }, [language, file]);
51 |
52 | useEffect(() => {
53 | if (monaco$.current) {
54 | monaco$.current.languages.register({ id: "vue-sfc" });
55 | monaco$.current.languages.setLanguageConfiguration("vue-sfc", {
56 | brackets: [["<", ">"]],
57 | autoClosingPairs: [
58 | { open: "<", close: ">" },
59 | { open: '"', close: '"' },
60 | { open: "'", close: "'" },
61 | { open: "`", close: "`" },
62 | ],
63 | });
64 | monaco$.current.languages.setTokensProvider("vue-sfc", vueSfc);
65 |
66 | monaco$.current.languages.register({ id: "svelte-sfc" });
67 |
68 | monaco$.current.languages.setLanguageConfiguration("svelte-sfc", {
69 | brackets: [["<", ">"]],
70 | autoClosingPairs: [
71 | { open: "<", close: ">" },
72 | { open: '"', close: '"' },
73 | { open: "'", close: "'" },
74 | { open: "`", close: "`" },
75 | ],
76 | });
77 |
78 | monaco$.current.languages.setTokensProvider("svelte-sfc", svelteSfc);
79 | }
80 | }, [monaco$.current !== null]);
81 |
82 | const onInputChange = (value: string | undefined) => {
83 | onChange(value ?? "");
84 | };
85 |
86 | return (
87 | {
90 | if (e.key === "s" && e.ctrlKey) {
91 | e.preventDefault();
92 | if (file) {
93 | console.log("save", file, input, webcontainer);
94 | webcontainer?.fs.writeFile(file.path, input);
95 | }
96 | }
97 | }}>
98 |
{
100 | editor$.current = editor;
101 | monaco$.current = monaco;
102 | }}
103 | options={{
104 | fontSize: 16,
105 | minimap: { enabled: true },
106 | }}
107 | language={language}
108 | value={input}
109 | onChange={onInputChange}
110 | />
111 |
112 |
119 |
120 |
121 |
122 |
123 | );
124 | }
125 |
--------------------------------------------------------------------------------
/all-in-one/src/components/Editor/FileTree.tsx:
--------------------------------------------------------------------------------
1 | import { IconButton } from "@mui/material";
2 | import TreeView from "@mui/lab/TreeView";
3 | import TreeItem, { TreeItemProps } from "@mui/lab/TreeItem";
4 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5 | import { faRefresh, faDownload } from "@fortawesome/free-solid-svg-icons";
6 |
7 | export type FileTreeItem = {
8 | path: string;
9 | name: string;
10 | type: "file" | "folder";
11 | children?: FileTreeItem[];
12 | };
13 |
14 | export type Props = {
15 | items: FileTreeItem[];
16 | refresh: () => void;
17 | downloadDeps: () => void;
18 | onSelected: (item: FileTreeItem) => void;
19 | };
20 |
21 | export default function FileTree({
22 | items = [],
23 | refresh,
24 | onSelected,
25 | downloadDeps,
26 | }: Props) {
27 | return (
28 |
29 |
30 | {/* top */}
31 | {
33 | refresh?.();
34 | }}>
35 |
36 |
37 | {
39 | downloadDeps?.();
40 | }}>
41 |
42 |
43 |
44 |
{
47 | const item = findItem(items, id);
48 | if (item) {
49 | onSelected(item);
50 | }
51 | }}>
52 | {}
53 |
54 |
55 | );
56 | }
57 |
58 | function findItem(items: FileTreeItem[], path: string): FileTreeItem | null {
59 | for (const item of items) {
60 | if (item.path === path) return item;
61 | if (item.children) {
62 | const r = findItem(item.children, path);
63 | if (r) return r;
64 | }
65 | }
66 |
67 | return null;
68 | }
69 |
70 | function Items({ items = [] }: { items: FileTreeItem[] | undefined }) {
71 | if (!items) return <>>;
72 |
73 | return (
74 | <>
75 | {items.map((item) => {
76 | return (
77 | }
82 | />
83 | );
84 | })}
85 | >
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/all-in-one/src/components/Editor/Terminal.css:
--------------------------------------------------------------------------------
1 | .terminal-container {
2 | /* this is important */
3 | overflow: hidden;
4 | }
5 |
6 | .xterm .xterm-viewport {
7 | /* see : https://github.com/xtermjs/xterm.js/issues/3564#issuecomment-1004417440 */
8 | width: initial !important;
9 | }
--------------------------------------------------------------------------------
/all-in-one/src/components/Editor/Terminal.tsx:
--------------------------------------------------------------------------------
1 | import { WebContainer, WebContainerProcess } from "@webcontainer/api";
2 | import { useEffect, useRef, useState } from "react";
3 | import { Terminal as Xterm } from "xterm";
4 | import { FitAddon } from "xterm-addon-fit";
5 |
6 | import "xterm/css/xterm.css";
7 | import "./Terminal.css";
8 |
9 | export type TerminalProps = {
10 | className?: string;
11 | webcontainer: WebContainer | null;
12 | };
13 |
14 | export default function Terminal({ className, webcontainer }: TerminalProps) {
15 | const terminal$ = useRef(null);
16 | const [term, setTerm] = useState(null);
17 |
18 | useEffect(() => {
19 | if (terminal$.current && webcontainer) {
20 | const term = new Xterm({
21 | convertEol: true,
22 |
23 | scrollOnUserInput: true,
24 | cursorBlink: true,
25 | cursorStyle: "block",
26 | fontFamily: "Fira Code",
27 | fontSize: 14,
28 | lineHeight: 1.5,
29 | theme: {
30 | background: "#fafafa",
31 | foreground: "#18181b",
32 | },
33 | });
34 | const fitAddon = new FitAddon();
35 | term.loadAddon(fitAddon);
36 |
37 | term.open(terminal$.current);
38 | document.body.addEventListener("resize", () => {
39 | fitAddon.fit();
40 | });
41 | setTimeout(() => {
42 | fitAddon.fit();
43 | }, 500);
44 |
45 | let shellProcess: WebContainerProcess | null = null;
46 |
47 | console.log("spawn jsh", webcontainer);
48 | webcontainer.spawn("jsh", {}).then(async (proc) => {
49 | shellProcess = proc;
50 | proc.output.pipeTo(
51 | new WritableStream({
52 | write(data) {
53 | console.log(
54 | "proc.output",
55 | data
56 | // new TextEncoder()
57 | // .encode(data)
58 | // .reduce((t, x) => t + x.toString(16).padStart(2, "0"), "")
59 | );
60 |
61 | if (data === "\x1b\x5b\x3f\x32\x30\x30\x34\x68") {
62 | console.log("ignore");
63 | return;
64 | }
65 | term.write(data);
66 | },
67 | })
68 | );
69 |
70 | const writer = proc.input.getWriter();
71 | setTimeout(() => {
72 | term.clear();
73 | writer.write("clear\n");
74 | }, 2500);
75 | term.onData((data) => {
76 | console.log("term.onData", data);
77 | writer.write(data);
78 | });
79 | });
80 | setTerm(term);
81 |
82 | return () => {
83 | term.dispose();
84 | setTerm(null);
85 | if (terminal$.current) {
86 | terminal$.current.innerHTML = "";
87 | }
88 | shellProcess?.kill();
89 | };
90 | }
91 | }, [webcontainer]);
92 |
93 | return (
94 |
97 | );
98 | }
99 |
--------------------------------------------------------------------------------
/all-in-one/src/components/Editor/svelte-sfc.ts:
--------------------------------------------------------------------------------
1 | // generated by GPT-4
2 |
3 | class SvelteSFCState {
4 | constructor(public state: string) {}
5 |
6 | clone(): SvelteSFCState {
7 | return new SvelteSFCState(this.state);
8 | }
9 |
10 | equals(other: SvelteSFCState): boolean {
11 | return this.state === other.state;
12 | }
13 | }
14 | const SvelteSFCStateHtml = new SvelteSFCState("html");
15 | const SvelteSFCStateJavascript = new SvelteSFCState("javascript");
16 | const SvelteSFCStateCss = new SvelteSFCState("css");
17 |
18 | export const svelteSfc: any = {
19 | getInitialState: function () {
20 | return SvelteSFCStateHtml.clone();
21 | },
22 | tokenize: function (line: any, state: SvelteSFCState) {
23 | let tokens: any = [];
24 | let offset = 0;
25 |
26 | function addToken(type: any, length: any) {
27 | tokens.push({
28 | startIndex: offset,
29 | scopes: type,
30 | });
31 | offset += length;
32 | }
33 |
34 | if (state.equals(SvelteSFCStateHtml)) {
35 | if (line.trim().startsWith("