bb-relay 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/README.md +47 -0
  3. package/dist/chunk-S47CVTVK.mjs +33 -0
  4. package/dist/chunk-UJCSKKID.mjs +30 -0
  5. package/dist/dev.d.mts +11 -0
  6. package/dist/dev.d.ts +11 -0
  7. package/dist/dev.js +5028 -0
  8. package/dist/dev.mjs +4991 -0
  9. package/dist/index.d.mts +666 -0
  10. package/dist/index.d.ts +666 -0
  11. package/dist/index.js +405 -0
  12. package/dist/index.mjs +376 -0
  13. package/eslint.config.mts +19 -0
  14. package/jest.config.js +11 -0
  15. package/package.json +60 -0
  16. package/src/dev.ts +4 -0
  17. package/src/index.ts +72 -0
  18. package/src/load-virtual-editor/app/StatusState.ts +6 -0
  19. package/src/load-virtual-editor/app/css.ts +154 -0
  20. package/src/load-virtual-editor/app/store.ts +25 -0
  21. package/src/load-virtual-editor/events/handle-dir-update.ts +23 -0
  22. package/src/load-virtual-editor/events/handle-file-update.ts +23 -0
  23. package/src/load-virtual-editor/events/handle-load.ts +39 -0
  24. package/src/load-virtual-editor/events/handle-selected.ts +30 -0
  25. package/src/load-virtual-editor/index.ts +52 -0
  26. package/src/load-virtual-editor/lib/indexedStorage.ts +28 -0
  27. package/src/load-virtual-editor/mocks/generate-files.ts +25 -0
  28. package/src/load-virtual-editor/node/NodeState.ts +23 -0
  29. package/src/load-virtual-editor/node/copyDir.ts +14 -0
  30. package/src/load-virtual-editor/node/copyFile.ts +14 -0
  31. package/src/load-virtual-editor/node/createDir.ts +10 -0
  32. package/src/load-virtual-editor/node/createFile.ts +13 -0
  33. package/src/load-virtual-editor/node/deleteDir.ts +10 -0
  34. package/src/load-virtual-editor/node/deleteFile.ts +13 -0
  35. package/src/load-virtual-editor/node/formatPath.ts +13 -0
  36. package/src/load-virtual-editor/node/formatText.ts +19 -0
  37. package/src/load-virtual-editor/node/generateDirs.ts +13 -0
  38. package/src/load-virtual-editor/node/getDescendantLevel.ts +9 -0
  39. package/src/load-virtual-editor/node/getDirInfo.ts +33 -0
  40. package/src/load-virtual-editor/node/getFileInfo.ts +31 -0
  41. package/src/load-virtual-editor/node/getFiles.ts +17 -0
  42. package/src/load-virtual-editor/node/getParent.ts +11 -0
  43. package/src/load-virtual-editor/node/readDir.ts +41 -0
  44. package/src/load-virtual-editor/node/readFile.ts +46 -0
  45. package/src/load-virtual-editor/node/store.ts +206 -0
  46. package/src/load-virtual-editor/node/watch.ts +9 -0
  47. package/src/load-virtual-editor/node/writeFile.ts +21 -0
  48. package/src/load-virtual-editor/postResponse.ts +21 -0
  49. package/src/load-virtual-editor/request/requestFS.ts +199 -0
  50. package/src/load-virtual-editor/request/requestSelected.ts +45 -0
  51. package/src/load-virtual-editor/selected/SelectedState.ts +7 -0
  52. package/src/load-virtual-editor/selected/selectDir.ts +13 -0
  53. package/src/load-virtual-editor/selected/selectFile.ts +13 -0
  54. package/src/load-virtual-editor/selected/store.ts +27 -0
  55. package/src/load-virtual-editor/selected/watch.ts +9 -0
  56. package/src/locales/en-GB.ts +117 -0
  57. package/src/locales/fr-FR.ts +125 -0
  58. package/src/relay/index.ts +89 -0
  59. package/src/relay/registerEvent.ts +16 -0
  60. package/src/relay/registerRequest.ts +16 -0
  61. package/src/relay/storage-bridge.ts +71 -0
  62. package/src/types/BBEvent.ts +51 -0
  63. package/src/types/BBRequest.ts +8 -0
  64. package/src/types/Checkpoint.ts +11 -0
  65. package/src/types/CopyArg.ts +6 -0
  66. package/src/types/DirectoryContents.ts +4 -0
  67. package/src/types/DirectoryStats.ts +4 -0
  68. package/src/types/EventParam.ts +8 -0
  69. package/src/types/EventReturn.ts +9 -0
  70. package/src/types/FileContent.ts +9 -0
  71. package/src/types/GitFileStatus.ts +5 -0
  72. package/src/types/IconArg.ts +6 -0
  73. package/src/types/Language.ts +5 -0
  74. package/src/types/Locale.ts +3 -0
  75. package/src/types/MenuContent.ts +10 -0
  76. package/src/types/Nav.ts +3 -0
  77. package/src/types/PluginItem.ts +14 -0
  78. package/src/types/RenameType.ts +4 -0
  79. package/src/types/RequestParam.ts +9 -0
  80. package/src/types/RequestReturn.ts +11 -0
  81. package/src/types/Result.ts +6 -0
  82. package/src/types/Route.ts +1 -0
  83. package/src/types/Settings.ts +7 -0
  84. package/src/types/TutorialHeader.ts +10 -0
  85. package/src/types/User.ts +9 -0
  86. package/src/types/WatchFSEvent.ts +1 -0
  87. package/src/types/database.types.ts +266 -0
  88. package/src/types/dir/DirInfo.ts +10 -0
  89. package/src/types/dir/index.ts +32 -0
  90. package/src/types/files/FileInfo.ts +12 -0
  91. package/src/types/files/FileTypes.ts +13 -0
  92. package/src/types/files/ReadFile.ts +17 -0
  93. package/src/types/files/index.ts +31 -0
  94. package/src/types/project/Project.ts +35 -0
  95. package/src/types/project/index.ts +11 -0
  96. package/src/types/status/Load.ts +16 -0
  97. package/src/types/storage/index.ts +11 -0
  98. package/src/utils/inject-styles.ts +13 -0
  99. package/tsconfig.json +20 -0
  100. package/tsup.config.ts +16 -0
@@ -0,0 +1,154 @@
1
+ const css = `@import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
4
+ @custom-variant dark (&:is(.dark *));
5
+
6
+ :root {
7
+ --background: oklch(1 0 0);
8
+ --foreground: oklch(0.145 0 0);
9
+ --card: oklch(1 0 0);
10
+ --card-foreground: oklch(0.145 0 0);
11
+ --popover: oklch(1 0 0);
12
+ --popover-foreground: oklch(0.145 0 0);
13
+ --primary: oklch(0.205 0 0);
14
+ --primary-foreground: oklch(0.985 0 0);
15
+ --secondary: oklch(0.44 0.07 188);
16
+ --secondary-foreground: oklch(0.99 0 0);
17
+ --muted: oklch(0.97 0 0);
18
+ --muted-foreground: oklch(0.556 0 0);
19
+ --accent: oklch(0.97 0 0);
20
+ --accent-foreground: oklch(0.205 0 0);
21
+ --destructive: oklch(0.577 0.245 27.325);
22
+ --destructive-foreground: oklch(0.577 0.245 27.325);
23
+ --border: oklch(0.922 0 0);
24
+ --input: oklch(0.922 0 0);
25
+ --ring: oklch(0.708 0 0);
26
+ --chart-1: oklch(0.646 0.222 41.116);
27
+ --chart-2: oklch(0.6 0.118 184.704);
28
+ --chart-3: oklch(0.398 0.07 227.392);
29
+ --chart-4: oklch(0.828 0.189 84.429);
30
+ --chart-5: oklch(0.769 0.188 70.08);
31
+ --radius: 0.625rem;
32
+ --sidebar: oklch(0.985 0 0);
33
+ --sidebar-foreground: oklch(0.145 0 0);
34
+ --sidebar-primary: oklch(0.205 0 0);
35
+ --sidebar-primary-foreground: oklch(0.985 0 0);
36
+ --sidebar-accent: oklch(0.97 0 0);
37
+ --sidebar-accent-foreground: oklch(0.205 0 0);
38
+ --sidebar-border: oklch(0.922 0 0);
39
+ --sidebar-ring: oklch(0.708 0 0);
40
+ }
41
+
42
+ .dark {
43
+ --background: oklch(0.145 0 0);
44
+ --foreground: oklch(0.985 0 0);
45
+ --card: oklch(0.145 0 0);
46
+ --card-foreground: oklch(0.985 0 0);
47
+ --popover: oklch(0.145 0 0);
48
+ --popover-foreground: oklch(0.985 0 0);
49
+ --primary: oklch(0.985 0 0);
50
+ --primary-foreground: oklch(0.205 0 0);
51
+ --muted: oklch(0.269 0 0);
52
+ --muted-foreground: oklch(0.708 0 0);
53
+ --accent: oklch(0.269 0 0);
54
+ --accent-foreground: oklch(0.985 0 0);
55
+ --destructive: oklch(0.396 0.141 25.723);
56
+ --destructive-foreground: oklch(0.637 0.237 25.331);
57
+ --border: oklch(0.269 0 0);
58
+ --input: oklch(0.269 0 0);
59
+ --ring: oklch(0.439 0 0);
60
+ --chart-1: oklch(0.488 0.243 264.376);
61
+ --chart-2: oklch(0.696 0.17 162.48);
62
+ --chart-3: oklch(0.769 0.188 70.08);
63
+ --chart-4: oklch(0.627 0.265 303.9);
64
+ --chart-5: oklch(0.645 0.246 16.439);
65
+ --sidebar: oklch(0.205 0 0);
66
+ --sidebar-foreground: oklch(0.985 0 0);
67
+ --sidebar-primary: oklch(0.488 0.243 264.376);
68
+ --sidebar-primary-foreground: oklch(0.985 0 0);
69
+ --sidebar-accent: oklch(0.269 0 0);
70
+ --sidebar-accent-foreground: oklch(0.985 0 0);
71
+ --sidebar-border: oklch(0.269 0 0);
72
+ --sidebar-ring: oklch(0.439 0 0);
73
+ }
74
+
75
+ @theme inline {
76
+ --color-background: var(--background);
77
+ --color-foreground: var(--foreground);
78
+ --color-card: var(--card);
79
+ --color-card-foreground: var(--card-foreground);
80
+ --color-popover: var(--popover);
81
+ --color-popover-foreground: var(--popover-foreground);
82
+ --color-primary: var(--primary);
83
+ --color-primary-foreground: var(--primary-foreground);
84
+ --color-secondary: var(--secondary);
85
+ --color-secondary-foreground: var(--secondary-foreground);
86
+ --color-muted: var(--muted);
87
+ --color-muted-foreground: var(--muted-foreground);
88
+ --color-accent: var(--accent);
89
+ --color-accent-foreground: var(--accent-foreground);
90
+ --color-destructive: var(--destructive);
91
+ --color-destructive-foreground: var(--destructive-foreground);
92
+ --color-border: var(--border);
93
+ --color-input: var(--input);
94
+ --color-ring: var(--ring);
95
+ --color-chart-1: var(--chart-1);
96
+ --color-chart-2: var(--chart-2);
97
+ --color-chart-3: var(--chart-3);
98
+ --color-chart-4: var(--chart-4);
99
+ --color-chart-5: var(--chart-5);
100
+ --radius-sm: calc(var(--radius) - 4px);
101
+ --radius-md: calc(var(--radius) - 2px);
102
+ --radius-lg: var(--radius);
103
+ --radius-xl: calc(var(--radius) + 4px);
104
+ --color-sidebar: var(--sidebar);
105
+ --color-sidebar-foreground: var(--sidebar-foreground);
106
+ --color-sidebar-primary: var(--sidebar-primary);
107
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
108
+ --color-sidebar-accent: var(--sidebar-accent);
109
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
110
+ --color-sidebar-border: var(--sidebar-border);
111
+ --color-sidebar-ring: var(--sidebar-ring);
112
+ }
113
+
114
+ @layer base {
115
+ * {
116
+ @apply border-border outline-ring/50;
117
+ }
118
+
119
+ body {
120
+ @apply bg-background text-foreground;
121
+ }
122
+ }
123
+
124
+ body {
125
+ scrollbar-color: var(--muted-foreground);
126
+ }
127
+
128
+ ::-webkit-scrollbar {
129
+ width: 6px;
130
+ height: 12px;
131
+ }
132
+
133
+ ::-webkit-scrollbar-track {
134
+ background: transparent;
135
+ }
136
+
137
+ ::-webkit-scrollbar-thumb {
138
+ background: linear-gradient(to bottom, var(--primary), var(--secondary));
139
+ border-radius: 10px;
140
+ }
141
+
142
+ ::-webkit-scrollbar-thumb:hover {
143
+ background: linear-gradient(to bottom, var(--muted-foreground), var(--secondary));
144
+ }
145
+
146
+ @font-face {
147
+ font-family: "codicon";
148
+ src: url("./codicon.ttf") format("truetype");
149
+ font-weight: normal;
150
+ font-style: normal;
151
+ }
152
+ `;
153
+
154
+ export default css;
@@ -0,0 +1,25 @@
1
+ import { create } from "zustand";
2
+ import { persist } from "zustand/middleware";
3
+ import css from "./css";
4
+ import { StatusState } from "./StatusState";
5
+
6
+ const appStore = create<StatusState>()(
7
+ persist(
8
+ (set) => ({
9
+ language:
10
+ navigator.language ||
11
+ (navigator as unknown as { userLanguage: string }).userLanguage,
12
+ mode: "dark",
13
+ css,
14
+ toggleMode: () =>
15
+ set((state) => ({
16
+ mode: state.mode === "dark" ? "light" : "dark",
17
+ })),
18
+ }),
19
+ {
20
+ name: "status-storage",
21
+ }
22
+ )
23
+ );
24
+
25
+ export default appStore;
@@ -0,0 +1,23 @@
1
+ import EventReturn from "@/types/EventReturn";
2
+ import postResponse from "../postResponse";
3
+ import { watch } from "../node/watch";
4
+
5
+ export default function handleDirUpdate({
6
+ sidebar,
7
+ main,
8
+ }: {
9
+ sidebar: HTMLIFrameElement | null;
10
+ main: HTMLIFrameElement | null;
11
+ }) {
12
+ watch((data) => {
13
+ if (data.dir !== null) {
14
+ const curr: EventReturn<"dir-updated"> = {
15
+ type: "dir-updated",
16
+ response: data.dir,
17
+ responseId: crypto.randomUUID(),
18
+ };
19
+ postResponse(sidebar, curr);
20
+ postResponse(main, curr);
21
+ }
22
+ });
23
+ }
@@ -0,0 +1,23 @@
1
+ import EventReturn from "@/types/EventReturn";
2
+ import postResponse from "../postResponse";
3
+ import { watch } from "../node/watch";
4
+
5
+ export default function handleFileUpdate({
6
+ sidebar,
7
+ main,
8
+ }: {
9
+ sidebar: HTMLIFrameElement | null;
10
+ main: HTMLIFrameElement | null;
11
+ }) {
12
+ watch((data) => {
13
+ if (data.file !== null) {
14
+ const curr: EventReturn<"file-updated"> = {
15
+ type: "file-updated",
16
+ response: data.file,
17
+ responseId: crypto.randomUUID(),
18
+ };
19
+ postResponse(sidebar, curr);
20
+ postResponse(main, curr);
21
+ }
22
+ });
23
+ }
@@ -0,0 +1,39 @@
1
+ import EventReturn from "@/types/EventReturn";
2
+ import appStore from "../app/store";
3
+ import postResponse from "../postResponse";
4
+
5
+ export default function handleLoad({
6
+ sidebar,
7
+ main,
8
+ }: {
9
+ sidebar: HTMLIFrameElement | null;
10
+ main: HTMLIFrameElement | null;
11
+ }) {
12
+ const value = appStore.getState();
13
+ const { mode, css, language } = value;
14
+ const curr: EventReturn<"load"> = {
15
+ type: "load",
16
+ response: {
17
+ mode,
18
+ css,
19
+ language,
20
+ },
21
+ responseId: crypto.randomUUID(),
22
+ };
23
+ postResponse(sidebar, curr);
24
+ postResponse(main, curr);
25
+ appStore.subscribe((state) => {
26
+ const { mode, css, language } = state;
27
+ const curr: EventReturn<"load"> = {
28
+ type: "load",
29
+ response: {
30
+ mode,
31
+ css,
32
+ language,
33
+ },
34
+ responseId: crypto.randomUUID(),
35
+ };
36
+ postResponse(sidebar, curr);
37
+ postResponse(main, curr);
38
+ });
39
+ }
@@ -0,0 +1,30 @@
1
+ import EventReturn from "@/types/EventReturn";
2
+ import postResponse from "../postResponse";
3
+ import selectedStore from "../selected/store";
4
+ import watch from "../selected/watch";
5
+
6
+ export default function handleSelected({
7
+ sidebar,
8
+ main,
9
+ }: {
10
+ sidebar: HTMLIFrameElement | null;
11
+ main: HTMLIFrameElement | null;
12
+ }) {
13
+ const data = selectedStore.getState().selectedPath;
14
+ const curr: EventReturn<"selected"> = {
15
+ type: "selected",
16
+ response: data,
17
+ responseId: crypto.randomUUID(),
18
+ };
19
+ postResponse(sidebar, curr);
20
+ postResponse(main, curr);
21
+ watch((data) => {
22
+ const curr: EventReturn<"selected"> = {
23
+ type: "selected",
24
+ response: data,
25
+ responseId: crypto.randomUUID(),
26
+ };
27
+ postResponse(sidebar, curr);
28
+ postResponse(main, curr);
29
+ });
30
+ }
@@ -0,0 +1,52 @@
1
+ import BBEvent from "@/types/BBEvent";
2
+ import BBRequest from "@/types/BBRequest";
3
+ import handleLoad from "./events/handle-load";
4
+ import requestFS from "./request/requestFS";
5
+ import handleFileUpdate from "./events/handle-file-update";
6
+ import handleDirUpdate from "./events/handle-dir-update";
7
+ import requestSelected from "./request/requestSelected";
8
+ import handleSelected from "./events/handle-selected";
9
+
10
+ type Request<K extends keyof BBRequest> = {
11
+ id: string;
12
+ type: K;
13
+ arg: BBRequest[K]["args"];
14
+ source: "request";
15
+ };
16
+
17
+ type Event<K extends keyof BBEvent> = {
18
+ type: K;
19
+ source: "event";
20
+ };
21
+ export default function loadVirtualEditor({
22
+ sidebar,
23
+ main,
24
+ }: {
25
+ sidebar: HTMLIFrameElement | null;
26
+ main: HTMLIFrameElement | null;
27
+ }) {
28
+ window.addEventListener("message", (event) => {
29
+ const data = event.data as Request<keyof BBRequest> | Event<keyof BBEvent>;
30
+
31
+ if (!data.type) return;
32
+
33
+ if (data.source === "event") {
34
+ if (data.type === "load") {
35
+ handleLoad({ sidebar, main });
36
+ }
37
+ if (data.type === "dir-updated") {
38
+ handleDirUpdate({ sidebar, main });
39
+ }
40
+ if (data.type === "file-updated") {
41
+ handleFileUpdate({ sidebar, main });
42
+ }
43
+ if (data.type === "selected") {
44
+ handleSelected({ sidebar, main });
45
+ }
46
+ }
47
+ if (data.source === "request") {
48
+ requestFS({ sidebar, main, request: data });
49
+ requestSelected({ sidebar, main, request: data });
50
+ }
51
+ });
52
+ }
@@ -0,0 +1,28 @@
1
+ import { openDB } from "idb";
2
+ import type { StateStorage } from "zustand/middleware";
3
+
4
+ const DB_NAME = "zustand-db";
5
+ const STORE_NAME = "store";
6
+
7
+ async function getDB() {
8
+ return openDB(DB_NAME, 1, {
9
+ upgrade(db) {
10
+ db.createObjectStore(STORE_NAME);
11
+ },
12
+ });
13
+ }
14
+
15
+ export const indexedStorage: StateStorage = {
16
+ getItem: async (name: string): Promise<string | null> => {
17
+ const db = await getDB();
18
+ return (await db.get(STORE_NAME, name)) ?? null;
19
+ },
20
+ setItem: async (name: string, value: string): Promise<void> => {
21
+ const db = await getDB();
22
+ await db.put(STORE_NAME, value, name);
23
+ },
24
+ removeItem: async (name: string): Promise<void> => {
25
+ const db = await getDB();
26
+ await db.delete(STORE_NAME, name);
27
+ },
28
+ };
@@ -0,0 +1,25 @@
1
+ import { faker } from "@faker-js/faker";
2
+ import nodeStore from "../node/store";
3
+ const generateFiles = ({
4
+ length = 100,
5
+ content,
6
+ }: { length?: number; content?: boolean | string } = {}) => {
7
+ nodeStore.getState().reset();
8
+ const files: {
9
+ path: string;
10
+ content?: string;
11
+ }[] = [];
12
+ for (let i = 0; i < length; i++) {
13
+ files.push({
14
+ path: faker.system.filePath(),
15
+ content: content
16
+ ? typeof content === "string"
17
+ ? content
18
+ : faker.lorem.paragraph()
19
+ : undefined,
20
+ });
21
+ }
22
+ nodeStore.getState().addFiles(files);
23
+ };
24
+
25
+ export default generateFiles;
@@ -0,0 +1,23 @@
1
+ export type NodeState = {
2
+ directories: string[];
3
+ files: {
4
+ name: string;
5
+ directory: string;
6
+ content: string;
7
+ createdAt: string;
8
+ modifiedAt: string;
9
+ }[];
10
+ addDir: (path: string) => void;
11
+ addFile: (arg: { path: string; content?: string }) => void;
12
+ removeDir: (path: string) => void;
13
+ removeFile: (path: string) => void;
14
+ copyDir: (source: string, destination: string) => void;
15
+ copyFile: (source: string, destination: string) => void;
16
+ writeFile: (arg: { path: string; content: string }) => void;
17
+ record: {
18
+ file: string | null;
19
+ dir: string | null;
20
+ };
21
+ addFiles: (files: { path: string; content?: string }[]) => void;
22
+ reset: () => void;
23
+ };
@@ -0,0 +1,14 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function copyDir(
4
+ source: string,
5
+ destination: string,
6
+ callback: (err: Error | null) => void
7
+ ) {
8
+ try {
9
+ nodeStore.getState().copyDir(source, destination);
10
+ callback(null);
11
+ } catch (err) {
12
+ callback(err as Error);
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function copyFile(
4
+ source: string,
5
+ destination: string,
6
+ callback: (err: Error | null) => void
7
+ ) {
8
+ try {
9
+ nodeStore.getState().copyFile(source, destination);
10
+ callback(null);
11
+ } catch (err) {
12
+ callback(err as Error);
13
+ }
14
+ }
@@ -0,0 +1,10 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function createDir(path: string, callback: (err: Error | null) => void) {
4
+ try {
5
+ nodeStore.getState().addDir(path);
6
+ callback(null);
7
+ } catch (err) {
8
+ callback(err as Error);
9
+ }
10
+ }
@@ -0,0 +1,13 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function createFile(
4
+ arg: { path: string; content?: string },
5
+ callback: (err: Error | null) => void
6
+ ) {
7
+ try {
8
+ nodeStore.getState().addFile(arg);
9
+ callback(null);
10
+ } catch (err) {
11
+ callback(err as Error);
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function deleteDir(path: string, callback: (err: Error | null) => void) {
4
+ try {
5
+ nodeStore.getState().removeDir(path);
6
+ callback(null);
7
+ } catch (err) {
8
+ callback(err as Error);
9
+ }
10
+ }
@@ -0,0 +1,13 @@
1
+ import { nodeStore } from "./store";
2
+
3
+ export function deleteFile(
4
+ path: string,
5
+ callback: (err: Error | null) => void
6
+ ) {
7
+ try {
8
+ nodeStore.getState().removeFile(path);
9
+ callback(null);
10
+ } catch (err) {
11
+ callback(err as Error);
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ const removeSurroundingSlash = (path: string) => {
2
+ const trimmedPath = path.trim();
3
+ if (trimmedPath.endsWith("/")) {
4
+ return removeSurroundingSlash(trimmedPath.slice(0, -1));
5
+ } else if (trimmedPath.startsWith("/")) {
6
+ return removeSurroundingSlash(trimmedPath.slice(1));
7
+ }
8
+ return path;
9
+ };
10
+
11
+ export default function formatPath(path: string) {
12
+ return removeSurroundingSlash(path);
13
+ }
@@ -0,0 +1,19 @@
1
+ export function binaryToString(binary: Uint8Array): string {
2
+ let binaryString = "";
3
+ const chunkSize = 0x8000;
4
+ for (let i = 0; i < binary.length; i += chunkSize) {
5
+ const chunk = binary.subarray(i, i + chunkSize);
6
+ binaryString += String.fromCharCode.apply(null, Array.from(chunk));
7
+ }
8
+ return binaryString;
9
+ }
10
+
11
+ export function stringToBinary(base64: string): Uint8Array<ArrayBuffer> {
12
+ const binaryString = base64;
13
+ const len = binaryString.length;
14
+ const bytes = new Uint8Array(len);
15
+ for (let i = 0; i < len; i++) {
16
+ bytes[i] = binaryString.charCodeAt(i);
17
+ }
18
+ return bytes;
19
+ }
@@ -0,0 +1,13 @@
1
+ import formatPath from "./formatPath";
2
+
3
+ export function generateDirs(path: string, allDirs: string[]) {
4
+ if (allDirs.includes(path)) return allDirs;
5
+ const dirs = path.split("/").filter((item) => item);
6
+ let currentPath = "";
7
+ dirs.forEach((dir) => {
8
+ currentPath += `/${dir}`;
9
+ if (!allDirs.includes(formatPath(currentPath)))
10
+ allDirs.push(formatPath(currentPath));
11
+ });
12
+ return allDirs;
13
+ }
@@ -0,0 +1,9 @@
1
+ export function getDescendantLevel(path1: string, path2: string) {
2
+ const parent = path1.length < path2.length ? path1 : path2;
3
+ const child = path1.length > path2.length ? path1 : path2;
4
+ const descendant = child
5
+ .replace(parent, "")
6
+ .split("/")
7
+ .filter((item) => item);
8
+ return descendant.length;
9
+ }
@@ -0,0 +1,33 @@
1
+ import DirInfo from "@/types/dir/DirInfo";
2
+ import nodeStore from "./store";
3
+ import formatPath from "./formatPath";
4
+
5
+ export function getDirInfo(
6
+ path: string,
7
+ callback: (err: Error | null, data: DirInfo | null) => void
8
+ ) {
9
+ try {
10
+ const dirs = nodeStore.getState().directories;
11
+ const dir = dirs.find((dir) => formatPath(dir) === formatPath(path));
12
+ if (!dir) throw new Error(`Dir not found: ${path}`);
13
+ const files = nodeStore.getState().files;
14
+ const matchedFiles = files.filter(
15
+ (file) => formatPath(file.directory) === formatPath(path)
16
+ );
17
+ const fsCount = matchedFiles.length;
18
+ const size = matchedFiles.reduce((acc, file) => {
19
+ return acc + file.content.length;
20
+ }, 0);
21
+
22
+ callback(null, {
23
+ name: dir.split("/").slice(-1)[0],
24
+ fullPath: dir,
25
+ createdAt: new Date().toISOString(),
26
+ modifiedAt: new Date().toISOString(),
27
+ fsCount,
28
+ size,
29
+ });
30
+ } catch (err) {
31
+ callback(err as Error, null);
32
+ }
33
+ }
@@ -0,0 +1,31 @@
1
+ import formatPath from "./formatPath";
2
+ import FileInfo from "@/types/files/FileInfo";
3
+ import nodeStore from "./store";
4
+
5
+ export function getFileInfo(
6
+ path: string,
7
+ callback: (err: Error | null, data: FileInfo | null) => void
8
+ ) {
9
+ try {
10
+ const files = nodeStore.getState().files;
11
+ const matchedFile = files.find(
12
+ (file) =>
13
+ formatPath(`${file.directory}/${file.name}`) === formatPath(path)
14
+ );
15
+
16
+ if (!matchedFile) throw Error("File not found");
17
+ const fileInfo: FileInfo = {
18
+ name: matchedFile.name,
19
+ fullPath: formatPath(`${matchedFile.directory}/${matchedFile.name}`),
20
+ createdAt: matchedFile.createdAt,
21
+ modifiedAt: matchedFile.modifiedAt,
22
+ ext: matchedFile.name,
23
+ size: matchedFile.content.length,
24
+ wordCount: matchedFile.content.split(" ").length,
25
+ summary: matchedFile.content.slice(0, 100),
26
+ };
27
+ callback(null, fileInfo);
28
+ } catch (err) {
29
+ callback(err as Error, null);
30
+ }
31
+ }
@@ -0,0 +1,17 @@
1
+ import formatPath from "./formatPath";
2
+ import { nodeStore } from "./store";
3
+
4
+ export function getFiles(
5
+ path: string,
6
+ callback: (err: Error | null, data: string[] | null) => void
7
+ ) {
8
+ try {
9
+ const files = nodeStore.getState().files;
10
+ const fileList = files
11
+ .filter((file) => formatPath(file.directory).startsWith(formatPath(path)))
12
+ .map((file) => formatPath(`${file.directory}/${file.name}`));
13
+ callback(null, fileList);
14
+ } catch (err) {
15
+ callback(err as Error, null);
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ import formatPath from "./formatPath";
2
+
3
+ export function getParent(path: string) {
4
+ const fullPath = path
5
+ .trim()
6
+ .split("/")
7
+ .filter((item) => item);
8
+ const dir = fullPath.slice(0, -1);
9
+ const parentPath = formatPath(dir.join("/"));
10
+ return parentPath || "";
11
+ }