@stacksjs/buddy 0.70.59 → 0.70.60

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 (79) hide show
  1. package/dist/cli.js +162 -4
  2. package/dist/commands/about.js +35 -0
  3. package/dist/commands/add.d.ts +2 -0
  4. package/dist/commands/add.js +33 -0
  5. package/dist/commands/auth.js +68 -0
  6. package/dist/commands/build.js +153 -0
  7. package/dist/commands/cd.js +39 -0
  8. package/dist/commands/changelog.js +32 -0
  9. package/dist/commands/clean.js +37 -0
  10. package/dist/commands/cloud.js +503 -0
  11. package/dist/commands/commit.js +16 -0
  12. package/dist/commands/completion.js +143 -0
  13. package/dist/commands/config-migrate.js +94 -0
  14. package/dist/commands/configure.js +48 -0
  15. package/dist/commands/create.js +137 -0
  16. package/dist/commands/deploy.js +1404 -0
  17. package/dist/commands/dev.js +911 -0
  18. package/dist/commands/dns.js +62 -0
  19. package/dist/commands/doctor.js +280 -0
  20. package/dist/commands/domains.js +159 -0
  21. package/dist/commands/email.js +526 -0
  22. package/dist/commands/env.js +246 -0
  23. package/dist/commands/features.js +422 -0
  24. package/dist/commands/fresh.js +39 -0
  25. package/dist/commands/generate.js +104 -0
  26. package/dist/commands/http.js +30 -0
  27. package/dist/commands/index.js +53 -0
  28. package/dist/commands/install.js +23 -0
  29. package/dist/commands/key.js +23 -0
  30. package/dist/commands/lint.js +50 -0
  31. package/dist/commands/list.js +108 -0
  32. package/dist/commands/mail.js +693 -0
  33. package/dist/commands/maintenance.d.ts +2 -0
  34. package/dist/commands/maintenance.js +141 -0
  35. package/dist/commands/make.js +375 -0
  36. package/dist/commands/migrate-project.js +49 -0
  37. package/dist/commands/migrate.js +373 -0
  38. package/dist/commands/outdated.js +19 -0
  39. package/dist/commands/package.d.ts +2 -0
  40. package/dist/commands/package.js +17 -0
  41. package/dist/commands/phone.js +188 -0
  42. package/dist/commands/ports.js +118 -0
  43. package/dist/commands/prepublish.js +17 -0
  44. package/dist/commands/projects.js +29 -0
  45. package/dist/commands/publish.js +169 -0
  46. package/dist/commands/queue.js +249 -0
  47. package/dist/commands/release.js +30 -0
  48. package/dist/commands/route.js +21 -0
  49. package/dist/commands/saas.js +25 -0
  50. package/dist/commands/schedule.js +61 -0
  51. package/dist/commands/search.js +84 -0
  52. package/dist/commands/seed.js +71 -0
  53. package/dist/commands/serve.js +176 -0
  54. package/dist/commands/setup.js +203 -0
  55. package/dist/commands/share.d.ts +2 -0
  56. package/dist/commands/share.js +209 -0
  57. package/dist/commands/sms.js +328 -0
  58. package/dist/commands/stacks.d.ts +2 -0
  59. package/dist/commands/stacks.js +69 -0
  60. package/dist/commands/telemetry.js +74 -0
  61. package/dist/commands/test.js +130 -0
  62. package/dist/commands/tinker.js +37 -0
  63. package/dist/commands/types.js +18 -0
  64. package/dist/commands/upgrade.js +97 -0
  65. package/dist/commands/version.js +16 -0
  66. package/dist/config.d.ts +43 -0
  67. package/dist/config.js +223 -0
  68. package/dist/custom-cli.d.ts +1 -0
  69. package/dist/custom-cli.js +23 -0
  70. package/dist/index.js +1 -3424
  71. package/dist/lazy-commands.d.ts +61 -0
  72. package/dist/lazy-commands.js +182 -0
  73. package/dist/migrators/index.js +62 -0
  74. package/dist/migrators/laravel/index.js +148 -0
  75. package/dist/migrators/laravel/migrations.js +231 -0
  76. package/dist/migrators/laravel/models.js +132 -0
  77. package/dist/migrators/rails/index.js +11 -0
  78. package/dist/migrators/types.js +0 -0
  79. package/package.json +1 -1
@@ -0,0 +1,132 @@
1
+ const RELATION_KINDS = ["belongsTo", "hasMany", "hasOne", "belongsToMany"];
2
+ export function parseLaravelModel(source) {
3
+ const classMatch = source.match(/\bclass\s+([A-Z][A-Za-z0-9_]*)\b/);
4
+ if (!classMatch)
5
+ return null;
6
+ const className = classMatch[1], table = extractStringProperty(source, "table") ?? snakeCasePlural(className), fillable = extractArrayProperty(source, "fillable"), hidden = extractArrayProperty(source, "hidden"), casts = extractKeyedArrayProperty(source, "casts"), relationships = extractRelationships(source), notes = [];
7
+ if (/protected\s+\$appends\s*=/.test(source))
8
+ notes.push("$appends accessors require a custom Stacks computed-attribute setup");
9
+ if (/protected\s+\$dates\s*=/.test(source))
10
+ notes.push("$dates is implicit in Stacks \u2014 datetime columns are already typed via validation rules");
11
+ if (/\buse\b[^;]*\bSoftDeletes\b/.test(source))
12
+ notes.push("SoftDeletes trait \u2192 enable `useDeletedAt` (or matching trait) in the Stacks model traits block");
13
+ if (/\buse\b[^;]*\bHasFactory\b/.test(source))
14
+ notes.push("HasFactory \u2192 Stacks generates factories automatically when `useSeeder` is enabled");
15
+ const tsSource = emitStacksModel({ className, table, fillable, hidden, casts, relationships });
16
+ return { className, table, fillable, hidden, casts, relationships, tsSource, notes };
17
+ }
18
+ function extractStringProperty(source, name) {
19
+ const re = new RegExp(`protected\\s+\\$${name}\\s*=\\s*['"]([^'"]+)['"]`), m = source.match(re);
20
+ return m ? m[1] : null;
21
+ }
22
+ function extractArrayProperty(source, name) {
23
+ const re = new RegExp(`protected\\s+\\$${name}\\s*=\\s*\\[([^\\]]*)\\]`, "s"), m = source.match(re);
24
+ if (!m)
25
+ return [];
26
+ return m[1].split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
27
+ }
28
+ function extractKeyedArrayProperty(source, name) {
29
+ const re = new RegExp(`protected\\s+\\$${name}\\s*=\\s*\\[([^\\]]*)\\]`, "s"), m = source.match(re);
30
+ if (!m)
31
+ return {};
32
+ const out = {}, pairs = m[1].split(",");
33
+ for (const pair of pairs) {
34
+ const kv = pair.match(/['"]([^'"]+)['"]\s*=>\s*['"]([^'"]+)['"]/);
35
+ if (kv)
36
+ out[kv[1]] = kv[2];
37
+ }
38
+ return out;
39
+ }
40
+ function extractRelationships(source) {
41
+ const found = [], methodRegex = /public\s+function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*(?::\s*[^\{]+)?\{[\s\S]*?return\s+\$this\s*->\s*(belongsTo|hasMany|hasOne|belongsToMany)\s*\(\s*([A-Z][A-Za-z0-9_]*)::class/g;
42
+ let m;
43
+ while ((m = methodRegex.exec(source)) !== null) {
44
+ const name = m[1], kind = m[2], target = m[3];
45
+ found.push({ name, kind, target });
46
+ }
47
+ return found;
48
+ }
49
+ function emitStacksModel(args) {
50
+ const attributeNames = unique([...args.fillable, ...Object.keys(args.casts)]), attrBlock = attributeNames.length === 0 ? " attributes: {}," : ` attributes: {
51
+ ${attributeNames.map((n) => emitAttribute(n, args)).join(`
52
+ `)}
53
+ },`, relationsBlock = args.relationships.length === 0 ? "" : `
54
+ // Relationships translated from Eloquent \u2014 refine targets / foreign keys to match your schema.
55
+ relations: {
56
+ ${args.relationships.map((r) => ` ${r.name}: { type: '${r.kind}', target: '${r.target}' },`).join(`
57
+ `)}
58
+ },
59
+ `;
60
+ return `import { defineModel } from '@stacksjs/orm'
61
+ import { schema } from '@stacksjs/validation'
62
+
63
+ export default defineModel({
64
+ name: '${args.className}',
65
+ table: '${args.table}',
66
+ primaryKey: 'id',
67
+ autoIncrement: true,
68
+
69
+ traits: {
70
+ useTimestamps: true,
71
+ },
72
+ ${relationsBlock}
73
+ ${attrBlock}
74
+ } as const)
75
+ `;
76
+ }
77
+ function emitAttribute(name, args) {
78
+ const rule = ruleForCast(args.casts[name]) ?? "schema.string()", fillable = args.fillable.includes(name), hidden = args.hidden.includes(name), notes = [];
79
+ if (hidden)
80
+ notes.push("hidden from API responses in source \u2014 handle via your Stacks resource/transformer");
81
+ const noteLine = notes.length > 0 ? ` // ${notes.join("; ")}
82
+ ` : "";
83
+ return ` ${name}: {
84
+ fillable: ${fillable},
85
+ ${noteLine} validation: {
86
+ rule: ${rule},
87
+ },
88
+ },`;
89
+ }
90
+ function ruleForCast(cast) {
91
+ if (!cast)
92
+ return null;
93
+ switch (cast.split(":")[0]) {
94
+ case "integer":
95
+ case "int":
96
+ return "schema.number().int()";
97
+ case "float":
98
+ case "double":
99
+ case "real":
100
+ return "schema.number()";
101
+ case "boolean":
102
+ case "bool":
103
+ return "schema.boolean()";
104
+ case "string":
105
+ return "schema.string()";
106
+ case "array":
107
+ case "collection":
108
+ case "json":
109
+ case "object":
110
+ return "schema.unknown()";
111
+ case "date":
112
+ case "datetime":
113
+ case "immutable_date":
114
+ case "immutable_datetime":
115
+ return "schema.string()";
116
+ case "decimal":
117
+ return "schema.number()";
118
+ default:
119
+ return null;
120
+ }
121
+ }
122
+ function snakeCasePlural(className) {
123
+ const snake = className.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
124
+ if (snake.endsWith("y") && !/[aeiou]y$/.test(snake))
125
+ return `${snake.slice(0, -1)}ies`;
126
+ if (snake.endsWith("s") || snake.endsWith("x") || snake.endsWith("z") || snake.endsWith("ch") || snake.endsWith("sh"))
127
+ return `${snake}es`;
128
+ return `${snake}s`;
129
+ }
130
+ function unique(arr) {
131
+ return [...new Set(arr)];
132
+ }
@@ -0,0 +1,11 @@
1
+ export const railsDriver = {
2
+ name: "rails",
3
+ async migrate(_req) {
4
+ return [{
5
+ source: ".",
6
+ target: "",
7
+ status: "skipped",
8
+ note: "Rails driver is not yet implemented (stacksjs/stacks#1241 \u2014 Laravel driver shipped first). Track follow-up at github.com/stacksjs/stacks/issues/1241."
9
+ }];
10
+ }
11
+ };
File without changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/buddy",
3
3
  "type": "module",
4
- "version": "0.70.59",
4
+ "version": "0.70.60",
5
5
  "description": "Meet Buddy. The Stacks runtime.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [