@sidekick-coder/zenith-kit 0.0.1 → 0.0.5

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/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Zenith-kit
2
+
3
+ Services and tools for the Zenith project.
package/artisan.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander'
4
+ import { readdirSync } from 'fs'
5
+ import { resolve, dirname } from 'path'
6
+ import { fileURLToPath, pathToFileURL } from 'url'
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url))
9
+
10
+ const program = new Command()
11
+
12
+ program
13
+ .name('artisan')
14
+ .description('CLI tool for sc_zenith-kit')
15
+
16
+ const commandsDir = resolve(__dirname, 'commands')
17
+
18
+ for (const file of readdirSync(commandsDir)) {
19
+ if (!file.endsWith('.js')) continue
20
+
21
+ const mod = await import(pathToFileURL(resolve(commandsDir, file)).href)
22
+
23
+ program.addCommand(mod.default)
24
+ }
25
+
26
+ program.parse(process.argv)
@@ -0,0 +1,75 @@
1
+ import { Command } from 'commander'
2
+ import { execSync, spawnSync } from 'child_process'
3
+ import readline from 'readline'
4
+
5
+ function exec(cmd) {
6
+ return execSync(cmd, { encoding: 'utf-8' }).trim()
7
+ }
8
+
9
+ function run(cmd, args = []) {
10
+ const result = spawnSync(cmd, args, { stdio: 'inherit' })
11
+
12
+ if (result.status !== 0) {
13
+ process.exit(result.status ?? 1)
14
+ }
15
+ }
16
+
17
+ function ask(question, choices) {
18
+ return new Promise((resolve) => {
19
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
20
+
21
+ const list = choices.map((c, i) => ` ${i + 1}) ${c}`).join('\n')
22
+
23
+ rl.question(`${question}\n${list}\n> `, (answer) => {
24
+ rl.close()
25
+ const index = parseInt(answer, 10) - 1
26
+
27
+ if (index >= 0 && index < choices.length) {
28
+ resolve(choices[index])
29
+ } else {
30
+ console.error('Invalid choice.')
31
+ process.exit(1)
32
+ }
33
+ })
34
+ })
35
+ }
36
+
37
+ const command = new Command('release')
38
+
39
+ command
40
+ .description('Bump version, publish to npm and push to origin')
41
+ .option('--patch', 'Bump patch version')
42
+ .option('--minor', 'Bump minor version')
43
+ .option('--major', 'Bump major version')
44
+ .action(async (options) => {
45
+ const staged = exec('git diff --cached --name-only')
46
+ const unstaged = exec('git diff --name-only')
47
+
48
+ if (staged || unstaged) {
49
+ console.error('Error: there are uncommitted changes. Please commit or stash them before releasing.')
50
+ process.exit(1)
51
+ }
52
+
53
+ let bump
54
+
55
+ if (options.patch) bump = 'patch'
56
+ else if (options.minor) bump = 'minor'
57
+ else if (options.major) bump = 'major'
58
+ else bump = await ask('Select version bump type:', ['patch', 'minor', 'major'])
59
+
60
+ console.log(`\nBumping ${bump} version...`)
61
+ run('npm', ['version', bump])
62
+
63
+ console.log('\nBuilding...')
64
+ run('npm', ['run', 'build', '--', '--dts'])
65
+
66
+ console.log('\nPublishing to npm...')
67
+ run('npm', ['publish'])
68
+
69
+ console.log('\nPushing commit and tag to origin...')
70
+ run('git', ['push', '--follow-tags'])
71
+
72
+ console.log('\nRelease complete.')
73
+ })
74
+
75
+ export default command
@@ -1,5 +1,84 @@
1
1
  import { ChildProcess } from "node:child_process";
2
2
 
3
+ //#region src/server/gateways/GitGateway.d.ts
4
+ interface GitRepoInfo {
5
+ directory: string;
6
+ head: string | null;
7
+ shortHash: string;
8
+ isDetachedHead: boolean;
9
+ remotes: string[];
10
+ }
11
+ interface GitGatewayOptions {
12
+ cwd: string;
13
+ sshKey?: string;
14
+ }
15
+ declare class GitGateway {
16
+ private readonly cwd;
17
+ private readonly env?;
18
+ constructor({
19
+ cwd,
20
+ sshKey
21
+ }: GitGatewayOptions);
22
+ run(args: string): Promise<string>;
23
+ tryRun(args: string): Promise<string | null>;
24
+ checkout(ref: string): Promise<void>;
25
+ fetch(): Promise<void>;
26
+ pull(): Promise<void>;
27
+ getInfo(): Promise<GitRepoInfo>;
28
+ }
29
+ //#endregion
30
+ //#region src/server/services/GitBranchRepository.d.ts
31
+ interface GitBranch {
32
+ name: string;
33
+ remote: string | null;
34
+ isCurrent: boolean;
35
+ isRemote: boolean;
36
+ }
37
+ interface GitBranchFetchOptions {
38
+ remote: string;
39
+ branch: string;
40
+ localName?: string;
41
+ }
42
+ declare class GitBranchRepository {
43
+ private readonly gateway;
44
+ constructor(gateway: GitGateway);
45
+ list(): Promise<GitBranch[]>;
46
+ fetch(options: GitBranchFetchOptions): Promise<void>;
47
+ }
48
+ //#endregion
49
+ //#region src/server/services/GitCommitRepository.d.ts
50
+ interface GitCommitRef {
51
+ name: string;
52
+ shortName: string;
53
+ type: 'branch' | 'tag' | 'remote' | 'other';
54
+ }
55
+ interface GitCommit {
56
+ hash: string;
57
+ shortHash: string;
58
+ authorName: string;
59
+ authorEmail: string;
60
+ date: string;
61
+ message: string;
62
+ refs: GitCommitRef[];
63
+ }
64
+ interface GitCommitListOptions {
65
+ branch?: string;
66
+ page?: number;
67
+ perPage?: number;
68
+ }
69
+ interface PaginatedCommits {
70
+ items: GitCommit[];
71
+ total: number;
72
+ page: number;
73
+ perPage: number;
74
+ totalPages: number;
75
+ }
76
+ declare class GitCommitRepository {
77
+ private readonly gateway;
78
+ constructor(gateway: GitGateway);
79
+ list(options?: GitCommitListOptions): Promise<PaginatedCommits>;
80
+ }
81
+ //#endregion
3
82
  //#region src/server/services/PluginIpcClient.d.ts
4
83
  type IpcMessage<T = any> = {
5
84
  id: string;
@@ -9,12 +88,10 @@ type IpcMessage<T = any> = {
9
88
  type IpcListener$1<T = any> = (data: T) => void;
10
89
  declare class PluginIpcClient {
11
90
  private listeners;
12
- private pending;
13
91
  constructor();
14
92
  on<T = any>(event: string, callback: IpcListener$1<T>): void;
15
93
  off<T = any>(event: string, callback: IpcListener$1<T>): void;
16
94
  emit<T = any>(event: string, data?: T): string;
17
- emitAsync<TData = any, TReply = any>(event: string, data?: TData): Promise<TReply>;
18
95
  }
19
96
  //#endregion
20
97
  //#region src/server/services/PluginIpcHost.d.ts
@@ -22,12 +99,10 @@ type IpcListener<T = any> = (data: T) => void;
22
99
  declare class PluginIpcHost {
23
100
  private readonly child;
24
101
  private listeners;
25
- private pending;
26
102
  constructor(child: ChildProcess);
27
103
  on<T = any>(event: string, callback: IpcListener<T>): void;
28
104
  off<T = any>(event: string, callback: IpcListener<T>): void;
29
105
  emit<T = any>(event: string, data?: T): string;
30
- emitAsync<TData = any, TReply = any>(event: string, data?: TData): Promise<TReply>;
31
106
  }
32
107
  //#endregion
33
108
  //#region src/server/services/PluginRouter.d.ts
@@ -69,4 +144,4 @@ declare class PluginRouter {
69
144
  delete(path: string, handler: RouteHandler): void;
70
145
  }
71
146
  //#endregion
72
- export { HttpMethod, IpcMessage, PluginIpcClient, PluginIpcHost, PluginRouter, RouteDefinition, RouteHandler, RouteReply, RouteRequest, RouteResponsePayload };
147
+ export { GitBranch, GitBranchFetchOptions, GitBranchRepository, GitCommit, GitCommitListOptions, GitCommitRef, GitCommitRepository, GitGateway, GitGatewayOptions, GitRepoInfo, HttpMethod, IpcMessage, PaginatedCommits, PluginIpcClient, PluginIpcHost, PluginRouter, RouteDefinition, RouteHandler, RouteReply, RouteRequest, RouteResponsePayload };
@@ -1,3 +1,116 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ //#region src/server/services/GitBranchRepository.ts
4
+ var GitBranchRepository = class {
5
+ constructor(gateway) {
6
+ this.gateway = gateway;
7
+ }
8
+ async list() {
9
+ return (await this.gateway.run(`branch -a --format='%(HEAD)|%(refname:short)|%(refname)|%(upstream:remotename)'`)).split("\n").filter(Boolean).filter((line) => line.includes("|")).map((line) => {
10
+ const [head, refShort, refFull, remoteName] = line.split("|");
11
+ const isRemote = refFull.startsWith("refs/remotes/");
12
+ const name = refShort;
13
+ return {
14
+ name,
15
+ remote: isRemote ? name.split("/")[0] : remoteName || null,
16
+ isCurrent: head === "*",
17
+ isRemote
18
+ };
19
+ });
20
+ }
21
+ async fetch(options) {
22
+ const { remote, branch, localName } = options;
23
+ const local = localName ?? branch;
24
+ await this.gateway.run(`fetch ${remote} ${branch}:${local}`);
25
+ }
26
+ };
27
+ //#endregion
28
+ //#region src/server/services/GitCommitRepository.ts
29
+ const LOG_FORMAT = [
30
+ "%H",
31
+ "%h",
32
+ "%an",
33
+ "%ae",
34
+ "%aI",
35
+ "%s",
36
+ "%D"
37
+ ].join("%x09");
38
+ function parseDecorations(decorStr) {
39
+ if (!decorStr.trim()) return [];
40
+ const refs = [];
41
+ for (const part of decorStr.split(", ")) {
42
+ const trimmed = part.trim();
43
+ if (!trimmed) continue;
44
+ if (trimmed.startsWith("HEAD -> ")) {
45
+ const shortName = trimmed.slice(8);
46
+ refs.push({
47
+ name: "HEAD",
48
+ shortName: "HEAD",
49
+ type: "other"
50
+ });
51
+ refs.push({
52
+ name: `refs/heads/${shortName}`,
53
+ shortName,
54
+ type: "branch"
55
+ });
56
+ } else if (trimmed.startsWith("tag: ")) {
57
+ const shortName = trimmed.slice(5);
58
+ refs.push({
59
+ name: `refs/tags/${shortName}`,
60
+ shortName,
61
+ type: "tag"
62
+ });
63
+ } else if (trimmed === "HEAD") refs.push({
64
+ name: "HEAD",
65
+ shortName: "HEAD",
66
+ type: "other"
67
+ });
68
+ else if (trimmed.includes("/")) refs.push({
69
+ name: `refs/remotes/${trimmed}`,
70
+ shortName: trimmed,
71
+ type: "remote"
72
+ });
73
+ else refs.push({
74
+ name: `refs/heads/${trimmed}`,
75
+ shortName: trimmed,
76
+ type: "branch"
77
+ });
78
+ }
79
+ return refs;
80
+ }
81
+ var GitCommitRepository = class {
82
+ constructor(gateway) {
83
+ this.gateway = gateway;
84
+ }
85
+ async list(options) {
86
+ const page = options?.page ?? 1;
87
+ const perPage = options?.perPage ?? 20;
88
+ const ref = options?.branch ?? "HEAD";
89
+ const all = (await this.gateway.run(`log ${ref} --format='${LOG_FORMAT}'`)).split("\n").filter(Boolean).map((line) => {
90
+ const [hash, shortHash, authorName, authorEmail, date, message, decorStr = ""] = line.split(" ");
91
+ return {
92
+ hash,
93
+ shortHash,
94
+ authorName,
95
+ authorEmail,
96
+ date,
97
+ message,
98
+ refs: parseDecorations(decorStr)
99
+ };
100
+ });
101
+ const total = all.length;
102
+ const totalPages = Math.ceil(total / perPage);
103
+ const start = (page - 1) * perPage;
104
+ return {
105
+ items: all.slice(start, start + perPage),
106
+ total,
107
+ page,
108
+ perPage,
109
+ totalPages
110
+ };
111
+ }
112
+ };
113
+ //#endregion
1
114
  //#region src/shared/utils/createId.ts
2
115
  function uuid() {
3
116
  if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
@@ -15,13 +128,8 @@ function createId(prefix = "") {
15
128
  //#region src/server/services/PluginIpcClient.ts
16
129
  var PluginIpcClient = class {
17
130
  listeners = /* @__PURE__ */ new Map();
18
- pending = /* @__PURE__ */ new Map();
19
131
  constructor() {
20
132
  process.on("message", (message) => {
21
- if (this.pending.has(message.id)) {
22
- this.pending.get(message.id)(message.data);
23
- this.pending.delete(message.id);
24
- }
25
133
  const handlers = this.listeners.get(message.event);
26
134
  if (!handlers) return;
27
135
  for (const handler of handlers) handler(message.data);
@@ -45,25 +153,14 @@ var PluginIpcClient = class {
45
153
  process.send(message);
46
154
  return id;
47
155
  }
48
- emitAsync(event, data) {
49
- return new Promise((resolve) => {
50
- const id = this.emit(event, data);
51
- this.pending.set(id, resolve);
52
- });
53
- }
54
156
  };
55
157
  //#endregion
56
158
  //#region src/server/services/PluginIpcHost.ts
57
159
  var PluginIpcHost = class {
58
160
  listeners = /* @__PURE__ */ new Map();
59
- pending = /* @__PURE__ */ new Map();
60
161
  constructor(child) {
61
162
  this.child = child;
62
163
  this.child.on("message", (message) => {
63
- if (this.pending.has(message.id)) {
64
- this.pending.get(message.id)(message.data);
65
- this.pending.delete(message.id);
66
- }
67
164
  const handlers = this.listeners.get(message.event);
68
165
  if (!handlers) return;
69
166
  for (const handler of handlers) handler(message.data);
@@ -87,12 +184,6 @@ var PluginIpcHost = class {
87
184
  this.child.send(message);
88
185
  return id;
89
186
  }
90
- emitAsync(event, data) {
91
- return new Promise((resolve) => {
92
- const id = this.emit(event, data);
93
- this.pending.set(id, resolve);
94
- });
95
- }
96
187
  };
97
188
  //#endregion
98
189
  //#region src/server/services/PluginRouter.ts
@@ -182,4 +273,59 @@ var PluginRouter = class {
182
273
  }
183
274
  };
184
275
  //#endregion
185
- export { PluginIpcClient, PluginIpcHost, PluginRouter };
276
+ //#region src/server/gateways/GitGateway.ts
277
+ const execAsync = promisify(exec);
278
+ function escapeShellArgument(value) {
279
+ return `'${value.replace(/'/g, `'\\''`)}'`;
280
+ }
281
+ var GitGateway = class {
282
+ cwd;
283
+ env;
284
+ constructor({ cwd, sshKey }) {
285
+ this.cwd = cwd;
286
+ this.env = sshKey ? {
287
+ ...process.env,
288
+ GIT_SSH_COMMAND: `ssh -i ${escapeShellArgument(sshKey)} -o StrictHostKeyChecking=no`
289
+ } : void 0;
290
+ }
291
+ async run(args) {
292
+ const { stdout } = await execAsync(`git ${args}`, {
293
+ cwd: this.cwd,
294
+ env: this.env
295
+ });
296
+ return stdout.trim();
297
+ }
298
+ async tryRun(args) {
299
+ try {
300
+ return await this.run(args);
301
+ } catch {
302
+ return null;
303
+ }
304
+ }
305
+ async checkout(ref) {
306
+ await this.run(`checkout ${ref}`);
307
+ }
308
+ async fetch() {
309
+ await this.run("fetch --all --prune");
310
+ }
311
+ async pull() {
312
+ await this.fetch();
313
+ if (await this.tryRun("rev-parse --abbrev-ref --symbolic-full-name @{upstream}")) await this.run("pull --ff-only");
314
+ }
315
+ async getInfo() {
316
+ const head = await this.run("rev-parse --abbrev-ref HEAD");
317
+ const isDetachedHead = head === "HEAD";
318
+ const shortHash = await this.run("rev-parse --short HEAD");
319
+ const remotesOutput = await this.tryRun("remote");
320
+ const remotes = remotesOutput ? remotesOutput.split("\n").filter(Boolean) : [];
321
+ return {
322
+ directory: this.cwd,
323
+ head: isDetachedHead ? null : head,
324
+ shortHash,
325
+ isDetachedHead,
326
+ remotes
327
+ };
328
+ }
329
+ };
330
+ //#endregion
331
+ export { GitBranchRepository, GitCommitRepository, GitGateway, PluginIpcClient, PluginIpcHost, PluginRouter };
@@ -90,6 +90,9 @@ declare function unflatten(obj: any): Record<string, any>;
90
90
  //#region src/shared/utils/formatBytes.d.ts
91
91
  declare function formatBytes(bytes: number, decimals?: number): string;
92
92
  //#endregion
93
+ //#region src/shared/utils/generateIndexFile.d.ts
94
+ declare function generateIndexFile(options: any): void;
95
+ //#endregion
93
96
  //#region src/shared/utils/tryCatch.d.ts
94
97
  interface Tryer {
95
98
  (...args: any[]): any;
@@ -104,4 +107,4 @@ declare namespace tryCatch {
104
107
  var sync: <T extends Tryer>(tryer: T) => TryCatchResult<T>;
105
108
  }
106
109
  //#endregion
107
- export { AnyClass, Constructor, EmmitterServiceOptions, Mixin, PartialBy, PublicData, UnionToIntersection, Valibot, ValibotSchema, ValibotSchemaAsync, ValidatePayload, ValidateResult, ValidatorCallback, ValidatorCallbackAsync, ValidatorResult, ValidatorService, compose, composeWith, createId, flatten, formatBytes, mixin, tryCatch, unflatten };
110
+ export { AnyClass, Constructor, EmmitterServiceOptions, Mixin, PartialBy, PublicData, UnionToIntersection, Valibot, ValibotSchema, ValibotSchemaAsync, ValidatePayload, ValidateResult, ValidatorCallback, ValidatorCallbackAsync, ValidatorResult, ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
@@ -1,5 +1,8 @@
1
1
  import "lodash-es";
2
2
  import * as v from "valibot";
3
+ import fg from "fast-glob";
4
+ import fs from "fs";
5
+ import path from "path";
3
6
  //#region src/shared/utils/compose.ts
4
7
  /**
5
8
  * Composes multiple mixins into a single class that can be extended.
@@ -184,4 +187,20 @@ var ValidatorService = class {
184
187
  };
185
188
  new ValidatorService();
186
189
  //#endregion
187
- export { ValidatorService, compose, composeWith, createId, flatten, formatBytes, mixin, tryCatch, unflatten };
190
+ //#region src/shared/utils/generateIndexFile.ts
191
+ function generateIndexFile(options) {
192
+ const folders = options.folders;
193
+ const filename = options.filename;
194
+ let content = "";
195
+ for (const folder of folders) {
196
+ const files = fg.sync(`${folder}/**/*.ts`, { ignore: ["**/index.ts"] });
197
+ for (const file of files) {
198
+ const filePath = path.relative(path.dirname(filename), file);
199
+ content += `export * from './${filePath}'\n`;
200
+ }
201
+ }
202
+ content = content.trim();
203
+ fs.writeFileSync(filename, content);
204
+ }
205
+ //#endregion
206
+ export { ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sidekick-coder/zenith-kit",
3
- "version": "0.0.1",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "description": "A collection of utilities and tools for building language servers and related applications.",
6
6
  "keywords": [],
@@ -27,7 +27,9 @@
27
27
  },
28
28
  "scripts": {
29
29
  "generate:indexes": "node indexes.js",
30
- "build": "node indexes.js && tsdown"
30
+ "build": "tsdown",
31
+ "watch": "tsdown --watch",
32
+ "release": "node artisan.js release"
31
33
  },
32
34
  "devDependencies": {
33
35
  "@eslint/js": "^9.39.4",
@@ -35,6 +37,7 @@
35
37
  "@types/lodash-es": "^4.17.12",
36
38
  "@types/node": "^25.6.0",
37
39
  "@vue/tsconfig": "^0.9.1",
40
+ "commander": "^14.0.3",
38
41
  "eslint": "^9.39.4",
39
42
  "eslint-config-prettier": "^10.1.8",
40
43
  "eslint-plugin-vue": "^10.8.0",
@@ -7,7 +7,6 @@
7
7
  "strict": true,
8
8
  "noUnusedLocals": false,
9
9
  "noUnusedParameters": true,
10
- "erasableSyntaxOnly": true,
11
10
  "noFallthroughCasesInSwitch": true,
12
11
  "noUncheckedSideEffectImports": true,
13
12
  "strictPropertyInitialization": false,
@@ -21,6 +20,6 @@
21
20
  "include": [
22
21
  "client/**/**/*.ts",
23
22
  "client/**/**/*.vue",
24
- "shared/**/**/*.ts",
23
+ "shared/**/**/*.ts"
25
24
  ]
26
25
  }
@@ -18,7 +18,6 @@
18
18
  "strict": true,
19
19
  "noUnusedLocals": false,
20
20
  "noUnusedParameters": true,
21
- "erasableSyntaxOnly": true,
22
21
  "noFallthroughCasesInSwitch": true,
23
22
  "noUncheckedSideEffectImports": true,
24
23
  "strictPropertyInitialization": false
@@ -15,12 +15,11 @@
15
15
  "strict": false,
16
16
  "noUnusedLocals": false,
17
17
  "noUnusedParameters": true,
18
- "erasableSyntaxOnly": true,
19
18
  "noFallthroughCasesInSwitch": true,
20
19
  "noUncheckedSideEffectImports": true,
21
20
  "strictPropertyInitialization": false
22
21
  },
23
22
  "include": [
24
- "src/shared/**/*.ts",
23
+ "src/shared/**/*.ts"
25
24
  ]
26
25
  }
package/tsdown.config.ts CHANGED
@@ -1,14 +1,38 @@
1
- import { defineConfig } from 'tsdown'
1
+ import { defineConfig, globalLogger } from 'tsdown'
2
+ import { generateIndexFile } from './src/shared/utils/generateIndexFile'
2
3
 
3
4
  export default defineConfig([
4
5
  {
5
6
  entry: 'src/shared/index.ts',
6
7
  outDir: 'dist/shared',
7
8
  tsconfig: 'tsconfig.shared.json',
9
+ hooks(hooks) {
10
+ hooks.hook('build:before', async () => {
11
+ generateIndexFile({
12
+ folders: ['src/shared/services', 'src/shared/utils'],
13
+ filename: 'src/shared/index.ts'
14
+ })
15
+
16
+ globalLogger.info('Generated index.ts for shared')
17
+ })
18
+ }
8
19
  },
9
20
  {
10
21
  entry: 'src/server/index.ts',
11
22
  outDir: 'dist/server',
12
23
  tsconfig: 'tsconfig.server.json',
24
+ hooks(hooks) {
25
+ hooks.hook('build:before', async () => {
26
+ generateIndexFile({
27
+ folders: [
28
+ 'src/server/services',
29
+ 'src/server/gateways',
30
+ ],
31
+ filename: 'src/server/index.ts'
32
+ })
33
+
34
+ globalLogger.info('Generated index.ts for server')
35
+ })
36
+ }
13
37
  }
14
38
  ])
package/indexes.js DELETED
@@ -1,37 +0,0 @@
1
- import fg from 'fast-glob'
2
- import fs from 'fs'
3
- import path from 'path'
4
-
5
- // generate indexes for folders
6
-
7
- function generate(options) {
8
- const folders = options.folders
9
- const filename = options.filename
10
-
11
- let content = ''
12
-
13
- for (const folder of folders) {
14
- const files = fg.sync(`${folder}/**/*.ts`, { ignore: ['**/index.ts'] })
15
-
16
- for (const file of files) {
17
- const filePath = path.relative(path.dirname(filename), file)
18
-
19
- content += `export * from './${filePath}'\n`
20
- }
21
- }
22
-
23
- content = content.trim()
24
-
25
- fs.writeFileSync(filename, content)
26
- }
27
-
28
-
29
- generate({
30
- folders: ['src/shared/services', 'src/shared/utils'],
31
- filename: 'src/shared/index.ts'
32
- })
33
-
34
- generate({
35
- folders: ['src/server/services'],
36
- filename: 'src/server/index.ts'
37
- })