From cfdf41513908e565c2b7cc3837b570d5bbe8719e Mon Sep 17 00:00:00 2001 From: Alexis Jacomy Date: Fri, 7 Feb 2025 16:25:35 +0100 Subject: [PATCH] [file] Generates JSON schema Details: - Fixes two typings ambiguities - Fixes some comments, that were poorly rendered in the output JSON schema - Installs typescript-json-schema, and updates build task to generate the JSON schema for the GephiLiteFileFormat type, and put it in the build directory --- package-lock.json | 213 +++++++++++++++++++++ packages/gephi-lite/package.json | 4 +- packages/gephi-lite/src/core/file/types.ts | 12 +- packages/sdk/src/appearance/types.ts | 3 +- packages/sdk/src/graph/index.ts | 4 +- packages/sdk/src/graph/types.ts | 25 ++- 6 files changed, 245 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17ab09f..f5ff6d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1656,6 +1656,30 @@ "tough-cookie": "^4.1.4" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@datapunt/matomo-tracker-js": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/@datapunt/matomo-tracker-js/-/matomo-tracker-js-0.5.1.tgz", @@ -4352,6 +4376,34 @@ } } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -5182,6 +5234,13 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -6085,6 +6144,13 @@ "node": ">= 6" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6296,6 +6362,16 @@ "node": ">=0.10" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-match-patch": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", @@ -9048,6 +9124,13 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/material-colors": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", @@ -9693,6 +9776,13 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, + "node_modules/path-equal": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", + "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10940,6 +11030,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -11755,6 +11855,50 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/ts-patch": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ts-patch/-/ts-patch-3.3.0.tgz", @@ -11928,6 +12072,57 @@ "typescript": ">=4.8.4 <5.8.0" } }, + "node_modules/typescript-json-schema": { + "version": "0.65.1", + "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.65.1.tgz", + "integrity": "sha512-tuGH7ff2jPaUYi6as3lHyHcKpSmXIqN7/mu50x3HlYn0EHzLpmt3nplZ7EuhUkO0eqDRc9GqWNkfjgBPIS9kxg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/node": "^18.11.9", + "glob": "^7.1.7", + "path-equal": "^1.2.5", + "safe-stable-stringify": "^2.2.0", + "ts-node": "^10.9.1", + "typescript": "~5.5.0", + "yargs": "^17.1.1" + }, + "bin": { + "typescript-json-schema": "bin/typescript-json-schema" + } + }, + "node_modules/typescript-json-schema/node_modules/@types/node": { + "version": "18.19.75", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.75.tgz", + "integrity": "sha512-UIksWtThob6ZVSyxcOqCLOUNg/dyO1Qvx4McgeuhrEtHTLFTf7BBhEazaE4K806FGTPtzd/2sE90qn4fVr7cyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/typescript-json-schema/node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-json-schema/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "node_modules/typia": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/typia/-/typia-7.6.0.tgz", @@ -12147,6 +12342,13 @@ "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/value-or-function": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz", @@ -13064,6 +13266,16 @@ "node": ">=12" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -13197,6 +13409,7 @@ "i18next-scanner": "^4.6.0", "sass": "1.77.6", "ts-patch": "^3.3.0", + "typescript-json-schema": "^0.65.1", "typia": "^7.6.0", "vite": "^6.0.11", "vite-plugin-checker": "^0.8.0", diff --git a/packages/gephi-lite/package.json b/packages/gephi-lite/package.json index 4b79a32..74d6a1d 100644 --- a/packages/gephi-lite/package.json +++ b/packages/gephi-lite/package.json @@ -5,12 +5,13 @@ "license": "gpl-3.0", "scripts": { "start": "vite", - "build": "vite build", + "build": "vite build && npm run generate-json-schema", "serve": "vite preview", "test": "npm run test:unit && npm run test:e2e", "test:unit": "vitest run src", "test:e2e": "playwright test", "translations-scan": "i18next-scanner --config ../../i18next-scanner.config.ts packages/gephi-lite/src/**/*.{ts,tsx}", + "generate-json-schema": "typescript-json-schema src/core/file/types.ts GephiLiteFileFormat -o build/gephi-lite-format.schema.json", "prepare": "ts-patch install && typia patch" }, "browserslist": { @@ -111,6 +112,7 @@ "http-proxy-middleware": "^3.0.3", "i18next-scanner": "^4.6.0", "sass": "1.77.6", + "typescript-json-schema": "^0.65.1", "ts-patch": "^3.3.0", "typia": "^7.6.0", "vite": "^6.0.11", diff --git a/packages/gephi-lite/src/core/file/types.ts b/packages/gephi-lite/src/core/file/types.ts index 0bf3906..d391833 100644 --- a/packages/gephi-lite/src/core/file/types.ts +++ b/packages/gephi-lite/src/core/file/types.ts @@ -5,13 +5,11 @@ import { FiltersState } from "../filters/types"; import { GraphDataset } from "../graph/types"; /** - * Type for the file format of gephi-lite. - * We save : - * - the gephi-lite version for checking compatibilities in the futur - * - the full graph with its metadata - * - filters - * - appearance - * - selection + * A serializable structure, to allow Gephi Lite to load and save graphs, with their surrounding context. + * This includes: + * - The full graph dataset + * - The filters state + * - The appearance state */ export type GephiLiteFileFormat = { type: "gephi-lite"; diff --git a/packages/sdk/src/appearance/types.ts b/packages/sdk/src/appearance/types.ts index 16dfb76..20d0a01 100644 --- a/packages/sdk/src/appearance/types.ts +++ b/packages/sdk/src/appearance/types.ts @@ -94,8 +94,9 @@ export interface ZIndexFieldAttr extends AppearanceBaseElement { export type ZIndexAttr = NoFieldValue<"none"> | ZIndexFieldAttr; /** - * This state contains everything needed to generate the visual getters: + * Describes how each visual variable should be used to render the graph in Gephi Lite. */ + export interface AppearanceState { showEdges: BooleanAppearance; nodesSize: Size; diff --git a/packages/sdk/src/graph/index.ts b/packages/sdk/src/graph/index.ts index ef58c73..21401ac 100644 --- a/packages/sdk/src/graph/index.ts +++ b/packages/sdk/src/graph/index.ts @@ -25,14 +25,14 @@ export function serializeDataset( ): SerializedGraphDataset | Partial { return dataset.fullGraph ? { ...dataset, fullGraph: dataset.fullGraph.export() } - : (dataset as Partial); + : (dataset as Omit, "fullGraph">); } export function deserializeDataset(dataset: SerializedGraphDataset): GraphDataset; export function deserializeDataset(dataset: Partial): Partial; export function deserializeDataset( dataset: SerializedGraphDataset | Partial, ): Partial | GraphDataset { - if (!dataset.fullGraph) return dataset as Partial; + if (!dataset.fullGraph) return dataset as Omit, "fullGraph">; const fullGraph = new MultiGraph(); fullGraph.import(dataset.fullGraph); diff --git a/packages/sdk/src/graph/types.ts b/packages/sdk/src/graph/types.ts index 308ea31..a8dff76 100644 --- a/packages/sdk/src/graph/types.ts +++ b/packages/sdk/src/graph/types.ts @@ -2,9 +2,10 @@ import { MultiGraph } from "graphology"; import { Attributes, GraphType, SerializedGraph } from "graphology-types"; /** - * Base types: + * BASE TYPES: * *********** */ + export type Scalar = boolean | number | string | undefined | null; export const SCALAR_TYPES = new Set(["boolean", "number", "string", "undefined"]); @@ -13,9 +14,10 @@ export type ItemData = Record; export type StaticDynamicItemData = { static: ItemData; dynamic: ItemData }; /** - * Items data: + * ITEMS DATA: * *********** */ + export interface EdgeRenderingData extends Attributes { label?: string | null; color?: string; @@ -43,9 +45,13 @@ export interface GraphMetadata { } /** - * Model: + * MODEL: * ****** */ + +/** + * Describes how Gephi Lite should interpret a nodes or edges field. + */ export interface FieldModel { id: string; itemType: T; @@ -68,18 +74,27 @@ export type FieldModelWithStats = FieldModel & }; /** - * Graphs: + * GRAPHS: * ******* */ + +/** + * A Graphology graph, without any attribute, to just describe the topology of a graph. + */ export type DatalessGraph = MultiGraph; export type SigmaGraph = MultiGraph; export type DataGraph = MultiGraph; export type FullGraph = MultiGraph; /** - * States: + * STATES: * ******* */ + +/** + * A canonical structure that contains the topology of a graph, its nodes and edges attributes and rendering attributes, + * as well as the models to know how to interpret all the attributes. + */ export interface GraphDataset { // The mandatory rendering data is stored in typed indices: nodeRenderingData: Record;