@opencraw/studio 0.0.27 → 0.0.29
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/browser-provisioning/install-chromium.use-case.d.ts +13 -0
- package/dist/document-view/workbook-view.mapper.d.ts +8 -0
- package/dist/folder-dialog/choose-folder.client.d.ts +25 -0
- package/dist/folder-dialog/folder-dialog.algorithm.d.ts +25 -0
- package/dist/folder-dialog/index.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +355 -8
- package/dist/main.d.ts +2 -0
- package/dist/recipe-workspace/index.d.ts +1 -0
- package/dist/recipe-workspace/open-path.use-case.d.ts +18 -0
- package/dist/src/browser-provisioning/install-chromium.use-case.d.ts +13 -0
- package/dist/src/document-view/workbook-view.mapper.d.ts +8 -0
- package/dist/src/folder-dialog/choose-folder.client.d.ts +25 -0
- package/dist/src/folder-dialog/folder-dialog.algorithm.d.ts +25 -0
- package/dist/src/folder-dialog/index.d.ts +2 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/main.d.ts +2 -0
- package/dist/src/recipe-workspace/index.d.ts +1 -0
- package/dist/src/recipe-workspace/open-path.use-case.d.ts +18 -0
- package/dist/src/studio-api/choose-folder-view.contract.d.ts +7 -0
- package/dist/src/studio-api/command.contract.d.ts +18 -0
- package/dist/src/studio-api/deck-view.contract.d.ts +8 -0
- package/dist/src/studio-api/grid-view.contract.d.ts +8 -0
- package/dist/src/studio-api/index.d.ts +6 -2
- package/dist/src/studio-api/open-path-view.contract.d.ts +23 -0
- package/dist/src/studio-server/choose-folder.handler.d.ts +13 -0
- package/dist/src/studio-server/open-path.handler.d.ts +11 -0
- package/dist/src/studio-server/studio-http.use-case.d.ts +7 -0
- package/dist/src/studio-server/workspace.store.d.ts +4 -0
- package/dist/studio-api/choose-folder-view.contract.d.ts +7 -0
- package/dist/studio-api/command.contract.d.ts +18 -0
- package/dist/studio-api/deck-view.contract.d.ts +8 -0
- package/dist/studio-api/grid-view.contract.d.ts +8 -0
- package/dist/studio-api/index.d.ts +6 -2
- package/dist/studio-api/open-path-view.contract.d.ts +23 -0
- package/dist/studio-server/choose-folder.handler.d.ts +13 -0
- package/dist/studio-server/open-path.handler.d.ts +11 -0
- package/dist/studio-server/studio-http.use-case.d.ts +7 -0
- package/dist/studio-server/workspace.store.d.ts +4 -0
- package/dist/ui/apple-touch-icon.png +0 -0
- package/dist/ui/assets/index-Bzb5bAuR.js +38 -0
- package/dist/ui/assets/{pdf-clzdjy4q.js → pdf-BReC8938.js} +1 -1
- package/dist/ui/favicon.ico +0 -0
- package/dist/ui/favicon.svg +30 -0
- package/dist/ui/index.html +4 -2
- package/package.json +3 -3
- package/dist/ui/assets/index-D1vjq3SW.js +0 -38
|
@@ -1,2 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the install is run: the current executable as a Node, on Playwright's own CLI. Inside the desktop app
|
|
3
|
+
* the executable is Electron, which runs as plain Node only with `ELECTRON_RUN_AS_NODE` (otherwise it would
|
|
4
|
+
* start a second copy of the app); under Node the variable does nothing.
|
|
5
|
+
*
|
|
6
|
+
* @param cliPath - Playwright's `cli.js`.
|
|
7
|
+
* @returns What to hand to `execFile`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function installInvocation(cliPath: string): {
|
|
10
|
+
file: string;
|
|
11
|
+
args: string[];
|
|
12
|
+
env: NodeJS.ProcessEnv;
|
|
13
|
+
};
|
|
1
14
|
export declare function installChromiumOnce(run?: () => Promise<void>): Promise<void>;
|
|
2
15
|
//# sourceMappingURL=install-chromium.use-case.d.ts.map
|
|
@@ -24,6 +24,14 @@ export interface GridSheetView {
|
|
|
24
24
|
columnCount: number;
|
|
25
25
|
rows: GridCellView[][];
|
|
26
26
|
merges: GridMergeView[];
|
|
27
|
+
/** Column widths in characters by 0-based column, as the spreadsheet stores them; absent keys are columns the file does not size. */
|
|
28
|
+
columnWidths?: Record<string, number>;
|
|
29
|
+
/** Row heights in points by 0-based row, as the spreadsheet stores them. */
|
|
30
|
+
rowHeights?: Record<string, number>;
|
|
31
|
+
/** The width of a column the file does not size, in characters. */
|
|
32
|
+
defaultColumnWidth?: number;
|
|
33
|
+
/** The height of a row the file does not size, in points. */
|
|
34
|
+
defaultRowHeight?: number;
|
|
27
35
|
}
|
|
28
36
|
/** What `grid-view` answers with (studio plan §3.4, issue #94's 5c): every sheet's cells, typed, with hidden sheets/rows marked and merged ranges resolved — the CSV/workbook grid's own view of the document, structurally the same idea as `pdf-view.mapper.ts`'s `PdfDocumentView`. */
|
|
29
37
|
export interface WorkbookDocumentView {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DialogCommand } from './folder-dialog.algorithm';
|
|
2
|
+
/** What a dialog program did: its output, or how it ended. `missing` means the program is not installed. */
|
|
3
|
+
export type DialogRun = {
|
|
4
|
+
output: string;
|
|
5
|
+
} | {
|
|
6
|
+
cancelled: true;
|
|
7
|
+
} | {
|
|
8
|
+
missing: true;
|
|
9
|
+
};
|
|
10
|
+
/** Runs one dialog program and waits for the person to answer; real by default, replaced in tests. */
|
|
11
|
+
export type RunDialog = (command: DialogCommand) => Promise<DialogRun>;
|
|
12
|
+
/** Runs the program with Node's own `execFile`: no shell, so a path or title is never parsed as a command. */
|
|
13
|
+
export declare const runDialogProgram: RunDialog;
|
|
14
|
+
/**
|
|
15
|
+
* Opens the operating system's own folder dialog on the machine the server
|
|
16
|
+
* runs on, which is where the recipe folder is: a browser tab cannot do it,
|
|
17
|
+
* the server can. Waits until the person picks a folder or closes the dialog.
|
|
18
|
+
*
|
|
19
|
+
* @param platform - `process.platform`; passed in so a test names the platform it means.
|
|
20
|
+
* @param run - How a dialog program is run.
|
|
21
|
+
* @returns The folder picked, or `undefined` when the dialog was closed without a choice.
|
|
22
|
+
* @throws Error when the platform has no dialog program installed (a server with no display, a container).
|
|
23
|
+
*/
|
|
24
|
+
export declare function chooseFolderWithDialog(platform?: NodeJS.Platform, run?: RunDialog): Promise<string | undefined>;
|
|
25
|
+
//# sourceMappingURL=choose-folder.client.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** One way to open a folder dialog: a program and its arguments. */
|
|
2
|
+
export interface DialogCommand {
|
|
3
|
+
file: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The programs that can open a folder dialog on a platform, in the order to
|
|
8
|
+
* try them: the first one installed is used. Windows and macOS have one each
|
|
9
|
+
* in every install; Linux has whichever of `zenity` (GNOME and most others)
|
|
10
|
+
* and `kdialog` (KDE) the desktop ships.
|
|
11
|
+
*
|
|
12
|
+
* @param platform - `process.platform`.
|
|
13
|
+
* @returns The candidates; empty for a platform with no known dialog.
|
|
14
|
+
*/
|
|
15
|
+
export declare function folderDialogCommands(platform: NodeJS.Platform): DialogCommand[];
|
|
16
|
+
/**
|
|
17
|
+
* The folder a dialog printed: its output without the line break and the
|
|
18
|
+
* trailing separator (`osascript` ends a folder with `/`), a root kept as it
|
|
19
|
+
* is. Nothing printed means the person cancelled.
|
|
20
|
+
*
|
|
21
|
+
* @param output - What the dialog program wrote to its standard output.
|
|
22
|
+
* @returns The folder path, or `undefined` for a cancelled dialog.
|
|
23
|
+
*/
|
|
24
|
+
export declare function folderFromDialogOutput(output: string): string | undefined;
|
|
25
|
+
//# sourceMappingURL=folder-dialog.algorithm.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export { runSample, loadRecipePair } from './sample-run';
|
|
|
9
9
|
export type { RecipePair, SampleRunCallbacks, SampleRunHandle, SampleRunRecord, SampleRunRejected, SampleRunResult, SampleStepSummary, SampleStoppedBy } from './sample-run';
|
|
10
10
|
export { fetchStartPage } from './page-snapshot';
|
|
11
11
|
export type { WhyFacts, WhyStepFact } from './explain-why';
|
|
12
|
-
export { sampleBudgetSchema, openWorkspaceCommandSchema, importDocumentCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, missingWhyTargetSchema, rejectedWhyTargetSchema, whyTargetSchema, explainWhyCommandSchema, studioCommandSchema, importDocumentViewSchema, stoppedBySchema, fieldTraceSchema, traceLineEventSchema, recordEventSchema, recordRejectedEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, loadedHooksSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, snapshotViewSchema, verifySelectorViewSchema, fieldPickSchema, inferSelectorViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, whyViewSchema, inspectPageCommandSchema, responsesSeenCommandSchema, documentTreeCommandSchema, pdfViewCommandSchema, tablePreviewOptionsSchema, tablePreviewCommandSchema, regionPreviewCommandSchema, regionPreviewMatchSchema, regionPreviewViewSchema, gridViewCommandSchema, gridPreviewOptionsSchema, gridPreviewCommandSchema, deckViewCommandSchema, deckPreviewOptionsSchema, deckPreviewCommandSchema, domTreeNodeViewSchema, pageDataFindingSchema, inspectViewSchema, observedResponseSchema, responsesSeenViewSchema, documentTreeNodeViewSchema, documentTreeViewSchema, pdfCellViewSchema, pdfRowViewSchema, pdfPageViewSchema, pdfDocumentViewSchema, tablePreviewTableSchema, tablePreviewBandSchema, tablePreviewMatchSchema, tablePreviewViewSchema, gridCellViewSchema, gridMergeViewSchema, gridSheetViewSchema, workbookDocumentViewSchema, gridTablePreviewMatchSchema, gridTablePreviewViewSchema, deckShapeViewSchema, deckChartSeriesViewSchema, deckChartViewSchema, deckSlideViewSchema, deckDocumentViewSchema, deckTablePreviewMatchSchema, deckTablePreviewViewSchema, startRecordingCommandSchema, stopRecordingCommandSchema, recordingCardEventSchema, recordingNoteEventSchema, recordingStoppedEventSchema, } from './studio-api';
|
|
13
|
-
export type { SampleBudget, OpenWorkspaceCommand, ImportDocumentCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, MissingWhyTarget, RejectedWhyTarget, WhyTarget, ExplainWhyCommand, InspectPageCommand, ResponsesSeenCommand, DocumentTreeCommand, PdfViewCommand, TablePreviewOptions, TablePreviewCommand, RegionPreviewCommand, GridViewCommand, GridPreviewOptions, GridPreviewCommand, DeckViewCommand, DeckPreviewOptions, DeckPreviewCommand, StudioCommand, ImportDocumentView, RegionPreviewMatchView, RegionPreviewView, StoppedBy, FieldTraceView, TraceLineEvent, RecordEvent, RecordRejectedEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, LoadedHooks, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SnapshotView, VerifySelectorView, FieldPick, InferSelectorView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, WhyView, DomTreeNodeView, PageDataKind, PageDataFindingView, InspectView, ObservedResponseView, ResponsesSeenView, DocumentTreeNodeView, DocumentTreeView, PdfCellView, PdfRowView, PdfPageView, PdfDocumentView, TablePreviewTableView, TablePreviewBandView, TablePreviewMatchView, TablePreviewView, GridCellView, GridMergeView, GridSheetView, WorkbookDocumentView, GridTablePreviewMatchView, GridTablePreviewView, DeckShapeView, DeckChartSeriesView, DeckChartView, DeckSlideView, DeckDocumentView, DeckTablePreviewMatchView, DeckTablePreviewView, StartRecordingCommand, StopRecordingCommand, RecordingCardEvent, RecordingNoteEvent, RecordingStoppedEvent, } from './studio-api';
|
|
12
|
+
export { sampleBudgetSchema, openWorkspaceCommandSchema, chooseFolderCommandSchema, openPathCommandSchema, importDocumentCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, missingWhyTargetSchema, rejectedWhyTargetSchema, whyTargetSchema, explainWhyCommandSchema, studioCommandSchema, chooseFolderViewSchema, openPathViewSchema, importDocumentViewSchema, stoppedBySchema, fieldTraceSchema, traceLineEventSchema, recordEventSchema, recordRejectedEventSchema, runFinishedEventSchema, workspaceChangedEventSchema, studioEventSchema, loadedHooksSchema, recipeIssueSchema, recipeListingSchema, workspaceViewSchema, sampleRunRecordSchema, sampleRunViewSchema, startPageViewSchema, snapshotViewSchema, verifySelectorViewSchema, fieldPickSchema, inferSelectorViewSchema, sentencePartSchema, outlineCardSchema, outlineBracketSchema, outlineNodeSchema, outlineViewSchema, whyViewSchema, inspectPageCommandSchema, responsesSeenCommandSchema, documentTreeCommandSchema, pdfViewCommandSchema, tablePreviewOptionsSchema, tablePreviewCommandSchema, regionPreviewCommandSchema, regionPreviewMatchSchema, regionPreviewViewSchema, gridViewCommandSchema, gridPreviewOptionsSchema, gridPreviewCommandSchema, deckViewCommandSchema, deckPreviewOptionsSchema, deckPreviewCommandSchema, domTreeNodeViewSchema, pageDataFindingSchema, inspectViewSchema, observedResponseSchema, responsesSeenViewSchema, documentTreeNodeViewSchema, documentTreeViewSchema, pdfCellViewSchema, pdfRowViewSchema, pdfPageViewSchema, pdfDocumentViewSchema, tablePreviewTableSchema, tablePreviewBandSchema, tablePreviewMatchSchema, tablePreviewViewSchema, gridCellViewSchema, gridMergeViewSchema, gridSheetViewSchema, workbookDocumentViewSchema, gridTablePreviewMatchSchema, gridTablePreviewViewSchema, deckShapeViewSchema, deckChartSeriesViewSchema, deckChartViewSchema, deckSlideViewSchema, deckDocumentViewSchema, deckTablePreviewMatchSchema, deckTablePreviewViewSchema, startRecordingCommandSchema, stopRecordingCommandSchema, recordingCardEventSchema, recordingNoteEventSchema, recordingStoppedEventSchema, } from './studio-api';
|
|
13
|
+
export type { SampleBudget, OpenWorkspaceCommand, ChooseFolderCommand, OpenPathCommand, ImportDocumentCommand, RunSampleCommand, StopRunCommand, SaveRecipeCommand, FetchStartPageCommand, SaveOutlineCommand, TakeSnapshotCommand, VerifySelectorCommand, InferSelectorCommand, MissingWhyTarget, RejectedWhyTarget, WhyTarget, ExplainWhyCommand, InspectPageCommand, ResponsesSeenCommand, DocumentTreeCommand, PdfViewCommand, TablePreviewOptions, TablePreviewCommand, RegionPreviewCommand, GridViewCommand, GridPreviewOptions, GridPreviewCommand, DeckViewCommand, DeckPreviewOptions, DeckPreviewCommand, StudioCommand, ChooseFolderView, OpenPathView, ImportDocumentView, RegionPreviewMatchView, RegionPreviewView, StoppedBy, FieldTraceView, TraceLineEvent, RecordEvent, RecordRejectedEvent, RunFinishedEvent, WorkspaceChangedEvent, StudioEvent, LoadedHooks, RecipeIssue, RecipeListing, WorkspaceView, SampleRunView, StartPageView, SnapshotView, VerifySelectorView, FieldPick, InferSelectorView, SentencePart, OutlineCard, OutlineBracket, OutlineNode, OutlineView, WhyView, DomTreeNodeView, PageDataKind, PageDataFindingView, InspectView, ObservedResponseView, ResponsesSeenView, DocumentTreeNodeView, DocumentTreeView, PdfCellView, PdfRowView, PdfPageView, PdfDocumentView, TablePreviewTableView, TablePreviewBandView, TablePreviewMatchView, TablePreviewView, GridCellView, GridMergeView, GridSheetView, WorkbookDocumentView, GridTablePreviewMatchView, GridTablePreviewView, DeckShapeView, DeckChartSeriesView, DeckChartView, DeckSlideView, DeckDocumentView, DeckTablePreviewMatchView, DeckTablePreviewView, StartRecordingCommand, StopRecordingCommand, RecordingCardEvent, RecordingNoteEvent, RecordingStoppedEvent, } from './studio-api';
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, dirname, basename, extname,
|
|
1
|
+
import { join, dirname, basename, extname, isAbsolute, relative, resolve, normalize, sep } from 'node:path';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
3
|
import { promisify, stripVTControlCharacters } from 'node:util';
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -8,7 +8,7 @@ import { randomBytes, createHash } from 'node:crypto';
|
|
|
8
8
|
import { execFile } from 'node:child_process';
|
|
9
9
|
import { createRequire } from 'node:module';
|
|
10
10
|
import { load } from 'cheerio';
|
|
11
|
-
import { readFile, writeFile, rm, rename, mkdir } from 'node:fs/promises';
|
|
11
|
+
import { readFile, writeFile, rm, rename, mkdir, stat } from 'node:fs/promises';
|
|
12
12
|
import { describeJson } from '@opencraw/probe';
|
|
13
13
|
import { tmpdir } from 'node:os';
|
|
14
14
|
import { existsSync, createReadStream } from 'node:fs';
|
|
@@ -52,6 +52,16 @@ const openWorkspaceCommandSchema = z.object({
|
|
|
52
52
|
type: z.literal('open-workspace'),
|
|
53
53
|
folder: z.string().min(1)
|
|
54
54
|
});
|
|
55
|
+
/** Says what a path is (folder, recipe or document) and where to open it: how a link or an IDE entry opens a path (issue #235). `workspace` is the folder a document should belong to, when the caller has one. */
|
|
56
|
+
const openPathCommandSchema = z.object({
|
|
57
|
+
type: z.literal('open-path'),
|
|
58
|
+
path: z.string().min(1),
|
|
59
|
+
workspace: z.string().min(1).optional()
|
|
60
|
+
});
|
|
61
|
+
/** Opens the operating system's folder dialog on the server's machine: the answer is the folder picked, if any. */
|
|
62
|
+
const chooseFolderCommandSchema = z.object({
|
|
63
|
+
type: z.literal('choose-folder')
|
|
64
|
+
});
|
|
55
65
|
/** Runs one input recipe under a budget, streaming `trace-line` and `record` events, ending in `run-finished`. */
|
|
56
66
|
const runSampleCommandSchema = z.object({
|
|
57
67
|
type: z.literal('run-sample'),
|
|
@@ -344,7 +354,7 @@ const importDocumentCommandSchema = z.object({
|
|
|
344
354
|
name: z.string().min(1),
|
|
345
355
|
bytes: z.string()
|
|
346
356
|
});
|
|
347
|
-
const studioCommandSchema = z.discriminatedUnion('type', [openWorkspaceCommandSchema, importDocumentCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, explainWhyCommandSchema, inspectPageCommandSchema, responsesSeenCommandSchema, documentTreeCommandSchema, pdfViewCommandSchema, tablePreviewCommandSchema, regionPreviewCommandSchema, gridViewCommandSchema, gridPreviewCommandSchema, deckViewCommandSchema, deckPreviewCommandSchema, startRecordingCommandSchema, stopRecordingCommandSchema]);
|
|
357
|
+
const studioCommandSchema = z.discriminatedUnion('type', [openWorkspaceCommandSchema, chooseFolderCommandSchema, openPathCommandSchema, importDocumentCommandSchema, runSampleCommandSchema, stopRunCommandSchema, saveRecipeCommandSchema, fetchStartPageCommandSchema, saveOutlineCommandSchema, takeSnapshotCommandSchema, verifySelectorCommandSchema, inferSelectorCommandSchema, explainWhyCommandSchema, inspectPageCommandSchema, responsesSeenCommandSchema, documentTreeCommandSchema, pdfViewCommandSchema, tablePreviewCommandSchema, regionPreviewCommandSchema, gridViewCommandSchema, gridPreviewCommandSchema, deckViewCommandSchema, deckPreviewCommandSchema, startRecordingCommandSchema, stopRecordingCommandSchema]);
|
|
348
358
|
|
|
349
359
|
/**
|
|
350
360
|
* What `take-snapshot` answers with: the rewritten document ready for the
|
|
@@ -525,6 +535,32 @@ const workspaceViewSchema = z.object({
|
|
|
525
535
|
hooks: loadedHooksSchema.optional()
|
|
526
536
|
});
|
|
527
537
|
|
|
538
|
+
/** `choose-folder`'s answer: the folder the person picked in the operating system's dialog; absent when the dialog was closed without a choice. */
|
|
539
|
+
const chooseFolderViewSchema = z.object({
|
|
540
|
+
folder: z.string().min(1).optional()
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* `open-path`'s answer: what the path turned out to be, and the folder to
|
|
545
|
+
* open as the workspace for it. A `recipe` names the input recipe to select
|
|
546
|
+
* when there is one; a `document` is where the file is read from (in place
|
|
547
|
+
* when it is already inside the folder, else the copy made there) and its
|
|
548
|
+
* `file:` URL, ready for a recipe's `start.url`.
|
|
549
|
+
*/
|
|
550
|
+
const openPathViewSchema = z.discriminatedUnion('kind', [z.object({
|
|
551
|
+
kind: z.literal('folder'),
|
|
552
|
+
folder: z.string().min(1)
|
|
553
|
+
}), z.object({
|
|
554
|
+
kind: z.literal('recipe'),
|
|
555
|
+
folder: z.string().min(1),
|
|
556
|
+
recipeId: z.string().min(1).optional()
|
|
557
|
+
}), z.object({
|
|
558
|
+
kind: z.literal('document'),
|
|
559
|
+
folder: z.string().min(1),
|
|
560
|
+
path: z.string().min(1),
|
|
561
|
+
url: z.string().startsWith('file:')
|
|
562
|
+
})]);
|
|
563
|
+
|
|
528
564
|
/** `import-document`'s answer: where the copy landed, and the `file:` URL a recipe's `start.url` points at it with. */
|
|
529
565
|
const importDocumentViewSchema = z.object({
|
|
530
566
|
path: z.string().min(1),
|
|
@@ -708,7 +744,15 @@ const gridSheetViewSchema = z.object({
|
|
|
708
744
|
hiddenRows: z.array(z.number().int()),
|
|
709
745
|
columnCount: z.number().int(),
|
|
710
746
|
rows: z.array(z.array(gridCellViewSchema)),
|
|
711
|
-
merges: z.array(gridMergeViewSchema)
|
|
747
|
+
merges: z.array(gridMergeViewSchema),
|
|
748
|
+
/** Column widths in characters by 0-based column, as the spreadsheet stores them (absent for a CSV, and for a column the file does not size). */
|
|
749
|
+
columnWidths: z.record(z.string(), z.number()).optional(),
|
|
750
|
+
/** Row heights in points by 0-based row, as the spreadsheet stores them. */
|
|
751
|
+
rowHeights: z.record(z.string(), z.number()).optional(),
|
|
752
|
+
/** The width of a column the file does not size, in characters. */
|
|
753
|
+
defaultColumnWidth: z.number().optional(),
|
|
754
|
+
/** The height of a row the file does not size, in points. */
|
|
755
|
+
defaultRowHeight: z.number().optional()
|
|
712
756
|
});
|
|
713
757
|
const csvFormatViewSchema = z.object({
|
|
714
758
|
encoding: z.string(),
|
|
@@ -860,14 +904,174 @@ function cookieToken(header) {
|
|
|
860
904
|
return undefined;
|
|
861
905
|
}
|
|
862
906
|
|
|
907
|
+
const TITLE = 'Choose the recipe folder';
|
|
908
|
+
/** PowerShell's own Windows Forms dialog: the only folder picker every Windows install has. UTF-8 out, so a path with accents survives the pipe. */
|
|
909
|
+
const WINDOWS_SCRIPT = ['[Console]::OutputEncoding = [System.Text.Encoding]::UTF8', 'Add-Type -AssemblyName System.Windows.Forms', '$dialog = New-Object System.Windows.Forms.FolderBrowserDialog', `$dialog.Description = '${TITLE}'`, '$dialog.ShowNewFolderButton = $true', "if ($dialog.ShowDialog() -eq 'OK') { [Console]::Out.Write($dialog.SelectedPath) }"].join('; ');
|
|
910
|
+
/**
|
|
911
|
+
* The programs that can open a folder dialog on a platform, in the order to
|
|
912
|
+
* try them: the first one installed is used. Windows and macOS have one each
|
|
913
|
+
* in every install; Linux has whichever of `zenity` (GNOME and most others)
|
|
914
|
+
* and `kdialog` (KDE) the desktop ships.
|
|
915
|
+
*
|
|
916
|
+
* @param platform - `process.platform`.
|
|
917
|
+
* @returns The candidates; empty for a platform with no known dialog.
|
|
918
|
+
*/
|
|
919
|
+
function folderDialogCommands(platform) {
|
|
920
|
+
switch (platform) {
|
|
921
|
+
case 'win32':
|
|
922
|
+
{
|
|
923
|
+
return [{
|
|
924
|
+
file: 'powershell.exe',
|
|
925
|
+
args: ['-NoProfile', '-STA', '-NonInteractive', '-Command', WINDOWS_SCRIPT]
|
|
926
|
+
}];
|
|
927
|
+
}
|
|
928
|
+
case 'darwin':
|
|
929
|
+
{
|
|
930
|
+
return [{
|
|
931
|
+
file: 'osascript',
|
|
932
|
+
args: ['-e', `POSIX path of (choose folder with prompt "${TITLE}")`]
|
|
933
|
+
}];
|
|
934
|
+
}
|
|
935
|
+
case 'linux':
|
|
936
|
+
case 'freebsd':
|
|
937
|
+
case 'openbsd':
|
|
938
|
+
{
|
|
939
|
+
return [{
|
|
940
|
+
file: 'zenity',
|
|
941
|
+
args: ['--file-selection', '--directory', `--title=${TITLE}`]
|
|
942
|
+
}, {
|
|
943
|
+
file: 'kdialog',
|
|
944
|
+
args: ['--getexistingdirectory', '.', '--title', TITLE]
|
|
945
|
+
}];
|
|
946
|
+
}
|
|
947
|
+
default:
|
|
948
|
+
{
|
|
949
|
+
return [];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* The folder a dialog printed: its output without the line break and the
|
|
955
|
+
* trailing separator (`osascript` ends a folder with `/`), a root kept as it
|
|
956
|
+
* is. Nothing printed means the person cancelled.
|
|
957
|
+
*
|
|
958
|
+
* @param output - What the dialog program wrote to its standard output.
|
|
959
|
+
* @returns The folder path, or `undefined` for a cancelled dialog.
|
|
960
|
+
*/
|
|
961
|
+
function folderFromDialogOutput(output) {
|
|
962
|
+
const line = output.trim();
|
|
963
|
+
if (line === '') return undefined;
|
|
964
|
+
const withoutSeparator = line.replace(/[/\\]+$/u, '');
|
|
965
|
+
return withoutSeparator === '' || /^[A-Za-z]:$/u.test(withoutSeparator) ? line : withoutSeparator;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/** Runs the program with Node's own `execFile`: no shell, so a path or title is never parsed as a command. */
|
|
969
|
+
const runDialogProgram = async command => await new Promise(resolve => {
|
|
970
|
+
execFile(command.file, command.args, {
|
|
971
|
+
windowsHide: false,
|
|
972
|
+
encoding: 'utf8'
|
|
973
|
+
}, (error, stdout) => {
|
|
974
|
+
if (error === null) {
|
|
975
|
+
resolve({
|
|
976
|
+
output: stdout
|
|
977
|
+
});
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
if ('code' in error && error.code === 'ENOENT') {
|
|
981
|
+
resolve({
|
|
982
|
+
missing: true
|
|
983
|
+
});
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
// `zenity` and `osascript` exit non-zero when the dialog is closed without a choice.
|
|
987
|
+
resolve(stdout.trim() === '' ? {
|
|
988
|
+
cancelled: true
|
|
989
|
+
} : {
|
|
990
|
+
output: stdout
|
|
991
|
+
});
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
/**
|
|
995
|
+
* Opens the operating system's own folder dialog on the machine the server
|
|
996
|
+
* runs on, which is where the recipe folder is: a browser tab cannot do it,
|
|
997
|
+
* the server can. Waits until the person picks a folder or closes the dialog.
|
|
998
|
+
*
|
|
999
|
+
* @param platform - `process.platform`; passed in so a test names the platform it means.
|
|
1000
|
+
* @param run - How a dialog program is run.
|
|
1001
|
+
* @returns The folder picked, or `undefined` when the dialog was closed without a choice.
|
|
1002
|
+
* @throws Error when the platform has no dialog program installed (a server with no display, a container).
|
|
1003
|
+
*/
|
|
1004
|
+
async function chooseFolderWithDialog(platform = process.platform, run = runDialogProgram) {
|
|
1005
|
+
const candidates = folderDialogCommands(platform);
|
|
1006
|
+
for (const command of candidates) {
|
|
1007
|
+
const result = await run(command);
|
|
1008
|
+
if ('missing' in result) continue;
|
|
1009
|
+
if ('cancelled' in result) return undefined;
|
|
1010
|
+
return folderFromDialogOutput(result.output);
|
|
1011
|
+
}
|
|
1012
|
+
const tried = candidates.map(command => command.file).join(' or ');
|
|
1013
|
+
throw new Error(`there is no folder dialog on this machine${tried === '' ? '' : ` (${tried} is not installed)`}: type the folder instead`);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/** Asks the dialog, and clears `openDialog` once it has answered or failed, so the next request opens a new one. */
|
|
1017
|
+
async function askOnce(state, ask) {
|
|
1018
|
+
try {
|
|
1019
|
+
return await ask();
|
|
1020
|
+
} finally {
|
|
1021
|
+
state.openDialog = undefined;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Handles `choose-folder`: opens the folder dialog of the machine the server
|
|
1026
|
+
* runs on and answers the folder picked. Only answers: the UI follows with
|
|
1027
|
+
* `open-workspace`, the same as when the folder is typed. A dialog still
|
|
1028
|
+
* open is not opened a second time; the second request waits for the first.
|
|
1029
|
+
*
|
|
1030
|
+
* @param state - The server state holding the dialog to use.
|
|
1031
|
+
* @returns The folder, or none when the dialog was closed.
|
|
1032
|
+
*/
|
|
1033
|
+
async function handleChooseFolder(state) {
|
|
1034
|
+
if (state.chooseFolder === undefined) throw new Error('this server has no folder dialog: type the folder instead');
|
|
1035
|
+
state.openDialog ??= askOnce(state, state.chooseFolder);
|
|
1036
|
+
const folder = await state.openDialog;
|
|
1037
|
+
return folder === undefined ? {} : {
|
|
1038
|
+
folder
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
|
|
863
1042
|
const execFileAsync = promisify(execFile);
|
|
864
1043
|
/** `playwright`'s own `exports` map doesn't whitelist a `./cli` subpath, so its CLI is resolved off `playwright/package.json`'s real location — the same technique `@opencraw/captcha-tesseract`'s `bundledLangPath()` uses for a bundled data path. */
|
|
865
1044
|
function playwrightCliPath() {
|
|
866
1045
|
const require = createRequire(import.meta.url);
|
|
867
1046
|
return join(dirname(require.resolve('playwright/package.json')), 'cli.js');
|
|
868
1047
|
}
|
|
1048
|
+
/**
|
|
1049
|
+
* How the install is run: the current executable as a Node, on Playwright's own CLI. Inside the desktop app
|
|
1050
|
+
* the executable is Electron, which runs as plain Node only with `ELECTRON_RUN_AS_NODE` (otherwise it would
|
|
1051
|
+
* start a second copy of the app); under Node the variable does nothing.
|
|
1052
|
+
*
|
|
1053
|
+
* @param cliPath - Playwright's `cli.js`.
|
|
1054
|
+
* @returns What to hand to `execFile`.
|
|
1055
|
+
*/
|
|
1056
|
+
function installInvocation(cliPath) {
|
|
1057
|
+
return {
|
|
1058
|
+
file: process.execPath,
|
|
1059
|
+
args: [cliPath, 'install', 'chromium'],
|
|
1060
|
+
env: {
|
|
1061
|
+
...process.env,
|
|
1062
|
+
ELECTRON_RUN_AS_NODE: '1'
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
869
1066
|
async function runPlaywrightInstall() {
|
|
870
|
-
|
|
1067
|
+
const {
|
|
1068
|
+
file,
|
|
1069
|
+
args,
|
|
1070
|
+
env
|
|
1071
|
+
} = installInvocation(playwrightCliPath());
|
|
1072
|
+
await execFileAsync(file, args, {
|
|
1073
|
+
env
|
|
1074
|
+
});
|
|
871
1075
|
}
|
|
872
1076
|
let installing;
|
|
873
1077
|
/**
|
|
@@ -1364,6 +1568,22 @@ function sheetView(sheet) {
|
|
|
1364
1568
|
ref: reference,
|
|
1365
1569
|
...range
|
|
1366
1570
|
}];
|
|
1571
|
+
}),
|
|
1572
|
+
...(sheet.columnWidths !== undefined && {
|
|
1573
|
+
columnWidths: {
|
|
1574
|
+
...sheet.columnWidths
|
|
1575
|
+
}
|
|
1576
|
+
}),
|
|
1577
|
+
...(sheet.rowHeights !== undefined && {
|
|
1578
|
+
rowHeights: {
|
|
1579
|
+
...sheet.rowHeights
|
|
1580
|
+
}
|
|
1581
|
+
}),
|
|
1582
|
+
...(sheet.defaultColumnWidth !== undefined && {
|
|
1583
|
+
defaultColumnWidth: sheet.defaultColumnWidth
|
|
1584
|
+
}),
|
|
1585
|
+
...(sheet.defaultRowHeight !== undefined && {
|
|
1586
|
+
defaultRowHeight: sheet.defaultRowHeight
|
|
1367
1587
|
})
|
|
1368
1588
|
};
|
|
1369
1589
|
}
|
|
@@ -3026,6 +3246,102 @@ function isAlreadyThere(error) {
|
|
|
3026
3246
|
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'EEXIST';
|
|
3027
3247
|
}
|
|
3028
3248
|
|
|
3249
|
+
/** A recipe is a small JSON file; anything larger is a document that happens to be JSON. */
|
|
3250
|
+
const MAX_RECIPE_BYTES = 5 * 1024 * 1024;
|
|
3251
|
+
/**
|
|
3252
|
+
* Says what a path is, for a link or an IDE menu entry that only knows a
|
|
3253
|
+
* path: a folder opens as the workspace; a `.json` file whose `kind` is
|
|
3254
|
+
* `input` or `output` is a recipe, opened through its own folder; any other
|
|
3255
|
+
* file is a document to start a recipe from.
|
|
3256
|
+
*
|
|
3257
|
+
* A document is read in place when it is already inside the workspace folder
|
|
3258
|
+
* (`workspace`, else the file's own folder), and copied into the folder
|
|
3259
|
+
* otherwise, with the same no-overwrite numbering `import-document` uses.
|
|
3260
|
+
*
|
|
3261
|
+
* @param path - An absolute path to a folder or a file.
|
|
3262
|
+
* @param workspace - The folder a document should belong to, when the caller has one (an IDE's workspace folder).
|
|
3263
|
+
* @returns What it is and where to open it.
|
|
3264
|
+
* @throws Error when the path is relative or does not exist.
|
|
3265
|
+
*/
|
|
3266
|
+
async function openPath(path, workspace) {
|
|
3267
|
+
if (!isAbsolute(path)) throw new Error(`"${path}" is not an absolute path`);
|
|
3268
|
+
const info = await statOrNothing(path);
|
|
3269
|
+
if (info === undefined) throw new Error(`"${path}" does not exist`);
|
|
3270
|
+
if (info.isDirectory()) return {
|
|
3271
|
+
kind: 'folder',
|
|
3272
|
+
folder: path
|
|
3273
|
+
};
|
|
3274
|
+
const recipe = info.size <= MAX_RECIPE_BYTES ? await recipeAt(path) : undefined;
|
|
3275
|
+
if (recipe !== undefined) return {
|
|
3276
|
+
kind: 'recipe',
|
|
3277
|
+
folder: dirname(path),
|
|
3278
|
+
recipeId: recipe.id
|
|
3279
|
+
};
|
|
3280
|
+
const folder = workspace ?? dirname(path);
|
|
3281
|
+
if (isInside(folder, path)) return {
|
|
3282
|
+
kind: 'document',
|
|
3283
|
+
folder,
|
|
3284
|
+
path,
|
|
3285
|
+
url: pathToFileURL(path).href
|
|
3286
|
+
};
|
|
3287
|
+
const copy = await importDocument(folder, basename(path), new Uint8Array(await readFile(path)));
|
|
3288
|
+
return {
|
|
3289
|
+
kind: 'document',
|
|
3290
|
+
folder,
|
|
3291
|
+
path: copy.path,
|
|
3292
|
+
url: copy.url
|
|
3293
|
+
};
|
|
3294
|
+
}
|
|
3295
|
+
/** The recipe a `.json` file holds, with the id of the input recipe to select (an output recipe selects the first input naming it); `undefined` when the file is not a recipe. */
|
|
3296
|
+
async function recipeAt(path) {
|
|
3297
|
+
if (extname(path).toLowerCase() !== '.json') return undefined;
|
|
3298
|
+
let content;
|
|
3299
|
+
try {
|
|
3300
|
+
content = JSON.parse(await readFile(path, 'utf8'));
|
|
3301
|
+
} catch {
|
|
3302
|
+
return undefined;
|
|
3303
|
+
}
|
|
3304
|
+
const {
|
|
3305
|
+
kind,
|
|
3306
|
+
id
|
|
3307
|
+
} = typeof content === 'object' && content !== null ? content : {};
|
|
3308
|
+
if (kind === 'input') return {
|
|
3309
|
+
id: typeof id === 'string' ? id : undefined
|
|
3310
|
+
};
|
|
3311
|
+
if (kind !== 'output') return undefined;
|
|
3312
|
+
const listing = await openWorkspace(dirname(path));
|
|
3313
|
+
for (const candidate of listing.recipes) {
|
|
3314
|
+
const named = candidate.kind === 'input' ? inputNaming(candidate.text, id) : undefined;
|
|
3315
|
+
if (named !== undefined) return {
|
|
3316
|
+
id: named
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
3319
|
+
return {};
|
|
3320
|
+
}
|
|
3321
|
+
/** The id of the input recipe whose text names `outputId` as its output, read from the JSON itself so an input that does not validate still counts. */
|
|
3322
|
+
function inputNaming(text, outputId) {
|
|
3323
|
+
try {
|
|
3324
|
+
const {
|
|
3325
|
+
id,
|
|
3326
|
+
output
|
|
3327
|
+
} = JSON.parse(text);
|
|
3328
|
+
return output === outputId && typeof id === 'string' ? id : undefined;
|
|
3329
|
+
} catch {
|
|
3330
|
+
return undefined;
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
async function statOrNothing(path) {
|
|
3334
|
+
try {
|
|
3335
|
+
return await stat(path);
|
|
3336
|
+
} catch {
|
|
3337
|
+
return undefined;
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
function isInside(folder, path) {
|
|
3341
|
+
const from = relative(resolve(folder), resolve(path));
|
|
3342
|
+
return from !== '' && !from.startsWith('..') && !isAbsolute(from);
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3029
3345
|
/**
|
|
3030
3346
|
* Handles `import-document` (issue #120): decodes the base64 bytes and copies
|
|
3031
3347
|
* the file into the folder (see `recipe-workspace/import-document.use-case.ts`
|
|
@@ -3860,6 +4176,18 @@ function handleInspectPage(state, command) {
|
|
|
3860
4176
|
};
|
|
3861
4177
|
}
|
|
3862
4178
|
|
|
4179
|
+
/**
|
|
4180
|
+
* Handles `open-path`: says what the path is (folder, recipe or document) and
|
|
4181
|
+
* where to open it. Opens nothing itself: the UI follows with `open-workspace`
|
|
4182
|
+
* on the answer's folder, the same as when the folder is typed.
|
|
4183
|
+
*
|
|
4184
|
+
* @param command - The path, and the workspace it should belong to if the caller has one.
|
|
4185
|
+
* @returns What the path is.
|
|
4186
|
+
*/
|
|
4187
|
+
async function handleOpenPath(command) {
|
|
4188
|
+
return await openPath(command.path, command.workspace);
|
|
4189
|
+
}
|
|
4190
|
+
|
|
3863
4191
|
/**
|
|
3864
4192
|
* Which of what Studio was started with calls outside the process, for the bar that warns the person and
|
|
3865
4193
|
* for the stubs a sample run may use.
|
|
@@ -5163,6 +5491,7 @@ async function startStudioServer(options = {}) {
|
|
|
5163
5491
|
if (options.initialFolder !== undefined) state.folder = options.initialFolder;
|
|
5164
5492
|
state.browser = options.browser;
|
|
5165
5493
|
state.plugins = options.plugins;
|
|
5494
|
+
state.chooseFolder = options.chooseFolder ?? (() => chooseFolderWithDialog());
|
|
5166
5495
|
if (options.recorderProfileDir !== undefined) state.recorderProfileDir = options.recorderProfileDir;
|
|
5167
5496
|
const server = createServer((request, response) => {
|
|
5168
5497
|
void handleRequest(request, response, token, state, uiRoot);
|
|
@@ -5177,9 +5506,15 @@ async function startStudioServer(options = {}) {
|
|
|
5177
5506
|
const address = server.address();
|
|
5178
5507
|
const port = typeof address === 'object' && address !== null ? address.port : 0;
|
|
5179
5508
|
const folderParam = options.initialFolder === undefined ? '' : `&folder=${encodeURIComponent(options.initialFolder)}`;
|
|
5509
|
+
const base = `http://127.0.0.1:${port}/?token=${token}`;
|
|
5180
5510
|
return {
|
|
5181
|
-
url:
|
|
5511
|
+
url: `${base}${folderParam}`,
|
|
5182
5512
|
token,
|
|
5513
|
+
link: target => {
|
|
5514
|
+
const workspace = target?.workspace ?? options.initialFolder;
|
|
5515
|
+
const open = target?.open === undefined ? '' : `&open=${encodeURIComponent(target.open)}`;
|
|
5516
|
+
return `${base}${workspace === undefined ? '' : `&folder=${encodeURIComponent(workspace)}`}${open}`;
|
|
5517
|
+
},
|
|
5183
5518
|
close: () => stop(server, state)
|
|
5184
5519
|
};
|
|
5185
5520
|
}
|
|
@@ -5275,6 +5610,14 @@ function dispatch(command, state) {
|
|
|
5275
5610
|
{
|
|
5276
5611
|
return handleOpenWorkspace(state, command);
|
|
5277
5612
|
}
|
|
5613
|
+
case 'choose-folder':
|
|
5614
|
+
{
|
|
5615
|
+
return handleChooseFolder(state);
|
|
5616
|
+
}
|
|
5617
|
+
case 'open-path':
|
|
5618
|
+
{
|
|
5619
|
+
return handleOpenPath(command);
|
|
5620
|
+
}
|
|
5278
5621
|
case 'import-document':
|
|
5279
5622
|
{
|
|
5280
5623
|
return handleImportDocument(command);
|
|
@@ -5416,7 +5759,11 @@ async function main(argv, options = {}) {
|
|
|
5416
5759
|
initialFolder: folder,
|
|
5417
5760
|
plugins: options.plugins
|
|
5418
5761
|
});
|
|
5419
|
-
|
|
5762
|
+
const address = options.open === undefined ? server.url : server.link({
|
|
5763
|
+
open: resolve(options.open),
|
|
5764
|
+
workspace: folder
|
|
5765
|
+
});
|
|
5766
|
+
process.stdout.write(`OpenCraw Studio: ${address}\n`);
|
|
5420
5767
|
process.stdout.write(`Workspace: ${folder}\n`);
|
|
5421
5768
|
if (options.plugins !== undefined) process.stdout.write(`Hooks: ${options.plugins.source} (runs as your code)\n`);
|
|
5422
5769
|
const shutdown = () => {
|
|
@@ -5426,5 +5773,5 @@ async function main(argv, options = {}) {
|
|
|
5426
5773
|
process.on('SIGTERM', shutdown);
|
|
5427
5774
|
}
|
|
5428
5775
|
|
|
5429
|
-
export { deckChartSeriesViewSchema, deckChartViewSchema, deckDocumentViewSchema, deckPreviewCommandSchema, deckPreviewOptionsSchema, deckShapeViewSchema, deckSlideViewSchema, deckTablePreviewMatchSchema, deckTablePreviewViewSchema, deckViewCommandSchema, documentTreeCommandSchema, documentTreeNodeViewSchema, documentTreeViewSchema, domTreeNodeViewSchema, explainWhyCommandSchema, fetchStartPage, fetchStartPageCommandSchema, fieldPickSchema, fieldTraceSchema, gridCellViewSchema, gridMergeViewSchema, gridPreviewCommandSchema, gridPreviewOptionsSchema, gridSheetViewSchema, gridTablePreviewMatchSchema, gridTablePreviewViewSchema, gridViewCommandSchema, importDocument, importDocumentCommandSchema, importDocumentViewSchema, inferSelectorCommandSchema, inferSelectorViewSchema, inspectPageCommandSchema, inspectViewSchema, loadRecipePair, loadedHooksSchema, main, missingWhyTargetSchema, observedResponseSchema, openWorkspace, openWorkspaceCommandSchema, outlineBracketSchema, outlineCardSchema, outlineNodeSchema, outlineViewSchema, pageDataFindingSchema, pdfCellViewSchema, pdfDocumentViewSchema, pdfPageViewSchema, pdfRowViewSchema, pdfViewCommandSchema, recipeIssueSchema, recipeListingSchema, recordEventSchema, recordRejectedEventSchema, recordingCardEventSchema, recordingNoteEventSchema, recordingStoppedEventSchema, regionPreviewCommandSchema, regionPreviewMatchSchema, regionPreviewViewSchema, rejectedWhyTargetSchema, responsesSeenCommandSchema, responsesSeenViewSchema, runFinishedEventSchema, runSample, runSampleCommandSchema, sampleBudgetSchema, sampleRunRecordSchema, sampleRunViewSchema, saveOutlineCommandSchema, saveRecipe, saveRecipeCommandSchema, sentencePartSchema, snapshotViewSchema, startPageViewSchema, startRecordingCommandSchema, startStudioServer, stopRecordingCommandSchema, stopRunCommandSchema, stoppedBySchema, studioCommandSchema, studioEventSchema, tablePreviewBandSchema, tablePreviewCommandSchema, tablePreviewMatchSchema, tablePreviewOptionsSchema, tablePreviewTableSchema, tablePreviewViewSchema, takeSnapshotCommandSchema, traceLineEventSchema, verifySelectorCommandSchema, verifySelectorViewSchema, whyTargetSchema, whyViewSchema, workbookDocumentViewSchema, workspaceChangedEventSchema, workspaceViewSchema };
|
|
5776
|
+
export { chooseFolderCommandSchema, chooseFolderViewSchema, deckChartSeriesViewSchema, deckChartViewSchema, deckDocumentViewSchema, deckPreviewCommandSchema, deckPreviewOptionsSchema, deckShapeViewSchema, deckSlideViewSchema, deckTablePreviewMatchSchema, deckTablePreviewViewSchema, deckViewCommandSchema, documentTreeCommandSchema, documentTreeNodeViewSchema, documentTreeViewSchema, domTreeNodeViewSchema, explainWhyCommandSchema, fetchStartPage, fetchStartPageCommandSchema, fieldPickSchema, fieldTraceSchema, gridCellViewSchema, gridMergeViewSchema, gridPreviewCommandSchema, gridPreviewOptionsSchema, gridSheetViewSchema, gridTablePreviewMatchSchema, gridTablePreviewViewSchema, gridViewCommandSchema, importDocument, importDocumentCommandSchema, importDocumentViewSchema, inferSelectorCommandSchema, inferSelectorViewSchema, inspectPageCommandSchema, inspectViewSchema, loadRecipePair, loadedHooksSchema, main, missingWhyTargetSchema, observedResponseSchema, openPathCommandSchema, openPathViewSchema, openWorkspace, openWorkspaceCommandSchema, outlineBracketSchema, outlineCardSchema, outlineNodeSchema, outlineViewSchema, pageDataFindingSchema, pdfCellViewSchema, pdfDocumentViewSchema, pdfPageViewSchema, pdfRowViewSchema, pdfViewCommandSchema, recipeIssueSchema, recipeListingSchema, recordEventSchema, recordRejectedEventSchema, recordingCardEventSchema, recordingNoteEventSchema, recordingStoppedEventSchema, regionPreviewCommandSchema, regionPreviewMatchSchema, regionPreviewViewSchema, rejectedWhyTargetSchema, responsesSeenCommandSchema, responsesSeenViewSchema, runFinishedEventSchema, runSample, runSampleCommandSchema, sampleBudgetSchema, sampleRunRecordSchema, sampleRunViewSchema, saveOutlineCommandSchema, saveRecipe, saveRecipeCommandSchema, sentencePartSchema, snapshotViewSchema, startPageViewSchema, startRecordingCommandSchema, startStudioServer, stopRecordingCommandSchema, stopRunCommandSchema, stoppedBySchema, studioCommandSchema, studioEventSchema, tablePreviewBandSchema, tablePreviewCommandSchema, tablePreviewMatchSchema, tablePreviewOptionsSchema, tablePreviewTableSchema, tablePreviewViewSchema, takeSnapshotCommandSchema, traceLineEventSchema, verifySelectorCommandSchema, verifySelectorViewSchema, whyTargetSchema, whyViewSchema, workbookDocumentViewSchema, workspaceChangedEventSchema, workspaceViewSchema };
|
|
5430
5777
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/main.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { TrustedPlugins } from './trusted-plugins';
|
|
|
3
3
|
export interface StudioMainOptions {
|
|
4
4
|
/** Hooks and plugins loaded from a file the person named at launch (`opencraw studio --hooks <file>`, issue #150). `main` never loads code itself. */
|
|
5
5
|
plugins?: TrustedPlugins;
|
|
6
|
+
/** A folder, recipe file or document the printed link opens straight away (`opencraw studio --open <path>`, issue #235); resolved against the current directory. */
|
|
7
|
+
open?: string;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* Runs `opencraw-studio`: starts the server, opens `folder` (if given) as
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { openWorkspace } from './open-workspace.use-case';
|
|
2
2
|
export { saveRecipe } from './save-recipe.use-case';
|
|
3
|
+
export { openPath } from './open-path.use-case';
|
|
3
4
|
export { importDocument } from './import-document.use-case';
|
|
4
5
|
export type { ImportedDocument } from './import-document.use-case';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OpenPathView } from '../studio-api';
|
|
2
|
+
/**
|
|
3
|
+
* Says what a path is, for a link or an IDE menu entry that only knows a
|
|
4
|
+
* path: a folder opens as the workspace; a `.json` file whose `kind` is
|
|
5
|
+
* `input` or `output` is a recipe, opened through its own folder; any other
|
|
6
|
+
* file is a document to start a recipe from.
|
|
7
|
+
*
|
|
8
|
+
* A document is read in place when it is already inside the workspace folder
|
|
9
|
+
* (`workspace`, else the file's own folder), and copied into the folder
|
|
10
|
+
* otherwise, with the same no-overwrite numbering `import-document` uses.
|
|
11
|
+
*
|
|
12
|
+
* @param path - An absolute path to a folder or a file.
|
|
13
|
+
* @param workspace - The folder a document should belong to, when the caller has one (an IDE's workspace folder).
|
|
14
|
+
* @returns What it is and where to open it.
|
|
15
|
+
* @throws Error when the path is relative or does not exist.
|
|
16
|
+
*/
|
|
17
|
+
export declare function openPath(path: string, workspace?: string): Promise<OpenPathView>;
|
|
18
|
+
//# sourceMappingURL=open-path.use-case.d.ts.map
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the install is run: the current executable as a Node, on Playwright's own CLI. Inside the desktop app
|
|
3
|
+
* the executable is Electron, which runs as plain Node only with `ELECTRON_RUN_AS_NODE` (otherwise it would
|
|
4
|
+
* start a second copy of the app); under Node the variable does nothing.
|
|
5
|
+
*
|
|
6
|
+
* @param cliPath - Playwright's `cli.js`.
|
|
7
|
+
* @returns What to hand to `execFile`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function installInvocation(cliPath: string): {
|
|
10
|
+
file: string;
|
|
11
|
+
args: string[];
|
|
12
|
+
env: NodeJS.ProcessEnv;
|
|
13
|
+
};
|
|
1
14
|
export declare function installChromiumOnce(run?: () => Promise<void>): Promise<void>;
|
|
2
15
|
//# sourceMappingURL=install-chromium.use-case.d.ts.map
|
|
@@ -24,6 +24,14 @@ export interface GridSheetView {
|
|
|
24
24
|
columnCount: number;
|
|
25
25
|
rows: GridCellView[][];
|
|
26
26
|
merges: GridMergeView[];
|
|
27
|
+
/** Column widths in characters by 0-based column, as the spreadsheet stores them; absent keys are columns the file does not size. */
|
|
28
|
+
columnWidths?: Record<string, number>;
|
|
29
|
+
/** Row heights in points by 0-based row, as the spreadsheet stores them. */
|
|
30
|
+
rowHeights?: Record<string, number>;
|
|
31
|
+
/** The width of a column the file does not size, in characters. */
|
|
32
|
+
defaultColumnWidth?: number;
|
|
33
|
+
/** The height of a row the file does not size, in points. */
|
|
34
|
+
defaultRowHeight?: number;
|
|
27
35
|
}
|
|
28
36
|
/** What `grid-view` answers with (studio plan §3.4, issue #94's 5c): every sheet's cells, typed, with hidden sheets/rows marked and merged ranges resolved — the CSV/workbook grid's own view of the document, structurally the same idea as `pdf-view.mapper.ts`'s `PdfDocumentView`. */
|
|
29
37
|
export interface WorkbookDocumentView {
|