binhend 1.5.16 → 2.0.0

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.
Files changed (38) hide show
  1. package/bin/commands/new-service.js +20 -0
  2. package/bin/commands/new-ui.js +21 -0
  3. package/bin/index.js +4 -0
  4. package/bin/templates/component/Service.js +0 -0
  5. package/bin/templates/component/UI.js +8 -0
  6. package/bin/templates/component/ui/Component.js +26 -0
  7. package/bin/templates/component/ui/Service.js +7 -0
  8. package/bin/templates/component/ui/Style.css +3 -0
  9. package/bin/templates/component/ui/UI.js +17 -0
  10. package/bin/templates/frontend/src/favicon.png +0 -0
  11. package/bin/templates/frontend/src/index.html +5 -0
  12. package/bin/templates/frontend/src/style.css +3 -0
  13. package/package.json +3 -3
  14. package/src/api.js +84 -58
  15. package/src/binh.js +15 -62
  16. package/src/configuration.js +29 -99
  17. package/src/csd/controller.js +93 -0
  18. package/src/csd/dao.js +17 -0
  19. package/src/csd/index.js +15 -0
  20. package/src/csd/service.js +58 -0
  21. package/src/middleware/parseBasicAuthToken.js +11 -0
  22. package/src/server.js +4 -50
  23. package/src/utils/bromise.js +20 -0
  24. package/src/utils/httpCodes.js +69 -0
  25. package/src/utils/typeOf.js +78 -0
  26. package/src/{component.build.js → web/component.build.js} +1 -0
  27. package/src/{component.format.js → web/component.format.js} +1 -0
  28. package/src/web/component.method.js +141 -0
  29. package/src/web/index.js +46 -0
  30. package/src/binh.server.app.js +0 -78
  31. package/src/binh.server.config.js +0 -80
  32. package/src/cors.js +0 -17
  33. package/src/enum.httpCodes.js +0 -49
  34. /package/src/{cryptography.js → security.js} +0 -0
  35. /package/src/{binh.web.builder.js → web/binh.web.builder.js} +0 -0
  36. /package/src/{code.js → web/code.js} +0 -0
  37. /package/src/{component.file.js → web/component.file.js} +0 -0
  38. /package/src/{component.js → web/component.js} +0 -0
@@ -0,0 +1,93 @@
1
+ const { trycatch, HttpError } = require('../api');
2
+ const { isEmptyObject, isString } = require('../utils/typeOf');
3
+ const { OK, CREATED, BAD_REQUEST } = require('../utils/httpCodes').HttpCodes;
4
+
5
+ const
6
+ ERROR_MISSING_ID = 'Missing required parameter: id',
7
+ ERROR_EMPTY_QUERY = 'Query should not be empty (null or no key-value)';
8
+
9
+ function Controller(service) {
10
+ function parseID(request) {
11
+ let id = request.params?.id || request.query?.id || request.body?.id;
12
+ if (!isString(id)) throw new HttpError(BAD_REQUEST, ERROR_MISSING_ID);
13
+ return id;
14
+ }
15
+
16
+ function parseQuery(request) {
17
+ let query = isEmptyObject(request.query) ? request.params : request.query;
18
+ query = isEmptyObject(query) ? request.body : query;
19
+ if (isEmptyObject(query)) throw new HttpError(BAD_REQUEST, ERROR_EMPTY_QUERY);
20
+ return query;
21
+ }
22
+
23
+ async function process(method, args, httpCode, response) {
24
+ let result = await service[method].apply(service, args);
25
+ response.status(httpCode).json(result);
26
+ }
27
+
28
+ /** CREATE */
29
+
30
+ this.create = trycatch(async (request, response) => {
31
+ let data = request.body;
32
+ await process('create', [data], CREATED, response);
33
+ });
34
+
35
+ this.upsert = trycatch(async (request, response) => {
36
+ let query = parseQuery(request), data = request.body;
37
+ await process('upsert', [query, data], OK, response);
38
+ });
39
+
40
+ /** READ */
41
+
42
+ this.getAll = trycatch(async (request, response) => {
43
+ await process('getAll', [], OK, response);
44
+ });
45
+
46
+ this.getByID = trycatch(async (request, response) => {
47
+ let id = parseID(request);
48
+ await process('getByID', [id], OK, response);
49
+ });
50
+
51
+ this.getByQuery = trycatch(async (request, response) => {
52
+ let query = parseQuery(request);
53
+ await process('getByQuery', [query], OK, response);
54
+ });
55
+
56
+ /** UPDATE */
57
+
58
+ this.updateAll = trycatch(async (request, response) => {
59
+ let data = request.body;
60
+ await process('updateAll', [data], OK, response);
61
+ });
62
+
63
+ this.updateByID = trycatch(async (request, response) => {
64
+ let id = parseID(request);
65
+ let data = request.body;
66
+ await process('updateByID', [id, data], OK, response);
67
+ });
68
+
69
+ this.updateByQuery = trycatch(async (request, response) => {
70
+ let query = parseQuery(request), data = request.body;
71
+ await process('updateByQuery', [query, data], OK, response);
72
+ });
73
+
74
+ /** DELETE */
75
+
76
+ this.deleteAll = trycatch(async (request, response) => {
77
+ await process('deleteAll', [], OK, response);
78
+ });
79
+
80
+ this.deleteByID = trycatch(async (request, response) => {
81
+ let id = parseID(request);
82
+ await process('deleteByID', [id], OK, response);
83
+ });
84
+
85
+ this.deleteByQuery = trycatch(async (request, response) => {
86
+ let query = parseQuery(request);
87
+ await process('deleteByQuery', [query], OK, response);
88
+ });
89
+ }
90
+
91
+ module.exports = (service) => {
92
+ return new Controller(service);
93
+ };
package/src/csd/dao.js ADDED
@@ -0,0 +1,17 @@
1
+
2
+ const initService = require('./service');
3
+
4
+ function DAO(instance) {
5
+ var service = initService({});
6
+
7
+ for (var key in service) {
8
+ if (!instance.hasOwnProperty(key) || typeof instance[key] !== 'function') {
9
+ throw new Error(`CSD: Missing function implementation for "${key}()"`);
10
+ }
11
+ this[key] = instance[key];
12
+ }
13
+ }
14
+
15
+ module.exports = (instance) => {
16
+ return new DAO(instance);
17
+ };
@@ -0,0 +1,15 @@
1
+
2
+ const initController = require('./controller');
3
+ const initService = require('./service');
4
+ const initDao = require('./dao');
5
+
6
+ function createCSD(instance) {
7
+ var dao = initDao(instance);
8
+ var service = initService(dao);
9
+ var controller = initController(service);
10
+ return { controller, service, dao };
11
+ };
12
+
13
+ module.exports = (DatabaseDriverAdapter) => {
14
+ return (input) => createCSD(new DatabaseDriverAdapter(input));
15
+ };
@@ -0,0 +1,58 @@
1
+
2
+ function Service(dao) {
3
+ /** CREATE */
4
+
5
+ this.create = async (data) => {
6
+ return await dao.create(data);
7
+ };
8
+
9
+ this.upsert = async (query, data) => {
10
+ return await dao.upsert(query, data);
11
+ };
12
+
13
+ /** READ */
14
+
15
+ this.getAll = async () => {
16
+ return await dao.getAll();
17
+ };
18
+
19
+ this.getByID = async (id) => {
20
+ return await dao.getByID(id);
21
+ };
22
+
23
+ this.getByQuery = async (query) => {
24
+ return await dao.getByQuery(query);
25
+ };
26
+
27
+ /** UPDATE */
28
+
29
+ this.updateAll = async (data) => {
30
+ return await dao.updateAll(data);
31
+ };
32
+
33
+ this.updateByID = async (id, data) => {
34
+ return await dao.updateByID(id, data);
35
+ };
36
+
37
+ this.updateByQuery = async (query, data) => {
38
+ return await dao.updateByQuery(query, data);
39
+ };
40
+
41
+ /** DELETE */
42
+
43
+ this.deleteAll = async () => {
44
+ return await dao.deleteAll();
45
+ };
46
+
47
+ this.deleteByID = async (id) => {
48
+ return await dao.deleteByID(id);
49
+ };
50
+
51
+ this.deleteByQuery = async (query) => {
52
+ return await dao.deleteByQuery(query);
53
+ };
54
+ }
55
+
56
+ module.exports = (dao) => {
57
+ return new Service(dao);
58
+ };
@@ -0,0 +1,11 @@
1
+ const { isString } = require('../utils/typeOf');
2
+
3
+ module.exports = (request, response, next) => {
4
+ var authString = request.headers['authorization'];
5
+
6
+ if (isString(authString) && authString.startsWith('Bearer ')) {
7
+ request.token = authString.split('Bearer ')[1];
8
+ }
9
+
10
+ next();
11
+ };
package/src/server.js CHANGED
@@ -1,53 +1,7 @@
1
-
2
1
  const express = require('express');
3
- const { defaultCORS } = require('./cors');
4
-
5
- function Server(options) {
6
- const server = express();
7
- const PORT = options.port || 1300;
8
- const WEB_DIRECTORY = options.web;
9
- const CORS = options.cors;
10
-
11
- // Handle error of ExpressJS: URIError: Failed to decode param
12
- // Error happens when add wrong '%' (e.i. invalid encoded URI component) into the request URL
13
- server.use(function(req, res, next) {
14
- try {
15
- decodeURIComponent(req.path);
16
- next();
17
- }
18
- catch(e) {
19
- res.redirect('/');
20
- }
21
- });
22
-
23
- if (CORS instanceof Function) {
24
- server.use(CORS);
25
- }
26
- else if (CORS === true) {
27
- server.use(defaultCORS);
28
- }
29
-
30
- if (WEB_DIRECTORY) {
31
- server.use(express.static(WEB_DIRECTORY));
32
- }
33
-
34
- if (options.api instanceof Function) {
35
- server.use(options.api);
36
- }
37
-
38
- if (WEB_DIRECTORY) {
39
- server.get('/*', (req, res) => res.sendFile('index.html', { root: WEB_DIRECTORY }));
40
- }
41
-
42
- server.listen(PORT, function() {
43
- console.log(`[BINHEND][SERVER] Server is listening on http://localhost:${PORT}/`);
44
-
45
- if (options.callback instanceof Function) {
46
- options.callback(server, options.configs);
47
- }
48
- });
49
2
 
50
- return server;
51
- }
3
+ const server = express();
52
4
 
53
- module.exports = { Server };
5
+ module.exports = {
6
+ server
7
+ };
@@ -0,0 +1,20 @@
1
+
2
+ function Bromise() {
3
+ var resolve, reject, promise = new Promise((res, rej) => (resolve = res) && (reject = rej));
4
+
5
+ return {
6
+ promise,
7
+ resolve: (value) => {
8
+ resolve(value);
9
+ return promise;
10
+ },
11
+ reject: (error) => {
12
+ reject(error);
13
+ return promise;
14
+ }
15
+ };
16
+ }
17
+
18
+ module.exports = {
19
+ Bromise
20
+ };
@@ -0,0 +1,69 @@
1
+ const HttpCodes = {
2
+ CONTINUE: 100,
3
+ SWITCHING_PROTOCOLS: 101,
4
+ PROCESSING: 102,
5
+ EARLY_HINTS: 103,
6
+ OK: 200,
7
+ CREATED: 201,
8
+ ACCEPTED: 202,
9
+ NON_AUTHORITATIVE_INFORMATION: 203,
10
+ NO_CONTENT: 204,
11
+ RESET_CONTENT: 205,
12
+ PARTIAL_CONTENT: 206,
13
+ MULTI_STATUS: 207,
14
+ ALREADY_REPORTED: 208,
15
+ IM_USED: 226,
16
+ MULTIPLE_CHOICES: 300,
17
+ MOVED_PERMANENTLY: 301,
18
+ FOUND: 302,
19
+ SEE_OTHER: 303,
20
+ NOT_MODIFIED: 304,
21
+ USE_PROXY: 305,
22
+ TEMPORARY_REDIRECT: 307,
23
+ PERMANENT_REDIRECT: 308,
24
+ BAD_REQUEST: 400,
25
+ UNAUTHORIZED: 401,
26
+ PAYMENT_REQUIRED: 402,
27
+ FORBIDDEN: 403,
28
+ NOT_FOUND: 404,
29
+ METHOD_NOT_ALLOWED: 405,
30
+ NOT_ACCEPTABLE: 406,
31
+ PROXY_AUTHENTICATION_REQUIRED: 407,
32
+ REQUEST_TIMEOUT: 408,
33
+ CONFLICT: 409,
34
+ GONE: 410,
35
+ LENGTH_REQUIRED: 411,
36
+ PRECONDITION_FAILED: 412,
37
+ PAYLOAD_TOO_LARGE: 413,
38
+ URI_TOO_LONG: 414,
39
+ UNSUPPORTED_MEDIA_TYPE: 415,
40
+ RANGE_NOT_SATISFIABLE: 416,
41
+ EXPECTATION_FAILED: 417,
42
+ IM_A_TEAPOT: 418,
43
+ MISDIRECTED_REQUEST: 421,
44
+ UNPROCESSABLE_ENTITY: 422,
45
+ LOCKED: 423,
46
+ FAILED_DEPENDENCY: 424,
47
+ TOO_EARLY: 425,
48
+ UPGRADE_REQUIRED: 426,
49
+ PRECONDITION_REQUIRED: 428,
50
+ TOO_MANY_REQUESTS: 429,
51
+ REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
52
+ UNAVAILABLE_FOR_LEGAL_REASONS: 451,
53
+ INTERNAL_SERVER_ERROR: 500,
54
+ NOT_IMPLEMENTED: 501,
55
+ BAD_GATEWAY: 502,
56
+ SERVICE_UNAVAILABLE: 503,
57
+ GATEWAY_TIMEOUT: 504,
58
+ HTTP_VERSION_NOT_SUPPORTED: 505,
59
+ VARIANT_ALSO_NEGOTIATES: 506,
60
+ INSUFFICIENT_STORAGE: 507,
61
+ LOOP_DETECTED: 508,
62
+ BANDWIDTH_LIMIT_EXCEEDED: 509,
63
+ NOT_EXTENDED: 510,
64
+ NETWORK_AUTHENTICATION_REQUIRED: 511,
65
+ };
66
+
67
+ module.exports = {
68
+ HttpCodes
69
+ };
@@ -0,0 +1,78 @@
1
+
2
+ function typeOf(input) {
3
+ return Object.prototype.toString.call(input).slice(8, -1);
4
+ }
5
+
6
+ function isObject(input) {
7
+ return typeOf(input) === 'Object';
8
+ }
9
+
10
+ function isEmptyObject(input) {
11
+ return isObject(input) && Object.keys(input).length === 0;
12
+ }
13
+
14
+ function isArray(input) {
15
+ return Array.isArray(input);
16
+ }
17
+
18
+ function isEmptyArray(input) {
19
+ return isArray(input) && input.length === 0;
20
+ }
21
+
22
+ function isFunction(input) {
23
+ return typeof input === 'function';
24
+ }
25
+
26
+ function isString(input) {
27
+ return typeOf(input) === 'String';
28
+ }
29
+
30
+ function isEmptyString(input) {
31
+ return isString(input) && input.length === 0;
32
+ }
33
+
34
+ function isNumber(input) {
35
+ return typeOf(input) === 'Number';
36
+ }
37
+
38
+ function isBigInt(input) {
39
+ return typeof input === 'bigint';
40
+ }
41
+
42
+ function isSymbol(input) {
43
+ return typeof input === 'symbol';
44
+ }
45
+
46
+ function isBoolean(input) {
47
+ return typeOf(input) === 'Boolean';
48
+ }
49
+
50
+ function isNull(input) {
51
+ return input === null;
52
+ }
53
+
54
+ function isUndefined(input) {
55
+ return input === undefined;
56
+ }
57
+
58
+ function isNullOrUndefined(input) {
59
+ return isNull(input) || isUndefined(input);
60
+ }
61
+
62
+ module.exports = Object.assign(typeOf, {
63
+ typeOf,
64
+ isObject,
65
+ isEmptyObject,
66
+ isArray,
67
+ isEmptyArray,
68
+ isFunction,
69
+ isNull,
70
+ isUndefined,
71
+ isNullOrUndefined,
72
+ isBoolean,
73
+ isNumber,
74
+ isString,
75
+ isEmptyString,
76
+ isSymbol,
77
+ isBigInt
78
+ });
@@ -31,6 +31,7 @@ function processEachFile({ source: sourceRootPath, web: outputRootPath, module:
31
31
  var component = require(file.path);
32
32
  }
33
33
  catch (error) {
34
+ if (path.parse(file.name).ext === '.js') console.error('[BINHEND][WEB-BUILD]', error);
34
35
  return cloneFileIfNew(fileSourcePath, fileOutputPath);
35
36
  }
36
37
 
@@ -5,6 +5,7 @@ const { scanNestedFiles, cloneFileIfNew, printError, makeFullDirPath, writeToFil
5
5
 
6
6
  const PREFIX_CODE =
7
7
  `var { context, tag, svg, script, require, css } = binh.context(module, require);
8
+ var Binh = binh.Binh;
8
9
  binh.component(context, ui, service, style);
9
10
  var ui = null, service = null, style = null;\r\n\r\n`;
10
11
 
@@ -0,0 +1,141 @@
1
+
2
+ const path = require('path');
3
+ const { isString } = require('../utils/typeOf');
4
+ const Component = require('./component');
5
+
6
+ const binh = {};
7
+
8
+ global.binh = binh;
9
+
10
+ binh.context = function(module, defaultRequire) {
11
+ var context = { module, require: defaultRequire };
12
+
13
+ return {
14
+ context,
15
+ tag: tag.bind(context),
16
+ svg: svg.bind(context),
17
+ script: script.bind(context),
18
+ require: customRequire.bind(context),
19
+ css: css.bind(context)
20
+ };
21
+ };
22
+
23
+ function tagnames(tagNames) {
24
+ return typeof tagNames === 'string' ? tagNames.split(/\s+/) : [];
25
+ }
26
+
27
+ function tag(tagNames) {
28
+ var htmltags = this.component.htmltags;
29
+ htmltags.push.apply(htmltags, tagnames(tagNames));
30
+ }
31
+
32
+ function svg(tagNames) {
33
+ var svgtags = this.component.svgtags;
34
+ svgtags.push.apply(svgtags, tagnames(tagNames));
35
+ }
36
+
37
+ function script() {
38
+ var scripts = Array.from(arguments);
39
+ var links = this.component.links;
40
+ links.push.apply(links, scripts);
41
+ }
42
+
43
+ function customRequire(filePath) {
44
+ filePath = filePath.endsWith('.css') ? (filePath+'.js') : filePath;
45
+ return this.require(filePath);
46
+ }
47
+
48
+ function css() {
49
+ var csses = Array.from(arguments);
50
+ var appliedStyles = this.component.options.csses;
51
+ appliedStyles.push.apply(appliedStyles, csses);
52
+ }
53
+
54
+ binh.component = function(context, ui, service, style) {
55
+ var component = ui || service || style;
56
+ var type = ui && 'ui' || service && 'service' || style && 'style';
57
+
58
+ if (!(component instanceof Function)) return;
59
+
60
+ context.component = component;
61
+
62
+ var module = context.module;
63
+ module.exports = component;
64
+
65
+ component.module = module;
66
+ component.constructor = Component;
67
+ component.filename = module.filename;
68
+ component.type = type;
69
+
70
+ component.htmltags = [];
71
+ component.svgtags = [];
72
+ component.links = [];
73
+ component.options = { csses: [] };
74
+ component.vars = {};
75
+ component.varname = getVariableName(component.filename);
76
+ component.as = alias;
77
+ component.eachChild = loopComponentChildren;
78
+ };
79
+
80
+ binh.final = function(module) {
81
+ var component = module.exports;
82
+
83
+ component.eachChild && component.eachChild(childComponent => {
84
+ if (childComponent.alias) {
85
+ component.vars[childComponent.filename] = childComponent.alias;
86
+ }
87
+ });
88
+ };
89
+
90
+ function loopComponentChildren(callback) {
91
+ this.module.children.forEach(childModule => {
92
+ var childComponent = childModule.exports;
93
+ if (!(childComponent instanceof Function) || childComponent.constructor !== Component) return;
94
+ callback(childComponent);
95
+ });
96
+ }
97
+
98
+ binh.ui = function(module, component, htmltags, links) {
99
+ binh.component({ module }, component);
100
+ component.htmltags = htmltags;
101
+ component.links = links;
102
+ binh.final(module);
103
+ };
104
+
105
+ binh.service = function(module, component, links) {
106
+ binh.component({ module }, null, component, null);
107
+ component.links = links;
108
+ binh.final(module);
109
+ };
110
+
111
+ binh.style = function(module, component) {
112
+ binh.component({ module }, null, null, component);
113
+ binh.final(module);
114
+ };
115
+
116
+ binh.css = function(module, cssFilename) {
117
+ var cssFilePath = cssFilename && path.join(module.path, cssFilename) || module.filename.replace(/.js$/, '');
118
+ var content = fs.readFileSync(cssFilePath, { encoding: 'utf8', flag: 'r' });
119
+ content = UglifyCSS.processString(content);
120
+ var component = new Function(`return function style() { return ${JSON.stringify(content)}; };`)();
121
+ component.cssFilePath = cssFilePath;
122
+ binh.component({ module }, null, null, component);
123
+ binh.final(module);
124
+ };
125
+
126
+ binh.Binh = function() {}; // dummy Binh object for binhjs => build web not logging error of undefined
127
+
128
+ function alias(name) {
129
+ if (!isString(name)) return this;
130
+ name = name.trim();
131
+ this.alias = name;
132
+ return this;
133
+ }
134
+
135
+ function getVariableName(filePath) {
136
+ return path.parse(filePath).name.replace(/-/g, '').replace(/\W.*/, '').trim();
137
+ }
138
+
139
+ module.exports = {
140
+ binh
141
+ };
@@ -0,0 +1,46 @@
1
+
2
+ const path = require('path');
3
+ const { isEmptyString, isString } = require('../utils/typeOf');
4
+ const ComponentFormat = require('./component.format');
5
+ const ComponentBuild = require('./component.build');
6
+ const { server } = require('../server');
7
+
8
+ function WebBuilder(source, { output } = {}) {
9
+
10
+ if (isEmptyString(source)) throw new Error(`[BINHEND][WEB] Require source code location. Current: source: ${source}`);
11
+
12
+ source = path.resolve(source);
13
+ output = isString(output) ? output : 'build';
14
+
15
+ if (source === path.resolve(output)) throw new Error(`[BINHEND][WEB] Location of build output & source code should not be the same: ${source}`);
16
+
17
+ var module = path.resolve(output, 'module');
18
+ var web = path.resolve(output, 'web');
19
+ var external = path.resolve(web, 'NPM');
20
+
21
+ this.bundle = () => {
22
+ ComponentFormat.generate(source, module, () => ComponentBuild.bundle({ source, web, module }));
23
+ };
24
+
25
+ this.lazy = () => {
26
+ ComponentFormat.generate(source, module, () => ComponentBuild.lazyload({ source, web, module, external }));
27
+ };
28
+
29
+ this.path = () => {
30
+ return web;
31
+ };
32
+
33
+ this.minify = (flag = true) => {
34
+ Component.minification = flag;
35
+ };
36
+
37
+ setTimeout(() => {
38
+ server.use(express.static(web));
39
+ server.get('/*', (req, res) => res.sendFile('index.html', { root: web }));
40
+ });
41
+
42
+ }
43
+
44
+ module.exports = {
45
+ WebBuilder
46
+ };