From cda596fac3bf640da669dc672efa9e3495795e20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Mon, 8 Jun 2020 15:57:30 +0200
Subject: [PATCH] [dome] safe & typed json library

---
 ivette/src/dome/src/renderer/data/json.ts | 114 ++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 ivette/src/dome/src/renderer/data/json.ts

diff --git a/ivette/src/dome/src/renderer/data/json.ts b/ivette/src/dome/src/renderer/data/json.ts
new file mode 100644
index 00000000000..277bc056659
--- /dev/null
+++ b/ivette/src/dome/src/renderer/data/json.ts
@@ -0,0 +1,114 @@
+// --------------------------------------------------------------------------
+// --- JSON Utilities
+// --------------------------------------------------------------------------
+
+import { DEVEL } from 'dome/system';
+
+/**
+   Safe JSON utilities
+   @package dome/data/json
+*/
+
+export type json =
+  undefined | null | number | string | json[] | { [key: string]: json }
+
+/**
+   Parse without _revivals_.
+   Returned data is guaranteed to have only [[json]] type.
+   If an error occurs and `noError` is set to `true`,
+   the function returns `undefined` and logs the error in console
+   (DEVEL mode only).
+ */
+export function parse(text: string, noError = false): json {
+  if (noError) {
+    try {
+      return JSON.parse(text);
+    } catch (err) {
+      if (DEVEL) console.error('[Dome.json] invalid format:', err);
+      return undefined;
+    }
+  } else
+    return JSON.parse(text);
+}
+
+/**
+   Export JSON as a compact string.
+*/
+export function stringify(js: json) {
+  return JSON.stringify(js, undefined, 0);
+}
+
+/**
+   Export JSON as a string with indented content.
+ */
+export function pretty(js: json) {
+  return JSON.stringify(js, undefined, 2);
+}
+
+// --------------------------------------------------------------------------
+// --- SAFE Decoder
+// --------------------------------------------------------------------------
+
+export type Loose<D> = (js: json) => D | undefined;
+export type Strict<D> = (js: json) => D;
+
+// --------------------------------------------------------------------------
+// --- Primitives
+// --------------------------------------------------------------------------
+
+export const jNumber: Loose<number> = (js: json) => (
+  typeof js === 'number' ? js : undefined
+);
+
+export const jZero: Strict<number> = (js: json) => (
+  typeof js === 'number' ? js : 0
+);
+
+export const jBoolean: Loose<boolean> = (js: json) => (
+  typeof js === 'boolean' ? js : undefined
+);
+
+export const jTrue: Strict<boolean> = (js: json) => (
+  typeof js === 'boolean' ? js : true
+);
+
+export const jFalse: Strict<boolean> = (js: json) => (
+  typeof js === 'boolean' ? js : false
+);
+
+export const jString: Loose<string> = (js: json) => (
+  typeof js === 'string' ? js : undefined
+);
+
+export function jEnum(...values: string[]): Loose<string> {
+  var m = new Map<string, string>();
+  values.forEach(v => m.set(v, v));
+  return (v: json) => (typeof v === 'string' ? m.get(v) : undefined);
+}
+
+export function jDefault<A>(
+  fn: Loose<A>,
+  defaultValue: A,
+): Strict<A> {
+  return (js: json) => js === undefined ? defaultValue : (fn(js) ?? defaultValue);
+}
+
+export function jArray<A>(fn: Strict<A>): Strict<A[]> {
+  return (js: json) => Array.isArray(js) ? js.map(fn) : [];
+}
+
+export function jList<A>(fn: Loose<A>): Strict<A[]> {
+  return (js: json) => {
+    const buffer: A[] = [];
+    if (Array.isArray(js)) js.forEach(vj => {
+      const d = fn(vj);
+      if (d !== undefined) buffer.push(d);
+    });
+    return buffer;
+  };
+}
+
+export
+
+
+// --------------------------------------------------------------------------
-- 
GitLab