Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Generate sharable link for code-explorer #24

Closed
wants to merge 16 commits into from
Closed
141 changes: 87 additions & 54 deletions src/hooks/use-explorer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
import { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
import {
devtools,
persist,
StateStorage,
createJSONStorage,
} from "zustand/middleware";
import type { Options } from "espree";
import { defaultJsCode, defaultJsonCode } from "../lib/const";

export type SourceType = Exclude<Options["sourceType"], undefined>;
export type Version = Exclude<Options["ecmaVersion"], undefined>;

const hashStorage: StateStorage = {
getItem: (key): string => {
const searchParams = new URLSearchParams(location.hash.slice(1));
const storedValue = searchParams.get(key) ?? "";
return storedValue ? JSON.parse(atob(storedValue)) : "";
},
setItem: (key, newValue): void => {
const searchParams = new URLSearchParams(location.hash.slice(1));
const encodedValue = btoa(JSON.stringify(newValue));
searchParams.set(key, encodedValue);
location.hash = searchParams.toString();
},
removeItem: (key): void => {
const searchParams = new URLSearchParams(location.hash.slice(1));
searchParams.delete(key);
location.hash = searchParams.toString();
},
};

type ExplorerState = {
tool: "ast" | "scope" | "path";
setTool: (tool: ExplorerState["tool"]) => void;
Expand Down Expand Up @@ -55,59 +80,67 @@ type ExplorerState = {
export const useExplorer = create<ExplorerState>()(
devtools(
persist(
set => ({
tool: "ast",
setTool: tool => set({ tool }),

jsCode: defaultJsCode,
setJsCode: jsCode => set({ jsCode }),

jsonCode: defaultJsonCode,
setJsonCode: jsonCode => set({ jsonCode }),

language: "javascript",
setLanguage: language => set({ language }),

parser: "espree",
setParser: parser => set({ parser }),

sourceType: "module",
setSourceType: sourceType =>
set({ sourceType: sourceType as SourceType }),

esVersion: "latest",
setEsVersion: esVersion =>
set({
esVersion:
esVersion === "latest"
? "latest"
: (Number(esVersion) as Options["ecmaVersion"]),
}),

isJSX: true,
setIsJSX: isJSX => set({ isJSX }),

jsonMode: "jsonc",
setJsonMode: mode => set({ jsonMode: mode }),

wrap: true,
setWrap: wrap => set({ wrap }),

astViewMode: "json",
setAstViewMode: mode => set({ astViewMode: mode }),

scopeViewMode: "flat",
setScopeViewMode: mode => set({ scopeViewMode: mode }),

pathViewMode: "code",
setPathViewMode: mode => set({ pathViewMode: mode }),

pathIndexes: 1,
setPathIndexes: indexes => set({ pathIndexes: indexes }),

pathIndex: 0,
setPathIndex: index => set({ pathIndex: index }),
}),
persist(
set => ({
tool: "ast",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming we are going to be adding many more languages, does it make sense to group language-related settings together rather than having them all be separate, top-level settings?

(Note: I have no idea how any of this works, so I don't have a strong opinion, just curious.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we'll group the options based on the language. I'll update the PR accordingly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change has been made as part of this pr.

setTool: tool => set({ tool }),

jsCode: defaultJsCode,
setJsCode: jsCode => set({ jsCode }),

jsonCode: defaultJsonCode,
setJsonCode: jsonCode => set({ jsonCode }),

language: "javascript",
setLanguage: language => set({ language }),

parser: "espree",
setParser: parser => set({ parser }),

sourceType: "module",
setSourceType: sourceType =>
set({ sourceType: sourceType as SourceType }),

esVersion: "latest",
setEsVersion: esVersion =>
set({
esVersion:
esVersion === "latest"
? "latest"
: (Number(
esVersion,
) as Options["ecmaVersion"]),
}),

isJSX: true,
setIsJSX: isJSX => set({ isJSX }),

jsonMode: "jsonc",
setJsonMode: mode => set({ jsonMode: mode }),

wrap: true,
setWrap: wrap => set({ wrap }),

astViewMode: "json",
setAstViewMode: mode => set({ astViewMode: mode }),

scopeViewMode: "flat",
setScopeViewMode: mode => set({ scopeViewMode: mode }),

pathViewMode: "code",
setPathViewMode: mode => set({ pathViewMode: mode }),

pathIndexes: 1,
setPathIndexes: indexes => set({ pathIndexes: indexes }),

pathIndex: 0,
setPathIndex: index => set({ pathIndex: index }),
}),
{
name: "eslint-explorer",
storage: createJSONStorage(() => hashStorage),
},
),
{
name: "eslint-explorer",
},
Expand Down