@simplysm/sd-cli 13.0.68 → 13.0.70
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 +10 -957
- package/dist/builders/BaseBuilder.d.ts +23 -23
- package/dist/builders/BaseBuilder.d.ts.map +1 -1
- package/dist/builders/BaseBuilder.js +15 -15
- package/dist/builders/DtsBuilder.d.ts +4 -4
- package/dist/builders/DtsBuilder.js +1 -1
- package/dist/builders/LibraryBuilder.d.ts +3 -3
- package/dist/builders/types.d.ts +10 -10
- package/dist/capacitor/capacitor.d.ts +36 -36
- package/dist/capacitor/capacitor.js +63 -63
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/add-client.d.ts +8 -8
- package/dist/commands/add-client.js +15 -15
- package/dist/commands/add-client.js.map +1 -1
- package/dist/commands/add-server.d.ts +9 -9
- package/dist/commands/add-server.js +13 -13
- package/dist/commands/add-server.js.map +1 -1
- package/dist/commands/build.d.ts +9 -9
- package/dist/commands/check.js +3 -3
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/dev.d.ts +9 -9
- package/dist/commands/device.d.ts +9 -9
- package/dist/commands/device.d.ts.map +1 -1
- package/dist/commands/device.js +17 -17
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/init.d.ts +6 -6
- package/dist/commands/init.js +12 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/lint.d.ts +23 -23
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +25 -25
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.d.ts +13 -13
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +61 -61
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.d.ts +3 -3
- package/dist/commands/replace-deps.d.ts.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/commands/typecheck.d.ts +20 -20
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +20 -20
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/commands/watch.d.ts +7 -7
- package/dist/electron/electron.d.ts +27 -27
- package/dist/electron/electron.js +32 -32
- package/dist/electron/electron.js.map +1 -1
- package/dist/infra/ResultCollector.d.ts +9 -9
- package/dist/infra/ResultCollector.js +5 -5
- package/dist/infra/SignalHandler.d.ts +7 -7
- package/dist/infra/SignalHandler.js +4 -4
- package/dist/infra/WorkerManager.d.ts +14 -14
- package/dist/infra/WorkerManager.js +11 -11
- package/dist/orchestrators/BuildOrchestrator.d.ts +19 -19
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +26 -26
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevOrchestrator.d.ts +25 -25
- package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevOrchestrator.js +30 -30
- package/dist/orchestrators/DevOrchestrator.js.map +1 -1
- package/dist/orchestrators/WatchOrchestrator.d.ts +13 -13
- package/dist/orchestrators/WatchOrchestrator.js +17 -17
- package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +2 -2
- package/dist/sd-cli-entry.js +38 -38
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.d.ts +2 -2
- package/dist/sd-cli.js +1 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +84 -84
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/build-env.d.ts +1 -1
- package/dist/utils/config-editor.d.ts +5 -5
- package/dist/utils/config-editor.js +2 -2
- package/dist/utils/config-editor.js.map +1 -1
- package/dist/utils/copy-public.d.ts +9 -9
- package/dist/utils/copy-src.d.ts +9 -9
- package/dist/utils/esbuild-config.d.ts +30 -30
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/output-utils.d.ts +6 -6
- package/dist/utils/package-utils.d.ts +6 -6
- package/dist/utils/package-utils.js +1 -1
- package/dist/utils/package-utils.js.map +1 -1
- package/dist/utils/rebuild-manager.js +3 -3
- package/dist/utils/rebuild-manager.js.map +1 -1
- package/dist/utils/replace-deps.d.ts +25 -25
- package/dist/utils/replace-deps.js +3 -3
- package/dist/utils/replace-deps.js.map +1 -1
- package/dist/utils/sd-config.d.ts +3 -3
- package/dist/utils/sd-config.js +3 -3
- package/dist/utils/sd-config.js.map +1 -1
- package/dist/utils/tailwind-config-deps.d.ts +3 -3
- package/dist/utils/template.d.ts +8 -8
- package/dist/utils/tsconfig.d.ts +16 -16
- package/dist/utils/tsconfig.js +2 -2
- package/dist/utils/tsconfig.js.map +1 -1
- package/dist/utils/typecheck-serialization.d.ts +8 -8
- package/dist/utils/vite-config.d.ts +8 -8
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +3 -3
- package/dist/utils/worker-events.d.ts +12 -12
- package/dist/utils/worker-events.d.ts.map +1 -1
- package/dist/utils/worker-utils.d.ts +3 -3
- package/dist/utils/worker-utils.js +2 -2
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts +14 -14
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +1 -1
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/dts.worker.d.ts +13 -13
- package/dist/workers/dts.worker.d.ts.map +1 -1
- package/dist/workers/dts.worker.js +3 -3
- package/dist/workers/dts.worker.js.map +1 -1
- package/dist/workers/library.worker.d.ts +12 -12
- package/dist/workers/library.worker.js +1 -1
- package/dist/workers/library.worker.js.map +1 -1
- package/dist/workers/lint.worker.d.ts +1 -1
- package/dist/workers/server-runtime.worker.d.ts +6 -6
- package/dist/workers/server-runtime.worker.js +6 -6
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/dist/workers/server.worker.d.ts +20 -20
- package/dist/workers/server.worker.d.ts.map +1 -1
- package/dist/workers/server.worker.js +6 -6
- package/dist/workers/server.worker.js.map +1 -1
- package/package.json +8 -7
- package/src/builders/BaseBuilder.ts +33 -33
- package/src/builders/DtsBuilder.ts +5 -5
- package/src/builders/LibraryBuilder.ts +9 -9
- package/src/builders/types.ts +10 -10
- package/src/capacitor/capacitor.ts +119 -119
- package/src/commands/add-client.ts +31 -31
- package/src/commands/add-server.ts +34 -34
- package/src/commands/build.ts +9 -9
- package/src/commands/check.ts +5 -5
- package/src/commands/dev.ts +9 -9
- package/src/commands/device.ts +30 -30
- package/src/commands/init.ts +25 -25
- package/src/commands/lint.ts +64 -64
- package/src/commands/publish.ts +139 -139
- package/src/commands/replace-deps.ts +4 -4
- package/src/commands/typecheck.ts +74 -74
- package/src/commands/watch.ts +7 -7
- package/src/electron/electron.ts +51 -51
- package/src/infra/ResultCollector.ts +9 -9
- package/src/infra/SignalHandler.ts +7 -7
- package/src/infra/WorkerManager.ts +14 -14
- package/src/orchestrators/BuildOrchestrator.ts +76 -76
- package/src/orchestrators/DevOrchestrator.ts +88 -88
- package/src/orchestrators/WatchOrchestrator.ts +39 -39
- package/src/sd-cli-entry.ts +43 -43
- package/src/sd-cli.ts +15 -15
- package/src/sd-config.types.ts +85 -85
- package/src/utils/build-env.ts +1 -1
- package/src/utils/config-editor.ts +19 -19
- package/src/utils/copy-public.ts +17 -17
- package/src/utils/copy-src.ts +11 -11
- package/src/utils/esbuild-config.ts +33 -33
- package/src/utils/output-utils.ts +11 -11
- package/src/utils/package-utils.ts +12 -12
- package/src/utils/rebuild-manager.ts +3 -3
- package/src/utils/replace-deps.ts +361 -361
- package/src/utils/sd-config.ts +44 -44
- package/src/utils/tailwind-config-deps.ts +98 -98
- package/src/utils/template.ts +56 -56
- package/src/utils/tsconfig.ts +127 -127
- package/src/utils/typecheck-serialization.ts +86 -86
- package/src/utils/vite-config.ts +341 -341
- package/src/utils/worker-events.ts +16 -16
- package/src/utils/worker-utils.ts +45 -45
- package/src/workers/client.worker.ts +34 -34
- package/src/workers/dts.worker.ts +467 -467
- package/src/workers/library.worker.ts +314 -314
- package/src/workers/lint.worker.ts +16 -16
- package/src/workers/server-runtime.worker.ts +157 -157
- package/src/workers/server.worker.ts +572 -572
- package/templates/add-client/__CLIENT__/package.json.hbs +1 -1
- package/templates/add-server/__SERVER__/package.json.hbs +2 -2
- package/templates/init/package.json.hbs +3 -3
- package/tests/config-editor.spec.ts +160 -0
- package/tests/copy-src.spec.ts +50 -0
- package/tests/get-compiler-options-for-package.spec.ts +139 -0
- package/tests/get-package-source-files.spec.ts +181 -0
- package/tests/get-types-from-package-json.spec.ts +107 -0
- package/tests/infra/ResultCollector.spec.ts +39 -0
- package/tests/infra/SignalHandler.spec.ts +38 -0
- package/tests/infra/WorkerManager.spec.ts +97 -0
- package/tests/load-ignore-patterns.spec.ts +188 -0
- package/tests/load-sd-config.spec.ts +137 -0
- package/tests/package-utils.spec.ts +188 -0
- package/tests/parse-root-tsconfig.spec.ts +89 -0
- package/tests/replace-deps.spec.ts +308 -0
- package/tests/run-lint.spec.ts +415 -0
- package/tests/run-typecheck.spec.ts +653 -0
- package/tests/run-watch.spec.ts +75 -0
- package/tests/sd-cli.spec.ts +330 -0
- package/tests/tailwind-config-deps.spec.ts +30 -0
- package/tests/template.spec.ts +70 -0
- package/tests/utils/rebuild-manager.spec.ts +43 -0
- package/tests/write-changed-output-files.spec.ts +97 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
|
|
5
|
+
// Mock typescript
|
|
6
|
+
vi.mock("typescript", async (importOriginal) => {
|
|
7
|
+
const actual = await importOriginal<typeof ts>();
|
|
8
|
+
return {
|
|
9
|
+
...actual,
|
|
10
|
+
default: {
|
|
11
|
+
...actual,
|
|
12
|
+
readConfigFile: vi.fn(),
|
|
13
|
+
parseJsonConfigFileContent: vi.fn(),
|
|
14
|
+
flattenDiagnosticMessageText: actual.flattenDiagnosticMessageText,
|
|
15
|
+
sys: actual.sys,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
import { parseRootTsconfig } from "../src/utils/tsconfig";
|
|
21
|
+
|
|
22
|
+
describe("parseRootTsconfig", () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("successfully parses valid tsconfig.json", () => {
|
|
32
|
+
const cwd = "/project";
|
|
33
|
+
const mockConfig = { compilerOptions: { strict: true } };
|
|
34
|
+
const mockParsedConfig: ts.ParsedCommandLine = {
|
|
35
|
+
options: { strict: true },
|
|
36
|
+
fileNames: ["/project/src/index.ts"],
|
|
37
|
+
errors: [],
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: mockConfig });
|
|
41
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue(mockParsedConfig);
|
|
42
|
+
|
|
43
|
+
const result = parseRootTsconfig(cwd);
|
|
44
|
+
|
|
45
|
+
expect(ts.readConfigFile).toHaveBeenCalledWith(
|
|
46
|
+
path.join("/project", "tsconfig.json"),
|
|
47
|
+
ts.sys.readFile,
|
|
48
|
+
);
|
|
49
|
+
expect(result).toEqual(mockParsedConfig);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("throws error when tsconfig.json fails to read", () => {
|
|
53
|
+
const cwd = "/project";
|
|
54
|
+
const mockError: ts.Diagnostic = {
|
|
55
|
+
category: ts.DiagnosticCategory.Error,
|
|
56
|
+
code: 5083,
|
|
57
|
+
messageText: "Cannot read file",
|
|
58
|
+
file: undefined,
|
|
59
|
+
start: undefined,
|
|
60
|
+
length: undefined,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ error: mockError });
|
|
64
|
+
|
|
65
|
+
expect(() => parseRootTsconfig(cwd)).toThrow("Failed to read tsconfig.json");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("throws error when tsconfig.json fails to parse", () => {
|
|
69
|
+
const cwd = "/project";
|
|
70
|
+
const mockConfig = { compilerOptions: { strict: true } };
|
|
71
|
+
const mockError: ts.Diagnostic = {
|
|
72
|
+
category: ts.DiagnosticCategory.Error,
|
|
73
|
+
code: 5024,
|
|
74
|
+
messageText: "Invalid option",
|
|
75
|
+
file: undefined,
|
|
76
|
+
start: undefined,
|
|
77
|
+
length: undefined,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
vi.mocked(ts.readConfigFile).mockReturnValue({ config: mockConfig });
|
|
81
|
+
vi.mocked(ts.parseJsonConfigFileContent).mockReturnValue({
|
|
82
|
+
options: {},
|
|
83
|
+
fileNames: [],
|
|
84
|
+
errors: [mockError],
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
expect(() => parseRootTsconfig(cwd)).toThrow("Failed to parse tsconfig.json");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
parseWorkspaceGlobs,
|
|
4
|
+
resolveReplaceDepEntries,
|
|
5
|
+
setupReplaceDeps,
|
|
6
|
+
watchReplaceDeps,
|
|
7
|
+
} from "../src/utils/replace-deps";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import os from "os";
|
|
11
|
+
|
|
12
|
+
describe("resolveReplaceDepEntries", () => {
|
|
13
|
+
test("captures glob * pattern and substitutes it in source path", () => {
|
|
14
|
+
const result = resolveReplaceDepEntries({ "@simplysm/*": "../simplysm/packages/*" }, [
|
|
15
|
+
"@simplysm/solid",
|
|
16
|
+
"@simplysm/core-common",
|
|
17
|
+
]);
|
|
18
|
+
expect(result).toEqual([
|
|
19
|
+
{ targetName: "@simplysm/solid", sourcePath: "../simplysm/packages/solid" },
|
|
20
|
+
{ targetName: "@simplysm/core-common", sourcePath: "../simplysm/packages/core-common" },
|
|
21
|
+
]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("matches exact package names without *", () => {
|
|
25
|
+
const result = resolveReplaceDepEntries({ "@other/lib": "../other-project/lib" }, [
|
|
26
|
+
"@other/lib",
|
|
27
|
+
"@other/unused",
|
|
28
|
+
]);
|
|
29
|
+
expect(result).toEqual([{ targetName: "@other/lib", sourcePath: "../other-project/lib" }]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("non-matching packages are not included in results", () => {
|
|
33
|
+
const result = resolveReplaceDepEntries({ "@simplysm/*": "../simplysm/packages/*" }, [
|
|
34
|
+
"@other/lib",
|
|
35
|
+
]);
|
|
36
|
+
expect(result).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("processes multiple replaceDeps entries", () => {
|
|
40
|
+
const result = resolveReplaceDepEntries(
|
|
41
|
+
{
|
|
42
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
43
|
+
"@other/lib": "../other/lib",
|
|
44
|
+
},
|
|
45
|
+
["@simplysm/solid", "@other/lib"],
|
|
46
|
+
);
|
|
47
|
+
expect(result).toEqual([
|
|
48
|
+
{ targetName: "@simplysm/solid", sourcePath: "../simplysm/packages/solid" },
|
|
49
|
+
{ targetName: "@other/lib", sourcePath: "../other/lib" },
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("parseWorkspaceGlobs", () => {
|
|
55
|
+
test("parses packages glob array", () => {
|
|
56
|
+
const yaml = `packages:\n - "packages/*"\n - "tools/*"`;
|
|
57
|
+
expect(parseWorkspaceGlobs(yaml)).toEqual(["packages/*", "tools/*"]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("parses glob without quotes", () => {
|
|
61
|
+
const yaml = `packages:\n - packages/*\n - tools/*`;
|
|
62
|
+
expect(parseWorkspaceGlobs(yaml)).toEqual(["packages/*", "tools/*"]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("returns empty array for empty content", () => {
|
|
66
|
+
expect(parseWorkspaceGlobs("")).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("returns empty array if packages section is missing", () => {
|
|
70
|
+
const yaml = `# some comment\nsomething: value`;
|
|
71
|
+
expect(parseWorkspaceGlobs(yaml)).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("setupReplaceDeps", () => {
|
|
76
|
+
let tmpDir: string;
|
|
77
|
+
|
|
78
|
+
beforeEach(async () => {
|
|
79
|
+
// Create test project structure in temporary directory
|
|
80
|
+
tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "sd-replace-deps-"));
|
|
81
|
+
|
|
82
|
+
// Source package (simplysm/packages/solid)
|
|
83
|
+
const sourceDir = path.join(tmpDir, "simplysm", "packages", "solid");
|
|
84
|
+
await fs.promises.mkdir(sourceDir, { recursive: true });
|
|
85
|
+
await fs.promises.writeFile(path.join(sourceDir, "index.js"), "export default 1;");
|
|
86
|
+
await fs.promises.writeFile(path.join(sourceDir, "README.md"), "readme");
|
|
87
|
+
|
|
88
|
+
// Create items to be excluded
|
|
89
|
+
await fs.promises.mkdir(path.join(sourceDir, "node_modules"), { recursive: true });
|
|
90
|
+
await fs.promises.writeFile(path.join(sourceDir, "node_modules", "dep.js"), "dep");
|
|
91
|
+
await fs.promises.writeFile(path.join(sourceDir, "package.json"), '{"name":"solid"}');
|
|
92
|
+
await fs.promises.mkdir(path.join(sourceDir, ".cache"), { recursive: true });
|
|
93
|
+
await fs.promises.writeFile(path.join(sourceDir, ".cache", "file.txt"), "cache");
|
|
94
|
+
await fs.promises.mkdir(path.join(sourceDir, "tests"), { recursive: true });
|
|
95
|
+
await fs.promises.writeFile(path.join(sourceDir, "tests", "test.spec.ts"), "test");
|
|
96
|
+
|
|
97
|
+
// Target project (app/node_modules/@simplysm/solid)
|
|
98
|
+
// pnpm style: app/node_modules/@simplysm/solid → symlink to .pnpm store
|
|
99
|
+
const appRoot = path.join(tmpDir, "app");
|
|
100
|
+
|
|
101
|
+
// .pnpm store directory (where actual contents are)
|
|
102
|
+
const pnpmStoreTarget = path.join(
|
|
103
|
+
appRoot,
|
|
104
|
+
"node_modules",
|
|
105
|
+
".pnpm",
|
|
106
|
+
"@simplysm+solid@1.0.0",
|
|
107
|
+
"node_modules",
|
|
108
|
+
"@simplysm",
|
|
109
|
+
"solid",
|
|
110
|
+
);
|
|
111
|
+
await fs.promises.mkdir(pnpmStoreTarget, { recursive: true });
|
|
112
|
+
await fs.promises.writeFile(path.join(pnpmStoreTarget, "index.js"), "old");
|
|
113
|
+
|
|
114
|
+
// node_modules/@simplysm/solid → symlink to .pnpm store
|
|
115
|
+
const nodeModulesSymlink = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
116
|
+
await fs.promises.mkdir(path.dirname(nodeModulesSymlink), { recursive: true });
|
|
117
|
+
const relativeToStore = path.relative(path.dirname(nodeModulesSymlink), pnpmStoreTarget);
|
|
118
|
+
await fs.promises.symlink(relativeToStore, nodeModulesSymlink, "dir");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
afterEach(async () => {
|
|
122
|
+
await fs.promises.rm(tmpDir, { recursive: true, force: true });
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("replaces package in node_modules by copying from source directory", async () => {
|
|
126
|
+
const appRoot = path.join(tmpDir, "app");
|
|
127
|
+
|
|
128
|
+
await setupReplaceDeps(appRoot, {
|
|
129
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const targetPath = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
133
|
+
|
|
134
|
+
// Symlink is preserved
|
|
135
|
+
const stat = await fs.promises.lstat(targetPath);
|
|
136
|
+
expect(stat.isSymbolicLink()).toBe(true);
|
|
137
|
+
|
|
138
|
+
// Verify source files are copied to symlink's actual path (.pnpm store)
|
|
139
|
+
const realPath = await fs.promises.realpath(targetPath);
|
|
140
|
+
const indexContent = await fs.promises.readFile(path.join(realPath, "index.js"), "utf-8");
|
|
141
|
+
expect(indexContent).toBe("export default 1;");
|
|
142
|
+
|
|
143
|
+
const readmeContent = await fs.promises.readFile(path.join(targetPath, "README.md"), "utf-8");
|
|
144
|
+
expect(readmeContent).toBe("readme");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("excludes node_modules, package.json, .cache, and tests when copying", async () => {
|
|
148
|
+
const appRoot = path.join(tmpDir, "app");
|
|
149
|
+
|
|
150
|
+
await setupReplaceDeps(appRoot, {
|
|
151
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const targetPath = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
155
|
+
|
|
156
|
+
// Files to be copied
|
|
157
|
+
expect(fs.existsSync(path.join(targetPath, "index.js"))).toBe(true);
|
|
158
|
+
expect(fs.existsSync(path.join(targetPath, "README.md"))).toBe(true);
|
|
159
|
+
|
|
160
|
+
// Items to be excluded
|
|
161
|
+
expect(fs.existsSync(path.join(targetPath, "node_modules"))).toBe(false);
|
|
162
|
+
expect(fs.existsSync(path.join(targetPath, "package.json"))).toBe(false);
|
|
163
|
+
expect(fs.existsSync(path.join(targetPath, ".cache"))).toBe(false);
|
|
164
|
+
expect(fs.existsSync(path.join(targetPath, "tests"))).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("skips package if source path does not exist", async () => {
|
|
168
|
+
const appRoot = path.join(tmpDir, "app");
|
|
169
|
+
|
|
170
|
+
// Create .pnpm store for no-exist package
|
|
171
|
+
const pnpmStoreNoExist = path.join(
|
|
172
|
+
appRoot,
|
|
173
|
+
"node_modules",
|
|
174
|
+
".pnpm",
|
|
175
|
+
"@simplysm+no-exist@1.0.0",
|
|
176
|
+
"node_modules",
|
|
177
|
+
"@simplysm",
|
|
178
|
+
"no-exist",
|
|
179
|
+
);
|
|
180
|
+
await fs.promises.mkdir(pnpmStoreNoExist, { recursive: true });
|
|
181
|
+
await fs.promises.writeFile(path.join(pnpmStoreNoExist, "index.js"), "no-exist-old");
|
|
182
|
+
|
|
183
|
+
// node_modules/@simplysm/no-exist → symlink to .pnpm store
|
|
184
|
+
const noExistSymlink = path.join(appRoot, "node_modules", "@simplysm", "no-exist");
|
|
185
|
+
await fs.promises.mkdir(path.dirname(noExistSymlink), { recursive: true });
|
|
186
|
+
const relativeToStore = path.relative(path.dirname(noExistSymlink), pnpmStoreNoExist);
|
|
187
|
+
await fs.promises.symlink(relativeToStore, noExistSymlink, "dir");
|
|
188
|
+
|
|
189
|
+
// Should complete without error
|
|
190
|
+
await setupReplaceDeps(appRoot, {
|
|
191
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// solid symlink is preserved, no-exist symlink remains unchanged
|
|
195
|
+
const solidPath = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
196
|
+
const solidStat = await fs.promises.lstat(solidPath);
|
|
197
|
+
expect(solidStat.isSymbolicLink()).toBe(true);
|
|
198
|
+
|
|
199
|
+
const noExistStat = await fs.promises.lstat(noExistSymlink);
|
|
200
|
+
expect(noExistStat.isSymbolicLink()).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("processes node_modules in workspace packages", async () => {
|
|
204
|
+
const appRoot = path.join(tmpDir, "app");
|
|
205
|
+
|
|
206
|
+
// Create workspace package structure (.pnpm store style)
|
|
207
|
+
const pkgPnpmStore = path.join(
|
|
208
|
+
appRoot,
|
|
209
|
+
"packages",
|
|
210
|
+
"client",
|
|
211
|
+
"node_modules",
|
|
212
|
+
".pnpm",
|
|
213
|
+
"@simplysm+solid@1.0.0",
|
|
214
|
+
"node_modules",
|
|
215
|
+
"@simplysm",
|
|
216
|
+
"solid",
|
|
217
|
+
);
|
|
218
|
+
await fs.promises.mkdir(pkgPnpmStore, { recursive: true });
|
|
219
|
+
await fs.promises.writeFile(path.join(pkgPnpmStore, "index.js"), "old");
|
|
220
|
+
|
|
221
|
+
// node_modules/@simplysm/solid → symlink to .pnpm store
|
|
222
|
+
const pkgNodeModulesSymlink = path.join(
|
|
223
|
+
appRoot,
|
|
224
|
+
"packages",
|
|
225
|
+
"client",
|
|
226
|
+
"node_modules",
|
|
227
|
+
"@simplysm",
|
|
228
|
+
"solid",
|
|
229
|
+
);
|
|
230
|
+
await fs.promises.mkdir(path.dirname(pkgNodeModulesSymlink), { recursive: true });
|
|
231
|
+
const relativeToStore = path.relative(path.dirname(pkgNodeModulesSymlink), pkgPnpmStore);
|
|
232
|
+
await fs.promises.symlink(relativeToStore, pkgNodeModulesSymlink, "dir");
|
|
233
|
+
|
|
234
|
+
// Create pnpm-workspace.yaml
|
|
235
|
+
await fs.promises.writeFile(
|
|
236
|
+
path.join(appRoot, "pnpm-workspace.yaml"),
|
|
237
|
+
"packages:\n - packages/*\n",
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
await setupReplaceDeps(appRoot, {
|
|
241
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Workspace package's node_modules symlink is also preserved
|
|
245
|
+
const stat = await fs.promises.lstat(pkgNodeModulesSymlink);
|
|
246
|
+
expect(stat.isSymbolicLink()).toBe(true);
|
|
247
|
+
|
|
248
|
+
// Verify source files are copied to symlink's actual path
|
|
249
|
+
const realPath = await fs.promises.realpath(pkgNodeModulesSymlink);
|
|
250
|
+
const indexContent = await fs.promises.readFile(path.join(realPath, "index.js"), "utf-8");
|
|
251
|
+
expect(indexContent).toBe("export default 1;");
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
describe("watchReplaceDeps", () => {
|
|
256
|
+
let tmpDir: string;
|
|
257
|
+
|
|
258
|
+
beforeEach(async () => {
|
|
259
|
+
tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "sd-watch-replace-"));
|
|
260
|
+
|
|
261
|
+
// 소스 패키지 (simplysm/packages/solid)
|
|
262
|
+
const sourceDir = path.join(tmpDir, "simplysm", "packages", "solid");
|
|
263
|
+
await fs.promises.mkdir(sourceDir, { recursive: true });
|
|
264
|
+
await fs.promises.writeFile(path.join(sourceDir, "index.js"), "export default 1;");
|
|
265
|
+
|
|
266
|
+
// 대상 프로젝트 (.pnpm 스토어 방식)
|
|
267
|
+
const appRoot = path.join(tmpDir, "app");
|
|
268
|
+
const pnpmStoreTarget = path.join(
|
|
269
|
+
appRoot,
|
|
270
|
+
"node_modules",
|
|
271
|
+
".pnpm",
|
|
272
|
+
"@simplysm+solid@1.0.0",
|
|
273
|
+
"node_modules",
|
|
274
|
+
"@simplysm",
|
|
275
|
+
"solid",
|
|
276
|
+
);
|
|
277
|
+
await fs.promises.mkdir(pnpmStoreTarget, { recursive: true });
|
|
278
|
+
await fs.promises.writeFile(path.join(pnpmStoreTarget, "index.js"), "old");
|
|
279
|
+
|
|
280
|
+
const nodeModulesSymlink = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
281
|
+
await fs.promises.mkdir(path.dirname(nodeModulesSymlink), { recursive: true });
|
|
282
|
+
const relativeToStore = path.relative(path.dirname(nodeModulesSymlink), pnpmStoreTarget);
|
|
283
|
+
await fs.promises.symlink(relativeToStore, nodeModulesSymlink, "dir");
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
afterEach(async () => {
|
|
287
|
+
await fs.promises.rm(tmpDir, { recursive: true, force: true });
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("copies source files to target when modified after watch starts", async () => {
|
|
291
|
+
const appRoot = path.join(tmpDir, "app");
|
|
292
|
+
const sourceDir = path.join(tmpDir, "simplysm", "packages", "solid");
|
|
293
|
+
const targetPath = path.join(appRoot, "node_modules", "@simplysm", "solid");
|
|
294
|
+
|
|
295
|
+
const { dispose } = await watchReplaceDeps(appRoot, {
|
|
296
|
+
"@simplysm/*": "../simplysm/packages/*",
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Modify source file
|
|
300
|
+
await fs.promises.writeFile(path.join(sourceDir, "index.js"), "export default 2;");
|
|
301
|
+
await new Promise((resolve) => setTimeout(resolve, 500)); // 300ms delay + buffer
|
|
302
|
+
|
|
303
|
+
const indexContent = await fs.promises.readFile(path.join(targetPath, "index.js"), "utf-8");
|
|
304
|
+
expect(indexContent).toBe("export default 2;");
|
|
305
|
+
|
|
306
|
+
dispose();
|
|
307
|
+
});
|
|
308
|
+
});
|