wip
This commit is contained in:
parent
4e75fae835
commit
b4293b2736
@ -44,11 +44,14 @@
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "==2.0.0-alpha.5 ",
|
||||
"@yanick/updeep-remeda": "^2.2.0",
|
||||
"ajv": "^8.12.0",
|
||||
"beercss": "^3.1.3",
|
||||
"git-describe": "^4.1.1",
|
||||
"git-repo-version": "^1.0.2",
|
||||
"histoire": "^0.16.1",
|
||||
"jsdom": "^21.1.1",
|
||||
"json-schema-shorthand": "^3.0.0",
|
||||
"json-schema-to-ts": "^2.9.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mdsvex": "^0.10.6",
|
||||
"memoize-one": "^6.0.0",
|
||||
|
13
src/lib/jsc.ts
Normal file
13
src/lib/jsc.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export default {
|
||||
string: (args = {}) => ({ type: "string" as const, ...args }),
|
||||
object: <P extends {}, A extends {}>(properties: P = {}, args: A = {}) => ({
|
||||
type: "object" as const,
|
||||
properties,
|
||||
...args,
|
||||
}),
|
||||
boolean: (args = {}) => ({ type: "boolean" as const, ...args }),
|
||||
number: (args = {}) => ({ type: "number" as const, ...args }),
|
||||
integer: (args = {}) => ({ type: "integer" as const, ...args }),
|
||||
type: <S extends string>(type: S, args = {}) => ({ type, ...args }),
|
||||
ref: <S extends string>(ref: S, args = {}) => ({ $ref: ref, ...args }),
|
||||
};
|
@ -2,6 +2,7 @@ import { createSelector } from "@reduxjs/toolkit";
|
||||
import Updux, { createPayloadAction } from "updux";
|
||||
import * as R from "remeda";
|
||||
import memoize from "memoize-one";
|
||||
import Ajv from "ajv";
|
||||
|
||||
import identification from "./ship/identification";
|
||||
import ftl, { calcFtlReqs } from "./ship/propulsion/ftl";
|
||||
@ -18,6 +19,7 @@ import { fireconsDux } from "./ship/weaponry/firecons";
|
||||
import { adfcDux } from "./ship/weaponry/adfc";
|
||||
import { weaponsDux } from "./ship/weaponry/weapons";
|
||||
import { weaponryDux } from "./ship/weaponry";
|
||||
import schema from "./ship/schema";
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
process.env.UPDEEP_MODE = "dangerously_never_freeze";
|
||||
@ -64,6 +66,31 @@ const shipDux = new Updux({
|
||||
},
|
||||
});
|
||||
|
||||
shipDux.addEffect((api) => {
|
||||
const ajv = new Ajv();
|
||||
|
||||
const validate = ajv.compile(schema);
|
||||
|
||||
return (next) => (action) => {
|
||||
next(action);
|
||||
|
||||
if (!validate(api.getState())) {
|
||||
console.error(
|
||||
JSON.stringify(
|
||||
{
|
||||
errors: validate.errors,
|
||||
state: api.getState(),
|
||||
action,
|
||||
},
|
||||
undefined,
|
||||
2
|
||||
)
|
||||
);
|
||||
throw new Error("validation failed");
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
shipDux.addMutation(restore, (state) => () => state);
|
||||
shipDux.addMutation(importShip, (state) => () => state);
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
import Updux, { createAction, withPayload } from "updux";
|
||||
import u from "@yanick/updeep-remeda";
|
||||
import { carrierDux } from "./carrier";
|
||||
import type { FromSchema } from "json-schema-to-ts";
|
||||
import * as j from "json-schema-shorthand";
|
||||
|
||||
const initialState = {
|
||||
shipType: "",
|
||||
shipClass: "",
|
||||
isCarrier: false,
|
||||
reqs: {
|
||||
mass: 10,
|
||||
cost: 0,
|
||||
usedMass: 0,
|
||||
},
|
||||
};
|
||||
import {
|
||||
identificationSchema,
|
||||
type Identification,
|
||||
} from "./identification/schema.js";
|
||||
|
||||
const initialState: Identification = identificationSchema.default;
|
||||
|
||||
const setShipClass = createAction("setShipClass", withPayload<string>());
|
||||
const updateIdentification = createAction("updateIdentification");
|
||||
|
33
src/lib/store/ship/identification/schema.ts
Normal file
33
src/lib/store/ship/identification/schema.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import type { FromSchema } from "json-schema-to-ts";
|
||||
import * as j from "json-schema-shorthand";
|
||||
|
||||
import { reqsSchema } from "../reqs";
|
||||
|
||||
export const identificationSchema = j.object(
|
||||
{
|
||||
shipType: "string",
|
||||
shipClass: "string",
|
||||
isCarrier: { type: "boolean", default: false },
|
||||
reqs: {
|
||||
allOf: ["#/$defs/reqs", { object: { usedMass: "number" } }],
|
||||
},
|
||||
} as const,
|
||||
{
|
||||
additionalProperties: false,
|
||||
$defs: {
|
||||
reqs: reqsSchema,
|
||||
},
|
||||
default: {
|
||||
shipType: "",
|
||||
shipClass: "",
|
||||
isCarrier: false,
|
||||
reqs: {
|
||||
mass: 10,
|
||||
cost: 0,
|
||||
usedMass: 0,
|
||||
},
|
||||
},
|
||||
} as const
|
||||
);
|
||||
|
||||
export type Identification = FromSchema<typeof identificationSchema>;
|
11
src/lib/store/ship/reqs.ts
Normal file
11
src/lib/store/ship/reqs.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { FromSchema, JSONSchema } from "json-schema-to-ts";
|
||||
import * as j from "json-schema-shorthand";
|
||||
|
||||
import jsc from "$lib/jsc";
|
||||
|
||||
export const reqsSchema = j.object({
|
||||
cost: "integer",
|
||||
mass: "integer",
|
||||
} as const);
|
||||
|
||||
export type Reqs = FromSchema<typeof reqsSchema>;
|
28
src/lib/store/ship/schema.test.ts
Normal file
28
src/lib/store/ship/schema.test.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import schema from "./schema";
|
||||
import shipDux from "../ship";
|
||||
import Ajv from "ajv";
|
||||
|
||||
const ajv = new Ajv();
|
||||
|
||||
test("initial value is valid", () => {
|
||||
const validate = ajv.compile(schema);
|
||||
console.log(shipDux.initialState);
|
||||
|
||||
try {
|
||||
expect(validate(shipDux.initialState)).toBeTruthy();
|
||||
} catch (e) {
|
||||
if (validate.errors) {
|
||||
console.warn(
|
||||
JSON.stringify(
|
||||
{
|
||||
state: shipDux.initialState,
|
||||
error: validate.errors,
|
||||
},
|
||||
undefined,
|
||||
2
|
||||
)
|
||||
);
|
||||
}
|
||||
throw new Error("validation failed");
|
||||
}
|
||||
});
|
29
src/lib/store/ship/schema.ts
Normal file
29
src/lib/store/ship/schema.ts
Normal file
@ -0,0 +1,29 @@
|
||||
const todo = {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
};
|
||||
|
||||
const shipSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
schemaVersion: { const: "1" },
|
||||
identification: { $ref: "#/$defs/identification" },
|
||||
structure: { $ref: "#/$defs/todo" },
|
||||
propulsion: { $ref: "#/$defs/todo" },
|
||||
carrier: { $ref: "#/$defs/todo" },
|
||||
weaponry: { $ref: "#/$defs/todo" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
$defs: {
|
||||
identification: identificationSchema,
|
||||
todo,
|
||||
...identificationSchema.$defs,
|
||||
},
|
||||
} as const;
|
||||
|
||||
import type { FromSchema } from "json-schema-to-ts";
|
||||
import { identificationSchema } from "./identification/schema";
|
||||
|
||||
type Ship = FromSchema<typeof shipSchema>;
|
||||
|
||||
export default shipSchema;
|
@ -1,4 +1,3 @@
|
||||
// vite.config.js
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import packageJson from "./package.json";
|
||||
import getVersion from "git-repo-version";
|
||||
@ -6,17 +5,17 @@ import git from "git-describe";
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
const config = {
|
||||
plugins: [sveltekit()],
|
||||
publicDir: "./static",
|
||||
ssr: {},
|
||||
optimizeDeps: {},
|
||||
define: {
|
||||
"import.meta.env.PACKAGE_VERSION": JSON.stringify(
|
||||
git.gitDescribeSync().semverString
|
||||
),
|
||||
"import.meta.env.HOMEPAGE": JSON.stringify(packageJson.homepage),
|
||||
"import.meta.env.BUGS": JSON.stringify(packageJson.bugs.url),
|
||||
},
|
||||
plugins: [sveltekit()],
|
||||
publicDir: "./static",
|
||||
ssr: {},
|
||||
optimizeDeps: {},
|
||||
define: {
|
||||
"import.meta.env.PACKAGE_VERSION": JSON.stringify(
|
||||
git.gitDescribeSync().semverString
|
||||
),
|
||||
"import.meta.env.HOMEPAGE": JSON.stringify(packageJson.homepage),
|
||||
"import.meta.env.BUGS": JSON.stringify(packageJson.bugs.url),
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
Loading…
Reference in New Issue
Block a user