Compare commits

...

65 Commits

Author SHA1 Message Date
155cd8bd6a 5.0.12 2024-04-14 02:10:29 +02:00
5eebd0fd02 fix(core): update 2024-04-14 02:10:29 +02:00
686aa0d2e7 5.0.11 2024-04-14 02:09:41 +02:00
f97d72da28 fix(core): update 2024-04-14 02:09:41 +02:00
78d1540ce0 update npmextra.json: githost 2024-04-01 21:33:26 +02:00
916dd116c1 update npmextra.json: githost 2024-04-01 19:57:30 +02:00
5fd57cb56b update npmextra.json: githost 2024-03-30 21:46:27 +01:00
1a106e322c 5.0.10 2024-02-13 02:10:21 +01:00
36ded40032 fix(core): update 2024-02-13 02:10:21 +01:00
44f5f84195 5.0.9 2024-02-13 02:09:00 +01:00
72655a6a0e fix(core): update 2024-02-13 02:08:59 +01:00
961df11121 5.0.8 2024-02-13 02:04:05 +01:00
ee6f5e63ee fix(core): update 2024-02-13 02:04:04 +01:00
a40b6adeef 5.0.7 2024-02-13 02:01:39 +01:00
6ee324a0ef fix(core): update 2024-02-13 02:01:39 +01:00
215a48a409 5.0.6 2024-02-13 01:54:51 +01:00
aeaa6149e4 fix(core): update 2024-02-13 01:54:50 +01:00
75059dfca8 5.0.5 2024-02-13 01:46:23 +01:00
90c0f30ce1 fix(core): update 2024-02-13 01:46:22 +01:00
9a55303978 5.0.4 2024-02-13 00:50:51 +01:00
224125fb8e fix(core): update 2024-02-13 00:50:50 +01:00
df9d197508 5.0.3 2024-02-13 00:48:45 +01:00
ae33716af4 fix(core): update 2024-02-13 00:48:44 +01:00
31b64eda5e 5.0.2 2024-02-12 20:09:27 +01:00
7f3437e3cd fix(core): update 2024-02-12 20:09:26 +01:00
8903bee78d 5.0.1 2024-02-12 19:16:58 +01:00
a02b45a673 fix(core): update 2024-02-12 19:16:57 +01:00
e7883f5997 5.0.0 2024-02-12 19:16:44 +01:00
39ab01b4af BREAKING CHANGE(core): update 2024-02-12 19:16:43 +01:00
bb9de1b13b 4.0.16 2024-02-12 18:40:01 +01:00
080e133e9f fix(core): update 2024-02-12 18:40:01 +01:00
a284c58a68 4.0.15 2024-02-10 04:55:51 +01:00
18bb54831d fix(core): update 2024-02-10 04:55:50 +01:00
141c7ed8a7 4.0.14 2024-02-10 04:54:01 +01:00
037481f195 fix(core): update 2024-02-10 04:54:00 +01:00
e414e392d3 4.0.13 2024-02-09 15:57:32 +01:00
4f7e382bc9 fix(core): update 2024-02-09 15:57:32 +01:00
1c0b428606 4.0.12 2024-02-09 13:47:52 +01:00
90e8625771 fix(core): update 2024-02-09 13:47:51 +01:00
abbce0d4a1 4.0.11 2024-02-09 11:52:31 +01:00
93c65acc95 fix(core): update 2024-02-09 11:52:30 +01:00
a68d59a4d2 4.0.10 2024-02-09 05:16:02 +01:00
0133dca698 fix(core): update 2024-02-09 05:16:02 +01:00
6174490e8e 4.0.9 2024-02-08 14:09:20 +01:00
d952a761b2 fix(core): update 2024-02-08 14:09:20 +01:00
05909f776e 4.0.8 2024-02-07 21:44:00 +01:00
779883fbab fix(core): update 2024-02-07 21:44:00 +01:00
349f074bb9 4.0.7 2024-02-07 18:16:41 +01:00
d209661586 fix(core): update 2024-02-07 18:16:40 +01:00
3ce6036478 4.0.6 2024-01-27 19:03:06 +01:00
54bf310403 fix(core): update 2024-01-27 19:03:06 +01:00
2ec485048b 4.0.5 2024-01-25 13:57:55 +01:00
caca370e77 fix(core): update 2024-01-25 13:57:55 +01:00
45deb1a8d2 4.0.4 2023-08-26 10:56:21 +02:00
4c9d3c7148 fix(core): update 2023-08-26 10:56:20 +02:00
320c627d4f 4.0.3 2023-08-26 09:56:21 +02:00
d834e0a220 fix(core): update 2023-08-26 09:56:20 +02:00
86427ac05d 4.0.2 2023-08-24 22:59:44 +02:00
dc59682c15 fix(core): update 2023-08-24 22:59:43 +02:00
45ebf0944c 4.0.1 2023-08-24 12:06:47 +02:00
677aa4f0ea fix(core): update 2023-08-24 12:06:46 +02:00
7f0985f24d 4.0.0 2023-08-24 12:02:25 +02:00
5f2f7e2b39 BREAKING CHANGE(core): update 2023-08-24 12:02:24 +02:00
26a6ac9651 3.0.13 2023-08-24 10:44:43 +02:00
072ee31c3f fix(core): update 2023-08-24 10:44:42 +02:00
11 changed files with 1423 additions and 1371 deletions

View File

@ -119,6 +119,6 @@ jobs:
run: |
npmci node install stable
npmci npm install
pnpm install -g @gitzone/tsdoc
pnpm install -g @git.zone/tsdoc
npmci command tsdoc
continue-on-error: true

View File

@ -11,12 +11,15 @@
"gitzone": {
"projectType": "npm",
"module": {
"githost": "gitlab.com",
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "npmextra",
"description": "do more with npm",
"npmPackagename": "@push.rocks/npmextra",
"license": "MIT"
}
},
"tsdocs": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@push.rocks/npmextra",
"version": "3.0.12",
"version": "5.0.12",
"private": false,
"description": "do more with npm",
"main": "dist_ts/index.js",
@ -21,19 +21,21 @@
},
"homepage": "https://gitlab.com/pushrocks/npmextra#README",
"dependencies": {
"@push.rocks/smartfile": "^10.0.30",
"@push.rocks/smartjson": "^5.0.8",
"@push.rocks/qenv": "^6.0.5",
"@push.rocks/smartfile": "^11.0.4",
"@push.rocks/smartjson": "^5.0.10",
"@push.rocks/smartlog": "^3.0.2",
"@push.rocks/smartpath": "^5.0.11",
"@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/taskbuffer": "^3.1.6"
"@push.rocks/smartrx": "^3.0.7",
"@push.rocks/taskbuffer": "^3.1.7"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.1.66",
"@gitzone/tsrun": "^1.2.44",
"@gitzone/tstest": "^1.0.77",
"@git.zone/tsbuild": "^2.1.66",
"@git.zone/tsrun": "^1.2.44",
"@git.zone/tstest": "^1.0.77",
"@push.rocks/tapbundle": "^5.0.15",
"@types/node": "^20.5.3"
"@types/node": "^20.11.17"
},
"files": [
"ts/**/*",

2516
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,3 @@
{"myKey":"myValue"}
{
"myKey": "myValue"
}

View File

@ -9,6 +9,10 @@ tap.test('should create a keyValueStore', async () => {
expect(myKeyValueStore).toBeInstanceOf(npmextra.KeyValueStore);
});
tap.test('should reset the keyValueStore', async () => {
await myKeyValueStore.reset();
});
tap.test('expect result to be empty', async () => {
let result = await myKeyValueStore.readAll();
expect(JSON.stringify(result)).toEqual('{}');

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/npmextra',
version: '3.0.12',
version: '5.0.12',
description: 'do more with npm'
}

View File

@ -1,29 +1,120 @@
import * as plugins from './npmextra.plugins.js';
import * as paths from './npmextra.paths.js';
import { KeyValueStore } from './npmextra.classes.keyvaluestore.js';
import { env } from 'process';
export class AppData {
public readyDeferred = plugins.smartpromise.defer();
public dirPathArg: string;
private kvStore: KeyValueStore;
constructor(pathArg?: string) {
this.init(pathArg);
export interface IAppDataOptions {
dirPath?: string;
requiredKeys?: string[];
/**
* kvStoreKey: 'MY_ENV_VAR'
*/
envMapping?: {
[key: string]: string | object;
};
}
export class AppData<T = any> {
/**
* creates appdata. If no pathArg is given, data will be stored here:
* ${PWD}/.nogit/appdata
* @param pathArg
* @returns
*/
public static async createAndInit<T = any>(optionsArg: IAppDataOptions = {}): Promise<AppData<T>> {
const appData = new AppData<T>(optionsArg);
await appData.readyDeferred.promise;
return appData;
}
// instance
public readyDeferred = plugins.smartpromise.defer();
public options: IAppDataOptions;
private kvStore: KeyValueStore<T>;
constructor(optionsArg: IAppDataOptions = {}) {
this.options = optionsArg;
this.init();
}
/**
* inits app data
* @param pathArg
*/
private async init(pathArg?: string) {
if (pathArg) {
this.dirPathArg = pathArg;
if (this.options.dirPath) {
// ok, nothing to do here;
} else {
const appDataDir = '/app/data';
const dataDir = '/data';
const nogitAppData = '.nogit/appdata';
const appDataExists = plugins.smartfile.fs.isDirectory(appDataDir);
const dataExists = plugins.smartfile.fs.isDirectory(dataDir);
if (appDataExists) {
this.dirPathArg = appDataDir;
this.dirPathArg = dataDir;
this.options.dirPath = appDataDir;
} else if (dataExists) {
this.options.dirPath = dataDir;
} else {
await plugins.smartfile.fs.ensureDir(nogitAppData);
this.options.dirPath = nogitAppData;
}
}
this.kvStore = new KeyValueStore('custom', 'appkv', this.dirPathArg);
this.kvStore = new KeyValueStore({
typeArg: 'custom',
identityArg: 'appkv',
customPath: this.options.dirPath,
mandatoryKeys: this.options.requiredKeys
});
if (this.options.envMapping) {
const qenvInstance = new plugins.qenv.Qenv(process.cwd(), plugins.path.join(process.cwd(), '.nogit'));
// Recursive function to handle nested objects, now includes key parameter
const processEnvMapping = async (key: string, mappingValue: any, parentKey: string = ''): Promise<any> => {
if (typeof mappingValue === 'string') {
let envValue: string;
if (mappingValue.startsWith('hard:')) {
envValue = mappingValue.replace('hard:', '');
} else {
envValue = await qenvInstance.getEnvVarOnDemand(mappingValue);
}
if (envValue) {
if (mappingValue.endsWith('_JSON')) {
envValue = JSON.parse(envValue);
}
if (!parentKey) {
await this.kvStore.writeKey(key, envValue);
} else {
return envValue;
}
} else {
return undefined;
}
} else if (typeof mappingValue === 'object' && mappingValue !== null) {
const resultObject = {};
for (const innerKey in mappingValue) {
const nestedValue = mappingValue[innerKey];
// For nested objects, call recursively but do not immediately write to kvStore
const nestedResult = await processEnvMapping(innerKey, nestedValue, key);
resultObject[innerKey] = nestedResult;
}
if (parentKey === '') {
// Only write to kvStore if at the top level
await this.kvStore.writeKey(key, resultObject);
} else {
// For nested objects, return the constructed object instead of writing to kvStore
return resultObject;
}
}
};
for (const key in this.options.envMapping) {
await processEnvMapping(key, this.options.envMapping[key]);
}
}
this.readyDeferred.resolve();
}
@ -34,4 +125,25 @@ export class AppData {
await this.readyDeferred.promise;
return this.kvStore;
}
}
public async logMissingKeys() {
const kvStore = await this.getKvStore();
const missingMandatoryKeys = await kvStore.getMissingMandatoryKeys();
if (missingMandatoryKeys.length > 0) {
console.log(
`The following mandatory keys are missing in the appdata:\n -> ${missingMandatoryKeys.join(
',\n -> '
)}`
);
} else {
console.log('All mandatory keys are present in the appdata');
}
return missingMandatoryKeys;
}
public async waitForAndGetKey(keyArg: string) {
await this.readyDeferred.promise;
await this.kvStore.waitForKeysPresent([keyArg]);
return this.kvStore.readKey[keyArg];
}
}

View File

@ -5,18 +5,30 @@ import { Task } from '@push.rocks/taskbuffer';
export type TKeyValueStore = 'custom' | 'userHomeDir';
export interface IKvStoreConstructorOptions {
typeArg: TKeyValueStore;
identityArg: string;
customPath?: string;
mandatoryKeys?: string[];
}
/**
* kvStore is a simple key value store to store data about projects between runs
*/
export class KeyValueStore {
private dataObject: any = {};
export class KeyValueStore<T = any> {
private dataObject: Partial<T> = {};
private deletedObject: any = {};
private mandatoryKeys: Set<string> = new Set();
public changeSubject = new plugins.smartrx.rxjs.Subject();
private storedStateString: string = '';
public syncTask = new Task({
name: 'syncTask',
buffered: true,
bufferMax: 1,
execDelay: 0,
taskFunction: async () => {
this.dataObject = {
...plugins.smartfile.fs.toObjectSync(this.filePath),
...this.dataObject,
@ -25,16 +37,27 @@ export class KeyValueStore {
delete this.dataObject[key];
}
this.deletedObject = {};
await plugins.smartfile.memory.toFs(plugins.smartjson.stringify(this.dataObject), this.filePath);
await plugins.smartfile.memory.toFs(
plugins.smartjson.stringifyPretty(this.dataObject),
this.filePath
);
const newStateString = plugins.smartjson.stringify(this.dataObject);
// change detection
if (newStateString !== this.storedStateString) {
this.storedStateString = newStateString;
this.changeSubject.next(this.dataObject);
}
},
});
/**
* computes the identity and filePath
*/
private initFilePath = () => {
if (this.customPath) { // Use custom path if provided
const absolutePath = plugins.smartpath.transform.makeAbsolute(this.customPath, paths.cwd)
if (this.customPath) {
// Use custom path if provided
const absolutePath = plugins.smartpath.transform.makeAbsolute(this.customPath, paths.cwd);
this.filePath = absolutePath;
if (plugins.smartfile.fs.isDirectorySync(this.filePath)) {
this.filePath = plugins.path.join(this.filePath, this.identity + '.json');
@ -42,7 +65,7 @@ export class KeyValueStore {
plugins.smartfile.fs.ensureFileSync(this.filePath, '{}');
return;
}
let baseDir: string;
if (this.type === 'userHomeDir') {
baseDir = paths.kvUserHomeDirBase;
@ -66,17 +89,20 @@ export class KeyValueStore {
* @param identityArg
* @param customPath Optional custom path for the keyValue store
*/
constructor(typeArg: TKeyValueStore, identityArg: string, customPath?: string) {
if (customPath && typeArg !== 'custom') {
constructor(optionsArg: IKvStoreConstructorOptions) {
if (optionsArg.customPath && optionsArg.typeArg !== 'custom') {
throw new Error('customPath can only be provided if typeArg is custom');
}
if (typeArg === 'custom' && !customPath) {
if (optionsArg.typeArg === 'custom' && !optionsArg.customPath) {
throw new Error('customPath must be provided if typeArg is custom');
}
this.type = typeArg;
this.identity = identityArg;
this.customPath = customPath; // Store custom path if provided
this.type = optionsArg.typeArg;
this.identity = optionsArg.identityArg;
this.customPath = optionsArg.customPath; // Store custom path if provided
this.initFilePath();
if (optionsArg.mandatoryKeys) {
this.setMandatoryKeys(optionsArg.mandatoryKeys);
}
}
/**
@ -124,4 +150,44 @@ export class KeyValueStore {
this.dataObject = {};
await plugins.smartfile.fs.remove(this.filePath);
}
/**
* resets the KeyValueStore to the initial state by syncing first, deleting all keys, and then triggering a sync again
*/
public async reset() {
await this.syncTask.trigger(); // Sync to get the latest state
// Delete all keys from the dataObject and add them to deletedObject
for (const key of Object.keys(this.dataObject)) {
this.deletedObject[key] = this.dataObject[key];
delete this.dataObject[key];
}
await this.syncTask.trigger(); // Sync again to reflect the deletion
}
private setMandatoryKeys(keys: string[]) {
keys.forEach(key => this.mandatoryKeys.add(key));
}
public async getMissingMandatoryKeys(): Promise<string[]> {
await this.readAll();
return Array.from(this.mandatoryKeys).filter(key => !(key in this.dataObject));
}
public async waitForKeysPresent(keysArg: string[]): Promise<void> {
const missingKeys = keysArg.filter(keyArg => !this.dataObject[keyArg]);
if (missingKeys.length === 0) {
return;
}
return new Promise((resolve, reject) => {
const subscription = this.changeSubject.subscribe(() => {
const missingKeys = keysArg.filter(keyArg => !this.dataObject[keyArg]);
if (missingKeys.length === 0) {
subscription.unsubscribe();
resolve();
}
});
});
}
}

View File

@ -1,9 +1,11 @@
import * as qenv from '@push.rocks/qenv';
import * as smartlog from '@push.rocks/smartlog';
import * as path from 'path';
import * as smartfile from '@push.rocks/smartfile';
import * as smartjson from '@push.rocks/smartjson';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartrx from '@push.rocks/smartrx';
import * as taskbuffer from '@push.rocks/taskbuffer';
export { smartlog, path, smartfile, smartjson, smartpath, smartpromise, taskbuffer };
export { qenv, smartlog, path, smartfile, smartjson, smartpath, smartpromise, smartrx, taskbuffer };

View File

@ -3,9 +3,12 @@
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "nodenext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true,
}
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}