@makano/rew 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -1
- package/bin/ui +0 -0
- package/build.sh +3 -1
- package/lib/rew/cli/cli.js +54 -36
- package/lib/rew/cli/utils.js +1 -0
- package/lib/rew/const/config_path.js +5 -0
- package/lib/rew/functions/import.js +6 -1
- package/lib/rew/misc/findAppInfo.js +16 -0
- package/lib/rew/misc/findAppPath.js +21 -0
- package/lib/rew/misc/seededid.js +15 -0
- package/lib/rew/modules/context.js +2 -1
- package/lib/rew/pkgs/conf.js +9 -2
- package/lib/rew/pkgs/rune.js +376 -0
- package/meson.build +13 -0
- package/package.json +9 -2
package/README.md
CHANGED
@@ -12,7 +12,7 @@ Rew
|
|
12
12
|
<a href="https://www.npmjs.com/package/rayous"> <img src="https://img.shields.io/npm/v/@makano/rew?style=for-the-badge&logo=npm&color=b4befe&logoColor=9399b2&labelColor=181825" alt="npm version" /></a>
|
13
13
|
</p>
|
14
14
|
|
15
|
-
|
15
|
+
Rew is a simple lightweight coffeescript runtime, made to simply using coffescript and revive it
|
16
16
|
in the process.
|
17
17
|
|
18
18
|
## Getting Started
|
package/bin/ui
CHANGED
Binary file
|
package/build.sh
CHANGED
@@ -3,4 +3,6 @@ opath=./bin/ui
|
|
3
3
|
if [ $1 ]; then
|
4
4
|
opath=$1
|
5
5
|
fi
|
6
|
-
g++ ./cpp/ui.cpp -o $opath `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0 libwebsockets jsoncpp`
|
6
|
+
# g++ ./cpp/ui.cpp -o $opath `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0 libwebsockets jsoncpp`
|
7
|
+
meson build
|
8
|
+
cd build && ninja && mv ./ui $opath && cd ../ && rm -r ./build
|
package/lib/rew/cli/cli.js
CHANGED
@@ -8,12 +8,13 @@ const { watch } = require('chokidar');
|
|
8
8
|
const utils = require('./utils');
|
9
9
|
const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs');
|
10
10
|
const { log } = require('./log');
|
11
|
-
const {
|
11
|
+
const { compile } = require('../modules/compiler');
|
12
|
+
const crypto = require('crypto');
|
12
13
|
|
13
14
|
yargs(hideBin(process.argv))
|
14
15
|
.command(
|
15
|
-
'$0 <file>',
|
16
|
-
'Run the specified file',
|
16
|
+
'$0 <file>',
|
17
|
+
'Run the specified file',
|
17
18
|
(yargs) => {
|
18
19
|
yargs
|
19
20
|
.positional('file', {
|
@@ -28,36 +29,36 @@ yargs(hideBin(process.argv))
|
|
28
29
|
},
|
29
30
|
(argv) => {
|
30
31
|
const filePath = path.resolve(process.cwd(), argv.file);
|
31
|
-
if(!existsSync(filePath)){
|
32
|
+
if (!existsSync(filePath)) {
|
32
33
|
log('File not found:', argv.file, ':end');
|
33
34
|
return;
|
34
35
|
}
|
35
36
|
const watching = [];
|
36
37
|
const watchIt = (file) => {
|
37
|
-
if(watching.includes(file)) return;
|
38
|
+
if (watching.includes(file)) return;
|
38
39
|
watch(file).on('change', () => runIt());
|
39
40
|
watching.push(file);
|
40
41
|
}
|
41
42
|
let prevFork;
|
42
43
|
const runIt = () => {
|
43
|
-
if(argv.watch) console.clear();
|
44
|
-
if(prevFork && !prevFork.killed) prevFork.kill?.();
|
44
|
+
if (argv.watch) console.clear();
|
45
|
+
if (prevFork && !prevFork.killed) prevFork.kill?.();
|
45
46
|
prevFork = fork(path.resolve(__dirname, './run.js'))
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if(argv.watch) watchIt(filePath);
|
47
|
+
.on('message', (data) => {
|
48
|
+
if (argv.watch) {
|
49
|
+
data.forEach(file => {
|
50
|
+
watchIt(file);
|
51
|
+
});
|
52
|
+
}
|
53
|
+
}).send({ filePath, watch: argv.watch });
|
54
|
+
if (argv.watch) watchIt(filePath);
|
54
55
|
}
|
55
56
|
runIt();
|
56
57
|
}
|
57
58
|
)
|
58
59
|
.command(
|
59
|
-
'conf <command> [path] [key] [value]',
|
60
|
-
'Configuration management',
|
60
|
+
'conf <command> [path] [key] [value]',
|
61
|
+
'Configuration management',
|
61
62
|
(yargs) => {
|
62
63
|
yargs
|
63
64
|
.positional('command', {
|
@@ -84,51 +85,68 @@ yargs(hideBin(process.argv))
|
|
84
85
|
(argv) => {
|
85
86
|
const { command, path, key, value } = argv;
|
86
87
|
const result = utils.conf(command, path, key, value);
|
87
|
-
if(result) console.log(result);
|
88
|
+
if (result) console.log(result);
|
88
89
|
}
|
89
90
|
)
|
90
|
-
.command('create <path>',
|
91
|
+
.command('create <path>', 'Create a new project', (yargs) => {
|
91
92
|
yargs
|
92
93
|
.positional('path', {
|
93
94
|
describe: 'Path of the project to create',
|
94
95
|
type: 'string',
|
95
96
|
});
|
96
|
-
|
97
|
+
},
|
97
98
|
(argv) => {
|
98
99
|
utils.createProject(argv.path);
|
99
100
|
}
|
100
101
|
)
|
101
|
-
.command('
|
102
|
+
.command('rune-keygen <secret>', 'Generate a rune encryption key', (yargs) => {
|
103
|
+
yargs.option('secret', {
|
104
|
+
describe: 'Secret used to generate encryption key',
|
105
|
+
type: 'string'
|
106
|
+
});
|
107
|
+
}, (argv) => {
|
108
|
+
const generateEncryptionKey = (secret) => {
|
109
|
+
if (secret) {
|
110
|
+
return crypto.createHash('sha256').update(secret).digest('hex');
|
111
|
+
} else {
|
112
|
+
return crypto.randomBytes(32).toString('hex');
|
113
|
+
}
|
114
|
+
};
|
115
|
+
|
116
|
+
const encryptionKey = generateEncryptionKey(argv.secret);
|
117
|
+
console.log('Encryption Key:', encryptionKey);
|
118
|
+
})
|
119
|
+
.command('ui-bin <path>', 'Build the UI bin for your own app', (yargs) => {
|
102
120
|
yargs
|
103
121
|
.positional('path', {
|
104
122
|
describe: 'Path of the output bin',
|
105
123
|
type: 'string',
|
106
124
|
});
|
107
|
-
|
125
|
+
},
|
108
126
|
(argv) => {
|
109
|
-
execSync('sh '+path.resolve(__dirname, '../../../build.sh')+' '+argv.path);
|
127
|
+
execSync('sh ' + path.resolve(__dirname, '../../../build.sh') + ' ' + argv.path);
|
110
128
|
}
|
111
129
|
)
|
112
|
-
.command('run <path | package>',
|
130
|
+
.command('run <path | package>', 'Run an app', (yargs) => {
|
113
131
|
yargs
|
114
132
|
.positional('path', {
|
115
133
|
describe: 'Path of the app to run',
|
116
134
|
type: 'string',
|
117
135
|
});
|
118
|
-
|
136
|
+
},
|
119
137
|
(argv) => {
|
120
138
|
utils.runApp(argv.path);
|
121
139
|
}
|
122
140
|
)
|
123
|
-
.command('install <path>',
|
141
|
+
.command('install <path>', 'Install an app', (yargs) => {
|
124
142
|
yargs
|
125
143
|
.positional('path', {
|
126
144
|
describe: 'Path of the app to install',
|
127
145
|
type: 'string',
|
128
146
|
});
|
129
|
-
|
147
|
+
},
|
130
148
|
async (argv) => {
|
131
|
-
if(argv.path.startsWith('github:')) utils.installApp(await utils.cloneGit(argv.path), true, true);
|
149
|
+
if (argv.path.startsWith('github:')) utils.installApp(await utils.cloneGit(argv.path), true, true);
|
132
150
|
else utils.installApp(argv.path);
|
133
151
|
}
|
134
152
|
)
|
@@ -161,7 +179,7 @@ yargs(hideBin(process.argv))
|
|
161
179
|
|
162
180
|
function writeCompiledFile(filePath, compiledCode) {
|
163
181
|
const dirName = outputDir ? outputDir : path.dirname(filePath);
|
164
|
-
if(!existsSync(dirName)) mkdirSync(dirName, { recursive: true });
|
182
|
+
if (!existsSync(dirName)) mkdirSync(dirName, { recursive: true });
|
165
183
|
const baseName = path.basename(filePath, path.extname(filePath));
|
166
184
|
const newFilePath = path.join(dirName, `${baseName}.js`);
|
167
185
|
writeFileSync(newFilePath, compiledCode, { encoding: 'utf-8' });
|
@@ -171,20 +189,20 @@ yargs(hideBin(process.argv))
|
|
171
189
|
function processFile(filePath, importsArray) {
|
172
190
|
const content = readFile(filePath);
|
173
191
|
const imports = extractImports(content);
|
174
|
-
|
192
|
+
|
175
193
|
imports.forEach(importStatement => {
|
176
194
|
const importedFilePath = path.resolve(path.dirname(filePath), importStatement.url);
|
177
195
|
if (!importsArray.some(importObj => importObj.url === importStatement.url)) {
|
178
|
-
|
179
|
-
if(existsSync(importedFilePath)){
|
196
|
+
|
197
|
+
if (existsSync(importedFilePath)) {
|
180
198
|
importsArray.push(importStatement);
|
181
199
|
processFile(importedFilePath, importsArray);
|
182
|
-
} else if(existsSync(importedFilePath+'.coffee')){
|
200
|
+
} else if (existsSync(importedFilePath + '.coffee')) {
|
183
201
|
importsArray.push(importStatement);
|
184
|
-
processFile(importedFilePath+'.coffee', importsArray);
|
185
|
-
} else if(existsSync(importedFilePath+'.js')){
|
202
|
+
processFile(importedFilePath + '.coffee', importsArray);
|
203
|
+
} else if (existsSync(importedFilePath + '.js')) {
|
186
204
|
importsArray.push(importStatement);
|
187
|
-
processFile(importedFilePath+'.js', importsArray);
|
205
|
+
processFile(importedFilePath + '.js', importsArray);
|
188
206
|
}
|
189
207
|
|
190
208
|
}
|
package/lib/rew/cli/utils.js
CHANGED
@@ -30,6 +30,10 @@ module.exports.imp = function (runPath, context) {
|
|
30
30
|
let exports,
|
31
31
|
ispkg = findPackage(filename);
|
32
32
|
|
33
|
+
if(filename.startsWith('@') && context.app){
|
34
|
+
filename = filename.replace('@', context.app.path);
|
35
|
+
}
|
36
|
+
|
33
37
|
let filepath = path.resolve(path.dirname(context.module.filepath), filename);
|
34
38
|
|
35
39
|
// console.log(typeof runPath);
|
@@ -74,7 +78,8 @@ module.exports.imp = function (runPath, context) {
|
|
74
78
|
).context.module.exports;
|
75
79
|
|
76
80
|
if (ispkg) {
|
77
|
-
|
81
|
+
const pkg = getPackage(filename)(context);
|
82
|
+
exports = pkg._onImport ? pkg._onImport() : pkg;
|
78
83
|
} else if (foundCache) {
|
79
84
|
|
80
85
|
} else if (type == "coffee") {
|
@@ -0,0 +1,16 @@
|
|
1
|
+
const jsYaml = require("js-yaml");
|
2
|
+
const { findAppPath } = require("./findAppPath");
|
3
|
+
const path = require('path');
|
4
|
+
const { readFileSync } = require("fs");
|
5
|
+
|
6
|
+
module.exports.findAppInfo = function(filepath){
|
7
|
+
const appPath = findAppPath(path.dirname(filepath));
|
8
|
+
if(appPath){
|
9
|
+
const config = jsYaml.load(readFileSync(path.join(appPath, 'app.yaml')));
|
10
|
+
return {
|
11
|
+
path: appPath,
|
12
|
+
config
|
13
|
+
}
|
14
|
+
}
|
15
|
+
return null;
|
16
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
const path = require('path'); // Import the 'path' module
|
2
|
+
const fs = require('fs'); // Import the 'path' module
|
3
|
+
|
4
|
+
module.exports.findAppPath = (currentDir = __dirname) => {
|
5
|
+
// Check if app.yaml exists in the current directory
|
6
|
+
const appYamlPath = path.join(currentDir, 'app.yaml');
|
7
|
+
if (fs.existsSync(appYamlPath)) {
|
8
|
+
return currentDir;
|
9
|
+
}
|
10
|
+
|
11
|
+
// If not found, move up a directory level
|
12
|
+
const parentDir = path.dirname(currentDir);
|
13
|
+
|
14
|
+
// Check if we reached the root directory
|
15
|
+
if (parentDir === currentDir) {
|
16
|
+
return null; // Not found
|
17
|
+
}
|
18
|
+
|
19
|
+
// Recursively call the function on the parent directory
|
20
|
+
return module.exports.findAppPath(parentDir);
|
21
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module.exports.seededID = function (seed) {
|
4
|
+
const charCodes = seed.split('').map(char => char.charCodeAt(0));
|
5
|
+
|
6
|
+
let result = '';
|
7
|
+
let sum = 0;
|
8
|
+
|
9
|
+
for (let i = 0; i < charCodes.length; i++) {
|
10
|
+
sum += charCodes[i];
|
11
|
+
result += String.fromCharCode((charCodes[i] + sum) % 26 + 97);
|
12
|
+
}
|
13
|
+
|
14
|
+
return result.slice(0, 12);
|
15
|
+
}
|
@@ -1,12 +1,12 @@
|
|
1
1
|
const defaultContext = require("../const/default");
|
2
2
|
const { execOptions } = require("../const/opt");
|
3
|
-
const emitter = require("../functions/emitter");
|
4
3
|
const { exportsFunction, pubFunction } = require("../functions/export");
|
5
4
|
const { imp } = require("../functions/import");
|
6
5
|
const { customRequire } = require("../functions/require");
|
7
6
|
const fsLib = require('../functions/fs');
|
8
7
|
const pathLib = require('../functions/path');
|
9
8
|
const execLib = require('../functions/exec');
|
9
|
+
const { findAppInfo } = require("../misc/findAppInfo");
|
10
10
|
|
11
11
|
let mainFile = "";
|
12
12
|
const isMainFile = filepath => filepath == mainFile;
|
@@ -28,6 +28,7 @@ module.exports.prepareContext = function (
|
|
28
28
|
meta: {},
|
29
29
|
assert: options.import ?? {}
|
30
30
|
},
|
31
|
+
app: findAppInfo(filepath),
|
31
32
|
...fsLib(filepath),
|
32
33
|
};
|
33
34
|
if (options.useContext) {
|
package/lib/rew/pkgs/conf.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
const fs = require('fs');
|
2
2
|
const jsYaml = require('js-yaml');
|
3
3
|
const path = require('path');
|
4
|
-
|
5
|
-
const
|
4
|
+
const { CONFIG_PATH } = require('../const/config_path');
|
5
|
+
const { seededID } = require('../misc/seededid');
|
6
6
|
|
7
7
|
const createPackageRoot = (packageName) => {
|
8
8
|
const rootPath = path.join(CONFIG_PATH, packageName);
|
@@ -12,6 +12,13 @@ const createPackageRoot = (packageName) => {
|
|
12
12
|
|
13
13
|
module.exports = (context) => ({
|
14
14
|
CONFIG_PATH,
|
15
|
+
_onImport(){
|
16
|
+
if(context.app){
|
17
|
+
return this.create(context.app.config.package);
|
18
|
+
} else {
|
19
|
+
return this.create(seededID(path.basename(context.module.filepath).replace(/[-_/\.]/g, '')));
|
20
|
+
}
|
21
|
+
},
|
15
22
|
create: (packageName) => {
|
16
23
|
const rootPath = createPackageRoot(packageName);
|
17
24
|
|
@@ -0,0 +1,376 @@
|
|
1
|
+
const fs = require('fs');
|
2
|
+
const { v4: uuidv4 } = require('uuid');
|
3
|
+
const path = require('path');
|
4
|
+
const msgpack = require('tiny-msgpack');
|
5
|
+
const crypto = require('crypto');
|
6
|
+
const { CONFIG_PATH } = require('../const/config_path');
|
7
|
+
|
8
|
+
const ENCRYPTION_KEY = 'e6ad8b0792b9e0472ea44d1f3adfd1d503182efcce25991b05cc5ef83f307ffc';
|
9
|
+
|
10
|
+
|
11
|
+
class Change {
|
12
|
+
constructor(values) {
|
13
|
+
this.values = values;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
class PopChange extends Change { };
|
18
|
+
|
19
|
+
class PushChange extends Change { };
|
20
|
+
|
21
|
+
const runePush = (...values) => new PushChange(values);
|
22
|
+
const runePop = (...values) => new PopChange(values);
|
23
|
+
|
24
|
+
|
25
|
+
function makeRef(value, props = '') {
|
26
|
+
if (!value['@rune.id']) return null;
|
27
|
+
const collection = getCollectionFromID(value['@rune.id']);
|
28
|
+
const ref = collection + '.' + value['@rune.id'];
|
29
|
+
return '@rune.ref ' + ref + props;
|
30
|
+
}
|
31
|
+
|
32
|
+
const eid = (s, diff) => s.split('')
|
33
|
+
.map(i => {
|
34
|
+
let charCode = i.charCodeAt(0) + diff;
|
35
|
+
if (charCode > 122) {
|
36
|
+
charCode -= 26;
|
37
|
+
}
|
38
|
+
return String.fromCharCode(charCode);
|
39
|
+
})
|
40
|
+
.join('');
|
41
|
+
|
42
|
+
function generateID(id, collection) {
|
43
|
+
return eid(collection, 5) + '+' + id;
|
44
|
+
}
|
45
|
+
|
46
|
+
function getCollectionFromID(id) {
|
47
|
+
return eid(id.split('+')[0], -5);
|
48
|
+
}
|
49
|
+
|
50
|
+
const createDB = (dbName, dirname, encryptionKey) => {
|
51
|
+
const dbDirPath = path.join(dirname, dbName);
|
52
|
+
const mainFilePath = path.join(dbDirPath, 'main.bin');
|
53
|
+
const algorithm = 'aes-256-ctr';
|
54
|
+
|
55
|
+
if (!fs.existsSync(dbDirPath)) {
|
56
|
+
fs.mkdirSync(dbDirPath);
|
57
|
+
}
|
58
|
+
|
59
|
+
const encrypt = (data) => {
|
60
|
+
const iv = crypto.randomBytes(16);
|
61
|
+
const cipher = crypto.createCipheriv(algorithm, Buffer.from(encryptionKey, 'hex'), iv);
|
62
|
+
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
|
63
|
+
return Buffer.concat([iv, encrypted]);
|
64
|
+
};
|
65
|
+
|
66
|
+
const decrypt = (data) => {
|
67
|
+
const iv = data.slice(0, 16);
|
68
|
+
const encryptedData = data.slice(16);
|
69
|
+
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(encryptionKey, 'hex'), iv);
|
70
|
+
const decrypted = Buffer.concat([decipher.update(encryptedData), decipher.final()]);
|
71
|
+
return decrypted;
|
72
|
+
};
|
73
|
+
|
74
|
+
const serializeData = (data) => {
|
75
|
+
return msgpack.encode(data);
|
76
|
+
};
|
77
|
+
|
78
|
+
const deserializeData = (buffer) => {
|
79
|
+
return msgpack.decode(decrypt(buffer));
|
80
|
+
};
|
81
|
+
|
82
|
+
const readMainData = () => {
|
83
|
+
if (!fs.existsSync(mainFilePath)) {
|
84
|
+
writeMainData({ collections: [], maps: [] });
|
85
|
+
}
|
86
|
+
const buffer = fs.readFileSync(mainFilePath);
|
87
|
+
return deserializeData(buffer);
|
88
|
+
};
|
89
|
+
|
90
|
+
const writeMainData = (data) => {
|
91
|
+
const buffer = encrypt(serializeData(data));
|
92
|
+
fs.writeFileSync(mainFilePath, buffer);
|
93
|
+
};
|
94
|
+
|
95
|
+
const readDataFile = (filePath) => {
|
96
|
+
const buffer = fs.readFileSync(filePath);
|
97
|
+
return deserializeData(buffer);
|
98
|
+
};
|
99
|
+
|
100
|
+
const writeDataFile = (filePath, data) => {
|
101
|
+
const buffer = encrypt(serializeData(data));
|
102
|
+
fs.writeFileSync(filePath, buffer);
|
103
|
+
};
|
104
|
+
|
105
|
+
const collection = (collectionName) => {
|
106
|
+
const collectionFilePath = path.join(dbDirPath, `${collectionName}.col`);
|
107
|
+
|
108
|
+
const create = (record) => {
|
109
|
+
const mainData = readMainData();
|
110
|
+
if (!mainData.collections.includes(collectionName)) {
|
111
|
+
mainData.collections.push(collectionName);
|
112
|
+
writeMainData(mainData);
|
113
|
+
}
|
114
|
+
|
115
|
+
let data = [];
|
116
|
+
if (fs.existsSync(collectionFilePath)) {
|
117
|
+
data = readDataFile(collectionFilePath);
|
118
|
+
}
|
119
|
+
const id = uuidv4();
|
120
|
+
record['@rune.id'] = generateID(id, collectionName);
|
121
|
+
data.push(record);
|
122
|
+
writeDataFile(collectionFilePath, data);
|
123
|
+
return record;
|
124
|
+
};
|
125
|
+
|
126
|
+
const read = (id, evaluate = true) => {
|
127
|
+
if (typeof id == "object" && '@rune.id' in id) id = id['@rune.id'];
|
128
|
+
if (!fs.existsSync(collectionFilePath)) return null;
|
129
|
+
const data = readDataFile(collectionFilePath);
|
130
|
+
const record = data.find(record => record['@rune.id'] === id);
|
131
|
+
if (record) {
|
132
|
+
return evaluateRecord(record);
|
133
|
+
}
|
134
|
+
return null;
|
135
|
+
};
|
136
|
+
|
137
|
+
const evaluateRecord = (record, prevRecord) => {
|
138
|
+
const evaluateValue = (val) => {
|
139
|
+
if (typeof val == "string" && val.startsWith('@rune.ref')) {
|
140
|
+
const ref = val.split('@rune.ref')[1].trim();
|
141
|
+
const refData = findRef(ref, false);
|
142
|
+
if (!refData) {
|
143
|
+
return null;
|
144
|
+
} else {
|
145
|
+
let value = refData;
|
146
|
+
if (refData['@rune.id']) {
|
147
|
+
value = prevRecord && prevRecord['@rune.id'] == refData['@rune.id'] ? prevRecord : evaluateRecord(refData, record);
|
148
|
+
}
|
149
|
+
return value;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
if (Array.isArray(val)) {
|
153
|
+
val = val.map(i => evaluateValue(i));
|
154
|
+
}
|
155
|
+
return val;
|
156
|
+
}
|
157
|
+
for (let i in record) {
|
158
|
+
const val = record[i];
|
159
|
+
record[i] = evaluateValue(val);
|
160
|
+
}
|
161
|
+
return record;
|
162
|
+
}
|
163
|
+
|
164
|
+
const update = (caseRecord, newRecord) => {
|
165
|
+
let id;
|
166
|
+
if (typeof caseRecord === 'string') {
|
167
|
+
id = caseRecord;
|
168
|
+
} else if (typeof caseRecord === 'object') {
|
169
|
+
const data = readDataFile(collectionFilePath);
|
170
|
+
const record = data.find(record => {
|
171
|
+
for (const key in caseRecord) {
|
172
|
+
if (record[key] !== caseRecord[key]) return false;
|
173
|
+
}
|
174
|
+
return true;
|
175
|
+
});
|
176
|
+
if (record) {
|
177
|
+
id = record['@rune.id'];
|
178
|
+
} else {
|
179
|
+
return null; // No matching record found
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
if (!id) return null;
|
184
|
+
|
185
|
+
const data = readDataFile(collectionFilePath);
|
186
|
+
const index = data.findIndex(record => record['@rune.id'] === id);
|
187
|
+
if (index !== -1) {
|
188
|
+
const oldRecord = data[index];
|
189
|
+
for (const key in newRecord) {
|
190
|
+
const value = newRecord[key];
|
191
|
+
if (value instanceof PushChange) {
|
192
|
+
if (!oldRecord[key] || !Array.isArray(oldRecord[key])) {
|
193
|
+
oldRecord[key] = [];
|
194
|
+
}
|
195
|
+
oldRecord[key].push(...value.values);
|
196
|
+
} else if (value instanceof PopChange) {
|
197
|
+
if (oldRecord[key] && Array.isArray(oldRecord[key])) {
|
198
|
+
value.values.forEach(val => {
|
199
|
+
const index = oldRecord[key].indexOf(val);
|
200
|
+
if (index !== -1) {
|
201
|
+
oldRecord[key].splice(index, 1);
|
202
|
+
}
|
203
|
+
});
|
204
|
+
}
|
205
|
+
} else {
|
206
|
+
oldRecord[key] = value;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
data[index] = oldRecord;
|
210
|
+
writeDataFile(collectionFilePath, data);
|
211
|
+
return data[index];
|
212
|
+
}
|
213
|
+
return null;
|
214
|
+
};
|
215
|
+
|
216
|
+
const find = (criteria) => {
|
217
|
+
if (typeof criteria == "string") return read(criteria);
|
218
|
+
if (!criteria || typeof criteria !== 'object') return null;
|
219
|
+
|
220
|
+
const data = readDataFile(collectionFilePath);
|
221
|
+
const record = data.find(record => {
|
222
|
+
for (const key in criteria) {
|
223
|
+
if (record[key] !== criteria[key]) return false;
|
224
|
+
}
|
225
|
+
return true;
|
226
|
+
}) || null;
|
227
|
+
if (record) {
|
228
|
+
evaluateRecord();
|
229
|
+
}
|
230
|
+
return null;
|
231
|
+
};
|
232
|
+
|
233
|
+
const remove = (id) => {
|
234
|
+
if ('@rune.id' in id) id = id['@rune.id'];
|
235
|
+
if (!fs.existsSync(collectionFilePath)) return false;
|
236
|
+
let data = readDataFile(collectionFilePath);
|
237
|
+
const index = data.findIndex(record => record['@rune.id'] === id);
|
238
|
+
if (index !== -1) {
|
239
|
+
data.splice(index, 1);
|
240
|
+
writeDataFile(collectionFilePath, data);
|
241
|
+
return true;
|
242
|
+
}
|
243
|
+
return false;
|
244
|
+
};
|
245
|
+
|
246
|
+
const list = () => {
|
247
|
+
if (!fs.existsSync(collectionFilePath)) return [];
|
248
|
+
const data = readDataFile(collectionFilePath);
|
249
|
+
return data.map(rec => evaluateRecord(rec));
|
250
|
+
};
|
251
|
+
|
252
|
+
const map = (cb, mutate = false) => {
|
253
|
+
const data = readDataFile(collectionFilePath);
|
254
|
+
const mappedData = data.map(cb);
|
255
|
+
if (mutate) {
|
256
|
+
writeDataFile(collectionFilePath, mappedData);
|
257
|
+
}
|
258
|
+
return mappedData;
|
259
|
+
};
|
260
|
+
|
261
|
+
const transform = (cb, mutate = false) => {
|
262
|
+
const data = readDataFile(collectionFilePath);
|
263
|
+
const transformedData = cb(cb);
|
264
|
+
if (mutate) {
|
265
|
+
writeDataFile(collectionFilePath, mappedData);
|
266
|
+
}
|
267
|
+
return transformedData;
|
268
|
+
}
|
269
|
+
|
270
|
+
const filter = (cb, mutate = false) => {
|
271
|
+
const data = readDataFile(collectionFilePath);
|
272
|
+
const filteredData = data.filter(cb);
|
273
|
+
if (mutate) {
|
274
|
+
writeDataFile(collectionFilePath, filteredData);
|
275
|
+
}
|
276
|
+
return filteredData;
|
277
|
+
};
|
278
|
+
|
279
|
+
const sort = (cb, mutate = false) => {
|
280
|
+
const data = readDataFile(collectionFilePath);
|
281
|
+
const sortedData = data.sort(cb);
|
282
|
+
if (mutate) {
|
283
|
+
writeDataFile(collectionFilePath, sortedData);
|
284
|
+
}
|
285
|
+
return sortedData;
|
286
|
+
};
|
287
|
+
|
288
|
+
return { create, findRef, read, update, remove, find, map, transform, filter, sort, list };
|
289
|
+
};
|
290
|
+
|
291
|
+
const findRef = (ref, evaluate = true) => {
|
292
|
+
const [name, id, ...rest] = ref.split('.');
|
293
|
+
const col = collection(name);
|
294
|
+
const record = col.read(id, evaluate);
|
295
|
+
if (rest.length === 0) return record;
|
296
|
+
let value = record;
|
297
|
+
for (const prop of rest) {
|
298
|
+
if (typeof value != "object") break;
|
299
|
+
if (!(prop in value)) return null;
|
300
|
+
value = value[prop];
|
301
|
+
}
|
302
|
+
return value;
|
303
|
+
};
|
304
|
+
|
305
|
+
const map = (mapName) => {
|
306
|
+
const mapFilePath = path.join(dbDirPath, `${mapName}.map`);
|
307
|
+
|
308
|
+
const set = (key, value) => {
|
309
|
+
const mainData = readMainData();
|
310
|
+
if (!mainData.maps.includes(mapName)) {
|
311
|
+
mainData.maps.push(mapName);
|
312
|
+
writeMainData(mainData);
|
313
|
+
}
|
314
|
+
|
315
|
+
let data = {};
|
316
|
+
if (fs.existsSync(mapFilePath)) {
|
317
|
+
data = readDataFile(mapFilePath);
|
318
|
+
}
|
319
|
+
data[key] = value;
|
320
|
+
writeDataFile(mapFilePath, data);
|
321
|
+
};
|
322
|
+
|
323
|
+
const get = (key) => {
|
324
|
+
if (!fs.existsSync(mapFilePath)) return null;
|
325
|
+
const data = readDataFile(mapFilePath);
|
326
|
+
return data[key] || null;
|
327
|
+
};
|
328
|
+
|
329
|
+
const remove = (key) => {
|
330
|
+
if (!fs.existsSync(mapFilePath)) return false;
|
331
|
+
const data = readDataFile(mapFilePath);
|
332
|
+
if (data[key]) {
|
333
|
+
delete data[key];
|
334
|
+
writeDataFile(mapFilePath, data);
|
335
|
+
return true;
|
336
|
+
}
|
337
|
+
return false;
|
338
|
+
};
|
339
|
+
|
340
|
+
const transform = (cb, mutate = false) => {
|
341
|
+
const data = readDataFile(mapFilePath);
|
342
|
+
const transformedData = cb(data);
|
343
|
+
if (mutate) {
|
344
|
+
writeDataFile(mapFilePath, transformedData);
|
345
|
+
}
|
346
|
+
return transformedData;
|
347
|
+
};
|
348
|
+
|
349
|
+
const list = () => {
|
350
|
+
if (!fs.existsSync(mapFilePath)) return {};
|
351
|
+
const data = readDataFile(mapFilePath);
|
352
|
+
return data;
|
353
|
+
};
|
354
|
+
|
355
|
+
return { set, get, remove, list, transform };
|
356
|
+
};
|
357
|
+
|
358
|
+
return { collection, findRef, makeRef, map };
|
359
|
+
};
|
360
|
+
|
361
|
+
module.exports = (context) => ({
|
362
|
+
_onImport() {
|
363
|
+
delete this.createDB;
|
364
|
+
return this;
|
365
|
+
},
|
366
|
+
db(dbname, encryptionKey) {
|
367
|
+
if (!context.app) throw new Error('rune can only be used in apps');
|
368
|
+
const pkg = path.join(CONFIG_PATH, context.app.config.package, 'db');
|
369
|
+
if (!fs.existsSync(pkg)) fs.mkdirSync(pkg, { recursive: true });
|
370
|
+
return createDB(dbname, pkg, encryptionKey || ENCRYPTION_KEY);
|
371
|
+
},
|
372
|
+
makeRef,
|
373
|
+
runePop,
|
374
|
+
runePush,
|
375
|
+
createDB
|
376
|
+
});
|
package/meson.build
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
project('rew', 'cpp',
|
2
|
+
version : '0.1',
|
3
|
+
default_options : ['warning_level=3', 'cpp_std=c++14'])
|
4
|
+
|
5
|
+
gtk3 = dependency('gtk+-3.0', method : 'pkg-config')
|
6
|
+
webkit2gtk = dependency('webkit2gtk-4.0', method : 'pkg-config')
|
7
|
+
libwebsockets = dependency('libwebsockets', method : 'pkg-config')
|
8
|
+
jsoncpp = dependency('jsoncpp', method : 'pkg-config')
|
9
|
+
|
10
|
+
executable('ui',
|
11
|
+
'cpp/ui.cpp',
|
12
|
+
install : true,
|
13
|
+
dependencies : [gtk3, webkit2gtk, libwebsockets, jsoncpp])
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@makano/rew",
|
3
|
-
"version": "1.1.
|
3
|
+
"version": "1.1.8",
|
4
4
|
"description": "A simple coffescript runtime",
|
5
5
|
"main": "lib/rew/main.js",
|
6
6
|
"directories": {
|
@@ -13,6 +13,7 @@
|
|
13
13
|
"lib/",
|
14
14
|
"cpp/",
|
15
15
|
"bin/",
|
16
|
+
"meson.build",
|
16
17
|
"build.sh",
|
17
18
|
"README.md"
|
18
19
|
],
|
@@ -23,7 +24,11 @@
|
|
23
24
|
"type": "git",
|
24
25
|
"url": "git+https://github.com/kevinj045/rew.git"
|
25
26
|
},
|
26
|
-
"keywords": [
|
27
|
+
"keywords": [
|
28
|
+
"coffescript",
|
29
|
+
"rew",
|
30
|
+
"runtime"
|
31
|
+
],
|
27
32
|
"author": "makano",
|
28
33
|
"license": "ISC",
|
29
34
|
"dependencies": {
|
@@ -33,6 +38,8 @@
|
|
33
38
|
"chalk": "^5.3.0",
|
34
39
|
"chokidar": "^3.6.0",
|
35
40
|
"js-yaml": "^4.1.0",
|
41
|
+
"tiny-msgpack": "^2.2.0",
|
42
|
+
"uuid": "^9.0.1",
|
36
43
|
"vm": "^0.1.0",
|
37
44
|
"yargs": "^17.7.2"
|
38
45
|
},
|