mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
set up a typescript pipeline for interpreter
This commit is contained in:
parent
53cafefdef
commit
7f60010c1e
11 changed files with 197 additions and 44 deletions
65
packages/interpreter/build.rs
Normal file
65
packages/interpreter/build.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use std::{
|
||||
fs::read_to_string,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
process::Command,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
// If any TS changes, re-run the build script
|
||||
println!("cargo:rerun-if-changed=src/*.ts");
|
||||
|
||||
for entry in ["common", "form", "interpreter"].iter() {
|
||||
gen_bindings(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// okay...... so tsc might fail if the user doesn't have it installed
|
||||
// we don't really want to fail if that's the case
|
||||
// but if you started *editing* the .ts files, you're gonna have a bad time
|
||||
// so.....
|
||||
// we need to hash each of the .ts files and add that hash to the JS files
|
||||
// if the hashes don't match, we need to fail the build
|
||||
// that way we also don't need
|
||||
fn gen_bindings(name: &str) {
|
||||
let contents = read_to_string(&format!("src/{name}.ts")).unwrap();
|
||||
let generated = read_to_string(&format!("src/gen/{name}.js")).unwrap_or_default();
|
||||
let hashed = hash_file(&contents);
|
||||
|
||||
// If the file is generated, and the hash is the same, we're good, don't do anything
|
||||
if generated
|
||||
.lines()
|
||||
.next()
|
||||
.unwrap_or_default()
|
||||
.starts_with(&format!("// DO NOT EDIT THIS FILE. HASH: {}", hashed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the file is generated, and the hash is different, we need to generate it
|
||||
let status = Command::new("tsc")
|
||||
.arg(format!("src/{name}.ts"))
|
||||
.arg("--outDir")
|
||||
.arg("gen")
|
||||
.arg("--target")
|
||||
.arg("es6")
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
if !status.success() {
|
||||
panic!(
|
||||
"Failed to generate bindings for {}. Make sure you have tsc installed",
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
// The file should exist, and now we need write the TS hash to the file
|
||||
let generated = read_to_string(&format!("gen/{name}.js")).unwrap();
|
||||
let generated = format!("// DO NOT EDIT THIS FILE. HASH: {}\n{}", hashed, generated);
|
||||
std::fs::write(&format!("src/gen/{name}.js"), generated).unwrap();
|
||||
}
|
||||
|
||||
fn hash_file(obj: &str) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
obj.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
3
packages/interpreter/gen/README.md
Normal file
3
packages/interpreter/gen/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
temporary generated code directory since tsc doesn't have a crossplatform way of generating typescript to stdout
|
||||
|
||||
https://github.com/microsoft/TypeScript/issues/1226#issuecomment-523544134
|
|
@ -1,4 +1,5 @@
|
|||
export function setAttributeInner(node, field, value, ns) {
|
||||
|
||||
const name = field;
|
||||
if (ns === "style") {
|
||||
// ????? why do we need to do this
|
0
packages/interpreter/src/form.ts
Normal file
0
packages/interpreter/src/form.ts
Normal file
81
packages/interpreter/src/gen/common.js
Normal file
81
packages/interpreter/src/gen/common.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
// DO NOT EDIT THIS FILE. HASH: 9578489549991746027
|
||||
export function setAttributeInner(node, field, value, ns) {
|
||||
const name = field;
|
||||
if (ns === "style") {
|
||||
// ????? why do we need to do this
|
||||
if (node.style === undefined) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style[name] = value;
|
||||
}
|
||||
else if (!!ns) {
|
||||
node.setAttributeNS(ns, name, value);
|
||||
}
|
||||
else {
|
||||
switch (name) {
|
||||
case "value":
|
||||
if (value !== node.value) {
|
||||
node.value = value;
|
||||
}
|
||||
break;
|
||||
case "initial_value":
|
||||
node.defaultValue = value;
|
||||
break;
|
||||
case "checked":
|
||||
node.checked = truthy(value);
|
||||
break;
|
||||
case "initial_checked":
|
||||
node.defaultChecked = truthy(value);
|
||||
break;
|
||||
case "selected":
|
||||
node.selected = truthy(value);
|
||||
break;
|
||||
case "initial_selected":
|
||||
node.defaultSelected = truthy(value);
|
||||
break;
|
||||
case "dangerous_inner_html":
|
||||
node.innerHTML = value;
|
||||
break;
|
||||
default:
|
||||
// https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
|
||||
if (!truthy(value) && bool_attrs.hasOwnProperty(name)) {
|
||||
node.removeAttribute(name);
|
||||
}
|
||||
else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool_attrs = {
|
||||
allowfullscreen: true,
|
||||
allowpaymentrequest: true,
|
||||
async: true,
|
||||
autofocus: true,
|
||||
autoplay: true,
|
||||
checked: true,
|
||||
controls: true,
|
||||
default: true,
|
||||
defer: true,
|
||||
disabled: true,
|
||||
formnovalidate: true,
|
||||
hidden: true,
|
||||
ismap: true,
|
||||
itemscope: true,
|
||||
loop: true,
|
||||
multiple: true,
|
||||
muted: true,
|
||||
nomodule: true,
|
||||
novalidate: true,
|
||||
open: true,
|
||||
playsinline: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
function truthy(val) {
|
||||
return val === "true" || val === true;
|
||||
}
|
1
packages/interpreter/src/gen/form.js
Normal file
1
packages/interpreter/src/gen/form.js
Normal file
|
@ -0,0 +1 @@
|
|||
// DO NOT EDIT THIS FILE. HASH: 3476900567878811119
|
0
packages/interpreter/src/gen/interpreter.js
Normal file
0
packages/interpreter/src/gen/interpreter.js
Normal file
|
@ -1,5 +1,7 @@
|
|||
class InterpreterConfig {
|
||||
constructor(intercept_link_redirects) {
|
||||
intercept_link_redirects: boolean;
|
||||
|
||||
constructor(intercept_link_redirects: boolean) {
|
||||
this.intercept_link_redirects = intercept_link_redirects;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +23,42 @@ async function handler(event, name, bubbles, config) {
|
|||
|
||||
let contents = await serialize_event(event);
|
||||
|
||||
if (
|
||||
target.tagName === "FORM" &&
|
||||
(event.type === "submit" || event.type === "input")
|
||||
) {
|
||||
const formData = new FormData(target);
|
||||
|
||||
for (let name of formData.keys()) {
|
||||
const fieldType = target.elements[name].type;
|
||||
|
||||
switch (fieldType) {
|
||||
case "select-multiple":
|
||||
contents.values[name] = formData.getAll(name);
|
||||
break;
|
||||
|
||||
// add cases for fieldTypes that can hold multiple values here
|
||||
default:
|
||||
contents.values[name] = formData.get(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
target.tagName === "SELECT" &&
|
||||
event.type === "input"
|
||||
) {
|
||||
const selectData = target.options;
|
||||
contents.values["options"] = [];
|
||||
for (let i = 0; i < selectData.length; i++) {
|
||||
let option = selectData[i];
|
||||
if (option.selected) {
|
||||
contents.values["options"].push(option.value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be liveview only
|
||||
if (
|
||||
target.tagName === "INPUT" &&
|
||||
|
@ -61,42 +99,6 @@ async function handler(event, name, bubbles, config) {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
target.tagName === "FORM" &&
|
||||
(event.type === "submit" || event.type === "input")
|
||||
) {
|
||||
const formData = new FormData(target);
|
||||
|
||||
for (let name of formData.keys()) {
|
||||
const fieldType = target.elements[name].type;
|
||||
|
||||
switch (fieldType) {
|
||||
case "select-multiple":
|
||||
contents.values[name] = formData.getAll(name);
|
||||
break;
|
||||
|
||||
// add cases for fieldTypes that can hold multiple values here
|
||||
default:
|
||||
contents.values[name] = formData.get(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
target.tagName === "SELECT" &&
|
||||
event.type === "input"
|
||||
) {
|
||||
const selectData = target.options;
|
||||
contents.values["options"] = [];
|
||||
for (let i = 0; i < selectData.length; i++) {
|
||||
let option = selectData[i];
|
||||
if (option.selected) {
|
||||
contents.values["options"].push(option.value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.ipc.postMessage(
|
||||
window.interpreter.serializeIpcMessage("user_event", {
|
||||
name: name,
|
||||
|
@ -324,7 +326,7 @@ window.interpreter.setFocus = function (id, focus) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function get_mouse_data(event) {
|
||||
function get_mouse_data(event: MouseEvent) {
|
||||
const {
|
||||
altKey,
|
||||
button,
|
||||
|
@ -447,7 +449,8 @@ async function serialize_event(event) {
|
|||
case "dragover":
|
||||
case "dragstart":
|
||||
case "drop": {
|
||||
let files = null;
|
||||
let files = [];
|
||||
|
||||
if (event.dataTransfer && event.dataTransfer.files) {
|
||||
files = ["a", "b", "c"];
|
||||
// files = await serializeFileList(event.dataTransfer.files);
|
|
@ -2,8 +2,8 @@
|
|||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
|
||||
pub static INTERPRETER_JS: &str = include_str!("./interpreter.js");
|
||||
pub static COMMON_JS: &str = include_str!("./common.js");
|
||||
pub static INTERPRETER_JS: &str = include_str!("./gen/interpreter.js");
|
||||
pub static COMMON_JS: &str = include_str!("./gen/common.js");
|
||||
|
||||
#[cfg(feature = "sledgehammer")]
|
||||
mod sledgehammer_bindings;
|
||||
|
@ -20,7 +20,7 @@ pub use write_native_mutations::*;
|
|||
#[cfg(all(feature = "minimal_bindings", feature = "webonly"))]
|
||||
pub mod minimal_bindings {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
#[wasm_bindgen(module = "/src/common.js")]
|
||||
#[wasm_bindgen(module = "/src/gen/common.js")]
|
||||
extern "C" {
|
||||
pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>);
|
||||
}
|
||||
|
|
|
@ -36,8 +36,6 @@ pub struct UiEvent {
|
|||
pub data: PlatformEventData,
|
||||
}
|
||||
|
||||
//fn get_document(elem: &web_sys::Element) ->
|
||||
|
||||
impl WebsysDom {
|
||||
pub fn new(cfg: Config, event_channel: mpsc::UnboundedSender<UiEvent>) -> Self {
|
||||
let (document, root) = match cfg.root {
|
||||
|
|
|
@ -441,6 +441,7 @@ impl HasFileData for WebFormData {
|
|||
fn files(&self) -> Option<std::sync::Arc<dyn FileEngine>> {
|
||||
#[cfg(not(feature = "file_engine"))]
|
||||
let files = None;
|
||||
|
||||
#[cfg(feature = "file_engine")]
|
||||
let files = self
|
||||
.element
|
||||
|
|
Loading…
Reference in a new issue