fix monaco
This commit is contained in:
parent
bf19dbf50f
commit
a1c5166748
|
|
@ -9,7 +9,8 @@ import { EdMain } from "./panel/main/main";
|
||||||
import { EdPane } from "./panel/main/pane-resize";
|
import { EdPane } from "./panel/main/pane-resize";
|
||||||
import { EdPopCompGroup } from "./panel/popup/comp-group";
|
import { EdPopCompGroup } from "./panel/popup/comp-group";
|
||||||
import { EdPopSite } from "./panel/popup/site";
|
import { EdPopSite } from "./panel/popup/site";
|
||||||
import { jscript } from "../editor/panel/script/script-element";
|
import { EdScriptInit } from "./panel/script/monaco/init";
|
||||||
|
import { EdScriptSite } from "./panel/script/site";
|
||||||
|
|
||||||
export const EdBase = () => {
|
export const EdBase = () => {
|
||||||
const p = useGlobal(EDGlobal, "EDITOR");
|
const p = useGlobal(EDGlobal, "EDITOR");
|
||||||
|
|
@ -33,7 +34,6 @@ export const EdBase = () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Editor = jscript.editor;
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col flex-1">
|
<div className="flex flex-col flex-1">
|
||||||
<div className="flex justify-between"></div>
|
<div className="flex justify-between"></div>
|
||||||
|
|
@ -42,20 +42,11 @@ export const EdBase = () => {
|
||||||
<EdPane type="left" />
|
<EdPane type="left" />
|
||||||
<EdMain />
|
<EdMain />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<>
|
<>
|
||||||
<EdPopSite />
|
<EdPopSite />
|
||||||
<EdPopCompGroup />
|
<EdPopCompGroup />
|
||||||
{Editor && !jscript.ready && (
|
<EdScriptInit />
|
||||||
<div className="hidden">
|
<EdScriptSite />
|
||||||
<Editor
|
|
||||||
onMount={() => {
|
|
||||||
jscript.ready = true;
|
|
||||||
p.render();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ export const EDGlobal = {
|
||||||
| "ready",
|
| "ready",
|
||||||
sync: null as unknown as Awaited<ReturnType<typeof clientStartSync>>,
|
sync: null as unknown as Awaited<ReturnType<typeof clientStartSync>>,
|
||||||
site: EmptySite,
|
site: EmptySite,
|
||||||
|
script: { siteTypes: {} as Record<string, string> },
|
||||||
page: {
|
page: {
|
||||||
cur: EmptyPage,
|
cur: EmptyPage,
|
||||||
doc: null as null | DPage,
|
doc: null as null | DPage,
|
||||||
|
|
@ -86,6 +87,9 @@ export const EDGlobal = {
|
||||||
group: {} as Record<string, Awaited<ReturnType<SAction["comp"]["group"]>>>,
|
group: {} as Record<string, Awaited<ReturnType<SAction["comp"]["group"]>>>,
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
|
script: {
|
||||||
|
site: false,
|
||||||
|
},
|
||||||
layout: {
|
layout: {
|
||||||
left: parseInt(localStorage.getItem("prasi-layout-left") || "250"),
|
left: parseInt(localStorage.getItem("prasi-layout-left") || "250"),
|
||||||
right: parseInt(localStorage.getItem("prasi-layout-right") || "250"),
|
right: parseInt(localStorage.getItem("prasi-layout-right") || "250"),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import init from "wasm-gzip";
|
import init from "wasm-gzip";
|
||||||
import { PG } from "./ed-global";
|
import { PG } from "./ed-global";
|
||||||
import { jscript } from "../../editor/panel/script/script-element";
|
import { jscript } from "../../../utils/script/jscript";
|
||||||
|
|
||||||
export const edInit = async (p: PG) => {
|
export const edInit = async (p: PG) => {
|
||||||
await init();
|
await init();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { useLocal } from "web-utils";
|
||||||
|
import { jscript } from "../../../../../utils/script/jscript";
|
||||||
|
import { Loading } from "../../../../../utils/ui/loading";
|
||||||
|
|
||||||
|
export const EdScriptInit = () => {
|
||||||
|
const Editor = jscript.editor;
|
||||||
|
const local = useLocal({ editorLoaded: false }, () => {});
|
||||||
|
|
||||||
|
jscript.events.editorLoaded = () => {
|
||||||
|
local.editorLoaded = true;
|
||||||
|
local.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{Editor && local.editorLoaded && (
|
||||||
|
<div className="hidden">
|
||||||
|
<Editor
|
||||||
|
onMount={() => {
|
||||||
|
jscript.events.pendingDone();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EdMonacoWrap = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: (Editor: Exclude<typeof jscript.editor, null>) => ReactNode;
|
||||||
|
}) => {
|
||||||
|
const local = useLocal({});
|
||||||
|
|
||||||
|
if (jscript.pending && (!jscript.editor || !jscript.build)) {
|
||||||
|
jscript.pending.then(() => {
|
||||||
|
local.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
"flex flex-1 absolute inset-[80px]",
|
||||||
|
css`
|
||||||
|
.monaco-editor {
|
||||||
|
.mtk9 {
|
||||||
|
color: #022f62;
|
||||||
|
}
|
||||||
|
.mtk1 {
|
||||||
|
color: #022f62;
|
||||||
|
}
|
||||||
|
.mtk22 {
|
||||||
|
color: #015cc5;
|
||||||
|
}
|
||||||
|
.mtk8 {
|
||||||
|
color: #015cc5;
|
||||||
|
}
|
||||||
|
.mtk5 {
|
||||||
|
color: #55bb8a;
|
||||||
|
}
|
||||||
|
.monaco-editor.showUnused .squiggly-inline-unnecessary {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
.jsx-expression-braces {
|
||||||
|
color: #7c3813;
|
||||||
|
}
|
||||||
|
.jsx-tag-angle-bracket {
|
||||||
|
color: #619ac3;
|
||||||
|
}
|
||||||
|
.jsx-tag-name {
|
||||||
|
color: #619ac3;
|
||||||
|
}
|
||||||
|
.jsx-tag-order-1 {
|
||||||
|
color: #23863a;
|
||||||
|
}
|
||||||
|
.jsx-tag-order-2 {
|
||||||
|
color: #4e7ca1;
|
||||||
|
}
|
||||||
|
.jsx-tag-order-3 {
|
||||||
|
color: #020360;
|
||||||
|
}
|
||||||
|
.jsx-tag-attribute-key {
|
||||||
|
color: #6f42c1;
|
||||||
|
}
|
||||||
|
.jsx-text {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{!jscript.editor || !jscript.build ? (
|
||||||
|
<Loading note="script-cst" backdrop={false} />
|
||||||
|
) : (
|
||||||
|
children(jscript.editor)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { jsMount } from "../../../../../utils/script/mount";
|
||||||
|
import { monacoTypings } from "../../../../../utils/script/typings";
|
||||||
|
import { Modal } from "../../../../../utils/ui/modal";
|
||||||
|
import { EdMonacoWrap } from "./init";
|
||||||
|
import type { Editor } from "@monaco-editor/react";
|
||||||
|
|
||||||
|
const monacoState = {} as Record<string, any>;
|
||||||
|
export const EdMonaco = (arg: {
|
||||||
|
id?: string;
|
||||||
|
type: "js" | "html" | "css";
|
||||||
|
filename: string;
|
||||||
|
monaco: Parameters<typeof Editor>[0];
|
||||||
|
onClose: () => void;
|
||||||
|
prop?: {
|
||||||
|
val: Record<string, any>;
|
||||||
|
types: Record<string, string>;
|
||||||
|
};
|
||||||
|
}) => {
|
||||||
|
const filename = arg.filename;
|
||||||
|
const m = arg.monaco;
|
||||||
|
const prop = { ...arg.monaco };
|
||||||
|
|
||||||
|
prop.options = {
|
||||||
|
minimap: { enabled: false },
|
||||||
|
wordWrap: "wordWrapColumn",
|
||||||
|
autoClosingBrackets: "always",
|
||||||
|
tabSize: 2,
|
||||||
|
autoIndent: "full",
|
||||||
|
formatOnPaste: true,
|
||||||
|
formatOnType: true,
|
||||||
|
useTabStops: true,
|
||||||
|
};
|
||||||
|
if (arg.type === "html") {
|
||||||
|
prop.language = "html";
|
||||||
|
}
|
||||||
|
if (arg.type === "css") {
|
||||||
|
prop.language = "scss";
|
||||||
|
}
|
||||||
|
if (arg.type === "js") {
|
||||||
|
prop.language = "typescript";
|
||||||
|
prop.onMount = async (editor, monaco) => {
|
||||||
|
const value = editor.getValue();
|
||||||
|
monaco.editor.getModels().forEach((model) => {
|
||||||
|
if (model.uri.toString().startsWith("inmemory://model")) {
|
||||||
|
model.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let model = monaco.editor.createModel(
|
||||||
|
value,
|
||||||
|
"typescript",
|
||||||
|
monaco.Uri.parse(`ts:${filename}`)
|
||||||
|
);
|
||||||
|
editor.setModel(model);
|
||||||
|
|
||||||
|
if (arg.id) {
|
||||||
|
if (!monacoState[arg.id]) {
|
||||||
|
editor.trigger("fold", "editor.foldAllMarkerRegions", null);
|
||||||
|
} else {
|
||||||
|
editor.restoreViewState(monacoState[arg.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await jsMount(editor, monaco);
|
||||||
|
|
||||||
|
if (arg.prop)
|
||||||
|
await monacoTypings(
|
||||||
|
{
|
||||||
|
script: {
|
||||||
|
siteTypes: {},
|
||||||
|
},
|
||||||
|
site: {
|
||||||
|
api_url: "",
|
||||||
|
},
|
||||||
|
site_dts: "",
|
||||||
|
},
|
||||||
|
monaco,
|
||||||
|
{
|
||||||
|
values: arg.prop.val,
|
||||||
|
types: arg.prop.types,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (m.onMount) m.onMount(editor, monaco);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open
|
||||||
|
onOpenChange={() => {
|
||||||
|
arg.onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EdMonacoWrap>{(Editor) => <Editor {...prop} />}</EdMonacoWrap>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { useGlobal } from "web-utils";
|
||||||
|
import { EdMonaco } from "./monaco/monaco";
|
||||||
|
import { EDGlobal } from "../../logic/ed-global";
|
||||||
|
|
||||||
|
export const EdScriptSite = () => {
|
||||||
|
const p = useGlobal(EDGlobal, "EDITOR");
|
||||||
|
|
||||||
|
if (!p.ui.script.site) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<EdMonaco
|
||||||
|
id="script-site"
|
||||||
|
type="js"
|
||||||
|
filename="site.tsx"
|
||||||
|
monaco={{
|
||||||
|
value: p.site.js,
|
||||||
|
onChange: (v) => {
|
||||||
|
console.log(v);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
prop={{
|
||||||
|
val: {},
|
||||||
|
types: {
|
||||||
|
exports: "any",
|
||||||
|
types: "any",
|
||||||
|
render: "()=>void",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onClose={() => {
|
||||||
|
p.ui.script.site = false;
|
||||||
|
p.render();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export const EdScriptSite = () => {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -1,8 +1,18 @@
|
||||||
|
import { useGlobal } from "web-utils";
|
||||||
import { TopBtn } from "../top-btn";
|
import { TopBtn } from "../top-btn";
|
||||||
|
import { EDGlobal } from "../../../logic/ed-global";
|
||||||
|
|
||||||
export const EdSiteJS = () => {
|
export const EdSiteJS = () => {
|
||||||
|
const p = useGlobal(EDGlobal, "EDITOR");
|
||||||
return (
|
return (
|
||||||
<TopBtn style="slim" className="font-bold font-mono">
|
<TopBtn
|
||||||
|
style="slim"
|
||||||
|
className="font-bold font-mono"
|
||||||
|
onClick={() => {
|
||||||
|
p.ui.script.site = true;
|
||||||
|
p.render();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="16"
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ import {
|
||||||
mergeScopeUpwards,
|
mergeScopeUpwards,
|
||||||
treeScopeEval,
|
treeScopeEval,
|
||||||
} from "../logic/tree-scope";
|
} from "../logic/tree-scope";
|
||||||
import { jscript } from "../panel/script/script-element";
|
|
||||||
import { fillID } from "../tools/fill-id";
|
import { fillID } from "../tools/fill-id";
|
||||||
import { newMap } from "../tools/yjs-tools";
|
import { newMap } from "../tools/yjs-tools";
|
||||||
import { ComponentOver, ElProp, createElProp } from "./e-relprop";
|
import { ComponentOver, ElProp, createElProp } from "./e-relprop";
|
||||||
import { ETextInternal } from "./e-text";
|
import { ETextInternal } from "./e-text";
|
||||||
import { DefaultScript } from "../panel/script/monaco/monaco-el";
|
import { DefaultScript } from "../panel/script/monaco/monaco-el";
|
||||||
|
import { jscript } from "../../../utils/script/jscript";
|
||||||
|
|
||||||
export const ERender: FC<{
|
export const ERender: FC<{
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -185,9 +185,7 @@ export const ERender: FC<{
|
||||||
meta.mitem
|
meta.mitem
|
||||||
) {
|
) {
|
||||||
if (!jscript.build) {
|
if (!jscript.build) {
|
||||||
jscript.init().then(() => {
|
jscript.init(p.render);
|
||||||
p.render();
|
|
||||||
});
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
jscript
|
jscript
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import {
|
||||||
} from "../../../utils/script/init-api";
|
} from "../../../utils/script/init-api";
|
||||||
import { LSite } from "../../live/logic/global";
|
import { LSite } from "../../live/logic/global";
|
||||||
import { validateLayout } from "../../live/logic/layout";
|
import { validateLayout } from "../../live/logic/layout";
|
||||||
import { jscript } from "../panel/script/script-element";
|
|
||||||
import importModule from "../tools/dynamic-import";
|
import importModule from "../tools/dynamic-import";
|
||||||
import { PG } from "./global";
|
import { PG } from "./global";
|
||||||
import { devLoader } from "../../live/dev-loader";
|
import { devLoader } from "../../live/dev-loader";
|
||||||
|
import { jscript } from "../../../utils/script/jscript";
|
||||||
|
|
||||||
export const w = window as unknown as {
|
export const w = window as unknown as {
|
||||||
basepath: string;
|
basepath: string;
|
||||||
|
|
@ -46,6 +46,10 @@ export const initEditor = async (p: PG, site_id: string) => {
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!jscript.pending) {
|
||||||
|
jscript.init(p.render);
|
||||||
|
}
|
||||||
|
|
||||||
if (!p.item) return;
|
if (!p.item) return;
|
||||||
|
|
||||||
p.item.active = localStorage.getItem("prasi-item-active-id") || "";
|
p.item.active = localStorage.getItem("prasi-item-active-id") || "";
|
||||||
|
|
@ -147,10 +151,6 @@ export const initEditor = async (p: PG, site_id: string) => {
|
||||||
|
|
||||||
p.status = "ready";
|
p.status = "ready";
|
||||||
p.render();
|
p.render();
|
||||||
|
|
||||||
if (!jscript.build) {
|
|
||||||
jscript.init();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const execSiteJS = (p: PG) => {
|
export const execSiteJS = (p: PG) => {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { mobileCSS } from "../elements/e-page";
|
||||||
import { editorStyle } from "../elements/style";
|
import { editorStyle } from "../elements/style";
|
||||||
import { EditorGlobal } from "../logic/global";
|
import { EditorGlobal } from "../logic/global";
|
||||||
import { Toolbar } from "./toolbar/Toolbar";
|
import { Toolbar } from "./toolbar/Toolbar";
|
||||||
|
import { EdScriptInit } from "../../ed/panel/script/monaco/init";
|
||||||
|
|
||||||
const ETree = lazy(async () => ({
|
const ETree = lazy(async () => ({
|
||||||
default: (await import("./tree/tree")).ETree,
|
default: (await import("./tree/tree")).ETree,
|
||||||
|
|
@ -61,6 +62,7 @@ export const EMainEditor = () => {
|
||||||
</div>
|
</div>
|
||||||
{p.status === "ready" && (
|
{p.status === "ready" && (
|
||||||
<Suspense fallback={<Loading note={`toolbar`} />}>
|
<Suspense fallback={<Loading note={`toolbar`} />}>
|
||||||
|
<EdScriptInit />
|
||||||
{p.manager.site && <SiteManager />}
|
{p.manager.site && <SiteManager />}
|
||||||
{p.manager.page && <PageManager />}
|
{p.manager.page && <PageManager />}
|
||||||
{p.manager.comp && <CompManager />}
|
{p.manager.comp && <CompManager />}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,12 @@ import type {
|
||||||
} from "@monaco-editor/react";
|
} from "@monaco-editor/react";
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { useGlobal, useLocal } from "web-utils";
|
import { useGlobal, useLocal } from "web-utils";
|
||||||
|
import { FBuild } from "../../../../../utils/script/jscript";
|
||||||
import { EditorGlobal } from "../../../logic/global";
|
import { EditorGlobal } from "../../../logic/global";
|
||||||
import { jsMount } from "./mount";
|
import { jsMount } from "./mount";
|
||||||
import { monacoTypings } from "./typings";
|
import { monacoTypings } from "./typings";
|
||||||
export type MonacoEditor = Parameters<OnMount>[0];
|
export type MonacoEditor = Parameters<OnMount>[0];
|
||||||
|
|
||||||
export type FBuild = (
|
|
||||||
entryFileName: string,
|
|
||||||
src: string,
|
|
||||||
files?: Record<string, string>
|
|
||||||
) => Promise<string>;
|
|
||||||
|
|
||||||
export const customMonacoState: Record<string, any> = {};
|
export const customMonacoState: Record<string, any> = {};
|
||||||
|
|
||||||
export const ScriptMonacoCustom: FC<{
|
export const ScriptMonacoCustom: FC<{
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,19 @@ import strDelta from "textdiff-create";
|
||||||
import { useGlobal, useLocal } from "web-utils";
|
import { useGlobal, useLocal } from "web-utils";
|
||||||
import * as Y from "yjs";
|
import * as Y from "yjs";
|
||||||
import { TypedMap } from "yjs-types";
|
import { TypedMap } from "yjs-types";
|
||||||
|
import { FBuild } from "../../../../../utils/script/jscript";
|
||||||
import { FMCompDef, FNAdv } from "../../../../../utils/types/meta-fn";
|
import { FMCompDef, FNAdv } from "../../../../../utils/types/meta-fn";
|
||||||
|
import { Button } from "../../../../../utils/ui/form/Button";
|
||||||
import { Loading } from "../../../../../utils/ui/loading";
|
import { Loading } from "../../../../../utils/ui/loading";
|
||||||
|
import { Popover } from "../../../../../utils/ui/popover";
|
||||||
import { EditorGlobal } from "../../../logic/global";
|
import { EditorGlobal } from "../../../logic/global";
|
||||||
import { mergeScopeUpwards } from "../../../logic/tree-scope";
|
import { mergeScopeUpwards } from "../../../logic/tree-scope";
|
||||||
import { newMap } from "../../../tools/yjs-tools";
|
import { newMap } from "../../../tools/yjs-tools";
|
||||||
|
import { MonacoElHistory } from "./monaco-el-history";
|
||||||
|
import { MonacoElSnippet } from "./monaco-el-snippet";
|
||||||
import { jsMount } from "./mount";
|
import { jsMount } from "./mount";
|
||||||
import { MonacoScopeBar } from "./scope-bar";
|
import { MonacoScopeBar } from "./scope-bar";
|
||||||
import { monacoTypings } from "./typings";
|
import { monacoTypings } from "./typings";
|
||||||
import { MonacoElSnippet } from "./monaco-el-snippet";
|
|
||||||
import { Button } from "../../../../../utils/ui/form/Button";
|
|
||||||
import { Popover } from "../../../../../utils/ui/popover";
|
|
||||||
import { MonacoElHistory } from "./monaco-el-history";
|
|
||||||
|
|
||||||
export type MonacoEditor = Parameters<OnMount>[0];
|
export type MonacoEditor = Parameters<OnMount>[0];
|
||||||
export const DefaultScript = {
|
export const DefaultScript = {
|
||||||
|
|
@ -42,13 +43,6 @@ const w = window as unknown as {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FBuild = (
|
|
||||||
entryFileName: string,
|
|
||||||
src: string,
|
|
||||||
files?: Record<string, string>,
|
|
||||||
verbose?: boolean
|
|
||||||
) => Promise<string>;
|
|
||||||
|
|
||||||
const monacoViewState = {} as Record<string, any>;
|
const monacoViewState = {} as Record<string, any>;
|
||||||
|
|
||||||
export const ScriptMonacoElement: FC<{
|
export const ScriptMonacoElement: FC<{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { Loading } from "../../../../utils/ui/loading";
|
||||||
import { EditorGlobal } from "../../logic/global";
|
import { EditorGlobal } from "../../logic/global";
|
||||||
import { ScriptMonacoCustom } from "./monaco/monaco-custom";
|
import { ScriptMonacoCustom } from "./monaco/monaco-custom";
|
||||||
import { MonacoEditor } from "./monaco/typings";
|
import { MonacoEditor } from "./monaco/typings";
|
||||||
import { jscript } from "./script-element";
|
import { jscript } from "../../../../utils/script/jscript";
|
||||||
|
|
||||||
export const EScriptCustom: FC<{
|
export const EScriptCustom: FC<{
|
||||||
monaco_id: string;
|
monaco_id: string;
|
||||||
|
|
@ -28,16 +28,8 @@ export const EScriptCustom: FC<{
|
||||||
}) => {
|
}) => {
|
||||||
const p = useGlobal(EditorGlobal);
|
const p = useGlobal(EditorGlobal);
|
||||||
|
|
||||||
if (!jscript.editor) {
|
if (!jscript.editor && jscript.pending) {
|
||||||
Promise.all([
|
jscript.pending.then(() => p.render());
|
||||||
import("@monaco-editor/react").then((e) => {
|
|
||||||
jscript.editor = e.Editor;
|
|
||||||
e.loader.config({ paths: { vs: "/min/vs" } });
|
|
||||||
}),
|
|
||||||
jscript.init(),
|
|
||||||
]).then(() => {
|
|
||||||
p.render();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,18 @@
|
||||||
import type { Editor as MonacoEditor } from "@monaco-editor/react";
|
|
||||||
import type { BuildOptions } from "esbuild-wasm";
|
|
||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { useGlobal } from "web-utils";
|
import { useGlobal } from "web-utils";
|
||||||
import * as Y from "yjs";
|
import * as Y from "yjs";
|
||||||
|
import { jscript } from "../../../../utils/script/jscript";
|
||||||
import { Loading } from "../../../../utils/ui/loading";
|
import { Loading } from "../../../../utils/ui/loading";
|
||||||
import { Modal } from "../../../../utils/ui/modal";
|
import { Modal } from "../../../../utils/ui/modal";
|
||||||
import { EditorGlobal } from "../../logic/global";
|
import { EditorGlobal } from "../../logic/global";
|
||||||
import { rebuildTree } from "../../logic/tree-logic";
|
import { rebuildTree } from "../../logic/tree-logic";
|
||||||
import { initJS } from "./monaco/init";
|
import { DefaultScript, ScriptMonacoElement } from "./monaco/monaco-el";
|
||||||
import { DefaultScript, FBuild, ScriptMonacoElement } from "./monaco/monaco-el";
|
|
||||||
|
|
||||||
export const jscript = {
|
|
||||||
editor: null as typeof MonacoEditor | null,
|
|
||||||
build: null as null | FBuild,
|
|
||||||
_init: false as false | Promise<void>,
|
|
||||||
ready: false,
|
|
||||||
_editor: false,
|
|
||||||
async init(render: () => void) {
|
|
||||||
if (this._init) await this._init;
|
|
||||||
if (!this._init) {
|
|
||||||
this._init = new Promise<void>(async (resolve) => {
|
|
||||||
const { sendIPC } = await import("./esbuild/ipc");
|
|
||||||
await initJS();
|
|
||||||
|
|
||||||
if (!this._editor) {
|
|
||||||
this._editor = true;
|
|
||||||
const e = await import("@monaco-editor/react");
|
|
||||||
jscript.editor = e.Editor;
|
|
||||||
e.loader.config({ paths: { vs: "/min/vs" } });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.build = async (entry, src, files, verbose?: boolean) => {
|
|
||||||
const options: BuildOptions = {
|
|
||||||
entryPoints: [entry],
|
|
||||||
jsx: "transform",
|
|
||||||
bundle: true,
|
|
||||||
format: "cjs",
|
|
||||||
minify: true,
|
|
||||||
};
|
|
||||||
const res = await sendIPC({
|
|
||||||
command_: "build",
|
|
||||||
input_: { ...files, [entry]: src },
|
|
||||||
options_: options,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (verbose && res.stderr_) {
|
|
||||||
console.log(res.stderr_);
|
|
||||||
}
|
|
||||||
if (res.outputFiles_) return res.outputFiles_[0].text;
|
|
||||||
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.build("el.tsx", `return ""`);
|
|
||||||
render();
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const EScriptElement: FC<{}> = ({}) => {
|
export const EScriptElement: FC<{}> = ({}) => {
|
||||||
const p = useGlobal(EditorGlobal, "EDITOR");
|
const p = useGlobal(EditorGlobal, "EDITOR");
|
||||||
|
|
||||||
if (!jscript.editor) {
|
if (!jscript.editor && jscript.pending) {
|
||||||
jscript.init(p.render);
|
jscript.pending.then(() => p.render());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.script.active) {
|
if (!p.script.active) {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ import { editComp, loadComponent } from "../../../logic/comp";
|
||||||
import { EditorGlobal, PG } from "../../../logic/global";
|
import { EditorGlobal, PG } from "../../../logic/global";
|
||||||
import { rebuildTree } from "../../../logic/tree-logic";
|
import { rebuildTree } from "../../../logic/tree-logic";
|
||||||
import { newMap } from "../../../tools/yjs-tools";
|
import { newMap } from "../../../tools/yjs-tools";
|
||||||
import { jscript } from "../../script/script-element";
|
|
||||||
import { CPJsx } from "./CPJsx";
|
import { CPJsx } from "./CPJsx";
|
||||||
import { CPOption } from "./CPOption";
|
import { CPOption } from "./CPOption";
|
||||||
import { CPText } from "./CPText";
|
import { CPText } from "./CPText";
|
||||||
import { mergeScopeUpwards } from "../../../logic/tree-scope";
|
import { mergeScopeUpwards } from "../../../logic/tree-scope";
|
||||||
import { treePropEval } from "../../../logic/tree-prop";
|
import { treePropEval } from "../../../logic/tree-prop";
|
||||||
|
import { jscript } from "../../../../../utils/script/jscript";
|
||||||
|
|
||||||
export const CPInstance: FC<{ mitem: MItem }> = ({ mitem }) => {
|
export const CPInstance: FC<{ mitem: MItem }> = ({ mitem }) => {
|
||||||
const p = useGlobal(EditorGlobal, "EDITOR");
|
const p = useGlobal(EditorGlobal, "EDITOR");
|
||||||
|
|
@ -65,10 +65,7 @@ export const CPInstance: FC<{ mitem: MItem }> = ({ mitem }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!jscript.build) {
|
if (!jscript.build) {
|
||||||
jscript.init().then(() => {
|
jscript.init(p.render);
|
||||||
local.status = "ready";
|
|
||||||
local.render();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
local.status = "ready";
|
local.status = "ready";
|
||||||
local.render();
|
local.render();
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ import { EditorGlobal, NodeMeta } from "../../../logic/global";
|
||||||
import { fillID } from "../../../tools/fill-id";
|
import { fillID } from "../../../tools/fill-id";
|
||||||
import { flatTree } from "../../../tools/flat-tree";
|
import { flatTree } from "../../../tools/flat-tree";
|
||||||
import { newMap } from "../../../tools/yjs-tools";
|
import { newMap } from "../../../tools/yjs-tools";
|
||||||
import { jscript } from "../../script/script-element";
|
|
||||||
import { detachComp } from "./action/detach";
|
import { detachComp } from "./action/detach";
|
||||||
import { rebuildTree } from "../../../logic/tree-logic";
|
import { rebuildTree } from "../../../logic/tree-logic";
|
||||||
|
import { jscript } from "../../../../../utils/script/jscript";
|
||||||
|
|
||||||
export const ETreeRightClick: FC<{
|
export const ETreeRightClick: FC<{
|
||||||
node: NodeModel<NodeMeta>;
|
node: NodeModel<NodeMeta>;
|
||||||
|
|
@ -304,7 +304,7 @@ export const ETreeRightClick: FC<{
|
||||||
label="Detach"
|
label="Detach"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (!jscript.build) {
|
if (!jscript.build) {
|
||||||
await jscript.init();
|
await jscript.init(p.render);
|
||||||
}
|
}
|
||||||
if (jscript.build && p.treeMeta[item.id]) {
|
if (jscript.build && p.treeMeta[item.id]) {
|
||||||
detachComp(
|
detachComp(
|
||||||
|
|
@ -344,7 +344,7 @@ export const ETreeRightClick: FC<{
|
||||||
comp_id: rootComp ? rootComp.id : undefined,
|
comp_id: rootComp ? rootComp.id : undefined,
|
||||||
group_id,
|
group_id,
|
||||||
})
|
})
|
||||||
.then(async (e) => {
|
.then(async (e: any) => {
|
||||||
if (e) {
|
if (e) {
|
||||||
await loadComponent(p, e.id);
|
await loadComponent(p, e.id);
|
||||||
delete p.compLoading[item.id];
|
delete p.compLoading[item.id];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
import type { Editor as MonacoEditor } from "@monaco-editor/react";
|
||||||
|
import type { BuildOptions } from "esbuild-wasm";
|
||||||
|
import type Prettier from "prettier/standalone";
|
||||||
|
import type estree from "prettier/plugins/estree";
|
||||||
|
import type ts from "prettier/plugins/typescript";
|
||||||
|
export type FBuild = (
|
||||||
|
entryFileName: string,
|
||||||
|
src: string,
|
||||||
|
files?: Record<string, string>,
|
||||||
|
verbose?: boolean
|
||||||
|
) => Promise<string>;
|
||||||
|
|
||||||
|
export const initJS = async () => {
|
||||||
|
const { tryToSetCurrentVersion } = await import("./esbuild/versions");
|
||||||
|
await tryToSetCurrentVersion("latest");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const jscript = {
|
||||||
|
editor: null as typeof MonacoEditor | null,
|
||||||
|
build: null as null | FBuild,
|
||||||
|
pending: null as null | Promise<void>,
|
||||||
|
events: {
|
||||||
|
editorLoaded: () => {},
|
||||||
|
esbuildLoaded: () => {},
|
||||||
|
prettierLoaded: () => {},
|
||||||
|
pendingDone: () => {},
|
||||||
|
},
|
||||||
|
prettier: {
|
||||||
|
standalone: null as null | typeof Prettier,
|
||||||
|
estree: null as null | typeof estree,
|
||||||
|
ts: null as null | typeof ts,
|
||||||
|
},
|
||||||
|
async init(render: () => void) {
|
||||||
|
if (this.pending) {
|
||||||
|
await this.pending;
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
if (!this.pending) {
|
||||||
|
this.pending = new Promise<void>(async (resolve) => {
|
||||||
|
this.events.pendingDone = resolve;
|
||||||
|
|
||||||
|
const { sendIPC } = await import("./esbuild/ipc");
|
||||||
|
await initJS();
|
||||||
|
this.events.esbuildLoaded();
|
||||||
|
|
||||||
|
this.prettier.standalone = (
|
||||||
|
await import("prettier/standalone")
|
||||||
|
).default;
|
||||||
|
this.prettier.estree = await import("prettier/plugins/estree");
|
||||||
|
this.prettier.ts = await import("prettier/plugins/typescript");
|
||||||
|
this.events.prettierLoaded();
|
||||||
|
|
||||||
|
const e = await import("@monaco-editor/react");
|
||||||
|
jscript.editor = e.Editor;
|
||||||
|
e.loader.config({ paths: { vs: "/min/vs" } });
|
||||||
|
this.events.editorLoaded();
|
||||||
|
|
||||||
|
this.build = async (entry, src, files, verbose?: boolean) => {
|
||||||
|
const options: BuildOptions = {
|
||||||
|
entryPoints: [entry],
|
||||||
|
jsx: "transform",
|
||||||
|
bundle: true,
|
||||||
|
format: "cjs",
|
||||||
|
minify: true,
|
||||||
|
};
|
||||||
|
const res = await sendIPC({
|
||||||
|
command_: "build",
|
||||||
|
input_: { ...files, [entry]: src },
|
||||||
|
options_: options,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (verbose && res.stderr_) {
|
||||||
|
console.log(res.stderr_);
|
||||||
|
}
|
||||||
|
if (res.outputFiles_) return res.outputFiles_[0].text;
|
||||||
|
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.build("el.tsx", `return ""`);
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
import type { OnMount } from "@monaco-editor/react";
|
||||||
|
import trim from "lodash.trim";
|
||||||
|
import {
|
||||||
|
MonacoJsxSyntaxHighlight,
|
||||||
|
getWorker,
|
||||||
|
} from "monaco-jsx-syntax-highlight-v2";
|
||||||
|
import { jscript } from "./jscript";
|
||||||
|
|
||||||
|
export type MonacoEditor = Parameters<OnMount>[0];
|
||||||
|
type Monaco = Parameters<OnMount>[1];
|
||||||
|
type CompilerOptions = Parameters<
|
||||||
|
Parameters<OnMount>[1]["languages"]["typescript"]["typescriptDefaults"]["setCompilerOptions"]
|
||||||
|
>[0];
|
||||||
|
|
||||||
|
export const jsMount = async (editor: MonacoEditor, monaco: Monaco) => {
|
||||||
|
const m = monaco as any;
|
||||||
|
if (!m.customJSMounted) {
|
||||||
|
m.customJSMounted = true;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const compilerOptions: CompilerOptions = {
|
||||||
|
jsx: monaco.languages.typescript.JsxEmit.React,
|
||||||
|
jsxFactory: "React.createElement",
|
||||||
|
jsxFragmentFactory: "React.Fragment",
|
||||||
|
target: monaco.languages.typescript.ScriptTarget.ES2015,
|
||||||
|
allowNonTsExtensions: true,
|
||||||
|
lib: ["esnext", "dom"],
|
||||||
|
module: monaco.languages.typescript.ModuleKind.ESNext,
|
||||||
|
esModuleInterop: true,
|
||||||
|
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
|
||||||
|
};
|
||||||
|
|
||||||
|
const jsxHgController = new MonacoJsxSyntaxHighlight(getWorker(), monaco);
|
||||||
|
const { highlighter } = jsxHgController.highlighterBuilder({
|
||||||
|
editor: editor,
|
||||||
|
});
|
||||||
|
highlighter();
|
||||||
|
editor.onDidChangeModelContent(() => {
|
||||||
|
highlighter();
|
||||||
|
});
|
||||||
|
|
||||||
|
monaco.languages.registerDocumentFormattingEditProvider("typescript", {
|
||||||
|
async provideDocumentFormattingEdits(model, options, token) {
|
||||||
|
const prettier = jscript.prettier.standalone;
|
||||||
|
const prettier_ts = jscript.prettier.ts;
|
||||||
|
const prettier_estree = jscript.prettier.estree;
|
||||||
|
|
||||||
|
if (prettier && prettier_estree && prettier_ts) {
|
||||||
|
const text = trim(
|
||||||
|
await prettier.format(model.getValue(), {
|
||||||
|
parser: "typescript",
|
||||||
|
plugins: [prettier_ts, prettier_estree],
|
||||||
|
}),
|
||||||
|
"; \n"
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
range: model.getFullModelRange(),
|
||||||
|
text,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
monaco.languages.registerCompletionItemProvider("typescript", {
|
||||||
|
provideCompletionItems: (model, position) => {
|
||||||
|
const word = model.getWordUntilPosition(position);
|
||||||
|
return {
|
||||||
|
suggestions: [
|
||||||
|
{
|
||||||
|
label: "log",
|
||||||
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||||
|
documentation: "Add Console.log",
|
||||||
|
insertText: `console.log($1)`,
|
||||||
|
insertTextRules:
|
||||||
|
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
range: {
|
||||||
|
startLineNumber: position.lineNumber,
|
||||||
|
endLineNumber: position.lineNumber,
|
||||||
|
startColumn: word.startColumn,
|
||||||
|
endColumn: word.endColumn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "sfy",
|
||||||
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||||
|
documentation: "Add JSON.stringify",
|
||||||
|
insertText: `JSON.stringify($1)`,
|
||||||
|
insertTextRules:
|
||||||
|
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
range: {
|
||||||
|
startLineNumber: position.lineNumber,
|
||||||
|
endLineNumber: position.lineNumber,
|
||||||
|
startColumn: word.startColumn,
|
||||||
|
endColumn: word.endColumn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
monaco.languages.registerCompletionItemProvider("typescript", {
|
||||||
|
triggerCharacters: [">"],
|
||||||
|
provideCompletionItems: (model, position) => {
|
||||||
|
const codePre: string = model.getValueInRange({
|
||||||
|
startLineNumber: position.lineNumber,
|
||||||
|
startColumn: 1,
|
||||||
|
endLineNumber: position.lineNumber,
|
||||||
|
endColumn: position.column,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tag = codePre.match(/.*<(\w+)>$/)?.[1];
|
||||||
|
|
||||||
|
if (!tag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const word = model.getWordUntilPosition(position);
|
||||||
|
|
||||||
|
return {
|
||||||
|
suggestions: [
|
||||||
|
{
|
||||||
|
label: `</${tag}>`,
|
||||||
|
kind: monaco.languages.CompletionItemKind.EnumMember,
|
||||||
|
insertText: `$1</${tag}>`,
|
||||||
|
insertTextRules:
|
||||||
|
monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
||||||
|
range: {
|
||||||
|
startLineNumber: position.lineNumber,
|
||||||
|
endLineNumber: position.lineNumber,
|
||||||
|
startColumn: word.startColumn,
|
||||||
|
endColumn: word.endColumn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
|
||||||
|
compilerOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
editor.getAction("editor.action.formatDocument")?.run();
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
export const baseTypings = `
|
||||||
|
type FC<T> = React.FC<T>;
|
||||||
|
const Fragment = React.Fragment;
|
||||||
|
const ReactNode = React.ReactNode;
|
||||||
|
const useCallback = React.useCallback;
|
||||||
|
const useMemo = React.useMemo;
|
||||||
|
const ReactElement = React.ReactElement;
|
||||||
|
const isValidElement = React.isValidElement;
|
||||||
|
const useEffect = React.useEffect;
|
||||||
|
const useState = React.useState;
|
||||||
|
|
||||||
|
const pathname: string;
|
||||||
|
const isEditor: boolean;
|
||||||
|
const isLayout: boolean;
|
||||||
|
const isMobile: boolean;
|
||||||
|
const isDesktop: boolean;
|
||||||
|
const preload: (pathname: string) => void;
|
||||||
|
const apiHeaders: Record<string, any>;
|
||||||
|
const navigate: (url:string) => void;
|
||||||
|
const params: any;
|
||||||
|
const cx = (...classNames: any[]) => string;
|
||||||
|
const css = (
|
||||||
|
tag: CSSAttribute | TemplateStringsArray | string,
|
||||||
|
...props: Array<string | number | boolean | undefined | null>
|
||||||
|
) => string;
|
||||||
|
|
||||||
|
const props: {
|
||||||
|
className: string;
|
||||||
|
onPointerDown?: () => void;
|
||||||
|
onPointerMove?: () => void;
|
||||||
|
onPointerLeave?: () => void;
|
||||||
|
};
|
||||||
|
const children: ReactNode;
|
||||||
|
|
||||||
|
const PassProp: FC<Record<string,any> & {children: React.ReactNode; }>;
|
||||||
|
const PassChild: FC<{name: string}>;
|
||||||
|
const Preload: FC<{url: string[]}>;
|
||||||
|
const apiurl: string;
|
||||||
|
const pageid: string;
|
||||||
|
type ITEM = {
|
||||||
|
id: string
|
||||||
|
name: string;
|
||||||
|
type: 'item' | 'text';
|
||||||
|
adv?: {
|
||||||
|
js?: string;
|
||||||
|
jsBuilt?: string;
|
||||||
|
css?: string;
|
||||||
|
html?: string;
|
||||||
|
},
|
||||||
|
text: string,
|
||||||
|
html: string,
|
||||||
|
component?: { id:string, props: Record<string, {
|
||||||
|
value: string,
|
||||||
|
valueBuilt: string,
|
||||||
|
meta: { type: string }
|
||||||
|
}>},
|
||||||
|
childs: ITEM[]
|
||||||
|
}
|
||||||
|
const newElement: (gen?: (item: ITEM) => ITEM | ITEM[]) => React.ReactNode;
|
||||||
|
const Local: <T extends Record<string, any>>(arg: {
|
||||||
|
name: string;
|
||||||
|
value: T;
|
||||||
|
children: ((local: T & { render: () => void }) => any);
|
||||||
|
deps?: any[];
|
||||||
|
effect?: (
|
||||||
|
local: T & { render: () => void }
|
||||||
|
) => void | (() => void) | Promise<void | (() => void)>;
|
||||||
|
hook?: (
|
||||||
|
local: T & { render: () => void }
|
||||||
|
) => void | (() => void) | Promise<void | (() => void)>;
|
||||||
|
cache?: boolean;
|
||||||
|
}) => ReactNode;
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
import trim from "lodash.trim";
|
||||||
|
import { isValidElement } from "react";
|
||||||
|
|
||||||
|
export const extractProp = (prop: {
|
||||||
|
values: Record<string, any>;
|
||||||
|
types: Record<string, string>;
|
||||||
|
}) => {
|
||||||
|
const propTypes: string[] = [];
|
||||||
|
const props: Record<string, { val?: any; type?: string }> = {};
|
||||||
|
|
||||||
|
if (prop) {
|
||||||
|
if (prop.values) {
|
||||||
|
for (const [k, v] of Object.entries(prop.values)) {
|
||||||
|
if (!props[k]) {
|
||||||
|
props[k] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof v === "function") {
|
||||||
|
if (isFunctionalComponent(v)) {
|
||||||
|
props[k].type = "React.FC";
|
||||||
|
} else if (isClassComponent(v)) {
|
||||||
|
props[k].type = "React.Component";
|
||||||
|
} else {
|
||||||
|
props[k].type = "any";
|
||||||
|
}
|
||||||
|
} else if (v) {
|
||||||
|
if (typeof v === "object" && v._jsx) {
|
||||||
|
props[k].type = "React.ReactElement;";
|
||||||
|
} else if (!!v.render && typeof v.$$typeof === "symbol") {
|
||||||
|
props[k].type = "React.FC<Record<string,any> & {ref?:any}>";
|
||||||
|
} else {
|
||||||
|
props[k].val = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop.types) {
|
||||||
|
for (const [k, v] of Object.entries(prop.types)) {
|
||||||
|
if (!props[k]) {
|
||||||
|
props[k] = {};
|
||||||
|
}
|
||||||
|
props[k].type = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(props)) {
|
||||||
|
if (v.type) {
|
||||||
|
propTypes.push(`const ${k}: ${trim(v.type, "; \n")};`);
|
||||||
|
} else if (v.val) {
|
||||||
|
if (typeof v.val === "object" && isValidElement(v.val)) {
|
||||||
|
propTypes.push(`const ${k}: ReactElement;`);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
let val = v.val;
|
||||||
|
|
||||||
|
if (typeof val === "object") {
|
||||||
|
if (typeof val.render === "function") {
|
||||||
|
val = { ...val, render: () => {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
propTypes.push(`const ${k}: ${recurseTypes(val)};`);
|
||||||
|
} else {
|
||||||
|
propTypes.push(`const ${k}: string;`);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return propTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
function recurseTypes(object: any) {
|
||||||
|
const result: string[] = [];
|
||||||
|
if (typeof object === "object") {
|
||||||
|
if (object === null) return "null";
|
||||||
|
if (Array.isArray(object)) {
|
||||||
|
return `any[]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(object)) {
|
||||||
|
result.push(
|
||||||
|
`${k}: ${typeof v === "object" && v ? recurseTypes(v) : typeof v}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return `{
|
||||||
|
${result.join(";\n ")}
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
return typeof object;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFunctionalComponent(Component: any) {
|
||||||
|
return (
|
||||||
|
typeof Component === "function" && // can be various things
|
||||||
|
!(
|
||||||
|
(
|
||||||
|
Component.prototype && // native arrows don't have prototypes
|
||||||
|
Component.prototype.isReactComponent
|
||||||
|
) // special property
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isClassComponent(Component: any) {
|
||||||
|
return !!(
|
||||||
|
typeof Component === "function" &&
|
||||||
|
Component.prototype &&
|
||||||
|
Component.prototype.isReactComponent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
export const typeStringify = function (this: any, key: string, value: any) {
|
||||||
|
if (typeof value === "function") {
|
||||||
|
return `___FFF||any||FFF___`;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const typeReviver = (key: any, value: any) => {
|
||||||
|
if (typeof key === "string" && key.indexOf("function ") === 0) {
|
||||||
|
let functionTemplate = `(${value})`;
|
||||||
|
return eval(functionTemplate);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
import type { OnMount } from "@monaco-editor/react";
|
||||||
|
import { w } from "../types/general";
|
||||||
|
import { baseTypings } from "./types/base";
|
||||||
|
import { extractProp } from "./types/prop";
|
||||||
|
export type MonacoEditor = Parameters<OnMount>[0];
|
||||||
|
type Monaco = Parameters<OnMount>[1];
|
||||||
|
|
||||||
|
const map = new WeakMap<any>();
|
||||||
|
|
||||||
|
export const monacoTypings = async (
|
||||||
|
p: {
|
||||||
|
site_dts: string;
|
||||||
|
site: { api_url: string };
|
||||||
|
script: { siteTypes: Record<string, string> };
|
||||||
|
},
|
||||||
|
monaco: Monaco,
|
||||||
|
prop: { values: Record<string, any>; types: Record<string, string> }
|
||||||
|
) => {
|
||||||
|
if (!map.has(prop.values)) {
|
||||||
|
map.set(prop.values, true);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w.prasiApi[p.site.api_url] && w.prasiApi[p.site.api_url].prismaTypes) {
|
||||||
|
const prisma = w.prasiApi[p.site.api_url].prismaTypes;
|
||||||
|
|
||||||
|
register(
|
||||||
|
monaco,
|
||||||
|
`\
|
||||||
|
declare module "ts:runtime/index" {
|
||||||
|
${prisma["runtime/index.d.ts"]}
|
||||||
|
}`,
|
||||||
|
`ts:runtime/index.d.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
register(
|
||||||
|
monaco,
|
||||||
|
`\
|
||||||
|
declare module "ts:runtime/library" {
|
||||||
|
${prisma["runtime/library.d.ts"]}
|
||||||
|
}`,
|
||||||
|
`ts:runtime/library.d.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
register(
|
||||||
|
monaco,
|
||||||
|
`\
|
||||||
|
declare module "ts:prisma" {
|
||||||
|
${prisma["prisma.d.ts"].replace(
|
||||||
|
`import * as runtime from './runtime/library';`,
|
||||||
|
`import * as runtime from 'ts:runtime/library';`
|
||||||
|
)}
|
||||||
|
}`,
|
||||||
|
`ts:prisma.d.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
register(monaco, w.prasiApi[p.site.api_url].apiTypes, "ts:api.d.ts");
|
||||||
|
}
|
||||||
|
|
||||||
|
monaco.languages.typescript.typescriptDefaults.setExtraLibs([
|
||||||
|
{
|
||||||
|
filePath: "react.d.ts",
|
||||||
|
content: await loadText(
|
||||||
|
"https://cdn.jsdelivr.net/npm/@types/react@18.2.0/index.d.ts"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filePath: "jsx-runtime.d.ts",
|
||||||
|
content: await loadText(
|
||||||
|
"https://cdn.jsdelivr.net/npm/@types/react@18.2.0/jsx-runtime.d.ts"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filePath: "site.d.ts",
|
||||||
|
content: p.site_dts.replaceAll("export declare const", "declare const"),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const propText = extractProp({
|
||||||
|
values: prop.values,
|
||||||
|
types: { ...prop.types, ...p.script.siteTypes },
|
||||||
|
});
|
||||||
|
|
||||||
|
const apiTypes = w.prasiApi[p.site.api_url]
|
||||||
|
? w.prasiApi[p.site.api_url].apiTypes
|
||||||
|
: "";
|
||||||
|
|
||||||
|
let apiPath = "app/gen/srv/api/srv";
|
||||||
|
if (apiTypes && apiTypes.includes(`export * as srv from "gen/srv/api/srv"`)) {
|
||||||
|
apiPath = "gen/srv/api/srv";
|
||||||
|
}
|
||||||
|
|
||||||
|
register(
|
||||||
|
monaco,
|
||||||
|
`\
|
||||||
|
import React from 'react';
|
||||||
|
import prisma from 'ts:prisma';
|
||||||
|
|
||||||
|
${iftext(
|
||||||
|
apiTypes,
|
||||||
|
`\
|
||||||
|
import "./api"
|
||||||
|
import type * as SRVAPI from "${apiPath}";`
|
||||||
|
)}
|
||||||
|
|
||||||
|
declare global {;
|
||||||
|
const db: prisma.PrismaClient;
|
||||||
|
|
||||||
|
${baseTypings}
|
||||||
|
|
||||||
|
const moko: {nama: string};
|
||||||
|
${propText.join("\n")}
|
||||||
|
|
||||||
|
${iftext(
|
||||||
|
apiTypes,
|
||||||
|
`
|
||||||
|
type Api = typeof SRVAPI;
|
||||||
|
type ApiName = keyof Api;
|
||||||
|
const api: { [k in ApiName]: Awaited<Api[k]["handler"]>["_"]["api"] };
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
}
|
||||||
|
|
||||||
|
`,
|
||||||
|
"ts:global.d.ts"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadText = async (url: string) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
return await res.text();
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const iftext = (condition: any, text: string) => {
|
||||||
|
if (condition) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const register = (monaco: Monaco, source: string, uri: string) => {
|
||||||
|
const model = monaco.editor.getModels().find((e) => {
|
||||||
|
return e.uri.toString() === uri;
|
||||||
|
});
|
||||||
|
if (model) {
|
||||||
|
model.setValue(source);
|
||||||
|
} else {
|
||||||
|
monaco.editor.createModel(source, "typescript", monaco.Uri.parse(uri));
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue