@impulselab/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.js +86 -8
  2. package/package.json +18 -9
  3. package/src/commands/add.test.ts +0 -147
  4. package/src/commands/add.ts +0 -335
  5. package/src/commands/init.ts +0 -114
  6. package/src/commands/list.ts +0 -79
  7. package/src/config/config-path.ts +0 -7
  8. package/src/config/has-config.ts +0 -9
  9. package/src/config/index.ts +0 -4
  10. package/src/config/read-config.ts +0 -20
  11. package/src/config/write-config.ts +0 -11
  12. package/src/config.test.ts +0 -64
  13. package/src/index.ts +0 -64
  14. package/src/installer.ts +0 -71
  15. package/src/registry/fetch-module-file.ts +0 -21
  16. package/src/registry/fetch-module-manifest.ts +0 -43
  17. package/src/registry/github-urls.ts +0 -13
  18. package/src/registry/index.ts +0 -5
  19. package/src/registry/list-available-modules.ts +0 -113
  20. package/src/registry/parse-module-id.ts +0 -30
  21. package/src/registry/registry.test.ts +0 -181
  22. package/src/schemas/impulse-config.ts +0 -21
  23. package/src/schemas/index.ts +0 -9
  24. package/src/schemas/module-dependency.ts +0 -3
  25. package/src/schemas/module-file.ts +0 -8
  26. package/src/schemas/module-manifest.ts +0 -23
  27. package/src/schemas/module-transform.ts +0 -15
  28. package/src/transforms/add-env.ts +0 -53
  29. package/src/transforms/add-nav-item.test.ts +0 -125
  30. package/src/transforms/add-nav-item.ts +0 -70
  31. package/src/transforms/append-export.test.ts +0 -50
  32. package/src/transforms/append-export.ts +0 -34
  33. package/src/transforms/index.ts +0 -32
  34. package/src/transforms/merge-schema.test.ts +0 -70
  35. package/src/transforms/merge-schema.ts +0 -35
  36. package/src/transforms/register-route.test.ts +0 -177
  37. package/src/transforms/register-route.ts +0 -47
  38. package/src/types.ts +0 -9
  39. package/tsconfig.json +0 -8
@@ -1,70 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdtemp, rm } from "fs/promises";
3
- import { outputFile, readFile } from "fs-extra";
4
- import path from "path";
5
- import os from "os";
6
- import { mergeSchema } from "./merge-schema";
7
-
8
- let tmpDir: string;
9
-
10
- beforeEach(async () => {
11
- tmpDir = await mkdtemp(path.join(os.tmpdir(), "impulse-test-"));
12
- });
13
-
14
- afterEach(async () => {
15
- await rm(tmpDir, { recursive: true, force: true });
16
- });
17
-
18
- describe("mergeSchema", () => {
19
- it("creates schema index if it does not exist", async () => {
20
- await mergeSchema(
21
- "src/server/db/schema/index.ts",
22
- "export * from './auth'",
23
- tmpDir,
24
- false
25
- );
26
- const content = await readFile(
27
- path.join(tmpDir, "src/server/db/schema/index.ts"),
28
- "utf-8"
29
- );
30
- expect(content).toBe("export * from './auth'\n");
31
- });
32
-
33
- it("appends to existing schema index", async () => {
34
- await outputFile(
35
- path.join(tmpDir, "src/server/db/schema/index.ts"),
36
- "export * from './users'\n"
37
- );
38
- await mergeSchema(
39
- "src/server/db/schema/index.ts",
40
- "export * from './auth'",
41
- tmpDir,
42
- false
43
- );
44
- const content = await readFile(
45
- path.join(tmpDir, "src/server/db/schema/index.ts"),
46
- "utf-8"
47
- );
48
- expect(content).toBe(
49
- "export * from './users'\nexport * from './auth'\n"
50
- );
51
- });
52
-
53
- it("skips duplicates", async () => {
54
- await outputFile(
55
- path.join(tmpDir, "src/server/db/schema/index.ts"),
56
- "export * from './auth'\n"
57
- );
58
- await mergeSchema(
59
- "src/server/db/schema/index.ts",
60
- "export * from './auth'",
61
- tmpDir,
62
- false
63
- );
64
- const content = await readFile(
65
- path.join(tmpDir, "src/server/db/schema/index.ts"),
66
- "utf-8"
67
- );
68
- expect(content).toBe("export * from './auth'\n");
69
- });
70
- });
@@ -1,35 +0,0 @@
1
- import fsExtra from "fs-extra";
2
- const { readFile, outputFile, pathExists } = fsExtra;
3
- import path from "path";
4
-
5
- /**
6
- * Adds a Drizzle schema import to the main schema index file.
7
- * target: path to the schema index (e.g. "src/server/db/schema/index.ts")
8
- * value: import/export line (e.g. "export * from './auth'")
9
- */
10
- export async function mergeSchema(
11
- target: string,
12
- value: string,
13
- cwd: string,
14
- dryRun: boolean
15
- ): Promise<void> {
16
- const file = path.join(cwd, target);
17
-
18
- if (!(await pathExists(file))) {
19
- // Create new schema index
20
- if (!dryRun) {
21
- await outputFile(file, `${value}\n`, "utf-8");
22
- }
23
- return;
24
- }
25
-
26
- const content = await readFile(file, "utf-8");
27
- if (content.includes(value)) return;
28
-
29
- if (!dryRun) {
30
- const newContent = content.endsWith("\n")
31
- ? `${content}${value}\n`
32
- : `${content}\n${value}\n`;
33
- await outputFile(file, newContent, "utf-8");
34
- }
35
- }
@@ -1,177 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { mkdtemp, rm } from "fs/promises";
3
- import { outputFile, readFile } from "fs-extra";
4
- import path from "path";
5
- import os from "os";
6
- import { registerRoute } from "./register-route";
7
-
8
- let tmpDir: string;
9
-
10
- beforeEach(async () => {
11
- tmpDir = await mkdtemp(path.join(os.tmpdir(), "impulse-route-test-"));
12
- });
13
-
14
- afterEach(async () => {
15
- await rm(tmpDir, { recursive: true, force: true });
16
- });
17
-
18
- const satisfiesRouter = `import { createRouter } from "@orpc/server";
19
- import { healthRouter } from "./health";
20
-
21
- export const appRouter = createRouter({
22
- health: healthRouter,
23
- } satisfies RouterInput);
24
- `;
25
-
26
- const asRouter = `import { createRouter } from "@orpc/server";
27
- import { healthRouter } from "./health";
28
-
29
- export const appRouter = {
30
- health: healthRouter,
31
- } as AppRouter;
32
- `;
33
-
34
- // Router that contains an inline `as` type cast inside a nested expression
35
- // — the fix must NOT insert into the inline cast.
36
- const routerWithInlineAs = `import { createRouter } from "@orpc/server";
37
-
38
- function helper(x: unknown) {
39
- return (x as string).toUpperCase();
40
- }
41
-
42
- export const appRouter = createRouter({
43
- health: healthRouter,
44
- } satisfies RouterInput);
45
- `;
46
-
47
- // Router where another typed object's `}` appears on its own line before
48
- // `satisfies`/`as` on the next line — cross-line match must be avoided.
49
- const routerWithCrossLineSatisfies = `const config = {
50
- setting: true,
51
- }
52
- satisfies ConfigType;
53
-
54
- export const appRouter = createRouter({
55
- health: healthRouter,
56
- } satisfies RouterInput);
57
- `;
58
-
59
- describe("registerRoute", () => {
60
- it("inserts route into a 'satisfies' router", async () => {
61
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
62
- await outputFile(routerFile, satisfiesRouter);
63
-
64
- await registerRoute(
65
- "src/server/api/router.ts",
66
- "auth: authRouter",
67
- tmpDir,
68
- false
69
- );
70
-
71
- const result = await readFile(routerFile, "utf-8");
72
- expect(result).toContain("auth: authRouter");
73
- expect(result).toContain("health: healthRouter");
74
- });
75
-
76
- it("inserts route into an 'as' router", async () => {
77
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
78
- await outputFile(routerFile, asRouter);
79
-
80
- await registerRoute(
81
- "src/server/api/router.ts",
82
- "auth: authRouter",
83
- tmpDir,
84
- false
85
- );
86
-
87
- const result = await readFile(routerFile, "utf-8");
88
- expect(result).toContain("auth: authRouter");
89
- });
90
-
91
- it("does not match when } and satisfies/as are on separate lines (cross-line false match)", async () => {
92
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
93
- await outputFile(routerFile, routerWithCrossLineSatisfies);
94
-
95
- await registerRoute(
96
- "src/server/api/router.ts",
97
- "auth: authRouter",
98
- tmpDir,
99
- false
100
- );
101
-
102
- const result = await readFile(routerFile, "utf-8");
103
- // Route must appear near the appRouter closing, not near the config object
104
- const insertIdx = result.indexOf("auth: authRouter");
105
- const configSatisfiesIdx = result.indexOf("}\nsatisfies ConfigType");
106
- expect(insertIdx).toBeGreaterThan(configSatisfiesIdx);
107
- });
108
-
109
- it("does not match inline 'as' casts inside nested expressions", async () => {
110
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
111
- await outputFile(routerFile, routerWithInlineAs);
112
-
113
- await registerRoute(
114
- "src/server/api/router.ts",
115
- "auth: authRouter",
116
- tmpDir,
117
- false
118
- );
119
-
120
- const result = await readFile(routerFile, "utf-8");
121
- // Route must appear just before `} satisfies`, not before `} as string`
122
- const insertIdx = result.indexOf("auth: authRouter");
123
- const satisfiesIdx = result.indexOf("} satisfies");
124
- expect(insertIdx).toBeGreaterThan(-1);
125
- expect(insertIdx).toBeLessThan(satisfiesIdx);
126
- });
127
-
128
- it("does not insert duplicate routes", async () => {
129
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
130
- await outputFile(routerFile, satisfiesRouter);
131
-
132
- await registerRoute(
133
- "src/server/api/router.ts",
134
- "health: healthRouter",
135
- tmpDir,
136
- false
137
- );
138
-
139
- const result = await readFile(routerFile, "utf-8");
140
- expect(result.split("health: healthRouter").length - 1).toBe(1);
141
- });
142
-
143
- it("does not write file in dry-run mode", async () => {
144
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
145
- await outputFile(routerFile, satisfiesRouter);
146
-
147
- await registerRoute(
148
- "src/server/api/router.ts",
149
- "auth: authRouter",
150
- tmpDir,
151
- true
152
- );
153
-
154
- const result = await readFile(routerFile, "utf-8");
155
- expect(result).toBe(satisfiesRouter);
156
- });
157
-
158
- it("throws if file not found", async () => {
159
- await expect(
160
- registerRoute("nonexistent/router.ts", "auth: authRouter", tmpDir, false)
161
- ).rejects.toThrow("target file not found");
162
- });
163
-
164
- it("throws if no router closing brace found", async () => {
165
- const routerFile = path.join(tmpDir, "src/server/api/router.ts");
166
- await outputFile(routerFile, `export const foo = "bar";\n`);
167
-
168
- await expect(
169
- registerRoute(
170
- "src/server/api/router.ts",
171
- "auth: authRouter",
172
- tmpDir,
173
- false
174
- )
175
- ).rejects.toThrow("could not find router closing brace");
176
- });
177
- });
@@ -1,47 +0,0 @@
1
- import fsExtra from "fs-extra";
2
- const { readFile, outputFile, pathExists } = fsExtra;
3
- import path from "path";
4
-
5
- /**
6
- * Registers an oRPC route in the router file.
7
- * target: path to the router file (e.g. "src/server/api/router.ts")
8
- * value: the route line to add (e.g. "auth: authRouter")
9
- */
10
- export async function registerRoute(
11
- target: string,
12
- value: string,
13
- cwd: string,
14
- dryRun: boolean
15
- ): Promise<void> {
16
- const file = path.join(cwd, target);
17
-
18
- if (!(await pathExists(file))) {
19
- throw new Error(
20
- `register-route: target file not found: ${target}. Please ensure your router file exists.`
21
- );
22
- }
23
-
24
- const content = await readFile(file, "utf-8");
25
- if (content.includes(value)) return;
26
-
27
- // Find the router object closing brace and insert before it.
28
- // Anchored to start-of-line (multiline) with [ \t]* (no newlines) to avoid
29
- // matching `}` on one line with `satisfies`/`as` on a subsequent line.
30
- const routerPattern = /^([ \t]*\})[ \t]*(?:satisfies|as)\s/m;
31
- const match = routerPattern.exec(content);
32
-
33
- if (!match) {
34
- throw new Error(
35
- `register-route: could not find router closing brace in ${target}. Add "${value}" manually.`
36
- );
37
- }
38
-
39
- if (!dryRun) {
40
- const insertPos = match.index;
41
- const newContent =
42
- content.slice(0, insertPos) +
43
- ` ${value},\n` +
44
- content.slice(insertPos);
45
- await outputFile(file, newContent, "utf-8");
46
- }
47
- }
package/src/types.ts DELETED
@@ -1,9 +0,0 @@
1
- export { ModuleFileSchema } from "./schemas/module-file";
2
- export type { ModuleFile } from "./schemas/module-file";
3
- export { ModuleDependencySchema } from "./schemas/module-dependency";
4
- export { ModuleTransformSchema } from "./schemas/module-transform";
5
- export type { ModuleTransform } from "./schemas/module-transform";
6
- export { ModuleManifestSchema } from "./schemas/module-manifest";
7
- export type { ModuleManifest } from "./schemas/module-manifest";
8
- export { ImpulseConfigSchema } from "./schemas/impulse-config";
9
- export type { ImpulseConfig } from "./schemas/impulse-config";
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist"
6
- },
7
- "include": ["src/**/*"]
8
- }