From 0fd541b28c23ef463193bac7cbb212eb0ef1a8ef Mon Sep 17 00:00:00 2001 From: LokiSharp Date: Sun, 15 Oct 2023 02:38:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + common/src/ConfigManager.ts | 2 +- common/src/configs/storage.ts | 1 + driver/.gitignore | 2 + package-lock.json | 35 ++++- storage/.eslintrc.json | 27 ++++ storage/.gitignore | 26 ++++ storage/jest.config.json | 13 ++ storage/package.json | 35 +++++ storage/src/Database.ts | 248 +++++++++++++++++++++++++++++++++ storage/src/index.ts | 2 + storage/src/main.ts | 3 + storage/src/types.d.ts | 16 +++ storage/tests/DataBase.test.ts | 163 ++++++++++++++++++++++ storage/tests/main.test.ts | 7 + storage/tsconfig.json | 40 ++++++ storage/tsconfig.node.json | 10 ++ storage/vite.config.ts | 25 ++++ 18 files changed, 653 insertions(+), 5 deletions(-) create mode 100644 storage/.eslintrc.json create mode 100644 storage/.gitignore create mode 100644 storage/jest.config.json create mode 100644 storage/package.json create mode 100644 storage/src/Database.ts create mode 100644 storage/src/index.ts create mode 100644 storage/src/main.ts create mode 100644 storage/src/types.d.ts create mode 100644 storage/tests/DataBase.test.ts create mode 100644 storage/tests/main.test.ts create mode 100644 storage/tsconfig.json create mode 100644 storage/tsconfig.node.json create mode 100644 storage/vite.config.ts diff --git a/.gitignore b/.gitignore index 7a1537b..27f7283 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ .idea node_modules + +coverage +tmp \ No newline at end of file diff --git a/common/src/ConfigManager.ts b/common/src/ConfigManager.ts index 9fa25e4..ac3d8b0 100644 --- a/common/src/ConfigManager.ts +++ b/common/src/ConfigManager.ts @@ -10,9 +10,9 @@ export class ConfigManager { class Config { public common = { constants: constants, - storage: storage, dbCollections: dbCollections, system: {}, }; public engine = engine; + public storage = storage; } diff --git a/common/src/configs/storage.ts b/common/src/configs/storage.ts index 6dc560a..31deb5e 100644 --- a/common/src/configs/storage.ts +++ b/common/src/configs/storage.ts @@ -2,4 +2,5 @@ export const storage = { db: {}, queue: {}, env: {}, + dbOptions: { autosave: true, autosaveInterval: 10000 }, }; diff --git a/driver/.gitignore b/driver/.gitignore index a547bf3..f8b68de 100644 --- a/driver/.gitignore +++ b/driver/.gitignore @@ -7,6 +7,8 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* +coverage +tmp node_modules dist dist-ssr diff --git a/package-lock.json b/package-lock.json index bece637..a272137 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1762,6 +1762,10 @@ "resolved": "driver", "link": true }, + "node_modules/@neo-screeps/storage": { + "resolved": "storage", + "link": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2071,12 +2075,24 @@ "integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==", "dev": true }, + "node_modules/@types/lokijs": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/@types/lokijs/-/lokijs-1.5.10.tgz", + "integrity": "sha512-Q/F6OUCZPHWY4hzEowhCswi9Tafc/E7DCUyyWIOH3+hM3K96Mkj2U3byfzs7Yd542I8gT/8oUALnoddqdA20xg==", + "dev": true + }, "node_modules/@types/node": { "version": "20.8.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz", "integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==", "dev": true }, + "node_modules/@types/q": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.6.tgz", + "integrity": "sha512-IKjZ8RjTSwD4/YG+2gtj7BPFRB/lNbWKTiSj3M7U/TD2B7HfYCxvp2Zz6xA2WIY7pAuL1QOUPw8gQRbUrrq4fQ==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", @@ -5556,8 +5572,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.get": { "version": "4.4.2", @@ -5583,6 +5598,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lokijs": { + "version": "1.5.12", + "resolved": "https://registry.npmjs.org/lokijs/-/lokijs-1.5.12.tgz", + "integrity": "sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==" + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -7811,8 +7831,15 @@ "storage": { "name": "@neo-screeps/storage", "version": "0.0.0", - "extraneous": true, - "license": "ISC" + "dependencies": { + "lodash": "^4.17.21", + "lokijs": "^1.5.12", + "q": "^1.5.1" + }, + "devDependencies": { + "@types/lokijs": "^1.5.10", + "@types/q": "^1.5.6" + } } } } diff --git a/storage/.eslintrc.json b/storage/.eslintrc.json new file mode 100644 index 0000000..62da3e2 --- /dev/null +++ b/storage/.eslintrc.json @@ -0,0 +1,27 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "plugins": [ + "prettier" + ], + "ignorePatterns": [ + "dist", + "coverage", + "vite.config.ts" + ], + "rules": { + "@typescript-eslint/explicit-function-return-type": "warn", + "@typescript-eslint/explicit-member-accessibility": "warn", + "no-unused-vars": "warn", + "prettier/prettier": "error" + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": [ + "./tsconfig.json" + ] + } +} diff --git a/storage/.gitignore b/storage/.gitignore new file mode 100644 index 0000000..f8b68de --- /dev/null +++ b/storage/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +coverage +tmp +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/storage/jest.config.json b/storage/jest.config.json new file mode 100644 index 0000000..3296308 --- /dev/null +++ b/storage/jest.config.json @@ -0,0 +1,13 @@ +{ + "roots": ["/tests"], + "moduleNameMapper": { + "^@/(.*)$": "/src/$1" + }, + "testMatch": [ + "**/__tests__/**/*.+(ts)", + "**/?(*.)+(spec|test).+(ts)" + ], + "transform": { + "^.+\\.(ts)$": "ts-jest" + } +} diff --git a/storage/package.json b/storage/package.json new file mode 100644 index 0000000..d813271 --- /dev/null +++ b/storage/package.json @@ -0,0 +1,35 @@ +{ + "name": "@neo-screeps/storage", + "private": true, + "version": "0.0.0", + "type": "module", + "files": [ + "dist" + ], + "main": "./dist/storage.cjs", + "module": "./dist/storage.js", + "exports": { + "types": "./dist/index.d.ts", + "import": "./dist/storage.js", + "require": "./dist/storage.cjs" + }, + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx", + "test": "jest", + "coverage": "jest --coverage" + }, + "_moduleAliases": { + "@": "src" + }, + "dependencies": { + "lodash": "^4.17.21", + "lokijs": "^1.5.12", + "q": "^1.5.1" + }, + "devDependencies": { + "@types/lokijs": "^1.5.10", + "@types/q": "^1.5.6" + } +} diff --git a/storage/src/Database.ts b/storage/src/Database.ts new file mode 100644 index 0000000..06bf4dd --- /dev/null +++ b/storage/src/Database.ts @@ -0,0 +1,248 @@ +import { common } from "@neo-screeps/common"; +import fs from "fs"; +import Q from "q"; +import _ from "lodash"; +import Loki, { Collection } from "lokijs"; + +const config = common.configManager.config; + +export class DataBase { + public db: Loki | undefined; + public getDb(): Loki { + try { + fs.statSync(process.env.DB_PATH!); + } catch (e) { + fs.writeFileSync(process.env.DB_PATH!, ""); + } + return new Loki(process.env.DB_PATH!, config.storage.dbOptions); + } + public loadDb(): Q.Promise { + this.db = this.getDb(); + return Q.ninvoke(this.db, "loadDatabase", {}).then(this.upgradeDb); + } + public upgradeDb(): void { + let upgradeInterval: NodeJS.Timeout; + if (process.send) { + upgradeInterval = setInterval(function () { + process.send!("storageUpgrading"); + }, 1000); + } + const env = this.db!.getCollection("env"); + const envData = env.get(1); + if (!envData) { + return; + } + if (upgradeInterval!) { + clearInterval(upgradeInterval); + } + } + public updateDocument(doc: object, update: Data): void { + if (update.$set) { + _.extend(doc, update.$set); + } + if (update.$merge) { + _.merge(doc, update.$merge); + } + if (update.$inc) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + _.forEach(update.$inc, (val, key) => (doc[key] = (doc[key] || 0) + val)); + } + if (update.$unset) { + for (const j in update.$unset) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + delete doc[j]; + } + } + if (update.$addToSet) { + for (const i in update.$addToSet) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (!doc[i]) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + doc[i] = []; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (doc[i].indexOf(update.$addToSet[i]) == -1) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + doc[i].push(update.$addToSet[i]); + } + } + } + if (update.$pull) { + for (const i in update.$pull) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (!doc[i]) { + continue; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const idx = doc[i].indexOf(update.$pull[i]); + if (idx != -1) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + doc[i].splice(idx, 1); + } + } + } + } + + public getRandomString(): string { + let val; + for ( + val = Math.floor(Math.random() * 0x10000).toString(16); + val.length < 4; + val = "0" + val + ); + return val; + } + + public genId(obj: object): string { + const id = + this.getRandomString() + + Date.now().toString(16).slice(4) + + this.getRandomString(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (obj && !obj._id) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + obj._id = id; + } + return id; + } + + public getOrAddCollection(collectionName: string): Collection { + let collection = this.db!.getCollection(collectionName); + if (!collection) { + collection = this.db!.addCollection(collectionName); + } + collection.ensureUniqueIndex("_id"); + switch (collectionName) { + case "users": { + collection.ensureIndex("username"); + break; + } + } + return collection; + } + + public recursReplaceNeNull(val: Data): void { + if (!_.isObject(val)) { + return; + } + + for (const i in val) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (_.isEqual(val[i], { $ne: null }) && !val.$and) { + val.$and = [{ [i]: { $ne: null } }, { [i]: { $ne: undefined } }]; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + delete val[i]; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (_.isEqual(val[i], { $eq: null }) && !val.$or) { + val.$or = [{ [i]: { $eq: null } }, { [i]: { $eq: undefined } }]; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + delete val[i]; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.recursReplaceNeNull(val[i]); + } + } + public dbRequest( + collectionName: string, + method: string, + argsArray: (object | object[])[], + cb: (message: string | null, obj?: object) => void, + ): void { + try { + const collection = this.getOrAddCollection(collectionName); + if (method == "insert") { + if (_.isArray(argsArray[0])) { + argsArray[0].forEach((obj) => this.genId(obj)); + } else { + this.genId(argsArray[0]); + } + } + + if ( + method == "find" || + method == "findOne" || + method == "count" || + method == "removeWhere" + ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.recursReplaceNeNull(argsArray[0]); + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line prefer-spread + const result = collection[method].apply(collection, argsArray); + cb(null, result); + } catch (e) { + cb((e as Error).message); + console.error(e); + } + } + + public dbUpdate( + collectionName: string, + query: Data, + update: Data, + params: { upsert?: boolean } | null, + cb: (message: string | null, obj?: object) => void, + ): void { + try { + this.recursReplaceNeNull(query); + const collection = this.getOrAddCollection(collectionName); + let result = []; + if ( + Object.keys(query).length == 1 && + query._id && + _.isString(query._id) + ) { + const found = collection.by("_id", query._id); + if (found) { + result = [found]; + } + } else { + result = collection.find(query); + } + if (result.length) { + result.forEach((doc) => { + this.updateDocument(doc, update); + collection.update(doc); + }); + cb(null, { modified: result.length }); + } else if (params && params.upsert) { + const item = {}; + if (query.$and) { + query.$and.forEach((i) => _.extend(item, i)); + } else { + _.extend(item, query); + } + this.updateDocument(item, update); + this.genId(item); + collection.insert(item); + cb(null, { inserted: 1 }); + } else { + cb(null, {}); + } + } catch (e) { + cb((e as Error).message); + console.error(e); + } + } +} diff --git a/storage/src/index.ts b/storage/src/index.ts new file mode 100644 index 0000000..7795da1 --- /dev/null +++ b/storage/src/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars +import { DataBase } from "@/Database"; diff --git a/storage/src/main.ts b/storage/src/main.ts new file mode 100644 index 0000000..a959064 --- /dev/null +++ b/storage/src/main.ts @@ -0,0 +1,3 @@ +export function helloWorld(): void { + console.log("Hello, World!"); +} diff --git a/storage/src/types.d.ts b/storage/src/types.d.ts new file mode 100644 index 0000000..d5ef4f4 --- /dev/null +++ b/storage/src/types.d.ts @@ -0,0 +1,16 @@ +type Data = { + $set?: { [key: string]: DataType }; + $merge?: { [key: string]: DataType }; + $inc?: { [key: string]: DataType }; + $unset?: { [key: string]: DataType }; + $addToSet?: { [key: string]: DataType }; + $pull?: { [key: string]: DataType }; + $and?: [DataType, DataType]; + $or?: [DataType, DataType]; + $not?: [DataType, DataType]; + _id?: string; + [op: keyof LokiOps]: DataType; + [propName: string]: DataType; +}; + +type DataType = object | number | string | null | Data; diff --git a/storage/tests/DataBase.test.ts b/storage/tests/DataBase.test.ts new file mode 100644 index 0000000..c935085 --- /dev/null +++ b/storage/tests/DataBase.test.ts @@ -0,0 +1,163 @@ +import { DataBase } from "@/Database"; +import fs from "fs/promises"; +import * as console from "console"; + +const OLD_ENV = process.env; + +let db: DataBase; +beforeEach(() => { + db = new DataBase(); + process.env = { ...OLD_ENV }; // Make a copy + process.env.DB_PATH = "test_db/db.json"; + fs.mkdir("test_db", { recursive: true }); + db.loadDb(); +}); + +afterEach(() => { + process.env = OLD_ENV; // Restore old environment + fs.rm("test_db", { recursive: true, force: true }); +}); + +test("DataBase", () => { + expect(db.db).not.toBeNull(); +}); + +test("DataBase updateDocument $set", () => { + const doc = {}; + const set1 = { $set: { a: 1 } }; + db.updateDocument(doc, set1); + expect(doc).toStrictEqual({ a: 1 }); + + const set2 = { $set: { a: 2, b: 2 } }; + db.updateDocument(doc, set2); + expect(doc).toStrictEqual({ a: 2, b: 2 }); + + const set3 = { $set: { c: { c1: 1, c2: 2 } } }; + db.updateDocument(doc, set3); + expect(doc).toStrictEqual({ a: 2, b: 2, c: { c1: 1, c2: 2 } }); +}); + +test("DataBase updateDocument $merge", () => { + const doc = { a: 1 }; + const merge1 = { $merge: { b: { b1: 1, b2: 1 } } }; + db.updateDocument(doc, merge1); + expect(doc).toStrictEqual({ a: 1, b: { b1: 1, b2: 1 } }); + const merge2 = { $merge: { b: { b3: 1 } } }; + db.updateDocument(doc, merge2); + expect(doc).toStrictEqual({ a: 1, b: { b1: 1, b2: 1, b3: 1 } }); +}); + +test("DataBase updateDocument $inc", () => { + const doc = { a: 1 }; + const inc1 = { $inc: { a: 1 } }; + db.updateDocument(doc, inc1); + expect(doc).toStrictEqual({ a: 2 }); + const inc2 = { $inc: { a: 1, b: 1 } }; + db.updateDocument(doc, inc2); + expect(doc).toStrictEqual({ a: 3, b: 1 }); +}); + +test("DataBase updateDocument $unset", () => { + const doc = { a: 1, b: 2, c: 3 }; + const unset1 = { $unset: { a: null } }; + db.updateDocument(doc, unset1); + expect(doc).toStrictEqual({ b: 2, c: 3 }); + const unset2 = { $unset: { b: null, c: null } }; + db.updateDocument(doc, unset2); + expect(doc).toStrictEqual({}); +}); + +test("DataBase updateDocument $addToSet", () => { + const doc = {}; + const addToSet1 = { $addToSet: { a: 1 } }; + db.updateDocument(doc, addToSet1); + expect(doc).toStrictEqual({ a: [1] }); + const addToSet2 = { $addToSet: { a: 2 } }; + db.updateDocument(doc, addToSet2); + expect(doc).toStrictEqual({ a: [1, 2] }); + const addToSet3 = { $addToSet: { b: 2, c: 3 } }; + db.updateDocument(doc, addToSet3); + expect(doc).toStrictEqual({ a: [1, 2], b: [2], c: [3] }); +}); + +test("DataBase updateDocument $pull", () => { + const doc = { a: [1, 2], b: [2], c: [3] }; + const addToSet1 = { $pull: { b: 2, c: 3 } }; + db.updateDocument(doc, addToSet1); + expect(doc).toStrictEqual({ a: [1, 2], b: [], c: [] }); + const addToSet2 = { $pull: { a: 2 } }; + db.updateDocument(doc, addToSet2); + expect(doc).toStrictEqual({ a: [1], b: [], c: [] }); + const addToSet3 = { $pull: { a: 1 } }; + db.updateDocument(doc, addToSet3); + expect(doc).toStrictEqual({ a: [], b: [], c: [] }); + const addToSet4 = { $pull: { d: 1 } }; + db.updateDocument(doc, addToSet4); + expect(doc).toStrictEqual({ a: [], b: [], c: [] }); +}); + +test("DataBase getRandomString", () => { + const str = db.getRandomString(); + expect(str.length).toBe(4); +}); + +test("DataBase genId", () => { + const obj = {}; + const str = db.genId(obj); + expect(str.length).toBe(15); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + expect(obj["_id"] as string).toBe(str); +}); + +test("DataBase getOrAddCollection", () => { + const collection = db.getOrAddCollection("users"); + expect(collection).not.toBeNull(); +}); + +test("DataBase recursReplaceNeNull", () => { + const notObject = ""; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + db.recursReplaceNeNull(notObject); + expect(notObject).toStrictEqual(""); + const eq = { $set: { $eq: null } }; + db.recursReplaceNeNull(eq); + expect(eq).toStrictEqual({ + $or: [{ $set: { $eq: null } }, { $set: { $eq: undefined } }], + }); + const ne = { $set: { $ne: null } }; + db.recursReplaceNeNull(ne); + expect(ne).toStrictEqual({ + $and: [{ $set: { $ne: null } }, { $set: { $ne: undefined } }], + }); +}); + +test("DataBase dbRequest", () => { + db.dbRequest("users", "insert", [{ name: "Loki", age: 10 }], (_, result) => + expect(result).not.toBeNull(), + ); + db.dbRequest("users", "find", [{ age: { $eq: 1 } }], (_, result) => + expect(result).not.toBeNull(), + ); +}); + +test("DataBase dbUpdate", () => { + db.dbRequest("users", "insert", [{ name: "Loki", age: 1 }], (_, result) => + expect(result).not.toBeNull(), + ); + db.dbUpdate( + "users", + { age: { $eq: 1 } }, + { $set: { name: "Thor", age: 35 } }, + { upsert: true }, + (_, result) => { + console.log(result); + expect(result).not.toBeNull(); + }, + ); + db.dbRequest("users", "find", [{ age: { $gt: 0 } }], (_, result) => { + console.log(result); + expect(result).not.toBeNull(); + }); +}); diff --git a/storage/tests/main.test.ts b/storage/tests/main.test.ts new file mode 100644 index 0000000..6bb4bcb --- /dev/null +++ b/storage/tests/main.test.ts @@ -0,0 +1,7 @@ +import { helloWorld } from "@/main"; + +test("Hello, World!", () => { + const logSpy = jest.spyOn(console, "log"); + helloWorld(); + expect(logSpy).toHaveBeenCalledWith("Hello, World!"); +}); diff --git a/storage/tsconfig.json b/storage/tsconfig.json new file mode 100644 index 0000000..baf4027 --- /dev/null +++ b/storage/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "alwaysStrict": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + }, + "include": [ + "src/**/*.ts", + "tests/**/*.ts", + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/storage/tsconfig.node.json b/storage/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/storage/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/storage/vite.config.ts b/storage/vite.config.ts new file mode 100644 index 0000000..308436b --- /dev/null +++ b/storage/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'vite' +import { resolve } from "node:path"; +import * as path from "path"; +import dts from "vite-plugin-dts"; + +export default defineConfig({ + build: { + lib: { + entry: resolve(__dirname, "src/index.ts"), + formats: ["es", "cjs"], + }, + sourcemap: true, + }, + resolve: { + alias: { + "@": path.join(__dirname, "src"), + }, + }, + optimizeDeps: { disabled: true }, + plugins: [ + dts({ + rollupTypes: true + }) + ] +})