@vanshbhardwaj/worklog 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/.github/ISSUE_TEMPLATE/bug_report.md +28 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- package/.github/workflows/release.yml +63 -0
- package/.github/workflows/validate.yml +103 -0
- package/.prettierrc +8 -0
- package/ARCHITECTURE.md +82 -0
- package/CODE_OF_CONDUCT.md +65 -0
- package/CONTRIBUTING.md +74 -0
- package/INSTALLATION.md +98 -0
- package/LICENSE +21 -0
- package/README.md +246 -0
- package/SECURITY.md +18 -0
- package/benchmarks/benchmark.ts +149 -0
- package/benchmarks/vitest.bench.config.ts +9 -0
- package/dist/database/migrations/001_initial.sql +60 -0
- package/dist/database/migrations/002_relational_tables.sql +22 -0
- package/dist/index.cjs +31007 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1873 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +38 -0
- package/package.json +49 -0
- package/pnpm-workspace.yaml +6 -0
- package/scripts/build-bin.js +75 -0
- package/sea-config.json +5 -0
- package/src/cli/commands/add.ts +176 -0
- package/src/cli/commands/continue.ts +80 -0
- package/src/cli/commands/dashboard.ts +30 -0
- package/src/cli/commands/export.ts +72 -0
- package/src/cli/commands/init.ts +52 -0
- package/src/cli/commands/list.ts +33 -0
- package/src/cli/commands/search.ts +33 -0
- package/src/cli/commands/show.ts +42 -0
- package/src/cli/commands/stats.ts +23 -0
- package/src/cli/commands/today.ts +27 -0
- package/src/cli/commands/week.ts +93 -0
- package/src/cli/index.ts +294 -0
- package/src/cli/ui.ts +323 -0
- package/src/core/config.ts +69 -0
- package/src/core/discovery.ts +38 -0
- package/src/core/logger.ts +53 -0
- package/src/database/connection.ts +95 -0
- package/src/database/migration-data.ts +71 -0
- package/src/database/migrations/001_initial.sql +60 -0
- package/src/database/migrations/002_relational_tables.sql +22 -0
- package/src/database/migrations.ts +65 -0
- package/src/errors/index.ts +51 -0
- package/src/exporters/csv.ts +59 -0
- package/src/exporters/json.ts +8 -0
- package/src/exporters/markdown.ts +71 -0
- package/src/models/work-unit.ts +38 -0
- package/src/repositories/work-unit.ts +466 -0
- package/src/services/work-unit.ts +131 -0
- package/src/tests/cli/__snapshots__/cli-productivity.test.ts.snap +37 -0
- package/src/tests/cli/__snapshots__/cli.test.ts.snap +20 -0
- package/src/tests/cli/cli-productivity.test.ts +167 -0
- package/src/tests/cli/cli.test.ts +171 -0
- package/src/tests/core/config.test.ts +53 -0
- package/src/tests/core/discovery.test.ts +46 -0
- package/src/tests/database/migrations.test.ts +75 -0
- package/src/tests/repositories/work-unit.test.ts +243 -0
- package/src/tests/services/work-unit.test.ts +87 -0
- package/src/validators/work-unit.ts +63 -0
- package/tsconfig.json +16 -0
- package/tsup.config.ts +50 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
import { runMigrations } from '../../database/migrations.js';
|
|
6
|
+
import { WorkUnitRepository } from '../../repositories/work-unit.js';
|
|
7
|
+
import { DatabaseError } from '../../errors/index.js';
|
|
8
|
+
|
|
9
|
+
describe('WorkUnitRepository', () => {
|
|
10
|
+
const tempTestDir = path.join(process.cwd(), 'src', 'tests', 'temp-repo-test');
|
|
11
|
+
let db: Database.Database;
|
|
12
|
+
let repo: WorkUnitRepository;
|
|
13
|
+
|
|
14
|
+
beforeAll(() => {
|
|
15
|
+
if (fs.existsSync(tempTestDir)) {
|
|
16
|
+
fs.rmSync(tempTestDir, { recursive: true, force: true });
|
|
17
|
+
}
|
|
18
|
+
fs.mkdirSync(tempTestDir, { recursive: true });
|
|
19
|
+
|
|
20
|
+
db = new Database(path.join(tempTestDir, 'test.db'));
|
|
21
|
+
runMigrations(db);
|
|
22
|
+
repo = new WorkUnitRepository(db);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterAll(() => {
|
|
26
|
+
if (db) {
|
|
27
|
+
db.close();
|
|
28
|
+
}
|
|
29
|
+
if (fs.existsSync(tempTestDir)) {
|
|
30
|
+
fs.rmSync(tempTestDir, { recursive: true, force: true });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
db.exec('DELETE FROM work_units');
|
|
36
|
+
db.exec('DELETE FROM work_unit_tags');
|
|
37
|
+
db.exec('DELETE FROM work_unit_relations');
|
|
38
|
+
db.exec('DELETE FROM work_units_fts');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should return null when finding a non-existent ID', () => {
|
|
42
|
+
expect(repo.findById(999)).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return empty list on recent, status, type search when DB is empty', () => {
|
|
46
|
+
expect(repo.findRecent()).toEqual([]);
|
|
47
|
+
expect(repo.findByStatus('Completed')).toEqual([]);
|
|
48
|
+
expect(repo.findByType('Bug')).toEqual([]);
|
|
49
|
+
expect(repo.search('anything')).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should create and find a work unit', () => {
|
|
53
|
+
const created = repo.create({
|
|
54
|
+
title: 'First feature',
|
|
55
|
+
type: 'Feature',
|
|
56
|
+
status: 'Planned',
|
|
57
|
+
priority: 'High',
|
|
58
|
+
module: 'core',
|
|
59
|
+
description: 'First feature desc',
|
|
60
|
+
nextStep: 'write tests',
|
|
61
|
+
decision: null,
|
|
62
|
+
blocker: null,
|
|
63
|
+
notes: 'some notes',
|
|
64
|
+
tags: ['backend', 'test'],
|
|
65
|
+
relatedWorkUnits: [],
|
|
66
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
67
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(created.id).toBeTypeOf('number');
|
|
71
|
+
expect(created.title).toBe('First feature');
|
|
72
|
+
expect(created.tags).toEqual(['backend', 'test']);
|
|
73
|
+
|
|
74
|
+
const found = repo.findById(created.id);
|
|
75
|
+
expect(found).not.toBeNull();
|
|
76
|
+
expect(found!.title).toBe('First feature');
|
|
77
|
+
expect(found!.tags).toEqual(['backend', 'test']);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should throw DatabaseError if creating relation to non-existent ID', () => {
|
|
81
|
+
expect(() =>
|
|
82
|
+
repo.create({
|
|
83
|
+
title: 'Invalid relation unit',
|
|
84
|
+
type: 'Feature',
|
|
85
|
+
status: 'Planned',
|
|
86
|
+
priority: null,
|
|
87
|
+
module: null,
|
|
88
|
+
description: null,
|
|
89
|
+
nextStep: null,
|
|
90
|
+
decision: null,
|
|
91
|
+
blocker: null,
|
|
92
|
+
notes: null,
|
|
93
|
+
tags: [],
|
|
94
|
+
relatedWorkUnits: [9999],
|
|
95
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
96
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
97
|
+
}),
|
|
98
|
+
).toThrow(DatabaseError);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should support creating relations between work units', () => {
|
|
102
|
+
const unit1 = repo.create({
|
|
103
|
+
title: 'Unit 1',
|
|
104
|
+
type: 'Feature',
|
|
105
|
+
status: 'Planned',
|
|
106
|
+
priority: null,
|
|
107
|
+
module: null,
|
|
108
|
+
description: null,
|
|
109
|
+
nextStep: null,
|
|
110
|
+
decision: null,
|
|
111
|
+
blocker: null,
|
|
112
|
+
notes: null,
|
|
113
|
+
tags: [],
|
|
114
|
+
relatedWorkUnits: [],
|
|
115
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
116
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const unit2 = repo.create({
|
|
120
|
+
title: 'Unit 2',
|
|
121
|
+
type: 'Bug',
|
|
122
|
+
status: 'In Progress',
|
|
123
|
+
priority: null,
|
|
124
|
+
module: null,
|
|
125
|
+
description: null,
|
|
126
|
+
nextStep: null,
|
|
127
|
+
decision: null,
|
|
128
|
+
blocker: null,
|
|
129
|
+
notes: null,
|
|
130
|
+
tags: [],
|
|
131
|
+
relatedWorkUnits: [unit1.id],
|
|
132
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
133
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const found2 = repo.findById(unit2.id);
|
|
137
|
+
expect(found2!.relatedWorkUnits).toEqual([unit1.id]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should update a work unit and its sub-tables', () => {
|
|
141
|
+
const original = repo.create({
|
|
142
|
+
title: 'Original Title',
|
|
143
|
+
type: 'Feature',
|
|
144
|
+
status: 'Planned',
|
|
145
|
+
priority: 'Low',
|
|
146
|
+
module: 'core',
|
|
147
|
+
description: 'Original description',
|
|
148
|
+
nextStep: 'original next',
|
|
149
|
+
decision: null,
|
|
150
|
+
blocker: null,
|
|
151
|
+
notes: 'some notes',
|
|
152
|
+
tags: ['alpha'],
|
|
153
|
+
relatedWorkUnits: [],
|
|
154
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
155
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const updated = repo.update(original.id, {
|
|
159
|
+
title: 'Updated Title',
|
|
160
|
+
priority: 'High',
|
|
161
|
+
tags: ['beta', 'gamma'],
|
|
162
|
+
updatedAt: '2026-07-26T21:00:00Z',
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(updated.title).toBe('Updated Title');
|
|
166
|
+
expect(updated.priority).toBe('High');
|
|
167
|
+
expect(updated.tags).toEqual(['beta', 'gamma']);
|
|
168
|
+
expect(updated.updatedAt).toBe('2026-07-26T21:00:00Z');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should search work units using FTS5 MATCH', () => {
|
|
172
|
+
repo.create({
|
|
173
|
+
title: 'Build the compiler frontend',
|
|
174
|
+
type: 'Feature',
|
|
175
|
+
status: 'In Progress',
|
|
176
|
+
priority: null,
|
|
177
|
+
module: null,
|
|
178
|
+
description: 'Using parsing techniques',
|
|
179
|
+
nextStep: null,
|
|
180
|
+
decision: null,
|
|
181
|
+
blocker: null,
|
|
182
|
+
notes: null,
|
|
183
|
+
tags: [],
|
|
184
|
+
relatedWorkUnits: [],
|
|
185
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
186
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
repo.create({
|
|
190
|
+
title: 'Clean the database connection logs',
|
|
191
|
+
type: 'Improvement',
|
|
192
|
+
status: 'Completed',
|
|
193
|
+
priority: null,
|
|
194
|
+
module: null,
|
|
195
|
+
description: 'Removed stdout statements',
|
|
196
|
+
nextStep: null,
|
|
197
|
+
decision: 'Keep logs silent by default',
|
|
198
|
+
blocker: null,
|
|
199
|
+
notes: null,
|
|
200
|
+
tags: [],
|
|
201
|
+
relatedWorkUnits: [],
|
|
202
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
203
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const search1 = repo.search('compiler');
|
|
207
|
+
expect(search1.length).toBe(1);
|
|
208
|
+
expect(search1[0].title).toBe('Build the compiler frontend');
|
|
209
|
+
|
|
210
|
+
const search2 = repo.search('logs');
|
|
211
|
+
expect(search2.length).toBe(1);
|
|
212
|
+
expect(search2[0].title).toBe('Clean the database connection logs');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should delete a work unit and cascade deletes to sub-tables', () => {
|
|
216
|
+
const created = repo.create({
|
|
217
|
+
title: 'Delete Me',
|
|
218
|
+
type: 'Bug',
|
|
219
|
+
status: 'Planned',
|
|
220
|
+
priority: null,
|
|
221
|
+
module: null,
|
|
222
|
+
description: null,
|
|
223
|
+
nextStep: null,
|
|
224
|
+
decision: null,
|
|
225
|
+
blocker: null,
|
|
226
|
+
notes: null,
|
|
227
|
+
tags: ['temp'],
|
|
228
|
+
relatedWorkUnits: [],
|
|
229
|
+
createdAt: '2026-07-26T20:00:00Z',
|
|
230
|
+
updatedAt: '2026-07-26T20:00:00Z',
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const deleted = repo.delete(created.id);
|
|
234
|
+
expect(deleted).toBe(true);
|
|
235
|
+
|
|
236
|
+
expect(repo.findById(created.id)).toBeNull();
|
|
237
|
+
|
|
238
|
+
const tagsCount = db
|
|
239
|
+
.prepare('SELECT count(*) as count FROM work_unit_tags WHERE work_unit_id = ?')
|
|
240
|
+
.get(created.id) as any;
|
|
241
|
+
expect(tagsCount.count).toBe(0);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { WorkUnitService } from '../../services/work-unit.js';
|
|
3
|
+
import { WorkUnitRepository } from '../../repositories/work-unit.js';
|
|
4
|
+
import { ValidationError } from '../../errors/index.js';
|
|
5
|
+
|
|
6
|
+
describe('WorkUnitService', () => {
|
|
7
|
+
it('should throw ValidationError if input title is empty', () => {
|
|
8
|
+
const mockRepo = {} as unknown as WorkUnitRepository;
|
|
9
|
+
const service = new WorkUnitService(mockRepo);
|
|
10
|
+
|
|
11
|
+
expect(() =>
|
|
12
|
+
service.createWorkUnit({
|
|
13
|
+
title: '',
|
|
14
|
+
type: 'Feature',
|
|
15
|
+
}),
|
|
16
|
+
).toThrow(ValidationError);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should throw ValidationError if input type is invalid', () => {
|
|
20
|
+
const mockRepo = {} as unknown as WorkUnitRepository;
|
|
21
|
+
const service = new WorkUnitService(mockRepo);
|
|
22
|
+
|
|
23
|
+
expect(() =>
|
|
24
|
+
service.createWorkUnit({
|
|
25
|
+
title: 'Valid Title',
|
|
26
|
+
type: 'INVALID_TYPE',
|
|
27
|
+
}),
|
|
28
|
+
).toThrow(ValidationError);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should validate creation inputs, set dates, and delegate to repo', () => {
|
|
32
|
+
const mockRepo = {
|
|
33
|
+
create: vi.fn().mockImplementation((data) => ({
|
|
34
|
+
id: 1,
|
|
35
|
+
...data,
|
|
36
|
+
})),
|
|
37
|
+
} as unknown as WorkUnitRepository;
|
|
38
|
+
|
|
39
|
+
const service = new WorkUnitService(mockRepo);
|
|
40
|
+
|
|
41
|
+
const result = service.createWorkUnit({
|
|
42
|
+
title: ' New Feature ', // tests string trimming
|
|
43
|
+
type: 'Feature',
|
|
44
|
+
status: 'Planned',
|
|
45
|
+
priority: 'High',
|
|
46
|
+
module: 'ui',
|
|
47
|
+
tags: ['css', 'layout'],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(mockRepo.create).toHaveBeenCalledOnce();
|
|
51
|
+
expect(result.id).toBe(1);
|
|
52
|
+
expect(result.createdAt).toBeDefined();
|
|
53
|
+
expect(result.updatedAt).toBeDefined();
|
|
54
|
+
expect(result.title).toBe('New Feature'); // verified trimmed
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should validate update inputs and delegate to repo', () => {
|
|
58
|
+
const mockRepo = {
|
|
59
|
+
update: vi.fn().mockImplementation((id, data) => ({
|
|
60
|
+
id,
|
|
61
|
+
...data,
|
|
62
|
+
})),
|
|
63
|
+
} as unknown as WorkUnitRepository;
|
|
64
|
+
|
|
65
|
+
const service = new WorkUnitService(mockRepo);
|
|
66
|
+
|
|
67
|
+
const result = service.updateWorkUnit(1, {
|
|
68
|
+
title: 'Updated Feature',
|
|
69
|
+
status: 'In Progress',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(mockRepo.update).toHaveBeenCalledOnce();
|
|
73
|
+
expect(result.id).toBe(1);
|
|
74
|
+
expect(result.title).toBe('Updated Feature');
|
|
75
|
+
expect(result.status).toBe('In Progress');
|
|
76
|
+
expect(result.updatedAt).toBeDefined();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should throw ValidationError on update with invalid ID', () => {
|
|
80
|
+
const mockRepo = {} as unknown as WorkUnitRepository;
|
|
81
|
+
const service = new WorkUnitService(mockRepo);
|
|
82
|
+
|
|
83
|
+
expect(() => service.updateWorkUnit(0, { title: 'Test' })).toThrow(ValidationError);
|
|
84
|
+
expect(() => service.updateWorkUnit(-5, { title: 'Test' })).toThrow(ValidationError);
|
|
85
|
+
expect(() => service.updateWorkUnit(3.14, { title: 'Test' })).toThrow(ValidationError);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const WorkUnitTypeSchema = z.enum([
|
|
4
|
+
'Feature',
|
|
5
|
+
'Bug',
|
|
6
|
+
'Spike',
|
|
7
|
+
'Refactor',
|
|
8
|
+
'Improvement',
|
|
9
|
+
'Research',
|
|
10
|
+
'Decision',
|
|
11
|
+
'Blocker',
|
|
12
|
+
'Review',
|
|
13
|
+
'Idea',
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
const WorkUnitStatusSchema = z.enum([
|
|
17
|
+
'Planned',
|
|
18
|
+
'In Progress',
|
|
19
|
+
'Blocked',
|
|
20
|
+
'Completed',
|
|
21
|
+
'Cancelled',
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
const WorkUnitPrioritySchema = z.enum(['Low', 'Medium', 'High']);
|
|
25
|
+
|
|
26
|
+
export const CreateWorkUnitSchema = z.object({
|
|
27
|
+
title: z
|
|
28
|
+
.string()
|
|
29
|
+
.trim()
|
|
30
|
+
.min(1, 'Title cannot be empty')
|
|
31
|
+
.max(200, 'Title cannot exceed 200 characters'),
|
|
32
|
+
type: WorkUnitTypeSchema,
|
|
33
|
+
status: WorkUnitStatusSchema.default('Planned'),
|
|
34
|
+
priority: WorkUnitPrioritySchema.nullable().optional().default(null),
|
|
35
|
+
module: z
|
|
36
|
+
.string()
|
|
37
|
+
.trim()
|
|
38
|
+
.max(100, 'Module cannot exceed 100 characters')
|
|
39
|
+
.nullable()
|
|
40
|
+
.optional()
|
|
41
|
+
.default(null),
|
|
42
|
+
description: z.string().trim().nullable().optional().default(null),
|
|
43
|
+
nextStep: z.string().trim().nullable().optional().default(null),
|
|
44
|
+
decision: z.string().trim().nullable().optional().default(null),
|
|
45
|
+
blocker: z.string().trim().nullable().optional().default(null),
|
|
46
|
+
tags: z
|
|
47
|
+
.array(
|
|
48
|
+
z
|
|
49
|
+
.string()
|
|
50
|
+
.trim()
|
|
51
|
+
.min(1, 'Tag cannot be empty')
|
|
52
|
+
.max(50, 'Tag cannot exceed 50 characters'),
|
|
53
|
+
)
|
|
54
|
+
.optional()
|
|
55
|
+
.default([]),
|
|
56
|
+
relatedWorkUnits: z.array(z.number().int().positive()).optional().default([]),
|
|
57
|
+
notes: z.string().trim().nullable().optional().default(null),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export const UpdateWorkUnitSchema = CreateWorkUnitSchema.partial();
|
|
61
|
+
|
|
62
|
+
export type CreateWorkUnitInput = z.infer<typeof CreateWorkUnitSchema>;
|
|
63
|
+
export type UpdateWorkUnitInput = z.infer<typeof UpdateWorkUnitSchema>;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"resolveJsonModule": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist", "src/**/*.test.ts"]
|
|
16
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
function copyMigrations() {
|
|
6
|
+
const srcDir = path.resolve('src/database/migrations');
|
|
7
|
+
const destDir = path.resolve('dist/database/migrations');
|
|
8
|
+
if (fs.existsSync(srcDir)) {
|
|
9
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
10
|
+
const files = fs.readdirSync(srcDir).filter((f) => f.endsWith('.sql'));
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
fs.copyFileSync(path.join(srcDir, file), path.join(destDir, file));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default defineConfig([
|
|
18
|
+
{
|
|
19
|
+
entry: ['src/cli/index.ts'],
|
|
20
|
+
format: ['esm'],
|
|
21
|
+
target: 'node20',
|
|
22
|
+
sourcemap: true,
|
|
23
|
+
clean: true,
|
|
24
|
+
dts: true,
|
|
25
|
+
shims: true,
|
|
26
|
+
external: ['better-sqlite3'],
|
|
27
|
+
onSuccess: async () => {
|
|
28
|
+
copyMigrations();
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
entry: ['src/cli/index.ts'],
|
|
33
|
+
format: ['cjs'],
|
|
34
|
+
target: 'node20',
|
|
35
|
+
sourcemap: true,
|
|
36
|
+
external: ['better-sqlite3'],
|
|
37
|
+
noExternal: [
|
|
38
|
+
'commander',
|
|
39
|
+
'cli-table3',
|
|
40
|
+
'ora',
|
|
41
|
+
'picocolors',
|
|
42
|
+
'pino',
|
|
43
|
+
'prompts',
|
|
44
|
+
'zod',
|
|
45
|
+
],
|
|
46
|
+
onSuccess: async () => {
|
|
47
|
+
copyMigrations();
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
]);
|