@topogram/cli 0.3.71 → 0.3.72

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@topogram/cli",
3
- "version": "0.3.71",
3
+ "version": "0.3.72",
4
4
  "description": "Topogram CLI for checking Topogram workspaces and generating app bundles.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,8 +43,5 @@ export function parseProjectCommandArgs(args) {
43
43
  if (args[0] === "package" && args[1] === "update-cli") {
44
44
  return { packageCommand: "update-cli", inputPath: args.includes("--latest") ? "latest" : args[2] };
45
45
  }
46
- if (args[0] === "migrate" && args[1] === "workspace-folder") {
47
- return { migrateCommand: "workspace-folder", inputPath: commandPath(args, 2, ".") };
48
- }
49
46
  return null;
50
47
  }
@@ -10,7 +10,6 @@ import { runGenerateAppCommand } from "./commands/generate.js";
10
10
  import { runGeneratorCommand } from "./commands/generator.js";
11
11
  import { runGeneratorPolicyCommand } from "./commands/generator-policy.js";
12
12
  import { runImportCommand } from "./commands/import-runner.js";
13
- import { runMigrateCommand } from "./commands/migrate.js";
14
13
  import { runNewProjectCommand } from "./commands/new.js";
15
14
  import { runPackageCommand } from "./commands/package.js";
16
15
  import { runParseCommand, runResolveCommand } from "./commands/inspect.js";
@@ -242,10 +241,6 @@ export async function runCliDispatch(context) {
242
241
  return runPackageCommand({ commandArgs, inputPath, json: emitJson });
243
242
  }
244
243
 
245
- if (commandArgs?.migrateCommand) {
246
- return runMigrateCommand(inputPath, { write: shouldWrite, json: emitJson });
247
- }
248
-
249
244
  if (commandArgs?.importCommand) {
250
245
  return runImportCommand({
251
246
  commandArgs,
package/src/cli/help.js CHANGED
@@ -28,7 +28,6 @@ export function printUsage(options = {}) {
28
28
  console.log(" or: topogram catalog doctor [--json] [--catalog <path-or-source>]");
29
29
  console.log(" or: topogram catalog check <path-or-url> [--json]");
30
30
  console.log(" or: topogram catalog copy <id> <target> [--version <version>] [--json] [--catalog <path-or-source>]");
31
- console.log(" or: topogram migrate workspace-folder [path] [--dry-run|--write] [--json]");
32
31
  console.log(" or: topogram package update-cli <version|--latest> [--json]");
33
32
  console.log(" or: topogram import <app-path> --out <target> [--from <track[,track]>] [--json]");
34
33
  console.log(" or: topogram import refresh [path] [--from <app-path>] [--dry-run] [--json]");
@@ -30,6 +30,9 @@ export function cliMigrationError(args) {
30
30
  if (args[0] === "component") {
31
31
  return "Command 'topogram component' was renamed to 'topogram widget'.";
32
32
  }
33
+ if (args[0] === "migrate") {
34
+ return "Command 'topogram migrate workspace-folder' was removed. Use topo/ workspaces or configure topogram.project.json workspace to a non-legacy relative path.";
35
+ }
33
36
  for (const [oldArg, newArg] of RENAMED_CLI_ARGS) {
34
37
  if (args.includes(oldArg)) {
35
38
  return `CLI flag '${oldArg}' was renamed to '${newArg}'.`;
@@ -209,8 +209,8 @@ discover_input_path() {
209
209
  )
210
210
  local candidate
211
211
  for candidate in "\${candidates[@]}"; do
212
- if resolved="$(resolve_path_candidate "$candidate" "$PWD")" && [[ -d "$resolved/topogram" ]]; then
213
- printf '%s\\n' "$resolved/topogram"
212
+ if resolved="$(resolve_path_candidate "$candidate" "$PWD")" && [[ -d "$resolved/topo" ]]; then
213
+ printf '%s\\n' "$resolved/topo"
214
214
  return
215
215
  fi
216
216
  done
@@ -4,10 +4,10 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
 
6
6
  export const DEFAULT_TOPO_FOLDER_NAME = "topo";
7
- export const LEGACY_TOPOGRAM_FOLDER_NAME = "topogram";
8
7
  export const DEFAULT_WORKSPACE_PATH = `./${DEFAULT_TOPO_FOLDER_NAME}`;
9
8
  export const PROJECT_CONFIG_FILE = "topogram.project.json";
10
9
 
10
+ const LEGACY_WORKSPACE_FOLDER_NAME = "topogram";
11
11
  const SIGNAL_SCAN_IGNORED_DIRS = new Set([
12
12
  ".git",
13
13
  ".next",
@@ -19,6 +19,7 @@ const SIGNAL_SCAN_IGNORED_DIRS = new Set([
19
19
  "coverage",
20
20
  "dist",
21
21
  "expected",
22
+ LEGACY_WORKSPACE_FOLDER_NAME,
22
23
  "node_modules",
23
24
  "tmp"
24
25
  ]);
@@ -128,6 +129,9 @@ export function normalizeWorkspaceConfigPath(workspacePath) {
128
129
  if (resolved === ".." || resolved.startsWith("../")) {
129
130
  throw new Error("topogram.project.json workspace must not escape the project root.");
130
131
  }
132
+ if (resolved === LEGACY_WORKSPACE_FOLDER_NAME || resolved.startsWith(`${LEGACY_WORKSPACE_FOLDER_NAME}/`)) {
133
+ throw new Error("topogram.project.json workspace must use ./topo or another non-legacy relative path.");
134
+ }
131
135
  return normalized;
132
136
  }
133
137
 
@@ -225,6 +229,9 @@ function signalWorkspaceCandidates(root) {
225
229
  */
226
230
  export function resolveWorkspaceContext(inputPath = ".") {
227
231
  const absolute = path.resolve(inputPath || ".");
232
+ if (isDirectory(absolute) && path.basename(absolute) === LEGACY_WORKSPACE_FOLDER_NAME && isWorkspaceSignalRoot(absolute)) {
233
+ throw new Error("Legacy workspace folders are not supported. Use topo/ or configure topogram.project.json workspace to a non-legacy relative path.");
234
+ }
228
235
  if (
229
236
  isDirectory(absolute) &&
230
237
  (
@@ -1,153 +0,0 @@
1
- // @ts-check
2
-
3
- import fs from "node:fs";
4
- import path from "node:path";
5
-
6
- import { stableStringify } from "../../format.js";
7
- import {
8
- DEFAULT_TOPO_FOLDER_NAME,
9
- DEFAULT_WORKSPACE_PATH,
10
- LEGACY_TOPOGRAM_FOLDER_NAME,
11
- PROJECT_CONFIG_FILE
12
- } from "../../workspace-paths.js";
13
-
14
- /**
15
- * @param {string|null|undefined} inputPath
16
- * @returns {string}
17
- */
18
- function projectRootForMigration(inputPath) {
19
- const absolute = path.resolve(inputPath || ".");
20
- const base = path.basename(absolute);
21
- if (base === DEFAULT_TOPO_FOLDER_NAME || base === LEGACY_TOPOGRAM_FOLDER_NAME) {
22
- return path.dirname(absolute);
23
- }
24
- return absolute;
25
- }
26
-
27
- /**
28
- * @param {string} projectRoot
29
- * @returns {string[]}
30
- */
31
- function caseCollisionEntries(projectRoot) {
32
- if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
33
- return [];
34
- }
35
- return fs.readdirSync(projectRoot)
36
- .filter((/** @type {string} */ entry) => entry.toLowerCase() === DEFAULT_TOPO_FOLDER_NAME && entry !== DEFAULT_TOPO_FOLDER_NAME);
37
- }
38
-
39
- /**
40
- * @param {string} projectRoot
41
- * @returns {{ write: boolean, path: string|null, before: any|null, after: any|null }}
42
- */
43
- function plannedProjectConfigUpdate(projectRoot) {
44
- const configPath = path.join(projectRoot, PROJECT_CONFIG_FILE);
45
- if (!fs.existsSync(configPath)) {
46
- return { write: false, path: null, before: null, after: null };
47
- }
48
- const before = JSON.parse(fs.readFileSync(configPath, "utf8"));
49
- const after = { ...before };
50
- const currentWorkspace = before.workspace;
51
- if (currentWorkspace == null || currentWorkspace === "./topogram" || currentWorkspace === "topogram") {
52
- after.workspace = DEFAULT_WORKSPACE_PATH;
53
- }
54
- return {
55
- write: JSON.stringify(before) !== JSON.stringify(after),
56
- path: configPath,
57
- before,
58
- after
59
- };
60
- }
61
-
62
- /**
63
- * @param {string|null|undefined} inputPath
64
- * @param {{ write?: boolean, json?: boolean }} [options]
65
- * @returns {number}
66
- */
67
- export function runMigrateCommand(inputPath, options = {}) {
68
- const projectRoot = projectRootForMigration(inputPath);
69
- const legacyPath = path.join(projectRoot, LEGACY_TOPOGRAM_FOLDER_NAME);
70
- const topoPath = path.join(projectRoot, DEFAULT_TOPO_FOLDER_NAME);
71
- const write = Boolean(options.write);
72
- /** @type {Array<Record<string, any>>} */
73
- const diagnostics = [];
74
- /** @type {Array<Record<string, any>>} */
75
- const actions = [];
76
-
77
- if (fs.existsSync(legacyPath) && fs.lstatSync(legacyPath).isSymbolicLink()) {
78
- diagnostics.push({ severity: "error", message: `Refusing to migrate symlinked ${LEGACY_TOPOGRAM_FOLDER_NAME}/ at ${legacyPath}.` });
79
- }
80
- const collisions = caseCollisionEntries(projectRoot);
81
- if (collisions.length > 0) {
82
- diagnostics.push({ severity: "error", message: `Refusing to migrate because case-conflicting topo path(s) exist: ${collisions.join(", ")}.` });
83
- }
84
- if (fs.existsSync(legacyPath) && fs.existsSync(topoPath)) {
85
- diagnostics.push({ severity: "error", message: `Refusing to migrate because both ${LEGACY_TOPOGRAM_FOLDER_NAME}/ and ${DEFAULT_TOPO_FOLDER_NAME}/ exist.` });
86
- }
87
- if (!fs.existsSync(legacyPath) && !fs.existsSync(topoPath)) {
88
- diagnostics.push({ severity: "error", message: `No ${LEGACY_TOPOGRAM_FOLDER_NAME}/ or ${DEFAULT_TOPO_FOLDER_NAME}/ workspace folder found at ${projectRoot}.` });
89
- }
90
- if (fs.existsSync(topoPath) && fs.statSync(topoPath).isDirectory() && fs.readdirSync(topoPath).length > 0 && fs.existsSync(legacyPath)) {
91
- diagnostics.push({ severity: "error", message: `Refusing to overwrite non-empty ${DEFAULT_TOPO_FOLDER_NAME}/ at ${topoPath}.` });
92
- }
93
-
94
- if (fs.existsSync(legacyPath) && diagnostics.length === 0) {
95
- actions.push({
96
- kind: "rename",
97
- from: legacyPath,
98
- to: topoPath
99
- });
100
- }
101
- const configUpdate = plannedProjectConfigUpdate(projectRoot);
102
- if (configUpdate.write) {
103
- actions.push({
104
- kind: "update_config",
105
- path: configUpdate.path,
106
- workspace: DEFAULT_WORKSPACE_PATH
107
- });
108
- }
109
-
110
- const ok = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length === 0;
111
- if (ok && write) {
112
- for (const action of actions) {
113
- if (action.kind === "rename") {
114
- fs.renameSync(action.from, action.to);
115
- }
116
- if (action.kind === "update_config" && configUpdate.path && configUpdate.after) {
117
- fs.writeFileSync(configUpdate.path, `${JSON.stringify(configUpdate.after, null, 2)}\n`, "utf8");
118
- }
119
- }
120
- }
121
-
122
- const payload = {
123
- ok,
124
- dryRun: !write,
125
- projectRoot,
126
- legacyPath,
127
- topoPath,
128
- actions,
129
- diagnostics,
130
- errors: diagnostics.filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message)
131
- };
132
- if (options.json) {
133
- console.log(stableStringify(payload));
134
- } else if (payload.ok) {
135
- console.log(write ? "Workspace folder migration complete." : "Workspace folder migration dry run.");
136
- if (actions.length === 0) {
137
- console.log("No changes needed.");
138
- }
139
- for (const action of actions) {
140
- if (action.kind === "rename") {
141
- console.log(`Rename: ${action.from} -> ${action.to}`);
142
- }
143
- if (action.kind === "update_config") {
144
- console.log(`Update ${action.path}: workspace ${DEFAULT_WORKSPACE_PATH}`);
145
- }
146
- }
147
- } else {
148
- for (const error of payload.errors) {
149
- console.error(error);
150
- }
151
- }
152
- return payload.ok ? 0 : 1;
153
- }