Compare commits
18 Commits
main
...
feat/ts-su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
513db7bf09 | ||
|
|
969fd0f63c | ||
|
|
bd1a0c9836 | ||
|
|
ba95eb5be2 | ||
|
|
6911bcc0f3 | ||
|
|
a6055feb1f | ||
|
|
31a185f49f | ||
|
|
d693458421 | ||
|
|
692bbeb9b2 | ||
|
|
a29368d633 | ||
|
|
0f32fcb71c | ||
|
|
90db6b1f12 | ||
|
|
dde0317544 | ||
|
|
a6ad39f6e8 | ||
|
|
0536e48cfe | ||
|
|
a08823a38b | ||
|
|
653e28583d | ||
|
|
e75443c8e2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -23,6 +23,7 @@
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
.yarn
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const DeployEditor = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`You haven't compiled any files yet, compile files on `}
|
{`You haven't compiled any files yet, compile files on `}
|
||||||
<NextLink shallow href={`/develop/${router.query.slug}`} passHref>
|
<NextLink legacyBehavior shallow href={`/develop/${router.query.slug}`} passHref>
|
||||||
<Link as="a">develop view</Link>
|
<Link as="a">develop view</Link>
|
||||||
</NextLink>
|
</NextLink>
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -155,9 +155,11 @@ const EditorNavigation = ({ renderNav }: { renderNav?: () => ReactNode }) => {
|
|||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={session?.user?.image || ''}
|
src={session?.user?.image || ''}
|
||||||
width="30px"
|
width="30"
|
||||||
height="30px"
|
height="30"
|
||||||
objectFit="cover"
|
style={{
|
||||||
|
objectFit: 'cover'
|
||||||
|
}}
|
||||||
alt="User avatar"
|
alt="User avatar"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ const EnrichLog: FC<EnrichLogProps> = ({ str }) => {
|
|||||||
if (match.startsWith('HookSet')) {
|
if (match.startsWith('HookSet')) {
|
||||||
const code = match.match(/^HookSet\((\d+)\)/)?.[1]
|
const code = match.match(/^HookSet\((\d+)\)/)?.[1]
|
||||||
const val = hookSetCodes.find(v => code && v.code === +code)
|
const val = hookSetCodes.find(v => code && v.code === +code)
|
||||||
console.log({ code, val })
|
|
||||||
if (!val) return match
|
if (!val) return match
|
||||||
|
|
||||||
const content = capitalize(val.description) || 'No hint available!'
|
const content = capitalize(val.description) || 'No hint available!'
|
||||||
|
|||||||
@@ -94,6 +94,14 @@ const setMarkers = (monacoE: typeof monaco) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const langWarnings: Record<string, { shown: boolean; message: string }> = {
|
||||||
|
ts: {
|
||||||
|
shown: false,
|
||||||
|
message:
|
||||||
|
'Typescript suppport for hooks is still in early planning stage, write actual hooks in C only for now!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const HooksEditor = () => {
|
const HooksEditor = () => {
|
||||||
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>()
|
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>()
|
||||||
const monacoRef = useRef<typeof monaco>()
|
const monacoRef = useRef<typeof monaco>()
|
||||||
@@ -125,6 +133,14 @@ const HooksEditor = () => {
|
|||||||
|
|
||||||
const file = snap.files[snap.active]
|
const file = snap.files[snap.active]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let warning = langWarnings[file?.language || '']
|
||||||
|
if (warning && !warning.shown) {
|
||||||
|
alert(warning.message) // TODO Custom dialog.
|
||||||
|
warning.shown = true
|
||||||
|
}
|
||||||
|
}, [file])
|
||||||
|
|
||||||
const renderNav = () => (
|
const renderNav = () => (
|
||||||
<Tabs
|
<Tabs
|
||||||
label="File"
|
label="File"
|
||||||
@@ -221,7 +237,7 @@ const HooksEditor = () => {
|
|||||||
monaco.languages.register({
|
monaco.languages.register({
|
||||||
id: 'text',
|
id: 'text',
|
||||||
extensions: ['.txt'],
|
extensions: ['.txt'],
|
||||||
mimetypes: ['text/plain'],
|
mimetypes: ['text/plain']
|
||||||
})
|
})
|
||||||
MonacoServices.install(monaco)
|
MonacoServices.install(monaco)
|
||||||
const webSocket = createWebSocket(
|
const webSocket = createWebSocket(
|
||||||
@@ -240,7 +256,7 @@ const HooksEditor = () => {
|
|||||||
try {
|
try {
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err', err)
|
console.error('err', err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export const Log: FC<ILog> = ({
|
|||||||
)}
|
)}
|
||||||
<Pre>{message}</Pre>
|
<Pre>{message}</Pre>
|
||||||
{link && (
|
{link && (
|
||||||
<NextLink href={link} shallow passHref>
|
<NextLink legacyBehavior href={link} shallow passHref>
|
||||||
<Link as="a">{linkText}</Link>
|
<Link as="a">{linkText}</Link>
|
||||||
</NextLink>
|
</NextLink>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Link from 'next/link'
|
import NextLink from 'next/link'
|
||||||
|
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
@@ -78,7 +78,7 @@ const Navigation = () => {
|
|||||||
pr: '$4'
|
pr: '$4'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Link href={gistId ? `/develop/${gistId}` : '/develop'} passHref>
|
<NextLink legacyBehavior href={gistId ? `/develop/${gistId}` : '/develop'} passHref>
|
||||||
<Box
|
<Box
|
||||||
as="a"
|
as="a"
|
||||||
css={{
|
css={{
|
||||||
@@ -89,7 +89,7 @@ const Navigation = () => {
|
|||||||
>
|
>
|
||||||
<Logo width="32px" height="32px" />
|
<Logo width="32px" height="32px" />
|
||||||
</Box>
|
</Box>
|
||||||
</Link>
|
</NextLink>
|
||||||
<Flex
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
ml: '$5',
|
ml: '$5',
|
||||||
@@ -105,7 +105,8 @@ const Navigation = () => {
|
|||||||
<Text css={{ fontSize: '$xs', color: '$mauve10', lineHeight: 1 }}>
|
<Text css={{ fontSize: '$xs', color: '$mauve10', lineHeight: 1 }}>
|
||||||
{snap.files.length > 0 ? 'Gist: ' : 'Builder'}
|
{snap.files.length > 0 ? 'Gist: ' : 'Builder'}
|
||||||
{snap.files.length > 0 && (
|
{snap.files.length > 0 && (
|
||||||
<Link
|
<NextLink
|
||||||
|
legacyBehavior
|
||||||
href={`https://gist.github.com/${snap.gistOwner || ''}/${snap.gistId || ''}`}
|
href={`https://gist.github.com/${snap.gistOwner || ''}/${snap.gistId || ''}`}
|
||||||
passHref
|
passHref
|
||||||
>
|
>
|
||||||
@@ -117,7 +118,7 @@ const Navigation = () => {
|
|||||||
>
|
>
|
||||||
{`${snap.gistOwner || '-'}/${truncate(snap.gistId || '')}`}
|
{`${snap.gistOwner || '-'}/${truncate(snap.gistId || '')}`}
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</NextLink>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
@@ -336,29 +337,39 @@ const Navigation = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Link href={gistId ? `/develop/${gistId}` : '/develop'} passHref shallow>
|
<NextLink
|
||||||
|
legacyBehavior
|
||||||
|
href={gistId ? `/develop/${gistId}` : '/develop'}
|
||||||
|
passHref
|
||||||
|
shallow
|
||||||
|
>
|
||||||
<Button as="a" outline={!router.pathname.includes('/develop')} uppercase>
|
<Button as="a" outline={!router.pathname.includes('/develop')} uppercase>
|
||||||
Develop
|
Develop
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</NextLink>
|
||||||
<Link href={gistId ? `/deploy/${gistId}` : '/deploy'} passHref shallow>
|
<NextLink
|
||||||
|
legacyBehavior
|
||||||
|
href={gistId ? `/deploy/${gistId}` : '/deploy'}
|
||||||
|
passHref
|
||||||
|
shallow
|
||||||
|
>
|
||||||
<Button as="a" outline={!router.pathname.includes('/deploy')} uppercase>
|
<Button as="a" outline={!router.pathname.includes('/deploy')} uppercase>
|
||||||
Deploy
|
Deploy
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</NextLink>
|
||||||
<Link href={gistId ? `/test/${gistId}` : '/test'} passHref shallow>
|
<NextLink legacyBehavior href={gistId ? `/test/${gistId}` : '/test'} passHref shallow>
|
||||||
<Button as="a" outline={!router.pathname.includes('/test')} uppercase>
|
<Button as="a" outline={!router.pathname.includes('/test')} uppercase>
|
||||||
Test
|
Test
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</NextLink>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<Link href="https://xrpl-hooks.readme.io/v2.0" passHref>
|
<NextLink legacyBehavior href="https://xrpl-hooks.readme.io/v2.0" passHref>
|
||||||
<a target="_blank" rel="noreferrer noopener">
|
<a target="_blank" rel="noreferrer noopener">
|
||||||
<Button outline>
|
<Button outline>
|
||||||
<BookOpen size="15px" />
|
<BookOpen size="15px" />
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</NextLink>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { NextRequest, NextFetchEvent } from 'next/server'
|
import type { NextRequest } from 'next/server'
|
||||||
import { NextResponse as Response } from 'next/server'
|
import { NextResponse as Response } from 'next/server'
|
||||||
|
|
||||||
export default function middleware(req: NextRequest, ev: NextFetchEvent) {
|
export default function middleware(req: NextRequest) {
|
||||||
if (req.nextUrl.pathname === '/') {
|
if (req.nextUrl.pathname === '/') {
|
||||||
const url = req.nextUrl.clone()
|
const url = req.nextUrl.clone()
|
||||||
url.pathname = '/develop'
|
url.pathname = '/develop'
|
||||||
@@ -8,8 +8,16 @@ module.exports = {
|
|||||||
config.resolve.alias['vscode'] = require.resolve(
|
config.resolve.alias['vscode'] = require.resolve(
|
||||||
'@codingame/monaco-languageclient/lib/vscode-compatibility'
|
'@codingame/monaco-languageclient/lib/vscode-compatibility'
|
||||||
)
|
)
|
||||||
|
config.experiments = {
|
||||||
|
topLevelAwait: true,
|
||||||
|
layers: true
|
||||||
|
}
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
config.resolve.fallback.fs = false
|
config.resolve.fallback = {
|
||||||
|
...config.resolve.fallback,
|
||||||
|
fs: false,
|
||||||
|
module: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
test: [/\.md$/, /hook-bundle\.js$/],
|
test: [/\.md$/, /hook-bundle\.js$/],
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -14,6 +14,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codingame/monaco-jsonrpc": "^0.3.1",
|
"@codingame/monaco-jsonrpc": "^0.3.1",
|
||||||
"@codingame/monaco-languageclient": "^0.17.0",
|
"@codingame/monaco-languageclient": "^0.17.0",
|
||||||
|
"@eqlabs/assemblyscript": "^0.0.0-alpha.1680097351",
|
||||||
"@monaco-editor/react": "^4.4.5",
|
"@monaco-editor/react": "^4.4.5",
|
||||||
"@octokit/core": "^3.5.1",
|
"@octokit/core": "^3.5.1",
|
||||||
"@radix-ui/colors": "^0.1.7",
|
"@radix-ui/colors": "^0.1.7",
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
"lodash.xor": "^4.5.0",
|
"lodash.xor": "^4.5.0",
|
||||||
"monaco-editor": "^0.33.0",
|
"monaco-editor": "^0.33.0",
|
||||||
"next": "^12.0.4",
|
"next": "^13.1.1",
|
||||||
"next-auth": "^4.10.3",
|
"next-auth": "^4.10.3",
|
||||||
"next-plausible": "^3.2.0",
|
"next-plausible": "^3.2.0",
|
||||||
"next-themes": "^0.1.1",
|
"next-themes": "^0.1.1",
|
||||||
@@ -49,8 +50,8 @@
|
|||||||
"postinstall-postinstall": "^2.1.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"re-resizable": "^6.9.1",
|
"re-resizable": "^6.9.1",
|
||||||
"react": "17.0.2",
|
"react": "^18.2.0",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.28.0",
|
"react-hook-form": "^7.28.0",
|
||||||
"react-hot-keys": "^2.7.1",
|
"react-hot-keys": "^2.7.1",
|
||||||
"react-hot-toast": "^2.1.1",
|
"react-hot-toast": "^2.1.1",
|
||||||
@@ -65,7 +66,7 @@
|
|||||||
"valtio": "^1.2.5",
|
"valtio": "^1.2.5",
|
||||||
"vscode-languageserver": "^7.0.0",
|
"vscode-languageserver": "^7.0.0",
|
||||||
"vscode-uri": "^3.0.2",
|
"vscode-uri": "^3.0.2",
|
||||||
"wabt": "^1.0.30",
|
"wabt": "^1.0.32",
|
||||||
"xrpl-accountlib": "^1.6.1",
|
"xrpl-accountlib": "^1.6.1",
|
||||||
"xrpl-client": "^2.0.2"
|
"xrpl-client": "^2.0.2"
|
||||||
},
|
},
|
||||||
@@ -78,7 +79,7 @@
|
|||||||
"@types/react": "17.0.31",
|
"@types/react": "17.0.31",
|
||||||
"browserify": "^17.0.0",
|
"browserify": "^17.0.0",
|
||||||
"eslint": "7.32.0",
|
"eslint": "7.32.0",
|
||||||
"eslint-config-next": "11.1.2",
|
"eslint-config-next": "^13.1.1",
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"typescript": "4.4.4"
|
"typescript": "4.4.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { ChatCircleText } from 'phosphor-react'
|
|||||||
TimeAgo.setDefaultLocale(en.locale)
|
TimeAgo.setDefaultLocale(en.locale)
|
||||||
TimeAgo.addLocale(en)
|
TimeAgo.addLocale(en)
|
||||||
|
|
||||||
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
|
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps<{ session?: any }>) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const slug = router.query?.slug
|
const slug = router.query?.slug
|
||||||
const gistId = (Array.isArray(slug) && slug[0]) ?? null
|
const gistId = (Array.isArray(slug) && slug[0]) ?? null
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export default async function handler(
|
|||||||
}
|
}
|
||||||
return res.status(200).json(json)
|
return res.status(200).json(json)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.error(err)
|
||||||
return res.status(500).json({ error: 'Server error' })
|
return res.status(500).json({ error: 'Server error' })
|
||||||
}
|
}
|
||||||
return res.status(500).json({ error: 'Not able to create faucet, try again' })
|
return res.status(500).json({ error: 'Not able to create faucet, try again' })
|
||||||
|
|||||||
@@ -150,7 +150,9 @@ const Home: NextPage = () => {
|
|||||||
|
|
||||||
const activeFile = snap.files[snap.active] as IFile | undefined
|
const activeFile = snap.files[snap.active] as IFile | undefined
|
||||||
const activeFileExt = getFileExtention(activeFile?.name)
|
const activeFileExt = getFileExtention(activeFile?.name)
|
||||||
const canCompile = activeFileExt === 'c' || activeFileExt === 'wat'
|
const canCompile = activeFileExt === 'c' || activeFileExt === 'wat' || activeFileExt === 'ts'
|
||||||
|
|
||||||
|
const isCompiling = snap.compiling.includes(snap.active);
|
||||||
return (
|
return (
|
||||||
<Split
|
<Split
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
@@ -166,7 +168,9 @@ const Home: NextPage = () => {
|
|||||||
{canCompile && (
|
{canCompile && (
|
||||||
<Hotkeys
|
<Hotkeys
|
||||||
keyName="command+b,ctrl+b"
|
keyName="command+b,ctrl+b"
|
||||||
onKeyDown={() => !snap.compiling && snap.files.length && compileCode(snap.active)}
|
onKeyDown={() =>
|
||||||
|
snap.compiling === undefined && snap.files.length && compileCode(snap.active)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
@@ -183,7 +187,7 @@ const Home: NextPage = () => {
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
uppercase
|
uppercase
|
||||||
disabled={!snap.files.length}
|
disabled={!snap.files.length}
|
||||||
isLoading={snap.compiling}
|
isLoading={isCompiling}
|
||||||
onClick={() => compileCode(snap.active)}
|
onClick={() => compileCode(snap.active)}
|
||||||
>
|
>
|
||||||
<Play weight="bold" size="16px" />
|
<Play weight="bold" size="16px" />
|
||||||
@@ -200,7 +204,9 @@ const Home: NextPage = () => {
|
|||||||
{activeFileExt === 'js' && (
|
{activeFileExt === 'js' && (
|
||||||
<Hotkeys
|
<Hotkeys
|
||||||
keyName="command+b,ctrl+b"
|
keyName="command+b,ctrl+b"
|
||||||
onKeyDown={() => !snap.compiling && snap.files.length && compileCode(snap.active)}
|
onKeyDown={() =>
|
||||||
|
!isCompiling && snap.files.length && compileCode(snap.active)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
css={{
|
css={{
|
||||||
|
|||||||
@@ -1,40 +1,91 @@
|
|||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import Router from 'next/router'
|
import Router from 'next/router'
|
||||||
|
|
||||||
import state from '../index'
|
import state, { IFile } from '../index'
|
||||||
import { saveFile } from './saveFile'
|
import { saveFile } from './saveFile'
|
||||||
import { decodeBinary } from '../../utils/decodeBinary'
|
import { decodeBinary } from '../../utils/decodeBinary'
|
||||||
import { ref } from 'valtio'
|
import { ref } from 'valtio'
|
||||||
|
import asc from "@eqlabs/assemblyscript/dist/asc"
|
||||||
|
import { getFileExtention } from '../../utils/helpers'
|
||||||
|
|
||||||
/* compileCode sends the code of the active file to compile endpoint
|
type CompilationResult = Pick<IFile, "compiledContent" | "compiledWatContent">
|
||||||
|
|
||||||
|
export const compileCode = async (activeId: number) => {
|
||||||
|
// Save the file to global state
|
||||||
|
saveFile(false, activeId)
|
||||||
|
const file = state.files[activeId]
|
||||||
|
|
||||||
|
// Bail out if we're already compiling the file.
|
||||||
|
if (!file || state.compiling.includes(activeId)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
state.compiling.push(activeId)
|
||||||
|
state.logs = []
|
||||||
|
file.containsErrors = false
|
||||||
|
|
||||||
|
let result: CompilationResult;
|
||||||
|
if (file.name.endsWith('.wat')) {
|
||||||
|
result = await compileWat(file);
|
||||||
|
}
|
||||||
|
else if (file.language === "ts") {
|
||||||
|
result = await compileTs(file);
|
||||||
|
}
|
||||||
|
else if (navigator?.onLine === false) {
|
||||||
|
throw Error('You seem offline, check you internet connection and try again!')
|
||||||
|
}
|
||||||
|
else if (file.language === 'c') {
|
||||||
|
result = await compileC(file)
|
||||||
|
}
|
||||||
|
else throw Error("Unknown file type.")
|
||||||
|
|
||||||
|
file.lastCompiled = new Date();
|
||||||
|
file.compiledValueSnapshot = file.content;
|
||||||
|
file.compiledContent = result.compiledContent;
|
||||||
|
file.compiledWatContent = result.compiledWatContent;
|
||||||
|
toast.success('Compiled successfully!', { position: 'bottom-center' })
|
||||||
|
state.logs.push({
|
||||||
|
type: 'success',
|
||||||
|
message: `File ${state.files?.[activeId]?.name} compiled successfully. Ready to deploy.`,
|
||||||
|
link: Router.asPath.replace('develop', 'deploy'),
|
||||||
|
linkText: 'Go to deploy'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
let message: string;
|
||||||
|
|
||||||
|
if (err instanceof Array && typeof err[0] === 'string') {
|
||||||
|
err.forEach(message => {
|
||||||
|
state.logs.push({
|
||||||
|
type: 'error',
|
||||||
|
message
|
||||||
|
})
|
||||||
|
})
|
||||||
|
message = "Compilation errors occurred, see logs for more info."
|
||||||
|
} else if (err instanceof Error) {
|
||||||
|
message = err.message
|
||||||
|
} else {
|
||||||
|
message = 'Something went wrong, try again later!'
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.error(message, { position: 'bottom-center' })
|
||||||
|
file.containsErrors = true
|
||||||
|
}
|
||||||
|
state.compiling = state.compiling.filter(id => id !== activeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compileC sends the code of the active file to compile endpoint
|
||||||
* If all goes well you will get base64 encoded wasm file back with
|
* If all goes well you will get base64 encoded wasm file back with
|
||||||
* some extra logging information if we can provide it. This function
|
* some extra logging information if we can provide it. This function
|
||||||
* also decodes the returned wasm and creates human readable WAT file
|
* also decodes the returned wasm and creates human readable WAT file
|
||||||
* out of it and store both in global state.
|
* out of it and store both in global state.
|
||||||
*/
|
*/
|
||||||
export const compileCode = async (activeId: number) => {
|
export const compileC = async (file: IFile): Promise<CompilationResult> => {
|
||||||
// Save the file to global state
|
|
||||||
saveFile(false, activeId)
|
|
||||||
const file = state.files[activeId]
|
|
||||||
if (file.name.endsWith('.wat')) {
|
|
||||||
return compileWat(activeId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT) {
|
if (!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT) {
|
||||||
throw Error('Missing env!')
|
throw Error('Missing C compile endpoint!')
|
||||||
}
|
}
|
||||||
// Bail out if we're already compiling
|
|
||||||
if (state.compiling) {
|
|
||||||
// if compiling is ongoing return // TODO Inform user about it.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Set loading state to true
|
|
||||||
state.compiling = true
|
|
||||||
state.logs = []
|
|
||||||
try {
|
|
||||||
file.containsErrors = false
|
|
||||||
let res: Response
|
let res: Response
|
||||||
try {
|
|
||||||
res = await fetch(process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT, {
|
res = await fetch(process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -54,11 +105,8 @@ export const compileCode = async (activeId: number) => {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} catch (error) {
|
|
||||||
throw Error('Something went wrong, check your network connection and try again!')
|
|
||||||
}
|
|
||||||
const json = await res.json()
|
const json = await res.json()
|
||||||
state.compiling = false
|
|
||||||
if (!json.success) {
|
if (!json.success) {
|
||||||
const errors = [json.message]
|
const errors = [json.message]
|
||||||
if (json.tasks && json.tasks.length > 0) {
|
if (json.tasks && json.tasks.length > 0) {
|
||||||
@@ -84,88 +132,87 @@ export const compileCode = async (activeId: number) => {
|
|||||||
|
|
||||||
const wast = myModule.toText({ foldExprs: false, inlineExport: false })
|
const wast = myModule.toText({ foldExprs: false, inlineExport: false })
|
||||||
|
|
||||||
file.compiledContent = ref(bufferData)
|
return {
|
||||||
file.lastCompiled = new Date()
|
compiledContent: ref(bufferData),
|
||||||
file.compiledValueSnapshot = file.content
|
compiledWatContent: wast
|
||||||
file.compiledWatContent = wast
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw Error('Invalid compilation result produced, check your code for errors and try again!')
|
throw Error('Invalid compilation result produced, check your code for errors and try again!')
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('Compiled successfully!', { position: 'bottom-center' })
|
|
||||||
state.logs.push({
|
|
||||||
type: 'success',
|
|
||||||
message: `File ${state.files?.[activeId]?.name} compiled successfully. Ready to deploy.`,
|
|
||||||
link: Router.asPath.replace('develop', 'deploy'),
|
|
||||||
linkText: 'Go to deploy'
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
|
|
||||||
if (err instanceof Array && typeof err[0] === 'string') {
|
|
||||||
err.forEach(message => {
|
|
||||||
state.logs.push({
|
|
||||||
type: 'error',
|
|
||||||
message
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else if (err instanceof Error) {
|
|
||||||
state.logs.push({
|
|
||||||
type: 'error',
|
|
||||||
message: err.message
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
state.logs.push({
|
|
||||||
type: 'error',
|
|
||||||
message: 'Something went wrong, come back later!'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
state.compiling = false
|
|
||||||
toast.error(`Error occurred while compiling!`, { position: 'bottom-center' })
|
|
||||||
file.containsErrors = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const compileWat = async (activeId: number) => {
|
export const compileWat = async (file: IFile): Promise<CompilationResult> => {
|
||||||
if (state.compiling) return;
|
|
||||||
const file = state.files[activeId]
|
|
||||||
state.compiling = true
|
|
||||||
state.logs = []
|
|
||||||
try {
|
|
||||||
const wabt = await (await import('wabt')).default()
|
const wabt = await (await import('wabt')).default()
|
||||||
const module = wabt.parseWat(file.name, file.content);
|
const mod = wabt.parseWat(file.name, file.content);
|
||||||
module.resolveNames();
|
mod.resolveNames();
|
||||||
module.validate();
|
mod.validate();
|
||||||
const { buffer } = module.toBinary({
|
const { buffer } = mod.toBinary({
|
||||||
log: false,
|
log: false,
|
||||||
write_debug_names: true,
|
write_debug_names: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
file.compiledContent = ref(buffer)
|
return {
|
||||||
file.lastCompiled = new Date()
|
compiledContent: ref(buffer),
|
||||||
file.compiledValueSnapshot = file.content
|
compiledWatContent: file.content,
|
||||||
file.compiledWatContent = file.content
|
|
||||||
|
|
||||||
toast.success('Compiled successfully!', { position: 'bottom-center' })
|
|
||||||
state.logs.push({
|
|
||||||
type: 'success',
|
|
||||||
message: `File ${state.files?.[activeId]?.name} compiled successfully. Ready to deploy.`,
|
|
||||||
link: Router.asPath.replace('develop', 'deploy'),
|
|
||||||
linkText: 'Go to deploy'
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
let message = "Error compiling WAT file!"
|
|
||||||
if (err instanceof Error) {
|
|
||||||
message = err.message
|
|
||||||
}
|
}
|
||||||
state.logs.push({
|
}
|
||||||
type: 'error',
|
|
||||||
message
|
export const compileTs = async (file: IFile): Promise<CompilationResult> => {
|
||||||
})
|
return new Promise(async (resolve, reject) => {
|
||||||
toast.error(`Error occurred while compiling!`, { position: 'bottom-center' })
|
let result: Partial<CompilationResult> = {}
|
||||||
file.containsErrors = true
|
const { error, stdout, stderr } = await asc.main([
|
||||||
}
|
// Command line options
|
||||||
state.compiling = false
|
file.name,
|
||||||
|
"--outFile", `${file.name}.wasm`,
|
||||||
|
"--textFile", `${file.name}.wat`,
|
||||||
|
"--runtime", "stub",
|
||||||
|
"--initialMemory", "1",
|
||||||
|
"--maximumMemory", "1",
|
||||||
|
"--noExportMemory",
|
||||||
|
"--optimize",
|
||||||
|
"--topLevelToHook"
|
||||||
|
], {
|
||||||
|
readFile: (name, baseDir) => {
|
||||||
|
const file = state.files.find(file => file.name === name)
|
||||||
|
if (file) {
|
||||||
|
return file.content
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
writeFile: async (name, data: ArrayBuffer | string, baseDir) => {
|
||||||
|
const ext = getFileExtention(name);
|
||||||
|
if (ext === 'wasm') {
|
||||||
|
result.compiledContent = data as ArrayBuffer;
|
||||||
|
}
|
||||||
|
else if (ext === 'wat') {
|
||||||
|
result.compiledWatContent = data as string;
|
||||||
|
}
|
||||||
|
if (result.compiledContent && result.compiledWatContent) {
|
||||||
|
resolve({ ...result });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
listFiles: (dirname, baseDir) => {
|
||||||
|
return state.files.map(file => file.name)
|
||||||
|
},
|
||||||
|
// reportDiagnostic?: ...,
|
||||||
|
});
|
||||||
|
|
||||||
|
let logMsg = stdout.toString()
|
||||||
|
let errMsg = stderr.toString()
|
||||||
|
if (logMsg) {
|
||||||
|
state.logs.push({
|
||||||
|
type: "log",
|
||||||
|
message: logMsg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (errMsg) {
|
||||||
|
state.logs.push({
|
||||||
|
type: "error",
|
||||||
|
message: errMsg
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) return reject(error)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { getFileExtention } from '../../utils/helpers'
|
import { getFileExtention } from '../../utils/helpers'
|
||||||
import state, { IFile } from '../index'
|
import state, { IFile, ILang } from '../index'
|
||||||
|
|
||||||
const languageMapping: Record<string, string | undefined> = {
|
const languageMapping: Record<string, ILang | undefined> = {
|
||||||
ts: 'typescript',
|
ts: 'ts',
|
||||||
js: 'javascript',
|
js: 'javascript',
|
||||||
md: 'markdown',
|
md: 'markdown',
|
||||||
c: 'c',
|
c: 'c',
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ export const deleteHook = async (account: IAccount & { name?: string }) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.error(err)
|
||||||
toast.error('Error occurred while deleting hook', { id: toastId })
|
toast.error('Error occurred while deleting hook', { id: toastId })
|
||||||
state.deployLogs.push({
|
state.deployLogs.push({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Octokit } from '@octokit/core'
|
import { Octokit } from '@octokit/core'
|
||||||
import state, { IFile } from '../index'
|
import state, { IFile, ILang } from '../index'
|
||||||
import { templateFileIds } from '../constants'
|
import { templateFileIds } from '../constants'
|
||||||
|
|
||||||
const octokit = new Octokit()
|
const octokit = new Octokit()
|
||||||
@@ -48,7 +48,7 @@ export const fetchFiles = async (gistId: string) => {
|
|||||||
|
|
||||||
const files: IFile[] = Object.keys(res.data.files).map(filename => ({
|
const files: IFile[] = Object.keys(res.data.files).map(filename => ({
|
||||||
name: res.data.files?.[filename]?.filename || 'untitled.c',
|
name: res.data.files?.[filename]?.filename || 'untitled.c',
|
||||||
language: res.data.files?.[filename]?.language?.toLowerCase() || '',
|
language: res.data.files?.[filename]?.language?.toLowerCase() as ILang | undefined,
|
||||||
content: res.data.files?.[filename]?.content || ''
|
content: res.data.files?.[filename]?.content || ''
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export const syncToGist = async (session?: Session | null, createNewGist?: boole
|
|||||||
return toast.success('Updated to gist successfully!', { id: toastId })
|
return toast.success('Updated to gist successfully!', { id: toastId })
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err)
|
console.error(err)
|
||||||
state.gistLoading = false
|
state.gistLoading = false
|
||||||
return toast.error(`Could not update Gist, try again later!`, {
|
return toast.error(`Could not update Gist, try again later!`, {
|
||||||
id: toastId
|
id: toastId
|
||||||
@@ -85,7 +85,7 @@ export const syncToGist = async (session?: Session | null, createNewGist?: boole
|
|||||||
return toast.success('Created new gist successfully!', { id: toastId })
|
return toast.success('Created new gist successfully!', { id: toastId })
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err)
|
console.error(err)
|
||||||
state.gistLoading = false
|
state.gistLoading = false
|
||||||
return toast.error(`Could not create Gist, try again later!`, {
|
return toast.error(`Could not create Gist, try again later!`, {
|
||||||
id: toastId
|
id: toastId
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ declare module 'valtio' {
|
|||||||
function snapshot<T extends object>(p: T): T
|
function snapshot<T extends object>(p: T): T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ILang = "ts" | "javascript" | "markdown" | "c" | "text"
|
||||||
export interface IFile {
|
export interface IFile {
|
||||||
name: string
|
name: string
|
||||||
language: string
|
language: ILang | undefined
|
||||||
content: string
|
content: string
|
||||||
compiledValueSnapshot?: string
|
compiledValueSnapshot?: string
|
||||||
compiledContent?: ArrayBuffer | null
|
compiledContent?: ArrayBuffer | null
|
||||||
@@ -66,7 +67,7 @@ export interface IState {
|
|||||||
loading: boolean
|
loading: boolean
|
||||||
gistLoading: boolean
|
gistLoading: boolean
|
||||||
zipLoading: boolean
|
zipLoading: boolean
|
||||||
compiling: boolean
|
compiling: /* file id */ number[]
|
||||||
logs: ILog[]
|
logs: ILog[]
|
||||||
deployLogs: ILog[]
|
deployLogs: ILog[]
|
||||||
transactionLogs: ILog[]
|
transactionLogs: ILog[]
|
||||||
@@ -98,7 +99,7 @@ let initialState: IState = {
|
|||||||
// Active file index on the Deploy page editor
|
// Active file index on the Deploy page editor
|
||||||
activeWat: 0,
|
activeWat: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
compiling: false,
|
compiling: [],
|
||||||
logs: [],
|
logs: [],
|
||||||
deployLogs: [],
|
deployLogs: [],
|
||||||
transactionLogs: [],
|
transactionLogs: [],
|
||||||
@@ -135,7 +136,7 @@ if (typeof window !== 'undefined') {
|
|||||||
try {
|
try {
|
||||||
localStorageAccounts = localStorage.getItem('hooksIdeAccounts')
|
localStorageAccounts = localStorage.getItem('hooksIdeAccounts')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(`localStorage state broken`)
|
console.error(`localStorage state broken`)
|
||||||
localStorage.removeItem('hooksIdeAccounts')
|
localStorage.removeItem('hooksIdeAccounts')
|
||||||
}
|
}
|
||||||
if (localStorageAccounts) {
|
if (localStorageAccounts) {
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ export const getFileExtention = (filename?: string): string | undefined => {
|
|||||||
return ext
|
return ext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getFileNamePart = (filename?: string): string | undefined => {
|
||||||
|
if (!filename) return
|
||||||
|
const name = (filename.includes('.') && filename.split('.').slice(0, -1).join(".")) || filename
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
type Type = "array" | "undefined" | "object" | "string" | "number" | "bigint" | "boolean" | "symbol" | "function"
|
type Type = "array" | "undefined" | "object" | "string" | "number" | "bigint" | "boolean" | "symbol" | "function"
|
||||||
type obj = Record<string | number | symbol, unknown>
|
type obj = Record<string | number | symbol, unknown>
|
||||||
type arr = unknown[]
|
type arr = unknown[]
|
||||||
|
|||||||
Reference in New Issue
Block a user