@contentful/experience-design-system-cli 2.7.1-dev-build-02830eb.0 → 2.7.1

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 (34) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/analyze/select/tui/App.js +475 -54
  3. package/dist/src/analyze/select/tui/components/ComponentDetail.d.ts +5 -3
  4. package/dist/src/analyze/select/tui/components/ComponentDetail.js +3 -3
  5. package/dist/src/analyze/select/tui/components/FinalizeDialog.d.ts +1 -1
  6. package/dist/src/analyze/select/tui/components/FinalizeDialog.js +10 -2
  7. package/dist/src/analyze/select/tui/components/HelpOverlay.d.ts +1 -1
  8. package/dist/src/analyze/select/tui/components/HelpOverlay.js +7 -2
  9. package/dist/src/analyze/select/tui/components/JsonEditor.d.ts +5 -7
  10. package/dist/src/analyze/select/tui/components/JsonEditor.js +146 -15
  11. package/dist/src/analyze/select/tui/components/QuitDialog.d.ts +1 -1
  12. package/dist/src/analyze/select/tui/components/QuitDialog.js +10 -2
  13. package/dist/src/analyze/select/tui/components/Sidebar.d.ts +2 -0
  14. package/dist/src/analyze/select/tui/components/StatusBar.d.ts +2 -0
  15. package/dist/src/analyze/select/tui/hooks/useImmediateInput.d.ts +0 -5
  16. package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +4 -7
  17. package/dist/src/analyze/select/tui/hooks/useKeymap.d.ts +23 -0
  18. package/dist/src/analyze/select/tui/hooks/useKeymap.js +67 -1
  19. package/dist/src/analyze/select/tui/hooks/useUndo.js +21 -15
  20. package/dist/src/analyze/tui/AnalyzeView.js +0 -2
  21. package/dist/src/import/tui/WizardApp.js +0 -2
  22. package/dist/src/import/tui/steps/GenerateReviewStep.js +11 -4
  23. package/dist/src/print/validate/tui/ValidateView.js +0 -2
  24. package/package.json +2 -2
  25. package/dist/src/analyze/select/tui/hooks/useRawMode.d.ts +0 -6
  26. package/dist/src/analyze/select/tui/hooks/useRawMode.js +0 -16
  27. package/dist/src/analyze/select/tui/hooks/useSideEffects.d.ts +0 -17
  28. package/dist/src/analyze/select/tui/hooks/useSideEffects.js +0 -226
  29. package/dist/src/analyze/select/tui/inputToAction.d.ts +0 -13
  30. package/dist/src/analyze/select/tui/inputToAction.js +0 -68
  31. package/dist/src/analyze/select/tui/state.d.ts +0 -136
  32. package/dist/src/analyze/select/tui/state.js +0 -385
  33. package/dist/src/analyze/select/tui/utils.d.ts +0 -5
  34. package/dist/src/analyze/select/tui/utils.js +0 -11
@@ -1,385 +0,0 @@
1
- import { stripScoringFields } from '../../../types.js';
2
- import { computeScrollOffset } from './utils.js';
3
- function makeEditorState(value) {
4
- return {
5
- cursor: { lines: value.split('\n'), cursorRow: 0, cursorCol: 0 },
6
- undoStack: [],
7
- scrollRow: 0,
8
- validationError: null,
9
- };
10
- }
11
- function editorWithCursor(e, next) {
12
- return {
13
- ...e,
14
- cursor: next,
15
- undoStack: e.undoStack.length >= 50 ? [...e.undoStack.slice(1), e.cursor] : [...e.undoStack, e.cursor],
16
- };
17
- }
18
- function syncEditorScroll(e, visibleHeight) {
19
- const { cursorRow } = e.cursor;
20
- let { scrollRow } = e;
21
- if (cursorRow < scrollRow)
22
- scrollRow = cursorRow;
23
- if (cursorRow >= scrollRow + visibleHeight)
24
- scrollRow = cursorRow - visibleHeight + 1;
25
- return scrollRow === e.scrollRow ? e : { ...e, scrollRow };
26
- }
27
- // Pure: apply one keypress to EditorState. Returns null if key has no effect.
28
- export function applyEditorKey(e, input, key, visibleHeight) {
29
- const { lines, cursorRow, cursorCol } = e.cursor;
30
- // Ctrl+Z undo
31
- if (key.ctrl && input === 'z') {
32
- if (e.undoStack.length === 0)
33
- return null;
34
- const prev = e.undoStack[e.undoStack.length - 1];
35
- return syncEditorScroll({ ...e, cursor: prev, undoStack: e.undoStack.slice(0, -1) }, visibleHeight);
36
- }
37
- let newLines = [...lines];
38
- let newRow = cursorRow;
39
- let newCol = cursorCol;
40
- if (key.return) {
41
- const before = newLines[cursorRow].slice(0, cursorCol);
42
- const after = newLines[cursorRow].slice(cursorCol);
43
- newLines = [...newLines.slice(0, cursorRow), before, after, ...newLines.slice(cursorRow + 1)];
44
- newRow = cursorRow + 1;
45
- newCol = 0;
46
- }
47
- else if (key.backspace) {
48
- if (cursorCol > 0) {
49
- newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol - 1) + newLines[cursorRow].slice(cursorCol);
50
- newCol = cursorCol - 1;
51
- }
52
- else if (cursorRow > 0) {
53
- const prevLen = newLines[cursorRow - 1].length;
54
- newLines[cursorRow - 1] = newLines[cursorRow - 1] + newLines[cursorRow];
55
- newLines = [...newLines.slice(0, cursorRow), ...newLines.slice(cursorRow + 1)];
56
- newRow = cursorRow - 1;
57
- newCol = prevLen;
58
- }
59
- else {
60
- return null;
61
- }
62
- }
63
- else if (key.delete) {
64
- if (cursorCol < newLines[cursorRow].length) {
65
- newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol) + newLines[cursorRow].slice(cursorCol + 1);
66
- }
67
- else if (cursorRow < newLines.length - 1) {
68
- newLines[cursorRow] = newLines[cursorRow] + newLines[cursorRow + 1];
69
- newLines = [...newLines.slice(0, cursorRow + 1), ...newLines.slice(cursorRow + 2)];
70
- }
71
- else {
72
- return null;
73
- }
74
- }
75
- else if (key.leftArrow) {
76
- if (cursorCol > 0) {
77
- newCol = cursorCol - 1;
78
- }
79
- else if (cursorRow > 0) {
80
- newRow = cursorRow - 1;
81
- newCol = newLines[cursorRow - 1].length;
82
- }
83
- else
84
- return null;
85
- }
86
- else if (key.rightArrow) {
87
- if (cursorCol < newLines[cursorRow].length) {
88
- newCol = cursorCol + 1;
89
- }
90
- else if (cursorRow < newLines.length - 1) {
91
- newRow = cursorRow + 1;
92
- newCol = 0;
93
- }
94
- else
95
- return null;
96
- }
97
- else if (key.upArrow) {
98
- if (cursorRow === 0)
99
- return null;
100
- newRow = cursorRow - 1;
101
- newCol = Math.min(cursorCol, newLines[newRow].length);
102
- }
103
- else if (key.downArrow) {
104
- if (cursorRow >= newLines.length - 1)
105
- return null;
106
- newRow = cursorRow + 1;
107
- newCol = Math.min(cursorCol, newLines[newRow].length);
108
- }
109
- else if (input === '\x1b[H' || input === '\x1b[1~') {
110
- newCol = 0; // Home
111
- }
112
- else if (input === '\x1b[F' || input === '\x1b[4~') {
113
- newCol = newLines[cursorRow].length; // End
114
- }
115
- else if (input && input.length === 1 && !key.ctrl && !key.meta) {
116
- newLines[cursorRow] = newLines[cursorRow].slice(0, cursorCol) + input + newLines[cursorRow].slice(cursorCol);
117
- newCol = cursorCol + 1;
118
- }
119
- else {
120
- return null;
121
- }
122
- return syncEditorScroll(editorWithCursor(e, { lines: newLines, cursorRow: newRow, cursorCol: newCol }), visibleHeight);
123
- }
124
- export const initialState = {
125
- mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
126
- session: null,
127
- paths: null,
128
- selectedId: null,
129
- sortedIds: [],
130
- sessionSummary: [],
131
- sidebarScrollOffset: 0,
132
- jsonScrollOffset: 0,
133
- draftsByComponentId: {},
134
- editor: null,
135
- sourceCodeById: {},
136
- previewAnnotations: (() => {
137
- const raw = process.env['EDS_PREVIEW_ANNOTATIONS'];
138
- if (!raw)
139
- return {};
140
- try {
141
- return JSON.parse(raw);
142
- }
143
- catch {
144
- return {};
145
- }
146
- })(),
147
- previewResponse: null,
148
- previewLoading: false,
149
- previewError: null,
150
- saveError: null,
151
- };
152
- // ── Derived data ──────────────────────────────────────────────────────────────
153
- function computeSortedIds(components) {
154
- return [...components]
155
- .map((c) => ({
156
- id: c.id,
157
- needsReview: c.originalProposal.needsReview ?? false,
158
- status: c.status,
159
- conf: c.originalProposal.extractionConfidence ?? 6,
160
- }))
161
- .sort((a, b) => {
162
- const aF = a.needsReview && a.status === 'needs-review' ? 0 : 1;
163
- const bF = b.needsReview && b.status === 'needs-review' ? 0 : 1;
164
- if (aF !== bF)
165
- return aF - bF;
166
- return a.conf - b.conf;
167
- })
168
- .map((c) => c.id);
169
- }
170
- // Builds a stable summary array for Sidebar — same reference if nothing changed.
171
- // Keeping this in state means Sidebar never re-renders on scroll/selection alone.
172
- function computeSessionSummary(components, annotations, sortedIds) {
173
- return sortedIds
174
- .map((id) => components.find((c) => c.id === id))
175
- .filter((c) => !!c)
176
- .map((c) => ({
177
- id: c.id,
178
- name: c.name,
179
- status: c.status,
180
- previewAnnotation: annotations[c.name],
181
- extractionConfidence: c.originalProposal.extractionConfidence ?? null,
182
- needsReview: c.originalProposal.needsReview ?? false,
183
- }));
184
- }
185
- // Rebuild both sortedIds and sessionSummary from updated components + annotations.
186
- function withUpdatedSession(state, components, annotations) {
187
- const ann = annotations ?? state.previewAnnotations;
188
- const sortedIds = computeSortedIds(components);
189
- const sessionSummary = computeSessionSummary(components, ann, sortedIds);
190
- return {
191
- ...state,
192
- session: { ...state.session, components },
193
- previewAnnotations: ann,
194
- sortedIds,
195
- sessionSummary,
196
- };
197
- }
198
- function updateStatus(state, newStatus) {
199
- if (!state.session || !state.selectedId)
200
- return state;
201
- const components = state.session.components.map((c) => (c.id === state.selectedId ? { ...c, status: newStatus } : c));
202
- return withUpdatedSession(state, components);
203
- }
204
- // ── Reducer ───────────────────────────────────────────────────────────────────
205
- export function reducer(state, action) {
206
- switch (action.type) {
207
- case 'SESSION_LOADED': {
208
- const sortedIds = computeSortedIds(action.session.components);
209
- const sessionSummary = computeSessionSummary(action.session.components, state.previewAnnotations, sortedIds);
210
- return {
211
- ...state,
212
- session: action.session,
213
- paths: action.paths,
214
- sortedIds,
215
- sessionSummary,
216
- selectedId: sortedIds[0] ?? null,
217
- };
218
- }
219
- case 'SELECT':
220
- return { ...state, selectedId: action.id, jsonScrollOffset: 0 };
221
- case 'SIDEBAR_UP': {
222
- if (!state.session || !state.selectedId)
223
- return state;
224
- const idx = state.sortedIds.indexOf(state.selectedId);
225
- if (idx <= 0)
226
- return state;
227
- const ni = idx - 1;
228
- return {
229
- ...state,
230
- selectedId: state.sortedIds[ni],
231
- jsonScrollOffset: 0,
232
- sidebarScrollOffset: computeScrollOffset(ni, state.sidebarScrollOffset, action.visibleCount),
233
- };
234
- }
235
- case 'SIDEBAR_DOWN': {
236
- if (!state.session || !state.selectedId)
237
- return state;
238
- const idx = state.sortedIds.indexOf(state.selectedId);
239
- if (idx >= state.sortedIds.length - 1)
240
- return state;
241
- const ni = idx + 1;
242
- return {
243
- ...state,
244
- selectedId: state.sortedIds[ni],
245
- jsonScrollOffset: 0,
246
- sidebarScrollOffset: computeScrollOffset(ni, state.sidebarScrollOffset, action.visibleCount),
247
- };
248
- }
249
- case 'ACCEPT':
250
- return updateStatus(state, 'accepted');
251
- case 'REJECT':
252
- return updateStatus(state, 'rejected');
253
- case 'APPROVE_ALL': {
254
- if (!state.session)
255
- return state;
256
- const components = state.session.components.map((c) => c.status === 'needs-review' ? { ...c, status: 'accepted' } : c);
257
- return withUpdatedSession(state, components);
258
- }
259
- case 'ENTER_EDIT': {
260
- if (state.mode.type !== 'browsing' || !state.selectedId || !state.session)
261
- return state;
262
- const component = state.session.components.find((c) => c.id === state.selectedId);
263
- if (!component)
264
- return state;
265
- const existing = state.draftsByComponentId[state.selectedId];
266
- const draft = existing ?? JSON.stringify(stripScoringFields(component.editedProposal), null, 2);
267
- const editor = makeEditorState(draft);
268
- return {
269
- ...state,
270
- mode: { type: 'editing', componentId: state.selectedId },
271
- draftsByComponentId: { ...state.draftsByComponentId, [state.selectedId]: draft },
272
- editor,
273
- };
274
- }
275
- case 'EDITOR_KEY': {
276
- if (!state.editor || state.mode.type !== 'editing')
277
- return state;
278
- const next = applyEditorKey(state.editor, action.input, action.key, action.visibleHeight);
279
- if (!next)
280
- return state;
281
- const newValue = next.cursor.lines.join('\n');
282
- return {
283
- ...state,
284
- editor: next,
285
- draftsByComponentId: { ...state.draftsByComponentId, [state.mode.componentId]: newValue },
286
- };
287
- }
288
- case 'EDITOR_VALIDATE': {
289
- // inputToAction calls this on Ctrl+S — reducer does the parse check
290
- if (!state.editor || state.mode.type !== 'editing')
291
- return state;
292
- const text = state.editor.cursor.lines.join('\n');
293
- try {
294
- JSON.parse(text);
295
- // Valid — switch mode back to browsing; side effect will detect the transition and persist
296
- return {
297
- ...state,
298
- editor: { ...state.editor, validationError: null },
299
- mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
300
- // keep draft in draftsByComponentId — side effect will persist it and clear it
301
- };
302
- }
303
- catch (e) {
304
- return {
305
- ...state,
306
- editor: { ...state.editor, validationError: e instanceof Error ? e.message : String(e) },
307
- };
308
- }
309
- }
310
- case 'DRAFT_DISCARD': {
311
- if (state.mode.type !== 'editing')
312
- return state;
313
- const { componentId } = state.mode;
314
- const { [componentId]: _removed, ...remaining } = state.draftsByComponentId;
315
- return {
316
- ...state,
317
- mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false },
318
- draftsByComponentId: remaining,
319
- editor: null,
320
- };
321
- }
322
- case 'DRAFT_PERSIST_DONE': {
323
- const { componentId, updatedComponents } = action;
324
- const { [componentId]: _removed, ...remaining } = state.draftsByComponentId;
325
- const base = withUpdatedSession(state, updatedComponents);
326
- return { ...base, draftsByComponentId: remaining };
327
- }
328
- case 'TOGGLE_FOCUS': {
329
- if (state.mode.type !== 'browsing')
330
- return state;
331
- return { ...state, mode: { ...state.mode, sidebarFocused: !state.mode.sidebarFocused } };
332
- }
333
- case 'SCROLL_UP':
334
- return { ...state, jsonScrollOffset: Math.max(0, state.jsonScrollOffset - 1) };
335
- case 'SCROLL_DOWN':
336
- return { ...state, jsonScrollOffset: state.jsonScrollOffset + 1 };
337
- case 'TOGGLE_SOURCE': {
338
- if (state.mode.type !== 'browsing')
339
- return state;
340
- if (action.terminalWidth < 120)
341
- return { ...state, saveError: 'Terminal too narrow for source panel (need 120+ cols)' };
342
- return { ...state, mode: { ...state.mode, sourceVisible: !state.mode.sourceVisible } };
343
- }
344
- case 'OPEN_DIALOG':
345
- return { ...state, mode: { type: 'dialog', which: action.which } };
346
- case 'CLOSE_DIALOG':
347
- return { ...state, mode: { type: 'browsing', sidebarFocused: true, sourceVisible: false } };
348
- case 'FINALIZE_CONFIRM': {
349
- if (!state.session)
350
- return state;
351
- const accepted = state.session.components.filter((c) => c.status === 'accepted').length;
352
- const rejected = state.session.components.filter((c) => c.status === 'rejected').length;
353
- const excluded = state.session.components.filter((c) => c.status === 'needs-review').length;
354
- return { ...state, mode: { type: 'finalized', accepted, rejected, excluded } };
355
- }
356
- case 'QUIT_CONFIRM':
357
- return state; // side effect handles exit
358
- case 'SOURCE_LOADED':
359
- return { ...state, sourceCodeById: { ...state.sourceCodeById, [action.componentId]: action.code } };
360
- case 'PREVIEW_START':
361
- return { ...state, previewLoading: true };
362
- case 'PREVIEW_SUCCESS': {
363
- const components = state.session?.components ?? [];
364
- const sortedIds = computeSortedIds(components);
365
- const sessionSummary = computeSessionSummary(components, action.annotations, sortedIds);
366
- return {
367
- ...state,
368
- previewResponse: action.response,
369
- previewAnnotations: action.annotations,
370
- previewLoading: false,
371
- previewError: null,
372
- sortedIds,
373
- sessionSummary,
374
- };
375
- }
376
- case 'PREVIEW_ERROR':
377
- return { ...state, previewLoading: false, previewError: action.message };
378
- case 'SAVE_ERROR':
379
- return { ...state, saveError: action.message };
380
- case 'CLEAR_ERRORS':
381
- return { ...state, saveError: null, previewError: null };
382
- default:
383
- return state;
384
- }
385
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Compute the new sidebar scroll offset after moving selection to `idx`.
3
- * Keeps the selected item within the visible window.
4
- */
5
- export declare function computeScrollOffset(idx: number, prev: number, visibleCount: number): number;
@@ -1,11 +0,0 @@
1
- /**
2
- * Compute the new sidebar scroll offset after moving selection to `idx`.
3
- * Keeps the selected item within the visible window.
4
- */
5
- export function computeScrollOffset(idx, prev, visibleCount) {
6
- if (idx < prev)
7
- return idx;
8
- if (idx >= prev + visibleCount)
9
- return idx - visibleCount + 1;
10
- return prev;
11
- }