Skip to content

Commit 9d87870

Browse files
committed
import/export
1 parent 6cbac48 commit 9d87870

File tree

90 files changed

+483
-325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+483
-325
lines changed

lasso/src/components/CodeSnippet/CodeSnippetCard.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,15 @@ export const CodeSnippetCard: React.FC<CodeSnippetProps> = ({ snippet }) => (
127127
<Typography variant="subtitle2" sx={{ mb: 0.5 }}>
128128
Source:
129129
</Typography>
130+
<Box sx={{maxHeight: 350,
131+
overflow: "auto"
132+
}}>
130133
<CodeBlock
131134
language="java">
132135
{snippet.content}
133136
</CodeBlock>
137+
</Box>
138+
134139
{/* <Box
135140
component="pre"
136141
sx={{

lasso/src/components/HubFeatures/HubFeatures.tsx

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,37 @@ export class TDSExamples {
1010
decode(java.lang.String)->byte[]
1111
}`,
1212
sheets: [{
13-
name: "testEncode",
14-
signature: "()",
15-
jsonl: `{"cells": {"A1": {}, "B1": "create", "C1": "Base64"}}
13+
name: "testEncode",
14+
signature: "()",
15+
body: `{"cells": {"A1": {}, "B1": "create", "C1": "Base64"}}
1616
{"cells": {"A2": "\\"SGVsbG8gV29ybGQh\\".getBytes()", "B2": "encode", "C2": "A1", "D2": "\\"Hello World!\\".getBytes()"}}`,
17-
invocations: []
17+
invocations: []
18+
}]
19+
},
20+
BASE64_PARAMETERIZED: {
21+
label: "Base64 (Parameterized Sheets)",
22+
lql: `Base64 {
23+
encode(byte[])->byte[]
24+
decode(java.lang.String)->byte[]
25+
}`,
26+
sheets: [{
27+
name: "testEncode",
28+
signature: "(p1=byte[])",
29+
body: `{"cells":{"A1":{},"B1":"create","C1":"Base64"}}\n{"cells":{"A2":"\\"SGVsbG8gV29ybGQh\\".getBytes()","B2":"encode","C2":"A1","D2":"?p1"}}`,
30+
invocations: [
31+
{
32+
id: 0,
33+
sequenceSheetName: "testEncode",
34+
signature: "",
35+
params: ["\"Hello World!\".getBytes()"]
36+
},
37+
38+
{
39+
id: 1,
40+
sequenceSheetName: "testEncode",
41+
signature: "",
42+
params: ["\"Hello World\".getBytes()"]
43+
}]
1844
}]
1945
},
2046
STACK: {
@@ -26,14 +52,14 @@ export class TDSExamples {
2652
size()->int
2753
}`,
2854
sheets: [{
29-
name: "testPush",
30-
signature: "()",
31-
jsonl: `{"cells":{"A1":{},"B1":"create","C1":"Stack"}}
55+
name: "testPush",
56+
signature: "()",
57+
body: `{"cells":{"A1":{},"B1":"create","C1":"Stack"}}
3258
{"cells":{"A2":{},"B2":"push","C2":"A1","D2":"\\"Hello World!\\""}}
3359
{"cells":{"A3":"D2","B3":"peek","C3":"A1"}}
3460
{"cells":{"A4":"D2","B4":"pop","C4":"A1"}}
3561
{"cells":{"A5":0,"B5":"size","C5":"A1"}}`,
36-
invocations: []
62+
invocations: []
3763
}]
3864
}
3965
}
@@ -443,12 +469,12 @@ study(name: 'Stack') {
443469
row '', 'push', 'A1', '"Hi"'
444470
row '', 'size', 'A1'
445471
},
446-
test(name: 'testPushParameterized(p1=java.lang.String)', p1: "Hello World!") {
472+
test(name: 'testPushParameterized(p1=java.lang.String)', p1: '"Hello World!"') {
447473
row '', 'create', 'Stack'
448474
row '', 'push', 'A1', '?p1'
449475
row '', 'size', 'A1'
450476
},
451-
test(name: 'testPushParameterized(p1=java.lang.String)', p1: "Bla blub!") // e.g., parameterized
477+
test(name: 'testPushParameterized(p1=java.lang.String)', p1: '"Bla blub!"') // e.g., parameterized
452478
]
453479
)
454480
}
@@ -502,12 +528,12 @@ study(name: 'Stack') {
502528
row '', 'push', 'A1', '"Hi"'
503529
row '', 'size', 'A1'
504530
},
505-
test(name: 'testPushParameterized(p1=java.lang.String)', p1: "Hello World!") {
531+
test(name: 'testPushParameterized(p1=java.lang.String)', p1: '"Hello World!"') {
506532
row '', 'create', 'Stack'
507533
row '', 'push', 'A1', '?p1'
508534
row '', 'size', 'A1'
509535
},
510-
test(name: 'testPushParameterized(p1=java.lang.String)', p1: "Bla blub!") // e.g., parameterized
536+
test(name: 'testPushParameterized(p1=java.lang.String)', p1: '"Bla blub!"') // e.g., parameterized
511537
]
512538
)
513539
}

lasso/src/components/SSN/SequenceSheetEditor.tsx

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import DownloadIcon from "@mui/icons-material/Download";
1111
import RemoveCircleOutlineIcon from "@mui/icons-material/RemoveCircleOutline";
1212
import AddIcon from "@mui/icons-material/Add";
1313
import RemoveIcon from "@mui/icons-material/Remove";
14-
import { sequenceSheetsToGroovyDSL } from "./ssnutilities";
1514

1615
const BASE_COLS = ["A", "B", "C", "D"];
1716
const OPERATION_NAMES = ["create", "push", "pop", "size"];
@@ -118,6 +117,17 @@ export interface SequenceSheetData {
118117
rows: any[];
119118
invocations: Invocation[];
120119
}
120+
export interface SequenceSheetDataModel {
121+
name: string;
122+
signature: string;
123+
body: string;
124+
invocations: Invocation[];
125+
}
126+
export interface SequenceSheetSetModel {
127+
sheets: SequenceSheetDataModel[];
128+
interfaceSpecification: string;
129+
}
130+
121131
interface SequenceSheetEditorProps {
122132
value: SequenceSheetData;
123133
onChange: (next: SequenceSheetData) => void;
@@ -181,7 +191,7 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
181191
handleChangeField("rows", nextRows);
182192
return newRow;
183193
};
184-
const handleExport = () => {
194+
const handleExportJSONL = () => {
185195
const jsonl = gridToJSONL(value.rows, value.columns);
186196

187197
// const sheet1 = {
@@ -201,17 +211,29 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
201211
a.click();
202212
a.remove();
203213
setSnackMsg("Exported as file.");
204-
};
205-
const handleImport = () => {
206-
const result = jsonlToRows(importText);
214+
};
215+
216+
const handleImport = (text: string) => {
217+
const model: SequenceSheetDataModel = JSON.parse(text);
218+
219+
const result = jsonlToRows(model.body);
207220
if ("error" in result) {
208221
setSnackMsg(result.error);
209222
} else {
210223
const importedRows = result.rows.map((row, idx) => ({
211224
...row,
212225
id: idx,
213226
}));
214-
onChange({ ...value, columns: result.cols, rows: importedRows });
227+
228+
const newValue: SequenceSheetData = {
229+
name: model.name,
230+
signature: model.signature,
231+
columns: result.cols,
232+
rows: importedRows,
233+
invocations: model.invocations
234+
};
235+
236+
onChange(newValue);
215237
setSnackMsg("Imported!");
216238
}
217239
};
@@ -248,12 +270,12 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
248270
};
249271

250272
// --- Invocations Logic ---
251-
const handleAddInvocation = () => {
273+
const handleAddInvocation = (sequenceSheetName: string) => {
252274
handleChangeField("invocations", [
253275
...value.invocations,
254276
{
255277
id: nextInvId,
256-
sequenceSheetName: "",
278+
sequenceSheetName: sequenceSheetName,
257279
signature: "",
258280
params: [""],
259281
},
@@ -287,9 +309,9 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
287309
value.invocations.map((inv) =>
288310
inv.id === invId
289311
? {
290-
...inv,
291-
params: inv.params.map((v, idx) => (idx === paramIdx ? paramVal : v)),
292-
}
312+
...inv,
313+
params: inv.params.map((v, idx) => (idx === paramIdx ? paramVal : v)),
314+
}
293315
: inv
294316
)
295317
);
@@ -414,7 +436,7 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
414436
<Button
415437
variant="outlined"
416438
startIcon={<DownloadIcon />}
417-
onClick={handleExport}
439+
onClick={handleExportJSONL}
418440
>
419441
Export JSONL
420442
</Button>
@@ -482,7 +504,7 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
482504
<Typography variant="h6" sx={{ mt: 6 }}>Invocations of Sequence Sheets</Typography>
483505
<Button
484506
startIcon={<AddIcon />}
485-
onClick={handleAddInvocation}
507+
onClick={(e) => handleAddInvocation(value.name)}
486508
sx={{ mt: 1, mb: 2 }}
487509
variant="contained"
488510
>
@@ -501,6 +523,7 @@ export const SequenceSheetEditor: React.FC<SequenceSheetEditorProps> = ({
501523
<TextField
502524
label="Sequence Sheet Name"
503525
value={inv.sequenceSheetName}
526+
disabled={true}
504527
onChange={e =>
505528
handleInvocationFieldChange(inv.id, "sequenceSheetName", e.target.value)
506529
}

lasso/src/components/SSN/ssnutilities.tsx

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Invocation } from "./SequenceSheetEditor";
2+
13
type SequenceSheetJsonLRow = {
24
cells: Record<string, any>
35
};
@@ -60,18 +62,57 @@ function sequenceSheetRowsJsonlToGroovyRows(jsonl: string, columns?: string[]):
6062
});
6163
}
6264

65+
export function extractParamNames(input: string): string[] {
66+
// Remove leading/trailing whitespace and any surrounding parentheses
67+
const cleaned = input.trim().replace(/^\(|\)$/g, '');
68+
69+
// If the string is empty after cleaning, return []
70+
if (!cleaned) return [];
71+
72+
// Split on commas to get individual key-value pairs
73+
const pairs = cleaned.split(',');
74+
75+
// Extract key names
76+
const keys = pairs.map(pair => {
77+
const match = /^\s*([^=]+)\s*=/.exec(pair);
78+
return match ? match[1].trim() : null;
79+
}).filter((key): key is string => !!key); // Filters out any nulls
80+
81+
return keys;
82+
}
83+
6384
/**
6485
* Converts a list of sequence sheets in JSONL to Groovy DSL.
6586
* @param sheets Array of { name: string, jsonl: string, columns: string[] }
6687
* @returns String of Groovy DSL representing all sheets.
6788
*/
6889
export function sequenceSheetsToGroovyDSL(
69-
sheets: { name: string; signature: string; jsonl: string; columns?: string[] }[]
90+
sheets: { name: string; signature: string; jsonl: string; invocations: Invocation[]; columns?: string[] }[]
7091
): string {
71-
const sheetBlocks = sheets.map(sheet => {
92+
const sheetBlocks = sheets.flatMap(sheet => {
93+
const paramNames = extractParamNames(sheet.signature);
7294
const title = sheet.name.replace(/'/g, "\\'") + sheet.signature; // Escape any single quote in name
7395
const bodyRows = sequenceSheetRowsJsonlToGroovyRows(sheet.jsonl, sheet.columns);
74-
return ` test(name: '${title}') {\n ${bodyRows.join('\n ')}\n }`;
96+
97+
console.log(paramNames)
98+
99+
if(sheet.invocations.length > 0) {
100+
// array
101+
return sheet.invocations.map((inv, index) => {
102+
const parameters = inv.params.map((p, pIndex) => `${paramNames[pIndex]}:'${p}'`).join(', ');
103+
104+
if(index == 0) {
105+
// declare entire sheet
106+
return ` test(name: '${title}', ${parameters}) {\n ${bodyRows.join('\n ')}\n }`;
107+
} else {
108+
// just invocation
109+
return ` test(name: '${title}', ${parameters})`;
110+
}
111+
});
112+
} else {
113+
// array
114+
return [` test(name: '${title}') {\n ${bodyRows.join('\n ')}\n }`];
115+
}
75116
});
76117
// Output as a Groovy list
77118
return '[\n' + sheetBlocks.join(',\n') + '\n]';

lasso/src/pages/generation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ LASSO's Sequence Sheet Notation (SSN) allows for a unique form of code generatio
1212
### Examples
1313

1414
* [**Base64 encoding**](lasso/ssn?recommendation=gen&example=BASE64)
15+
* [**Base64 encoding (Parameterized Tests)**](lasso/ssn?recommendation=gen&example=BASE64_PARAMETERIZED)
1516
* [**Stack**](lasso/ssn?recommendation=gen&example=STACK)
1617

1718
## Research

lasso/src/pages/lasso/result.tsx

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -306,60 +306,6 @@ DRAFT
306306
{ab.codeUnits.length} Code Module(s)
307307
</Typography>
308308

309-
{/* <br />
310-
<Typography variant="body2" color="text.secondary">
311-
<Link
312-
href={`/web/lasso/search?query=*:*&filter=executionId:${executionId}&ds=lasso_quickstart`}
313-
target="_blank"
314-
rel="noopener"
315-
underline="hover"
316-
>
317-
Click here
318-
</Link> to view all <b>code modules</b>.
319-
</Typography>
320-
<br /> */}
321-
322-
323-
{/* <List dense={true}>
324-
325-
{ab.codeUnits.map((codeUnit) => (
326-
327-
<ListItem key={codeUnit.id}>
328-
<ListItemIcon>
329-
<Code />
330-
</ListItemIcon>
331-
<ListItemText
332-
primary={codeUnit.packagename + "." + codeUnit.name}
333-
secondary={
334-
<React.Fragment>
335-
<Typography
336-
component="span"
337-
variant="body2"
338-
sx={{ color: 'text.primary', display: 'inline' }}
339-
>
340-
<small>{codeUnit.id}</small>
341-
</Typography>
342-
<CodeBlock language="java">{codeUnit.content ? codeUnit.content : "n/a"}</CodeBlock>
343-
344-
<Typography variant="body2" color="text.secondary">
345-
Learn more about <b>this code module</b>: <Link
346-
href={`/web/lasso/search?query=*:*&filter=id:${codeUnit.id}&ds=${codeUnit.dataSource}`}
347-
target="_blank"
348-
rel="noopener"
349-
underline="hover"
350-
>
351-
Details
352-
</Link>
353-
</Typography>
354-
355-
</React.Fragment>
356-
}
357-
></ListItemText>
358-
359-
</ListItem>
360-
))}
361-
</List> */}
362-
363309
<Grid container spacing={3} sx={{ mt: 1 }}>
364310
{ab.codeUnits.map((codeUnit) => (
365311
<Grid item xs={12} key={codeUnit.id}>

0 commit comments

Comments
 (0)