@makano/rew 1.5.4 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/rew/const/default.js +4 -1
- package/lib/rew/functions/core.js +21 -2
- package/lib/rew/functions/curl.js +1 -1
- package/lib/rew/functions/import.js +14 -11
- package/lib/rew/functions/json.js +6 -2
- package/lib/rew/misc/findAppInfo.js +3 -3
- package/lib/rew/misc/findAppPath.js +3 -7
- package/lib/rew/misc/strace.js +1 -1
- package/lib/rew/modules/compiler.js +54 -42
- package/lib/rew/modules/context.js +6 -6
- package/lib/rew/modules/runtime.js +5 -4
- package/lib/rew/modules/yaml.js +9 -2
- package/lib/rew/pkgs/alpha.js +18 -0
- package/lib/rew/pkgs/conf.js +20 -3
- package/lib/rew/pkgs/modules/rune/db.js +9 -0
- package/lib/rew/pkgs/rune.js +179 -45
- package/lib/rew/pkgs/rune.schema.js +94 -0
- package/package.json +1 -1
package/lib/rew/const/default.js
CHANGED
@@ -6,7 +6,7 @@ const sleep = require('../functions/sleep');
|
|
6
6
|
const { match } = require('../functions/match');
|
7
7
|
const { map } = require('../functions/map');
|
8
8
|
const { typex, typeis, typedef, typei, int, float, num, str, bool, typef } = require('../functions/types');
|
9
|
-
const { isEmpty, clone, deepClone, merge, uniqueId, compose, curry, getters, setters, deepMerge } = require('../functions/core');
|
9
|
+
const { isEmpty, clone, deepClone, merge, uniqueId, compose, curry, getters, setters, deepMerge, randFrom, pickRandom } = require('../functions/core');
|
10
10
|
const { print, input, clear, printf } = require('../functions/stdout');
|
11
11
|
const { curl } = require('../functions/curl');
|
12
12
|
const { wait } = require('../functions/wait');
|
@@ -64,4 +64,7 @@ module.exports = {
|
|
64
64
|
print,
|
65
65
|
printf,
|
66
66
|
input,
|
67
|
+
|
68
|
+
randFrom,
|
69
|
+
pickRandom
|
67
70
|
};
|
@@ -114,7 +114,23 @@ function setters(object, setters) {
|
|
114
114
|
configurable: true
|
115
115
|
});
|
116
116
|
}
|
117
|
-
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
function withOut(object, ...keys){
|
121
|
+
let o = {...object};
|
122
|
+
for(let key of keys) delete o[key];
|
123
|
+
return o;
|
124
|
+
}
|
125
|
+
|
126
|
+
function randFrom(min,max) {
|
127
|
+
return Math.floor(Math.random()*(max-min+1)+min);
|
128
|
+
}
|
129
|
+
|
130
|
+
function pickRandom(...stuff){
|
131
|
+
return stuff[
|
132
|
+
randFrom(0, stuff.length - 1)
|
133
|
+
];
|
118
134
|
}
|
119
135
|
|
120
136
|
module.exports = {
|
@@ -129,5 +145,8 @@ module.exports = {
|
|
129
145
|
compose,
|
130
146
|
curry,
|
131
147
|
getters,
|
132
|
-
setters
|
148
|
+
setters,
|
149
|
+
withOut,
|
150
|
+
randFrom,
|
151
|
+
pickRandom
|
133
152
|
};
|
@@ -10,7 +10,7 @@ module.exports.curl = function curl(options, url){
|
|
10
10
|
if(options.url && !url){
|
11
11
|
url = options.url
|
12
12
|
}
|
13
|
-
const method = options.x || "GET";
|
13
|
+
const method = options.x || options.method || "GET";
|
14
14
|
const f = future.promise(fetch(url, {
|
15
15
|
...options,
|
16
16
|
method
|
@@ -20,7 +20,7 @@ module.exports.cleanCache = () => {
|
|
20
20
|
while(cachedFiles.length) cachedFiles.pop();
|
21
21
|
};
|
22
22
|
const lookUpInOtherApps = (fullPath) => {
|
23
|
-
straceLog('===> WARN:
|
23
|
+
straceLog('===> WARN: Lookup slows process');
|
24
24
|
const con = conf({});
|
25
25
|
const name = fullPath.indexOf('/') ? fullPath.split('/')[0] : fullPath;
|
26
26
|
let dpath = fullPath.indexOf('/') ? fullPath.split('/')[1] : '';
|
@@ -41,7 +41,7 @@ const lookUpInOtherApps = (fullPath) => {
|
|
41
41
|
};
|
42
42
|
|
43
43
|
module.exports.imp = function (runPath, context) {
|
44
|
-
return function (filename, options = {}) {
|
44
|
+
return function (filename, options = {}, defaultMode) {
|
45
45
|
if (!options) options = {};
|
46
46
|
if(filename == 'std' || filename == '#std') return {};
|
47
47
|
let type = options.type ? options.type : filename.endsWith('.coffee') ? 'coffee' : (
|
@@ -51,10 +51,10 @@ module.exports.imp = function (runPath, context) {
|
|
51
51
|
let exports,
|
52
52
|
ispkg = findPackage(filename);
|
53
53
|
|
54
|
-
straceLog('
|
54
|
+
straceLog('import file', '"' + filename + '"', 'as type', type);
|
55
55
|
|
56
56
|
if (filename.startsWith('@') && context.app) {
|
57
|
-
straceLog('===>
|
57
|
+
straceLog('===> from app root');
|
58
58
|
filename = filename.replace('@', context.app.path);
|
59
59
|
}
|
60
60
|
|
@@ -62,7 +62,7 @@ module.exports.imp = function (runPath, context) {
|
|
62
62
|
if(path.extname(filepath) == '.qrew') options.qrew = true;
|
63
63
|
|
64
64
|
const lookUp = () => {
|
65
|
-
straceLog('===>
|
65
|
+
straceLog('===> lookUp()');
|
66
66
|
const otherPath = lookUpInOtherApps(filename);
|
67
67
|
if (!otherPath) throw new Error('Module "' + filename + '" not found');
|
68
68
|
else filepath = otherPath;
|
@@ -80,7 +80,7 @@ module.exports.imp = function (runPath, context) {
|
|
80
80
|
typeof ext == 'string' ? existsSync(filepath + ext) : existsSync(filepath + (ext.ext || '')),
|
81
81
|
);
|
82
82
|
if (resolve) {
|
83
|
-
straceLog('===>
|
83
|
+
straceLog('===> resolve()');
|
84
84
|
filepath += typeof resolve == 'string' ? resolve : resolve.ext;
|
85
85
|
if (typeof resolve == 'object' && resolve.options) {
|
86
86
|
if (resolve.options.type) type = resolve.options.type;
|
@@ -91,7 +91,7 @@ module.exports.imp = function (runPath, context) {
|
|
91
91
|
}
|
92
92
|
|
93
93
|
const exec = (coptions = {}) => {
|
94
|
-
straceLog('===>
|
94
|
+
straceLog('===> execute(importFile)');
|
95
95
|
const r = runPath(
|
96
96
|
filepath,
|
97
97
|
{
|
@@ -113,7 +113,7 @@ module.exports.imp = function (runPath, context) {
|
|
113
113
|
}
|
114
114
|
|
115
115
|
if (ispkg) {
|
116
|
-
straceLog('===>
|
116
|
+
straceLog('===> findPackage()');
|
117
117
|
const pkg = getPackage(filename)(context, options);
|
118
118
|
exports = pkg._onImport ? pkg._onImport() : pkg;
|
119
119
|
if(options.useDefaultForPackages) exports = { default: exports };
|
@@ -124,10 +124,10 @@ module.exports.imp = function (runPath, context) {
|
|
124
124
|
} else if (type == 'js') {
|
125
125
|
exports = exec({ compile: false });
|
126
126
|
} else if (type == 'yaml' || type == 'json' || type == 'text') {
|
127
|
-
straceLog('===>
|
127
|
+
straceLog('===> getRawFile()');
|
128
128
|
const f = getFile(filepath);
|
129
129
|
if (type == 'yaml') {
|
130
|
-
straceLog('===>
|
130
|
+
straceLog('===> fromYaml()');
|
131
131
|
exports = _returns(options, importYaml(f.path, f));
|
132
132
|
} else if (type == 'json') {
|
133
133
|
straceLog('===>');
|
@@ -137,7 +137,7 @@ module.exports.imp = function (runPath, context) {
|
|
137
137
|
exports = _returns(options, {});
|
138
138
|
}
|
139
139
|
} else {
|
140
|
-
straceLog('===>
|
140
|
+
straceLog('===> fromText()');
|
141
141
|
exports = _returns(options, f.content);
|
142
142
|
}
|
143
143
|
}
|
@@ -168,6 +168,9 @@ module.exports.imp = function (runPath, context) {
|
|
168
168
|
/**/ if(options.mock === null) return null;
|
169
169
|
//**
|
170
170
|
|
171
|
+
//** Return defaults
|
172
|
+
/**/ if(defaultMode !== true && exports?.default) exports = exports.default;
|
173
|
+
|
171
174
|
return exports;
|
172
175
|
};
|
173
176
|
};
|
@@ -1,4 +1,5 @@
|
|
1
1
|
const jsYaml = require("js-yaml");
|
2
|
+
const { yamlFile } = require("../modules/yaml");
|
2
3
|
|
3
4
|
|
4
5
|
|
@@ -11,8 +12,11 @@ function jsons(thing){
|
|
11
12
|
}
|
12
13
|
|
13
14
|
|
14
|
-
function yaml(thing){
|
15
|
-
return
|
15
|
+
function yaml(thing, ...schema){
|
16
|
+
return yamlFile({
|
17
|
+
content: thing,
|
18
|
+
path: ''
|
19
|
+
}, schema);
|
16
20
|
}
|
17
21
|
|
18
22
|
function yamls(thing){
|
@@ -6,11 +6,11 @@ const { straceLog } = require('./strace');
|
|
6
6
|
|
7
7
|
module.exports.findAppInfo = function (filepath) {
|
8
8
|
const appPath = findAppPath(path.dirname(filepath));
|
9
|
-
straceLog('
|
9
|
+
straceLog('findAppInfo() for', filepath);
|
10
10
|
if (appPath) {
|
11
11
|
const config = jsYaml.load(readFileSync(path.join(appPath, 'app.yaml')));
|
12
|
-
straceLog('==>
|
13
|
-
straceLog('==>
|
12
|
+
straceLog('==> INFO Found config at:', '"' + appPath + '"');
|
13
|
+
straceLog('==> INFO App Package:', '"' + config?.manifest?.package + '"');
|
14
14
|
return {
|
15
15
|
path: appPath,
|
16
16
|
config,
|
@@ -3,23 +3,19 @@ const fs = require('fs'); // Import the 'path' module
|
|
3
3
|
const { straceLog } = require('./strace');
|
4
4
|
|
5
5
|
module.exports.findAppPath = (currentDir = __dirname) => {
|
6
|
-
|
7
|
-
straceLog('FINDAPP() for', currentDir);
|
6
|
+
straceLog('findApp() for', '"' + currentDir + '"');
|
8
7
|
const appYamlPath = path.join(currentDir, 'app.yaml');
|
9
8
|
if (fs.existsSync(appYamlPath)) {
|
10
9
|
|
11
|
-
straceLog('==>
|
10
|
+
straceLog('==> INFO found path', `"${appYamlPath}"`);
|
12
11
|
return currentDir;
|
13
12
|
}
|
14
13
|
|
15
|
-
// If not found, move up a directory level
|
16
14
|
const parentDir = path.dirname(currentDir);
|
17
15
|
|
18
|
-
// Check if we reached the root directory
|
19
16
|
if (parentDir === currentDir) {
|
20
|
-
return null;
|
17
|
+
return null;
|
21
18
|
}
|
22
19
|
|
23
|
-
// Recursively call the function on the parent directory
|
24
20
|
return module.exports.findAppPath(parentDir);
|
25
21
|
};
|
package/lib/rew/misc/strace.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module.exports.straceLog = function(...logs){
|
2
2
|
if(process.straceMode){
|
3
|
-
console.log(`[${new Date().
|
3
|
+
console.log(`[${new Date().toLocaleTimeString()} ${new Date().getDate()}/${new Date().getMonth()}/${new Date().getFullYear()}] [${process.pid}]`, ...logs.map(i => i.replace(/^([=>]+)/, '\x1b[34m$1\x1b[39m').replace(/WARN:/g, '\x1b[30m\x1b[43m WARN \x1b[39m\x1b[49m').replace(/INFO/g, '\x1b[30m\x1b[44m INFO \x1b[39m\x1b[49m').replace(/^"(.+)"$/, '\x1b[32m$1\x1b[39m').replace(/!([A-Z-+]+)/, (_, a) => `\x1b[30m\x1b[4${a.startsWith('-') ? '5' : a.startsWith('+') ? '6' : '2'}m ${a.replace(/^[-+]/, '')} \x1b[39m\x1b[49m`)));
|
4
4
|
}
|
5
5
|
}
|
@@ -137,15 +137,15 @@ const fnextToken = (i, tokens, type, value) => {
|
|
137
137
|
function declareAlias(aliases, token) {
|
138
138
|
const regex = /^#declare(\*)?\s+(\w+)\s+"([^"]+)"\s*=\s*([\s\S]*);$/;
|
139
139
|
const match = token.value.trim().match(regex);
|
140
|
-
straceLog('
|
141
|
-
straceLog('==>
|
140
|
+
straceLog('declareCase()');
|
141
|
+
straceLog('==> WARN: Experimental feature detected');
|
142
142
|
|
143
143
|
if (match) {
|
144
144
|
const isPublic = !!match[1];
|
145
145
|
const type = match[2] == "key" ? 'IDENTIFIER' : match[2];
|
146
146
|
let name = match[3];
|
147
147
|
let value = match[4].trim();
|
148
|
-
straceLog('==> DECLARE', name, 'as', value);
|
148
|
+
straceLog('==> INFO !DECLARE', name, 'as', value);
|
149
149
|
|
150
150
|
let aliasValue = value.startsWith('${')
|
151
151
|
? new Function('token', 'tokens', 'code', 'hooks', 'index', 'setIndex', value.slice(2, -1))
|
@@ -210,7 +210,7 @@ function declareAlias(aliases, token) {
|
|
210
210
|
aliases[type][name] = aliasValue;
|
211
211
|
|
212
212
|
if(isPublic){
|
213
|
-
straceLog('==>', '
|
213
|
+
straceLog('==>', 'INFO Declaration Globalized');
|
214
214
|
execOptions._syntaxAliases[type] = execOptions._syntaxAliases[type] || {};
|
215
215
|
execOptions._syntaxAliases[type][name] = aliasValue;
|
216
216
|
}
|
@@ -234,11 +234,11 @@ const stdTypes = (isPublic) => {
|
|
234
234
|
return r;
|
235
235
|
};
|
236
236
|
const includeFile = (includeContent, options) => {
|
237
|
-
straceLog('
|
237
|
+
straceLog('include()', includeContent);
|
238
238
|
const dontInclude = includeContent.startsWith('*');
|
239
239
|
if(dontInclude) {
|
240
240
|
includeContent = includeContent.slice(1);
|
241
|
-
straceLog('==>
|
241
|
+
straceLog('==> INFO ingoring output', includeContent);
|
242
242
|
};
|
243
243
|
const fp = path.resolve(path.dirname(options.filename || ''), includeContent);
|
244
244
|
let packageName = options.filename ? (existsSync(fp) ? fp : includeContent) : includeContent;
|
@@ -257,13 +257,13 @@ const includeFile = (includeContent, options) => {
|
|
257
257
|
if(packageName == 'std'){
|
258
258
|
r = _inc(stdTypes(dontInclude), true);
|
259
259
|
} else if (existsSync(packageName)) {
|
260
|
-
straceLog('==>
|
260
|
+
straceLog('==> includeFile(', '"'+packageName+'"', ')');
|
261
261
|
r = _inc(packageName);
|
262
262
|
} else {
|
263
263
|
const packageName = includeContent.match('/') ? includeContent.split('/')[0] : includeContent;
|
264
264
|
const headerFile = includeContent.match('/') ? includeContent.replace(packageName+'/', '') : 'main.h.coffee';
|
265
265
|
const pathname = path.join(CONFIG_PATH, packageName, 'app', headerFile);
|
266
|
-
straceLog('==>
|
266
|
+
straceLog('==> includePackage(', '"'+packageName+'"');
|
267
267
|
if(existsSync(pathname)) r = _inc(pathname);
|
268
268
|
}
|
269
269
|
if(dontInclude){
|
@@ -277,12 +277,12 @@ function useImp(token, options){
|
|
277
277
|
token.value.startsWith('"#') ||
|
278
278
|
token.value.startsWith("'#")
|
279
279
|
)){
|
280
|
-
straceLog('==>
|
280
|
+
straceLog('==> INFO imp() Uses HEADER');
|
281
281
|
const dem = token.value.slice(0, 1);
|
282
282
|
const value = token.value.slice(1, -1);
|
283
283
|
let packageName = value.slice(1);
|
284
284
|
token.value = dem+packageName+dem;
|
285
|
-
straceLog('
|
285
|
+
straceLog('imp() with header for', `"${packageName}"`);
|
286
286
|
return includeFile(packageName !== 'std' ? packageName : '*'+packageName, options);
|
287
287
|
}
|
288
288
|
return '';
|
@@ -344,7 +344,7 @@ function insertAt(array, index, ...values) {
|
|
344
344
|
}
|
345
345
|
|
346
346
|
function compileRewStuff(content, options) {
|
347
|
-
straceLog('
|
347
|
+
straceLog('tokeinze(currentFile)');
|
348
348
|
const tokens = tokenizeCoffeeScript(content);
|
349
349
|
let result = '';
|
350
350
|
let multilineDeclareBuffer = [];
|
@@ -360,11 +360,16 @@ function compileRewStuff(content, options) {
|
|
360
360
|
for (let i = 0; i < tokens.length; i++) {
|
361
361
|
const token = tokens[i];
|
362
362
|
let { token: nextToken, n } = gnextToken(i, 1, tokens) || {};
|
363
|
+
let { token: prevToken } = gnextToken(i, -2, tokens) || {};
|
363
364
|
|
364
365
|
if(token.type == "COMMENT" && i < 2 && token.value.startsWith('#!')){
|
365
366
|
continue;
|
366
367
|
}
|
367
368
|
|
369
|
+
if(token.type == "IDENTIFIER" && token.value == "fn" && i < 2 && prevToken?.value !== "." && nextToken?.type === "IDENTIFIER"){
|
370
|
+
token.value = "function";
|
371
|
+
}
|
372
|
+
|
368
373
|
if ((token.type === "COMMENT" && multilineDeclare) || (token.type !== "COMMENT" && multilineDeclare)) {
|
369
374
|
if(token.type === "COMMENT"){
|
370
375
|
multilineDeclareBuffer.push(token.value.startsWith('###') ? token.value.slice(3) : token.value.slice(1));
|
@@ -412,17 +417,17 @@ function compileRewStuff(content, options) {
|
|
412
417
|
|
413
418
|
if (token.type === 'COMMENT' && token.value.slice(1).trim().startsWith('@jsx')) {
|
414
419
|
options.jsx = true;
|
415
|
-
straceLog('
|
420
|
+
straceLog('jsx().with(comments)');
|
416
421
|
if(token.value.split('@jsx')[1].trim()){
|
417
422
|
options.jsxPragma = token.value.split('@jsx')[1].trim();
|
418
|
-
straceLog('
|
423
|
+
straceLog('jsx().withPragma(', `"${options.jsxPragma}"`, ')');
|
419
424
|
}
|
420
425
|
}
|
421
426
|
|
422
427
|
if (token.type === 'COMMENT' && token.value.slice(1).trim() === '@cls') {
|
423
428
|
options.cls = true;
|
424
|
-
straceLog('
|
425
|
-
straceLog('===> HIGHLY EXPERIMENTAL FEATURE DETECTED');
|
429
|
+
straceLog('cliSyntax::enable()');
|
430
|
+
straceLog('===> WARN: HIGHLY EXPERIMENTAL FEATURE DETECTED');
|
426
431
|
}
|
427
432
|
|
428
433
|
if (options.cls && token.type === 'OTHER' && token.value === '-' && nextToken.value == '-' && tokens[i-1]?.type == 'WHITESPACE') {
|
@@ -442,12 +447,12 @@ function compileRewStuff(content, options) {
|
|
442
447
|
|
443
448
|
if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'export' && !options.keepImports) {
|
444
449
|
token.value = 'pub';
|
445
|
-
straceLog('
|
450
|
+
straceLog('INFO !TRANSLATE converting export to pub');
|
446
451
|
}
|
447
452
|
|
448
453
|
if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'package' && nextToken.type == 'STRING') {
|
449
454
|
token.value = 'appPackage';
|
450
|
-
straceLog('
|
455
|
+
straceLog('changeAppPackage()');
|
451
456
|
}
|
452
457
|
|
453
458
|
if (
|
@@ -465,7 +470,7 @@ function compileRewStuff(content, options) {
|
|
465
470
|
}
|
466
471
|
|
467
472
|
if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'using' && !options.disableUse) {
|
468
|
-
straceLog('
|
473
|
+
straceLog('!+DIRECTIVE using()');
|
469
474
|
const next = nextToken?.value;
|
470
475
|
if(next in USING_DEFAULT) {
|
471
476
|
const { use } = USING_DEFAULT[next];
|
@@ -475,7 +480,7 @@ function compileRewStuff(content, options) {
|
|
475
480
|
|
476
481
|
const { token: nextNextToken } = gnextToken(i, 3, tokens) || {};
|
477
482
|
if(nextNextToken.value == "as") nextNextToken.value = ",";
|
478
|
-
} else straceLog('==> UNKNOWN');
|
483
|
+
} else straceLog('==> !-UNKNOWN');
|
479
484
|
}
|
480
485
|
|
481
486
|
if (token.type === 'IDENTIFIER' && token.value === 'as' && !options.keepImports) {
|
@@ -493,15 +498,15 @@ function compileRewStuff(content, options) {
|
|
493
498
|
|
494
499
|
if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && token.value === 'import' && !options.keepImports) {
|
495
500
|
// console.log(nextToken.type);
|
496
|
-
straceLog('
|
497
|
-
straceLog('==> WARN:
|
501
|
+
straceLog('import()');
|
502
|
+
straceLog('==> WARN: Slows compilation');
|
498
503
|
let ind = i + n + 2;
|
499
504
|
let isAs = false;
|
500
505
|
let usedDefault = false;
|
501
506
|
|
502
507
|
let defaultName;
|
503
508
|
if (nextToken.type === 'STRING') {
|
504
|
-
straceLog('==> SIMPLE');
|
509
|
+
straceLog('==> !SIMPLE');
|
505
510
|
if(useImp(nextToken, options)) updateAliases(aliases);
|
506
511
|
result += `inc ${nextToken.value}`;
|
507
512
|
i += n;
|
@@ -538,7 +543,7 @@ function compileRewStuff(content, options) {
|
|
538
543
|
.filter((t, i, arr) => !arr[i+1]?.match(':') && !arr[i-1]?.match(':'))
|
539
544
|
.join(', ');
|
540
545
|
|
541
|
-
straceLog('==>', exports, 'from', nameToken.value);
|
546
|
+
straceLog('==> !COMPLEX', exports, 'from', nameToken.value);
|
542
547
|
|
543
548
|
if(useImp(nameToken, options)) updateAliases(aliases);
|
544
549
|
result += `{ ${exports} } ${options.type == 'coffee' ? '=' : ':='} inc ${nameToken.value}`;
|
@@ -550,7 +555,7 @@ function compileRewStuff(content, options) {
|
|
550
555
|
const nameToken = fnextToken(asToken.ti, tokens, 'STRING');
|
551
556
|
const nextToken = fnextToken(asToken.ti + 1, tokens, 'IDENTIFIER');
|
552
557
|
defaultName = nextToken.value;
|
553
|
-
straceLog('==>', defaultName, 'from', nameToken.value);
|
558
|
+
straceLog('==> !COMPLEX', defaultName, 'from', nameToken.value);
|
554
559
|
if(useImp(nameToken, options)) updateAliases(aliases);
|
555
560
|
result += `${defaultName} ${options.type == 'coffee' ? '=' : ':='} inc ${nameToken.value}`;
|
556
561
|
i = ind + 6;
|
@@ -570,7 +575,7 @@ function compileRewStuff(content, options) {
|
|
570
575
|
.flat(1)
|
571
576
|
.filter((t, i, arr) => !arr[i+1]?.match(':') && !arr[i-1]?.match(':'))
|
572
577
|
.join(', ');
|
573
|
-
straceLog('==>', defaultName, 'and', exports, 'from', nameToken.value);
|
578
|
+
straceLog('==> !COMPLEX', defaultName, 'and', exports, 'from', nameToken.value);
|
574
579
|
if(useImp(nameToken, options)) updateAliases(aliases);
|
575
580
|
result += `{ default: ${defaultName}, ${exports} } ${options.type == 'coffee' ? '=' : ':='} inc ${nameToken?.value || ''}`;
|
576
581
|
i = closingBraceToken.ti + 4;
|
@@ -589,7 +594,7 @@ function compileRewStuff(content, options) {
|
|
589
594
|
if (nextLastToken?.value == 'assert') {
|
590
595
|
result += ', ';
|
591
596
|
const assertionToken = gnextToken(nextLastToken.ti, 2, tokens);
|
592
|
-
straceLog('==> ASSERT', assertionToken);
|
597
|
+
straceLog('==> !ASSERT', assertionToken);
|
593
598
|
if(assertionToken.token.type == 'OTHER' && assertionToken.token.value == '{'){
|
594
599
|
hooks.push({
|
595
600
|
index: assertionToken.token.ti,
|
@@ -607,7 +612,7 @@ function compileRewStuff(content, options) {
|
|
607
612
|
}
|
608
613
|
|
609
614
|
if (tokens[i-1]?.value !== '.' && token.type === 'IDENTIFIER' && (token.value === 'imp' || token.value === 'inc')) {
|
610
|
-
straceLog('
|
615
|
+
straceLog('!+DIRECTIVE imp()');
|
611
616
|
let { token: t1 } = gnextToken(i, 1, tokens) || {};
|
612
617
|
let { token: t2 } = gnextToken(i, 2, tokens) || {};
|
613
618
|
let r = '';
|
@@ -634,7 +639,7 @@ function compileRewStuff(content, options) {
|
|
634
639
|
nextToken.value &&
|
635
640
|
nextToken.value !== 'undefined' && !options.keepImports
|
636
641
|
) {
|
637
|
-
straceLog('
|
642
|
+
straceLog('!+DIRECTIVE pub()');
|
638
643
|
let next = {...nextToken}, isClass = false;
|
639
644
|
if(next.value == 'default'){
|
640
645
|
i += 2;
|
@@ -643,7 +648,14 @@ function compileRewStuff(content, options) {
|
|
643
648
|
next.value = gnextToken(i, n + 1, tokens)?.token.value || "default";
|
644
649
|
isClass = true;
|
645
650
|
}
|
646
|
-
|
651
|
+
if(next.value == 'fn' || next.value == 'function'){
|
652
|
+
next.value = gnextToken(i, n + 1, tokens)?.token.value || "default";
|
653
|
+
isClass = true;
|
654
|
+
if(nextToken && nextToken.value == "fn"){
|
655
|
+
nextToken.value = "function";
|
656
|
+
}
|
657
|
+
}
|
658
|
+
straceLog('==> !PUBLIC', next.value);
|
647
659
|
hooks.push({
|
648
660
|
index: i + 1,
|
649
661
|
value: `"${next.value}", ${isClass ? `${next.value} = ` : ''}`,
|
@@ -653,13 +665,13 @@ function compileRewStuff(content, options) {
|
|
653
665
|
const aliasType = aliases[token.type];
|
654
666
|
// if(token.value == 'sidewest') console.log(aliases, token.value, token.type);
|
655
667
|
if (aliasType && Object.keys(aliasType).includes(token.value)) {
|
656
|
-
straceLog('
|
668
|
+
straceLog('!+DIRECTIVE alias()', token.type);
|
657
669
|
const aliasValue = aliasType[token.value];
|
658
670
|
if (typeof aliasValue === 'function') {
|
659
|
-
straceLog('==>
|
671
|
+
straceLog('==> INFO Execute alias:', token.value);
|
660
672
|
result += aliasValue(token, tokens, result, hooks, i, (n) => i = n) || "";
|
661
673
|
} else {
|
662
|
-
straceLog('==>
|
674
|
+
straceLog('==> INFO Literal alias:', token.value);
|
663
675
|
result += aliasValue;
|
664
676
|
}
|
665
677
|
continue;
|
@@ -697,12 +709,12 @@ function compileRewStuff(content, options) {
|
|
697
709
|
}
|
698
710
|
|
699
711
|
const compileCivetStuff = (file, options) => {
|
700
|
-
straceLog('
|
712
|
+
straceLog('compileCivet(currentFile)');
|
701
713
|
const preCompileOptions = {
|
702
714
|
filename: file.path,
|
703
715
|
...options
|
704
716
|
};
|
705
|
-
straceLog('
|
717
|
+
straceLog('prepareOptions(currentFile).as(', `"${JSON.stringify(preCompileOptions)}"`, ')');
|
706
718
|
|
707
719
|
if(options?.type == 'js' || file?.path?.endsWith('.js')){
|
708
720
|
return {
|
@@ -724,7 +736,7 @@ const compileCivetStuff = (file, options) => {
|
|
724
736
|
};
|
725
737
|
|
726
738
|
let compiled = options.async ? compileCivet(prepared, compileOptions) : wait(compileCivet, prepared, compileOptions);
|
727
|
-
straceLog('==>
|
739
|
+
straceLog('==> !COMPILER civetCompile(fileContent)');
|
728
740
|
|
729
741
|
return {
|
730
742
|
compiled,
|
@@ -745,10 +757,10 @@ const cpl = (module.exports.compile = function (file, options = {}) {
|
|
745
757
|
compiledCode = result.compiled;
|
746
758
|
|
747
759
|
const babelify = (code, options) => {
|
748
|
-
straceLog('
|
749
|
-
if(doJSX) straceLog('==> WITH JSX');
|
750
|
-
if(doTypes) straceLog('==> WITH
|
751
|
-
if(doDecorators) straceLog('==> WITH DECORATORS');
|
760
|
+
straceLog('!COMPILER babel()');
|
761
|
+
if(doJSX) straceLog('==> INFO !-WITH JSX');
|
762
|
+
if(doTypes) straceLog('==> INFO !-WITH Types');
|
763
|
+
if(doDecorators) straceLog('==> INFO !-WITH DECORATORS');
|
752
764
|
return babel.transformSync(code, {
|
753
765
|
presets: [
|
754
766
|
...(doJSX ? [[babelReact, { throwIfNamespace: false, pragmaFrag: options.jsxPragmaFrag || execOptions.jsxPragmaFrag, pragma: options.jsxPragma || execOptions.jsxPragma }]] : [])
|
@@ -782,7 +794,7 @@ const cpl = (module.exports.compile = function (file, options = {}) {
|
|
782
794
|
});
|
783
795
|
|
784
796
|
module.exports.compileFile = function (filepath, options = {}) {
|
785
|
-
straceLog('
|
797
|
+
straceLog('compile(currentFile)');
|
786
798
|
const f = typeof filepath == "object" ? filepath : getFile(filepath);
|
787
799
|
if(typeof filepath == "object") filepath = filepath.path;
|
788
800
|
let qrew = false;
|
@@ -791,13 +803,13 @@ module.exports.compileFile = function (filepath, options = {}) {
|
|
791
803
|
qrew = true
|
792
804
|
f.content = from_qrew(readFileSync(f.path), options.package || findAppInfo(filepath)?.config.manifest.package || path.basename(filepath).split('.').slice(0, -1).join('.')).toString();
|
793
805
|
options.type = f.content.split('\n')[0]?.match(/"initFile (.+)"/)?.[1]?.split('.').pop();
|
794
|
-
straceLog('
|
806
|
+
straceLog('decodeCrew(currentFile).as(', `"${options.type}"`,')');
|
795
807
|
}
|
796
808
|
|
797
809
|
let compiled_code = cpl(f, { ...options });
|
798
810
|
|
799
811
|
if(options.onlyCompile && !qrew){
|
800
|
-
straceLog('
|
812
|
+
straceLog('writeAndQuit(compileData)');
|
801
813
|
if(compiled_code instanceof Promise){
|
802
814
|
compiled_code.then((r) => {
|
803
815
|
console.log(r);
|
@@ -25,7 +25,7 @@ module.exports.prepareContext = function (
|
|
25
25
|
filepath = "",
|
26
26
|
runPath = () => {},
|
27
27
|
) {
|
28
|
-
straceLog('
|
28
|
+
straceLog('!-NEW context()');
|
29
29
|
if (mainFile == "") mainFile = filepath;
|
30
30
|
/** @type {Record<string, any>} */
|
31
31
|
let context = {
|
@@ -82,7 +82,7 @@ module.exports.prepareContext = function (
|
|
82
82
|
this['@cb'] = cb;
|
83
83
|
}
|
84
84
|
});
|
85
|
-
}, out: {...process.stdout, cols: process.stdout.columns, rows: process.stdout.rows, put: (...logs) => context.print(...logs), strace: (...logs) => straceLog('==>
|
85
|
+
}, out: {...process.stdout, cols: process.stdout.columns, rows: process.stdout.rows, put: (...logs) => context.print(...logs), strace: (...logs) => straceLog('==> !+OUT straceOut(): ', ...logs ), write: (logs) => context.printf(logs+'\n') }, in: {...process.stdin, read: (...args) => context.input(...args)}, define: (name, object) => {
|
86
86
|
if(Array.isArray(name) && name.length == 2 && typeof name[0] == 'string'){
|
87
87
|
object = name[1];
|
88
88
|
name = name[0];
|
@@ -216,7 +216,7 @@ module.exports.prepareContext = function (
|
|
216
216
|
try {
|
217
217
|
if (package.startsWith("node:") || package.startsWith("pkg:"))
|
218
218
|
throw new Error("");
|
219
|
-
return context.imp(package, asserts);
|
219
|
+
return context.imp(package, asserts, true);
|
220
220
|
} catch (e) {
|
221
221
|
if(e.message.match('Module') && e.message.match('not found')){
|
222
222
|
let pname = package.startsWith("pkg:") ? package.split("pkg:")[1] : package;
|
@@ -242,14 +242,14 @@ module.exports.prepareContext = function (
|
|
242
242
|
if(context.app?.config?.exec?.['auto import']){
|
243
243
|
const autoipath = path.join(context.app.path, context.app.config?.exec?.['auto import']);
|
244
244
|
if(autoipath !== filepath){
|
245
|
-
straceLog('==>
|
245
|
+
straceLog('==> !ACTION autoImport()', autoipath);
|
246
246
|
const all = context.imp(path.relative(path.dirname(filepath), autoipath));
|
247
247
|
for(let i in all) context[i] = all[i];
|
248
248
|
}
|
249
249
|
}
|
250
250
|
|
251
251
|
if(!context.app){
|
252
|
-
straceLog('==>
|
252
|
+
straceLog('==> WARN: App not found');
|
253
253
|
context.appPackage = (packageName) => context.app = { config: { manifest: { package: packageName } } }
|
254
254
|
} else {
|
255
255
|
context.appPackage = context.mod = (packageName) => context.module.modset = packageName;
|
@@ -265,7 +265,7 @@ module.exports.prepareContext = function (
|
|
265
265
|
context.module.main ||
|
266
266
|
(options.fromMain == true && options.as == "main")
|
267
267
|
) {
|
268
|
-
straceLog('==>
|
268
|
+
straceLog('==> !MAIN', filepath);
|
269
269
|
context.opt = {
|
270
270
|
set: (key, value) => (execOptions[key] = value),
|
271
271
|
get: (key) => execOptions[key],
|
@@ -21,17 +21,17 @@ module.exports.runPath = function runPath(filepath, options = {}, custom_context
|
|
21
21
|
if(filepath.endsWith('.coffee')) options.type = 'coffee';
|
22
22
|
if(filepath.endsWith('.qrew')) options.type = 'qrew';
|
23
23
|
|
24
|
-
straceLog('
|
24
|
+
straceLog('!+DECLARE currentFile =', filepath, 'as', options.type || '!UNKNOWN');
|
25
25
|
|
26
26
|
if(options.import?.async) options.async = true;
|
27
|
-
if(options.async) straceLog('ASYNCMODE()
|
27
|
+
if(options.async) straceLog('==> !ASYNCMODE currentFile::async()');
|
28
28
|
let { compiled_code, file } = compileFile(options.code ? { content: options.code, path: filepath } : filepath, options);
|
29
|
-
straceLog('
|
29
|
+
straceLog('==> INFO Compile done with compileData');
|
30
30
|
// context.module.compiled = compiled_code;
|
31
31
|
// context.process.exit = (int) => process.exit(int);
|
32
32
|
|
33
33
|
const doCode = () => {
|
34
|
-
straceLog('
|
34
|
+
straceLog('runCode(compileData)');
|
35
35
|
const context = options.import?.takeThisContext ? custom_context : prepareContext(custom_context, options, file.path, runPath);
|
36
36
|
|
37
37
|
if(context.app){
|
@@ -51,6 +51,7 @@ module.exports.runPath = function runPath(filepath, options = {}, custom_context
|
|
51
51
|
let execd = exec(compiled_code, context, file.content);
|
52
52
|
|
53
53
|
if(context.module.main && (context.module.exports?.main || (typeof context.module.exports == "function" && context.module.exports.name == 'main'))){
|
54
|
+
straceLog('call(currentFile::mainFn)');
|
54
55
|
const mainFn = context.module.exports.main ?? context.module.exports;
|
55
56
|
let ctx = context;
|
56
57
|
if(mainFn._class){
|
package/lib/rew/modules/yaml.js
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
const yaml = require('js-yaml');
|
2
2
|
const path = require('path');
|
3
3
|
const { getFile } = require('./fs');
|
4
|
+
const { withOut } = require('../functions/core');
|
4
5
|
|
5
|
-
function yamlFile(file) {
|
6
|
+
function yamlFile(file, schemaProps) {
|
6
7
|
const schema = new yaml.Schema([
|
7
8
|
new yaml.Type('!import', {
|
8
9
|
kind: 'scalar',
|
@@ -20,11 +21,17 @@ function yamlFile(file) {
|
|
20
21
|
kind: 'scalar',
|
21
22
|
construct: (data) => (data == 'true' ? true : false),
|
22
23
|
}),
|
23
|
-
]
|
24
|
+
].concat(
|
25
|
+
(schemaProps || []).map((item) => new yaml.Type(item.key, {
|
26
|
+
...withOut(item, 'key')
|
27
|
+
}))
|
28
|
+
));
|
24
29
|
|
25
30
|
return file.content.startsWith('---') ? yaml.loadAll(file.content, { schema })[0] : yaml.load(file.content, { schema });
|
26
31
|
}
|
27
32
|
|
33
|
+
module.exports.yamlFile = yamlFile;
|
34
|
+
|
28
35
|
const importYaml = (module.exports.importYaml = function importYaml(filepath, file) {
|
29
36
|
if (!file) {
|
30
37
|
file = getFile(filepath);
|
@@ -0,0 +1,18 @@
|
|
1
|
+
const { pickRandom } = require("../const/default")
|
2
|
+
|
3
|
+
const alphabets = 'abcdefghijklmnopqrstuvwxyz';
|
4
|
+
const numericals = '0123456789';
|
5
|
+
|
6
|
+
module.exports = () => ({
|
7
|
+
alphabets,
|
8
|
+
numericals,
|
9
|
+
rn(length = 1){
|
10
|
+
return Array(length || 1).fill(0).map(() => pickRandom(...numericals.split(''))).join('');
|
11
|
+
},
|
12
|
+
rl(length = 1){
|
13
|
+
return Array(length || 1).fill(0).map(() => pickRandom(...alphabets.split(''))).join('');
|
14
|
+
},
|
15
|
+
rnl(length = 1){
|
16
|
+
return Array(length || 1).fill(0).map(() => pickRandom(...(alphabets + numericals).split(''))).join('');
|
17
|
+
}
|
18
|
+
})
|
package/lib/rew/pkgs/conf.js
CHANGED
@@ -3,6 +3,7 @@ const jsYaml = require('js-yaml');
|
|
3
3
|
const path = require('path');
|
4
4
|
const { CONFIG_PATH } = require('../const/config_path');
|
5
5
|
const { seededID } = require('../misc/seededid');
|
6
|
+
const { Usage } = require('../const/usage');
|
6
7
|
|
7
8
|
const createPackageRoot = (packageName) => {
|
8
9
|
const rootPath = path.join(CONFIG_PATH, packageName);
|
@@ -30,18 +31,22 @@ module.exports = (context) => ({
|
|
30
31
|
};
|
31
32
|
|
32
33
|
const setData = (optionCenter, key, value) => {
|
34
|
+
if(conf[optionCenter.name] === undefined) conf[optionCenter.name] = {};
|
35
|
+
// console.log(conf, optionCenter.name, key, value);
|
33
36
|
conf[optionCenter.name][key] = value;
|
34
37
|
fs.writeFileSync(optionCenter.root, dumpYaml(conf[optionCenter.name]));
|
35
38
|
return true;
|
36
39
|
};
|
37
40
|
|
38
41
|
const removeData = (optionCenter, key) => {
|
42
|
+
if(conf[optionCenter.name] === undefined) conf[optionCenter.name] = {};
|
39
43
|
delete conf[optionCenter.name][key];
|
40
44
|
fs.writeFileSync(optionCenter.root, dumpYaml(conf[optionCenter.name]));
|
41
45
|
return true;
|
42
46
|
};
|
43
47
|
|
44
48
|
const getData = (optionCenter, key) => {
|
49
|
+
if(conf[optionCenter.name] === undefined) conf[optionCenter.name] = {};
|
45
50
|
return conf[optionCenter.name][key];
|
46
51
|
};
|
47
52
|
|
@@ -88,7 +93,7 @@ module.exports = (context) => ({
|
|
88
93
|
get: (key, defaultValue) => getData(optionCenter, key) ?? defaultValue,
|
89
94
|
set: (key, value) => setData(optionCenter, key, value),
|
90
95
|
remove: (key) => removeData(optionCenter, key),
|
91
|
-
reset: () => fs.writeFileSync(optionCenter.root, dumpYaml(defaults))
|
96
|
+
reset: () => { fs.writeFileSync(optionCenter.root, dumpYaml(defaults)); conf[name] = defaults;},
|
92
97
|
getAll: (str = false) => (str ? dumpYaml(conf[name]) : conf[name]),
|
93
98
|
...optionCenter,
|
94
99
|
};
|
@@ -96,7 +101,7 @@ module.exports = (context) => ({
|
|
96
101
|
|
97
102
|
const defaultCenter = createOptionCenter('_default', { default: true });
|
98
103
|
|
99
|
-
|
104
|
+
const confNamespace = {
|
100
105
|
optionCenter: createOptionCenter,
|
101
106
|
staticFile: staticFile,
|
102
107
|
set: (key, value) => defaultCenter.set(key, value),
|
@@ -104,7 +109,19 @@ module.exports = (context) => ({
|
|
104
109
|
remove: (key) => defaultCenter.remove(key),
|
105
110
|
root: rootPath,
|
106
111
|
package: packageName,
|
107
|
-
loadYaml: (file) => jsYaml.load(fs.readFileSync(file, { encoding: 'utf-8' }))
|
112
|
+
loadYaml: (file) => jsYaml.load(fs.readFileSync(file, { encoding: 'utf-8' })),
|
113
|
+
prototype: {
|
114
|
+
class: (name, defaults = {}) => new Usage('conf::class', (cb) => {
|
115
|
+
const optionCenter = createOptionCenter(name, defaults);
|
116
|
+
return cb.call(confNamespace, optionCenter);
|
117
|
+
}),
|
118
|
+
center: (name, defaults = {}) => (cb) => new Usage('conf::class', () => {
|
119
|
+
const optionCenter = createOptionCenter(name, defaults);
|
120
|
+
return cb.call(confNamespace, optionCenter);
|
121
|
+
})
|
122
|
+
}
|
108
123
|
};
|
124
|
+
|
125
|
+
return confNamespace;
|
109
126
|
},
|
110
127
|
});
|
package/lib/rew/pkgs/rune.js
CHANGED
@@ -3,8 +3,11 @@ const { v4: uuidv4 } = require('uuid');
|
|
3
3
|
const path = require('path');
|
4
4
|
const { CONFIG_PATH } = require('../const/config_path');
|
5
5
|
const { serializeData, deserializeData, gen_key } = require('../misc/bin');
|
6
|
+
const RuneDB = require('./modules/rune/db');
|
7
|
+
const { typeis } = require('../const/default');
|
6
8
|
|
7
9
|
const ENCRYPTION_KEY = 'e6ad8b0792b9e0472ea44d1f3adfd1d503182efcce25991b05cc5ef83f307ffc';
|
10
|
+
const PAGE_LIMIT = 100;
|
8
11
|
|
9
12
|
class Change {
|
10
13
|
constructor(values) {
|
@@ -46,6 +49,37 @@ function getCollectionFromID(id) {
|
|
46
49
|
return eid(id.split('+')[0], -5);
|
47
50
|
}
|
48
51
|
|
52
|
+
function coltypedef(cb) {
|
53
|
+
const typedef = {};
|
54
|
+
const ctx = {
|
55
|
+
opt: (name, type, defaultValue) => {
|
56
|
+
typedef[name] = type;
|
57
|
+
if(typeof defaultValue !== "undefined"){
|
58
|
+
if(!typedef['@rune.default']){
|
59
|
+
typedef['@rune.default'] = {};
|
60
|
+
}
|
61
|
+
typedef['@rune.default'][name] = defaultValue;
|
62
|
+
}
|
63
|
+
},
|
64
|
+
req: (name, type, defaultValue) => {
|
65
|
+
if(!typedef['@rune.required']){
|
66
|
+
typedef['@rune.required'] = {};
|
67
|
+
}
|
68
|
+
typedef['@rune.required'][name] = true;
|
69
|
+
ctx.opt(name, type, defaultValue);
|
70
|
+
},
|
71
|
+
unique: (name, type, defaultValue) => {
|
72
|
+
if(!typedef['@rune.unique']){
|
73
|
+
typedef['@rune.unique'] = {};
|
74
|
+
}
|
75
|
+
typedef['@rune.unique'][name] = true;
|
76
|
+
ctx.req(name, type, defaultValue);
|
77
|
+
}
|
78
|
+
};
|
79
|
+
cb.call(ctx);
|
80
|
+
return typedef;
|
81
|
+
}
|
82
|
+
|
49
83
|
const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
50
84
|
const dbDirPath = path.join(dirname, dbName);
|
51
85
|
const mainFilePath = path.join(dbDirPath, 'main.bin');
|
@@ -109,10 +143,76 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
109
143
|
fs.writeFileSync(filePath, buffer);
|
110
144
|
};
|
111
145
|
|
112
|
-
const collection = (collectionName
|
146
|
+
const collection = (collectionName, {
|
147
|
+
model,
|
148
|
+
exclude
|
149
|
+
} = {}) => {
|
113
150
|
const collectionFilePath = path.join(dbDirPath, `${collectionName}.col`);
|
114
151
|
|
115
|
-
const
|
152
|
+
const validateFields = (definition, data, optional = false) => {
|
153
|
+
if(!definition){
|
154
|
+
return data;
|
155
|
+
}
|
156
|
+
|
157
|
+
const validatedData = {};
|
158
|
+
for (const [field, type] of Object.entries(definition)) {
|
159
|
+
if(field.startsWith('@rune.')) continue;
|
160
|
+
if(!data[field] && typeof definition['@rune.default']?.[field] !== "undefined") data[field] = definition['@rune.default']?.[field];
|
161
|
+
|
162
|
+
if(typeof data[field] == "function"){
|
163
|
+
data[field] = data[field](data, definition);
|
164
|
+
}
|
165
|
+
|
166
|
+
if (data[field] === undefined) {
|
167
|
+
if(optional) continue;
|
168
|
+
else if(definition['@rune.required']){
|
169
|
+
if(definition['@rune.required'][field]){
|
170
|
+
throw new ReferenceError(`Field ${field} is required, yet not provided.`)
|
171
|
+
} else continue;
|
172
|
+
} else continue;
|
173
|
+
}
|
174
|
+
|
175
|
+
const value = data[field];
|
176
|
+
if (!typeis(value, type) && value != type) {
|
177
|
+
throw new TypeError(`Invalid type for field "${field}". Expected ${
|
178
|
+
type?.type?.type || type?.type || type
|
179
|
+
}, got ${typeof value}`);
|
180
|
+
}
|
181
|
+
validatedData[field] = value;
|
182
|
+
}
|
183
|
+
return validatedData;
|
184
|
+
};
|
185
|
+
|
186
|
+
const validateUniqueFields = (record, data) => {
|
187
|
+
if(!model) return null;
|
188
|
+
if(!model['@rune.unique']) return null;
|
189
|
+
|
190
|
+
const uniqueFields = Object.keys(model['@rune.unique']);
|
191
|
+
|
192
|
+
return uniqueFields.find(
|
193
|
+
(field) => data.find(storedRecord => storedRecord[field] == record[field])
|
194
|
+
);
|
195
|
+
}
|
196
|
+
|
197
|
+
const applyFieldSelection = (record, select) => {
|
198
|
+
const newRecord = {...record};
|
199
|
+
if(exclude) for (const key of exclude) {
|
200
|
+
if (record[key]) delete newRecord[key];
|
201
|
+
}
|
202
|
+
if (!select) return newRecord;
|
203
|
+
const selectedRecord = {};
|
204
|
+
for (const key of Array.isArray(select) ? select : Object.keys(select)) {
|
205
|
+
if (record[key]) selectedRecord[key] = record[key];
|
206
|
+
}
|
207
|
+
return selectedRecord;
|
208
|
+
};
|
209
|
+
|
210
|
+
const insert = (record, fields) => {
|
211
|
+
|
212
|
+
if(Array.isArray(record)){
|
213
|
+
return record.map((item) => insert(item));
|
214
|
+
}
|
215
|
+
|
116
216
|
const mainData = readMainData();
|
117
217
|
if (!mainData.collections.includes(collectionName)) {
|
118
218
|
mainData.collections.push(collectionName);
|
@@ -123,20 +223,27 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
123
223
|
if (fs.existsSync(collectionFilePath)) {
|
124
224
|
data = readDataFile(collectionFilePath);
|
125
225
|
}
|
226
|
+
if(model){
|
227
|
+
record = validateFields(model, record);
|
228
|
+
const invalidUniqueFields = validateUniqueFields(record, data);
|
229
|
+
if(invalidUniqueFields){
|
230
|
+
throw new ReferenceError(`Duplicate value for field ${invalidUniqueFields}`);
|
231
|
+
}
|
232
|
+
}
|
126
233
|
const id = uuidv4();
|
127
234
|
record['@rune.id'] = generateID(id, collectionName);
|
128
235
|
data.push(record);
|
129
236
|
writeDataFile(collectionFilePath, data);
|
130
|
-
return record;
|
237
|
+
return applyFieldSelection(record, fields);
|
131
238
|
};
|
132
239
|
|
133
|
-
const read = (id,
|
240
|
+
const read = (id, fields) => {
|
134
241
|
if (typeof id == 'object' && '@rune.id' in id) id = id['@rune.id'];
|
135
242
|
if (!fs.existsSync(collectionFilePath)) return null;
|
136
243
|
const data = readDataFile(collectionFilePath);
|
137
244
|
const record = data.find((record) => record['@rune.id'] === id);
|
138
245
|
if (record) {
|
139
|
-
return evaluateRecord(record);
|
246
|
+
return applyFieldSelection(evaluateRecord(record), fields);
|
140
247
|
}
|
141
248
|
return null;
|
142
249
|
};
|
@@ -168,34 +275,29 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
168
275
|
return record;
|
169
276
|
};
|
170
277
|
|
171
|
-
const update = (caseRecord, newRecord) => {
|
172
|
-
|
173
|
-
let id;
|
174
|
-
if (typeof caseRecord === 'string') {
|
175
|
-
id = caseRecord;
|
176
|
-
} else if (typeof caseRecord === 'object') {
|
177
|
-
const data = readDataFile(collectionFilePath);
|
178
|
-
const record = data.find((record) => {
|
179
|
-
for (const key in caseRecord) {
|
180
|
-
if (record[key] !== caseRecord[key]) return false;
|
181
|
-
}
|
182
|
-
return true;
|
183
|
-
});
|
184
|
-
if (record) {
|
185
|
-
id = record['@rune.id'];
|
186
|
-
} else {
|
187
|
-
return null; // No matching record found
|
188
|
-
}
|
189
|
-
}
|
190
|
-
|
191
|
-
if (!id) return null;
|
192
|
-
|
278
|
+
const update = (caseRecord, newRecord, limit = 0, fields) => {
|
279
|
+
let updatedRecords = [];
|
193
280
|
const data = readDataFile(collectionFilePath);
|
194
|
-
const
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
281
|
+
const validatedNewRecord = model ? validateFields(model, newRecord, true) : newRecord;
|
282
|
+
const invalidUniqueFields = validateUniqueFields(validatedNewRecord, data);
|
283
|
+
if(invalidUniqueFields){
|
284
|
+
throw new ReferenceError(`Duplicate value for field ${invalidUniqueFields}`);
|
285
|
+
}
|
286
|
+
|
287
|
+
const matches = data.filter((record) => {
|
288
|
+
if (typeof caseRecord === 'string') {
|
289
|
+
return record['@rune.id'] === caseRecord;
|
290
|
+
} else if (typeof caseRecord === 'object') {
|
291
|
+
return Object.keys(caseRecord).every((key) => record[key] === caseRecord[key]);
|
292
|
+
}
|
293
|
+
return false;
|
294
|
+
});
|
295
|
+
if (matches.length === 0) return null;
|
296
|
+
|
297
|
+
matches.forEach((oldRecord, index) => {
|
298
|
+
if(limit > 0 && updatedRecords.length > limit) return;
|
299
|
+
for (const key in validatedNewRecord) {
|
300
|
+
const value = validatedNewRecord[key];
|
199
301
|
if (value instanceof PushChange) {
|
200
302
|
if (!oldRecord[key] || !Array.isArray(oldRecord[key])) {
|
201
303
|
oldRecord[key] = [];
|
@@ -211,17 +313,17 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
211
313
|
});
|
212
314
|
}
|
213
315
|
} else {
|
214
|
-
oldRecord[key] = value;
|
316
|
+
oldRecord[key] = typeof value == "function" ? value(oldRecord, index) : value;
|
215
317
|
}
|
216
318
|
}
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
return
|
319
|
+
updatedRecords.push(applyFieldSelection(evaluateRecord(oldRecord), fields));
|
320
|
+
});
|
321
|
+
writeDataFile(collectionFilePath, data);
|
322
|
+
|
323
|
+
return updatedRecords;
|
222
324
|
};
|
223
325
|
|
224
|
-
const find = (criteria) => {
|
326
|
+
const find = (criteria, fields, limit = 0, index = 0) => {
|
225
327
|
if (typeof criteria == 'string') return read(criteria);
|
226
328
|
if (!criteria || typeof criteria !== 'object') return null;
|
227
329
|
|
@@ -230,19 +332,19 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
230
332
|
|
231
333
|
const data = readDataFile(collectionFilePath);
|
232
334
|
const record =
|
233
|
-
data
|
335
|
+
data[limit > 0 || limit == -1 ? 'filter' : 'find']((record) => {
|
234
336
|
for (const key in criteria) {
|
235
337
|
if (record[key] !== criteria[key]) return false;
|
236
338
|
}
|
237
339
|
return true;
|
238
340
|
}) || null;
|
239
341
|
if (record) {
|
240
|
-
return evaluateRecord(record);
|
342
|
+
return Array.isArray(record) ? (limit > 0 ? record.slice(index, index + limit) : record).map(i => applyFieldSelection(evaluateRecord(i), fields)) : applyFieldSelection(evaluateRecord(record), fields);
|
241
343
|
}
|
242
344
|
return null;
|
243
345
|
};
|
244
346
|
|
245
|
-
const
|
347
|
+
const removeOne = (id) => {
|
246
348
|
if ('@rune.id' in id) id = id['@rune.id'];
|
247
349
|
let data = readDataFile(collectionFilePath);
|
248
350
|
const index = data.findIndex((record) => record['@rune.id'] === id);
|
@@ -254,10 +356,34 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
254
356
|
return false;
|
255
357
|
};
|
256
358
|
|
257
|
-
const
|
359
|
+
const remove = (criteria, limit = Infinity) => {
|
360
|
+
let data = readDataFile(collectionFilePath);
|
361
|
+
let deletedCount = 0;
|
362
|
+
|
363
|
+
const filteredData = data.filter((record, index) => {
|
364
|
+
if (deletedCount >= limit) return true;
|
365
|
+
|
366
|
+
const matches = Object.keys(criteria).every((key) => typeof criteria[key] == 'function' ? criteria[key](record[key], record, index) : record[key] === criteria[key]);
|
367
|
+
if (matches) {
|
368
|
+
deletedCount++;
|
369
|
+
return false;
|
370
|
+
}
|
371
|
+
|
372
|
+
return true;
|
373
|
+
});
|
374
|
+
|
375
|
+
if (deletedCount === 0) return false;
|
376
|
+
|
377
|
+
writeDataFile(collectionFilePath, filteredData);
|
378
|
+
|
379
|
+
return true;
|
380
|
+
};
|
381
|
+
|
382
|
+
|
383
|
+
const list = (fields) => {
|
258
384
|
if (!fs.existsSync(collectionFilePath)) return [];
|
259
385
|
const data = readDataFile(collectionFilePath);
|
260
|
-
return data.map((rec) => evaluateRecord(rec));
|
386
|
+
return data.map((rec) => applyFieldSelection(evaluateRecord(rec), fields));
|
261
387
|
};
|
262
388
|
|
263
389
|
const map = (cb, mutate = false) => {
|
@@ -296,6 +422,10 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
296
422
|
return sortedData;
|
297
423
|
};
|
298
424
|
|
425
|
+
const empty = () => {
|
426
|
+
writeDataFile(collectionFilePath, []);
|
427
|
+
}
|
428
|
+
|
299
429
|
if (!fs.existsSync(collectionFilePath)) writeDataFile(collectionFilePath, []);
|
300
430
|
|
301
431
|
return {
|
@@ -303,12 +433,14 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
303
433
|
read,
|
304
434
|
update,
|
305
435
|
remove,
|
436
|
+
removeOne,
|
306
437
|
find,
|
307
438
|
map,
|
308
439
|
transform,
|
309
440
|
filter,
|
310
441
|
sort,
|
311
442
|
list,
|
443
|
+
empty
|
312
444
|
};
|
313
445
|
};
|
314
446
|
|
@@ -387,9 +519,11 @@ const createDB = (dbName, dirname, dbData = {}, encryptionKey) => {
|
|
387
519
|
return { set, get, remove, list, transform };
|
388
520
|
};
|
389
521
|
|
522
|
+
collection.type = coltypedef;
|
523
|
+
|
390
524
|
readMainData();
|
391
525
|
|
392
|
-
return { setData, getData, collection, findRef, makeRef, map };
|
526
|
+
return new RuneDB({ setData, getData, collection, findRef, makeRef, map });
|
393
527
|
};
|
394
528
|
|
395
529
|
module.exports = (context) => ({
|
@@ -0,0 +1,94 @@
|
|
1
|
+
const { typeis } = require("../const/default");
|
2
|
+
const RuneDB = require("./modules/rune/db");
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module.exports = (context) => ({
|
7
|
+
schema(runeDB) {
|
8
|
+
if (!runeDB) throw new ReferenceError('You should pass a rune database for the schema.');
|
9
|
+
if (!(runeDB instanceof RuneDB)) throw new TypeError('First argument is not a Rune database.');
|
10
|
+
|
11
|
+
const models = {};
|
12
|
+
|
13
|
+
const validateFields = (definition, data) => {
|
14
|
+
const validatedData = {};
|
15
|
+
for (const [field, type] of Object.entries(definition)) {
|
16
|
+
if (data[field] === undefined) continue;
|
17
|
+
const value = data[field];
|
18
|
+
if (!typeis(value, type) && value != type) {
|
19
|
+
throw new TypeError(`Invalid type for field "${field}". Expected ${
|
20
|
+
type?.type?.type || type?.type || type
|
21
|
+
}, got ${typeof value}`);
|
22
|
+
}
|
23
|
+
validatedData[field] = value;
|
24
|
+
}
|
25
|
+
return validatedData;
|
26
|
+
};
|
27
|
+
|
28
|
+
const applyFieldSelection = (record, select) => {
|
29
|
+
if (!select) return record;
|
30
|
+
if (Array.isArray(select)) select = Object.fromEntries(select.map(i => [i, true]));
|
31
|
+
const selectedRecord = {};
|
32
|
+
for (const key of Object.keys(select)) {
|
33
|
+
if (select[key]) selectedRecord[key] = record[key];
|
34
|
+
}
|
35
|
+
return selectedRecord;
|
36
|
+
};
|
37
|
+
|
38
|
+
return {
|
39
|
+
model(modelName, definition, options = {}) {
|
40
|
+
if (models[modelName]) throw new Error(`Model "${modelName}" is already defined.`);
|
41
|
+
|
42
|
+
const collection = runeDB.collection(modelName);
|
43
|
+
|
44
|
+
const modelAPI = {
|
45
|
+
create(record) {
|
46
|
+
const validatedRecord = validateFields(definition, record);
|
47
|
+
return collection.insert(validatedRecord);
|
48
|
+
},
|
49
|
+
|
50
|
+
findUnique(id, select) {
|
51
|
+
const record = collection.read(id);
|
52
|
+
if (!record) return null;
|
53
|
+
|
54
|
+
let finalRecord = record;
|
55
|
+
return applyFieldSelection(finalRecord, select);
|
56
|
+
},
|
57
|
+
|
58
|
+
findMany(where, select, cursor, count = 0) {
|
59
|
+
|
60
|
+
const records = collection.find(where, count == 0 ? -1 : count, cursor);
|
61
|
+
|
62
|
+
return select
|
63
|
+
? records.map((record) => applyFieldSelection(record, select))
|
64
|
+
: records;
|
65
|
+
},
|
66
|
+
|
67
|
+
update(identifier, updates, limit) {
|
68
|
+
return collection.update(identifier, updates, limit);
|
69
|
+
},
|
70
|
+
|
71
|
+
delete(identifier, limit) {
|
72
|
+
return collection.remove(identifier, limit);
|
73
|
+
},
|
74
|
+
|
75
|
+
list() {
|
76
|
+
return collection.list();
|
77
|
+
},
|
78
|
+
|
79
|
+
empty(){
|
80
|
+
return collection.empty();
|
81
|
+
}
|
82
|
+
};
|
83
|
+
|
84
|
+
models[modelName] = modelAPI;
|
85
|
+
return modelAPI;
|
86
|
+
},
|
87
|
+
|
88
|
+
useModel(modelName) {
|
89
|
+
if (!models[modelName]) throw new Error(`Model "${modelName}" is not defined.`);
|
90
|
+
return models[modelName];
|
91
|
+
},
|
92
|
+
};
|
93
|
+
},
|
94
|
+
});
|