Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • alexander.clausen/snip
  • irp/snip
2 results
Select Git revision
Show changes
Commits on Source (10)
Showing
with 1520 additions and 110 deletions
...@@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ...@@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## 1.12.3
### Fixed
- Update next (see CVE-2025-29927)
- Minor styling issues in schema tables
### Added
- Added stampy snippet in uprp namespace
## 1.12.2 ## 1.12.2
- Hotfix: Fixed a small bug with newly inserted snippets being instantly rendered on a page - Hotfix: Fixed a small bug with newly inserted snippets being instantly rendered on a page
......
...@@ -88,10 +88,11 @@ async function SchemasTables() { ...@@ -88,10 +88,11 @@ async function SchemasTables() {
<figure> <figure>
<figcaption>External snippets</figcaption> <figcaption>External snippets</figcaption>
<table className={styles.table}> <table className={styles.table + " table"}>
<thead> <thead>
<tr> <tr>
<th className={styles.type}>Type</th> <th>Namespace</th>
<th>Type</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
......
...@@ -6,25 +6,29 @@ ...@@ -6,25 +6,29 @@
border-color: var(--bs-gray-100); border-color: var(--bs-gray-100);
} }
thead {
th:first-child {
border-top-left-radius: var(--bs-border-radius);
}
th:last-child {
border-top-right-radius: var(--bs-border-radius);
}
}
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
padding: 0.5rem; padding: 0.5rem;
// Border radius for start and end of table // Border radius for start and end of table
tr:first-child th:first-child { tbody {
border-top-left-radius: var(--bs-border-radius); tr:nth-last-of-type(1) {
} td:first-child {
border-bottom-left-radius: var(--bs-border-radius);
tr:first-child th:last-child { }
border-top-right-radius: var(--bs-border-radius); td:last-child {
} border-bottom-right-radius: var(--bs-border-radius);
}
tr:last-child td:first-child { }
border-bottom-left-radius: var(--bs-border-radius);
}
tr:last-child td:last-child {
border-bottom-right-radius: var(--bs-border-radius);
} }
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
"highlight.js": "^11.10.0", "highlight.js": "^11.10.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"katex": "^0.16.11", "katex": "^0.16.11",
"next": "14.2.18", "next": "^14.2.26",
"next-mdx-remote": "^4.4.1", "next-mdx-remote": "^4.4.1",
"openid-client": "^6.1.1", "openid-client": "^6.1.1",
"probe-image-size": "^7.2.3", "probe-image-size": "^7.2.3",
......
{ {
"name": "snip", "name": "snip",
"version": "1.12.2", "version": "1.12.3",
"description": "our digital lab book", "description": "our digital lab book",
"author": "Sebastian B. Mohr, Markus Osterhoff", "author": "Sebastian B. Mohr, Markus Osterhoff",
"repository": { "repository": {
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"@types/sprintf-js": "^1.1.4", "@types/sprintf-js": "^1.1.4",
"tree-sitter-cli": "^0.25.1", "tree-sitter-cli": "^0.25.1",
"tree-sitter-python": "^0.23.6", "tree-sitter-python": "^0.23.6",
"skia-canvas": "catalog:",
"tsup": "catalog:", "tsup": "catalog:",
"typescript": "catalog:", "typescript": "catalog:",
"vitest": "catalog:" "vitest": "catalog:"
...@@ -39,7 +40,8 @@ ...@@ -39,7 +40,8 @@
"build": "tsup", "build": "tsup",
"watch": "tsc -w", "watch": "tsc -w",
"test": "vitest", "test": "vitest",
"generate-grammars": "tree-sitter build --wasm node_modules/tree-sitter-python -o ../../assets/grammars/tree-sitter-python.wasm" "generate-grammars": "tree-sitter build --wasm node_modules/tree-sitter-python -o ../../assets/grammars/tree-sitter-python.wasm",
"json_to_snip": "tsx ./src/json_to_snip.ts"
}, },
"type": "module" "type": "module"
} }
...@@ -265,15 +265,15 @@ export class TextSnip extends BaseSnip { ...@@ -265,15 +265,15 @@ export class TextSnip extends BaseSnip {
lineWrap: validation.view?.wrap, lineWrap: validation.view?.wrap,
baseline: validation.view?.baseline, baseline: validation.view?.baseline,
//Base //Base
id: data.id, id: validation.id,
page_id: data.page_id, page_id: validation.page_id,
book_id: data.book_id, book_id: validation.book_id,
last_updated: data.last_updated, last_updated: validation.last_updated,
created: data.created, created: validation.created,
x: data.view?.x, x: validation.view?.x,
y: data.view?.y, y: validation.view?.y,
rot: data.view?.rot, rot: validation.view?.rot,
mirror: data.view?.mirror, mirror: validation.view?.mirror,
}); });
} }
......
/** Debugging script to render a snippet
*
* Can be use to develop a new snippet type and test it easily.
*/
import fs from "fs";
import { Canvas } from "skia-canvas";
import { get_snip_from_data } from "./get_snip_from_data";
const file_name = process.argv[2];
let output_file = process.argv[3];
if (!file_name) {
console.error("Usage: tsx render_json.ts <file_name> [output_file]");
process.exit(1);
}
if (output_file && !output_file.endsWith(".png")) {
console.error("Output file must be a PNG file");
process.exit(1);
}
if (!fs.existsSync(file_name)) {
console.error("File does not exist");
process.exit(1);
}
if (!output_file) {
console.log("No output file specified, rendering to output.png");
output_file = "./output.png";
}
// Read file as JSON
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let data: any;
try {
const f = fs.readFileSync(file_name, "utf8");
data = JSON.parse(f);
} catch (e) {
console.error(`Error reading file: ${e}`);
process.exit(1);
}
const snip = get_snip_from_data(data);
const canvas = new Canvas(1400, 2100);
const ctx = canvas.getContext("2d");
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
snip.render(ctx as unknown as OffscreenCanvasRenderingContext2D);
// Save to file
canvas.saveAsSync(output_file);
import { RenderContext } from "@/general/base";
/** An abstract class for all parts.
*
* Parts may be rendered but have far less functionality than snips.
*/
export abstract class Part {
render(ctx: RenderContext): void {
ctx.save();
this._render(ctx);
ctx.restore();
}
/** The actual render function. This should be implemented by all parts.
*
* This function is called by the render function and should not be called
* directly.
*/
abstract _render(ctx: RenderContext): void;
abstract size(ctx: RenderContext): {
width: number;
height: number;
};
}
import { Part } from "./abc";
import { RenderContext } from "@/general/base";
interface TableStyling {
columnWidths?: number[];
borderStyle?: string;
textStyle?: {
fontSize?: number;
headerFontSize?: number;
fill?: string;
};
gap?: {
row?: number;
column?: number;
header?: number;
};
labelWidth?: number;
columnAlign?: ("left" | "right" | "center")[];
}
/** Minimal table with minimal styling.
*/
export class Table extends Part {
private style: TableStyling;
private data: string[][];
private headers?: string[]; // titles horizontal
private labels?: string[]; // titles vertical
private title?: string; // title of the table (placed top left)
constructor(
data: string[][],
styling?: TableStyling,
headers?: string[],
labels?: string[],
title?: string,
) {
super();
this.style = styling || {};
this.data = data;
this.headers = headers;
this.labels = labels;
this.title = title;
}
get columnWidths() {
return this.style.columnWidths || this.data[0]!.map(() => 100);
}
get fontSize() {
return this.style.textStyle?.fontSize || 24;
}
get headerFontSize() {
return this.style.textStyle?.headerFontSize || 24;
}
get labelWidth() {
return this.style.labelWidth || 100;
}
get width() {
let w = this.columnWidths.reduce((a, b) => a + b);
if (this.labels) {
w += this.labelWidth;
}
return w;
}
get headerGap() {
return this.style.gap?.header || 8;
}
get height() {
const rowGap = this.style.gap?.row || 0;
let h = this.data.length * (this.fontSize + rowGap);
if (this.headers) {
h += this.headerFontSize + this.headerGap;
}
return h;
}
size(ctx: RenderContext) {
return {
width: this.width,
height: this.height,
};
}
_render(ctx: RenderContext) {
ctx.save();
// render rect around
ctx.textBaseline = "top";
ctx.strokeStyle = "#000";
ctx.lineWidth = 1;
// Render headers
if (this.headers) {
ctx.font = `bold ${this.headerFontSize}px Arial`;
ctx.fillStyle = this.style.textStyle?.fill || "#000";
if (this.title) {
this.renderRow(ctx, [this.title]);
}
if (this.labels || this.title) {
// skip title
ctx.translate(this.labelWidth, 0);
}
this.renderRow(ctx, this.headers);
ctx.translate(
this.labels ? -this.labelWidth : 0,
this.fontSize + (this.style.gap?.row || 0),
);
//Draw line
ctx.translate(0, this.headerGap / 2);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(this.width, 0);
ctx.stroke();
ctx.translate(0, this.headerGap / 2);
}
// Set font
ctx.font = `${this.fontSize}px PlexMono`;
ctx.fillStyle = this.style.textStyle?.fill || "#000";
// Render data
this.renderRows(ctx, this.data);
ctx.restore();
}
private renderRows(ctx: RenderContext, data: string[][]) {
const rowGap = this.style.gap?.row || 0;
let height = 0;
for (let i = 0; i < data.length; i++) {
let offset = 0;
// resolve labels
if (this.labels && this.labels[i]) {
ctx.font = `bold ${this.fontSize}px PlexMono`;
offset = this.labelWidth;
const rowLabel = this.labels[i]!;
// center
ctx.fillText(
rowLabel,
(offset - ctx.measureText(rowLabel).width) / 2,
0,
);
}
ctx.font = `${this.fontSize}px PlexMono`;
ctx.translate(offset, 0);
height += this.renderRow(ctx, data[i]!) + rowGap;
ctx.translate(-offset, this.fontSize + rowGap);
}
// Draw line
if (this.labels) {
ctx.beginPath();
ctx.moveTo(this.labelWidth, this.fontSize / 3);
ctx.lineTo(this.labelWidth, -(height + this.fontSize / 1.5));
ctx.stroke();
}
}
private renderRow(ctx: RenderContext, row: string[]) {
let currentX = 0;
const colGap = this.style?.gap?.column || 0;
for (let i = 0; i < row.length; i++) {
const width = this.columnWidths[i]!;
const text = row[i]!;
const align = this.style.columnAlign?.[i] || "center";
const textWidth = ctx.measureText(text).width;
let x = 0;
switch (align) {
case "left":
x = currentX + colGap / 2;
break;
case "right":
x = currentX + width - textWidth - colGap / 2;
break;
case "center":
x = currentX + (width / 2 - textWidth / 2);
break;
}
ctx.fillText(text, x, 0);
currentX += width;
}
return this.fontSize;
}
}
import { Part } from "./abc";
import { RenderContext } from "@/general/base";
export interface FontStyle {
fontSize: number;
fontFamily: string;
fontWeight: string;
textAlign: "left" | "right" | "center";
textBaseline: "top" | "middle" | "bottom";
fill: string;
}
export class TextPart extends Part {
protected text: string;
protected fontStyle: Required<FontStyle>;
constructor(text: string, fontStyle?: Partial<FontStyle>) {
super();
this.text = text;
this.fontStyle = {
fontSize: fontStyle?.fontSize || 24,
fontFamily: fontStyle?.fontFamily || "Arial",
fontWeight: fontStyle?.fontWeight || "normal",
textAlign: fontStyle?.textAlign || "left",
textBaseline: fontStyle?.textBaseline || "top",
fill: fontStyle?.fill || "black",
};
}
get fontString() {
return `${this.fontStyle.fontWeight} ${this.fontStyle.fontSize}px ${this.fontStyle.fontFamily}`;
}
get fontSize() {
return this.fontStyle.fontSize;
}
_render(ctx: RenderContext) {
ctx.font = this.fontString;
ctx.fillStyle = this.fontStyle.fill;
ctx.textAlign = this.fontStyle.textAlign;
ctx.textBaseline = this.fontStyle.textBaseline;
ctx.fillText(this.text, 0, 0);
}
size(ctx: RenderContext) {
return {
width: ctx.measureText(this.text).width,
height: this.fontSize,
};
}
}
export class KeyValuePart extends TextPart {
private value: string;
private fontStyleValue: Required<FontStyle>;
constructor(
key: string,
value: string,
fontStyleKey?: Partial<FontStyle>,
fontStyleValue?: Partial<FontStyle>,
) {
super(
key + ": ",
fontStyleKey || {
fontSize: 24,
fontFamily: "Arial",
fontWeight: "bold",
textAlign: "left",
textBaseline: "top",
fill: "black",
},
);
this.value = value;
this.fontStyleValue = {
fontSize: fontStyleValue?.fontSize || 24,
fontFamily: fontStyleValue?.fontFamily || "Arial",
fontWeight: fontStyleValue?.fontWeight || "normal",
textAlign: fontStyleValue?.textAlign || "left",
textBaseline: fontStyleValue?.textBaseline || "top",
fill: fontStyleValue?.fill || "black",
};
}
get fontStringValue() {
return `${this.fontStyleValue.fontWeight} ${this.fontStyleValue.fontSize}px ${this.fontStyleValue.fontFamily}`;
}
_render(ctx: RenderContext) {
// Render key
super._render(ctx);
const metrics = super.size(ctx);
ctx.font = this.fontStringValue;
ctx.fillStyle = this.fontStyleValue.fill;
ctx.textAlign = this.fontStyleValue.textAlign;
ctx.textBaseline = this.fontStyleValue.textBaseline;
ctx.fillText(this.value, metrics.width, 0);
}
size(ctx: RenderContext) {
const metrics = super.size(ctx);
const metricsValue = ctx.measureText(this.value);
return {
width: metrics.width + metricsValue.width,
height: Math.max(metrics.height, this.fontStyleValue.fontSize),
};
}
}
/** Text block with out wrapping */
export class TextBlock extends Part {
protected text: string;
protected fontStyle: Required<FontStyle>;
protected maxWidth: number;
constructor(
text: string,
maxWidth: number,
fontStyle?: Partial<FontStyle>,
) {
super();
this.text = text;
this.maxWidth = maxWidth;
this.fontStyle = {
fontSize: fontStyle?.fontSize || 24,
fontFamily: fontStyle?.fontFamily || "Arial",
fontWeight: fontStyle?.fontWeight || "normal",
textAlign: fontStyle?.textAlign || "left",
textBaseline: fontStyle?.textBaseline || "top",
fill: fontStyle?.fill || "black",
};
}
get fontString() {
return `${this.fontStyle.fontWeight} ${this.fontStyle.fontSize}px ${this.fontStyle.fontFamily}`;
}
_render(ctx: RenderContext): void {
ctx.font = this.fontString;
ctx.fillStyle = this.fontStyle.fill;
ctx.textAlign = this.fontStyle.textAlign;
ctx.textBaseline = this.fontStyle.textBaseline;
const block = this.text.split("\\n");
for (let i = 0; i < block.length; i++) {
const [, y] = this.__renderWrap(ctx, block[i]!);
ctx.translate(0, y);
}
}
__renderWrap(ctx: RenderContext, text: string): [number, number] {
const parts = text.match(/\S+|\s+/g) || [];
let currentX = 0;
let currentY = 0;
for (let part of parts) {
const metrics = ctx.measureText(part);
if (currentX + metrics.width > this.maxWidth) {
currentX = 0;
currentY +=
metrics.fontBoundingBoxAscent +
metrics.fontBoundingBoxDescent;
part = part.trimStart();
}
ctx.fillText(part, currentX, currentY);
currentX += ctx.measureText(part).width;
}
return [currentX, currentY + this.fontStyle.fontSize];
}
size(ctx: RenderContext) {
ctx.font = this.fontString;
const parts = this.text.match(/\S+|\s+/g) || [];
let currentX = 0;
let currentY = this.fontStyle.fontSize;
for (let part of parts) {
const metrics = ctx.measureText(part);
if (currentX + metrics.width > this.maxWidth) {
currentX = 0;
currentY +=
metrics.fontBoundingBoxAscent +
metrics.fontBoundingBoxDescent;
part = part.trimStart();
}
currentX += ctx.measureText(part).width;
}
return {
width: this.maxWidth,
height: currentY + this.fontStyle.fontSize,
};
}
}
...@@ -5,6 +5,7 @@ import { LogfileSnip } from "./spec/logfile"; ...@@ -5,6 +5,7 @@ import { LogfileSnip } from "./spec/logfile";
import { MacroSpecSnip } from "./spec/macrospec"; import { MacroSpecSnip } from "./spec/macrospec";
import { MotorsSnip } from "./spec/motors"; import { MotorsSnip } from "./spec/motors";
import { TimestampSnip } from "./spec/timestamp"; import { TimestampSnip } from "./spec/timestamp";
import { StampySnip } from "./stampy";
const TYPE_TO_SNIP: Map<string, typeof BaseSnip> = new Map(); const TYPE_TO_SNIP: Map<string, typeof BaseSnip> = new Map();
...@@ -25,4 +26,7 @@ TYPE_TO_SNIP.set("uprp/spec/matlab", ImageSnip); ...@@ -25,4 +26,7 @@ TYPE_TO_SNIP.set("uprp/spec/matlab", ImageSnip);
// SPOC mapping // SPOC mapping
// TODO:@Markus // TODO:@Markus
// Stampy
TYPE_TO_SNIP.set("uprp/stampy", StampySnip);
export default TYPE_TO_SNIP; export default TYPE_TO_SNIP;
import { type } from "arktype";
import { DataValidationError } from "@/errors";
import {
BaseSnip,
BaseSnipArgs,
BaseViewSchema,
RenderContext,
SnipData,
SnipDataSchema,
} from "@/general/base";
import { Part } from "@/parts/abc";
import { Table } from "@/parts/table";
import { FontStyle, KeyValuePart, TextBlock, TextPart } from "@/parts/text";
/* -------------------------------------------------------------------------- */
/* Schema for insert */
/* -------------------------------------------------------------------------- */
// The dataschema is a one to one mapping from the stampy json
// TODO: Might need some adjustments depending on what we actually need on the snip side
// I would suggest to remove all the optional fields and only keep the required ones
const StampySchema = type({
meta: {
version: "number",
instrument: "string",
setup: "string",
experiment: "string",
date: "string",
},
sample: {
name: "string",
id: "number",
comment: "string",
},
measurement: {
volume: {
diameter: "number",
height: "number",
fovw: "number",
fovh: "number",
unit: "'mm' | 'cm'",
},
stack: {
motor: "string",
factorh: "number",
values: "number[]",
},
detector: {
name: "string",
pixelSize: "number",
pixels: ["number", "number"],
},
grid: {
motors: "('cx'|'cy')[]",
method: "'hexagonal'",
factorw: "number",
prefill: "number",
values: "number[][]",
},
timing: {
illumination: "number",
interval: "number",
unit: "'second' | 'minute' | 'hour'",
mode: "string",
topupSync: "'no' | 'yes'",
topupParameter: "number[]",
trgLine: "number",
trgDelay: "number",
},
tomo: {
motor: "string",
frames: "number",
commands: "string[]",
angles: {
range: "number",
safety: "number",
unit: "string",
},
velocity: {
tomo: "number",
moving: "number",
},
},
empty: {
frames: "number",
commands: "string[]",
scheme: "string",
pattern: "string",
},
dark: {
frames: "number",
commands: "string[]",
},
range: "string",
},
motors: {
tomo: {
stx: "number",
cx: "number",
sty: "number",
cy: "number",
stz: "number",
cz: "number",
stzrot: "number",
},
empty: {
stx: "number",
cx: "number",
sty: "number",
cy: "number",
stz: "number",
cz: "number",
stzrot: "number",
},
final: {
stx: "number",
cx: "number",
sty: "number",
cy: "number",
stz: "number",
cz: "number",
stzrot: "number",
},
detector: {
mdetx: "number",
mdety: "number",
mdetz: "number",
},
energy: {
mono: "number",
unit: "string",
},
innerLoop: "Record<string,string|number>[]",
outerLoop: "Record<string,string|number>[]",
},
});
export const StampyDataSchema = type({
"version?": type("1").describe(
"The version of the stampy snippet, empty for latest.",
),
stampy: StampySchema.describe("The data returned from stampy."),
});
export const StampyViewSchema = type(
{
"padding?": type("number").describe(
"Padding between the different parts of the snip. Default: 8",
),
},
"&",
BaseViewSchema,
).describe(BaseViewSchema.description);
export const StampySnipSchema = type(SnipDataSchema, "&", {
data: StampyDataSchema,
"view?": StampyViewSchema,
}).describe("Represents a stampy snippet.");
export type StampyData = typeof StampyDataSchema.infer;
export type StampyView = typeof StampyViewSchema.infer;
export type StampySnipArgs = BaseSnipArgs & StampyData;
/* -------------------------------------------------------------------------- */
/* StampySnip implementation */
/* -------------------------------------------------------------------------- */
export class StampySnip extends BaseSnip {
public type = "stampy";
stampy: StampyData["stampy"];
// Indent of the text blocks
padding: number = 8;
parts: Part[];
constructor({ version, stampy, ...baseArgs }: StampySnipArgs) {
super({ ...baseArgs });
this.stampy = stampy;
// Crate render parts
const header = new TextPart(`Sample: ${this.stampy.sample.name}`, {
fontSize: 35,
fill: "#000",
fontWeight: "bold",
});
const id = new KeyValuePart("ID", "" + this.stampy.sample.id);
const date = new KeyValuePart("Date", this.stampy.meta.date);
const table = new MotorsTable(this.stampy.motors);
const timings = new TimingsSection("Timings:", {
Illumination: `${this.stampy.measurement.timing.illumination}s`,
Interval: `${this.stampy.measurement.timing.interval}s`,
});
const grid = new SampleGrid(this.stampy.measurement);
const comment = new CommentSection(
"Comment:",
this.stampy.sample.comment,
{
fontSize: 24,
fill: "#000",
fontWeight: "normal",
},
);
this.parts = [header, id, date, table, timings, grid, comment];
if (
this.stampy.motors.outerLoop.length > 0 ||
this.stampy.motors.innerLoop.length > 0
) {
const loops = new LoopTables(
"Loops:",
this.stampy.motors.outerLoop,
this.stampy.motors.innerLoop,
{
fontSize: 24,
fill: "#000",
fontWeight: "normal",
},
);
this.parts = [...this.parts, loops];
}
}
static readonly _schema = StampySnipSchema;
static from_data(data: SnipData<StampyData, StampyView>): StampySnip {
// Validate
const validation = this._schema(data);
if (validation instanceof type.errors) {
throw DataValidationError.from_ark(validation);
}
// We can check the version here if necessary
// in the future
return new StampySnip({
stampy: validation.data.stampy,
// Base
id: validation.id,
page_id: validation.page_id,
book_id: validation.book_id,
last_updated: validation.last_updated,
created: validation.created,
x: validation.view?.x,
y: validation.view?.y,
rot: validation.view?.rot,
mirror: validation.view?.mirror,
});
}
// TODO: Make this dynamic
get width(): number {
return 700;
}
get height(): number {
return 700;
}
public render(ctx: RenderContext): void {
ctx.save();
this.transform(ctx);
for (const part of this.parts) {
part.render(ctx);
const partsize = part.size(ctx);
ctx.translate(0, this.padding);
ctx.translate(0, partsize.height);
}
ctx.restore();
}
}
/** The sample grid.
*/
class SampleGrid extends Part {
measurement: StampyData["stampy"]["measurement"];
width: number = 700;
height: number = 700;
constructor(measurement: StampyData["stampy"]["measurement"]) {
super();
this.measurement = measurement;
}
size(_ctx: RenderContext): {
width: number;
height: number;
} {
return {
width: this.width,
height: this.height,
};
}
/** Compute the scale such that
* the max values fits inside
* the width and height
*/
private computeScale(width: number, height: number, max: number): number {
return Math.min(width, height) / max;
}
_render(ctx: RenderContext): void {
// Draw rect around the area
ctx.strokeStyle = "#000";
ctx.lineWidth = 1;
ctx.rect(0, 0, this.width, this.height);
ctx.stroke();
// translate to center
ctx.translate(this.width / 2, this.height / 2);
// Render Scale
const s = this.computeScale(
this.width,
this.height,
this.measurement.volume.diameter * 2.5,
);
const scale = new Scale(this.width / 2, this.height / 2);
scale.setScaleFactor(s, 1);
scale.render(ctx);
// Render grid
const r = (this.measurement.volume.fovw * s) / 2;
const positions = this.measurement.grid.values;
for (let i = 0; i < positions.length; i++) {
const x = positions[i]![0]!;
const y = positions[i]![1]!;
this.drawCircle(ctx, x * s, y * s, r, {
stroke: "#000",
fill: "#000",
fill_alpha: 0.2,
});
}
// Render sample circle
this.drawCircle(ctx, 0, 0, (this.measurement.volume.diameter / 2) * s, {
stroke: "#000",
fill: "red",
fill_alpha: 0.2,
});
// Label (top right)
ctx.font = "bold 28px Arial";
ctx.fillStyle = "#000";
ctx.textBaseline = "top";
ctx.fillText(
`Grid(${this.measurement.grid.method})`,
-this.height / 2 + 5,
-this.height / 2 + 5,
);
}
private drawCircle(
ctx: RenderContext,
x: number,
y: number,
radius: number,
style: {
stroke: string;
fill?: string;
fill_alpha?: number;
stroke_alpha?: number;
},
) {
if (style.fill_alpha === undefined) {
style.fill_alpha = 1;
}
if (style.stroke_alpha === undefined) {
style.stroke_alpha = 1;
}
// Draw center point
ctx.save();
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
// Draw stroke
ctx.globalAlpha = style.stroke_alpha;
ctx.strokeStyle = style.stroke;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
// Draw fill if fill color is defined
if (style.fill) {
ctx.globalAlpha = style.fill_alpha;
ctx.fillStyle = style.fill;
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
ctx.restore();
}
}
class MotorsTable extends Table {
header: TextPart;
constructor(motors: StampyData["stampy"]["motors"]) {
super(
[
[
motors.detector.mdetx.toString(),
motors.tomo.stx.toString(),
motors.tomo.cx.toString(),
],
[
motors.detector.mdety.toString(),
motors.tomo.sty.toString(),
motors.tomo.cy.toString(),
],
[
motors.detector.mdetz.toString(),
motors.tomo.stz.toString(),
motors.tomo.cz.toString(),
],
["", motors.tomo.stzrot.toString(), ""],
[
motors.energy.mono.toString() + " " + motors.energy.unit,
"",
"",
],
],
{
labelWidth: 50,
columnWidths: [550 / 3, 550 / 3, 550 / 3],
gap: {
column: 5,
},
columnAlign: ["right", "right", "right"],
textStyle: {
fontSize: 24,
},
},
["mdet", "st", "c"],
["x", "y", "z", "θ", "E"],
);
this.header = new TextPart("Motors:", {
fontSize: 24,
fontWeight: "bold",
fill: "#000",
textAlign: "left",
textBaseline: "top",
});
}
_render(ctx: RenderContext): void {
this.header.render(ctx);
ctx.translate(0, this.header.size(ctx).height);
super._render(ctx);
}
size(ctx: RenderContext): {
width: number;
height: number;
} {
const headerSize = this.header.size(ctx);
const tableSize = super.size(ctx);
return {
width: Math.max(headerSize.width, tableSize.width),
height: headerSize.height + tableSize.height,
};
}
}
/** Simple scale component usable to render a scale showing
* a bar of the length of the scaleUnit.
*/
class Scale extends Part {
// Positions
x: number;
y: number;
height: number = 8;
maxWidth: number = 200;
// Styling
padding: number = 15;
constructor(x: number, y: number, height?: number, maxWidth?: number) {
super();
this.x = x;
this.y = y;
if (height) {
this.height = height;
}
if (maxWidth) {
this.maxWidth = maxWidth;
}
}
// ScaleFactor of the component
// i.e. 1mm equals this scaleFactor
scaleWidth: number = 100;
scaleUnit: number = 1;
setScaleFactor(factor: number, mm: number) {
// try to approximatly fill the maxWidth
let _mm = mm;
let s = factor;
while (s < this.maxWidth) {
_mm *= 2;
s *= 2;
}
this.scaleWidth = s;
this.scaleUnit = _mm;
}
get text() {
return `${this.scaleUnit} mm`;
}
_render(ctx: RenderContext) {
ctx.font = "26px Arial";
ctx.textBaseline = "top";
const ts = ctx.measureText(this.text);
// Translate to position regarding align
// TODO: make dynamic
const align = {
horizontal: "right",
vertical: "bottom",
};
ctx.translate(this.x, this.y);
ctx.translate(
align.horizontal === "right"
? -this.scaleWidth - this.padding
: this.padding,
align.vertical === "bottom"
? -this.height - 26 - this.padding - 5
: this.padding,
);
// Render scale rect
ctx.globalAlpha = 0.8;
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.fillRect(0, 0, this.scaleWidth, this.height);
ctx.fill();
// Render text
ctx.globalAlpha = 1;
ctx.fillStyle = "#000";
ctx.fillText(
`${this.scaleUnit} mm`,
this.scaleWidth / 2 - ts.width / 2,
this.height + 5,
);
}
size(_ctx: RenderContext): {
width: number;
height: number;
} {
return {
width: this.scaleWidth,
height: this.height + 26 + this.padding,
};
}
}
class TimingsSection extends Part {
header: TextPart;
items: Record<string, string>;
fontStyle: FontStyle;
constructor(
headerText: string,
items: Record<string, string>,
fontStyle?: Partial<FontStyle>,
) {
super();
this.header = new TextPart(headerText, {
...fontStyle,
fontWeight: "bold",
});
this.items = items;
this.fontStyle = {
fontSize: fontStyle?.fontSize || 24,
fontFamily: fontStyle?.fontFamily || "Arial",
fontWeight: fontStyle?.fontWeight || "normal",
textAlign: fontStyle?.textAlign || "left",
textBaseline: fontStyle?.textBaseline || "top",
fill: fontStyle?.fill || "black",
};
}
_render(ctx: RenderContext): void {
this.header.render(ctx);
ctx.translate(0, this.header.size(ctx).height);
ctx.font = `${this.fontStyle.fontWeight} ${this.fontStyle.fontSize}px ${this.fontStyle.fontFamily}`;
ctx.fillStyle = this.fontStyle.fill;
ctx.textAlign = this.fontStyle.textAlign;
// 2 items per row
let c = 0;
for (const [key, value] of Object.entries(this.items)) {
if (c % 2 === 0 && c > 0) {
ctx.translate(0, this.fontStyle.fontSize);
}
ctx.fillText(
key + ": ",
0 + (c % 2) * 350,
this.fontStyle.fontSize,
);
const width = ctx.measureText(key + ": ").width;
ctx.fillText(value, width + (c % 2) * 350, this.fontStyle.fontSize);
c++;
}
}
size(ctx: RenderContext): {
width: number;
height: number;
} {
const headerSize = this.header.size(ctx);
return {
width: 700,
height:
headerSize.height +
Math.ceil(Object.entries(this.items).length / 2) *
this.fontStyle.fontSize,
};
}
}
class CommentSection extends TextBlock {
header: TextPart;
constructor(
headerText: string,
text: string,
fontStyle?: Partial<FontStyle>,
) {
super(text, 700, fontStyle);
this.header = new TextPart(headerText, {
...fontStyle,
fontWeight: "bold",
});
}
_render(ctx: RenderContext): void {
this.header.render(ctx);
ctx.translate(0, this.header.size(ctx).height);
super._render(ctx);
}
size(ctx: RenderContext): {
width: number;
height: number;
} {
const headerSize = this.header.size(ctx);
const textSize = super.size(ctx);
return {
width: Math.max(headerSize.width, textSize.width),
height: headerSize.height + textSize.height,
};
}
}
class LoopTables extends Part {
header: TextPart;
outer?: Table;
inner?: Table;
constructor(
headerText: string,
outer: Record<string, string | number>[],
inner: Record<string, string | number>[],
fontStyle?: Partial<FontStyle>,
) {
super();
this.header = new TextPart(headerText, {
...fontStyle,
fontWeight: "bold",
});
if (outer.length > 0) {
this.outer = new Table(
create2DArrayFromDynamicKeys(outer),
{
columnWidths: Object.keys(outer[0]!).map(() => 100),
gap: {
column: 5,
},
},
Object.keys(outer[0]!),
// loop iteration [1,2,...]
Array.from({ length: outer.length }, (_, i) =>
(i + 1).toString(),
),
"outer",
);
}
if (inner.length > 0) {
this.inner = new Table(
create2DArrayFromDynamicKeys(inner),
{
columnWidths: Object.keys(inner[0]!).map(() => 100),
gap: {
column: 5,
},
},
Object.keys(inner[0]!),
Array.from({ length: inner.length }, (_, i) =>
(i + 1).toString(),
),
"inner",
);
}
}
get padding() {
return this.header.fontSize / 2;
}
_render(ctx: RenderContext): void {
this.header.render(ctx);
ctx.translate(0, this.header.size(ctx).height);
// Render tables
if (this.outer) {
this.outer.render(ctx);
ctx.translate(0, this.outer.size(ctx).height);
ctx.translate(0, this.padding);
}
if (this.inner) {
this.inner.render(ctx);
ctx.translate(0, this.inner.size(ctx).height);
}
}
size(ctx: RenderContext): {
width: number;
height: number;
} {
const headerSize = this.header.size(ctx);
let h = headerSize.height;
let w = headerSize.width;
if (this.outer) {
const outerSize = this.outer.size(ctx);
h += outerSize.height + this.padding;
w = Math.max(w, outerSize.width);
}
if (this.inner) {
const innerSize = this.inner.size(ctx);
h += innerSize.height;
w = Math.max(w, innerSize.width);
}
return {
width: w,
height: h,
};
}
}
function create2DArrayFromDynamicKeys(
outerLoop: Record<string, string | number>[],
) {
if (outerLoop.length === 0) return [];
// Get all keys from the first object (assuming all objects have the same keys)
const keys = Object.keys(outerLoop[0]!);
return outerLoop.map((item) => keys.map((key) => "" + (item[key] ?? "")));
}
{
"type": "uprp/stampy",
"book_id": -1,
"data": {
"stampy": {
"meta": {
"version": 1,
"instrument": "GINIX",
"setup": "PB tomo",
"experiment": "run123",
"date": "2024-9-27"
},
"sample": {
"name": "sample01a",
"id": 0,
"comment": "NR_PREV\\nImaging of top part"
},
"measurement": {
"volume": {
"diameter": 1,
"height": 1,
"fovw": 1.4,
"fovh": 1.2,
"unit": "mm"
},
"stack": { "motor": "stz", "factorh": 1.1, "values": [0] },
"detector": {
"name": "PCO.edge",
"pixelSize": 0.65e-6,
"pixels": [2560, 2160]
},
"grid": {
"motors": ["cx", "cy"],
"method": "hexagonal",
"factorw": 1.1,
"prefill": 1,
"values": [[0, 0]]
},
"timing": {
"illumination": 0.035,
"interval": 0.015,
"unit": "second",
"mode": "continuous-1",
"topupSync": "no",
"topupParameter": [100.9, 100.8],
"trgLine": 2,
"trgDelay": 2000
},
"tomo": {
"motor": "stzrot",
"frames": 3000,
"commands": ["oslow; sleep(1);", "cslow;"],
"angles": {
"range": 360.014,
"safety": 20,
"unit": "degree"
},
"velocity": { "tomo": 11972, "moving": 240000 }
},
"empty": {
"frames": 500,
"commands": ["", ""],
"scheme": "pre-volume",
"pattern": "eted"
},
"dark": { "frames": 100, "commands": ["cslow; sleep(1);", ""] },
"range": "all"
},
"motors": {
"tomo": {
"stx": 180,
"cx": 2.50001,
"sty": -3.94607,
"cy": 1.60297,
"stz": -1,
"cz": 2.07352,
"stzrot": 0.000194
},
"empty": {
"stx": 180,
"cx": 2.50001,
"sty": -3.94607,
"cy": -4,
"stz": -1,
"cz": 2.07352,
"stzrot": 0.000194
},
"final": {
"stx": 180,
"cx": 2.50001,
"sty": -3.94607,
"cy": 1.60297,
"stz": -1,
"cz": 2.07352,
"stzrot": 0.000194
},
"detector": { "mdetx": 0, "mdety": 0, "mdetz": 0 },
"energy": { "mono": 8, "unit": "keV" },
"innerLoop": [
{ "x": 0, "y": 0, "z": 0 },
{ "x": 1, "y": 1, "z": 1 },
{ "x": 2, "y": 2, "z": 2 },
{ "x": 3, "y": 3, "z": 3 }
],
"outerLoop": [
{ "mdetx": 1.1, "mdety": 1.2, "mdetz": 1.3 },
{ "mdetx": 2.1, "mdety": 2.2, "mdetz": 2.3 },
{ "mdetx": 3.1, "mdety": 3.2, "mdetz": 3.3 },
{ "mdetx": 4.1, "mdety": 4.2, "mdetz": 4.3 }
]
}
}
},
"view": {
"x": 10,
"y": 0
}
}
...@@ -267,8 +267,8 @@ importers: ...@@ -267,8 +267,8 @@ importers:
specifier: ^0.16.11 specifier: ^0.16.11
version: 0.16.11 version: 0.16.11
next: next:
specifier: 14.2.18 specifier: ^14.2.26
version: 14.2.18(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.4) version: 14.2.26(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.4)
next-mdx-remote: next-mdx-remote:
specifier: ^4.4.1 specifier: ^4.4.1
version: 4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
...@@ -1013,6 +1013,9 @@ importers: ...@@ -1013,6 +1013,9 @@ importers:
'@types/sprintf-js': '@types/sprintf-js':
specifier: ^1.1.4 specifier: ^1.1.4
version: 1.1.4 version: 1.1.4
skia-canvas:
specifier: 'catalog:'
version: 2.0.2
tree-sitter-cli: tree-sitter-cli:
specifier: ^0.25.1 specifier: ^0.25.1
version: 0.25.1 version: 0.25.1
...@@ -1787,8 +1790,8 @@ packages: ...@@ -1787,8 +1790,8 @@ packages:
'@next/bundle-analyzer@14.2.18': '@next/bundle-analyzer@14.2.18':
resolution: {integrity: sha512-3tfi//6w3T1JGelYl+CSIwFFLrMui+R7kGc+dRZJNYAPwg7xL9/CBtGnSKZLPgsA/CwwPOdnMrYYBOPZ2BSezQ==} resolution: {integrity: sha512-3tfi//6w3T1JGelYl+CSIwFFLrMui+R7kGc+dRZJNYAPwg7xL9/CBtGnSKZLPgsA/CwwPOdnMrYYBOPZ2BSezQ==}
'@next/env@14.2.18': '@next/env@14.2.26':
resolution: {integrity: sha512-2vWLOUwIPgoqMJKG6dt35fVXVhgM09tw4tK3/Q34GFXDrfiHlG7iS33VA4ggnjWxjiz9KV5xzfsQzJX6vGAekA==} resolution: {integrity: sha512-vO//GJ/YBco+H7xdQhzJxF7ub3SUwft76jwaeOyVVQFHCi5DCnkP16WHB+JBylo4vOKPoZBlR94Z8xBxNBdNJA==}
'@next/eslint-plugin-next@14.2.5': '@next/eslint-plugin-next@14.2.5':
resolution: {integrity: sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==} resolution: {integrity: sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==}
...@@ -1804,56 +1807,56 @@ packages: ...@@ -1804,56 +1807,56 @@ packages:
'@mdx-js/react': '@mdx-js/react':
optional: true optional: true
'@next/swc-darwin-arm64@14.2.18': '@next/swc-darwin-arm64@14.2.26':
resolution: {integrity: sha512-tOBlDHCjGdyLf0ube/rDUs6VtwNOajaWV+5FV/ajPgrvHeisllEdymY/oDgv2cx561+gJksfMUtqf8crug7sbA==} resolution: {integrity: sha512-zDJY8gsKEseGAxG+C2hTMT0w9Nk9N1Sk1qV7vXYz9MEiyRoF5ogQX2+vplyUMIfygnjn9/A04I6yrUTRTuRiyQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@next/swc-darwin-x64@14.2.18': '@next/swc-darwin-x64@14.2.26':
resolution: {integrity: sha512-uJCEjutt5VeJ30jjrHV1VIHCsbMYnEqytQgvREx+DjURd/fmKy15NaVK4aR/u98S1LGTnjq35lRTnRyygglxoA==} resolution: {integrity: sha512-U0adH5ryLfmTDkahLwG9sUQG2L0a9rYux8crQeC92rPhi3jGQEY47nByQHrVrt3prZigadwj/2HZ1LUUimuSbg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@next/swc-linux-arm64-gnu@14.2.18': '@next/swc-linux-arm64-gnu@14.2.26':
resolution: {integrity: sha512-IL6rU8vnBB+BAm6YSWZewc+qvdL1EaA+VhLQ6tlUc0xp+kkdxQrVqAnh8Zek1ccKHlTDFRyAft0e60gteYmQ4A==} resolution: {integrity: sha512-SINMl1I7UhfHGM7SoRiw0AbwnLEMUnJ/3XXVmhyptzriHbWvPPbbm0OEVG24uUKhuS1t0nvN/DBvm5kz6ZIqpg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-arm64-musl@14.2.18': '@next/swc-linux-arm64-musl@14.2.26':
resolution: {integrity: sha512-RCaENbIZqKKqTlL8KNd+AZV/yAdCsovblOpYFp0OJ7ZxgLNbV5w23CUU1G5On+0fgafrsGcW+GdMKdFjaRwyYA==} resolution: {integrity: sha512-s6JaezoyJK2DxrwHWxLWtJKlqKqTdi/zaYigDXUJ/gmx/72CrzdVZfMvUc6VqnZ7YEvRijvYo+0o4Z9DencduA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-x64-gnu@14.2.18': '@next/swc-linux-x64-gnu@14.2.26':
resolution: {integrity: sha512-3kmv8DlyhPRCEBM1Vavn8NjyXtMeQ49ID0Olr/Sut7pgzaQTo4h01S7Z8YNE0VtbowyuAL26ibcz0ka6xCTH5g==} resolution: {integrity: sha512-FEXeUQi8/pLr/XI0hKbe0tgbLmHFRhgXOUiPScz2hk0hSmbGiU8aUqVslj/6C6KA38RzXnWoJXo4FMo6aBxjzg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-linux-x64-musl@14.2.18': '@next/swc-linux-x64-musl@14.2.26':
resolution: {integrity: sha512-mliTfa8seVSpTbVEcKEXGjC18+TDII8ykW4a36au97spm9XMPqQTpdGPNBJ9RySSFw9/hLuaCMByluQIAnkzlw==} resolution: {integrity: sha512-BUsomaO4d2DuXhXhgQCVt2jjX4B4/Thts8nDoIruEJkhE5ifeQFtvW5c9JkdOtYvE5p2G0hcwQ0UbRaQmQwaVg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-win32-arm64-msvc@14.2.18': '@next/swc-win32-arm64-msvc@14.2.26':
resolution: {integrity: sha512-J5g0UFPbAjKYmqS3Cy7l2fetFmWMY9Oao32eUsBPYohts26BdrMUyfCJnZFQkX9npYaHNDOWqZ6uV9hSDPw9NA==} resolution: {integrity: sha512-5auwsMVzT7wbB2CZXQxDctpWbdEnEW/e66DyXO1DcgHxIyhP06awu+rHKshZE+lPLIGiwtjo7bsyeuubewwxMw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@next/swc-win32-ia32-msvc@14.2.18': '@next/swc-win32-ia32-msvc@14.2.26':
resolution: {integrity: sha512-Ynxuk4ZgIpdcN7d16ivJdjsDG1+3hTvK24Pp8DiDmIa2+A4CfhJSEHHVndCHok6rnLUzAZD+/UOKESQgTsAZGg==} resolution: {integrity: sha512-GQWg/Vbz9zUGi9X80lOeGsz1rMH/MtFO/XqigDznhhhTfDlDoynCM6982mPCbSlxJ/aveZcKtTlwfAjwhyxDpg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@next/swc-win32-x64-msvc@14.2.18': '@next/swc-win32-x64-msvc@14.2.26':
resolution: {integrity: sha512-dtRGMhiU9TN5nyhwzce+7c/4CCeykYS+ipY/4mIrGzJ71+7zNo55ZxCB7cAVuNqdwtYniFNR2c9OFQ6UdFIMcg==} resolution: {integrity: sha512-2rdB3T1/Gp7bv1eQTTm9d1Y1sv9UuJ2LAwOE0Pe2prHKe32UNscj7YS13fRB37d0GAiGNR+Y7ZcW8YjDI8Ns0w==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
...@@ -2290,6 +2293,9 @@ packages: ...@@ -2290,6 +2293,9 @@ packages:
'@types/estree@1.0.6': '@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
'@types/estree@1.0.7':
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
'@types/express-serve-static-core@4.19.5': '@types/express-serve-static-core@4.19.5':
resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==}
...@@ -2365,12 +2371,12 @@ packages: ...@@ -2365,12 +2371,12 @@ packages:
'@types/node@20.16.1': '@types/node@20.16.1':
resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==} resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==}
'@types/node@20.17.19':
resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==}
'@types/node@20.17.2': '@types/node@20.17.2':
resolution: {integrity: sha512-OOHK4sjXqkL7yQ7VEEHcf6+0jSvKjWqwnaCtY7AKD/VLEvRHMsxxu7eI8ErnjxHS8VwmekD4PeVCpu4qZEZSxg==} resolution: {integrity: sha512-OOHK4sjXqkL7yQ7VEEHcf6+0jSvKjWqwnaCtY7AKD/VLEvRHMsxxu7eI8ErnjxHS8VwmekD4PeVCpu4qZEZSxg==}
'@types/node@20.17.28':
resolution: {integrity: sha512-DHlH/fNL6Mho38jTy7/JT7sn2wnXI+wULR6PV4gy4VHLVvnrV/d3pHAMQHhc4gjdLmK2ZiPoMxzp6B3yRajLSQ==}
'@types/node@22.13.4': '@types/node@22.13.4':
resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
...@@ -2771,6 +2777,11 @@ packages: ...@@ -2771,6 +2777,11 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
acorn@8.14.1:
resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
engines: {node: '>=0.4.0'}
hasBin: true
agent-base@6.0.2: agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'} engines: {node: '>= 6.0.0'}
...@@ -3087,8 +3098,8 @@ packages: ...@@ -3087,8 +3098,8 @@ packages:
caniuse-lite@1.0.30001674: caniuse-lite@1.0.30001674:
resolution: {integrity: sha512-jOsKlZVRnzfhLojb+Ykb+gyUSp9Xb57So+fAiFlLzzTKpqg8xxSav0e40c8/4F/v9N8QSvrRRaLeVzQbLqomYw==} resolution: {integrity: sha512-jOsKlZVRnzfhLojb+Ykb+gyUSp9Xb57So+fAiFlLzzTKpqg8xxSav0e40c8/4F/v9N8QSvrRRaLeVzQbLqomYw==}
caniuse-lite@1.0.30001700: caniuse-lite@1.0.30001707:
resolution: {integrity: sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==} resolution: {integrity: sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==}
cargo-cp-artifact@0.1.9: cargo-cp-artifact@0.1.9:
resolution: {integrity: sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA==} resolution: {integrity: sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA==}
...@@ -3579,8 +3590,8 @@ packages: ...@@ -3579,8 +3590,8 @@ packages:
ee-first@1.1.1: ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
electron-to-chromium@1.5.104: electron-to-chromium@1.5.128:
resolution: {integrity: sha512-Us9M2L4cO/zMBqVkJtnj353nQhMju9slHm62NprKTmdF3HH8wYOtNvDFq/JB2+ZRoGLzdvYDiATlMHs98XBM1g==} resolution: {integrity: sha512-bo1A4HH/NS522Ws0QNFIzyPcyUUNV/yyy70Ho1xqfGYzPUme2F/xr4tlEOuM6/A538U1vDA7a4XfCd1CKRegKQ==}
electron-to-chromium@1.5.49: electron-to-chromium@1.5.49:
resolution: {integrity: sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==} resolution: {integrity: sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==}
...@@ -5358,8 +5369,8 @@ packages: ...@@ -5358,8 +5369,8 @@ packages:
react: '>=16.x <=18.x' react: '>=16.x <=18.x'
react-dom: '>=16.x <=18.x' react-dom: '>=16.x <=18.x'
next@14.2.18: next@14.2.26:
resolution: {integrity: sha512-H9qbjDuGivUDEnK6wa+p2XKO+iMzgVgyr9Zp/4Iv29lKa+DYaxJGjOeEA+5VOvJh/M7HLiskehInSa0cWxVXUw==} resolution: {integrity: sha512-b81XSLihMwCfwiUVRRja3LphLo4uBBMZEzBBWMaISbKTwOmq3wPknIETy/8000tr7Gq4WmbuFYPS7jOYIf+ZJw==}
engines: {node: '>=18.17.0'} engines: {node: '>=18.17.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
...@@ -5434,8 +5445,8 @@ packages: ...@@ -5434,8 +5445,8 @@ packages:
nth-check@2.1.1: nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
nwsapi@2.2.16: nwsapi@2.2.20:
resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}
oauth4webapi@3.1.1: oauth4webapi@3.1.1:
resolution: {integrity: sha512-0h4FZjsntbKQ5IHGM9mFT7uOwQCRdcTG7YhC0xXlWIcCch24wUa6Vggaipa3Sw6Ab7nEnmO4rctROmyuHBfP7Q==} resolution: {integrity: sha512-0h4FZjsntbKQ5IHGM9mFT7uOwQCRdcTG7YhC0xXlWIcCch24wUa6Vggaipa3Sw6Ab7nEnmO4rctROmyuHBfP7Q==}
...@@ -6337,8 +6348,8 @@ packages: ...@@ -6337,8 +6348,8 @@ packages:
resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==} resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
terser-webpack-plugin@5.3.11: terser-webpack-plugin@5.3.14:
resolution: {integrity: sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==} resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==}
engines: {node: '>= 10.13.0'} engines: {node: '>= 10.13.0'}
peerDependencies: peerDependencies:
'@swc/core': '*' '@swc/core': '*'
...@@ -6705,8 +6716,8 @@ packages: ...@@ -6705,8 +6716,8 @@ packages:
peerDependencies: peerDependencies:
browserslist: '>= 4.21.0' browserslist: '>= 4.21.0'
update-browserslist-db@1.1.2: update-browserslist-db@1.1.3:
resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
browserslist: '>= 4.21.0' browserslist: '>= 4.21.0'
...@@ -7753,7 +7764,7 @@ snapshots: ...@@ -7753,7 +7764,7 @@ snapshots:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
'@next/env@14.2.18': {} '@next/env@14.2.26': {}
'@next/eslint-plugin-next@14.2.5': '@next/eslint-plugin-next@14.2.5':
dependencies: dependencies:
...@@ -7766,31 +7777,31 @@ snapshots: ...@@ -7766,31 +7777,31 @@ snapshots:
'@mdx-js/loader': 3.0.1(webpack@5.92.1) '@mdx-js/loader': 3.0.1(webpack@5.92.1)
'@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1) '@mdx-js/react': 3.0.1(@types/react@18.3.3)(react@18.3.1)
'@next/swc-darwin-arm64@14.2.18': '@next/swc-darwin-arm64@14.2.26':
optional: true optional: true
'@next/swc-darwin-x64@14.2.18': '@next/swc-darwin-x64@14.2.26':
optional: true optional: true
'@next/swc-linux-arm64-gnu@14.2.18': '@next/swc-linux-arm64-gnu@14.2.26':
optional: true optional: true
'@next/swc-linux-arm64-musl@14.2.18': '@next/swc-linux-arm64-musl@14.2.26':
optional: true optional: true
'@next/swc-linux-x64-gnu@14.2.18': '@next/swc-linux-x64-gnu@14.2.26':
optional: true optional: true
'@next/swc-linux-x64-musl@14.2.18': '@next/swc-linux-x64-musl@14.2.26':
optional: true optional: true
'@next/swc-win32-arm64-msvc@14.2.18': '@next/swc-win32-arm64-msvc@14.2.26':
optional: true optional: true
'@next/swc-win32-ia32-msvc@14.2.18': '@next/swc-win32-ia32-msvc@14.2.26':
optional: true optional: true
'@next/swc-win32-x64-msvc@14.2.18': '@next/swc-win32-x64-msvc@14.2.26':
optional: true optional: true
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
...@@ -8166,11 +8177,11 @@ snapshots: ...@@ -8166,11 +8177,11 @@ snapshots:
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
dependencies: dependencies:
'@types/eslint': 9.6.1 '@types/eslint': 9.6.1
'@types/estree': 1.0.6 '@types/estree': 1.0.7
'@types/eslint@9.6.1': '@types/eslint@9.6.1':
dependencies: dependencies:
'@types/estree': 1.0.6 '@types/estree': 1.0.7
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
'@types/estree-jsx@1.0.5': '@types/estree-jsx@1.0.5':
...@@ -8179,6 +8190,8 @@ snapshots: ...@@ -8179,6 +8190,8 @@ snapshots:
'@types/estree@1.0.6': {} '@types/estree@1.0.6': {}
'@types/estree@1.0.7': {}
'@types/express-serve-static-core@4.19.5': '@types/express-serve-static-core@4.19.5':
dependencies: dependencies:
'@types/node': 20.17.2 '@types/node': 20.17.2
...@@ -8262,11 +8275,11 @@ snapshots: ...@@ -8262,11 +8275,11 @@ snapshots:
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
'@types/node@20.17.19': '@types/node@20.17.2':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
'@types/node@20.17.2': '@types/node@20.17.28':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
...@@ -8842,13 +8855,13 @@ snapshots: ...@@ -8842,13 +8855,13 @@ snapshots:
acorn-globals@7.0.1: acorn-globals@7.0.1:
dependencies: dependencies:
acorn: 8.14.0 acorn: 8.14.1
acorn-walk: 8.3.4 acorn-walk: 8.3.4
optional: true optional: true
acorn-import-attributes@1.9.5(acorn@8.14.0): acorn-import-attributes@1.9.5(acorn@8.14.1):
dependencies: dependencies:
acorn: 8.14.0 acorn: 8.14.1
acorn-jsx@5.3.2(acorn@8.12.1): acorn-jsx@5.3.2(acorn@8.12.1):
dependencies: dependencies:
...@@ -8864,13 +8877,15 @@ snapshots: ...@@ -8864,13 +8877,15 @@ snapshots:
acorn-walk@8.3.4: acorn-walk@8.3.4:
dependencies: dependencies:
acorn: 8.14.0 acorn: 8.14.1
optional: true optional: true
acorn@8.12.1: {} acorn@8.12.1: {}
acorn@8.14.0: {} acorn@8.14.0: {}
acorn@8.14.1: {}
agent-base@6.0.2: agent-base@6.0.2:
dependencies: dependencies:
debug: 4.4.0 debug: 4.4.0
...@@ -9191,10 +9206,10 @@ snapshots: ...@@ -9191,10 +9206,10 @@ snapshots:
browserslist@4.24.4: browserslist@4.24.4:
dependencies: dependencies:
caniuse-lite: 1.0.30001700 caniuse-lite: 1.0.30001707
electron-to-chromium: 1.5.104 electron-to-chromium: 1.5.128
node-releases: 2.0.19 node-releases: 2.0.19
update-browserslist-db: 1.1.2(browserslist@4.24.4) update-browserslist-db: 1.1.3(browserslist@4.24.4)
buffer-crc32@0.2.13: {} buffer-crc32@0.2.13: {}
...@@ -9245,7 +9260,7 @@ snapshots: ...@@ -9245,7 +9260,7 @@ snapshots:
caniuse-lite@1.0.30001674: {} caniuse-lite@1.0.30001674: {}
caniuse-lite@1.0.30001700: {} caniuse-lite@1.0.30001707: {}
cargo-cp-artifact@0.1.9: {} cargo-cp-artifact@0.1.9: {}
...@@ -9697,7 +9712,7 @@ snapshots: ...@@ -9697,7 +9712,7 @@ snapshots:
ee-first@1.1.1: {} ee-first@1.1.1: {}
electron-to-chromium@1.5.104: {} electron-to-chromium@1.5.128: {}
electron-to-chromium@1.5.49: {} electron-to-chromium@1.5.49: {}
...@@ -11216,7 +11231,7 @@ snapshots: ...@@ -11216,7 +11231,7 @@ snapshots:
jest-worker@27.5.1: jest-worker@27.5.1:
dependencies: dependencies:
'@types/node': 20.17.19 '@types/node': 20.17.28
merge-stream: 2.0.0 merge-stream: 2.0.0
supports-color: 8.1.1 supports-color: 8.1.1
...@@ -11240,7 +11255,7 @@ snapshots: ...@@ -11240,7 +11255,7 @@ snapshots:
jsdom@20.0.3: jsdom@20.0.3:
dependencies: dependencies:
abab: 2.0.6 abab: 2.0.6
acorn: 8.14.0 acorn: 8.14.1
acorn-globals: 7.0.1 acorn-globals: 7.0.1
cssom: 0.5.0 cssom: 0.5.0
cssstyle: 2.3.0 cssstyle: 2.3.0
...@@ -11253,7 +11268,7 @@ snapshots: ...@@ -11253,7 +11268,7 @@ snapshots:
http-proxy-agent: 5.0.0 http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.1 https-proxy-agent: 5.0.1
is-potential-custom-element-name: 1.0.1 is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.16 nwsapi: 2.2.20
parse5: 7.2.1 parse5: 7.2.1
saxes: 6.0.0 saxes: 6.0.0
symbol-tree: 3.2.4 symbol-tree: 3.2.4
...@@ -12447,9 +12462,9 @@ snapshots: ...@@ -12447,9 +12462,9 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
next@14.2.18(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.4): next@14.2.26(@playwright/test@1.45.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.83.4):
dependencies: dependencies:
'@next/env': 14.2.18 '@next/env': 14.2.26
'@swc/helpers': 0.5.5 '@swc/helpers': 0.5.5
busboy: 1.6.0 busboy: 1.6.0
caniuse-lite: 1.0.30001674 caniuse-lite: 1.0.30001674
...@@ -12459,15 +12474,15 @@ snapshots: ...@@ -12459,15 +12474,15 @@ snapshots:
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(react@18.3.1) styled-jsx: 5.1.1(react@18.3.1)
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 14.2.18 '@next/swc-darwin-arm64': 14.2.26
'@next/swc-darwin-x64': 14.2.18 '@next/swc-darwin-x64': 14.2.26
'@next/swc-linux-arm64-gnu': 14.2.18 '@next/swc-linux-arm64-gnu': 14.2.26
'@next/swc-linux-arm64-musl': 14.2.18 '@next/swc-linux-arm64-musl': 14.2.26
'@next/swc-linux-x64-gnu': 14.2.18 '@next/swc-linux-x64-gnu': 14.2.26
'@next/swc-linux-x64-musl': 14.2.18 '@next/swc-linux-x64-musl': 14.2.26
'@next/swc-win32-arm64-msvc': 14.2.18 '@next/swc-win32-arm64-msvc': 14.2.26
'@next/swc-win32-ia32-msvc': 14.2.18 '@next/swc-win32-ia32-msvc': 14.2.26
'@next/swc-win32-x64-msvc': 14.2.18 '@next/swc-win32-x64-msvc': 14.2.26
'@playwright/test': 1.45.2 '@playwright/test': 1.45.2
sass: 1.83.4 sass: 1.83.4
transitivePeerDependencies: transitivePeerDependencies:
...@@ -12531,7 +12546,7 @@ snapshots: ...@@ -12531,7 +12546,7 @@ snapshots:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
nwsapi@2.2.16: nwsapi@2.2.20:
optional: true optional: true
oauth4webapi@3.1.1: {} oauth4webapi@3.1.1: {}
...@@ -13665,7 +13680,7 @@ snapshots: ...@@ -13665,7 +13680,7 @@ snapshots:
tarn@3.0.2: {} tarn@3.0.2: {}
terser-webpack-plugin@5.3.11(webpack@5.92.1): terser-webpack-plugin@5.3.14(webpack@5.92.1):
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1 jest-worker: 27.5.1
...@@ -13684,7 +13699,7 @@ snapshots: ...@@ -13684,7 +13699,7 @@ snapshots:
terser@5.39.0: terser@5.39.0:
dependencies: dependencies:
'@jridgewell/source-map': 0.3.6 '@jridgewell/source-map': 0.3.6
acorn: 8.14.0 acorn: 8.14.1
commander: 2.20.3 commander: 2.20.3
source-map-support: 0.5.21 source-map-support: 0.5.21
...@@ -14049,7 +14064,7 @@ snapshots: ...@@ -14049,7 +14064,7 @@ snapshots:
escalade: 3.2.0 escalade: 3.2.0
picocolors: 1.1.1 picocolors: 1.1.1
update-browserslist-db@1.1.2(browserslist@4.24.4): update-browserslist-db@1.1.3(browserslist@4.24.4):
dependencies: dependencies:
browserslist: 4.24.4 browserslist: 4.24.4
escalade: 3.2.0 escalade: 3.2.0
...@@ -14463,12 +14478,12 @@ snapshots: ...@@ -14463,12 +14478,12 @@ snapshots:
webpack@5.92.1: webpack@5.92.1:
dependencies: dependencies:
'@types/eslint-scope': 3.7.7 '@types/eslint-scope': 3.7.7
'@types/estree': 1.0.6 '@types/estree': 1.0.7
'@webassemblyjs/ast': 1.14.1 '@webassemblyjs/ast': 1.14.1
'@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1
'@webassemblyjs/wasm-parser': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1
acorn: 8.14.0 acorn: 8.14.1
acorn-import-attributes: 1.9.5(acorn@8.14.0) acorn-import-attributes: 1.9.5(acorn@8.14.1)
browserslist: 4.24.4 browserslist: 4.24.4
chrome-trace-event: 1.0.4 chrome-trace-event: 1.0.4
enhanced-resolve: 5.18.1 enhanced-resolve: 5.18.1
...@@ -14483,7 +14498,7 @@ snapshots: ...@@ -14483,7 +14498,7 @@ snapshots:
neo-async: 2.6.2 neo-async: 2.6.2
schema-utils: 3.3.0 schema-utils: 3.3.0
tapable: 2.2.1 tapable: 2.2.1
terser-webpack-plugin: 5.3.11(webpack@5.92.1) terser-webpack-plugin: 5.3.14(webpack@5.92.1)
watchpack: 2.4.2 watchpack: 2.4.2
webpack-sources: 3.2.3 webpack-sources: 3.2.3
transitivePeerDependencies: transitivePeerDependencies:
......