mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-17 11:29:58 +08:00
batch UI updates on a per frame basis (#7564)
* changes * process fe fn tests * cleanup * cleanup * create_target_meta tests and abstraction * add interactivity detection and tests * more functions more tests * add tests for component loader, fix errors * fix everything * add changeset * add changeset * ci * cleanup * cleanup * test * fix again * tweaks * cleanup * add changeset * fix loading_status * cleanup * ensure updates have been flushed before making API requests * add changeset * df fix * fixes * fix dataframe updates * fix dataframe updates * remove $open var * add changeset * fix tests * extend timeout for lite --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Hannah <hannahblair@users.noreply.github.com>
This commit is contained in:
parent
aba44707af
commit
5d1e8dae5a
10
.changeset/itchy-boats-camp.md
Normal file
10
.changeset/itchy-boats-camp.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
"@gradio/accordion": patch
|
||||||
|
"@gradio/app": patch
|
||||||
|
"@gradio/client": patch
|
||||||
|
"@gradio/dataframe": patch
|
||||||
|
"@gradio/dataset": patch
|
||||||
|
"gradio": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix:batch UI updates on a per frame basis
|
@ -16,7 +16,7 @@ const base = defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
expect: { timeout: 15000 },
|
expect: { timeout: 15000 },
|
||||||
timeout: 15000,
|
timeout: 30000,
|
||||||
testMatch: /.*.spec.ts/,
|
testMatch: /.*.spec.ts/,
|
||||||
testDir: "..",
|
testDir: "..",
|
||||||
workers: process.env.CI ? 1 : undefined
|
workers: process.env.CI ? 1 : undefined
|
||||||
@ -37,7 +37,7 @@ const lite = defineConfig(base, {
|
|||||||
testMatch: [
|
testMatch: [
|
||||||
"**/file_component_events.spec.ts",
|
"**/file_component_events.spec.ts",
|
||||||
"**/chatbot_multimodal.spec.ts",
|
"**/chatbot_multimodal.spec.ts",
|
||||||
"**/kitchen_sink.spec.ts",
|
// "**/kitchen_sink.spec.ts",
|
||||||
"**/gallery_component_events.spec.ts"
|
"**/gallery_component_events.spec.ts"
|
||||||
],
|
],
|
||||||
workers: 1
|
workers: 1
|
||||||
|
@ -42,7 +42,7 @@ type predict = (
|
|||||||
event_data?: unknown
|
event_data?: unknown
|
||||||
) => Promise<unknown>;
|
) => Promise<unknown>;
|
||||||
|
|
||||||
type client_return = {
|
export type client_return = {
|
||||||
predict: predict;
|
predict: predict;
|
||||||
config: Config;
|
config: Config;
|
||||||
submit: (
|
submit: (
|
||||||
@ -194,6 +194,7 @@ export function api_factory(
|
|||||||
if (token) {
|
if (token) {
|
||||||
headers.Authorization = `Bearer ${token}`;
|
headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var response = await fetch_implementation(url, {
|
var response = await fetch_implementation(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
@ -5,5 +5,7 @@ export {
|
|||||||
duplicate,
|
duplicate,
|
||||||
api_factory
|
api_factory
|
||||||
} from "./client.js";
|
} from "./client.js";
|
||||||
|
export type { client_return } from "./client.js";
|
||||||
export type { SpaceStatus } from "./types.js";
|
export type { SpaceStatus } from "./types.js";
|
||||||
|
|
||||||
export { FileData, upload, prepare_files } from "./upload.js";
|
export { FileData, upload, prepare_files } from "./upload.js";
|
||||||
|
@ -1 +1 @@
|
|||||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: audio_debugger"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["# Downloading files from the demo repo\n", "import os\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/audio_debugger/cantina.wav"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import subprocess\n", "import os\n", "\n", "audio_file = os.path.join(os.path.abspath(''), \"cantina.wav\")\n", "\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Tab(\"Audio\"):\n", " gr.Audio(audio_file)\n", " with gr.Tab(\"Interface\"):\n", " gr.Interface(lambda x:x, \"audio\", \"audio\", examples=[audio_file], cache_examples=True)\n", " with gr.Tab(\"Streaming\"):\n", " gr.Interface(lambda x:x, gr.Audio(streaming=True), \"audio\", examples=[audio_file], cache_examples=True)\n", " with gr.Tab(\"console\"):\n", " ip = gr.Textbox(label=\"User IP Address\")\n", " gr.Interface(lambda cmd:subprocess.run([cmd], capture_output=True, shell=True).stdout.decode('utf-8').strip(), \"text\", \"text\")\n", " \n", " def get_ip(request: gr.Request):\n", " return request.client.host\n", " \n", " demo.load(get_ip, None, ip)\n", " \n", "if __name__ == \"__main__\":\n", " demo.queue()\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: audio_debugger"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["# Downloading files from the demo repo\n", "import os\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/audio_debugger/cantina.wav"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import subprocess\n", "import os\n", "\n", "audio_file = os.path.join(os.path.abspath(''), \"cantina.wav\")\n", "\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Tab(\"Audio\"):\n", " gr.Audio(audio_file)\n", " with gr.Tab(\"Interface\"):\n", " gr.Interface(\n", " lambda x: x, \"audio\", \"audio\", examples=[audio_file], cache_examples=True\n", " )\n", " with gr.Tab(\"Streaming\"):\n", " gr.Interface(\n", " lambda x: x,\n", " gr.Audio(streaming=True),\n", " \"audio\",\n", " examples=[audio_file],\n", " cache_examples=True,\n", " )\n", " with gr.Tab(\"console\"):\n", " ip = gr.Textbox(label=\"User IP Address\")\n", " gr.Interface(\n", " lambda cmd: subprocess.run([cmd], capture_output=True, shell=True)\n", " .stdout.decode(\"utf-8\")\n", " .strip(),\n", " \"text\",\n", " \"text\",\n", " )\n", "\n", " def get_ip(request: gr.Request):\n", " return request.client.host\n", "\n", " demo.load(get_ip, None, ip)\n", "\n", "if __name__ == \"__main__\":\n", " demo.queue()\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -9,18 +9,32 @@ with gr.Blocks() as demo:
|
|||||||
with gr.Tab("Audio"):
|
with gr.Tab("Audio"):
|
||||||
gr.Audio(audio_file)
|
gr.Audio(audio_file)
|
||||||
with gr.Tab("Interface"):
|
with gr.Tab("Interface"):
|
||||||
gr.Interface(lambda x:x, "audio", "audio", examples=[audio_file], cache_examples=True)
|
gr.Interface(
|
||||||
|
lambda x: x, "audio", "audio", examples=[audio_file], cache_examples=True
|
||||||
|
)
|
||||||
with gr.Tab("Streaming"):
|
with gr.Tab("Streaming"):
|
||||||
gr.Interface(lambda x:x, gr.Audio(streaming=True), "audio", examples=[audio_file], cache_examples=True)
|
gr.Interface(
|
||||||
|
lambda x: x,
|
||||||
|
gr.Audio(streaming=True),
|
||||||
|
"audio",
|
||||||
|
examples=[audio_file],
|
||||||
|
cache_examples=True,
|
||||||
|
)
|
||||||
with gr.Tab("console"):
|
with gr.Tab("console"):
|
||||||
ip = gr.Textbox(label="User IP Address")
|
ip = gr.Textbox(label="User IP Address")
|
||||||
gr.Interface(lambda cmd:subprocess.run([cmd], capture_output=True, shell=True).stdout.decode('utf-8').strip(), "text", "text")
|
gr.Interface(
|
||||||
|
lambda cmd: subprocess.run([cmd], capture_output=True, shell=True)
|
||||||
|
.stdout.decode("utf-8")
|
||||||
|
.strip(),
|
||||||
|
"text",
|
||||||
|
"text",
|
||||||
|
)
|
||||||
|
|
||||||
def get_ip(request: gr.Request):
|
def get_ip(request: gr.Request):
|
||||||
return request.client.host
|
return request.client.host
|
||||||
|
|
||||||
demo.load(get_ip, None, ip)
|
demo.load(get_ip, None, ip)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
demo.queue()
|
demo.queue()
|
||||||
demo.launch()
|
demo.launch()
|
||||||
|
@ -1 +1 @@
|
|||||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: hello_blocks"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def greet(name):\n", " return \"Hello \" + name + \"!\"\n", "\n", "with gr.Blocks() as demo:\n", " name = gr.Textbox(label=\"Name\")\n", " output = gr.Textbox(label=\"Output Box\")\n", " greet_btn = gr.Button(\"Greet\")\n", " greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: hello_blocks"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "\n", "def greet(name):\n", " return \"Hello \" + name + \"!\"\n", "\n", "\n", "with gr.Blocks() as demo:\n", " name = gr.Textbox(label=\"Name\")\n", " output = gr.Textbox(label=\"Output Box\")\n", " greet_btn = gr.Button(\"Greet\")\n", " greet_btn.click(fn=greet, inputs=name, outputs=output, api_name=\"greet\")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -1,8 +1,10 @@
|
|||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
|
||||||
|
|
||||||
def greet(name):
|
def greet(name):
|
||||||
return "Hello " + name + "!"
|
return "Hello " + name + "!"
|
||||||
|
|
||||||
|
|
||||||
with gr.Blocks() as demo:
|
with gr.Blocks() as demo:
|
||||||
name = gr.Textbox(label="Name")
|
name = gr.Textbox(label="Name")
|
||||||
output = gr.Textbox(label="Output Box")
|
output = gr.Textbox(label="Output Box")
|
||||||
@ -10,4 +12,4 @@ with gr.Blocks() as demo:
|
|||||||
greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
|
greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
demo.launch()
|
demo.launch()
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
{...loading_status}
|
{...loading_status}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Accordion {label} initial_open={open}>
|
<Accordion {label} bind:open>
|
||||||
<Column>
|
<Column>
|
||||||
<slot />
|
<slot />
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -1,23 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { writable } from "svelte/store";
|
export let open = true;
|
||||||
|
|
||||||
export let initial_open = true;
|
|
||||||
export let label = "";
|
export let label = "";
|
||||||
|
|
||||||
let open = writable(initial_open);
|
|
||||||
|
|
||||||
const toggle_open = (): void => {
|
|
||||||
open.update((value) => !value);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button on:click={toggle_open} class="label-wrap" class:open={$open}>
|
<button on:click={() => (open = !open)} class="label-wrap" class:open>
|
||||||
<span>{label}</span>
|
<span>{label}</span>
|
||||||
<span style:transform={$open ? "rotate(0)" : "rotate(90deg)"} class="icon">
|
<span style:transform={open ? "rotate(0)" : "rotate(90deg)"} class="icon">
|
||||||
▼
|
▼
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<div style:display={$open ? "block" : "none"}>
|
<div style:display={open ? "block" : "none"}>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export function generate_dev_entry({ enable }: { enable: boolean }): Plugin {
|
|||||||
|
|
||||||
const new_code = code.replace(RE_SVELTE_IMPORT, (str, $1, $2) => {
|
const new_code = code.replace(RE_SVELTE_IMPORT, (str, $1, $2) => {
|
||||||
return `const ${$1.replace(
|
return `const ${$1.replace(
|
||||||
" as ",
|
/ as /g,
|
||||||
": "
|
": "
|
||||||
)} = window.__gradio__svelte__internal;`;
|
)} = window.__gradio__svelte__internal;`;
|
||||||
});
|
});
|
||||||
@ -255,17 +255,35 @@ function generate_component_imports(): string {
|
|||||||
return imports;
|
return imports;
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_virtual_component_loader(): string {
|
function load_virtual_component_loader(mode: string): string {
|
||||||
const loader_path = join(__dirname, "component_loader.js");
|
const loader_path = join(__dirname, "component_loader.js");
|
||||||
const component_map = `
|
let component_map = "";
|
||||||
const component_map = {
|
|
||||||
${generate_component_imports()}
|
if (mode === "test") {
|
||||||
};
|
component_map = `
|
||||||
`;
|
const component_map = {
|
||||||
|
"test-component-one": {
|
||||||
|
component: () => import("@gradio-test/test-one"),
|
||||||
|
example: () => import("@gradio-test/test-one/example")
|
||||||
|
},
|
||||||
|
"dataset": {
|
||||||
|
component: () => import("@gradio-test/test-two"),
|
||||||
|
example: () => import("@gradio-test/test-two/example")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
component_map = `
|
||||||
|
const component_map = {
|
||||||
|
${generate_component_imports()}
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
return `${component_map}\n\n${readFileSync(loader_path, "utf8")}`;
|
return `${component_map}\n\n${readFileSync(loader_path, "utf8")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inject_component_loader(): Plugin {
|
export function inject_component_loader({ mode }: { mode: string }): Plugin {
|
||||||
const v_id = "virtual:component-loader";
|
const v_id = "virtual:component-loader";
|
||||||
const resolved_v_id = "\0" + v_id;
|
const resolved_v_id = "\0" + v_id;
|
||||||
|
|
||||||
@ -276,8 +294,9 @@ export function inject_component_loader(): Plugin {
|
|||||||
if (id === v_id) return resolved_v_id;
|
if (id === v_id) return resolved_v_id;
|
||||||
},
|
},
|
||||||
load(id: string) {
|
load(id: string) {
|
||||||
|
this.addWatchFile(join(__dirname, "component_loader.js"));
|
||||||
if (id === resolved_v_id) {
|
if (id === resolved_v_id) {
|
||||||
return load_virtual_component_loader();
|
return load_virtual_component_loader(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -311,3 +330,39 @@ export function resolve_svelte(enable: boolean): Plugin {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function mock_modules(): Plugin {
|
||||||
|
const v_id_1 = "@gradio-test/test-one";
|
||||||
|
const v_id_2 = "@gradio-test/test-two";
|
||||||
|
const v_id_1_example = "@gradio-test/test-one/example";
|
||||||
|
const v_id_2_example = "@gradio-test/test-two/example";
|
||||||
|
const resolved_v_id = "\0" + v_id_1;
|
||||||
|
const resolved_v_id_2 = "\0" + v_id_2;
|
||||||
|
const resolved_v_id_1_example = "\0" + v_id_1_example;
|
||||||
|
const resolved_v_id_2_example = "\0" + v_id_2_example;
|
||||||
|
const fallback_example = "@gradio/fallback/example";
|
||||||
|
const resolved_fallback_example = "\0" + fallback_example;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "mock-modules",
|
||||||
|
enforce: "pre",
|
||||||
|
resolveId(id: string) {
|
||||||
|
if (id === v_id_1) return resolved_v_id;
|
||||||
|
if (id === v_id_2) return resolved_v_id_2;
|
||||||
|
if (id === v_id_1_example) return resolved_v_id_1_example;
|
||||||
|
if (id === v_id_2_example) return resolved_v_id_2_example;
|
||||||
|
if (id === fallback_example) return resolved_fallback_example;
|
||||||
|
},
|
||||||
|
load(id: string) {
|
||||||
|
if (
|
||||||
|
id === resolved_v_id ||
|
||||||
|
id === resolved_v_id_2 ||
|
||||||
|
id === resolved_v_id_1_example ||
|
||||||
|
id === resolved_v_id_2_example ||
|
||||||
|
id === resolved_fallback_example
|
||||||
|
) {
|
||||||
|
return `export default {}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
export async function load_component({ api_url, name, id, variant }) {
|
const request_map = {};
|
||||||
|
|
||||||
|
export function load_component({ api_url, name, id, variant }) {
|
||||||
const comps = window.__GRADIO__CC__;
|
const comps = window.__GRADIO__CC__;
|
||||||
|
|
||||||
const _component_map = {
|
const _component_map = {
|
||||||
@ -9,31 +11,41 @@ export async function load_component({ api_url, name, id, variant }) {
|
|||||||
...(!comps ? {} : comps)
|
...(!comps ? {} : comps)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (request_map[`${id}-${variant}`]) {
|
||||||
|
return { component: request_map[`${id}-${variant}`], name };
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const c = await (
|
if (!_component_map?.[id]?.[variant] && !_component_map?.[name]?.[variant])
|
||||||
|
throw new Error();
|
||||||
|
|
||||||
|
request_map[`${id}-${variant}`] = (
|
||||||
_component_map?.[id]?.[variant] || // for dev mode custom components
|
_component_map?.[id]?.[variant] || // for dev mode custom components
|
||||||
_component_map?.[name]?.[variant]
|
_component_map?.[name]?.[variant]
|
||||||
)();
|
)();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
component: c
|
component: request_map[`${id}-${variant}`]
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
|
||||||
try {
|
try {
|
||||||
await load_css(`${api_url}/custom_component/${id}/${variant}/style.css`);
|
request_map[`${id}-${variant}`] = get_component_with_css(
|
||||||
const c = await import(
|
api_url,
|
||||||
/* @vite-ignore */ `${api_url}/custom_component/${id}/${variant}/index.js`
|
id,
|
||||||
|
variant
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
component: c
|
component: request_map[`${id}-${variant}`]
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (variant === "example") {
|
if (variant === "example") {
|
||||||
|
request_map[`${id}-${variant}`] = import("@gradio/fallback/example");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
component: await import("@gradio/fallback/example")
|
component: request_map[`${id}-${variant}`]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
console.error(`failed to load: ${name}`);
|
console.error(`failed to load: ${name}`);
|
||||||
@ -53,3 +65,14 @@ function load_css(url) {
|
|||||||
link.onerror = () => reject();
|
link.onerror = () => reject();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_component_with_css(api_url, id, variant) {
|
||||||
|
return Promise.all([
|
||||||
|
load_css(`${api_url}/custom_component/${id}/${variant}/style.css`),
|
||||||
|
import(
|
||||||
|
/* @vite-ignore */ `${api_url}/custom_component/${id}/${variant}/index.js`
|
||||||
|
)
|
||||||
|
]).then(([_, module]) => {
|
||||||
|
return module;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { load_component } from "virtual:component-loader";
|
|
||||||
|
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import { _ } from "svelte-i18n";
|
import { _ } from "svelte-i18n";
|
||||||
import type { client } from "@gradio/client";
|
import { client } from "@gradio/client";
|
||||||
|
|
||||||
import { create_loading_status_store } from "./stores";
|
|
||||||
import type { LoadingStatusCollection } from "./stores";
|
import type { LoadingStatusCollection } from "./stores";
|
||||||
|
|
||||||
import type { ComponentMeta, Dependency, LayoutNode } from "./types";
|
import type { ComponentMeta, Dependency, LayoutNode } from "./types";
|
||||||
|
import type { UpdateTransaction } from "./init";
|
||||||
import { setupi18n } from "./i18n";
|
import { setupi18n } from "./i18n";
|
||||||
import { ApiDocs } from "./api_docs/";
|
import { ApiDocs } from "./api_docs/";
|
||||||
import type { ThemeMode, Payload } from "./types";
|
import type { ThemeMode, Payload } from "./types";
|
||||||
@ -19,6 +17,7 @@
|
|||||||
|
|
||||||
import logo from "./images/logo.svg";
|
import logo from "./images/logo.svg";
|
||||||
import api_logo from "./api_docs/img/api-logo.svg";
|
import api_logo from "./api_docs/img/api-logo.svg";
|
||||||
|
import { create_components, AsyncFunction } from "./init";
|
||||||
|
|
||||||
setupi18n();
|
setupi18n();
|
||||||
|
|
||||||
@ -40,38 +39,23 @@
|
|||||||
export let version: string;
|
export let version: string;
|
||||||
export let js: string | null;
|
export let js: string | null;
|
||||||
export let fill_height = false;
|
export let fill_height = false;
|
||||||
|
export let ready: boolean;
|
||||||
|
|
||||||
let loading_status = create_loading_status_store();
|
const {
|
||||||
|
layout: _layout,
|
||||||
let rootNode: ComponentMeta = {
|
targets,
|
||||||
id: layout.id,
|
update_value,
|
||||||
type: "column",
|
get_data,
|
||||||
props: { interactive: false, scale: fill_height ? 1 : null },
|
loading_status,
|
||||||
has_modes: false,
|
scheduled_updates
|
||||||
instance: null as unknown as ComponentMeta["instance"],
|
} = create_components(components, layout, dependencies, root, app, {
|
||||||
component: null as unknown as ComponentMeta["component"],
|
fill_height
|
||||||
component_class_id: ""
|
|
||||||
};
|
|
||||||
|
|
||||||
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
||||||
dependencies.forEach((d) => {
|
|
||||||
if (d.js) {
|
|
||||||
const wrap = d.backend_fn
|
|
||||||
? d.inputs.length === 1
|
|
||||||
: d.outputs.length === 1;
|
|
||||||
try {
|
|
||||||
d.frontend_fn = new AsyncFunction(
|
|
||||||
"__fn_args",
|
|
||||||
`let result = await (${d.js})(...__fn_args);
|
|
||||||
return (${wrap} && !Array.isArray(result)) ? [result] : result;`
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Could not parse custom js method.");
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: {
|
||||||
|
ready = !!$_layout;
|
||||||
|
}
|
||||||
|
|
||||||
let params = new URLSearchParams(window.location.search);
|
let params = new URLSearchParams(window.location.search);
|
||||||
let api_docs_visible = params.get("view") === "api" && show_api;
|
let api_docs_visible = params.get("view") === "api" && show_api;
|
||||||
function set_api_docs_visible(visible: boolean): void {
|
function set_api_docs_visible(visible: boolean): void {
|
||||||
@ -85,276 +69,25 @@
|
|||||||
history.replaceState(null, "", "?" + params.toString());
|
history.replaceState(null, "", "?" + params.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_dep(
|
|
||||||
id: number,
|
|
||||||
type: "inputs" | "outputs",
|
|
||||||
deps: Dependency[]
|
|
||||||
): boolean {
|
|
||||||
for (const dep of deps) {
|
|
||||||
for (const dep_item of dep[type]) {
|
|
||||||
if (dep_item === id) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dynamic_ids: Set<number> = new Set();
|
|
||||||
|
|
||||||
function has_no_default_value(value: any): boolean {
|
|
||||||
return (
|
|
||||||
(Array.isArray(value) && value.length === 0) ||
|
|
||||||
value === "" ||
|
|
||||||
value === 0 ||
|
|
||||||
!value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance_map: { [id: number]: ComponentMeta };
|
|
||||||
|
|
||||||
type LoadedComponent = {
|
|
||||||
default: ComponentMeta["component"];
|
|
||||||
};
|
|
||||||
|
|
||||||
let component_set = new Set<
|
|
||||||
Promise<{ name: ComponentMeta["type"]; component: LoadedComponent }>
|
|
||||||
>();
|
|
||||||
|
|
||||||
let _component_map = new Map<
|
|
||||||
`${ComponentMeta["type"]}_${ComponentMeta["props"]["interactive"]}`,
|
|
||||||
Promise<{ name: ComponentMeta["type"]; component: LoadedComponent }>
|
|
||||||
>();
|
|
||||||
|
|
||||||
async function walk_layout(
|
|
||||||
node: LayoutNode,
|
|
||||||
type_map: Map<number, ComponentMeta["props"]["interactive"]>,
|
|
||||||
instance_map: { [id: number]: ComponentMeta },
|
|
||||||
component_map: Map<
|
|
||||||
`${ComponentMeta["type"]}_${ComponentMeta["props"]["interactive"]}`,
|
|
||||||
Promise<{ name: ComponentMeta["type"]; component: LoadedComponent }>
|
|
||||||
>
|
|
||||||
): Promise<void> {
|
|
||||||
ready = false;
|
|
||||||
let instance = instance_map[node.id];
|
|
||||||
|
|
||||||
const _component = (await component_map.get(
|
|
||||||
`${instance.type}_${type_map.get(node.id) || "false"}`
|
|
||||||
))!.component;
|
|
||||||
instance.component = _component.default;
|
|
||||||
|
|
||||||
if (node.children) {
|
|
||||||
instance.children = node.children.map((v) => instance_map[v.id]);
|
|
||||||
await Promise.all(
|
|
||||||
node.children.map((v) =>
|
|
||||||
walk_layout(v, type_map, instance_map, component_map)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export let ready = false;
|
|
||||||
export let render_complete = false;
|
export let render_complete = false;
|
||||||
|
|
||||||
$: components, layout, prepare_components();
|
|
||||||
|
|
||||||
let target_map: Record<number, Record<string, number[]>> = {};
|
|
||||||
|
|
||||||
function prepare_components(): void {
|
|
||||||
target_map = dependencies.reduce(
|
|
||||||
(acc, dep, i) => {
|
|
||||||
dep.targets.forEach(([id, trigger]) => {
|
|
||||||
if (!acc[id]) {
|
|
||||||
acc[id] = {};
|
|
||||||
}
|
|
||||||
if (acc[id]?.[trigger]) {
|
|
||||||
acc[id][trigger].push(i);
|
|
||||||
} else {
|
|
||||||
acc[id][trigger] = [i];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{} as Record<number, Record<string, number[]>>
|
|
||||||
);
|
|
||||||
loading_status = create_loading_status_store();
|
|
||||||
|
|
||||||
dependencies.forEach((v, i) => {
|
|
||||||
loading_status.register(i, v.inputs, v.outputs);
|
|
||||||
});
|
|
||||||
|
|
||||||
const _dynamic_ids = new Set<number>();
|
|
||||||
for (const comp of components) {
|
|
||||||
const { id, props } = comp;
|
|
||||||
const is_input = is_dep(id, "inputs", dependencies);
|
|
||||||
if (
|
|
||||||
is_input ||
|
|
||||||
(!is_dep(id, "outputs", dependencies) &&
|
|
||||||
has_no_default_value(props?.value))
|
|
||||||
) {
|
|
||||||
_dynamic_ids.add(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_ids = _dynamic_ids;
|
|
||||||
|
|
||||||
const _rootNode: typeof rootNode = {
|
|
||||||
id: layout.id,
|
|
||||||
type: "column",
|
|
||||||
props: { interactive: false, scale: fill_height ? 1 : null },
|
|
||||||
has_modes: false,
|
|
||||||
instance: null as unknown as ComponentMeta["instance"],
|
|
||||||
component: null as unknown as ComponentMeta["component"],
|
|
||||||
component_class_id: ""
|
|
||||||
};
|
|
||||||
components.push(_rootNode);
|
|
||||||
const _component_set = new Set<
|
|
||||||
Promise<{ name: ComponentMeta["type"]; component: LoadedComponent }>
|
|
||||||
>();
|
|
||||||
const __component_map = new Map<
|
|
||||||
`${ComponentMeta["type"]}_${ComponentMeta["props"]["interactive"]}`,
|
|
||||||
Promise<{ name: ComponentMeta["type"]; component: LoadedComponent }>
|
|
||||||
>();
|
|
||||||
const __type_for_id = new Map<
|
|
||||||
number,
|
|
||||||
ComponentMeta["props"]["interactive"]
|
|
||||||
>();
|
|
||||||
const _instance_map = components.reduce(
|
|
||||||
(acc, next) => {
|
|
||||||
acc[next.id] = next;
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{} as { [id: number]: ComponentMeta }
|
|
||||||
);
|
|
||||||
components.forEach((c) => {
|
|
||||||
if ((c.props as any).interactive === false) {
|
|
||||||
(c.props as any).interactive = false;
|
|
||||||
} else if ((c.props as any).interactive === true) {
|
|
||||||
(c.props as any).interactive = true;
|
|
||||||
} else if (dynamic_ids.has(c.id)) {
|
|
||||||
(c.props as any).interactive = true;
|
|
||||||
} else {
|
|
||||||
(c.props as any).interactive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c.props as any).server_fns) {
|
|
||||||
let server: Record<string, (...args: any[]) => Promise<any>> = {};
|
|
||||||
(c.props as any).server_fns.forEach((fn: string) => {
|
|
||||||
server[fn] = async (...args: any[]) => {
|
|
||||||
if (args.length === 1) {
|
|
||||||
args = args[0];
|
|
||||||
}
|
|
||||||
const result = await app.component_server(c.id, fn, args);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
(c.props as any).server = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_map[c.id]) {
|
|
||||||
c.props.attached_events = Object.keys(target_map[c.id]);
|
|
||||||
}
|
|
||||||
__type_for_id.set(c.id, c.props.interactive);
|
|
||||||
|
|
||||||
if (c.type === "dataset") {
|
|
||||||
const example_component_map = new Map();
|
|
||||||
|
|
||||||
(c.props.components as string[]).forEach((name: string) => {
|
|
||||||
if (example_component_map.has(name)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let _c;
|
|
||||||
|
|
||||||
const matching_component = components.find((c) => c.type === name);
|
|
||||||
if (matching_component) {
|
|
||||||
_c = load_component({
|
|
||||||
api_url: root,
|
|
||||||
name,
|
|
||||||
id: matching_component.component_class_id,
|
|
||||||
variant: "example"
|
|
||||||
});
|
|
||||||
example_component_map.set(name, _c);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
c.props.component_map = example_component_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe load custom
|
|
||||||
|
|
||||||
const _c = load_component({
|
|
||||||
api_url: root,
|
|
||||||
name: c.type,
|
|
||||||
id: c.component_class_id,
|
|
||||||
variant: "component"
|
|
||||||
});
|
|
||||||
_component_set.add(_c);
|
|
||||||
__component_map.set(`${c.type}_${c.props.interactive}`, _c);
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(Array.from(_component_set)).then(() => {
|
|
||||||
walk_layout(layout, __type_for_id, _instance_map, __component_map)
|
|
||||||
.then(async () => {
|
|
||||||
ready = true;
|
|
||||||
component_set = _component_set;
|
|
||||||
_component_map = __component_map;
|
|
||||||
instance_map = _instance_map;
|
|
||||||
rootNode = _rootNode;
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function throttle<T extends (...args: any[]) => any>(
|
|
||||||
func: T,
|
|
||||||
limit: number
|
|
||||||
): (...funcArgs: Parameters<T>) => void {
|
|
||||||
let lastFunc: ReturnType<typeof setTimeout>;
|
|
||||||
let lastRan: number;
|
|
||||||
let lastThis: any;
|
|
||||||
let lastArgs: IArguments | null;
|
|
||||||
|
|
||||||
return function (this: any, ...args: Parameters<T>) {
|
|
||||||
if (!lastRan) {
|
|
||||||
func.apply(this, args);
|
|
||||||
lastRan = Date.now();
|
|
||||||
} else {
|
|
||||||
clearTimeout(lastFunc);
|
|
||||||
lastThis = this;
|
|
||||||
lastArgs = arguments;
|
|
||||||
|
|
||||||
lastFunc = setTimeout(
|
|
||||||
() => {
|
|
||||||
if (Date.now() - lastRan >= limit) {
|
|
||||||
if (lastArgs) {
|
|
||||||
func.apply(lastThis, Array.prototype.slice.call(lastArgs));
|
|
||||||
}
|
|
||||||
lastRan = Date.now();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Math.max(limit - (Date.now() - lastRan), 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const refresh = throttle(() => {
|
|
||||||
rootNode = rootNode;
|
|
||||||
}, 50);
|
|
||||||
|
|
||||||
async function handle_update(data: any, fn_index: number): Promise<void> {
|
async function handle_update(data: any, fn_index: number): Promise<void> {
|
||||||
const outputs = dependencies[fn_index].outputs;
|
const outputs = dependencies[fn_index].outputs;
|
||||||
|
|
||||||
data?.forEach((value: any, i: number) => {
|
const meta_updates = data?.map((value: any, i: number) => {
|
||||||
const output = instance_map[outputs[i]];
|
return {
|
||||||
output.props.value_is_output = true;
|
id: outputs[i],
|
||||||
|
prop: "value_is_output",
|
||||||
|
value: true
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
refresh();
|
update_value(meta_updates);
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
|
const updates: UpdateTransaction[] = [];
|
||||||
|
|
||||||
data?.forEach((value: any, i: number) => {
|
data?.forEach((value: any, i: number) => {
|
||||||
const output = instance_map[outputs[i]];
|
|
||||||
if (
|
if (
|
||||||
typeof value === "object" &&
|
typeof value === "object" &&
|
||||||
value !== null &&
|
value !== null &&
|
||||||
@ -364,30 +97,26 @@
|
|||||||
if (update_key === "__type__") {
|
if (update_key === "__type__") {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
output.props[update_key] = update_value;
|
updates.push({
|
||||||
|
id: outputs[i],
|
||||||
|
prop: update_key,
|
||||||
|
value: update_value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
output.props.value = value;
|
updates.push({
|
||||||
|
id: outputs[i],
|
||||||
|
prop: "value",
|
||||||
|
value
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
refresh();
|
update_value(updates);
|
||||||
}
|
}
|
||||||
|
|
||||||
let submit_map: Map<number, ReturnType<typeof app.submit>> = new Map();
|
let submit_map: Map<number, ReturnType<typeof app.submit>> = new Map();
|
||||||
|
|
||||||
function set_prop<T extends ComponentMeta>(
|
|
||||||
obj: T,
|
|
||||||
prop: string,
|
|
||||||
val: any
|
|
||||||
): void {
|
|
||||||
if (!obj?.props) {
|
|
||||||
// @ts-ignore
|
|
||||||
obj.props = {};
|
|
||||||
}
|
|
||||||
obj.props[prop] = val;
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
let handled_dependencies: number[][] = [];
|
let handled_dependencies: number[][] = [];
|
||||||
|
|
||||||
let messages: (ToastMessage & { fn_index: number })[] = [];
|
let messages: (ToastMessage & { fn_index: number })[] = [];
|
||||||
@ -427,11 +156,26 @@
|
|||||||
let showed_duplicate_message = false;
|
let showed_duplicate_message = false;
|
||||||
let showed_mobile_warning = false;
|
let showed_mobile_warning = false;
|
||||||
|
|
||||||
function get_data(comp: ComponentMeta): any | Promise<any> {
|
// as state updates are not synchronous, we need to ensure updates are flushed before triggering any requests
|
||||||
if (comp.instance.get_value) {
|
function wait_then_trigger_api_call(
|
||||||
return comp.instance.get_value() as Promise<any>;
|
dep_index: number,
|
||||||
|
trigger_id: number | null = null,
|
||||||
|
event_data: unknown = null
|
||||||
|
): void {
|
||||||
|
let _unsub = (): void => {};
|
||||||
|
function unsub(): void {
|
||||||
|
_unsub();
|
||||||
|
}
|
||||||
|
if ($scheduled_updates) {
|
||||||
|
_unsub = scheduled_updates.subscribe((updating) => {
|
||||||
|
if (!updating) {
|
||||||
|
trigger_api_call(dep_index, trigger_id, event_data);
|
||||||
|
unsub();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
trigger_api_call(dep_index, trigger_id, event_data);
|
||||||
}
|
}
|
||||||
return comp.props.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function trigger_api_call(
|
async function trigger_api_call(
|
||||||
@ -440,6 +184,7 @@
|
|||||||
event_data: unknown = null
|
event_data: unknown = null
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let dep = dependencies[dep_index];
|
let dep = dependencies[dep_index];
|
||||||
|
|
||||||
const current_status = loading_status.get_status_for_fn(dep_index);
|
const current_status = loading_status.get_status_for_fn(dep_index);
|
||||||
messages = messages.filter(({ fn_index }) => fn_index !== dep_index);
|
messages = messages.filter(({ fn_index }) => fn_index !== dep_index);
|
||||||
if (dep.cancels) {
|
if (dep.cancels) {
|
||||||
@ -457,9 +202,7 @@
|
|||||||
|
|
||||||
let payload: Payload = {
|
let payload: Payload = {
|
||||||
fn_index: dep_index,
|
fn_index: dep_index,
|
||||||
data: await Promise.all(
|
data: await Promise.all(dep.inputs.map((id) => get_data(id))),
|
||||||
dep.inputs.map((id) => get_data(instance_map[id]))
|
|
||||||
),
|
|
||||||
event_data: dep.collects_event_data ? event_data : null,
|
event_data: dep.collects_event_data ? event_data : null,
|
||||||
trigger_id: trigger_id
|
trigger_id: trigger_id
|
||||||
};
|
};
|
||||||
@ -468,9 +211,7 @@
|
|||||||
dep
|
dep
|
||||||
.frontend_fn(
|
.frontend_fn(
|
||||||
payload.data.concat(
|
payload.data.concat(
|
||||||
await Promise.all(
|
await Promise.all(dep.inputs.map((id) => get_data(id)))
|
||||||
dep.inputs.map((id) => get_data(instance_map[id]))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then((v: unknown[]) => {
|
.then((v: unknown[]) => {
|
||||||
@ -497,7 +238,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_prediction(payload: Payload): void {
|
async function make_prediction(payload: Payload): Promise<void> {
|
||||||
const submission = app
|
const submission = app
|
||||||
.submit(
|
.submit(
|
||||||
payload.fn_index,
|
payload.fn_index,
|
||||||
@ -514,7 +255,7 @@
|
|||||||
handle_update(data, fn_index);
|
handle_update(data, fn_index);
|
||||||
})
|
})
|
||||||
.on("status", ({ fn_index, ...status }) => {
|
.on("status", ({ fn_index, ...status }) => {
|
||||||
tick().then(() => {
|
requestAnimationFrame(() => {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
loading_status.update({
|
loading_status.update({
|
||||||
...status,
|
...status,
|
||||||
@ -552,7 +293,7 @@
|
|||||||
if (status.stage === "complete") {
|
if (status.stage === "complete") {
|
||||||
dependencies.map(async (dep, i) => {
|
dependencies.map(async (dep, i) => {
|
||||||
if (dep.trigger_after === fn_index) {
|
if (dep.trigger_after === fn_index) {
|
||||||
trigger_api_call(i, payload.trigger_id);
|
wait_then_trigger_api_call(i, payload.trigger_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -565,7 +306,11 @@
|
|||||||
...messages
|
...messages
|
||||||
];
|
];
|
||||||
}, 0);
|
}, 0);
|
||||||
trigger_api_call(dep_index, payload.trigger_id, event_data);
|
wait_then_trigger_api_call(
|
||||||
|
dep_index,
|
||||||
|
payload.trigger_id,
|
||||||
|
event_data
|
||||||
|
);
|
||||||
user_left_page = false;
|
user_left_page = false;
|
||||||
} else if (status.stage === "error") {
|
} else if (status.stage === "error") {
|
||||||
if (status.message) {
|
if (status.message) {
|
||||||
@ -583,7 +328,7 @@
|
|||||||
dep.trigger_after === fn_index &&
|
dep.trigger_after === fn_index &&
|
||||||
!dep.trigger_only_on_success
|
!dep.trigger_only_on_success
|
||||||
) {
|
) {
|
||||||
trigger_api_call(i, payload.trigger_id);
|
wait_then_trigger_api_call(i, payload.trigger_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -627,7 +372,7 @@
|
|||||||
`let result = await (${js})();
|
`let result = await (${js})();
|
||||||
return (!Array.isArray(result)) ? [result] : result;`
|
return (!Array.isArray(result)) ? [result] : result;`
|
||||||
);
|
);
|
||||||
blocks_frontend_fn();
|
await blocks_frontend_fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
@ -646,11 +391,17 @@
|
|||||||
// handle load triggers
|
// handle load triggers
|
||||||
dependencies.forEach((dep, i) => {
|
dependencies.forEach((dep, i) => {
|
||||||
if (dep.targets[0][1] === "load") {
|
if (dep.targets[0][1] === "load") {
|
||||||
trigger_api_call(i);
|
wait_then_trigger_api_call(i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (render_complete) return;
|
if (render_complete) return;
|
||||||
|
|
||||||
|
target.addEventListener("prop_change", (e: Event) => {
|
||||||
|
if (!isCustomEvent(e)) throw new Error("not a custom event");
|
||||||
|
const { id, prop, value } = e.detail;
|
||||||
|
update_value([{ id, prop, value }]);
|
||||||
|
});
|
||||||
target.addEventListener("gradio", (e: Event) => {
|
target.addEventListener("gradio", (e: Event) => {
|
||||||
if (!isCustomEvent(e)) throw new Error("not a custom event");
|
if (!isCustomEvent(e)) throw new Error("not a custom event");
|
||||||
|
|
||||||
@ -662,9 +413,10 @@
|
|||||||
} else if (event === "error" || event === "warning") {
|
} else if (event === "error" || event === "warning") {
|
||||||
messages = [new_message(data, -1, event), ...messages];
|
messages = [new_message(data, -1, event), ...messages];
|
||||||
} else {
|
} else {
|
||||||
const deps = target_map[id]?.[event];
|
const deps = targets[id]?.[event];
|
||||||
|
|
||||||
deps?.forEach((dep_id) => {
|
deps?.forEach((dep_id) => {
|
||||||
trigger_api_call(dep_id, id, data);
|
wait_then_trigger_api_call(dep_id, id, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -681,18 +433,30 @@
|
|||||||
$: set_status($loading_status);
|
$: set_status($loading_status);
|
||||||
|
|
||||||
function set_status(statuses: LoadingStatusCollection): void {
|
function set_status(statuses: LoadingStatusCollection): void {
|
||||||
for (const id in statuses) {
|
const updates = Object.entries(statuses).map(([id, loading_status]) => {
|
||||||
let loading_status = statuses[id];
|
|
||||||
let dependency = dependencies[loading_status.fn_index];
|
let dependency = dependencies[loading_status.fn_index];
|
||||||
loading_status.scroll_to_output = dependency.scroll_to_output;
|
loading_status.scroll_to_output = dependency.scroll_to_output;
|
||||||
loading_status.show_progress = dependency.show_progress;
|
loading_status.show_progress = dependency.show_progress;
|
||||||
|
return {
|
||||||
|
id: parseInt(id),
|
||||||
|
prop: "loading_status",
|
||||||
|
value: loading_status
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
set_prop(instance_map[id], "loading_status", loading_status);
|
|
||||||
}
|
|
||||||
const inputs_to_update = loading_status.get_inputs_to_update();
|
const inputs_to_update = loading_status.get_inputs_to_update();
|
||||||
for (const [id, pending_status] of inputs_to_update) {
|
|
||||||
set_prop(instance_map[id], "pending", pending_status === "pending");
|
const additional_updates = Array.from(inputs_to_update).map(
|
||||||
}
|
([id, pending_status]) => {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
prop: "pending",
|
||||||
|
value: pending_status === "pending"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
update_value([...updates, ...additional_updates]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCustomEvent(event: Event): event is CustomEvent {
|
function isCustomEvent(event: Event): event is CustomEvent {
|
||||||
@ -725,11 +489,9 @@
|
|||||||
|
|
||||||
<div class="wrap" style:min-height={app_mode ? "100%" : "auto"}>
|
<div class="wrap" style:min-height={app_mode ? "100%" : "auto"}>
|
||||||
<div class="contain" style:flex-grow={app_mode ? "1" : "auto"}>
|
<div class="contain" style:flex-grow={app_mode ? "1" : "auto"}>
|
||||||
{#if ready}
|
{#if $_layout}
|
||||||
<MountComponents
|
<MountComponents
|
||||||
{rootNode}
|
rootNode={$_layout}
|
||||||
{dynamic_ids}
|
|
||||||
{instance_map}
|
|
||||||
{root}
|
{root}
|
||||||
{target}
|
{target}
|
||||||
{theme_mode}
|
{theme_mode}
|
||||||
@ -768,7 +530,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if api_docs_visible && ready}
|
{#if api_docs_visible && $_layout}
|
||||||
<div class="api-docs">
|
<div class="api-docs">
|
||||||
<!-- TODO: fix -->
|
<!-- TODO: fix -->
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events-->
|
<!-- svelte-ignore a11y-click-events-have-key-events-->
|
||||||
@ -781,10 +543,10 @@
|
|||||||
/>
|
/>
|
||||||
<div class="api-docs-wrap">
|
<div class="api-docs-wrap">
|
||||||
<ApiDocs
|
<ApiDocs
|
||||||
|
root_node={$_layout}
|
||||||
on:close={() => {
|
on:close={() => {
|
||||||
set_api_docs_visible(false);
|
set_api_docs_visible(false);
|
||||||
}}
|
}}
|
||||||
{instance_map}
|
|
||||||
{dependencies}
|
{dependencies}
|
||||||
{root}
|
{root}
|
||||||
{app}
|
{app}
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
import Render from "./Render.svelte";
|
import Render from "./Render.svelte";
|
||||||
|
|
||||||
export let rootNode: any;
|
export let rootNode: any;
|
||||||
export let dynamic_ids: any;
|
|
||||||
export let instance_map: any;
|
|
||||||
export let root: any;
|
export let root: any;
|
||||||
export let target: any;
|
export let target: any;
|
||||||
export let theme_mode: any;
|
export let theme_mode: any;
|
||||||
@ -17,16 +15,4 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Render
|
<Render node={rootNode} {root} {target} {theme_mode} {version} {autoscroll} />
|
||||||
component={rootNode.component}
|
|
||||||
id={rootNode.id}
|
|
||||||
props={rootNode.props}
|
|
||||||
children={rootNode.children}
|
|
||||||
{dynamic_ids}
|
|
||||||
{instance_map}
|
|
||||||
{root}
|
|
||||||
{target}
|
|
||||||
{theme_mode}
|
|
||||||
{version}
|
|
||||||
{autoscroll}
|
|
||||||
/>
|
|
||||||
|
@ -2,16 +2,11 @@
|
|||||||
import { Gradio } from "./gradio_helper";
|
import { Gradio } from "./gradio_helper";
|
||||||
import { onMount, createEventDispatcher, setContext } from "svelte";
|
import { onMount, createEventDispatcher, setContext } from "svelte";
|
||||||
import type { ComponentMeta, ThemeMode } from "./types";
|
import type { ComponentMeta, ThemeMode } from "./types";
|
||||||
|
import RenderComponent from "./RenderComponent.svelte";
|
||||||
|
|
||||||
export let root: string;
|
export let root: string;
|
||||||
export let component: ComponentMeta["component"];
|
|
||||||
export let instance_map: Record<number, ComponentMeta>;
|
|
||||||
|
|
||||||
export let id: number;
|
export let node: ComponentMeta;
|
||||||
export let props: ComponentMeta["props"];
|
|
||||||
|
|
||||||
export let children: ComponentMeta["children"];
|
|
||||||
export let dynamic_ids: Set<number>;
|
|
||||||
export let parent: string | null = null;
|
export let parent: string | null = null;
|
||||||
export let target: HTMLElement;
|
export let target: HTMLElement;
|
||||||
export let theme_mode: ThemeMode;
|
export let theme_mode: ThemeMode;
|
||||||
@ -22,14 +17,14 @@
|
|||||||
let filtered_children: ComponentMeta[] = [];
|
let filtered_children: ComponentMeta[] = [];
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
dispatch("mount", id);
|
dispatch("mount", node.id);
|
||||||
|
|
||||||
for (const child of filtered_children) {
|
for (const child of filtered_children) {
|
||||||
dispatch("mount", child.id);
|
dispatch("mount", child.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
dispatch("destroy", id);
|
dispatch("destroy", node.id);
|
||||||
|
|
||||||
for (const child of filtered_children) {
|
for (const child of filtered_children) {
|
||||||
dispatch("mount", child.id);
|
dispatch("mount", child.id);
|
||||||
@ -37,10 +32,10 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
$: children =
|
$: node.children =
|
||||||
children &&
|
node.children &&
|
||||||
children.filter((v) => {
|
node.children.filter((v) => {
|
||||||
const valid_node = instance_map[v.id].type !== "statustracker";
|
const valid_node = node.type !== "statustracker";
|
||||||
if (!valid_node) {
|
if (!valid_node) {
|
||||||
filtered_children.push(v);
|
filtered_children.push(v);
|
||||||
}
|
}
|
||||||
@ -50,51 +45,49 @@
|
|||||||
setContext("BLOCK_KEY", parent);
|
setContext("BLOCK_KEY", parent);
|
||||||
|
|
||||||
function handle_prop_change(e: { detail: Record<string, any> }): void {
|
function handle_prop_change(e: { detail: Record<string, any> }): void {
|
||||||
for (const k in e.detail) {
|
// for (const k in e.detail) {
|
||||||
instance_map[id].props[k] = e.detail[k];
|
// instance_map[id].props[k] = e.detail[k];
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (instance_map[id].type === "form") {
|
if (node.type === "form") {
|
||||||
if (children?.every((c) => !c.props.visible)) {
|
if (node.children?.every((c) => !c.props.visible)) {
|
||||||
props.visible = false;
|
node.props.visible = false;
|
||||||
} else {
|
} else {
|
||||||
props.visible = true;
|
node.props.visible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:component
|
<RenderComponent
|
||||||
this={component}
|
id={node.id}
|
||||||
bind:this={instance_map[id].instance}
|
component={node.component}
|
||||||
bind:value={instance_map[id].props.value}
|
bind:instance={node.instance}
|
||||||
elem_id={("elem_id" in props && props.elem_id) || `component-${id}`}
|
bind:value={node.props.value}
|
||||||
elem_classes={("elem_classes" in props && props.elem_classes) || []}
|
elem_id={("elem_id" in node.props && node.props.elem_id) ||
|
||||||
|
`component-${node.id}`}
|
||||||
|
elem_classes={("elem_classes" in node.props && node.props.elem_classes) || []}
|
||||||
on:prop_change={handle_prop_change}
|
on:prop_change={handle_prop_change}
|
||||||
{target}
|
{target}
|
||||||
{...props}
|
{...node.props}
|
||||||
{theme_mode}
|
{theme_mode}
|
||||||
{root}
|
{root}
|
||||||
gradio={new Gradio(id, target, theme_mode, version, root, autoscroll)}
|
gradio={new Gradio(node.id, target, theme_mode, version, root, autoscroll)}
|
||||||
>
|
>
|
||||||
{#if children && children.length}
|
{#if node.children && node.children.length}
|
||||||
{#each children as { component, id: each_id, props, children: _children, has_modes } (each_id)}
|
{#each node.children as _node (_node.id)}
|
||||||
<svelte:self
|
<svelte:self
|
||||||
{component}
|
node={_node}
|
||||||
|
component={_node.component}
|
||||||
{target}
|
{target}
|
||||||
id={each_id}
|
id={_node.id}
|
||||||
{props}
|
|
||||||
{root}
|
{root}
|
||||||
{instance_map}
|
|
||||||
children={_children}
|
|
||||||
{dynamic_ids}
|
|
||||||
{has_modes}
|
|
||||||
{theme_mode}
|
{theme_mode}
|
||||||
on:destroy
|
on:destroy
|
||||||
on:mount
|
on:mount
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:component>
|
</RenderComponent>
|
||||||
|
69
js/app/src/RenderComponent.svelte
Normal file
69
js/app/src/RenderComponent.svelte
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<svelte:options immutable={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Gradio } from "./gradio_helper";
|
||||||
|
import type { ComponentMeta, ThemeMode } from "./types";
|
||||||
|
import type { SvelteComponent, ComponentType } from "svelte";
|
||||||
|
// @ts-ignore
|
||||||
|
import { bind, binding_callbacks } from "svelte/internal";
|
||||||
|
|
||||||
|
export let root: string;
|
||||||
|
export let component: ComponentMeta["component"];
|
||||||
|
export let target: HTMLElement;
|
||||||
|
export let theme_mode: ThemeMode;
|
||||||
|
export let instance: ComponentMeta["instance"];
|
||||||
|
export let value: any;
|
||||||
|
export let gradio: Gradio;
|
||||||
|
export let elem_id: string;
|
||||||
|
export let elem_classes: string[];
|
||||||
|
export let id: number;
|
||||||
|
|
||||||
|
const s = (id: number, p: string, v: any): CustomEvent =>
|
||||||
|
new CustomEvent("prop_change", { detail: { id, prop: p, value: v } });
|
||||||
|
|
||||||
|
function wrap(
|
||||||
|
component: ComponentType<SvelteComponent>
|
||||||
|
): ComponentType<SvelteComponent> {
|
||||||
|
const ProxiedMyClass = new Proxy(component, {
|
||||||
|
construct(_target, args: Record<string, any>[]) {
|
||||||
|
//@ts-ignore
|
||||||
|
const instance = new _target(...args);
|
||||||
|
const props = Object.getOwnPropertyNames(instance).filter(
|
||||||
|
(s) => !s.startsWith("$")
|
||||||
|
);
|
||||||
|
|
||||||
|
function report(props: string) {
|
||||||
|
return function (propargs: any) {
|
||||||
|
const ev = s(id, props, propargs);
|
||||||
|
target.dispatchEvent(ev);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
props.forEach((v) => {
|
||||||
|
binding_callbacks.push(() => bind(instance, v, report(v)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ProxiedMyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _component = wrap(component);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:component
|
||||||
|
this={_component}
|
||||||
|
bind:this={instance}
|
||||||
|
bind:value
|
||||||
|
on:prop_change
|
||||||
|
{elem_id}
|
||||||
|
{elem_classes}
|
||||||
|
{target}
|
||||||
|
{...$$restProps}
|
||||||
|
{theme_mode}
|
||||||
|
{root}
|
||||||
|
{gradio}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</svelte:component>
|
@ -16,14 +16,11 @@
|
|||||||
import python from "./img/python.svg";
|
import python from "./img/python.svg";
|
||||||
import javascript from "./img/javascript.svg";
|
import javascript from "./img/javascript.svg";
|
||||||
|
|
||||||
export let instance_map: {
|
|
||||||
[id: number]: ComponentMeta;
|
|
||||||
};
|
|
||||||
export let dependencies: Dependency[];
|
export let dependencies: Dependency[];
|
||||||
export let root: string;
|
export let root: string;
|
||||||
export let app: Awaited<ReturnType<typeof client>>;
|
export let app: Awaited<ReturnType<typeof client>>;
|
||||||
export let space_id: string | null;
|
export let space_id: string | null;
|
||||||
|
export let root_node: ComponentMeta;
|
||||||
const js_docs =
|
const js_docs =
|
||||||
"https://www.gradio.app/guides/getting-started-with-the-js-client";
|
"https://www.gradio.app/guides/getting-started-with-the-js-client";
|
||||||
const py_docs =
|
const py_docs =
|
||||||
@ -50,9 +47,27 @@
|
|||||||
|
|
||||||
let is_running = false;
|
let is_running = false;
|
||||||
|
|
||||||
|
function find_recursive(
|
||||||
|
node: ComponentMeta,
|
||||||
|
id: number
|
||||||
|
): ComponentMeta | null {
|
||||||
|
if (node.id === id) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node.children) {
|
||||||
|
for (let child of node.children) {
|
||||||
|
let result = find_recursive(child, id);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let dependency_inputs = dependencies.map((dependency) =>
|
let dependency_inputs = dependencies.map((dependency) =>
|
||||||
dependency.inputs.map((_id) => {
|
dependency.inputs.map((_id) => {
|
||||||
let default_data = instance_map[_id].documentation?.example_data;
|
let default_data = find_recursive(root_node, _id)?.props?.default;
|
||||||
if (default_data === undefined) {
|
if (default_data === undefined) {
|
||||||
default_data = "";
|
default_data = "";
|
||||||
} else if (typeof default_data === "object") {
|
} else if (typeof default_data === "object") {
|
||||||
@ -103,10 +118,9 @@
|
|||||||
let dependency = dependencies[index];
|
let dependency = dependencies[index];
|
||||||
let attempted_component_index = 0;
|
let attempted_component_index = 0;
|
||||||
try {
|
try {
|
||||||
var inputs = dependency_inputs[index].map((input_val, i) => {
|
var inputs = dependency_inputs[index].map((input_val: any, i: number) => {
|
||||||
attempted_component_index = i;
|
attempted_component_index = i;
|
||||||
let component = instance_map[dependency.inputs[i]];
|
let component = find_recursive(root_node, dependency.inputs[i])!;
|
||||||
// @ts-ignore
|
|
||||||
input_val = represent_value(
|
input_val = represent_value(
|
||||||
input_val,
|
input_val,
|
||||||
component.documentation?.type?.input_payload ||
|
component.documentation?.type?.input_payload ||
|
||||||
@ -130,7 +144,7 @@
|
|||||||
if (status_code == 200) {
|
if (status_code == 200) {
|
||||||
dependency_outputs[index] = response.data.map(
|
dependency_outputs[index] = response.data.map(
|
||||||
(output_val: any, i: number) => {
|
(output_val: any, i: number) => {
|
||||||
let component = instance_map[dependency.outputs[i]];
|
let component = find_recursive(root_node, dependency.outputs[i])!;
|
||||||
|
|
||||||
return represent_value(
|
return represent_value(
|
||||||
output_val,
|
output_val,
|
||||||
|
@ -35,6 +35,7 @@ export class Gradio<T extends Record<string, any> = Record<string, any>> {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
detail: { data, id: this.#id, event: event_name }
|
detail: { data, id: this.#id, event: event_name }
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#el.dispatchEvent(e);
|
this.#el.dispatchEvent(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
521
js/app/src/init.test.ts
Normal file
521
js/app/src/init.test.ts
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
import { describe, test, expect, vi } from "vitest";
|
||||||
|
import { spy } from "tinyspy";
|
||||||
|
import { setupServer } from "msw/node";
|
||||||
|
import { http, HttpResponse } from "msw";
|
||||||
|
import type { client_return } from "@gradio/client";
|
||||||
|
import { Dependency, TargetMap } from "./types";
|
||||||
|
import {
|
||||||
|
process_frontend_fn,
|
||||||
|
create_target_meta,
|
||||||
|
determine_interactivity,
|
||||||
|
process_server_fn,
|
||||||
|
get_component
|
||||||
|
} from "./init";
|
||||||
|
|
||||||
|
describe("process_frontend_fn", () => {
|
||||||
|
test("empty source code returns null", () => {
|
||||||
|
const source = "";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
expect(fn).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("falsey source code returns null: false", () => {
|
||||||
|
const source = false;
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
expect(fn).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("falsey source code returns null: undefined", () => {
|
||||||
|
const source = undefined;
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
expect(fn).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("falsey source code returns null: null", () => {
|
||||||
|
const source = null;
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
expect(fn).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("source code returns a function", () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
expect(typeof fn).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("arrays of values can be passed to the generated function", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual([1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("arrays of many values can be passed", async () => {
|
||||||
|
const source = "(...args) => args";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1, 2, 3, 4, 5, 6])).resolves.toEqual([1, 2, 3, 4, 5, 6]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The generated function returns a promise", () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
expect(fn([1])).toBeInstanceOf(Promise);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The generated function is callable and returns the expected value", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual([1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The return value of the function is wrapped in an array if there is no backend function and the input length is 1", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual([1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The return value of the function is not wrapped in an array if there is no backend function and the input length is greater than 1", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, false, 2, 2);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The return value of the function is wrapped in an array if there is a backend function and the input length is 1", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, true, 1, 1);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual([1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("The return value of the function is not wrapped in an array if there is a backend function and the input length is greater than 1", async () => {
|
||||||
|
const source = "(arg) => arg";
|
||||||
|
|
||||||
|
const fn = process_frontend_fn(source, true, 2, 2);
|
||||||
|
if (fn) {
|
||||||
|
await expect(fn([1])).resolves.toEqual(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("create_target_meta", () => {
|
||||||
|
test("creates a target map", () => {
|
||||||
|
const targets: Dependency["targets"] = [
|
||||||
|
[1, "change"],
|
||||||
|
[2, "input"],
|
||||||
|
[3, "load"]
|
||||||
|
];
|
||||||
|
const fn_index = 0;
|
||||||
|
const target_map = {};
|
||||||
|
|
||||||
|
const result = create_target_meta(targets, fn_index, target_map);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: { change: [0] },
|
||||||
|
2: { input: [0] },
|
||||||
|
3: { load: [0] }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the target already exists, it adds the new trigger to the list", () => {
|
||||||
|
const targets: Dependency["targets"] = [
|
||||||
|
[1, "change"],
|
||||||
|
[1, "input"],
|
||||||
|
[1, "load"]
|
||||||
|
];
|
||||||
|
const fn_index = 1;
|
||||||
|
const target_map: TargetMap = {
|
||||||
|
1: { change: [0] }
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = create_target_meta(targets, fn_index, target_map);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: { change: [0, 1], input: [1], load: [1] }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the trigger already exists, it adds the new function to the list", () => {
|
||||||
|
const targets: Dependency["targets"] = [
|
||||||
|
[1, "change"],
|
||||||
|
[2, "change"],
|
||||||
|
[3, "change"]
|
||||||
|
];
|
||||||
|
const fn_index = 1;
|
||||||
|
const target_map: TargetMap = {
|
||||||
|
1: { change: [0] },
|
||||||
|
2: { change: [0] },
|
||||||
|
3: { change: [0] }
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = create_target_meta(targets, fn_index, target_map);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: { change: [0, 1] },
|
||||||
|
2: { change: [0, 1] },
|
||||||
|
3: { change: [0, 1] }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the target and trigger already exist, it adds the new function to the list", () => {
|
||||||
|
const targets: Dependency["targets"] = [[1, "change"]];
|
||||||
|
const fn_index = 1;
|
||||||
|
const target_map: TargetMap = {
|
||||||
|
1: { change: [0] }
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = create_target_meta(targets, fn_index, target_map);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: { change: [0, 1] }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the target, trigger and function id already exist, it does not add duplicates", () => {
|
||||||
|
const targets: Dependency["targets"] = [[1, "change"]];
|
||||||
|
const fn_index = 0;
|
||||||
|
const target_map: TargetMap = {
|
||||||
|
1: { change: [0] }
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = create_target_meta(targets, fn_index, target_map);
|
||||||
|
expect(result).toEqual({
|
||||||
|
1: { change: [0] }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("determine_interactivity", () => {
|
||||||
|
test("returns true if the prop is interactive = true", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
"hi",
|
||||||
|
new Set([0]),
|
||||||
|
new Set([2])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns false if the prop is interactive = false", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
"hi",
|
||||||
|
new Set([0]),
|
||||||
|
new Set([2])
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is an input", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
0,
|
||||||
|
undefined,
|
||||||
|
"hi",
|
||||||
|
new Set([0]),
|
||||||
|
new Set([2])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: empty string", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
"",
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: empty array", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
[],
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: boolean", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: undefined", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: null", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
null,
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns true if the component is not an input or output and the component has no default value: 0", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
0,
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns false if the component is not an input or output and the component has a default value", () => {
|
||||||
|
const result = determine_interactivity(
|
||||||
|
2,
|
||||||
|
undefined,
|
||||||
|
"hello",
|
||||||
|
new Set([0]),
|
||||||
|
new Set([1])
|
||||||
|
);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("process_server_fn", () => {
|
||||||
|
test("returns an object", () => {
|
||||||
|
const result = process_server_fn(1, ["fn1", "fn2"], {} as any);
|
||||||
|
expect(result).toBeTypeOf("object");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns an object with the correct keys", () => {
|
||||||
|
const result = process_server_fn(1, ["fn1", "fn2"], {} as any);
|
||||||
|
expect(Object.keys(result)).toEqual(["fn1", "fn2"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns an object with the correct keys and values", () => {
|
||||||
|
const app = {
|
||||||
|
component_server: async (id: number, fn: string, args: any) => {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
} as client_return;
|
||||||
|
|
||||||
|
const result = process_server_fn(1, ["fn1", "fn2"], app);
|
||||||
|
expect(Object.keys(result)).toEqual(["fn1", "fn2"]);
|
||||||
|
|
||||||
|
expect(result.fn1).toBeInstanceOf(Function);
|
||||||
|
expect(result.fn2).toBeInstanceOf(Function);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returned server functions should resolve to a promise", async () => {
|
||||||
|
const app = {
|
||||||
|
component_server: async (id: number, fn: string, args: any) => {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
} as client_return;
|
||||||
|
|
||||||
|
const result = process_server_fn(1, ["fn1", "fn2"], app);
|
||||||
|
const response = result.fn1("hello");
|
||||||
|
expect(response).toBeInstanceOf(Promise);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("the functions call the clients component_server function with the correct arguments ", async () => {
|
||||||
|
const mock = spy(async (id: number, fn: string, args: any) => {
|
||||||
|
return args;
|
||||||
|
});
|
||||||
|
const app = {
|
||||||
|
component_server: mock as any
|
||||||
|
} as client_return;
|
||||||
|
|
||||||
|
const result = process_server_fn(1, ["fn1", "fn2"], app as client_return);
|
||||||
|
const response = await result.fn1("hello");
|
||||||
|
expect(response).toBe("hello");
|
||||||
|
expect(mock.calls).toEqual([[1, "fn1", "hello"]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if there are no server functions, it returns an empty object", () => {
|
||||||
|
const result = process_server_fn(1, undefined, {} as any);
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("get_component", () => {
|
||||||
|
test("returns an object", () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
expect(result.component).toBeTypeOf("object");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns an object with the correct keys", () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
expect(Object.keys(result)).toEqual([
|
||||||
|
"component",
|
||||||
|
"name",
|
||||||
|
"example_components"
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("the component key is a promise", () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
expect(result.component).toBeInstanceOf(Promise);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("the resolved component key is an object", async () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
const o = await result.component;
|
||||||
|
|
||||||
|
expect(o).toBeTypeOf("object");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getting the same component twice should return the same promise", () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
const result_two = get_component(
|
||||||
|
"test-component-one",
|
||||||
|
"class_id",
|
||||||
|
"root",
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.component).toBe(result_two.component);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if example components are not provided, the example_components key is undefined", async () => {
|
||||||
|
const result = get_component("dataset", "class_id", "root", []);
|
||||||
|
expect(result.example_components).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the type is not a dataset, the example_components key is undefined", async () => {
|
||||||
|
const result = get_component("test-component-one", "class_id", "root", []);
|
||||||
|
expect(result.example_components).toBe(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("when the type is a dataset, returns an object with the correct keys and values and example components", () => {
|
||||||
|
const result = get_component(
|
||||||
|
"dataset",
|
||||||
|
"class_id",
|
||||||
|
"root",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "test-component-one",
|
||||||
|
component_class_id: "example_class_id",
|
||||||
|
id: 1,
|
||||||
|
props: {
|
||||||
|
value: "hi",
|
||||||
|
interactive: false
|
||||||
|
},
|
||||||
|
has_modes: false,
|
||||||
|
instance: {} as any,
|
||||||
|
component: {} as any
|
||||||
|
}
|
||||||
|
],
|
||||||
|
["test-component-one"]
|
||||||
|
);
|
||||||
|
expect(result.component).toBeTypeOf("object");
|
||||||
|
expect(result.example_components).toBeInstanceOf(Map);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("when example components are returned, returns an object with the correct keys and values and example components", () => {
|
||||||
|
const result = get_component(
|
||||||
|
"dataset",
|
||||||
|
"class_id",
|
||||||
|
"root",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: "test-component-one",
|
||||||
|
component_class_id: "example_class_id",
|
||||||
|
id: 1,
|
||||||
|
props: {
|
||||||
|
value: "hi",
|
||||||
|
interactive: false
|
||||||
|
},
|
||||||
|
has_modes: false,
|
||||||
|
instance: {} as any,
|
||||||
|
component: {} as any
|
||||||
|
}
|
||||||
|
],
|
||||||
|
["test-component-one"]
|
||||||
|
);
|
||||||
|
expect(result.example_components?.get("test-component-one")).toBeTypeOf(
|
||||||
|
"object"
|
||||||
|
);
|
||||||
|
expect(result.example_components?.get("test-component-one")).toBeInstanceOf(
|
||||||
|
Promise
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("if the component is not found then it should request the component from the server", async () => {
|
||||||
|
const api_url = "example.com";
|
||||||
|
const id = "test-random";
|
||||||
|
const variant = "component";
|
||||||
|
const handlers = [
|
||||||
|
http.get(`${api_url}/custom_component/${id}/${variant}/style.css`, () => {
|
||||||
|
return new HttpResponse('console.log("boo")', {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "text/css"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
// vi.mock calls are always hoisted out of the test function to the top of the file
|
||||||
|
// so we need to use vi.hoisted to hoist the mock function above the vi.mock call
|
||||||
|
const { mock } = vi.hoisted(() => {
|
||||||
|
return { mock: vi.fn() };
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock(
|
||||||
|
`example.com/custom_component/test-random/component/index.js`,
|
||||||
|
async () => {
|
||||||
|
mock();
|
||||||
|
return {
|
||||||
|
default: {
|
||||||
|
default: "HELLO"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const server = setupServer(...handlers);
|
||||||
|
server.listen();
|
||||||
|
|
||||||
|
await get_component("test-random", id, api_url, []).component;
|
||||||
|
|
||||||
|
expect(mock).toHaveBeenCalled();
|
||||||
|
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
});
|
438
js/app/src/init.ts
Normal file
438
js/app/src/init.ts
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import type {
|
||||||
|
ComponentMeta,
|
||||||
|
Dependency,
|
||||||
|
LayoutNode,
|
||||||
|
TargetMap,
|
||||||
|
LoadingComponent
|
||||||
|
} from "./types";
|
||||||
|
import { load_component } from "virtual:component-loader";
|
||||||
|
import type { client_return } from "@gradio/client";
|
||||||
|
import { create_loading_status_store } from "./stores";
|
||||||
|
|
||||||
|
export interface UpdateTransaction {
|
||||||
|
id: number;
|
||||||
|
value: any;
|
||||||
|
prop: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pending_updates: UpdateTransaction[][] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a store with the layout and a map of targets
|
||||||
|
* @param components An array of component metadata
|
||||||
|
* @param layout The layout tree
|
||||||
|
* @param dependencies The events, triggers, inputs, and outputs
|
||||||
|
* @param root The root url of the app
|
||||||
|
* @param app The client instance
|
||||||
|
* @param options Options for the layout
|
||||||
|
* @returns A store with the layout and a map of targets
|
||||||
|
*/
|
||||||
|
export function create_components(
|
||||||
|
components: ComponentMeta[],
|
||||||
|
layout: LayoutNode,
|
||||||
|
dependencies: Dependency[],
|
||||||
|
root: string,
|
||||||
|
app: client_return,
|
||||||
|
options: {
|
||||||
|
fill_height: boolean;
|
||||||
|
}
|
||||||
|
): {
|
||||||
|
layout: Writable<ComponentMeta>;
|
||||||
|
targets: TargetMap;
|
||||||
|
update_value: (updates: UpdateTransaction[]) => void;
|
||||||
|
get_data: (id: number) => any | Promise<any>;
|
||||||
|
loading_status: ReturnType<typeof create_loading_status_store>;
|
||||||
|
scheduled_updates: Writable<boolean>;
|
||||||
|
} {
|
||||||
|
const _component_map = new Map();
|
||||||
|
|
||||||
|
const target_map: TargetMap = {};
|
||||||
|
const inputs = new Set<number>();
|
||||||
|
const outputs = new Set<number>();
|
||||||
|
|
||||||
|
const _rootNode: ComponentMeta = {
|
||||||
|
id: layout.id,
|
||||||
|
type: "column",
|
||||||
|
props: { interactive: false, scale: options.fill_height ? 1 : null },
|
||||||
|
has_modes: false,
|
||||||
|
instance: null as unknown as ComponentMeta["instance"],
|
||||||
|
component: null as unknown as ComponentMeta["component"],
|
||||||
|
component_class_id: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
components.push(_rootNode);
|
||||||
|
const loading_status = create_loading_status_store();
|
||||||
|
|
||||||
|
dependencies.forEach((dep, fn_index) => {
|
||||||
|
loading_status.register(fn_index, dep.inputs, dep.outputs);
|
||||||
|
dep.frontend_fn = process_frontend_fn(
|
||||||
|
dep.js,
|
||||||
|
!!dep.backend_fn,
|
||||||
|
dep.inputs.length,
|
||||||
|
dep.outputs.length
|
||||||
|
);
|
||||||
|
create_target_meta(dep.targets, fn_index, target_map);
|
||||||
|
get_inputs_outputs(dep, inputs, outputs);
|
||||||
|
});
|
||||||
|
|
||||||
|
const constructor_map = preload_all_components(components, root);
|
||||||
|
|
||||||
|
let instance_map: { [id: number]: ComponentMeta } = components.reduce(
|
||||||
|
(acc, c) => {
|
||||||
|
acc[c.id] = c;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as { [id: number]: ComponentMeta }
|
||||||
|
);
|
||||||
|
|
||||||
|
async function walk_layout(node: LayoutNode): Promise<ComponentMeta> {
|
||||||
|
const instance = instance_map[node.id];
|
||||||
|
|
||||||
|
instance.component = (await constructor_map.get(
|
||||||
|
instance.component_class_id
|
||||||
|
))!?.default;
|
||||||
|
|
||||||
|
if (instance.type === "dataset") {
|
||||||
|
instance.props.component_map = get_component(
|
||||||
|
instance.type,
|
||||||
|
instance.component_class_id,
|
||||||
|
root,
|
||||||
|
components,
|
||||||
|
instance.props.components
|
||||||
|
).example_components;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_map[instance.id]) {
|
||||||
|
instance.props.attached_events = Object.keys(target_map[instance.id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.props.interactive = determine_interactivity(
|
||||||
|
instance.id,
|
||||||
|
instance.props.interactive,
|
||||||
|
instance.props.value,
|
||||||
|
inputs,
|
||||||
|
outputs
|
||||||
|
);
|
||||||
|
|
||||||
|
instance.props.server = process_server_fn(
|
||||||
|
instance.id,
|
||||||
|
instance.props.server_fns,
|
||||||
|
app
|
||||||
|
);
|
||||||
|
|
||||||
|
_component_map.set(instance.id, instance);
|
||||||
|
|
||||||
|
if (node.children) {
|
||||||
|
instance.children = await Promise.all(
|
||||||
|
node.children.map((v) => walk_layout(v))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
const layout_store: Writable<ComponentMeta> = writable();
|
||||||
|
walk_layout(layout).then(() => {
|
||||||
|
layout_store.set(_rootNode);
|
||||||
|
});
|
||||||
|
|
||||||
|
let update_scheduled = false;
|
||||||
|
let update_scheduled_store = writable(false);
|
||||||
|
|
||||||
|
function flush(): void {
|
||||||
|
layout_store.update((layout) => {
|
||||||
|
for (let i = 0; i < pending_updates.length; i++) {
|
||||||
|
for (let j = 0; j < pending_updates[i].length; j++) {
|
||||||
|
const update = pending_updates[i][j];
|
||||||
|
const instance = instance_map[update.id];
|
||||||
|
let new_value;
|
||||||
|
if (Array.isArray(update.value)) new_value = [...update.value];
|
||||||
|
else if (update.value === null) new_value = null;
|
||||||
|
else if (typeof update.value === "object")
|
||||||
|
new_value = { ...update.value };
|
||||||
|
else new_value = update.value;
|
||||||
|
instance.props[update.prop] = new_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return layout;
|
||||||
|
});
|
||||||
|
|
||||||
|
pending_updates = [];
|
||||||
|
update_scheduled = false;
|
||||||
|
update_scheduled_store.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_value(updates: UpdateTransaction[]): void {
|
||||||
|
pending_updates.push(updates);
|
||||||
|
|
||||||
|
if (!update_scheduled) {
|
||||||
|
update_scheduled = true;
|
||||||
|
update_scheduled_store.set(true);
|
||||||
|
requestAnimationFrame(flush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_data(id: number): any | Promise<any> {
|
||||||
|
const comp = _component_map.get(id);
|
||||||
|
if (comp.instance.get_value) {
|
||||||
|
return comp.instance.get_value() as Promise<any>;
|
||||||
|
}
|
||||||
|
return comp.props.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
layout: layout_store,
|
||||||
|
targets: target_map,
|
||||||
|
update_value,
|
||||||
|
get_data,
|
||||||
|
loading_status,
|
||||||
|
scheduled_updates: update_scheduled_store
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An async version of 'new Function' */
|
||||||
|
export const AsyncFunction: new (
|
||||||
|
...args: string[]
|
||||||
|
) => (...args: any[]) => Promise<any> = Object.getPrototypeOf(
|
||||||
|
async function () {}
|
||||||
|
).constructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a string of source code and returns a function that can be called with arguments
|
||||||
|
* @param source the source code
|
||||||
|
* @param backend_fn if there is also a backend function
|
||||||
|
* @param input_length the number of inputs
|
||||||
|
* @param output_length the number of outputs
|
||||||
|
* @returns The function, or null if the source code is invalid or missing
|
||||||
|
*/
|
||||||
|
export function process_frontend_fn(
|
||||||
|
source: string | null | undefined | false,
|
||||||
|
backend_fn: boolean,
|
||||||
|
input_length: number,
|
||||||
|
output_length: number
|
||||||
|
): ((...args: unknown[]) => Promise<unknown[]>) | null {
|
||||||
|
if (!source) return null;
|
||||||
|
|
||||||
|
const wrap = backend_fn ? input_length === 1 : output_length === 1;
|
||||||
|
try {
|
||||||
|
return new AsyncFunction(
|
||||||
|
"__fn_args",
|
||||||
|
` let result = await (${source})(...__fn_args);
|
||||||
|
return (${wrap} && !Array.isArray(result)) ? [result] : result;`
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not parse custom js method.");
|
||||||
|
console.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Dependency.targets` is an array of `[id, trigger]` pairs with the indices as the `fn_index`.
|
||||||
|
* This function take a single list of `Dependency.targets` and add those to the target_map.
|
||||||
|
* @param targets the targets array
|
||||||
|
* @param fn_index the function index
|
||||||
|
* @param target_map the target map
|
||||||
|
* @returns the tagert map
|
||||||
|
*/
|
||||||
|
export function create_target_meta(
|
||||||
|
targets: Dependency["targets"],
|
||||||
|
fn_index: number,
|
||||||
|
target_map: TargetMap
|
||||||
|
): TargetMap {
|
||||||
|
targets.forEach(([id, trigger]) => {
|
||||||
|
if (!target_map[id]) {
|
||||||
|
target_map[id] = {};
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
target_map[id]?.[trigger] &&
|
||||||
|
!target_map[id]?.[trigger].includes(fn_index)
|
||||||
|
) {
|
||||||
|
target_map[id][trigger].push(fn_index);
|
||||||
|
} else {
|
||||||
|
target_map[id][trigger] = [fn_index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return target_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all component ids that are an input or output of a dependency
|
||||||
|
* @param dep the dependency
|
||||||
|
* @param inputs the set of inputs
|
||||||
|
* @param outputs the set of outputs
|
||||||
|
* @returns a tuple of the inputs and outputs
|
||||||
|
*/
|
||||||
|
export function get_inputs_outputs(
|
||||||
|
dep: Dependency,
|
||||||
|
inputs: Set<number>,
|
||||||
|
outputs: Set<number>
|
||||||
|
): [Set<number>, Set<number>] {
|
||||||
|
dep.inputs.forEach((input) => inputs.add(input));
|
||||||
|
dep.outputs.forEach((output) => outputs.add(output));
|
||||||
|
return [inputs, outputs];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is not a default value
|
||||||
|
* @param value the value to check
|
||||||
|
* @returns default value boolean
|
||||||
|
*/
|
||||||
|
function has_no_default_value(value: any): boolean {
|
||||||
|
return (
|
||||||
|
(Array.isArray(value) && value.length === 0) ||
|
||||||
|
value === "" ||
|
||||||
|
value === 0 ||
|
||||||
|
!value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a component is interactive
|
||||||
|
* @param id component id
|
||||||
|
* @param interactive_prop value of the interactive prop
|
||||||
|
* @param value the main value of the component
|
||||||
|
* @param inputs set of ids that are inputs to a dependency
|
||||||
|
* @param outputs set of ids that are outputs to a dependency
|
||||||
|
* @returns if the component is interactive
|
||||||
|
*/
|
||||||
|
export function determine_interactivity(
|
||||||
|
id: number,
|
||||||
|
interactive_prop: boolean | undefined,
|
||||||
|
value: any,
|
||||||
|
inputs: Set<number>,
|
||||||
|
outputs: Set<number>
|
||||||
|
): boolean {
|
||||||
|
if (interactive_prop === false) {
|
||||||
|
return false;
|
||||||
|
} else if (interactive_prop === true) {
|
||||||
|
return true;
|
||||||
|
} else if (
|
||||||
|
inputs.has(id) ||
|
||||||
|
(!outputs.has(id) && has_no_default_value(value))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerFunctions = Record<string, (...args: any[]) => Promise<any>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the server function names and return a dictionary of functions
|
||||||
|
* @param id the component id
|
||||||
|
* @param server_fns the server function names
|
||||||
|
* @param app the client instance
|
||||||
|
* @returns the actual server functions
|
||||||
|
*/
|
||||||
|
export function process_server_fn(
|
||||||
|
id: number,
|
||||||
|
server_fns: string[] | undefined,
|
||||||
|
app: client_return
|
||||||
|
): ServerFunctions {
|
||||||
|
if (!server_fns) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return server_fns.reduce((acc, fn: string) => {
|
||||||
|
acc[fn] = async (...args: any[]) => {
|
||||||
|
if (args.length === 1) {
|
||||||
|
args = args[0];
|
||||||
|
}
|
||||||
|
const result = await app.component_server(id, fn, args);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
}, {} as ServerFunctions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a component from the backend
|
||||||
|
* @param type the type of the component
|
||||||
|
* @param class_id the class id of the component
|
||||||
|
* @param root the root url of the app
|
||||||
|
* @param components the list of component metadata
|
||||||
|
* @param example_components the list of example components
|
||||||
|
* @returns the component and its name
|
||||||
|
*/
|
||||||
|
export function get_component(
|
||||||
|
type: string,
|
||||||
|
class_id: string,
|
||||||
|
root: string,
|
||||||
|
components: ComponentMeta[],
|
||||||
|
example_components?: string[]
|
||||||
|
): {
|
||||||
|
component: LoadingComponent;
|
||||||
|
name: ComponentMeta["type"];
|
||||||
|
example_components?: Map<ComponentMeta["type"], LoadingComponent>;
|
||||||
|
} {
|
||||||
|
let example_component_map: Map<ComponentMeta["type"], LoadingComponent> =
|
||||||
|
new Map();
|
||||||
|
if (type === "dataset" && example_components) {
|
||||||
|
(example_components as string[]).forEach((name: string) => {
|
||||||
|
if (example_component_map.has(name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let _c;
|
||||||
|
|
||||||
|
const matching_component = components.find((c) => c.type === name);
|
||||||
|
if (matching_component) {
|
||||||
|
_c = load_component({
|
||||||
|
api_url: root,
|
||||||
|
name,
|
||||||
|
id: matching_component.component_class_id,
|
||||||
|
variant: "example"
|
||||||
|
});
|
||||||
|
example_component_map.set(name, _c.component);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const _c = load_component({
|
||||||
|
api_url: root,
|
||||||
|
name: type,
|
||||||
|
id: class_id,
|
||||||
|
variant: "component"
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
component: _c.component,
|
||||||
|
name: _c.name,
|
||||||
|
example_components:
|
||||||
|
example_component_map.size > 0 ? example_component_map : undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preload all components
|
||||||
|
* @param components A list of component metadata
|
||||||
|
* @param root The root url of the app
|
||||||
|
* @returns A map of component ids to their constructors
|
||||||
|
*/
|
||||||
|
export function preload_all_components(
|
||||||
|
components: ComponentMeta[],
|
||||||
|
root: string
|
||||||
|
): Map<ComponentMeta["type"], LoadingComponent> {
|
||||||
|
let constructor_map: Map<ComponentMeta["type"], LoadingComponent> = new Map();
|
||||||
|
|
||||||
|
components.forEach((c) => {
|
||||||
|
const { component, example_components } = get_component(
|
||||||
|
c.type,
|
||||||
|
c.component_class_id,
|
||||||
|
root,
|
||||||
|
components
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor_map.set(c.component_class_id, component);
|
||||||
|
|
||||||
|
if (example_components) {
|
||||||
|
for (const [name, example_component] of example_components) {
|
||||||
|
constructor_map.set(name, example_component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return constructor_map;
|
||||||
|
}
|
@ -1,17 +1,25 @@
|
|||||||
import type { ComponentType } from "svelte";
|
import type { ComponentType } from "svelte";
|
||||||
import type { SvelteComponent } from "svelte";
|
import type { SvelteComponent } from "svelte";
|
||||||
|
|
||||||
interface ComponentImport {
|
/** The props that are always present on a component */
|
||||||
interactive: SvelteComponent;
|
interface SharedProps {
|
||||||
static: SvelteComponent;
|
elem_id?: string;
|
||||||
example: SvelteComponent;
|
elem_classes?: string[];
|
||||||
|
components?: string[];
|
||||||
|
server_fns?: string[];
|
||||||
|
interactive: boolean;
|
||||||
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The metadata for a component
|
||||||
|
* The non optional fields are what are received from the backend
|
||||||
|
* The optional fields are what are added by the frontend
|
||||||
|
*/
|
||||||
export interface ComponentMeta {
|
export interface ComponentMeta {
|
||||||
type: string;
|
type: string;
|
||||||
id: number;
|
id: number;
|
||||||
has_modes: boolean;
|
has_modes: boolean;
|
||||||
props: Record<string, unknown> & { interactive: boolean };
|
props: SharedProps;
|
||||||
instance: SvelteComponent;
|
instance: SvelteComponent;
|
||||||
component: ComponentType<SvelteComponent>;
|
component: ComponentType<SvelteComponent>;
|
||||||
documentation?: Documentation;
|
documentation?: Documentation;
|
||||||
@ -20,11 +28,13 @@ export interface ComponentMeta {
|
|||||||
component_class_id: string;
|
component_class_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Dictates whether a dependency is continous and/or a generator */
|
||||||
export interface DependencyTypes {
|
export interface DependencyTypes {
|
||||||
continuous: boolean;
|
continuous: boolean;
|
||||||
generator: boolean;
|
generator: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An event payload that is sent with an API request */
|
||||||
export interface Payload {
|
export interface Payload {
|
||||||
fn_index: number;
|
fn_index: number;
|
||||||
data: unknown[];
|
data: unknown[];
|
||||||
@ -32,6 +42,7 @@ export interface Payload {
|
|||||||
trigger_id: number | null;
|
trigger_id: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A dependency as received from the backend */
|
||||||
export interface Dependency {
|
export interface Dependency {
|
||||||
targets: [number, string][];
|
targets: [number, string][];
|
||||||
inputs: number[];
|
inputs: number[];
|
||||||
@ -40,7 +51,7 @@ export interface Dependency {
|
|||||||
js: string | null;
|
js: string | null;
|
||||||
scroll_to_output: boolean;
|
scroll_to_output: boolean;
|
||||||
show_progress: "full" | "minimal" | "hidden";
|
show_progress: "full" | "minimal" | "hidden";
|
||||||
frontend_fn?: (...args: unknown[]) => Promise<unknown[]>;
|
frontend_fn: ((...args: unknown[]) => Promise<unknown[]>) | null;
|
||||||
status?: string;
|
status?: string;
|
||||||
queue: boolean | null;
|
queue: boolean | null;
|
||||||
api_name: string | null;
|
api_name: string | null;
|
||||||
@ -67,9 +78,24 @@ export interface Documentation {
|
|||||||
example_data?: string;
|
example_data?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A layout node as recived from the backend */
|
||||||
export interface LayoutNode {
|
export interface LayoutNode {
|
||||||
id: number;
|
id: number;
|
||||||
children: LayoutNode[];
|
children: LayoutNode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The system theme mode */
|
||||||
export type ThemeMode = "system" | "light" | "dark";
|
export type ThemeMode = "system" | "light" | "dark";
|
||||||
|
|
||||||
|
/** the target map is an object mapping the target id to a series of events (another object), those events are a mapping of the event name to the function id's they trigger */
|
||||||
|
export type TargetMap = Record<number, Record<string, number[]>>;
|
||||||
|
|
||||||
|
/** A component that has been loaded via dynamic import */
|
||||||
|
export type LoadedComponent = {
|
||||||
|
default: ComponentMeta["component"];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**A component that is loading */
|
||||||
|
export type LoadingComponent = Promise<{
|
||||||
|
default: ComponentMeta["component"];
|
||||||
|
}>;
|
||||||
|
4
js/app/src/vite-env-override.d.ts
vendored
4
js/app/src/vite-env-override.d.ts
vendored
@ -13,8 +13,8 @@ declare module "virtual:component-loader" {
|
|||||||
id: string;
|
id: string;
|
||||||
variant: "component" | "example";
|
variant: "component" | "example";
|
||||||
}
|
}
|
||||||
export function load_component(args: Args): Promise<{
|
export function load_component(args: Args): {
|
||||||
name: ComponentMeta["type"];
|
name: ComponentMeta["type"];
|
||||||
component: LoadedComponent;
|
component: LoadedComponent;
|
||||||
}>;
|
};
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ test("chatinterface works with streaming functions and all buttons behave as exp
|
|||||||
const expected_text_el_2 = page.locator(".bot p", {
|
const expected_text_el_2 = page.locator(".bot p", {
|
||||||
hasText: "Run 3 - You typed: hello"
|
hasText: "Run 3 - You typed: hello"
|
||||||
});
|
});
|
||||||
expect(textbox).toHaveValue("");
|
|
||||||
await expect(expected_text_el_2).toBeVisible();
|
await expect(expected_text_el_2).toBeVisible();
|
||||||
|
|
||||||
await expect
|
await expect
|
||||||
|
@ -32,7 +32,8 @@ import {
|
|||||||
generate_dev_entry,
|
generate_dev_entry,
|
||||||
handle_ce_css,
|
handle_ce_css,
|
||||||
inject_component_loader,
|
inject_component_loader,
|
||||||
resolve_svelte
|
resolve_svelte,
|
||||||
|
mock_modules
|
||||||
} from "./build_plugins";
|
} from "./build_plugins";
|
||||||
|
|
||||||
const GRADIO_VERSION = version_raw || "asd_stub_asd";
|
const GRADIO_VERSION = version_raw || "asd_stub_asd";
|
||||||
@ -41,7 +42,6 @@ const TEST_MODE = process.env.TEST_MODE || "happy-dom";
|
|||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
console.log(mode);
|
|
||||||
const targets = {
|
const targets = {
|
||||||
production: "../../gradio/templates/frontend",
|
production: "../../gradio/templates/frontend",
|
||||||
"dev:custom": "../../gradio/templates/frontend"
|
"dev:custom": "../../gradio/templates/frontend"
|
||||||
@ -161,7 +161,8 @@ export default defineConfig(({ mode }) => {
|
|||||||
inject_ejs(),
|
inject_ejs(),
|
||||||
generate_cdn_entry({ version: GRADIO_VERSION, cdn_base: CDN_BASE }),
|
generate_cdn_entry({ version: GRADIO_VERSION, cdn_base: CDN_BASE }),
|
||||||
handle_ce_css(),
|
handle_ce_css(),
|
||||||
inject_component_loader()
|
inject_component_loader({ mode }),
|
||||||
|
mode === "test" && mock_modules()
|
||||||
],
|
],
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ["@ffmpeg/ffmpeg", "@ffmpeg/util"]
|
exclude: ["@ffmpeg/ffmpeg", "@ffmpeg/util"]
|
||||||
@ -179,6 +180,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
if (log.includes("was created with unknown prop")) return false;
|
if (log.includes("was created with unknown prop")) return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
// For the Wasm app to import the wheel file URLs.
|
// For the Wasm app to import the wheel file URLs.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { afterUpdate } from "svelte";
|
import { afterUpdate, tick } from "svelte";
|
||||||
import type { Gradio, SelectData } from "@gradio/utils";
|
import type { Gradio, SelectData } from "@gradio/utils";
|
||||||
import { Block } from "@gradio/atoms";
|
import { Block } from "@gradio/atoms";
|
||||||
import Table from "./shared/Table.svelte";
|
import Table from "./shared/Table.svelte";
|
||||||
@ -20,7 +20,7 @@
|
|||||||
headers: ["1", "2", "3"],
|
headers: ["1", "2", "3"],
|
||||||
metadata: null
|
metadata: null
|
||||||
};
|
};
|
||||||
let old_value: string = JSON.stringify(value);
|
let old_value = "";
|
||||||
export let value_is_output = false;
|
export let value_is_output = false;
|
||||||
export let col_count: [number, "fixed" | "dynamic"];
|
export let col_count: [number, "fixed" | "dynamic"];
|
||||||
export let row_count: [number, "fixed" | "dynamic"];
|
export let row_count: [number, "fixed" | "dynamic"];
|
||||||
@ -49,21 +49,44 @@
|
|||||||
export let loading_status: LoadingStatus;
|
export let loading_status: LoadingStatus;
|
||||||
export let interactive: boolean;
|
export let interactive: boolean;
|
||||||
|
|
||||||
function handle_change(): void {
|
let _headers: Headers;
|
||||||
|
let display_value: string[][] | null;
|
||||||
|
let styling: string[][] | null;
|
||||||
|
let values: (string | number)[][];
|
||||||
|
async function handle_change(data?: {
|
||||||
|
data: Data;
|
||||||
|
headers: Headers;
|
||||||
|
metadata: Metadata;
|
||||||
|
}): Promise<void> {
|
||||||
|
let _data = data || value;
|
||||||
|
|
||||||
|
_headers = [...(_data.headers || headers)];
|
||||||
|
values = _data.data ? [..._data.data] : [];
|
||||||
|
display_value = _data?.metadata?.display_value
|
||||||
|
? [..._data?.metadata?.display_value]
|
||||||
|
: null;
|
||||||
|
styling = _data?.metadata?.styling ? [..._data?.metadata?.styling] : null;
|
||||||
|
await tick();
|
||||||
|
|
||||||
gradio.dispatch("change");
|
gradio.dispatch("change");
|
||||||
if (!value_is_output) {
|
if (!value_is_output) {
|
||||||
gradio.dispatch("input");
|
gradio.dispatch("input");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle_change();
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
value_is_output = false;
|
value_is_output = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (JSON.stringify(value) !== old_value) {
|
if (old_value && JSON.stringify(value) !== old_value) {
|
||||||
old_value = JSON.stringify(value);
|
old_value = JSON.stringify(value);
|
||||||
handle_change();
|
handle_change();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(Array.isArray(value) && value?.[0]?.length === 0) ||
|
(Array.isArray(value) && value?.[0]?.length === 0) ||
|
||||||
value.data?.[0]?.length === 0
|
value.data?.[0]?.length === 0
|
||||||
@ -76,6 +99,18 @@
|
|||||||
metadata: null
|
metadata: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handle_value_change(data: {
|
||||||
|
data: Data;
|
||||||
|
headers: Headers;
|
||||||
|
metadata: Metadata;
|
||||||
|
}): Promise<void> {
|
||||||
|
if (JSON.stringify(data) !== old_value) {
|
||||||
|
value = { ...data };
|
||||||
|
old_value = JSON.stringify(value);
|
||||||
|
handle_change(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Block
|
<Block
|
||||||
@ -99,9 +134,11 @@
|
|||||||
{show_label}
|
{show_label}
|
||||||
{row_count}
|
{row_count}
|
||||||
{col_count}
|
{col_count}
|
||||||
{value}
|
{values}
|
||||||
{headers}
|
{display_value}
|
||||||
on:change={interactive ? (e) => (value = e.detail) : () => {}}
|
{styling}
|
||||||
|
headers={_headers}
|
||||||
|
on:change={(e) => handle_value_change(e.detail)}
|
||||||
on:select={(e) => gradio.dispatch("select", e.detail)}
|
on:select={(e) => gradio.dispatch("select", e.detail)}
|
||||||
{wrap}
|
{wrap}
|
||||||
{datatype}
|
{datatype}
|
||||||
|
@ -21,8 +21,7 @@
|
|||||||
export let label: string | null = null;
|
export let label: string | null = null;
|
||||||
export let show_label = true;
|
export let show_label = true;
|
||||||
export let headers: Headers = [];
|
export let headers: Headers = [];
|
||||||
let values: (string | number)[][];
|
export let values: (string | number)[][] = [];
|
||||||
export let value: { data: Data; headers: Headers; metadata: Metadata } | null;
|
|
||||||
export let col_count: [number, "fixed" | "dynamic"];
|
export let col_count: [number, "fixed" | "dynamic"];
|
||||||
export let row_count: [number, "fixed" | "dynamic"];
|
export let row_count: [number, "fixed" | "dynamic"];
|
||||||
export let latex_delimiters: {
|
export let latex_delimiters: {
|
||||||
@ -41,21 +40,10 @@
|
|||||||
export let column_widths: string[] = [];
|
export let column_widths: string[] = [];
|
||||||
|
|
||||||
let selected: false | [number, number] = false;
|
let selected: false | [number, number] = false;
|
||||||
let display_value: string[][] | null = value?.metadata?.display_value ?? null;
|
export let display_value: string[][] | null = null;
|
||||||
let styling: string[][] | null = value?.metadata?.styling ?? null;
|
export let styling: string[][] | null = null;
|
||||||
let t_rect: DOMRectReadOnly;
|
let t_rect: DOMRectReadOnly;
|
||||||
|
|
||||||
$: {
|
|
||||||
if (value) {
|
|
||||||
headers = value.headers;
|
|
||||||
values = value.data;
|
|
||||||
display_value = value?.metadata?.display_value ?? null;
|
|
||||||
styling = value?.metadata?.styling ?? null;
|
|
||||||
} else if (values === null) {
|
|
||||||
values = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
change: {
|
change: {
|
||||||
data: (string | number)[][];
|
data: (string | number)[][];
|
||||||
@ -69,6 +57,7 @@
|
|||||||
|
|
||||||
const get_data_at = (row: number, col: number): string | number =>
|
const get_data_at = (row: number, col: number): string | number =>
|
||||||
data?.[row]?.[col]?.value;
|
data?.[row]?.[col]?.value;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (selected !== false) {
|
if (selected !== false) {
|
||||||
const [row, col] = selected;
|
const [row, col] = selected;
|
||||||
@ -77,6 +66,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let els: Record<
|
let els: Record<
|
||||||
string,
|
string,
|
||||||
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
|
{ cell: null | HTMLTableCellElement; input: null | HTMLInputElement }
|
||||||
@ -87,6 +77,7 @@
|
|||||||
function make_id(): string {
|
function make_id(): string {
|
||||||
return Math.random().toString(36).substring(2, 15);
|
return Math.random().toString(36).substring(2, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_headers(_head: Headers): HeadersWithIDs {
|
function make_headers(_head: Headers): HeadersWithIDs {
|
||||||
let _h = _head || [];
|
let _h = _head || [];
|
||||||
if (col_count[1] === "fixed" && _h.length < col_count[0]) {
|
if (col_count[1] === "fixed" && _h.length < col_count[0]) {
|
||||||
@ -105,6 +96,7 @@
|
|||||||
return { id: _id, value: JSON.stringify(i + 1) };
|
return { id: _id, value: JSON.stringify(i + 1) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return _h.map((h, i) => {
|
return _h.map((h, i) => {
|
||||||
const _id = make_id();
|
const _id = make_id();
|
||||||
els[_id] = { cell: null, input: null };
|
els[_id] = { cell: null, input: null };
|
||||||
@ -157,7 +149,9 @@
|
|||||||
_headers = make_headers(headers);
|
_headers = make_headers(headers);
|
||||||
|
|
||||||
old_headers = headers.slice();
|
old_headers = headers.slice();
|
||||||
|
trigger_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if (!dequal(values, old_val)) {
|
$: if (!dequal(values, old_val)) {
|
||||||
data = process_data(values as (string | number)[][]);
|
data = process_data(values as (string | number)[][]);
|
||||||
old_val = values as (string | number)[][];
|
old_val = values as (string | number)[][];
|
||||||
@ -167,7 +161,7 @@
|
|||||||
|
|
||||||
let old_val: undefined | (string | number)[][] = undefined;
|
let old_val: undefined | (string | number)[][] = undefined;
|
||||||
|
|
||||||
$: _headers &&
|
async function trigger_change(): Promise<void> {
|
||||||
dispatch("change", {
|
dispatch("change", {
|
||||||
data: data.map((r) => r.map(({ value }) => value)),
|
data: data.map((r) => r.map(({ value }) => value)),
|
||||||
headers: _headers.map((h) => h.value),
|
headers: _headers.map((h) => h.value),
|
||||||
@ -175,6 +169,7 @@
|
|||||||
? null
|
? null
|
||||||
: { display_value: display_value, styling: styling }
|
: { display_value: display_value, styling: styling }
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function get_sort_status(
|
function get_sort_status(
|
||||||
name: string,
|
name: string,
|
||||||
@ -425,6 +420,8 @@
|
|||||||
selected = [index ? index + 1 : data.length - 1, 0];
|
selected = [index ? index + 1 : data.length - 1, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: data && trigger_change();
|
||||||
|
|
||||||
async function add_col(): Promise<void> {
|
async function add_col(): Promise<void> {
|
||||||
parent.focus();
|
parent.focus();
|
||||||
if (col_count[1] !== "dynamic") return;
|
if (col_count[1] !== "dynamic") return;
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
export let component_map: Map<
|
export let component_map: Map<
|
||||||
string,
|
string,
|
||||||
Promise<{
|
Promise<{
|
||||||
name: string;
|
default: ComponentType<SvelteComponent>;
|
||||||
component: { default: ComponentType<SvelteComponent> };
|
|
||||||
}>
|
}>
|
||||||
>;
|
>;
|
||||||
export let label = "Examples";
|
export let label = "Examples";
|
||||||
@ -46,6 +45,7 @@
|
|||||||
function handle_mouseenter(i: number): void {
|
function handle_mouseenter(i: number): void {
|
||||||
current_hover = i;
|
current_hover = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_mouseleave(): void {
|
function handle_mouseleave(): void {
|
||||||
current_hover = -1;
|
current_hover = -1;
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@
|
|||||||
sample_row.map(async (sample_cell, j) => {
|
sample_row.map(async (sample_cell, j) => {
|
||||||
return {
|
return {
|
||||||
value: sample_cell,
|
value: sample_cell,
|
||||||
component: (await component_map.get(components[j]))?.component
|
component: (await component_map.get(components[j]))
|
||||||
?.default as ComponentType<SvelteComponent>
|
?.default as ComponentType<SvelteComponent>
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
@ -57,10 +57,10 @@
|
|||||||
"eslint": "^8.46.0",
|
"eslint": "^8.46.0",
|
||||||
"eslint-plugin-svelte": "^2.32.4",
|
"eslint-plugin-svelte": "^2.32.4",
|
||||||
"globals": "^14.0.0",
|
"globals": "^14.0.0",
|
||||||
"happy-dom": "^13.3.8",
|
"happy-dom": "^13.6.2",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"kleur": "^4.1.5",
|
"kleur": "^4.1.5",
|
||||||
"msw": "^2.0.0",
|
"msw": "^2.2.1",
|
||||||
"node-html-parser": "^6.0.0",
|
"node-html-parser": "^6.0.0",
|
||||||
"npm-run-all2": "^6.0.0",
|
"npm-run-all2": "^6.0.0",
|
||||||
"playwright": "^1.39.0",
|
"playwright": "^1.39.0",
|
||||||
@ -86,7 +86,7 @@
|
|||||||
"typescript-svelte-plugin": "^0.3.34",
|
"typescript-svelte-plugin": "^0.3.34",
|
||||||
"vite": "^4.3.9",
|
"vite": "^4.3.9",
|
||||||
"vite-plugin-turbosnap": "1.0.3",
|
"vite-plugin-turbosnap": "1.0.3",
|
||||||
"vitest": "^1.2.2"
|
"vitest": "^1.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/addon-a11y": "^7.5.1",
|
"@storybook/addon-a11y": "^7.5.1",
|
||||||
|
278
pnpm-lock.yaml
278
pnpm-lock.yaml
@ -43,7 +43,7 @@ importers:
|
|||||||
version: 9.0.0
|
version: 9.0.0
|
||||||
'@testing-library/jest-dom':
|
'@testing-library/jest-dom':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0(vitest@1.2.2)
|
version: 6.0.0(vitest@1.3.1)
|
||||||
'@testing-library/user-event':
|
'@testing-library/user-event':
|
||||||
specifier: ^14.0.0
|
specifier: ^14.0.0
|
||||||
version: 14.0.0(@testing-library/dom@9.0.0)
|
version: 14.0.0(@testing-library/dom@9.0.0)
|
||||||
@ -81,8 +81,8 @@ importers:
|
|||||||
specifier: ^14.0.0
|
specifier: ^14.0.0
|
||||||
version: 14.0.0
|
version: 14.0.0
|
||||||
happy-dom:
|
happy-dom:
|
||||||
specifier: ^13.3.8
|
specifier: ^13.6.2
|
||||||
version: 13.3.8
|
version: 13.6.2
|
||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^24.0.0
|
specifier: ^24.0.0
|
||||||
version: 24.0.0
|
version: 24.0.0
|
||||||
@ -90,8 +90,8 @@ importers:
|
|||||||
specifier: ^4.1.5
|
specifier: ^4.1.5
|
||||||
version: 4.1.5
|
version: 4.1.5
|
||||||
msw:
|
msw:
|
||||||
specifier: ^2.0.0
|
specifier: ^2.2.1
|
||||||
version: 2.0.0(typescript@5.0.2)
|
version: 2.2.1(typescript@5.0.2)
|
||||||
node-html-parser:
|
node-html-parser:
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
@ -168,8 +168,8 @@ importers:
|
|||||||
specifier: 1.0.3
|
specifier: 1.0.3
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^1.2.2
|
specifier: ^1.3.1
|
||||||
version: 1.2.2(@types/node@20.3.2)(happy-dom@13.3.8)(jsdom@24.0.0)(less@4.2.0)
|
version: 1.3.1(@types/node@20.3.2)(happy-dom@13.6.2)(jsdom@24.0.0)(less@4.2.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@storybook/addon-a11y':
|
'@storybook/addon-a11y':
|
||||||
specifier: ^7.5.1
|
specifier: ^7.5.1
|
||||||
@ -2906,12 +2906,6 @@ packages:
|
|||||||
cookie: 0.5.0
|
cookie: 0.5.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@bundled-es-modules/js-levenshtein@2.0.1:
|
|
||||||
resolution: {integrity: sha512-DERMS3yfbAljKsQc0U2wcqGKUWpdFjwqWuoMugEJlqBnKO180/n+4SR/J8MRDt1AN48X1ovgoD9KrdVXcaa3Rg==}
|
|
||||||
dependencies:
|
|
||||||
js-levenshtein: 1.1.6
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@bundled-es-modules/statuses@1.0.1:
|
/@bundled-es-modules/statuses@1.0.1:
|
||||||
resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
|
resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4297,6 +4291,39 @@ packages:
|
|||||||
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@inquirer/confirm@3.0.0:
|
||||||
|
resolution: {integrity: sha512-LHeuYP1D8NmQra1eR4UqvZMXwxEdDXyElJmmZfU44xdNLL6+GcQBS0uE16vyfZVjH8c22p9e+DStROfE/hyHrg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
'@inquirer/core': 7.0.0
|
||||||
|
'@inquirer/type': 1.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@inquirer/core@7.0.0:
|
||||||
|
resolution: {integrity: sha512-g13W5yEt9r1sEVVriffJqQ8GWy94OnfxLCreNSOTw0HPVcszmc/If1KIf7YBmlwtX4klmvwpZHnQpl3N7VX2xA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dependencies:
|
||||||
|
'@inquirer/type': 1.2.0
|
||||||
|
'@types/mute-stream': 0.0.4
|
||||||
|
'@types/node': 20.11.20
|
||||||
|
'@types/wrap-ansi': 3.0.0
|
||||||
|
ansi-escapes: 4.3.2
|
||||||
|
chalk: 4.1.2
|
||||||
|
cli-spinners: 2.9.2
|
||||||
|
cli-width: 4.1.0
|
||||||
|
figures: 3.2.0
|
||||||
|
mute-stream: 1.0.0
|
||||||
|
run-async: 3.0.0
|
||||||
|
signal-exit: 4.1.0
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
wrap-ansi: 6.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@inquirer/type@1.2.0:
|
||||||
|
resolution: {integrity: sha512-/vvkUkYhrjbm+RolU7V1aUFDydZVKNKqKHR5TsE+j5DXgXFwrsOPcoGUJ02K0O7q7O53CU2DOTMYCHeGZ25WHA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@isaacs/cliui@8.0.2:
|
/@isaacs/cliui@8.0.2:
|
||||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -4577,15 +4604,15 @@ packages:
|
|||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mswjs/interceptors@0.25.11:
|
/@mswjs/interceptors@0.25.16:
|
||||||
resolution: {integrity: sha512-27aonWAjdeoZN4j4j6QvePOSOacQUucFRUESAU8FUXsmmagDjmyOi4/NHizxzY/NHSk/HAyqF/IMhl+9puhqNw==}
|
resolution: {integrity: sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@open-draft/deferred-promise': 2.2.0
|
'@open-draft/deferred-promise': 2.2.0
|
||||||
'@open-draft/logger': 0.3.0
|
'@open-draft/logger': 0.3.0
|
||||||
'@open-draft/until': 2.1.0
|
'@open-draft/until': 2.1.0
|
||||||
is-node-process: 1.2.0
|
is-node-process: 1.2.0
|
||||||
outvariant: 1.4.0
|
outvariant: 1.4.2
|
||||||
strict-event-emitter: 0.5.1
|
strict-event-emitter: 0.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@ -4623,7 +4650,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
|
resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
is-node-process: 1.2.0
|
is-node-process: 1.2.0
|
||||||
outvariant: 1.4.0
|
outvariant: 1.4.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@open-draft/until@2.1.0:
|
/@open-draft/until@2.1.0:
|
||||||
@ -7165,7 +7192,7 @@ packages:
|
|||||||
lz-string: 1.5.0
|
lz-string: 1.5.0
|
||||||
pretty-format: 27.5.1
|
pretty-format: 27.5.1
|
||||||
|
|
||||||
/@testing-library/jest-dom@6.0.0(vitest@1.2.2):
|
/@testing-library/jest-dom@6.0.0(vitest@1.3.1):
|
||||||
resolution: {integrity: sha512-Ye2R3+/oM27jir8CzYPmuWdavTaKwNZcu0d22L9pO/vnOYE0wmrtpw79TQJa8H6gV8/i7yd+pLaqeLlA0rTMfg==}
|
resolution: {integrity: sha512-Ye2R3+/oM27jir8CzYPmuWdavTaKwNZcu0d22L9pO/vnOYE0wmrtpw79TQJa8H6gV8/i7yd+pLaqeLlA0rTMfg==}
|
||||||
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
|
engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -7191,7 +7218,7 @@ packages:
|
|||||||
dom-accessibility-api: 0.5.16
|
dom-accessibility-api: 0.5.16
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
redent: 3.0.0
|
redent: 3.0.0
|
||||||
vitest: 1.2.2(@types/node@20.3.2)(happy-dom@13.3.8)(jsdom@24.0.0)(less@4.2.0)
|
vitest: 1.3.1(@types/node@20.3.2)(happy-dom@13.6.2)(jsdom@24.0.0)(less@4.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@testing-library/user-event@14.0.0(@testing-library/dom@9.0.0):
|
/@testing-library/user-event@14.0.0(@testing-library/dom@9.0.0):
|
||||||
@ -7271,13 +7298,13 @@ packages:
|
|||||||
'@types/node': 20.9.0
|
'@types/node': 20.9.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/cookie@0.4.1:
|
|
||||||
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/cookie@0.5.4:
|
/@types/cookie@0.5.4:
|
||||||
resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==}
|
resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==}
|
||||||
|
|
||||||
|
/@types/cookie@0.6.0:
|
||||||
|
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/cross-spawn@6.0.5:
|
/@types/cross-spawn@6.0.5:
|
||||||
resolution: {integrity: sha512-wsIMP68FvGXk+RaWhraz6Xp4v7sl4qwzHAmtPaJEN2NRTXXI9LtFawUpeTsBNL/pd6QoLStdytCaAyiK7AEd/Q==}
|
resolution: {integrity: sha512-wsIMP68FvGXk+RaWhraz6Xp4v7sl4qwzHAmtPaJEN2NRTXXI9LtFawUpeTsBNL/pd6QoLStdytCaAyiK7AEd/Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7407,10 +7434,6 @@ packages:
|
|||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/js-levenshtein@1.1.3:
|
|
||||||
resolution: {integrity: sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/json-schema@7.0.15:
|
/@types/json-schema@7.0.15:
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
@ -7442,6 +7465,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
|
resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/mute-stream@0.0.4:
|
||||||
|
resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.11.20
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/node-fetch@2.6.9:
|
/@types/node-fetch@2.6.9:
|
||||||
resolution: {integrity: sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==}
|
resolution: {integrity: sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7463,7 +7492,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==}
|
resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 5.26.5
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/node@20.3.2:
|
/@types/node@20.3.2:
|
||||||
resolution: {integrity: sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==}
|
resolution: {integrity: sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==}
|
||||||
@ -7587,6 +7615,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==}
|
resolution: {integrity: sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/wrap-ansi@3.0.0:
|
||||||
|
resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/ws@8.5.4:
|
/@types/ws@8.5.4:
|
||||||
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
|
resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7760,38 +7792,38 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vitest/expect@1.2.2:
|
/@vitest/expect@1.3.1:
|
||||||
resolution: {integrity: sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==}
|
resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 1.2.2
|
'@vitest/spy': 1.3.1
|
||||||
'@vitest/utils': 1.2.2
|
'@vitest/utils': 1.3.1
|
||||||
chai: 4.3.10
|
chai: 4.3.10
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vitest/runner@1.2.2:
|
/@vitest/runner@1.3.1:
|
||||||
resolution: {integrity: sha512-JctG7QZ4LSDXr5CsUweFgcpEvrcxOV1Gft7uHrvkQ+fsAVylmWQvnaAr/HDp3LAH1fztGMQZugIheTWjaGzYIg==}
|
resolution: {integrity: sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/utils': 1.2.2
|
'@vitest/utils': 1.3.1
|
||||||
p-limit: 5.0.0
|
p-limit: 5.0.0
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vitest/snapshot@1.2.2:
|
/@vitest/snapshot@1.3.1:
|
||||||
resolution: {integrity: sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==}
|
resolution: {integrity: sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vitest/spy@1.2.2:
|
/@vitest/spy@1.3.1:
|
||||||
resolution: {integrity: sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==}
|
resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==}
|
||||||
dependencies:
|
dependencies:
|
||||||
tinyspy: 2.2.0
|
tinyspy: 2.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vitest/utils@1.2.2:
|
/@vitest/utils@1.3.1:
|
||||||
resolution: {integrity: sha512-WKITBHLsBHlpjnDQahr+XK6RE7MiAsgrIkr0pGhQ9ygoxBfUeG0lUG5iLlzqjmKSlBv3+j5EGsriBzh+C3Tq9g==}
|
resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
diff-sequences: 29.6.3
|
diff-sequences: 29.6.3
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
@ -8395,6 +8427,7 @@ packages:
|
|||||||
|
|
||||||
/base64-js@1.5.1:
|
/base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/better-opn@3.0.2:
|
/better-opn@3.0.2:
|
||||||
resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
|
resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==}
|
||||||
@ -8435,6 +8468,7 @@ packages:
|
|||||||
buffer: 5.7.1
|
buffer: 5.7.1
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/body-parser@1.20.1:
|
/body-parser@1.20.1:
|
||||||
resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
|
resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
|
||||||
@ -8548,6 +8582,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/bufferutil@4.0.7:
|
/bufferutil@4.0.7:
|
||||||
resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
|
resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==}
|
||||||
@ -8734,10 +8769,17 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
restore-cursor: 3.1.0
|
restore-cursor: 3.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/cli-spinners@2.9.1:
|
/cli-spinners@2.9.1:
|
||||||
resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==}
|
resolution: {integrity: sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/cli-spinners@2.9.2:
|
||||||
|
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/cli-table3@0.6.3:
|
/cli-table3@0.6.3:
|
||||||
resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==}
|
resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==}
|
||||||
@ -8748,9 +8790,9 @@ packages:
|
|||||||
'@colors/colors': 1.5.0
|
'@colors/colors': 1.5.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/cli-width@3.0.0:
|
/cli-width@4.1.0:
|
||||||
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
|
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 12'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/cliui@6.0.0:
|
/cliui@6.0.0:
|
||||||
@ -10753,14 +10795,6 @@ packages:
|
|||||||
combined-stream: 1.0.8
|
combined-stream: 1.0.8
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
|
|
||||||
/formdata-node@4.4.1:
|
|
||||||
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
|
||||||
engines: {node: '>= 12.20'}
|
|
||||||
dependencies:
|
|
||||||
node-domexception: 1.0.0
|
|
||||||
web-streams-polyfill: 4.0.0-beta.3
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/forwarded@0.2.0:
|
/forwarded@0.2.0:
|
||||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@ -11106,8 +11140,8 @@ packages:
|
|||||||
uglify-js: 3.17.4
|
uglify-js: 3.17.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/happy-dom@13.3.8:
|
/happy-dom@13.6.2:
|
||||||
resolution: {integrity: sha512-RAbq4oYfJNkVan1m1F3jfA4YEyRY0/ASoNvZsNJbuX85jIypidmsz9jQZD7Tqz0VXA2MhAGfcsh5oshwmwNYSg==}
|
resolution: {integrity: sha512-Ku+wDqcF/KwFA0dI+xIMZd9Jn020RXjuSil/Vz7gu2yhDC3FsDYZ55qqV9k+SGC4opwb4acisXqVSRxUJMlPbQ==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
@ -11282,6 +11316,7 @@ packages:
|
|||||||
|
|
||||||
/ieee754@1.2.1:
|
/ieee754@1.2.1:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/ignore@4.0.6:
|
/ignore@4.0.6:
|
||||||
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
|
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
|
||||||
@ -11334,27 +11369,6 @@ packages:
|
|||||||
/inherits@2.0.4:
|
/inherits@2.0.4:
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
/inquirer@8.2.6:
|
|
||||||
resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
dependencies:
|
|
||||||
ansi-escapes: 4.3.2
|
|
||||||
chalk: 4.1.2
|
|
||||||
cli-cursor: 3.1.0
|
|
||||||
cli-width: 3.0.0
|
|
||||||
external-editor: 3.1.0
|
|
||||||
figures: 3.2.0
|
|
||||||
lodash: 4.17.21
|
|
||||||
mute-stream: 0.0.8
|
|
||||||
ora: 5.4.1
|
|
||||||
run-async: 2.4.1
|
|
||||||
rxjs: 7.8.1
|
|
||||||
string-width: 4.2.3
|
|
||||||
strip-ansi: 6.0.1
|
|
||||||
through: 2.3.8
|
|
||||||
wrap-ansi: 6.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/internal-slot@1.0.6:
|
/internal-slot@1.0.6:
|
||||||
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
|
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -11522,6 +11536,7 @@ packages:
|
|||||||
/is-interactive@1.0.0:
|
/is-interactive@1.0.0:
|
||||||
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
|
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/is-module@1.0.0:
|
/is-module@1.0.0:
|
||||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||||
@ -11649,6 +11664,7 @@ packages:
|
|||||||
/is-unicode-supported@0.1.0:
|
/is-unicode-supported@0.1.0:
|
||||||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/is-weakref@1.0.2:
|
/is-weakref@1.0.2:
|
||||||
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
|
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
|
||||||
@ -11849,11 +11865,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
|
resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/js-levenshtein@1.1.6:
|
|
||||||
resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/js-stringify@1.0.2:
|
/js-stringify@1.0.2:
|
||||||
resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
|
resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -11861,6 +11872,10 @@ packages:
|
|||||||
/js-tokens@4.0.0:
|
/js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
|
/js-tokens@8.0.3:
|
||||||
|
resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/js-yaml@3.14.1:
|
/js-yaml@3.14.1:
|
||||||
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
|
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -12266,6 +12281,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
is-unicode-supported: 0.1.0
|
is-unicode-supported: 0.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/loose-envify@1.4.0:
|
/loose-envify@1.4.0:
|
||||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||||
@ -12567,6 +12583,7 @@ packages:
|
|||||||
/mimic-fn@2.1.0:
|
/mimic-fn@2.1.0:
|
||||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/mimic-fn@4.0.0:
|
/mimic-fn@4.0.0:
|
||||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||||
@ -12686,43 +12703,35 @@ packages:
|
|||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/msw@2.0.0(typescript@5.0.2):
|
/msw@2.2.1(typescript@5.0.2):
|
||||||
resolution: {integrity: sha512-lw9UHuzNCWoODHaThGeLLIIuzEBUQkj3fJXQnChHifMKbB2UmF2msHd4d/lnyqjAyD0XWoibdviW9wlstFPpkA==}
|
resolution: {integrity: sha512-DCsZAQwan+2onEcpD86fiEnCKW4IvYzqcwDq/2TIoeNrmBqNp/mJW4wHQyxcoYrRPwgujin7wDFflqiSO1iT/w==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>= 4.7.x <= 5.2.x'
|
typescript: '>= 4.7.x <= 5.3.x'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@bundled-es-modules/cookie': 2.0.0
|
'@bundled-es-modules/cookie': 2.0.0
|
||||||
'@bundled-es-modules/js-levenshtein': 2.0.1
|
|
||||||
'@bundled-es-modules/statuses': 1.0.1
|
'@bundled-es-modules/statuses': 1.0.1
|
||||||
|
'@inquirer/confirm': 3.0.0
|
||||||
'@mswjs/cookies': 1.1.0
|
'@mswjs/cookies': 1.1.0
|
||||||
'@mswjs/interceptors': 0.25.11
|
'@mswjs/interceptors': 0.25.16
|
||||||
'@open-draft/until': 2.1.0
|
'@open-draft/until': 2.1.0
|
||||||
'@types/cookie': 0.4.1
|
'@types/cookie': 0.6.0
|
||||||
'@types/js-levenshtein': 1.1.3
|
|
||||||
'@types/statuses': 2.0.4
|
'@types/statuses': 2.0.4
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
chokidar: 3.5.3
|
|
||||||
formdata-node: 4.4.1
|
|
||||||
graphql: 16.8.1
|
graphql: 16.8.1
|
||||||
headers-polyfill: 4.0.2
|
headers-polyfill: 4.0.2
|
||||||
inquirer: 8.2.6
|
|
||||||
is-node-process: 1.2.0
|
is-node-process: 1.2.0
|
||||||
js-levenshtein: 1.1.6
|
outvariant: 1.4.2
|
||||||
node-fetch: 2.7.0
|
|
||||||
outvariant: 1.4.0
|
|
||||||
path-to-regexp: 6.2.1
|
path-to-regexp: 6.2.1
|
||||||
strict-event-emitter: 0.5.1
|
strict-event-emitter: 0.5.1
|
||||||
type-fest: 2.19.0
|
type-fest: 4.10.3
|
||||||
typescript: 5.0.2
|
typescript: 5.0.2
|
||||||
yargs: 17.7.2
|
yargs: 17.7.2
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/multi-buffer-data-view@5.0.11:
|
/multi-buffer-data-view@5.0.11:
|
||||||
@ -12733,8 +12742,9 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/mute-stream@0.0.8:
|
/mute-stream@1.0.0:
|
||||||
resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
|
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
|
||||||
|
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/mz@2.7.0:
|
/mz@2.7.0:
|
||||||
@ -12790,11 +12800,6 @@ packages:
|
|||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/node-domexception@1.0.0:
|
|
||||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
|
||||||
engines: {node: '>=10.5.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-fetch-native@1.4.1:
|
/node-fetch-native@1.4.1:
|
||||||
resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==}
|
resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -12964,6 +12969,7 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn: 2.1.0
|
mimic-fn: 2.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/onetime@6.0.0:
|
/onetime@6.0.0:
|
||||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||||
@ -13005,6 +13011,7 @@ packages:
|
|||||||
log-symbols: 4.1.0
|
log-symbols: 4.1.0
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
wcwidth: 1.0.1
|
wcwidth: 1.0.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/os-tmpdir@1.0.2:
|
/os-tmpdir@1.0.2:
|
||||||
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
|
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
|
||||||
@ -13015,8 +13022,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
|
resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/outvariant@1.4.0:
|
/outvariant@1.4.2:
|
||||||
resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==}
|
resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/p-filter@2.1.0:
|
/p-filter@2.1.0:
|
||||||
@ -14216,6 +14223,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
onetime: 5.1.2
|
onetime: 5.1.2
|
||||||
signal-exit: 3.0.7
|
signal-exit: 3.0.7
|
||||||
|
dev: true
|
||||||
|
|
||||||
/reusify@1.0.4:
|
/reusify@1.0.4:
|
||||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||||
@ -14289,8 +14297,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
|
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/run-async@2.4.1:
|
/run-async@3.0.0:
|
||||||
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
|
resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==}
|
||||||
engines: {node: '>=0.12.0'}
|
engines: {node: '>=0.12.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@ -14307,12 +14315,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw==}
|
resolution: {integrity: sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/rxjs@7.8.1:
|
|
||||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
|
||||||
dependencies:
|
|
||||||
tslib: 2.6.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/sade@1.8.1:
|
/sade@1.8.1:
|
||||||
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -14819,10 +14821,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
/strip-literal@1.3.0:
|
/strip-literal@2.0.0:
|
||||||
resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
|
resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.11.2
|
js-tokens: 8.0.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/style-loader@3.3.3(webpack@5.90.3):
|
/style-loader@3.3.3(webpack@5.90.3):
|
||||||
@ -15442,10 +15444,6 @@ packages:
|
|||||||
xtend: 4.0.2
|
xtend: 4.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/through@2.3.8:
|
|
||||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/timers-ext@0.1.7:
|
/timers-ext@0.1.7:
|
||||||
resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==}
|
resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -15656,6 +15654,12 @@ packages:
|
|||||||
/type-fest@2.19.0:
|
/type-fest@2.19.0:
|
||||||
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||||
engines: {node: '>=12.20'}
|
engines: {node: '>=12.20'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/type-fest@4.10.3:
|
||||||
|
resolution: {integrity: sha512-JLXyjizi072smKGGcZiAJDCNweT8J+AuRxmPZ1aG7TERg4ijx9REl8CNhbr36RV4qXqL1gO1FF9HL8OkVmmrsA==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/type-is@1.6.18:
|
/type-is@1.6.18:
|
||||||
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
|
||||||
@ -16398,8 +16402,8 @@ packages:
|
|||||||
unist-util-stringify-position: 2.0.3
|
unist-util-stringify-position: 2.0.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vite-node@1.2.2(@types/node@20.3.2)(less@4.2.0):
|
/vite-node@1.3.1(@types/node@20.3.2)(less@4.2.0):
|
||||||
resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==}
|
resolution: {integrity: sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -16590,15 +16594,15 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
vite: 4.5.2(@types/node@20.3.2)(less@4.2.0)(lightningcss@1.21.7)(sass@1.66.1)(stylus@0.63.0)(sugarss@4.0.1)
|
vite: 4.5.2(@types/node@20.3.2)(less@4.2.0)(lightningcss@1.21.7)(sass@1.66.1)(stylus@0.63.0)(sugarss@4.0.1)
|
||||||
|
|
||||||
/vitest@1.2.2(@types/node@20.3.2)(happy-dom@13.3.8)(jsdom@24.0.0)(less@4.2.0):
|
/vitest@1.3.1(@types/node@20.3.2)(happy-dom@13.6.2)(jsdom@24.0.0)(less@4.2.0):
|
||||||
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==}
|
resolution: {integrity: sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@edge-runtime/vm': '*'
|
'@edge-runtime/vm': '*'
|
||||||
'@types/node': ^18.0.0 || >=20.0.0
|
'@types/node': ^18.0.0 || >=20.0.0
|
||||||
'@vitest/browser': ^1.0.0
|
'@vitest/browser': 1.3.1
|
||||||
'@vitest/ui': ^1.0.0
|
'@vitest/ui': 1.3.1
|
||||||
happy-dom: '*'
|
happy-dom: '*'
|
||||||
jsdom: '*'
|
jsdom: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
@ -16616,28 +16620,27 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.3.2
|
'@types/node': 20.3.2
|
||||||
'@vitest/expect': 1.2.2
|
'@vitest/expect': 1.3.1
|
||||||
'@vitest/runner': 1.2.2
|
'@vitest/runner': 1.3.1
|
||||||
'@vitest/snapshot': 1.2.2
|
'@vitest/snapshot': 1.3.1
|
||||||
'@vitest/spy': 1.2.2
|
'@vitest/spy': 1.3.1
|
||||||
'@vitest/utils': 1.2.2
|
'@vitest/utils': 1.3.1
|
||||||
acorn-walk: 8.3.2
|
acorn-walk: 8.3.2
|
||||||
cac: 6.7.14
|
|
||||||
chai: 4.3.10
|
chai: 4.3.10
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
execa: 8.0.1
|
execa: 8.0.1
|
||||||
happy-dom: 13.3.8
|
happy-dom: 13.6.2
|
||||||
jsdom: 24.0.0
|
jsdom: 24.0.0
|
||||||
local-pkg: 0.5.0
|
local-pkg: 0.5.0
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
pathe: 1.1.1
|
pathe: 1.1.1
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
std-env: 3.7.0
|
std-env: 3.7.0
|
||||||
strip-literal: 1.3.0
|
strip-literal: 2.0.0
|
||||||
tinybench: 2.5.1
|
tinybench: 2.5.1
|
||||||
tinypool: 0.8.2
|
tinypool: 0.8.2
|
||||||
vite: 5.1.1(@types/node@20.3.2)(less@4.2.0)
|
vite: 5.1.1(@types/node@20.3.2)(less@4.2.0)
|
||||||
vite-node: 1.2.2(@types/node@20.3.2)(less@4.2.0)
|
vite-node: 1.3.1(@types/node@20.3.2)(less@4.2.0)
|
||||||
why-is-node-running: 2.2.2
|
why-is-node-running: 2.2.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- less
|
- less
|
||||||
@ -16688,11 +16691,6 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
defaults: 1.0.4
|
defaults: 1.0.4
|
||||||
|
|
||||||
/web-streams-polyfill@4.0.0-beta.3:
|
|
||||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
|
||||||
engines: {node: '>= 14'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/webidl-conversions@3.0.1:
|
/webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user