diff --git a/package.json b/package.json
index 6ea3ff1..b514c1d 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"name": "babel-sandboxes",
"version": "1.0.0",
"description": "",
+ "proxy": "http://localhost:3005",
"dependencies": {
"@babel/core": "~7.10.0",
"@babel/plugin-external-helpers": "~7.10.0",
diff --git a/src/components/App.js b/src/components/App.js
index 647ad32..bf42083 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -8,7 +8,7 @@ import { Output } from "./Output";
import { gzipSize } from "../gzip";
import { Root } from "./styles";
import { useDebounce } from "../utils/useDebounce";
-import REPLState from "../state/REPLState.js";
+import { REPLState } from "../state";
import { Grid } from "semantic-ui-react";
import { plugins } from "../plugins-list";
@@ -17,18 +17,34 @@ window.babel = Babel;
/**
* Converts internal json plugin/preset config to babel form
- * @param {Object} jsonConfig
+ * @param {Object} jsonConfig
*/
export function convertToBabelConfig(jsonConfig) {
let result = { plugins: [], presets: [] };
+<<<<<<< HEAD
+ result.plugins = jsonConfig.plugins?.map(plugin => [
+ plugin.name,
+ plugin.defaultConfig,
+ ]);
+ result.presets = jsonConfig.presets?.map(preset => [
+ preset.name,
+ preset.defaultConfig,
+ ]);
+=======
result.plugins = jsonConfig.plugins?.map(plugin => [plugin.name, plugin.defaultConfig]);
result.presets = jsonConfig.presets?.map(preset => [preset.name, preset.defaultConfig]);
+>>>>>>> master
return result;
}
export function convertToJsonConfig(babelConfig) {
+<<<<<<< HEAD
+ let result = { plugins: [], presets: [] };
+ result.plugins = babelConfig.plugins?.map(plugin => {
+=======
let result = { plugins: [], presets: [] }
result.plugins = babelConfig.plugins?.map((plugin) => {
+>>>>>>> master
return {
name: plugin[0],
description: plugins[plugin[0]].description,
@@ -71,16 +87,12 @@ function registerDefaultPlugins() {
);
}
-
-
export const App = ({ defaultSource, defaultConfig, defCustomPlugin }) => {
const [source, setSource] = React.useState(defaultSource);
const [enableCustomPlugin, toggleCustomPlugin] = React.useState(false);
const [customPlugin, setCustomPlugin] = React.useState(defCustomPlugin);
const [jsonConfig, setJsonConfig] = useState(
- Array.isArray(defaultConfig)
- ? defaultConfig
- : [defaultConfig]
+ Array.isArray(defaultConfig) ? defaultConfig : [defaultConfig]
);
const [size, setSize] = useState(null);
const [gzip, setGzip] = useState(null);
@@ -89,7 +101,7 @@ export const App = ({ defaultSource, defaultConfig, defCustomPlugin }) => {
const [showShareLink, setShowShareLink] = React.useState(false);
const updateBabelConfig = useCallback((config, index) => {
- setJsonConfig((configs) => {
+ setJsonConfig(configs => {
const newConfigs = [...configs];
newConfigs[index] = config;
@@ -97,8 +109,8 @@ export const App = ({ defaultSource, defaultConfig, defCustomPlugin }) => {
});
}, []);
- const removeBabelConfig = useCallback((index) => {
- setJsonConfig((configs) => configs.filter((c, i) => index !== i));
+ const removeBabelConfig = useCallback(index => {
+ setJsonConfig(configs => configs.filter((c, i) => index !== i));
}, []);
useEffect(() => {
@@ -124,18 +136,17 @@ export const App = ({ defaultSource, defaultConfig, defCustomPlugin }) => {
const state = new REPLState(
source,
enableCustomPlugin ? customPlugin : "",
- jsonConfig.map((config) => JSON.stringify(config))
+ jsonConfig.map(config => JSON.stringify(config))
);
const link = await state.Link();
+
setShareLink(link);
setShowShareLink(true);
}}
>
Share
-
- {showShareLink && (
-
- )}
+
+ {showShareLink && }
{enableCustomPlugin && (
diff --git a/src/index.js b/src/index.js
index a88fc39..0f12bdb 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,7 @@
import React from "react";
import { render } from "react-dom";
import { App } from "./components/App";
+import { extractID, isShareLink, REPLState } from "./state";
// css
import "semantic-ui-less/semantic.less";
@@ -45,7 +46,7 @@ const CONFIG = [
// description: "does this",
// defaultConfig: {},
// }
- ]
+ ],
},
// {},
];
@@ -61,11 +62,31 @@ const PLUGIN = `export default function customPlugin(babel) {
}
`;
-render(
- ,
- document.getElementById("root")
+const defaultState = new REPLState(
+ SOURCE,
+ PLUGIN,
+ CONFIG.map(conf => JSON.stringify(conf))
);
+
+/**
+ * @returns {Promise}
+ */
+async function getState() {
+ if (!isShareLink()) {
+ return defaultState;
+ }
+ const state = await REPLState.FromID(extractID());
+ return state === null ? defaultState : state;
+}
+
+(async () => {
+ const state = await getState();
+ render(
+ JSON.parse(conf))}
+ defaultSource={state.jsSource}
+ defCustomPlugin={state.pluginSource}
+ />,
+ document.getElementById("root")
+ );
+})();
diff --git a/src/state/REPLState.js b/src/state/REPLState.js
index 853e5b1..3cb1e39 100644
--- a/src/state/REPLState.js
+++ b/src/state/REPLState.js
@@ -62,30 +62,12 @@ class REPLState {
return JSON.stringify({
source: encodeToBase64(this.jsSource),
plugin: encodeToBase64(this.pluginSource),
- configs: this.configs.map((configSrc) => {
+ configs: this.configs.map(configSrc => {
return encodeToBase64(configSrc);
}),
});
}
- /**
- * Link gets the sharing the sharing link
- * for the given REPL state.
- * @returns {Promise} String URL.
- */
- async Link() {
- const url = "http://localhost:1337/api/v1/blobs/create";
- const resp = await fetch(url, {
- method: "POST",
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- },
- body: this.Encode(),
- });
- return resp.text();
- }
-
/**
* Decode decodes the json string.
* @param {string} encodedState
@@ -94,13 +76,58 @@ class REPLState {
static Decode(encodedState) {
let jsonState = JSON.parse(encodedState);
return new REPLState(
- decodeBase64(jsonState.source),
- decodeBase64(jsonState.plugin),
- jsonState.configs.map((configs) => {
+ decodeBase64(jsonState.base64SourceKey),
+ decodeBase64(jsonState.base64PluginKey),
+ jsonState.configIDs.map(configs => {
return decodeBase64(configs);
})
);
}
+
+ /**
+ * Link gets the sharing the sharing link
+ * for the given REPL state.
+ * @returns {Promise} String URL.
+ */
+ async Link() {
+ const url = `/api/v1/blobs/create`;
+ try {
+ const resp = await fetch(url, {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json",
+ },
+ body: this.Encode(),
+ });
+ const message = await resp.json();
+
+ // https://stackoverflow.com/questions/6941533/get-protocol-domain-and-port-from-url
+ return (
+ window.location.href.split("/").slice(0, 3).join("/") + message.url
+ );
+ } catch (err) {
+ console.error(err);
+ return err;
+ }
+ }
+
+ /**
+ * REPLState.FromID returns a REPLState given a unique identifier.
+ * @param {string} ID
+ * @returns {Promise}
+ */
+ static async FromID(ID) {
+ const url = `/api/v1/blobs/${ID}`;
+ try {
+ const resp = await fetch(url);
+ const text = await resp.text();
+ return REPLState.Decode(text);
+ } catch (err) {
+ console.error(err);
+ return null;
+ }
+ }
}
export default REPLState;
diff --git a/src/state/detectShare.js b/src/state/detectShare.js
new file mode 100644
index 0000000..8ccb288
--- /dev/null
+++ b/src/state/detectShare.js
@@ -0,0 +1,22 @@
+/**
+ * isShareLink returns true iff the pathname contains the text `share`
+ * @returns {boolean}
+ */
+function isShareLink() {
+ const path = window.location.pathname;
+ const shareIndicator = "share";
+ return path.includes(shareIndicator);
+}
+
+function extractID() {
+
+ // Attempt to capture :key from http://example.com/share/:key/
+ const pathParts = window.location.pathname.split('/');
+ if (pathParts[1] == 'share' && pathParts[2]) {
+ return pathParts[2];
+ } else {
+ throw new Error("Trying to extract ID from a share link that doesn't have one.")
+ }
+}
+
+export { isShareLink, extractID };
diff --git a/src/state/index.js b/src/state/index.js
new file mode 100644
index 0000000..c241dc1
--- /dev/null
+++ b/src/state/index.js
@@ -0,0 +1,4 @@
+import REPLState from "./REPLState.js";
+import { extractID, isShareLink } from "./detectShare.js";
+
+export { REPLState, extractID, isShareLink };