@mfeflow/core 0.5.0 → 0.6.0

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/dist/plan.d.ts CHANGED
@@ -95,6 +95,8 @@ export declare class PlanBuilder {
95
95
  private open;
96
96
  exists(file: string): Promise<boolean>;
97
97
  content(file: string): Promise<string | undefined>;
98
+ /** Whether `file` was on disk before this plan changed anything. */
99
+ existed(file: string): Promise<boolean>;
98
100
  /** Remembers `mfeflow.json` as it is now; `applyPlan` refuses to continue if it changes before the write. */
99
101
  captureProject(): Promise<void>;
100
102
  addFeature(feature: PlanFeature): void;
@@ -117,6 +119,7 @@ export declare class PlanBuilder {
117
119
  * range that is already there.
118
120
  */
119
121
  setRange(file: string, name: string, range: string): Promise<void>;
122
+ /** The first range for `name` that is not already `wanted`, else the first one; a name can be listed in several sections. */
120
123
  private declaredRange;
121
124
  private setCatalogEntry;
122
125
  /** Adds a script. An identical one already there is a no-op; a different command under the same name is a conflict. */
@@ -11,6 +11,8 @@ export interface SchemaKey {
11
11
  name: string;
12
12
  /** The key may be missing: an arktype `'key?'`, or a Zod or Valibot schema whose outermost call is optional, nullish, default, catch, fallback or exactOptional. */
13
13
  optional: boolean;
14
+ /** The validator as written in the file, for example `z.string().min(1)`. */
15
+ schema: string;
14
16
  }
15
17
  /**
16
18
  * The keys of the `server` schema (`env.ts`) or of the runtime-config schema object,
@@ -9,6 +9,7 @@ export interface Edit {
9
9
  /** Applies edits from the end backwards so earlier offsets stay valid. */
10
10
  export declare function applyEdits(source: string, edits: Edit[]): string;
11
11
  export declare function parseSource(source: string, file: string): File;
12
+ export declare const SKIP_KEYS: Set<string>;
12
13
  /** Every node under `root` (including it) for which `match` returns true, in source order. */
13
14
  export declare function findAll(root: Node, match: (node: Node) => boolean): Node[];
14
15
  export type FunctionNode = FunctionDeclaration | FunctionExpression | ArrowFunctionExpression;
@@ -0,0 +1,109 @@
1
+ import type { LoadedFeature } from './features/load.js';
2
+ import { PlanBuilder, type Plan, type ReadFile } from './plan.js';
3
+ import type { MfeflowProject } from './project.js';
4
+ /**
5
+ * What a first-party migration module exports (as `default` or `migrate`). It records its
6
+ * changes on the builder and returns nothing, so a dry run, `--json` and rollback work for it.
7
+ */
8
+ export type Migration = (builder: PlanBuilder, project: MfeflowProject) => void | Promise<void>;
9
+ export interface UpgradeInput {
10
+ /** The version the project is moving to; every `@mfeflow/*` range becomes `^<toVersion>`. */
11
+ toVersion: string;
12
+ /** Reads a project file by relative path; undefined when it does not exist. */
13
+ read: ReadFile;
14
+ /**
15
+ * The features to replay, in the order `init` applies them (`core` first). Each is replayed with
16
+ * the options `mfeflow.json` recorded for it.
17
+ */
18
+ features: readonly LoadedFeature[];
19
+ /** First-party parts replayed after the features, such as the per-remote registry and route files. */
20
+ glue?: readonly LoadedFeature[];
21
+ /** Recorded features the caller could not load. Their files are left alone and nothing is reported as removed. */
22
+ skipped?: readonly {
23
+ name: string;
24
+ reason: string;
25
+ }[];
26
+ /** Whether a project file is itself a symlink. Such a file is never replaced. */
27
+ isSymlink?: (file: string) => Promise<boolean>;
28
+ /** Loads a migration module. Defaults to a dynamic `import()`. */
29
+ importModule?: (file: string) => Promise<unknown>;
30
+ /**
31
+ * What the person decided about files that differ. An accepted file is written with the new
32
+ * version; a kept one is left, and the plan's project remembers it. `all` leaves out symlinks.
33
+ */
34
+ decisions?: UpgradeDecisions;
35
+ }
36
+ export interface UpgradeDecisions {
37
+ accept?: ReadonlySet<string> | 'all';
38
+ keep?: ReadonlySet<string> | 'all';
39
+ }
40
+ export type DivergeReason =
41
+ /** Tracked, and the file no longer matches the hash recorded when it was written. */
42
+ 'edited'
43
+ /** The CLI never wrote this file, but a file is there and differs. */
44
+ | 'untracked'
45
+ /** The CLI edits this file after generating it (`add env-key`), so a match with the recorded hash proves nothing. */
46
+ | 'edited-by-cli'
47
+ /** A feature that could not be replayed may have patched this file, so a matching hash proves nothing. */
48
+ | 'skipped-feature'
49
+ /** The path is a symlink; it is not replaced with a regular file. */
50
+ | 'symlink';
51
+ /** A file the new version wants to change that the upgrade will not write. */
52
+ export interface DivergedUpgrade {
53
+ path: string;
54
+ reason: DivergeReason;
55
+ /** What is on disk. */
56
+ yours: string;
57
+ /** What the new version generates. */
58
+ incoming: string;
59
+ /** Unified diff from `yours` to `incoming`. */
60
+ diff: string;
61
+ /** `accept` is written with the new version in `plan`; `keep` is left and remembered. Absent: undecided, left as it is. */
62
+ decision?: 'accept' | 'keep';
63
+ /** For files the CLI adds keys to: keys in your file that the new version lacks, which accepting drops. */
64
+ lostKeys?: string[];
65
+ /** The part of `lostKeys` that is in the new file with another value; the rest are not in it at all. */
66
+ changedValues?: string[];
67
+ }
68
+ export interface UpgradePlan {
69
+ /** The version the project was made with, and where that came from. */
70
+ from: string;
71
+ fromSource: 'mfeflow.json' | 'package.json';
72
+ to: string;
73
+ /** Replaced, created and structurally edited files. Apply it with `applyPlan`, passing `project`. */
74
+ plan: Plan;
75
+ /** The project to hand to `applyPlan`: `cli` is `to`; hashes and feature versions are filled in on apply. */
76
+ project: MfeflowProject;
77
+ /** Files the new version wants to change that you changed too, each with a diff. Only those without a `decision` are left undecided. */
78
+ diverged: DivergedUpgrade[];
79
+ /** Feature migrations that ran, in order. */
80
+ migrations: {
81
+ feature: string;
82
+ from: string;
83
+ to: string;
84
+ }[];
85
+ /** Files the old version generated and the new one no longer does. Reported, never deleted. */
86
+ removed: string[];
87
+ /** Files the old version generated that you deleted. They are not brought back. */
88
+ missing: string[];
89
+ }
90
+ /**
91
+ * The version of the CLI that made the project: `cli` in `mfeflow.json`, else the lowest version
92
+ * the shell's `@mfeflow/runtime` range allows (0.1 projects have no `cli`). A `workspace:`,
93
+ * `link:` or non-version range cannot be read, and that is an error rather than a guess.
94
+ */
95
+ export declare function detectBaseline(project: MfeflowProject, read: ReadFile): Promise<{
96
+ version: string;
97
+ source: 'mfeflow.json' | 'package.json';
98
+ }>;
99
+ /**
100
+ * Works out what moving a project to `toVersion` changes, without touching the disk.
101
+ *
102
+ * It replays the skeleton and every recorded feature, with its recorded options, into memory and
103
+ * compares the result with the project. A tracked file you have not edited is replaced; one you
104
+ * have edited is returned in `diverged` with a diff and left alone; a new file is created; a file
105
+ * the new version no longer makes is listed in `removed` and never deleted. `package.json`,
106
+ * `pnpm-workspace.yaml` and `turbo.json` only get structured edits. Feature migrations whose
107
+ * version the upgrade crosses then run, in order, on the same plan.
108
+ */
109
+ export declare function planUpgrade(project: MfeflowProject, input: UpgradeInput): Promise<UpgradePlan>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mfeflow/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "The engine behind the mfeflow CLI: project model, change plans with diffs, atomic apply with rollback, and feature resolution.",
5
5
  "keywords": [
6
6
  "micro-frontend",
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "@babel/parser": "8.0.10",
47
47
  "@babel/types": "8.0.10",
48
- "@mfeflow/contracts": "0.5.0",
48
+ "@mfeflow/contracts": "0.6.0",
49
49
  "diff": "9.0.0",
50
50
  "eta": "4.6.0",
51
51
  "semver": "7.8.5",