@skalfa/skalfa-app-core 1.0.0
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.
- package/dist/api.util.d.ts +49 -0
- package/dist/api.util.js +125 -0
- package/dist/auth.util.d.ts +10 -0
- package/dist/auth.util.js +37 -0
- package/dist/cavity.util.d.ts +20 -0
- package/dist/cavity.util.js +124 -0
- package/dist/cn.util.d.ts +3 -0
- package/dist/cn.util.js +45 -0
- package/dist/commands/barrels.d.ts +1 -0
- package/dist/commands/barrels.js +22 -0
- package/dist/commands/blueprint.d.ts +3 -0
- package/dist/commands/blueprint.js +306 -0
- package/dist/commands/light.d.ts +1 -0
- package/dist/commands/light.js +16 -0
- package/dist/commands/logger.d.ts +10 -0
- package/dist/commands/logger.js +36 -0
- package/dist/commands/use-pdf.d.ts +1 -0
- package/dist/commands/use-pdf.js +17 -0
- package/dist/conversion.util.d.ts +10 -0
- package/dist/conversion.util.js +53 -0
- package/dist/encryption.util.d.ts +6 -0
- package/dist/encryption.util.js +56 -0
- package/dist/form.util.d.ts +87 -0
- package/dist/form.util.js +294 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +79 -0
- package/dist/langs/index.d.ts +1 -0
- package/dist/langs/index.js +1 -0
- package/dist/langs/validation.langs.d.ts +17 -0
- package/dist/langs/validation.langs.js +17 -0
- package/dist/registry/index.d.ts +19 -0
- package/dist/registry/index.js +10 -0
- package/dist/resource.util.d.ts +36 -0
- package/dist/resource.util.js +81 -0
- package/dist/shortcut.util.d.ts +12 -0
- package/dist/shortcut.util.js +22 -0
- package/dist/table.util.d.ts +51 -0
- package/dist/table.util.js +140 -0
- package/dist/validation.util.d.ts +18 -0
- package/dist/validation.util.js +150 -0
- package/package.json +47 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AxiosResponse } from "axios";
|
|
2
|
+
export declare const authBearer: (bearer?: string) => string | null;
|
|
3
|
+
export type ApiFilterType = {
|
|
4
|
+
/** Use filter logic with: "and" / "or". */
|
|
5
|
+
logic?: "and" | "or";
|
|
6
|
+
/** Use filter type with: "eq" = Equal, "ne" = Not Equal, "in" = In, "ni" = Not In, "bw" = Between. */
|
|
7
|
+
type?: "eq" | "ne" | "in" | "ni" | "bw" | "";
|
|
8
|
+
column?: string;
|
|
9
|
+
value?: string | number | number[] | string[] | null;
|
|
10
|
+
};
|
|
11
|
+
export type ApiParamsType = {
|
|
12
|
+
page?: number;
|
|
13
|
+
paginate?: number;
|
|
14
|
+
sort?: string[];
|
|
15
|
+
search?: string;
|
|
16
|
+
searchable?: string[];
|
|
17
|
+
selectable?: string[];
|
|
18
|
+
expand?: string[];
|
|
19
|
+
selectableOption?: string[];
|
|
20
|
+
filter?: ApiFilterType[];
|
|
21
|
+
};
|
|
22
|
+
export type ApiType = {
|
|
23
|
+
path?: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
26
|
+
params?: ApiParamsType;
|
|
27
|
+
payload?: any;
|
|
28
|
+
includeParams?: Record<string, any>;
|
|
29
|
+
headers?: Record<string, any>;
|
|
30
|
+
bearer?: string;
|
|
31
|
+
};
|
|
32
|
+
export declare const ApiFilterValue: {
|
|
33
|
+
eq: string;
|
|
34
|
+
ne: string;
|
|
35
|
+
in: string;
|
|
36
|
+
ni: string;
|
|
37
|
+
bw: string;
|
|
38
|
+
};
|
|
39
|
+
export declare const api: ({ path, url, method, params, payload, includeParams, headers, bearer, }: ApiType) => Promise<AxiosResponse<any, any, {}>>;
|
|
40
|
+
export declare const useGetApi: (props: ApiType & {
|
|
41
|
+
method?: "GET";
|
|
42
|
+
cacheName?: string;
|
|
43
|
+
expired?: number;
|
|
44
|
+
}, sleep?: boolean) => {
|
|
45
|
+
loading: boolean;
|
|
46
|
+
code: number | null;
|
|
47
|
+
data: any;
|
|
48
|
+
reset: () => Promise<"" | undefined>;
|
|
49
|
+
};
|
package/dist/api.util.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import axios from "axios";
|
|
4
|
+
import { redirect } from "next/navigation";
|
|
5
|
+
import { auth } from "./auth.util";
|
|
6
|
+
import { cavity } from "./cavity.util";
|
|
7
|
+
// =========================>
|
|
8
|
+
// ## Build auth bearer
|
|
9
|
+
// =========================>
|
|
10
|
+
export const authBearer = (bearer) => {
|
|
11
|
+
const token = bearer || auth.getAccessToken() || null;
|
|
12
|
+
return token ? `Bearer ${token}` : null;
|
|
13
|
+
};
|
|
14
|
+
// =========================>
|
|
15
|
+
// ## Api error handler
|
|
16
|
+
// =========================>
|
|
17
|
+
const handleErrors = (fetch) => {
|
|
18
|
+
if (fetch?.status === 401)
|
|
19
|
+
redirect(auth.PATH_LOGIN);
|
|
20
|
+
if (fetch?.status === 403)
|
|
21
|
+
redirect(auth.PATH_BASE);
|
|
22
|
+
return fetch;
|
|
23
|
+
};
|
|
24
|
+
// =========================>
|
|
25
|
+
// ## Api filter value
|
|
26
|
+
// =========================>
|
|
27
|
+
export const ApiFilterValue = {
|
|
28
|
+
eq: "eq",
|
|
29
|
+
ne: "ne",
|
|
30
|
+
in: "in",
|
|
31
|
+
ni: "ni",
|
|
32
|
+
bw: "bw",
|
|
33
|
+
};
|
|
34
|
+
// =========================>
|
|
35
|
+
// ## Api fetching handler
|
|
36
|
+
// =========================>
|
|
37
|
+
export const api = async ({ path, url, method, params, payload, includeParams, headers, bearer, }) => {
|
|
38
|
+
const fetchUrl = url || `${process.env.NEXT_PUBLIC_API_HOST}/${path || ""}`;
|
|
39
|
+
const buildHeaders = { Authorization: authBearer(bearer) || "", ...headers };
|
|
40
|
+
buildHeaders["Content-Type"] = buildHeaders["Content-Type"] || "multipart/form-data";
|
|
41
|
+
const filter = {};
|
|
42
|
+
const jsonParams = {};
|
|
43
|
+
if (params?.filter) {
|
|
44
|
+
params?.filter?.map((val) => {
|
|
45
|
+
filter[val.column] = `${ApiFilterValue[val.type]}:${Array.isArray(val.value) ? val.value.join(",") : val.value}`;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (params) {
|
|
49
|
+
const normalizeToJson = ["sort", "searchable", "selectable", "selectableOption", "expand"];
|
|
50
|
+
normalizeToJson.forEach((key) => {
|
|
51
|
+
const k = key;
|
|
52
|
+
if (Array.isArray(params[k])) {
|
|
53
|
+
jsonParams[k] = JSON.stringify(params[k]);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return await axios(fetchUrl, {
|
|
58
|
+
method: method || "GET",
|
|
59
|
+
headers: buildHeaders,
|
|
60
|
+
data: payload,
|
|
61
|
+
params: {
|
|
62
|
+
...params,
|
|
63
|
+
...jsonParams,
|
|
64
|
+
...(params?.filter ? { filter: JSON.stringify(filter) } : {}),
|
|
65
|
+
...includeParams,
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
.then((res) => res)
|
|
69
|
+
.catch((err) => handleErrors(err.response));
|
|
70
|
+
};
|
|
71
|
+
// =========================>
|
|
72
|
+
// ## Hook of get api
|
|
73
|
+
// =========================>
|
|
74
|
+
export const useGetApi = (props, sleep) => {
|
|
75
|
+
const [loading, setLoading] = useState(true);
|
|
76
|
+
const [code, setCode] = useState(null);
|
|
77
|
+
const [data, setData] = useState(null);
|
|
78
|
+
const fetch = async (revalidation = false) => {
|
|
79
|
+
setLoading(true);
|
|
80
|
+
// =========================>
|
|
81
|
+
// ## When cache ready
|
|
82
|
+
// =========================>
|
|
83
|
+
const cacheData = props.expired && !revalidation ? await cavity.get(props.cacheName || `fetch_${props?.path}`) : null;
|
|
84
|
+
if (cacheData) {
|
|
85
|
+
setLoading(false);
|
|
86
|
+
setCode(200);
|
|
87
|
+
setData(cacheData);
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
// =========================>
|
|
91
|
+
// ## Fetch from api
|
|
92
|
+
// =========================>
|
|
93
|
+
const response = await api(props);
|
|
94
|
+
if (response?.status) {
|
|
95
|
+
setLoading(false);
|
|
96
|
+
setCode(response?.status);
|
|
97
|
+
setData(response?.data);
|
|
98
|
+
// =========================>
|
|
99
|
+
// ## Save to cache
|
|
100
|
+
// =========================>
|
|
101
|
+
if (props.expired)
|
|
102
|
+
cavity.set({ key: props?.cacheName || `fetch_${props?.path}`, data: response?.data, expired: props.expired });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!sleep && (props.path || props.url))
|
|
107
|
+
fetch();
|
|
108
|
+
}, [
|
|
109
|
+
props.path,
|
|
110
|
+
props.url,
|
|
111
|
+
props.params?.paginate,
|
|
112
|
+
props.params?.page,
|
|
113
|
+
props.params?.search,
|
|
114
|
+
props.params?.sort,
|
|
115
|
+
props.params?.filter,
|
|
116
|
+
props.params?.selectable,
|
|
117
|
+
props.params?.selectableOption,
|
|
118
|
+
props.includeParams,
|
|
119
|
+
props.headers,
|
|
120
|
+
props.bearer,
|
|
121
|
+
sleep
|
|
122
|
+
]);
|
|
123
|
+
const reset = () => fetch(true);
|
|
124
|
+
return { loading, code, data, reset };
|
|
125
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const auth: {
|
|
2
|
+
PATH_LOGIN: string;
|
|
3
|
+
PATH_BASE: string;
|
|
4
|
+
ACCESS_TOKEN_EXPIRED: number;
|
|
5
|
+
ACCESS_TOKEN_NAME: string;
|
|
6
|
+
setAccessToken: (token: string | null, expired?: number) => string | undefined;
|
|
7
|
+
getAccessToken: () => any;
|
|
8
|
+
deleteAccessToken: () => void;
|
|
9
|
+
check: () => false;
|
|
10
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation';
|
|
2
|
+
import Cookies from 'js-cookie';
|
|
3
|
+
import { encryption } from './encryption.util';
|
|
4
|
+
export const auth = {
|
|
5
|
+
// ==============================>
|
|
6
|
+
// ## Path of login page
|
|
7
|
+
// ==============================>
|
|
8
|
+
PATH_LOGIN: '/auth/login',
|
|
9
|
+
// ==============================>
|
|
10
|
+
// ## Path of home page
|
|
11
|
+
// ==============================>
|
|
12
|
+
PATH_BASE: '/',
|
|
13
|
+
// ==============================>
|
|
14
|
+
// ## Access token expired (days)
|
|
15
|
+
// ==============================>
|
|
16
|
+
ACCESS_TOKEN_EXPIRED: 7,
|
|
17
|
+
// ==============================>
|
|
18
|
+
// ## Name of cookie access token
|
|
19
|
+
// ==============================>
|
|
20
|
+
ACCESS_TOKEN_NAME: String(process.env.NEXT_PUBLIC_APP_NAME || '').toLowerCase().trim().replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, '-').replace(/^-+|-+$/g, '') + '.user.token',
|
|
21
|
+
// ==============================>
|
|
22
|
+
// ## set access token to cookie
|
|
23
|
+
// ==============================>
|
|
24
|
+
setAccessToken: (token, expired) => Cookies.set(auth.ACCESS_TOKEN_NAME, token ? encryption.set(token) : "", { expires: expired || auth.ACCESS_TOKEN_EXPIRED, secure: true }),
|
|
25
|
+
// ==============================>
|
|
26
|
+
// ## get access token from cookie
|
|
27
|
+
// ==============================>
|
|
28
|
+
getAccessToken: () => encryption.get(Cookies.get(auth.ACCESS_TOKEN_NAME) || ""),
|
|
29
|
+
// ==============================>
|
|
30
|
+
// ## delete access token from cookie
|
|
31
|
+
// ==============================>
|
|
32
|
+
deleteAccessToken: () => Cookies.remove(auth.ACCESS_TOKEN_NAME),
|
|
33
|
+
// ==============================>
|
|
34
|
+
// ## Check auth
|
|
35
|
+
// ==============================>
|
|
36
|
+
check: () => (!Cookies.get(auth.ACCESS_TOKEN_NAME)) && redirect(auth.PATH_LOGIN),
|
|
37
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type CavityType = {
|
|
2
|
+
key: string;
|
|
3
|
+
data: any;
|
|
4
|
+
expired: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const cavity: {
|
|
7
|
+
set: ({ key, data, expired }: CavityType) => Promise<() => void>;
|
|
8
|
+
get: (key: string) => Promise<{
|
|
9
|
+
message: string;
|
|
10
|
+
data: Record<string, any>;
|
|
11
|
+
}>;
|
|
12
|
+
delete: (key: string) => Promise<() => void>;
|
|
13
|
+
socket: {
|
|
14
|
+
register: () => void;
|
|
15
|
+
subscribe(key: string): void;
|
|
16
|
+
unsubscribe(key: string): void;
|
|
17
|
+
invalidate(key: string): void;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { registry } from "./registry";
|
|
2
|
+
import { logger } from "./commands/logger";
|
|
3
|
+
const name = String(process.env.NEXT_PUBLIC_APP_NAME || "").toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "") + ".cavity";
|
|
4
|
+
const storeName = "cache";
|
|
5
|
+
const version = 1;
|
|
6
|
+
const subscriptions = new Set();
|
|
7
|
+
let registered = false;
|
|
8
|
+
function getSocket() {
|
|
9
|
+
const s = registry.get("socket");
|
|
10
|
+
if (s && process.env.NEXT_PUBLIC_SOCKET_URL) {
|
|
11
|
+
return s.connect();
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// ==============================>
|
|
16
|
+
// ## Init indexDb
|
|
17
|
+
// ==============================>
|
|
18
|
+
async function idb() {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const request = indexedDB.open(name, version);
|
|
21
|
+
request.onupgradeneeded = () => {
|
|
22
|
+
const db = request.result;
|
|
23
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
24
|
+
db.createObjectStore(storeName, { keyPath: "key" });
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
request.onsuccess = () => resolve(request.result);
|
|
28
|
+
request.onerror = () => reject(request.error);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export const cavity = {
|
|
32
|
+
// ==============================>
|
|
33
|
+
// ## Set cache to indexDb
|
|
34
|
+
// ==============================>
|
|
35
|
+
set: async ({ key, data, expired }) => {
|
|
36
|
+
const db = await idb();
|
|
37
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
38
|
+
const store = tx.objectStore(storeName);
|
|
39
|
+
const item = {
|
|
40
|
+
key,
|
|
41
|
+
expired: new Date().getTime() + expired * 60 * 1000,
|
|
42
|
+
data,
|
|
43
|
+
};
|
|
44
|
+
store.put(item);
|
|
45
|
+
return tx.commit;
|
|
46
|
+
},
|
|
47
|
+
// ==============================>
|
|
48
|
+
// ## Get cache from indexDb
|
|
49
|
+
// ==============================>
|
|
50
|
+
get: async (key) => {
|
|
51
|
+
const db = await idb();
|
|
52
|
+
const tx = db.transaction(storeName, "readonly");
|
|
53
|
+
const store = tx.objectStore(storeName);
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const request = store.get(key);
|
|
56
|
+
request.onsuccess = () => {
|
|
57
|
+
const item = request.result;
|
|
58
|
+
if (!item)
|
|
59
|
+
return resolve({ message: "Record not found!", data: [] });
|
|
60
|
+
if (item.expired > Date.now()) {
|
|
61
|
+
resolve(item.data);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const deleteTx = db.transaction(storeName, "readwrite");
|
|
65
|
+
deleteTx.objectStore(storeName).delete(key);
|
|
66
|
+
resolve({ message: "Record not found!", data: [] });
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
request.onerror = () => resolve({ message: "Error!", data: [] });
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
// ==============================>
|
|
73
|
+
// ## Remove cache from indexDb
|
|
74
|
+
// ==============================>
|
|
75
|
+
delete: async (key) => {
|
|
76
|
+
const db = await idb();
|
|
77
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
78
|
+
const store = tx.objectStore(storeName);
|
|
79
|
+
store.delete(key);
|
|
80
|
+
return tx.commit;
|
|
81
|
+
},
|
|
82
|
+
socket: {
|
|
83
|
+
register: () => {
|
|
84
|
+
const socket = getSocket();
|
|
85
|
+
if (registered || !socket)
|
|
86
|
+
return;
|
|
87
|
+
registered = true;
|
|
88
|
+
socket.on("cache:invalidate", async ({ key }) => {
|
|
89
|
+
await cavity.delete(key);
|
|
90
|
+
});
|
|
91
|
+
socket.on("connect", () => {
|
|
92
|
+
logger.cavity("WS connected:", socket.id);
|
|
93
|
+
subscriptions.forEach((key) => cavity.socket.subscribe(key));
|
|
94
|
+
});
|
|
95
|
+
socket.on("disconnect", (reason) => {
|
|
96
|
+
logger.cavityError("WS disconnected:", reason);
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
subscribe(key) {
|
|
100
|
+
const socket = getSocket();
|
|
101
|
+
if (!socket?.connected)
|
|
102
|
+
return;
|
|
103
|
+
if (subscriptions.has(key))
|
|
104
|
+
return;
|
|
105
|
+
subscriptions.add(key);
|
|
106
|
+
socket.emit("cache:subscribe", { key });
|
|
107
|
+
},
|
|
108
|
+
unsubscribe(key) {
|
|
109
|
+
const socket = getSocket();
|
|
110
|
+
if (!socket?.connected)
|
|
111
|
+
return;
|
|
112
|
+
if (!subscriptions.has(key))
|
|
113
|
+
return;
|
|
114
|
+
subscriptions.delete(key);
|
|
115
|
+
socket.emit("cache:unsubscribe", { key });
|
|
116
|
+
},
|
|
117
|
+
invalidate(key) {
|
|
118
|
+
const socket = getSocket();
|
|
119
|
+
if (!socket?.connected)
|
|
120
|
+
return;
|
|
121
|
+
socket.emit("cache:invalidate", { key });
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
};
|
package/dist/cn.util.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
// ==============================>
|
|
4
|
+
// ## Merge class name
|
|
5
|
+
// ==============================>
|
|
6
|
+
export const cn = (...classes) => twMerge(clsx(classes));
|
|
7
|
+
// ==============================>
|
|
8
|
+
// ## Parse class name with custom prefix
|
|
9
|
+
// ==============================>
|
|
10
|
+
export const pcn = (className, prefix, pseudoClass) => {
|
|
11
|
+
const classes = className.split(" ");
|
|
12
|
+
const matchedClasses = classes.filter((cls) => {
|
|
13
|
+
const [clsPrefix, ...rest] = cls.split("::");
|
|
14
|
+
if (rest.length === 0 && (prefix === "input" || prefix === "base"))
|
|
15
|
+
return true;
|
|
16
|
+
if (rest.length > 0 && clsPrefix === prefix) {
|
|
17
|
+
if (pseudoClass) {
|
|
18
|
+
const [pseudo] = rest.join("::").split(":");
|
|
19
|
+
return pseudo === pseudoClass;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}).map((cls) => {
|
|
25
|
+
const [clsPrefix, ...rest] = cls.split("::");
|
|
26
|
+
if (rest.length > 0 && clsPrefix === prefix) {
|
|
27
|
+
const classNameWithoutPrefix = rest.join("::");
|
|
28
|
+
if (pseudoClass) {
|
|
29
|
+
return classNameWithoutPrefix.split(":").slice(1).join(":");
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
if (/^(?!.*\b\w+:).*$/.test(classNameWithoutPrefix)) {
|
|
33
|
+
return classNameWithoutPrefix;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (rest.length === 0 && (prefix === "input" || prefix === "base"))
|
|
41
|
+
return cls;
|
|
42
|
+
return "";
|
|
43
|
+
}).filter(Boolean);
|
|
44
|
+
return matchedClasses.join(" ");
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { exec } from "child_process";
|
|
4
|
+
import { logger } from "./logger";
|
|
5
|
+
const rootDir = path.resolve();
|
|
6
|
+
const configText = fs.readFileSync("barrels.json", "utf8");
|
|
7
|
+
const config = JSON.parse(configText);
|
|
8
|
+
const directories = Array.isArray(config.directory) ? config.directory : [config.directory];
|
|
9
|
+
directories.forEach((dir) => {
|
|
10
|
+
const absoluteDir = path.join(rootDir, dir);
|
|
11
|
+
if (!fs.existsSync(absoluteDir)) {
|
|
12
|
+
logger.error(`Barrels error: ${absoluteDir} directory not found`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
fs.watch(absoluteDir, { recursive: true }, (_, filename) => {
|
|
16
|
+
if (filename && (filename.endsWith(".ts") || filename.endsWith(".tsx")) && filename !== "index.ts") {
|
|
17
|
+
exec("npx barrelsby -c barrels.json", { cwd: rootDir });
|
|
18
|
+
logger.info("Barrels updated " + absoluteDir + "/index.ts");
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
logger.start("Barrels watched " + directories.join(", "));
|