create-flow-os 0.0.47-dev.1772052163 → 0.0.47-dev.1772054229

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/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "create-flow-os",
3
- "version": "0.0.47-dev.1772052163",
3
+ "version": "0.0.47-dev.1772054229",
4
4
  "license": "PolyForm-Shield-1.0.0",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@flow-os/client": ">=0.0.1-dev.0",
8
- "node-diff3": "^3.2.0"
7
+ "@flow-os/client": ">=0.0.1-dev.0"
9
8
  },
10
9
  "bin": {
11
10
  "create-flow-os": "./src/index.ts"
package/src/init/merge.ts CHANGED
@@ -1,21 +1,19 @@
1
1
  /**
2
- * Merge generico per qualsiasi file.
3
- * JSON: merge additivo. Code/altri: merge 3-way (tipo Git) quando possibile.
2
+ * Merge: strategia "never overwrite" (create-react-app, ecc.).
3
+ * File vuoto → template. File con contenuto mantieni utente. Mai corrompere.
4
+ * JSON: merge additivo strutturato.
4
5
  */
5
6
 
6
7
  import * as readline from "readline";
7
- import { merge as diff3Merge } from "node-diff3";
8
8
 
9
9
  export type Conflict = { key: string; userVal: unknown; templateVal: unknown; path: string };
10
10
 
11
- /** Opzioni per merge 3-way: base (template precedente) e callback per salvare la nuova base */
11
+ /** Opzioni (compatibilità): non usate con never-overwrite */
12
12
  export type Merge3WayOptions = {
13
13
  baseContent?: string;
14
14
  saveBase?: (content: string) => void;
15
15
  };
16
16
 
17
- const LINE_SEP = /\n/;
18
-
19
17
  /** Deep merge di oggetti: aggiunge chiavi nuove, per esistenti chiede se diverso */
20
18
  function deepMergeAdditive(
21
19
  user: Record<string, unknown>,
@@ -73,21 +71,6 @@ export function mergeCodeTemplates(a: string, b: string): string {
73
71
  return b || a;
74
72
  }
75
73
 
76
- /** Merge 3-way per file di codice (tipo Git). Base = template precedente (da cache). */
77
- function merge3Way(
78
- userContent: string,
79
- templateContent: string,
80
- baseContent: string | undefined
81
- ): { merged: string; hasConflicts: boolean } {
82
- if (!userContent.trim()) return { merged: templateContent, hasConflicts: false };
83
- const base = baseContent ?? templateContent;
84
- const { conflict, result } = diff3Merge(userContent, base, templateContent, {
85
- stringSeparator: LINE_SEP,
86
- excludeFalseConflicts: true,
87
- });
88
- return { merged: result.join("\n"), hasConflicts: conflict };
89
- }
90
-
91
74
  /** Chiede all'utente se applicare i valori del template in conflitto */
92
75
  export async function resolveConflicts(conflicts: Conflict[], path: string): Promise<Record<string, unknown>> {
93
76
  if (conflicts.length === 0) return {};
@@ -104,16 +87,15 @@ export async function resolveConflicts(conflicts: Conflict[], path: string): Pro
104
87
  return overrides;
105
88
  }
106
89
 
107
- /** Merge generico: JSON additivo, code/altri merge 3-way (tipo Git) */
90
+ /** Never overwrite: file vuoto → template, file con contenuto mantieni. Mai corrompere. */
108
91
  export async function mergeFile(
109
92
  userContent: string | null,
110
93
  templateContent: string,
111
94
  relPath: string,
112
95
  promptConflict: (path: string, conflicts: Conflict[]) => Promise<Record<string, unknown>>,
113
- options?: Merge3WayOptions
96
+ _options?: Merge3WayOptions
114
97
  ): Promise<string> {
115
98
  const isJson = relPath.toLowerCase().endsWith(".json");
116
- const use3Way = /\.(ts|tsx|js|jsx|mjs|cjs|html|css|md|vue|svelte)$/.test(relPath);
117
99
 
118
100
  if (isJson) {
119
101
  const { merged, conflicts } = mergeJson(userContent ?? "{}", templateContent, relPath);
@@ -126,21 +108,13 @@ export async function mergeFile(
126
108
  return merged;
127
109
  }
128
110
 
129
- if (use3Way) {
130
- const { merged, hasConflicts } = merge3Way(
131
- userContent ?? "",
132
- templateContent,
133
- options?.baseContent
134
- );
135
- if (hasConflicts) {
136
- console.warn(`\n[flow-os] Conflitti in ${relPath} - risolvi i marker <<<<<<< / >>>>>>>`);
137
- }
138
- options?.saveBase?.(templateContent);
139
- return merged;
111
+ // Never overwrite: vuoto → template. Con contenuto → mantieni. Eccezione: file incompleto (manca export che template ha)
112
+ const content = (userContent ?? "").trim();
113
+ if (!content) return templateContent;
114
+ const tHasExport = /\bexport\s+default\b/.test(templateContent);
115
+ const uHasExport = /\bexport\s+default\b/.test(userContent ?? "");
116
+ if (tHasExport && !uHasExport) {
117
+ return templateContent; // File troncato
140
118
  }
141
-
142
- // Altri file: merge 3-way se possibile
143
- const { merged } = merge3Way(userContent ?? "", templateContent, options?.baseContent);
144
- options?.saveBase?.(templateContent);
145
- return merged;
119
+ return userContent!;
146
120
  }
@@ -2,7 +2,7 @@ import { existsSync, cpSync, readFileSync, writeFileSync, readdirSync, mkdirSync
2
2
  import { join, basename, dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  import { pkgRoot, flowDeps, toPkgName, toShortName } from "./lib";
5
- import { mergeFile, resolveConflicts, mergeJsonTemplates, mergeCodeTemplates, type Merge3WayOptions } from "./merge";
5
+ import { mergeFile, resolveConflicts, mergeJsonTemplates, mergeCodeTemplates } from "./merge";
6
6
 
7
7
  const SKIP = new Set(["node_modules", ".git", ".vite", "package.json"]);
8
8
  const NPM_REGISTRY = "https://registry.npmjs.org";
@@ -48,54 +48,22 @@ function mergeTemplateInto(combined: Map<string, string>, pkgFiles: Map<string,
48
48
  }
49
49
  }
50
50
 
51
- const INIT_BASE_FILE = ".flow-os/init-base.json";
52
-
53
- function loadInitBase(cwd: string): Record<string, string> {
54
- const p = join(cwd, INIT_BASE_FILE);
55
- if (!existsSync(p)) return {};
56
- try {
57
- return JSON.parse(readFileSync(p, "utf-8")) as Record<string, string>;
58
- } catch {
59
- return {};
60
- }
61
- }
62
-
63
- function saveInitBase(cwd: string, base: Record<string, string>): void {
64
- const dir = join(cwd, ".flow-os");
65
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
66
- writeFileSync(join(cwd, INIT_BASE_FILE), JSON.stringify(base, null, 2));
67
- }
68
-
69
- /** Scrive combined template in cwd facendo merge con file utente (merge 3-way tipo Git) */
51
+ /** Scrive combined template in cwd. Never overwrite: file con contenuto → mantieni. */
70
52
  async function writeMergedWithUser(
71
53
  combined: Map<string, string>,
72
54
  cwd: string,
73
55
  promptConflict: (path: string, conflicts: import("./merge").Conflict[]) => Promise<Record<string, unknown>>
74
56
  ): Promise<void> {
75
- const baseCache = loadInitBase(cwd);
76
- const newBase: Record<string, string> = {};
77
-
78
57
  for (const [relPath, templateContent] of combined) {
79
58
  const dest = join(cwd, relPath);
80
59
  const destDir = dirname(dest);
81
60
  if (!existsSync(destDir)) {
82
- const { mkdirSync } = await import("fs");
83
61
  mkdirSync(destDir, { recursive: true });
84
62
  }
85
63
  const userContent = existsSync(dest) ? readFileSync(dest, "utf-8") : null;
86
- const mergeOpts: Merge3WayOptions = {
87
- baseContent: baseCache[relPath],
88
- saveBase: (content) => {
89
- newBase[relPath] = content;
90
- },
91
- };
92
- const merged = await mergeFile(userContent, templateContent, relPath, promptConflict, mergeOpts);
64
+ const merged = await mergeFile(userContent, templateContent, relPath, promptConflict);
93
65
  writeFileSync(dest, merged);
94
66
  }
95
-
96
- if (Object.keys(newBase).length > 0) {
97
- saveInitBase(cwd, { ...baseCache, ...newBase });
98
- }
99
67
  }
100
68
 
101
69
  /** Indica se create-flow-os è in modalità dev (flow-os@dev) */