@simplysm/sd-cli 13.0.71 → 13.0.74

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 (108) hide show
  1. package/README.md +62 -14
  2. package/dist/commands/init.d.ts +4 -5
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +26 -8
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/commands/publish.js +1 -1
  7. package/dist/commands/publish.js.map +1 -1
  8. package/dist/sd-cli-entry.d.ts.map +1 -1
  9. package/dist/sd-cli-entry.js +0 -20
  10. package/dist/sd-cli-entry.js.map +1 -1
  11. package/package.json +4 -4
  12. package/src/commands/init.ts +40 -21
  13. package/src/commands/publish.ts +1 -1
  14. package/src/sd-cli-entry.ts +0 -24
  15. package/src/utils/replace-deps.ts +361 -361
  16. package/src/utils/sd-config.ts +44 -44
  17. package/src/utils/tailwind-config-deps.ts +98 -98
  18. package/src/utils/template.ts +56 -56
  19. package/src/utils/tsconfig.ts +127 -127
  20. package/src/utils/typecheck-serialization.ts +86 -86
  21. package/templates/init/{.prettierrc.yaml.hbs → .prettierrc.yaml} +1 -1
  22. package/templates/init/eslint.config.ts +15 -0
  23. package/templates/init/mise.toml +3 -0
  24. package/templates/init/package.json.hbs +8 -7
  25. package/templates/init/packages/client-admin/index.html.hbs +144 -0
  26. package/templates/init/packages/client-admin/package.json.hbs +26 -0
  27. package/templates/init/packages/client-admin/public/assets/logo-landscape.png +0 -0
  28. package/templates/init/packages/client-admin/public/assets/logo.png +0 -0
  29. package/templates/init/packages/client-admin/src/App.tsx +42 -0
  30. package/templates/init/packages/client-admin/src/dev/DevDialog.tsx +34 -0
  31. package/templates/{add-client/__CLIENT__/src/main.css.hbs → init/packages/client-admin/src/main.css} +1 -1
  32. package/templates/init/packages/client-admin/src/main.tsx.hbs +146 -0
  33. package/templates/init/packages/client-admin/src/providers/AppServiceProvider.tsx.hbs +103 -0
  34. package/templates/init/packages/client-admin/src/providers/AppStructureProvider.tsx +84 -0
  35. package/templates/init/packages/client-admin/src/providers/AuthProvider.tsx.hbs +71 -0
  36. package/templates/init/packages/client-admin/src/providers/configureSharedData.ts.hbs +67 -0
  37. package/templates/init/packages/client-admin/src/views/auth/LoginView.tsx +132 -0
  38. package/templates/init/packages/client-admin/src/views/home/HomeView.tsx +108 -0
  39. package/templates/init/packages/client-admin/src/views/home/base/employee/EmployeeDetail.tsx.hbs +262 -0
  40. package/templates/init/packages/client-admin/src/views/home/base/employee/EmployeeSheet.tsx.hbs +271 -0
  41. package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleDetail.tsx.hbs +154 -0
  42. package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionDetail.tsx.hbs +123 -0
  43. package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionView.tsx +52 -0
  44. package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleSheet.tsx.hbs +125 -0
  45. package/templates/init/packages/client-admin/src/views/home/main/MainView.tsx.hbs +13 -0
  46. package/templates/init/packages/client-admin/src/views/home/my-info/MyInfoDetail.tsx.hbs +248 -0
  47. package/templates/init/packages/client-admin/src/views/home/system/system-log/SystemLogSheet.tsx.hbs +169 -0
  48. package/templates/init/packages/client-admin/src/views/not-found/NotFoundView.tsx +15 -0
  49. package/templates/init/packages/client-admin/tailwind.config.ts +10 -0
  50. package/templates/init/packages/db-main/package.json.hbs +13 -0
  51. package/templates/init/packages/db-main/src/MainDbContext.ts +20 -0
  52. package/templates/init/packages/db-main/src/dataLogExt.ts +127 -0
  53. package/templates/init/packages/db-main/src/index.ts +10 -0
  54. package/templates/init/packages/db-main/src/tables/Employee.ts +24 -0
  55. package/templates/init/packages/db-main/src/tables/EmployeeConfig.ts +13 -0
  56. package/templates/init/packages/db-main/src/tables/Role.ts +9 -0
  57. package/templates/init/packages/db-main/src/tables/RolePermission.ts +13 -0
  58. package/templates/init/packages/db-main/src/tables/_DataLog.ts +19 -0
  59. package/templates/init/packages/db-main/src/tables/_Log.ts +16 -0
  60. package/templates/init/packages/server/package.json.hbs +20 -0
  61. package/templates/init/packages/server/public-dev/dev//354/264/210/352/270/260/355/231/224.xlsx +0 -0
  62. package/templates/init/packages/server/src/index.ts +4 -0
  63. package/templates/init/packages/server/src/main.ts.hbs +34 -0
  64. package/templates/init/packages/server/src/services/AuthService.ts.hbs +171 -0
  65. package/templates/init/packages/server/src/services/DevService.ts.hbs +94 -0
  66. package/templates/init/packages/server/src/services/EmployeeService.ts.hbs +122 -0
  67. package/templates/init/packages/server/src/services/RoleService.ts.hbs +59 -0
  68. package/templates/init/{pnpm-workspace.yaml.hbs → pnpm-workspace.yaml} +3 -1
  69. package/templates/init/sd.config.ts.hbs +30 -1
  70. package/templates/init/tests/e2e/package.json.hbs +16 -0
  71. package/templates/init/tests/e2e/src/e2e.spec.ts +36 -0
  72. package/templates/init/tests/e2e/src/employee-crud.ts +204 -0
  73. package/templates/init/tests/e2e/src/login.ts +61 -0
  74. package/templates/init/tests/e2e/vitest.setup.ts.hbs +220 -0
  75. package/templates/init/tsconfig.json.hbs +0 -11
  76. package/templates/init/{vitest.config.ts.hbs → vitest.config.ts} +16 -12
  77. package/dist/commands/add-client.d.ts +0 -18
  78. package/dist/commands/add-client.d.ts.map +0 -1
  79. package/dist/commands/add-client.js +0 -79
  80. package/dist/commands/add-client.js.map +0 -6
  81. package/dist/commands/add-server.d.ts +0 -18
  82. package/dist/commands/add-server.d.ts.map +0 -1
  83. package/dist/commands/add-server.js +0 -83
  84. package/dist/commands/add-server.js.map +0 -6
  85. package/dist/utils/config-editor.d.ts +0 -17
  86. package/dist/utils/config-editor.d.ts.map +0 -1
  87. package/dist/utils/config-editor.js +0 -79
  88. package/dist/utils/config-editor.js.map +0 -6
  89. package/src/commands/add-client.ts +0 -126
  90. package/src/commands/add-server.ts +0 -138
  91. package/src/utils/config-editor.ts +0 -141
  92. package/templates/add-client/__CLIENT__/index.html.hbs +0 -13
  93. package/templates/add-client/__CLIENT__/package.json.hbs +0 -16
  94. package/templates/add-client/__CLIENT__/src/App.tsx.hbs +0 -65
  95. package/templates/add-client/__CLIENT__/src/appStructure.ts.hbs +0 -20
  96. package/templates/add-client/__CLIENT__/src/main.tsx.hbs +0 -24
  97. package/templates/add-client/__CLIENT__/src/pages/HomePage.tsx.hbs +0 -9
  98. package/templates/add-client/__CLIENT__/tailwind.config.ts.hbs +0 -15
  99. package/templates/add-server/__SERVER__/package.json.hbs +0 -10
  100. package/templates/add-server/__SERVER__/src/main.ts.hbs +0 -14
  101. package/templates/init/.gitignore.hbs +0 -26
  102. package/templates/init/.npmrc.hbs +0 -1
  103. package/templates/init/eslint.config.ts.hbs +0 -5
  104. package/templates/init/mise.toml.hbs +0 -3
  105. package/tests/config-editor.spec.ts +0 -160
  106. /package/templates/init/{.prettierignore.hbs → .prettierignore} +0 -0
  107. /package/templates/{add-client/__CLIENT__ → init/packages/client-admin}/public/favicon.ico +0 -0
  108. /package/templates/init/{stylelint.config.ts.hbs → stylelint.config.ts} +0 -0
@@ -1,18 +0,0 @@
1
- /**
2
- * Add-server command options
3
- */
4
- export interface AddServerOptions {
5
- }
6
- /**
7
- * Adds a server package to the project.
8
- *
9
- * 1. Verify project root
10
- * 2. Interactive prompts (name suffix, client selection)
11
- * 3. Check for duplicate package directory
12
- * 4. Render Handlebars template
13
- * 5. Add server package entry to sd.config.ts
14
- * 6. Update server field in selected clients
15
- * 7. Run pnpm install
16
- */
17
- export declare function runAddServer(_options: AddServerOptions): Promise<void>;
18
- //# sourceMappingURL=add-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"add-server.d.ts","sourceRoot":"","sources":["..\\..\\src\\commands\\add-server.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,MAAM,WAAW,gBAAgB;CAAG;AA0BpC;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoF5E"}
@@ -1,83 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { input, checkbox } from "@inquirer/prompts";
4
- import { consola } from "consola";
5
- import { renderTemplateDir } from "../utils/template.js";
6
- import { addPackageToSdConfig, setClientServerInSdConfig } from "../utils/config-editor.js";
7
- import { execa } from "execa";
8
- import { findPackageRoot } from "../utils/package-utils.js";
9
- function findClientPackages(sdConfigPath) {
10
- const content = fs.readFileSync(sdConfigPath, "utf-8");
11
- const clients = [];
12
- const regex = /"([^"]+)":\s*\{[^}]*target:\s*"client"/g;
13
- let match;
14
- while ((match = regex.exec(content)) != null) {
15
- clients.push(match[1]);
16
- }
17
- return clients;
18
- }
19
- async function runAddServer(_options) {
20
- const cwd = process.cwd();
21
- const logger = consola.withTag("sd:cli:add-server");
22
- const sdConfigPath = path.join(cwd, "sd.config.ts");
23
- if (!fs.existsSync(sdConfigPath)) {
24
- consola.error("Cannot find sd.config.ts. Please run this from the project root.");
25
- process.exitCode = 1;
26
- return;
27
- }
28
- const projectName = path.basename(cwd);
29
- const serverSuffix = await input({
30
- message: 'Server name suffix (leave empty for "server"):',
31
- validate: (value) => {
32
- if (value.trim() === "") return true;
33
- if (!/^[a-z][a-z0-9-]*$/.test(value)) return "Only lowercase letters, numbers, and hyphens are allowed.";
34
- return true;
35
- }
36
- });
37
- const serverName = serverSuffix.trim() === "" ? "server" : `server-${serverSuffix}`;
38
- const clientPackages = findClientPackages(sdConfigPath);
39
- let selectedClients = [];
40
- if (clientPackages.length > 0) {
41
- selectedClients = await checkbox({
42
- message: "Select the clients this server will serve:",
43
- choices: clientPackages.map((name) => ({ name, value: name }))
44
- });
45
- }
46
- const packageDir = path.join(cwd, "packages", serverName);
47
- if (fs.existsSync(packageDir)) {
48
- consola.error(`packages/${serverName} directory already exists.`);
49
- process.exitCode = 1;
50
- return;
51
- }
52
- const pkgRoot = findPackageRoot(import.meta.dirname);
53
- const templateDir = path.join(pkgRoot, "templates", "add-server");
54
- const context = {
55
- projectName,
56
- serverName,
57
- port: 3e3
58
- };
59
- const dirReplacements = {
60
- __SERVER__: serverName
61
- };
62
- logger.info(`Creating ${serverName} package...`);
63
- await renderTemplateDir(templateDir, path.join(cwd, "packages"), context, dirReplacements);
64
- logger.success(`packages/${serverName} created successfully`);
65
- const added = addPackageToSdConfig(sdConfigPath, serverName, { target: "server" });
66
- if (added) {
67
- logger.success("Server package added to sd.config.ts");
68
- } else {
69
- consola.warn(`"${serverName}" already exists in sd.config.ts.`);
70
- }
71
- for (const clientName of selectedClients) {
72
- setClientServerInSdConfig(sdConfigPath, clientName, serverName);
73
- logger.info(`Set ${clientName} server to "${serverName}"`);
74
- }
75
- logger.info("Running pnpm install...");
76
- await execa("pnpm", ["install"], { cwd });
77
- logger.success("pnpm install completed");
78
- consola.box(`Server "${serverName}" has been added!`);
79
- }
80
- export {
81
- runAddServer
82
- };
83
- //# sourceMappingURL=add-server.js.map
@@ -1,6 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/commands/add-server.ts"],
4
- "mappings": "AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,OAAO,gBAAgB;AAChC,SAAS,eAAe;AACxB,SAAS,yBAAyB;AAClC,SAAS,sBAAsB,iCAAiC;AAChE,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAgBhC,SAAS,mBAAmB,cAAgC;AAC1D,QAAM,UAAU,GAAG,aAAa,cAAc,OAAO;AACrD,QAAM,UAAoB,CAAC;AAG3B,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,QAAQ,MAAM,KAAK,OAAO,MAAM,MAAM;AAC5C,YAAQ,KAAK,MAAM,CAAC,CAAC;AAAA,EACvB;AACA,SAAO;AACT;AAiBA,eAAsB,aAAa,UAA2C;AAC5E,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,SAAS,QAAQ,QAAQ,mBAAmB;AAGlD,QAAM,eAAe,KAAK,KAAK,KAAK,cAAc;AAClD,MAAI,CAAC,GAAG,WAAW,YAAY,GAAG;AAChC,YAAQ,MAAM,kEAAkE;AAChF,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,cAAc,KAAK,SAAS,GAAG;AAGrC,QAAM,eAAe,MAAM,MAAM;AAAA,IAC/B,SAAS;AAAA,IACT,UAAU,CAAC,UAAU;AACnB,UAAI,MAAM,KAAK,MAAM,GAAI,QAAO;AAChC,UAAI,CAAC,oBAAoB,KAAK,KAAK,EAAG,QAAO;AAC7C,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,QAAM,aAAa,aAAa,KAAK,MAAM,KAAK,WAAW,UAAU,YAAY;AAGjF,QAAM,iBAAiB,mBAAmB,YAAY;AACtD,MAAI,kBAA4B,CAAC;AAEjC,MAAI,eAAe,SAAS,GAAG;AAC7B,sBAAkB,MAAM,SAAS;AAAA,MAC/B,SAAS;AAAA,MACT,SAAS,eAAe,IAAI,CAAC,UAAU,EAAE,MAAM,OAAO,KAAK,EAAE;AAAA,IAC/D,CAAC;AAAA,EACH;AAGA,QAAM,aAAa,KAAK,KAAK,KAAK,YAAY,UAAU;AACxD,MAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,YAAQ,MAAM,YAAY,UAAU,4BAA4B;AAChE,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,QAAM,UAAU,gBAAgB,YAAY,OAAO;AACnD,QAAM,cAAc,KAAK,KAAK,SAAS,aAAa,YAAY;AAEhE,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AAEA,QAAM,kBAAkB;AAAA,IACtB,YAAY;AAAA,EACd;AAEA,SAAO,KAAK,YAAY,UAAU,aAAa;AAC/C,QAAM,kBAAkB,aAAa,KAAK,KAAK,KAAK,UAAU,GAAG,SAAS,eAAe;AACzF,SAAO,QAAQ,YAAY,UAAU,uBAAuB;AAG5D,QAAM,QAAQ,qBAAqB,cAAc,YAAY,EAAE,QAAQ,SAAS,CAAC;AACjF,MAAI,OAAO;AACT,WAAO,QAAQ,sCAAsC;AAAA,EACvD,OAAO;AACL,YAAQ,KAAK,IAAI,UAAU,mCAAmC;AAAA,EAChE;AAGA,aAAW,cAAc,iBAAiB;AACxC,8BAA0B,cAAc,YAAY,UAAU;AAC9D,WAAO,KAAK,OAAO,UAAU,eAAe,UAAU,GAAG;AAAA,EAC3D;AAGA,SAAO,KAAK,yBAAyB;AACrC,QAAM,MAAM,QAAQ,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC;AACxC,SAAO,QAAQ,wBAAwB;AAGvC,UAAQ,IAAI,WAAW,UAAU,mBAAmB;AACtD;",
5
- "names": []
6
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * Add new package entry to packages object in sd.config.ts
3
- *
4
- * @returns true: success, false: already exists
5
- */
6
- export declare function addPackageToSdConfig(configPath: string, packageName: string, config: Record<string, unknown>): boolean;
7
- /**
8
- * Set server field for specific client in sd.config.ts
9
- */
10
- export declare function setClientServerInSdConfig(configPath: string, clientName: string, serverName: string): void;
11
- /**
12
- * Add tailwindcss config block to eslint.config.ts
13
- *
14
- * @returns true: added, false: already exists
15
- */
16
- export declare function addTailwindToEslintConfig(configPath: string, clientName: string): boolean;
17
- //# sourceMappingURL=config-editor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-editor.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\config-editor.ts"],"names":[],"mappings":"AAyCA;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAsBT;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,IAAI,CAyBN;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CA2BzF"}
@@ -1,79 +0,0 @@
1
- import { Project, SyntaxKind } from "ts-morph";
2
- function findPackagesObject(configPath) {
3
- const project = new Project();
4
- const sourceFile = project.addSourceFileAtPath(configPath);
5
- const configVar = sourceFile.getVariableDeclarationOrThrow("config");
6
- const arrowFn = configVar.getInitializerIfKindOrThrow(SyntaxKind.ArrowFunction);
7
- const body = arrowFn.getBody();
8
- let returnObj;
9
- if (body.isKind(SyntaxKind.ParenthesizedExpression)) {
10
- returnObj = body.getExpressionIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
11
- } else if (body.isKind(SyntaxKind.Block)) {
12
- const returnStmt = body.getFirstDescendantByKindOrThrow(SyntaxKind.ReturnStatement);
13
- returnObj = returnStmt.getExpressionIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
14
- } else {
15
- throw new Error("Unable to recognize structure of sd.config.ts");
16
- }
17
- const packagesProp = returnObj.getPropertyOrThrow("packages").asKindOrThrow(SyntaxKind.PropertyAssignment);
18
- const packagesObj = packagesProp.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
19
- return { project, packagesObj };
20
- }
21
- function addPackageToSdConfig(configPath, packageName, config) {
22
- const { project, packagesObj } = findPackagesObject(configPath);
23
- const existing = packagesObj.getProperty(`"${packageName}"`) ?? packagesObj.getProperty(packageName);
24
- if (existing) {
25
- return false;
26
- }
27
- const configStr = JSON.stringify(config).replace(/"([^"]+)":/g, "$1: ").replace(/"/g, '"');
28
- packagesObj.addPropertyAssignment({
29
- name: `"${packageName}"`,
30
- initializer: configStr
31
- });
32
- project.saveSync();
33
- return true;
34
- }
35
- function setClientServerInSdConfig(configPath, clientName, serverName) {
36
- const { project, packagesObj } = findPackagesObject(configPath);
37
- const clientPropNode = packagesObj.getProperty(`"${clientName}"`) ?? packagesObj.getProperty(clientName);
38
- if (clientPropNode == null) {
39
- throw new Error(`Client "${clientName}" not found in sd.config.ts`);
40
- }
41
- const clientProp = clientPropNode.asKindOrThrow(SyntaxKind.PropertyAssignment);
42
- const clientObj = clientProp.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
43
- const serverProp = clientObj.getProperty("server");
44
- if (serverProp) {
45
- serverProp.remove();
46
- }
47
- clientObj.addPropertyAssignment({
48
- name: "server",
49
- initializer: `"${serverName}"`
50
- });
51
- project.saveSync();
52
- }
53
- function addTailwindToEslintConfig(configPath, clientName) {
54
- const project = new Project();
55
- const sourceFile = project.addSourceFileAtPath(configPath);
56
- const defaultExport = sourceFile.getFirstDescendantByKindOrThrow(
57
- SyntaxKind.ArrayLiteralExpression
58
- );
59
- const text = defaultExport.getText();
60
- if (text.includes("tailwindcss")) {
61
- return false;
62
- }
63
- defaultExport.addElement(`{
64
- files: ["**/*.{ts,tsx}"],
65
- settings: {
66
- tailwindcss: {
67
- config: "packages/${clientName}/tailwind.config.ts",
68
- },
69
- },
70
- }`);
71
- project.saveSync();
72
- return true;
73
- }
74
- export {
75
- addPackageToSdConfig,
76
- addTailwindToEslintConfig,
77
- setClientServerInSdConfig
78
- };
79
- //# sourceMappingURL=config-editor.js.map
@@ -1,6 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/utils/config-editor.ts"],
4
- "mappings": "AAAA,SAAS,SAAS,kBAAgD;AAQlE,SAAS,mBAAmB,YAG1B;AACA,QAAM,UAAU,IAAI,QAAQ;AAC5B,QAAM,aAAa,QAAQ,oBAAoB,UAAU;AAGzD,QAAM,YAAY,WAAW,8BAA8B,QAAQ;AACnE,QAAM,UAAU,UAAU,4BAA4B,WAAW,aAAa;AAG9E,QAAM,OAAO,QAAQ,QAAQ;AAC7B,MAAI;AAEJ,MAAI,KAAK,OAAO,WAAW,uBAAuB,GAAG;AACnD,gBAAY,KAAK,2BAA2B,WAAW,uBAAuB;AAAA,EAChF,WAAW,KAAK,OAAO,WAAW,KAAK,GAAG;AACxC,UAAM,aAAa,KAAK,gCAAgC,WAAW,eAAe;AAClF,gBAAY,WAAW,2BAA2B,WAAW,uBAAuB;AAAA,EACtF,OAAO;AACL,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAGA,QAAM,eAAe,UAClB,mBAAmB,UAAU,EAC7B,cAAc,WAAW,kBAAkB;AAC9C,QAAM,cAAc,aAAa,4BAA4B,WAAW,uBAAuB;AAE/F,SAAO,EAAE,SAAS,YAAY;AAChC;AAOO,SAAS,qBACd,YACA,aACA,QACS;AACT,QAAM,EAAE,SAAS,YAAY,IAAI,mBAAmB,UAAU;AAG9D,QAAM,WACJ,YAAY,YAAY,IAAI,WAAW,GAAG,KAAK,YAAY,YAAY,WAAW;AACpF,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,KAAK,UAAU,MAAM,EACpC,QAAQ,eAAe,MAAM,EAC7B,QAAQ,MAAM,GAAG;AAEpB,cAAY,sBAAsB;AAAA,IAChC,MAAM,IAAI,WAAW;AAAA,IACrB,aAAa;AAAA,EACf,CAAC;AAED,UAAQ,SAAS;AACjB,SAAO;AACT;AAKO,SAAS,0BACd,YACA,YACA,YACM;AACN,QAAM,EAAE,SAAS,YAAY,IAAI,mBAAmB,UAAU;AAE9D,QAAM,iBACJ,YAAY,YAAY,IAAI,UAAU,GAAG,KAAK,YAAY,YAAY,UAAU;AAClF,MAAI,kBAAkB,MAAM;AAC1B,UAAM,IAAI,MAAM,WAAW,UAAU,6BAA6B;AAAA,EACpE;AAEA,QAAM,aAAa,eAAe,cAAc,WAAW,kBAAkB;AAC7E,QAAM,YAAY,WAAW,4BAA4B,WAAW,uBAAuB;AAG3F,QAAM,aAAa,UAAU,YAAY,QAAQ;AACjD,MAAI,YAAY;AACd,eAAW,OAAO;AAAA,EACpB;AAGA,YAAU,sBAAsB;AAAA,IAC9B,MAAM;AAAA,IACN,aAAa,IAAI,UAAU;AAAA,EAC7B,CAAC;AAED,UAAQ,SAAS;AACnB;AAOO,SAAS,0BAA0B,YAAoB,YAA6B;AACzF,QAAM,UAAU,IAAI,QAAQ;AAC5B,QAAM,aAAa,QAAQ,oBAAoB,UAAU;AAGzD,QAAM,gBAAgB,WAAW;AAAA,IAC/B,WAAW;AAAA,EACb;AAGA,QAAM,OAAO,cAAc,QAAQ;AACnC,MAAI,KAAK,SAAS,aAAa,GAAG;AAChC,WAAO;AAAA,EACT;AAGA,gBAAc,WAAW;AAAA;AAAA;AAAA;AAAA,4BAIC,UAAU;AAAA;AAAA;AAAA,IAGlC;AAEF,UAAQ,SAAS;AACjB,SAAO;AACT;",
5
- "names": []
6
- }
@@ -1,126 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { input, confirm } from "@inquirer/prompts";
4
- import { consola } from "consola";
5
- import { renderTemplateDir } from "../utils/template";
6
- import { addPackageToSdConfig, addTailwindToEslintConfig } from "../utils/config-editor";
7
- import { execa } from "execa";
8
- import { findPackageRoot } from "../utils/package-utils";
9
-
10
- //#region Types
11
-
12
- /**
13
- * Add-client command options
14
- */
15
- export interface AddClientOptions {}
16
-
17
- //#endregion
18
-
19
- //#region Utilities
20
- //#endregion
21
-
22
- //#region Main
23
-
24
- /**
25
- * Add client package to the project.
26
- *
27
- * 1. Verify project root (sd.config.ts exists)
28
- * 2. Interactive prompt (name suffix, router usage)
29
- * 3. Check for duplicate package directory
30
- * 4. Render Handlebars template
31
- * 5. Add package entry to sd.config.ts (ts-morph)
32
- * 6. Add tailwind configuration to eslint.config.ts (if first client)
33
- * 7. pnpm install
34
- */
35
- export async function runAddClient(_options: AddClientOptions): Promise<void> {
36
- const cwd = process.cwd();
37
- const logger = consola.withTag("sd:cli:add-client");
38
-
39
- // 1. Verify project root
40
- if (!fs.existsSync(path.join(cwd, "sd.config.ts"))) {
41
- consola.error("Cannot find sd.config.ts. Please run from the project root.");
42
- process.exitCode = 1;
43
- return;
44
- }
45
-
46
- // Project name
47
- const projectName = path.basename(cwd);
48
-
49
- // 2. Interactive prompt
50
- const clientSuffix = await input({
51
- message: "Enter client name suffix (client-___):",
52
- validate: (value) => {
53
- if (!value.trim()) return "Please enter a name.";
54
- if (!/^[a-z][a-z0-9-]*$/.test(value)) return "Only lowercase letters, numbers, and hyphens are allowed.";
55
- return true;
56
- },
57
- });
58
-
59
- const useRouter = await confirm({
60
- message: "Do you want to use router?",
61
- default: true,
62
- });
63
-
64
- const clientName = `client-${clientSuffix}`;
65
-
66
- // 3. Check for duplicate package directory
67
- const packageDir = path.join(cwd, "packages", clientName);
68
- if (fs.existsSync(packageDir)) {
69
- consola.error(`packages/${clientName} directory already exists.`);
70
- process.exitCode = 1;
71
- return;
72
- }
73
-
74
- // 4. Render template
75
- const pkgRoot = findPackageRoot(import.meta.dirname);
76
- const templateDir = path.join(pkgRoot, "templates", "add-client");
77
-
78
- const context = {
79
- projectName,
80
- clientSuffix,
81
- clientName,
82
- router: useRouter,
83
- };
84
-
85
- const dirReplacements = {
86
- __CLIENT__: clientName,
87
- };
88
-
89
- logger.info(`Creating ${clientName} package...`);
90
- await renderTemplateDir(templateDir, path.join(cwd, "packages"), context, dirReplacements);
91
- logger.success(`packages/${clientName} created successfully`);
92
-
93
- // 5. Update sd.config.ts
94
- const sdConfigPath = path.join(cwd, "sd.config.ts");
95
- const added = addPackageToSdConfig(sdConfigPath, clientName, { target: "client" });
96
- if (added) {
97
- logger.success("sd.config.ts updated successfully");
98
- } else {
99
- consola.warn(`"${clientName}" already exists in sd.config.ts.`);
100
- }
101
-
102
- // 6. Add tailwind configuration to eslint.config.ts (if first client)
103
- const eslintConfigPath = path.join(cwd, "eslint.config.ts");
104
- if (fs.existsSync(eslintConfigPath)) {
105
- const tailwindAdded = addTailwindToEslintConfig(eslintConfigPath, clientName);
106
- if (tailwindAdded) {
107
- logger.success("Added tailwind configuration to eslint.config.ts");
108
- }
109
- }
110
-
111
- // 7. pnpm install
112
- logger.info("Running pnpm install...");
113
- await execa("pnpm", ["install"], { cwd });
114
- logger.success("pnpm install completed");
115
-
116
- // Done
117
- consola.box(
118
- [
119
- `Client "${clientName}" has been added!`,
120
- "",
121
- ` pnpm dev ${clientName} Run development server`,
122
- ].join("\n"),
123
- );
124
- }
125
-
126
- //#endregion
@@ -1,138 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { input, checkbox } from "@inquirer/prompts";
4
- import { consola } from "consola";
5
- import { renderTemplateDir } from "../utils/template";
6
- import { addPackageToSdConfig, setClientServerInSdConfig } from "../utils/config-editor";
7
- import { execa } from "execa";
8
- import { findPackageRoot } from "../utils/package-utils";
9
-
10
- //#region Types
11
-
12
- /**
13
- * Add-server command options
14
- */
15
- export interface AddServerOptions {}
16
-
17
- //#endregion
18
-
19
- //#region Utilities
20
-
21
- /**
22
- * Reads sd.config.ts and returns a list of package names with target "client".
23
- */
24
- function findClientPackages(sdConfigPath: string): string[] {
25
- const content = fs.readFileSync(sdConfigPath, "utf-8");
26
- const clients: string[] = [];
27
-
28
- // Find client packages using simple pattern matching
29
- const regex = /"([^"]+)":\s*\{[^}]*target:\s*"client"/g;
30
- let match: RegExpExecArray | null;
31
- while ((match = regex.exec(content)) != null) {
32
- clients.push(match[1]);
33
- }
34
- return clients;
35
- }
36
-
37
- //#endregion
38
-
39
- //#region Main
40
-
41
- /**
42
- * Adds a server package to the project.
43
- *
44
- * 1. Verify project root
45
- * 2. Interactive prompts (name suffix, client selection)
46
- * 3. Check for duplicate package directory
47
- * 4. Render Handlebars template
48
- * 5. Add server package entry to sd.config.ts
49
- * 6. Update server field in selected clients
50
- * 7. Run pnpm install
51
- */
52
- export async function runAddServer(_options: AddServerOptions): Promise<void> {
53
- const cwd = process.cwd();
54
- const logger = consola.withTag("sd:cli:add-server");
55
-
56
- // 1. Verify project root
57
- const sdConfigPath = path.join(cwd, "sd.config.ts");
58
- if (!fs.existsSync(sdConfigPath)) {
59
- consola.error("Cannot find sd.config.ts. Please run this from the project root.");
60
- process.exitCode = 1;
61
- return;
62
- }
63
-
64
- const projectName = path.basename(cwd);
65
-
66
- // 2. Interactive prompts
67
- const serverSuffix = await input({
68
- message: 'Server name suffix (leave empty for "server"):',
69
- validate: (value) => {
70
- if (value.trim() === "") return true; // Allow empty value
71
- if (!/^[a-z][a-z0-9-]*$/.test(value)) return "Only lowercase letters, numbers, and hyphens are allowed.";
72
- return true;
73
- },
74
- });
75
-
76
- const serverName = serverSuffix.trim() === "" ? "server" : `server-${serverSuffix}`;
77
-
78
- // Client selection (if existing clients are present)
79
- const clientPackages = findClientPackages(sdConfigPath);
80
- let selectedClients: string[] = [];
81
-
82
- if (clientPackages.length > 0) {
83
- selectedClients = await checkbox({
84
- message: "Select the clients this server will serve:",
85
- choices: clientPackages.map((name) => ({ name, value: name })),
86
- });
87
- }
88
-
89
- // 3. Check for duplicate package directory
90
- const packageDir = path.join(cwd, "packages", serverName);
91
- if (fs.existsSync(packageDir)) {
92
- consola.error(`packages/${serverName} directory already exists.`);
93
- process.exitCode = 1;
94
- return;
95
- }
96
-
97
- // 4. Render template
98
- const pkgRoot = findPackageRoot(import.meta.dirname);
99
- const templateDir = path.join(pkgRoot, "templates", "add-server");
100
-
101
- const context = {
102
- projectName,
103
- serverName,
104
- port: 3000,
105
- };
106
-
107
- const dirReplacements = {
108
- __SERVER__: serverName,
109
- };
110
-
111
- logger.info(`Creating ${serverName} package...`);
112
- await renderTemplateDir(templateDir, path.join(cwd, "packages"), context, dirReplacements);
113
- logger.success(`packages/${serverName} created successfully`);
114
-
115
- // 5. Add server package to sd.config.ts
116
- const added = addPackageToSdConfig(sdConfigPath, serverName, { target: "server" });
117
- if (added) {
118
- logger.success("Server package added to sd.config.ts");
119
- } else {
120
- consola.warn(`"${serverName}" already exists in sd.config.ts.`);
121
- }
122
-
123
- // 6. Update server field in selected clients
124
- for (const clientName of selectedClients) {
125
- setClientServerInSdConfig(sdConfigPath, clientName, serverName);
126
- logger.info(`Set ${clientName} server to "${serverName}"`);
127
- }
128
-
129
- // 7. Run pnpm install
130
- logger.info("Running pnpm install...");
131
- await execa("pnpm", ["install"], { cwd });
132
- logger.success("pnpm install completed");
133
-
134
- // Done
135
- consola.box(`Server "${serverName}" has been added!`);
136
- }
137
-
138
- //#endregion
@@ -1,141 +0,0 @@
1
- import { Project, SyntaxKind, type ObjectLiteralExpression } from "ts-morph";
2
-
3
- /**
4
- * Find packages object literal in sd.config.ts
5
- *
6
- * Structure: const config: SdConfigFn = () => ({ packages: { ... } });
7
- * -> ArrowFunction -> ParenthesizedExpression -> ObjectLiteral -> "packages" property -> ObjectLiteral
8
- */
9
- function findPackagesObject(configPath: string): {
10
- project: Project;
11
- packagesObj: ObjectLiteralExpression;
12
- } {
13
- const project = new Project();
14
- const sourceFile = project.addSourceFileAtPath(configPath);
15
-
16
- // Find "config" variable declaration
17
- const configVar = sourceFile.getVariableDeclarationOrThrow("config");
18
- const arrowFn = configVar.getInitializerIfKindOrThrow(SyntaxKind.ArrowFunction);
19
-
20
- // Find return object in arrow function body
21
- const body = arrowFn.getBody();
22
- let returnObj: ObjectLiteralExpression;
23
-
24
- if (body.isKind(SyntaxKind.ParenthesizedExpression)) {
25
- returnObj = body.getExpressionIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
26
- } else if (body.isKind(SyntaxKind.Block)) {
27
- const returnStmt = body.getFirstDescendantByKindOrThrow(SyntaxKind.ReturnStatement);
28
- returnObj = returnStmt.getExpressionIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
29
- } else {
30
- throw new Error("Unable to recognize structure of sd.config.ts");
31
- }
32
-
33
- // Find "packages" property
34
- const packagesProp = returnObj
35
- .getPropertyOrThrow("packages")
36
- .asKindOrThrow(SyntaxKind.PropertyAssignment);
37
- const packagesObj = packagesProp.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
38
-
39
- return { project, packagesObj };
40
- }
41
-
42
- /**
43
- * Add new package entry to packages object in sd.config.ts
44
- *
45
- * @returns true: success, false: already exists
46
- */
47
- export function addPackageToSdConfig(
48
- configPath: string,
49
- packageName: string,
50
- config: Record<string, unknown>,
51
- ): boolean {
52
- const { project, packagesObj } = findPackagesObject(configPath);
53
-
54
- // Check if already exists (check both quoted and unquoted forms)
55
- const existing =
56
- packagesObj.getProperty(`"${packageName}"`) ?? packagesObj.getProperty(packageName);
57
- if (existing) {
58
- return false;
59
- }
60
-
61
- // Add new property -- convert config object to ts-morph initializer string
62
- const configStr = JSON.stringify(config)
63
- .replace(/"([^"]+)":/g, "$1: ")
64
- .replace(/"/g, '"');
65
-
66
- packagesObj.addPropertyAssignment({
67
- name: `"${packageName}"`,
68
- initializer: configStr,
69
- });
70
-
71
- project.saveSync();
72
- return true;
73
- }
74
-
75
- /**
76
- * Set server field for specific client in sd.config.ts
77
- */
78
- export function setClientServerInSdConfig(
79
- configPath: string,
80
- clientName: string,
81
- serverName: string,
82
- ): void {
83
- const { project, packagesObj } = findPackagesObject(configPath);
84
-
85
- const clientPropNode =
86
- packagesObj.getProperty(`"${clientName}"`) ?? packagesObj.getProperty(clientName);
87
- if (clientPropNode == null) {
88
- throw new Error(`Client "${clientName}" not found in sd.config.ts`);
89
- }
90
-
91
- const clientProp = clientPropNode.asKindOrThrow(SyntaxKind.PropertyAssignment);
92
- const clientObj = clientProp.getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
93
-
94
- // Remove existing server property if present
95
- const serverProp = clientObj.getProperty("server");
96
- if (serverProp) {
97
- serverProp.remove();
98
- }
99
-
100
- // Add server property
101
- clientObj.addPropertyAssignment({
102
- name: "server",
103
- initializer: `"${serverName}"`,
104
- });
105
-
106
- project.saveSync();
107
- }
108
-
109
- /**
110
- * Add tailwindcss config block to eslint.config.ts
111
- *
112
- * @returns true: added, false: already exists
113
- */
114
- export function addTailwindToEslintConfig(configPath: string, clientName: string): boolean {
115
- const project = new Project();
116
- const sourceFile = project.addSourceFileAtPath(configPath);
117
-
118
- // Find default export array
119
- const defaultExport = sourceFile.getFirstDescendantByKindOrThrow(
120
- SyntaxKind.ArrayLiteralExpression,
121
- );
122
-
123
- // Check if tailwindcss config already exists
124
- const text = defaultExport.getText();
125
- if (text.includes("tailwindcss")) {
126
- return false;
127
- }
128
-
129
- // Add new config object
130
- defaultExport.addElement(`{
131
- files: ["**/*.{ts,tsx}"],
132
- settings: {
133
- tailwindcss: {
134
- config: "packages/${clientName}/tailwind.config.ts",
135
- },
136
- },
137
- }`);
138
-
139
- project.saveSync();
140
- return true;
141
- }
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <link rel="icon" href="favicon.ico" />
7
- <title>{{projectName}}</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="src/main.tsx"></script>
12
- </body>
13
- </html>
@@ -1,16 +0,0 @@
1
- {
2
- "name": "@{{projectName}}/{{clientName}}",
3
- "version": "1.0.0",
4
- "type": "module",
5
- "private": true,
6
- "dependencies": {
7
- "@simplysm/solid": "~13.0.71",
8
- {{#if router}}
9
- "@solidjs/router": "^0.15.4",
10
- {{/if}}
11
- "solid-js": "^1.9.11"
12
- },
13
- "devDependencies": {
14
- "tailwindcss": "^3.4.19"
15
- }
16
- }