@t1mmen/srtd 0.2.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.
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/__tests__/vitest.setup.d.ts +2 -0
- package/dist/__tests__/vitest.setup.js +72 -0
- package/dist/__tests__/vitest.setup.js.map +1 -0
- package/dist/__tests__/watch.test.d.ts +1 -0
- package/dist/__tests__/watch.test.js +24 -0
- package/dist/__tests__/watch.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/_app.d.ts +3 -0
- package/dist/commands/_app.js +7 -0
- package/dist/commands/_app.js.map +1 -0
- package/dist/commands/apply.d.ts +1 -0
- package/dist/commands/apply.js +20 -0
- package/dist/commands/apply.js.map +1 -0
- package/dist/commands/build.d.ts +1 -0
- package/dist/commands/build.js +15 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +2 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.js +37 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +80 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/register.d.ts +8 -0
- package/dist/commands/register.js +82 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +127 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/components/Branding.d.ts +6 -0
- package/dist/components/Branding.js +28 -0
- package/dist/components/Branding.js.map +1 -0
- package/dist/components/TimeSince.d.ts +4 -0
- package/dist/components/TimeSince.js +29 -0
- package/dist/components/TimeSince.js.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -0
- package/dist/hooks/useTemplateState.d.ts +6 -0
- package/dist/hooks/useTemplateState.js +28 -0
- package/dist/hooks/useTemplateState.js.map +1 -0
- package/dist/lib/templateManager.d.ts +32 -0
- package/dist/lib/templateManager.js +237 -0
- package/dist/lib/templateManager.js.map +1 -0
- package/dist/lib/templateManager.test.d.ts +1 -0
- package/dist/lib/templateManager.test.js +289 -0
- package/dist/lib/templateManager.test.js.map +1 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/applyMigration.d.ts +2 -0
- package/dist/utils/applyMigration.js +29 -0
- package/dist/utils/applyMigration.js.map +1 -0
- package/dist/utils/applyMigrations.test.d.ts +1 -0
- package/dist/utils/applyMigrations.test.js +112 -0
- package/dist/utils/applyMigrations.test.js.map +1 -0
- package/dist/utils/calculateMD5.d.ts +1 -0
- package/dist/utils/calculateMD5.js +5 -0
- package/dist/utils/calculateMD5.js.map +1 -0
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.js +78 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/config.test.d.ts +1 -0
- package/dist/utils/config.test.js +61 -0
- package/dist/utils/config.test.js.map +1 -0
- package/dist/utils/createEmptyBuildLog.d.ts +1 -0
- package/dist/utils/createEmptyBuildLog.js +10 -0
- package/dist/utils/createEmptyBuildLog.js.map +1 -0
- package/dist/utils/databaseConnection.d.ts +3 -0
- package/dist/utils/databaseConnection.js +45 -0
- package/dist/utils/databaseConnection.js.map +1 -0
- package/dist/utils/databaseConnection.test.d.ts +1 -0
- package/dist/utils/databaseConnection.test.js +45 -0
- package/dist/utils/databaseConnection.test.js.map +1 -0
- package/dist/utils/ensureDirectories.d.ts +4 -0
- package/dist/utils/ensureDirectories.js +23 -0
- package/dist/utils/ensureDirectories.js.map +1 -0
- package/dist/utils/fileExists.d.ts +1 -0
- package/dist/utils/fileExists.js +11 -0
- package/dist/utils/fileExists.js.map +1 -0
- package/dist/utils/getNextTimestamp.d.ts +2 -0
- package/dist/utils/getNextTimestamp.js +12 -0
- package/dist/utils/getNextTimestamp.js.map +1 -0
- package/dist/utils/isWipTemplate.d.ts +1 -0
- package/dist/utils/isWipTemplate.js +6 -0
- package/dist/utils/isWipTemplate.js.map +1 -0
- package/dist/utils/loadBuildLog.d.ts +2 -0
- package/dist/utils/loadBuildLog.js +21 -0
- package/dist/utils/loadBuildLog.js.map +1 -0
- package/dist/utils/loadBuildLog.test.d.ts +1 -0
- package/dist/utils/loadBuildLog.test.js +62 -0
- package/dist/utils/loadBuildLog.test.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/registerTemplate.d.ts +1 -0
- package/dist/utils/registerTemplate.js +44 -0
- package/dist/utils/registerTemplate.js.map +1 -0
- package/dist/utils/safeCreate.d.ts +1 -0
- package/dist/utils/safeCreate.js +10 -0
- package/dist/utils/safeCreate.js.map +1 -0
- package/dist/utils/saveBuildLog.d.ts +2 -0
- package/dist/utils/saveBuildLog.js +9 -0
- package/dist/utils/saveBuildLog.js.map +1 -0
- package/package.json +91 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Timm Stokke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# `srtd` đŞ Supabase Repeatable Template Definitions
|
|
2
|
+
|
|
3
|
+
Live-reloading SQL templates for [Supabase](https://supabase.com) projects. DX supercharged! đ
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
`srtd` enhances the [Supabase](https://supabase.com) development workflow by adding live-reloading SQL templates, and a single-source-of-truth template migrations system for your database functions, RLS policies, etc. Drastically simplify code reviews đŞ
|
|
7
|
+
|
|
8
|
+
Built specifically for projects using the standard [Supabase](https://supabase.com) stack (but probably works alright for other Postgres-based projects, too).
|
|
9
|
+
|
|
10
|
+
## Why This Exists đ¤
|
|
11
|
+
|
|
12
|
+
While building [Timely](https://www.timely.com)'s next-generation [Memory Engine](https://www.timely.com/memory-app) on [Supabase](https://supabase.com), we found ourselves facing two major annoyances:
|
|
13
|
+
|
|
14
|
+
1. Code reviews were painful - function changes showed up as complete rewrites rather than helpful diffs
|
|
15
|
+
2. Designing and iterating on database changes locally meant constant friction, like the dance around copy-pasting into SQL console
|
|
16
|
+
|
|
17
|
+
After over a year of looking-but-not-finding a better way, I paired up with [Claude](https://claude.ai) to eliminate these annoyances. Say hello to `srtd`.
|
|
18
|
+
|
|
19
|
+
## Key Features â¨
|
|
20
|
+
|
|
21
|
+
- **Live Reload**: Changes to your SQL templates instantly update your local database
|
|
22
|
+
- **Single Source of Truth**: Templates are the source of all (non-mutable) database objects, making code reviews a breeze
|
|
23
|
+
- **Clean Migrations**: Generate standard [Supabase](https://supabase.com) migrations when you're ready to deploy
|
|
24
|
+
- **Developer Friendly**: Interactive CLI with visual feedback for all operations
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Node.js v20.x or higher
|
|
29
|
+
- [Supabase](https://supabase.com) CLI installed and project initialized (with `/supabase` directory)
|
|
30
|
+
- Local Postgres instance running (typically via `supabase start`)
|
|
31
|
+
|
|
32
|
+
## Quick Start đ
|
|
33
|
+
|
|
34
|
+
First, install `srtd` globally or in your project:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g srtd # Global installation
|
|
38
|
+
# or
|
|
39
|
+
npm install --save-dev srtd # Project installation
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then set up in your [Supabase](https://supabase.com) project:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd your-supabase-project
|
|
46
|
+
srtd init
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Create a template (e.g., `supabase/migrations-templates/my_function.sql`):
|
|
50
|
+
|
|
51
|
+
```sql
|
|
52
|
+
CREATE OR REPLACE FUNCTION my_function()
|
|
53
|
+
RETURNS void AS $$
|
|
54
|
+
BEGIN
|
|
55
|
+
-- Your function logic here
|
|
56
|
+
END;
|
|
57
|
+
$$ LANGUAGE plpgsql;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Start development mode:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
srtd watch # Changes auto-apply to local database
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
When ready to deploy:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
srtd build # Creates timestamped migration file
|
|
70
|
+
supabase migrate up # Apply using Supabase CLI
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Commands đŽ
|
|
74
|
+
|
|
75
|
+
Running `srtd` without arguments opens an interactive menu:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
⯠đď¸ build - Build Supabase migrations from templates
|
|
79
|
+
âśď¸ apply - Apply migration templates directly to database
|
|
80
|
+
âď¸ register - Register templates as already built
|
|
81
|
+
đ watch - Watch templates for changes, apply directly to database
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or use these commands directly:
|
|
85
|
+
|
|
86
|
+
- đď¸ `build` - Generate [Supabase](https://supabase.com) migrations from templates
|
|
87
|
+
- âśď¸ `apply` - Apply templates directly to local database
|
|
88
|
+
- âď¸ `register [file.sql]` - Mark templates as already built (interactive UI if no file specified)
|
|
89
|
+
- đ `watch` - Watch templates and apply changes instantly
|
|
90
|
+
|
|
91
|
+
## Perfect For đŻ
|
|
92
|
+
|
|
93
|
+
Ideal for [Supabase](https://supabase.com) database objects that need full redefinition:
|
|
94
|
+
|
|
95
|
+
â
Functions and stored procedures:
|
|
96
|
+
```sql
|
|
97
|
+
CREATE OR REPLACE FUNCTION search_products(query text, category_id uuid DEFAULT NULL)
|
|
98
|
+
RETURNS SETOF products AS $$
|
|
99
|
+
BEGIN
|
|
100
|
+
RETURN QUERY
|
|
101
|
+
SELECT p.* FROM products p
|
|
102
|
+
LEFT JOIN product_categories pc ON pc.product_id = p.id
|
|
103
|
+
WHERE to_tsvector('english',
|
|
104
|
+
p.name || ' ' ||
|
|
105
|
+
p.description || ' ' ||
|
|
106
|
+
p.tags || ' ' ||
|
|
107
|
+
COALESCE((
|
|
108
|
+
SELECT string_agg(c.name, ' ')
|
|
109
|
+
FROM categories c
|
|
110
|
+
WHERE c.id = ANY(p.category_ids)
|
|
111
|
+
), '')
|
|
112
|
+
) @@ plainto_tsquery('english', query)
|
|
113
|
+
AND (category_id IS NULL OR pc.category_id = category_id);
|
|
114
|
+
END;
|
|
115
|
+
$$ LANGUAGE plpgsql;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
â
Row-Level Security (RLS) policies:
|
|
119
|
+
```sql
|
|
120
|
+
CREATE POLICY "users can view own data"
|
|
121
|
+
ON profiles FOR SELECT
|
|
122
|
+
USING (auth.uid() = user_id);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
â
Roles and permissions:
|
|
126
|
+
```sql
|
|
127
|
+
CREATE ROLE authenticated;
|
|
128
|
+
GRANT USAGE ON SCHEMA public TO authenticated;
|
|
129
|
+
GRANT SELECT ON ALL TABLES IN SCHEMA public TO authenticated;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Not recommended for:**
|
|
133
|
+
|
|
134
|
+
* â Table structures
|
|
135
|
+
* â Indexes
|
|
136
|
+
* â Data modifications
|
|
137
|
+
* â Anything that is not fully re-definable, really.
|
|
138
|
+
|
|
139
|
+
In these cases, use regular [Supabase](https://supabase.com) migrations.
|
|
140
|
+
|
|
141
|
+
## The Power of Templates đŞ
|
|
142
|
+
|
|
143
|
+
Here's why templates make your life easier. Consider a PR that adds priority to our notification dispatch function.
|
|
144
|
+
|
|
145
|
+
With templates, the change is clear and reviewable:
|
|
146
|
+
|
|
147
|
+
```diff
|
|
148
|
+
CREATE OR REPLACE FUNCTION dispatch_notification(
|
|
149
|
+
user_id uuid,
|
|
150
|
+
type text,
|
|
151
|
+
payload jsonb
|
|
152
|
+
) RETURNS uuid AS $$
|
|
153
|
+
DECLARE
|
|
154
|
+
notification_id uuid;
|
|
155
|
+
user_settings jsonb;
|
|
156
|
+
BEGIN
|
|
157
|
+
-- Get user notification settings
|
|
158
|
+
SELECT settings INTO user_settings
|
|
159
|
+
FROM user_preferences
|
|
160
|
+
WHERE id = user_id;
|
|
161
|
+
|
|
162
|
+
-- Create notification record
|
|
163
|
+
+ -- Include priority based on notification type
|
|
164
|
+
INSERT INTO notifications (
|
|
165
|
+
id,
|
|
166
|
+
user_id,
|
|
167
|
+
type,
|
|
168
|
+
payload,
|
|
169
|
+
+ priority,
|
|
170
|
+
created_at
|
|
171
|
+
) VALUES (
|
|
172
|
+
gen_random_uuid(),
|
|
173
|
+
dispatch_notification.user_id,
|
|
174
|
+
type,
|
|
175
|
+
payload,
|
|
176
|
+
+ COALESCE((SELECT priority FROM notification_types WHERE name = type), 'normal'),
|
|
177
|
+
CURRENT_TIMESTAMP
|
|
178
|
+
)
|
|
179
|
+
RETURNING id INTO notification_id;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Without templates, the same change appears as a complete new file in your PR.
|
|
183
|
+
|
|
184
|
+
## Configuration đ
|
|
185
|
+
|
|
186
|
+
During initialization, `srtd` creates a `srtd.config.json`:
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"wipIndicator": ".wip",
|
|
191
|
+
"filter": "**/*.sql",
|
|
192
|
+
"banner": "You very likely **DO NOT** want to manually edit this generated file.",
|
|
193
|
+
"footer": "",
|
|
194
|
+
"wrapInTransaction": true,
|
|
195
|
+
"templateDir": "supabase/migrations-templates",
|
|
196
|
+
"migrationDir": "supabase/migrations",
|
|
197
|
+
"buildLog": "supabase/migrations-templates/.buildlog.json",
|
|
198
|
+
"localBuildLog": "supabase/migrations-templates/.buildlog.local.json",
|
|
199
|
+
"pgConnection": "postgresql://postgres:postgres@localhost:54322/postgres"
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Other Features đ§
|
|
204
|
+
|
|
205
|
+
### Work in Progress Templates
|
|
206
|
+
|
|
207
|
+
Add `.wip.sql` extension to templates under development to prevent accidental migration generation:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
my_function.wip.sql # Won't generate migrations during build
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Template State Management
|
|
214
|
+
|
|
215
|
+
`srtd` maintains two logs:
|
|
216
|
+
|
|
217
|
+
- `.buildlog.json` - Tracks which templates have been built into migrations (commit this)
|
|
218
|
+
- `.buildlog.local.json` - Tracks local database state (add to .gitignore)
|
|
219
|
+
|
|
220
|
+
### Register Existing Objects
|
|
221
|
+
|
|
222
|
+
Import existing database objects into the template system:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
srtd register my_function.sql # Won't generate new migration until changed
|
|
226
|
+
# or
|
|
227
|
+
srtd register # Opens interactive UI for selecting multiple templates
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Development đ ď¸
|
|
231
|
+
|
|
232
|
+
This project uses TypeScript and modern Node.js features. To contribute:
|
|
233
|
+
|
|
234
|
+
1. Set up the development environment:
|
|
235
|
+
```bash
|
|
236
|
+
git clone https://github.com/stokke/srtd.git
|
|
237
|
+
cd srtd
|
|
238
|
+
npm install
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
2. Start development:
|
|
242
|
+
```bash
|
|
243
|
+
npm run dev # Watches for changes
|
|
244
|
+
npm test # Runs tests
|
|
245
|
+
npm start # Builds, links, and runs CLI
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
3. Other useful commands:
|
|
249
|
+
```bash
|
|
250
|
+
npm run typecheck # Type checking
|
|
251
|
+
npm run lint # Lint and fix
|
|
252
|
+
npm run test:coverage # Test coverage
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Contributing đ¤
|
|
256
|
+
|
|
257
|
+
This tool was built to solve specific problems in our [Supabase](https://supabase.com) development workflow. While it's considered feature-complete for our needs, we welcome improvements through pull requests, especially for:
|
|
258
|
+
|
|
259
|
+
- Bug fixes and reliability improvements
|
|
260
|
+
- Documentation improvements and examples
|
|
261
|
+
- Test coverage
|
|
262
|
+
- Performance optimizations
|
|
263
|
+
|
|
264
|
+
### Contribution Guidelines
|
|
265
|
+
|
|
266
|
+
1. Create a [changeset](https://github.com/changesets/changesets) (`npm run changeset`)
|
|
267
|
+
2. Ensure tests pass (`npm test`)
|
|
268
|
+
3. Follow existing code style
|
|
269
|
+
4. Update documentation as needed
|
|
270
|
+
|
|
271
|
+
Note that new features may or may not be accepted depending on whether they align with the project's focused scope. However, improvements to existing functionality, documentation, and tests are always welcome!
|
|
272
|
+
|
|
273
|
+
## License
|
|
274
|
+
|
|
275
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
276
|
+
|
|
277
|
+
Made with đŞ by [Timm Stokke](https://timm.stokke.me) & [Claude Sonnet](https://claude.ai)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterAll, beforeAll, vi } from 'vitest';
|
|
5
|
+
import { connect, disconnect } from '../utils/databaseConnection.js';
|
|
6
|
+
export const TEST_FN_PREFIX = 'srtd_scoped_test_func_';
|
|
7
|
+
export const TEST_ROOT = join(tmpdir(), `srtd-test-${Date.now()}`);
|
|
8
|
+
if (process.env.CI) {
|
|
9
|
+
let consoleLogMock;
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
consoleLogMock = vi.spyOn(console, 'log').mockImplementation(() => {
|
|
12
|
+
// Do nothing
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
afterAll(() => {
|
|
16
|
+
consoleLogMock.mockRestore();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
beforeAll(async () => {
|
|
20
|
+
await fs.mkdir(TEST_ROOT, { recursive: true });
|
|
21
|
+
});
|
|
22
|
+
afterAll(async () => {
|
|
23
|
+
await fs.rm(TEST_ROOT, { recursive: true, force: true });
|
|
24
|
+
// Be extra sure to clean up any test functions from db
|
|
25
|
+
const client = await connect();
|
|
26
|
+
try {
|
|
27
|
+
await client.query('BEGIN');
|
|
28
|
+
await client.query(`
|
|
29
|
+
DO $$
|
|
30
|
+
DECLARE
|
|
31
|
+
r record;
|
|
32
|
+
BEGIN
|
|
33
|
+
FOR r IN
|
|
34
|
+
SELECT quote_ident(proname) AS func_name
|
|
35
|
+
FROM pg_proc
|
|
36
|
+
WHERE proname LIKE '${TEST_FN_PREFIX}%'
|
|
37
|
+
LOOP
|
|
38
|
+
EXECUTE 'DROP FUNCTION IF EXISTS ' || r.func_name;
|
|
39
|
+
END LOOP;
|
|
40
|
+
END;
|
|
41
|
+
$$
|
|
42
|
+
`);
|
|
43
|
+
await client.query('COMMIT');
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
await client.query('ROLLBACK');
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
client.release();
|
|
51
|
+
}
|
|
52
|
+
disconnect();
|
|
53
|
+
});
|
|
54
|
+
vi.mock('../utils/config', async (importOriginal) => {
|
|
55
|
+
const actual = (await importOriginal());
|
|
56
|
+
return {
|
|
57
|
+
...actual,
|
|
58
|
+
getConfig: vi.fn().mockResolvedValue({
|
|
59
|
+
wipIndicator: '.wip',
|
|
60
|
+
filter: '**/*.sql',
|
|
61
|
+
templateDir: 'test-templates',
|
|
62
|
+
migrationDir: 'test-migrations',
|
|
63
|
+
buildLog: '.buildlog-test.json',
|
|
64
|
+
localBuildLog: '.buildlog-test.local.json',
|
|
65
|
+
pgConnection: process.env.POSTGRES_URL || 'postgresql://postgres:postgres@localhost:54322/postgres',
|
|
66
|
+
banner: 'Test banner',
|
|
67
|
+
footer: 'Test footer',
|
|
68
|
+
wrapInTransaction: true,
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=vitest.setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.setup.js","sourceRoot":"","sources":["../../src/__tests__/vitest.setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAEnE,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IACnB,IAAI,cAA2C,CAAC;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE;YAChE,aAAa;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE;QACZ,cAAc,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;IAClB,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,uDAAuD;IACvD,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;gCAQS,cAAc;;;;;;KAMzC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,CAAC,CAAC;IACV,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,UAAU,EAAE,CAAC;AACf,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE;IAChD,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,EAAE,CAAwC,CAAC;IAC/E,OAAO;QACL,GAAG,MAAM;QACT,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YACnC,YAAY,EAAE,MAAM;YACpB,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,gBAAgB;YAC7B,YAAY,EAAE,iBAAiB;YAC/B,QAAQ,EAAE,qBAAqB;YAC/B,aAAa,EAAE,2BAA2B;YAC1C,YAAY,EACV,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,yDAAyD;YACvF,MAAM,EAAE,aAAa;YACrB,MAAM,EAAE,aAAa;YACrB,iBAAiB,EAAE,IAAI;SACxB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { render } from 'ink-testing-library';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
4
|
+
import Watch from '../commands/watch.js';
|
|
5
|
+
vi.mock('ink', async (importOriginal) => {
|
|
6
|
+
const actual = (await importOriginal());
|
|
7
|
+
return {
|
|
8
|
+
...actual,
|
|
9
|
+
useApp: () => ({ exit: vi.fn() }),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
describe('Watch Command', () => {
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
test('renders initial state with no templates', async () => {
|
|
17
|
+
const { lastFrame } = render(React.createElement(Watch, null));
|
|
18
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
19
|
+
const output = lastFrame();
|
|
20
|
+
expect(output).toContain('Watch Mode');
|
|
21
|
+
expect(output).toContain('Watching for template changes');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=watch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.test.js","sourceRoot":"","sources":["../../src/__tests__/watch.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAChE,OAAO,KAAK,MAAM,sBAAsB,CAAC;AAEzC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE;IACpC,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,EAAE,CAAyB,CAAC;IAChE,OAAO;QACL,GAAG,MAAM;QACT,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;KAClC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,oBAAC,KAAK,OAAG,CAAC,CAAC;QACxC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC,IAAI;CACxB,CAAC,CAAC;AAEH,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Box } from 'ink';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export default function App({ Component, commandProps }) {
|
|
4
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
5
|
+
React.createElement(Component, { ...commandProps })));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=_app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_app.js","sourceRoot":"","sources":["../../src/commands/_app.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY,EAAY;IAC/D,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,SAAS,OAAK,YAAY,GAAI,CAC3B,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function Apply(): null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TemplateManager } from '../lib/templateManager.js';
|
|
3
|
+
export default function Apply() {
|
|
4
|
+
React.useEffect(() => {
|
|
5
|
+
async function doApply() {
|
|
6
|
+
try {
|
|
7
|
+
const manager = await TemplateManager.create(process.cwd());
|
|
8
|
+
await manager.processTemplates({ apply: true });
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
console.error('Error:', err instanceof Error ? err.message : String(err));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
void doApply();
|
|
17
|
+
}, []);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,CAAC,OAAO,UAAU,KAAK;IAC3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,KAAK,UAAU,OAAO;YACpB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC5D,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function Build(): null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// commands/build.tsx
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { TemplateManager } from '../lib/templateManager.js';
|
|
4
|
+
export default function Build() {
|
|
5
|
+
React.useEffect(() => {
|
|
6
|
+
async function doBuild() {
|
|
7
|
+
const manager = await TemplateManager.create(process.cwd());
|
|
8
|
+
await manager.processTemplates({ generateFiles: true });
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
doBuild();
|
|
12
|
+
}, []);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.tsx"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,CAAC,OAAO,UAAU,KAAK;IAC3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,KAAK,UAAU,OAAO;YACpB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAC5D,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Select } from '@inkjs/ui';
|
|
2
|
+
import { Box } from 'ink';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import Branding from '../components/Branding.js';
|
|
5
|
+
import Apply from './apply.js';
|
|
6
|
+
import Build from './build.js';
|
|
7
|
+
import Register from './register.js';
|
|
8
|
+
import Watch from './watch.js';
|
|
9
|
+
export default function UI() {
|
|
10
|
+
const [selectedCommand, setSelectedCommand] = React.useState(null);
|
|
11
|
+
// For now, we only demonstrate navigation to "register"
|
|
12
|
+
if (selectedCommand === 'register') {
|
|
13
|
+
return React.createElement(Register, { args: undefined });
|
|
14
|
+
}
|
|
15
|
+
if (selectedCommand === 'apply') {
|
|
16
|
+
return React.createElement(Apply, null);
|
|
17
|
+
}
|
|
18
|
+
if (selectedCommand === 'build') {
|
|
19
|
+
return React.createElement(Build, null);
|
|
20
|
+
}
|
|
21
|
+
if (selectedCommand === 'watch') {
|
|
22
|
+
return React.createElement(Watch, null);
|
|
23
|
+
}
|
|
24
|
+
const menuItems = [
|
|
25
|
+
{ label: 'đď¸ build - Build Supabase migrations from templates', value: 'build' },
|
|
26
|
+
{ label: 'âśď¸ apply - Apply migration templates directly to database', value: 'apply' },
|
|
27
|
+
{ label: 'âď¸ register - Register templates as already built', value: 'register' },
|
|
28
|
+
{
|
|
29
|
+
label: 'đ watch - Watch templates for changes and apply directly to database',
|
|
30
|
+
value: 'watch',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
34
|
+
React.createElement(Branding, null),
|
|
35
|
+
React.createElement(Select, { options: menuItems, onChange: value => setSelectedCommand(value) })));
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,CAAC,OAAO,UAAU,EAAE;IACxB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAElF,wDAAwD;IACxD,IAAI,eAAe,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,oBAAC,QAAQ,IAAC,IAAI,EAAE,SAAS,GAAI,CAAC;IACvC,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAG;QAChB,EAAE,KAAK,EAAE,uDAAuD,EAAE,KAAK,EAAE,OAAO,EAAE;QAClF,EAAE,KAAK,EAAE,4DAA4D,EAAE,KAAK,EAAE,OAAO,EAAE;QACvF,EAAE,KAAK,EAAE,oDAAoD,EAAE,KAAK,EAAE,UAAU,EAAE;QAClF;YACE,KAAK,EAAE,wEAAwE;YAC/E,KAAK,EAAE,OAAO;SACf;KACF,CAAC;IAEF,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,QAAQ,OAAG;QACZ,oBAAC,MAAM,IAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAI,CACxE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function Init(): null;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { CONFIG_FILE } from '../constants.js';
|
|
6
|
+
import { getConfig, saveConfig } from '../utils/config.js';
|
|
7
|
+
import { createEmptyBuildLog } from '../utils/createEmptyBuildLog.js';
|
|
8
|
+
import { ensureDirectories } from '../utils/ensureDirectories.js';
|
|
9
|
+
import { fileExists } from '../utils/fileExists.js';
|
|
10
|
+
import { logger } from '../utils/logger.js';
|
|
11
|
+
export default function Init() {
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
async function doInit() {
|
|
14
|
+
console.log(`${chalk.green('\n⨠Initializing srtd\n')}`);
|
|
15
|
+
try {
|
|
16
|
+
const baseDir = process.cwd();
|
|
17
|
+
const config = await getConfig(baseDir);
|
|
18
|
+
const configPath = path.join(baseDir, CONFIG_FILE);
|
|
19
|
+
if (await fileExists(configPath)) {
|
|
20
|
+
logger.skip(`${CONFIG_FILE} already exists`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await saveConfig(baseDir, {});
|
|
24
|
+
logger.success(`Created ${CONFIG_FILE} with default configuration`);
|
|
25
|
+
}
|
|
26
|
+
const dirs = await ensureDirectories(baseDir);
|
|
27
|
+
if (dirs.templateDir) {
|
|
28
|
+
logger.success(`Created template directory ${config.templateDir}`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logger.skip(`Template directory ${config.templateDir} already exists`);
|
|
32
|
+
}
|
|
33
|
+
if (dirs.migrationDir) {
|
|
34
|
+
logger.success(`Created migration directory ${config.migrationDir}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
logger.skip(`Migration directory ${config.migrationDir} already exists`);
|
|
38
|
+
}
|
|
39
|
+
const buildLogCreated = await createEmptyBuildLog(path.join(baseDir, config.buildLog));
|
|
40
|
+
const localBuildLogCreated = await createEmptyBuildLog(path.join(baseDir, config.localBuildLog));
|
|
41
|
+
if (buildLogCreated) {
|
|
42
|
+
logger.success(`Created build log at ${config.buildLog}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
logger.skip(`Build log already exists at ${config.buildLog}`);
|
|
46
|
+
}
|
|
47
|
+
if (localBuildLogCreated) {
|
|
48
|
+
logger.success(`Created local build log at ${config.localBuildLog}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
logger.skip(`Local build log already exists at ${config.localBuildLog}`);
|
|
52
|
+
}
|
|
53
|
+
const gitignorePath = path.join(baseDir, '.gitignore');
|
|
54
|
+
const ignoreEntry = path.basename(config.localBuildLog);
|
|
55
|
+
let content = '';
|
|
56
|
+
try {
|
|
57
|
+
content = await fs.readFile(gitignorePath, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Ignore
|
|
61
|
+
}
|
|
62
|
+
if (!content.includes(ignoreEntry)) {
|
|
63
|
+
content = `${content.trim()}\n\n# srtd's local logs should not be committed, as they're per-environment specific\n${ignoreEntry}\n`;
|
|
64
|
+
await fs.writeFile(gitignorePath, content);
|
|
65
|
+
logger.success(`Added ${ignoreEntry} to .gitignore`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
logger.skip(`.gitignore already contains ${ignoreEntry}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
logger.error(`Failed to initialize: ${JSON.stringify(error)}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
doInit();
|
|
77
|
+
}, []);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import zod from 'zod';
|
|
3
|
+
export declare const args: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
|
|
4
|
+
type Props = {
|
|
5
|
+
args: zod.infer<typeof args>;
|
|
6
|
+
};
|
|
7
|
+
export default function Register({ args: templateArgs }: Props): React.JSX.Element;
|
|
8
|
+
export {};
|