binhend 1.0.11 → 1.1.1

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 (37) hide show
  1. package/{example → example_api}/routes/test/bb.js +1 -1
  2. package/{example → example_api}/routes/test/index.js +1 -1
  3. package/{example → example_api}/routes/test/some.js +1 -1
  4. package/{example → example_api}/routes/test.js +5 -1
  5. package/{example → example_api}/routes/testa.js +1 -1
  6. package/example_webcomp/components/AnUserInterface.js +0 -0
  7. package/example_webcomp/components/common/InputText.js +24 -0
  8. package/example_webcomp/components/common/Link.js +16 -0
  9. package/example_webcomp/components/common/Link2.js +13 -0
  10. package/example_webcomp/components/index.html +18 -0
  11. package/example_webcomp/components/index.js +14 -0
  12. package/example_webcomp/components/layouts/AppMainLayout.js +22 -0
  13. package/example_webcomp/components/layouts/AppToDos.js +49 -0
  14. package/example_webcomp/components/layouts/Link.js +16 -0
  15. package/example_webcomp/components/layouts/PageContent.js +25 -0
  16. package/example_webcomp/components/layouts/PageHeader.js +49 -0
  17. package/example_webcomp/components/layouts/ToDoItem.js +26 -0
  18. package/example_webcomp/components/services/AnyService.js +6 -0
  19. package/example_webcomp/components/services/ServiceToDos.js +42 -0
  20. package/example_webcomp/components/styles/ToDoItemStyle.js +40 -0
  21. package/example_webcomp/components/styles/ToDoItemStyle2.js +2 -0
  22. package/example_webcomp/components/styles/temp.css +7 -0
  23. package/example_webcomp/components/styles/todo.css +31 -0
  24. package/example_webcomp/components/styles/todo.css.js +2 -0
  25. package/example_webcomp/config.js +13 -0
  26. package/example_webcomp/index.js +10 -0
  27. package/package.json +12 -2
  28. package/src/binh.js +20 -140
  29. package/src/binh.server.app.js +70 -0
  30. package/src/binh.server.config.js +79 -0
  31. package/src/binh.web.builder.js +72 -0
  32. package/src/code.js +143 -0
  33. package/src/component.js +108 -0
  34. package/src/cryptography.js +6 -1
  35. package/src/server.js +9 -0
  36. /package/{example → example_api}/config.js +0 -0
  37. /package/{example → example_api}/index.js +0 -0
@@ -1,4 +1,4 @@
1
- const { get } = binh().Router(module);
1
+ const { get } = binh.router(module);
2
2
 
3
3
  // get('/', function(req, res) {
4
4
  // res.json({ path:'/', dir: __dirname, file: __filename });
@@ -1,4 +1,4 @@
1
- const { router, get, post } = binh().Router(module);
1
+ const { router, get, post } = binh.router(module);
2
2
 
3
3
  get('/', function(req, res) {
4
4
  res.json({ path:'/', dir: __dirname, file: __filename });
@@ -1,4 +1,4 @@
1
- const { router, get, post } = binh().Router(module);
1
+ const { router, get, post } = binh.router(module);
2
2
 
3
3
  get('/', function(req, res) {
4
4
  res.json({ path:'/', dir: __dirname, file: __filename });
@@ -1,4 +1,8 @@
1
- const { get } = binh().Router(module);
1
+ const { get } = binh.router(module);
2
+
3
+ get('/', function(req, res) {
4
+ res.json({ path:'/', dir: __dirname, file: __filename });
5
+ });
2
6
 
3
7
  get('/bb', function(req, res) {
4
8
  res.json({ path:'/bb', dir: __dirname, file: __filename });
@@ -1,4 +1,4 @@
1
- const { router, get, post } = binh().Router(module);
1
+ const { router, get, post } = binh.router(module);
2
2
 
3
3
  get('/', function(req, res) {
4
4
  res.json({ path:'/', dir: __dirname, file: __filename });
File without changes
@@ -0,0 +1,24 @@
1
+
2
+ require('./../services/ServiceToDos').as('Toto');
3
+
4
+ function main() {
5
+ // var addTodoItem = Toto.debounce('add', 1500, true);
6
+
7
+ // setTimeout(function() {
8
+ // addTodoItem('over 10kms');
9
+ // }, 10000);
10
+
11
+ var inputbox = input({ type: 'text', placeholder: 'Enter to-do item' });
12
+
13
+ var submit = inputbox.action('submit');
14
+
15
+ inputbox.on('keypress', function (event) {
16
+ if (event.key === "Enter") {
17
+ submit(inputbox.element.value);
18
+ }
19
+ });
20
+
21
+ return inputbox;
22
+ }
23
+
24
+ binh.ui(module, main, ['input']);
@@ -0,0 +1,16 @@
1
+
2
+
3
+ function Link() {
4
+ var { a } = Binh.element();
5
+
6
+ var text = arguments[0];
7
+ var path = arguments[1];
8
+
9
+ var link = a(text).on('click', function() {
10
+ Binh.Router.navigate(path);
11
+ });
12
+
13
+ return link;
14
+ }
15
+
16
+ binh.ui(module, Link);
@@ -0,0 +1,13 @@
1
+
2
+ Binh.ui(function() {
3
+ var { a } = Binh.element('a');
4
+
5
+ var text = arguments[0];
6
+ var path = arguments[1];
7
+
8
+ var link = a(text).on('click', function() {
9
+ Binh.Router.navigate(path);
10
+ });
11
+
12
+ return link;
13
+ });
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Binh Demo</title>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <!-- <link rel="stylesheet" href="/lib/bootstrap.3.4.1.min.css"> -->
8
+ <!-- <link rel="stylesheet" href="style.css"> -->
9
+ <!-- <script src="/lib/jquery.3.5.1.min.js"></script>
10
+ <script src="/lib/bootstrap.3.4.1.min.js"></script> -->
11
+
12
+ <script src="http://localhost:1300/dev/binh.min.js"></script>
13
+ <!-- <script src="https://binhjs.pages.dev/dist/binh.min.js"></script> -->
14
+ <!-- <script src="https://cdn.jsdelivr.net/gh/penciless/binhjs/dist/binh.min.js"></script> -->
15
+ <script src="/index.js"></script>
16
+ </head>
17
+ <body></body>
18
+ </html>
@@ -0,0 +1,14 @@
1
+
2
+ Binh.script('https://cdn.jsdelivr.net/gh/jquery/jquery@3.5.1/dist/jquery.min.js', function() {
3
+ Binh.link('https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css');
4
+ Binh.script('https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js');
5
+ });
6
+
7
+ Binh.Router.onload(function() {
8
+ console.log('#### ON ROUTING !!!');
9
+ });
10
+
11
+ Binh({
12
+ '': '/layouts/AppMainLayout.js',
13
+ '/todos': '/layouts/AppToDos.js'
14
+ });
@@ -0,0 +1,22 @@
1
+
2
+ require('./PageHeader');
3
+ require('./PageContent');
4
+ require('./../services/AnyService');
5
+
6
+ function AppMainLayout() {
7
+ var MainLayout = div({ id: 'app-main-layout' });
8
+
9
+ MainLayout(
10
+ PageHeader,
11
+ PageContent,
12
+ function (thisEl) {
13
+ setTimeout(function() {
14
+ console.log('>>> App Main Layout:', thisEl);
15
+ }, 1000);
16
+ }
17
+ );
18
+
19
+ return MainLayout;
20
+ }
21
+
22
+ binh.ui(module, AppMainLayout, ['div'], ['https://code.jquery.com/jquery-3.7.0.min.js', 'https://code.jquery.com/jquery-3.7.0.min.js']);
@@ -0,0 +1,49 @@
1
+
2
+ require('./PageHeader');
3
+ // require('./ToDoItem');
4
+ require('./../common/InputText');
5
+ require('./Link');
6
+ require('./../services/ServiceToDos').as('Dodo');
7
+
8
+
9
+ function main() {
10
+ var ServiceToDos = Dodo;
11
+ // var PageHeader = Binh.ui('/layouts/PageHeader.js');
12
+ var ToDoItem = Binh.ui('/layouts/ToDoItem.js');
13
+ // var addTodoItem = ServiceToDos.does('add');
14
+ // var addTodoItem = ServiceToDos.debounce('add', 1500); // trailing only
15
+ var addTodoItem = ServiceToDos.debounce('add', 1500, true); // both leading & trailing
16
+ // var addTodoItem = ServiceToDos.debounce('add', 1500, true, true); // leading only
17
+ // var addTodoItem = ServiceToDos.throttle('add', 1500);
18
+ // var addTodoItem = ServiceToDos.once('add', 1500);
19
+
20
+ var inputbox = InputText().when('submit', addTodoItem);
21
+
22
+ var todolist = div({ class: 'todo-items' });
23
+
24
+ todolist.subscribe('todos', function(data) {
25
+ todolist.empty();
26
+ data.forEach(function(datum) {
27
+ todolist(
28
+ ToDoItem(datum).when('remove', ServiceToDos.instant('remove'))
29
+ );
30
+ });
31
+ });
32
+
33
+ var maindiv = div({ class: 'container' });
34
+ var left_section = div({ id: 'left-section' })('left section')(PageHeader);
35
+ var right_section = div({ id: 'right-section' })('right section');
36
+
37
+ maindiv(
38
+ left_section,
39
+ right_section(
40
+ div('To-Do List'),
41
+ inputbox,
42
+ todolist
43
+ )
44
+ );
45
+
46
+ return maindiv;
47
+ }
48
+
49
+ binh.ui(module, main, ['div', 'span'], ['https://code.jquery.com/jquery-3.7.0.min.js']);
@@ -0,0 +1,16 @@
1
+
2
+
3
+ function Link() {
4
+ var { a } = Binh.element('a');
5
+
6
+ var text = arguments[0];
7
+ var path = arguments[1];
8
+
9
+ var link = a(text).on('click', function() {
10
+ Binh.Router.navigate(path);
11
+ });
12
+
13
+ return link;
14
+ }
15
+
16
+ binh.ui(module, Link);
@@ -0,0 +1,25 @@
1
+
2
+ function PageContent() {
3
+ var { Router } = Binh;
4
+
5
+ var PageContent = div({ id: 'page-content' });
6
+
7
+ PageContent(
8
+ new Router({
9
+ '': div('default work!'),
10
+ '/abc': div('abc work!'),
11
+ '/haha': trans('haha work!')
12
+ })
13
+ )
14
+ (
15
+ function (thisEl) {
16
+ setTimeout(function() {
17
+ console.log('>>> Page Content:', thisEl);
18
+ }, 1000);
19
+ }
20
+ );
21
+
22
+ return PageContent;
23
+ }
24
+
25
+ binh.ui(module, PageContent, ['div', 'trans'], ['https://code.jquery.com/jquery-3.7.0.min.js']);
@@ -0,0 +1,49 @@
1
+
2
+ var { Link } = require('./../common/Link');
3
+
4
+ function PageHeader() {
5
+ // var Link = Binh.ui('/common/Link2.js');
6
+
7
+ var PageHeader = div({ id: 'page-header' });
8
+
9
+ PageHeader(
10
+ div({ class: 'container' })(
11
+ div({ class: 'row' })(
12
+ nav({ class: 'navbar navbar-default' })(
13
+ div({ class: 'container-fluid' })([
14
+ div({ class: 'navbar-header' })(
15
+ a({ class: 'navbar-brand', href: '#' })(
16
+ 'Website Name'
17
+ )
18
+ ),
19
+ ul({ class: 'nav navbar-nav' })(
20
+ li({ class: 'active' })(
21
+ Link('Home', '/')
22
+ ),
23
+ li(
24
+ Link('Abc', '/abc')
25
+ ),
26
+ li(
27
+ Link('Haha', '/haha')
28
+ ),
29
+ li(
30
+ a('Page 3')
31
+ )
32
+ )
33
+ ])
34
+ )
35
+ )
36
+ ),
37
+ function (thisEl) {
38
+ setTimeout(function() {
39
+ console.log('>>> Page Header:', thisEl);
40
+ }, 1000);
41
+ }
42
+ );
43
+
44
+ return PageHeader;
45
+ }
46
+
47
+ var htmltags = ['div', 'nav', 'ul', 'li', 'a'];
48
+
49
+ binh.ui(module, PageHeader, htmltags);
@@ -0,0 +1,26 @@
1
+
2
+ // require('./../styles/ToDoItemStyle');
3
+ require('./../styles/ToDoItemStyle2');
4
+ // require('../styles/todo.css.js');
5
+
6
+ function main(props) {
7
+ // var ToDoItemStyle = Binh.style('/styles/todo.css');
8
+
9
+ var todoitem = div({ style: 'margin: 3px;' });
10
+ var removeToDoItem = todoitem.action('remove');
11
+
12
+ var remove_button = span({ class: 'btn-remove' })('X');
13
+
14
+ remove_button.on('click', function() {
15
+ removeToDoItem(props.id);
16
+ });
17
+
18
+ todoitem(span(props.text), span('-------'), remove_button);
19
+
20
+ // return todoitem.style(ToDoItemStyle);
21
+ // return todoitem.style('styles/todo.css');
22
+ return todoitem.style(ToDoItemStyle2);
23
+ // return todoitem.style(todo);
24
+ }
25
+
26
+ binh.ui(module, main, ['div', 'span']);
@@ -0,0 +1,6 @@
1
+
2
+ function AnyService() {
3
+
4
+ }
5
+
6
+ binh.service(module, AnyService);
@@ -0,0 +1,42 @@
1
+
2
+ binh.service(module, function(define, state, http) {
3
+ var todos = state.as('todos');
4
+
5
+ todos.schema(function(resolve) {
6
+ new http(api('get'))
7
+ .get(function(response) {
8
+ resolve(parseResponse(response));
9
+ });
10
+ });
11
+
12
+ function handleResponse(response) {
13
+ todos.set(parseResponse(response));
14
+ }
15
+
16
+ function parseResponse(response) {
17
+ var todoitems = [];
18
+
19
+ Object.keys(response).forEach(function(key) {
20
+ var each = response[key];
21
+ todoitems.push({ id: key, text: each.text });
22
+ });
23
+
24
+ return todoitems;
25
+ }
26
+
27
+ define('add', function(value) {
28
+ new http(api('add'))
29
+ .body({ text: value })
30
+ .post(handleResponse);
31
+ });
32
+
33
+ define('remove', function(id) {
34
+ new http(api('remove'))
35
+ .body({ id: id })
36
+ .post(handleResponse);
37
+ });
38
+
39
+ function api(relative_url) {
40
+ return 'https://todolist-of-binh.fly.dev/todos/' + relative_url;
41
+ }
42
+ });
@@ -0,0 +1,40 @@
1
+
2
+ binh.style(module, function(css) {
3
+ // css('@charset "utf-8";');
4
+
5
+ css(`@import url("styles/temp.css");`);
6
+
7
+
8
+ css('.btn-remove', [
9
+ 'color: purple;',
10
+ 'margin-left: 10px'
11
+ ]);
12
+
13
+ css(
14
+ `@media (min-width: 800px) {
15
+ .btn-remove {
16
+ color: red;
17
+ margin-left: '15px';
18
+ }
19
+ }`
20
+ );
21
+
22
+ css(`
23
+ @keyframes slidein {
24
+ from {
25
+ transform: translateX(0%);
26
+ }
27
+
28
+ to {
29
+ transform: translateX(100%);
30
+ }
31
+ }
32
+ `);
33
+
34
+ css(`
35
+ @page {
36
+ size: 8.5in 9in;
37
+ margin-top: 4in;
38
+ }
39
+ `);
40
+ });
@@ -0,0 +1,2 @@
1
+
2
+ binh.css(module, './todo.css');
@@ -0,0 +1,7 @@
1
+
2
+ @import url("/styles/todo.css");
3
+
4
+ .btn-remove {
5
+ color: purple;
6
+ margin-left: '15px';
7
+ }
@@ -0,0 +1,31 @@
1
+ @charset "utf-8";
2
+
3
+ @import url("/styles/temp.css");
4
+
5
+ /* .btn-remove {
6
+ color: blue;
7
+ margin-left: '15px';
8
+ } */
9
+
10
+ @media (min-width: 800px) {
11
+
12
+ .btn-remove {
13
+ color: red;
14
+ margin-left: '15px';
15
+ }
16
+ }
17
+
18
+ @keyframes slidein {
19
+ from {
20
+ transform: translateX(0%);
21
+ }
22
+
23
+ to {
24
+ transform: translateX(100%);
25
+ }
26
+ }
27
+
28
+ @page {
29
+ size: 8.5in 9in;
30
+ margin-top: 4in;
31
+ }
@@ -0,0 +1,2 @@
1
+
2
+ binh.css(module);
@@ -0,0 +1,13 @@
1
+
2
+ module.exports = function(loader) {
3
+ var sample = {
4
+ ABC: 123,
5
+ Text: 'Hello',
6
+ NAME: 'MyApp',
7
+ PORT: 1400
8
+ };
9
+
10
+ var { filter, object } = loader;
11
+
12
+ filter(object, sample, ['PORT', 'NAME']);
13
+ };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ const { Binh } = require('../src/binh');
4
+
5
+ new Binh()
6
+ .web('public', 'components')
7
+ .port(1234)
8
+ .start(function(server, configs) {
9
+ console.log('### START >>> configs:', configs);
10
+ });
package/package.json CHANGED
@@ -1,17 +1,27 @@
1
1
  {
2
2
  "name": "binhend",
3
- "version": "1.0.11",
3
+ "version": "1.1.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "Nguyen Duc Binh",
7
7
  "license": "UNLICENSED",
8
8
  "scripts": {
9
9
  "test": "echo \"Error: no test specified\" && exit 1",
10
- "example": "node example PORT=5555"
10
+ "example-api": "nodemon example_api PORT=5555",
11
+ "example-webcomp": "nodemon example_webcomp"
11
12
  },
12
13
  "dependencies": {
13
14
  "express": "^4.17.1"
14
15
  },
16
+ "devDependencies": {
17
+ "nodemon": "^2.0.20"
18
+ },
19
+ "nodemonConfig": {
20
+ "ignore": [
21
+ "example_webcomp/public/**"
22
+ ],
23
+ "delay": 2500
24
+ },
15
25
  "engines": {
16
26
  "node": ">= 16.17.1"
17
27
  }
package/src/binh.js CHANGED
@@ -1,93 +1,18 @@
1
- const crypto = require('crypto');
2
- const cluster = require('cluster');
3
- const os = require('os');
4
1
  const path = require('path');
5
-
6
- const { ConfigLoader } = require('./configuration');
7
- const { HTTPS } = require('./https');
8
- const { Server } = require('./server');
9
- const { APIs, Router } = require('./api');
10
-
11
2
  const Crypto = require('./cryptography');
12
3
 
13
- const maxcpus = os.cpus().length;
14
-
15
- function generateId() {
16
- crypto.randomUUID({ disableEntropyCache: true });
17
- }
18
-
19
- function defaultConfigLoader(loader) {
20
- loader.object(process.env);
21
-
22
- try {
23
- loader.file('.env');
24
- }
25
- catch(e) {}
4
+ const { HTTPS } = require('./https');
5
+ const { ConfigLoader } = require('./configuration');
26
6
 
27
- loader.cli();
28
- }
7
+ const { ServerApp } = require('./binh.server.app');
8
+ const { ServerConfig } = require('./binh.server.config');
9
+ const { WebBuilder } = require('./binh.web.builder');
29
10
 
30
11
  function Binh() {
31
- var _this = this,
32
- forkcount = 0,
33
- rootpath = require.main.path;
34
-
35
- var config = {}, loadConfigs = null, groupLoadConfigs = [], configloader = new ConfigLoader(config);
36
-
37
- var binh = function(module_path) {
38
- return module_path == undefined ? module.exports : require(path.join(rootpath, module_path));
39
- };
40
-
41
- binh.path = function(any_path = '') {
42
- return path.join(rootpath, any_path);
43
- };
44
-
45
- binh.config = function(key) {
46
- if (typeof key !== 'string') return config;
47
-
48
- if (config.hasOwnProperty(key)) return config[key];
49
-
50
- var pointer = config, keys = key.split('.'), length = keys.length;
51
-
52
- try {
53
- for (var i = 0; i < length; i++) {
54
- pointer = pointer[keys[i]];
55
- }
56
- return pointer;
57
- }
58
- catch (e) {
59
- return undefined;
60
- }
61
- };
62
-
63
- binh.config.reload = function() {
64
- return new Promise(function(resolve) {
65
- var loader = new ConfigLoader(config);
66
-
67
- groupLoadConfigs.forEach(function(loadConfigs) {
68
- if (loadConfigs instanceof Function) {
69
- loadConfigs(loader);
70
- }
71
- });
72
-
73
- loader.done(resolve);
74
- });
75
- };
76
-
77
- binh.config.loader = function() {
78
- return new ConfigLoader(config);
79
- };
80
-
81
- global.binh = binh;
82
- global.config = binh.config;
83
-
84
- this.rootpath = function(path) {
85
- rootpath = typeof path === 'string' ? path : require.main.path;
86
- return this;
87
- };
12
+ var rootpath = require.main.path;
88
13
 
89
14
  this.id = function(id) {
90
- binh.id = id == undefined ? generateId() : JSON.stringify(id);
15
+ binh.id = id == undefined ? Crypto.randomUUID() : JSON.stringify(id);
91
16
  return this;
92
17
  };
93
18
 
@@ -96,73 +21,28 @@ function Binh() {
96
21
  return this;
97
22
  };
98
23
 
99
- this.config = function(module) {
100
- if (module instanceof Function) {
101
- loadConfigs = module;
102
- loadConfigs(configloader);
103
- }
104
- else if (typeof module === 'string') {
105
- loadConfigs = binh(module);
106
- loadConfigs(configloader);
107
- }
108
- else {
109
- loadConfigs = defaultConfigLoader;
110
- loadConfigs(configloader);
111
- }
112
-
113
- groupLoadConfigs.push(loadConfigs);
114
-
24
+ this.rootpath = function(path) {
25
+ rootpath = typeof path === 'string' ? path : require.main.path;
115
26
  return this;
116
27
  };
117
28
 
118
- this.cluster = {
119
- fork: function(number) {
120
- forkcount = Math.max(0, number >= 0 ? number : maxcpus + number);
121
- return _this;
122
- },
123
- max: function() {
124
- forkcount = maxcpus;
125
- return _this;
126
- }
29
+ this.getRootpath = function() {
30
+ return rootpath;
127
31
  };
128
32
 
129
- this.api = function(api_path) {
130
- this.api.value =`${rootpath}/${api_path}`;
131
- return this;
33
+ function binh(modulePath) {
34
+ return modulePath == undefined ? module.exports : require(path.join(rootpath, modulePath));
132
35
  };
133
36
 
134
- this.port = function(port) {
135
- if (typeof port === 'number') {
136
- this.port.value = port;
137
- }
138
- else if (typeof port === 'string') {
139
- this.port.value = binh.config(port);
140
- }
141
- return this;
142
- };
143
-
144
- this.start = function(callback) {
145
- if (forkcount > 0 && cluster.isMaster) {
146
- for (var i = 0; i < forkcount; i++) {
147
- cluster.fork();
148
- }
149
- }
150
- else {
151
- launch(callback);
152
- }
37
+ binh.path = function(anyPath = '') {
38
+ return path.join(rootpath, anyPath);
153
39
  };
154
40
 
155
- function launch(callback) {
156
- configloader.done(function(configs) {
157
- new Server({
158
- port: _this.port.value,
159
- api: APIs(_this.api.value),
160
- callback: callback,
161
- configs: configs
162
- });
163
- });
164
- }
41
+ ServerApp(binh, this, ServerConfig(binh, this));
42
+ WebBuilder(binh, this);
165
43
 
44
+ global.binh = binh;
45
+ global.config = binh.config;
166
46
  }
167
47
 
168
- module.exports = { Binh, HTTPS, ConfigLoader, Crypto, Router };
48
+ module.exports = { Binh, HTTPS, ConfigLoader, Crypto };
@@ -0,0 +1,70 @@
1
+
2
+ const os = require('os');
3
+ const cluster = require('cluster');
4
+ const path = require('path');
5
+ const { Server } = require('./server');
6
+ const { APIs, Router } = require('./api');
7
+
8
+ const maxcpus = os.cpus().length;
9
+
10
+ function ServerApp(binh, Binh, configloader) {
11
+ var forkcount = 0,
12
+ rootpath = Binh.getRootpath();
13
+
14
+ binh.router = function(module) {
15
+ return Router(module);
16
+ };
17
+
18
+ Binh.api = function(api_path) {
19
+ Binh.api.value = path.join(rootpath, api_path);
20
+ return Binh;
21
+ };
22
+
23
+ Binh.cluster = {
24
+ fork: function(number) {
25
+ forkcount = Math.max(0, number >= 0 ? number : maxcpus + number);
26
+ return Binh;
27
+ },
28
+ max: function() {
29
+ forkcount = maxcpus;
30
+ return Binh;
31
+ }
32
+ };
33
+
34
+ Binh.port = function(port) {
35
+ if (typeof port === 'number') {
36
+ Binh.port.value = port;
37
+ }
38
+ else if (typeof port === 'string') {
39
+ Binh.port.value = binh.config(port);
40
+ }
41
+ return Binh;
42
+ };
43
+
44
+ Binh.start = function(callback) {
45
+ if (forkcount > 0 && cluster.isMaster) {
46
+ for (var i = 0; i < forkcount; i++) {
47
+ cluster.fork();
48
+ }
49
+ }
50
+ else {
51
+ launch(callback);
52
+ }
53
+ };
54
+
55
+ function launch(callback) {
56
+ configloader.done(function(configs) {
57
+ new Server({
58
+ port: Binh.port.value,
59
+ api: APIs(Binh.api.value),
60
+ web: Binh.web.value,
61
+ callback: callback,
62
+ configs: configs
63
+ });
64
+ });
65
+ }
66
+ }
67
+
68
+ module.exports = {
69
+ ServerApp
70
+ };
@@ -0,0 +1,79 @@
1
+
2
+ const { ConfigLoader } = require('./configuration');
3
+
4
+ function ServerConfig(binh, Binh) {
5
+
6
+ var config = {}, loadConfigs = null, groupLoadConfigs = [], configloader = new ConfigLoader(config);
7
+
8
+ binh.config = function(key) {
9
+ if (typeof key !== 'string') return config;
10
+
11
+ if (config.hasOwnProperty(key)) return config[key];
12
+
13
+ var pointer = config, keys = key.split('.'), length = keys.length;
14
+
15
+ try {
16
+ for (var i = 0; i < length; i++) {
17
+ pointer = pointer[keys[i]];
18
+ }
19
+ return pointer;
20
+ }
21
+ catch (e) {
22
+ return undefined;
23
+ }
24
+ };
25
+
26
+ binh.config.reload = function() {
27
+ return new Promise(function(resolve) {
28
+ var loader = new ConfigLoader(config);
29
+
30
+ groupLoadConfigs.forEach(function(loadConfigs) {
31
+ if (loadConfigs instanceof Function) {
32
+ loadConfigs(loader);
33
+ }
34
+ });
35
+
36
+ loader.done(resolve);
37
+ });
38
+ };
39
+
40
+ binh.config.loader = function() {
41
+ return new ConfigLoader(config);
42
+ };
43
+
44
+ Binh.config = function(module) {
45
+ if (module instanceof Function) {
46
+ loadConfigs = module;
47
+ loadConfigs(configloader);
48
+ }
49
+ else if (typeof module === 'string') {
50
+ loadConfigs = binh(module);
51
+ loadConfigs(configloader);
52
+ }
53
+ else {
54
+ loadConfigs = defaultConfigLoader;
55
+ loadConfigs(configloader);
56
+ }
57
+
58
+ groupLoadConfigs.push(loadConfigs);
59
+
60
+ return Binh;
61
+ };
62
+
63
+ return configloader;
64
+ }
65
+
66
+ function defaultConfigLoader(loader) {
67
+ loader.object(process.env);
68
+
69
+ try {
70
+ loader.file('.env');
71
+ }
72
+ catch(e) {}
73
+
74
+ loader.cli();
75
+ }
76
+
77
+ module.exports = {
78
+ ServerConfig
79
+ };
@@ -0,0 +1,72 @@
1
+
2
+ const path = require('path');
3
+
4
+ const Component = require('./component');
5
+
6
+ function WebBuilder(binh, Binh) {
7
+ binh.ui = function(amodule, component, htmltags, links) {
8
+ component.htmltags = htmltags;
9
+ component.links = links;
10
+ binh.bundle('ui', amodule, component);
11
+ };
12
+
13
+ binh.service = function(amodule, component, links) {
14
+ component.links = links;
15
+ binh.bundle('service', amodule, component);
16
+ };
17
+
18
+ binh.style = function(amodule, component) {
19
+ binh.bundle('style', amodule, component);
20
+ };
21
+
22
+ binh.css = function(amodule, cssFilename) {
23
+ var cssFilePath = cssFilename && path.join(amodule.path, cssFilename) || amodule.filename.replace(/.js$/, '');
24
+ var content = require('fs').readFileSync(cssFilePath, { encoding: 'utf8', flag: 'r' });
25
+ content = content.replace(/\s+/g, ' ');
26
+ var component = new Function(`return ${JSON.stringify(content)};`);
27
+ binh.bundle('style', amodule, component);
28
+ };
29
+
30
+ binh.bundle = function(type, amodule, component) {
31
+ if (!(component instanceof Function)) return;
32
+
33
+ component.type = type;
34
+ component.filename = amodule.filename;
35
+ component.constructor = Component;
36
+ component.module = amodule;
37
+ component.as = alias;
38
+ component.vars = {};
39
+
40
+ amodule.exports = component;
41
+
42
+ amodule.children.forEach(function(child) {
43
+ child = child.exports;
44
+ if (child.constructor !== Component) return;
45
+ if (child.alias) component.vars[child.filename] = child.alias;
46
+ });
47
+ };
48
+
49
+ function alias(name) {
50
+ this.alias = name;
51
+ }
52
+
53
+ Binh.web = function(buildpath, sourcepath) {
54
+ if (typeof buildpath !== 'string') return this;
55
+
56
+ var rootpath = Binh.getRootpath(),
57
+ destination = path.join(rootpath, buildpath);
58
+
59
+ if (typeof sourcepath === 'string') {
60
+ var source = path.join(rootpath, sourcepath);
61
+ Component.generate(source, destination);
62
+ }
63
+
64
+ Binh.web.value = destination;
65
+
66
+ return Binh;
67
+ };
68
+ }
69
+
70
+ module.exports = {
71
+ WebBuilder
72
+ };
package/src/code.js ADDED
@@ -0,0 +1,143 @@
1
+
2
+ const { parse } = require('path');
3
+
4
+ function dependencies(component, root, metadata) {
5
+ var global = metadata || {}, local = {}, variables = {}, code = '';
6
+
7
+ var children = component.module.children;
8
+
9
+ children.forEach(function(child) {
10
+ child = child.exports;
11
+
12
+ if (child.constructor !== component.constructor) return;
13
+
14
+ var filename = child.filename;
15
+ var url = filename.replace(root, '').replace(/\\/g, '/');
16
+ var name = component.vars[filename] || parse(filename).name.replace(/-/g, '').replace(/\W.*/, '');
17
+
18
+ local[filename] = {
19
+ name, url,
20
+ type: child.type,
21
+ component: child
22
+ };
23
+ });
24
+
25
+ Object.keys(local).forEach(function(filename) {
26
+ var declaration = '',
27
+ current = local[filename],
28
+ existed = global[filename];
29
+
30
+ var { type, name, url, component } = current;
31
+
32
+ if (existed) {
33
+ var sameVariableName = (name === existed.name);
34
+ if (sameVariableName) return;
35
+
36
+ declaration += `${name} = Binh.${type}('${url}');\r\n`;
37
+ variables[name] = true;
38
+ }
39
+ else {
40
+ declaration += `${name} = Binh.${type}('${url}', ${component.toString()});\r\n`;
41
+ global[filename] = local[filename];
42
+ variables[name] = true;
43
+ };
44
+
45
+ code += IIF([
46
+ declaration,
47
+ dependencies(component, root, Object.assign({}, global, local))
48
+ ]);
49
+
50
+ code += '\r\n\r\n';
51
+ });
52
+
53
+ var vars = Object.keys(variables);
54
+
55
+ if (vars.length) {
56
+ code += `var ${vars.join(', ')};\r\n`;
57
+ }
58
+
59
+ return code;
60
+ }
61
+
62
+ function bundle(component, root) {
63
+ var code = '';
64
+
65
+ if (component.filename.indexOf('AppToDos.js') > -1) {
66
+ console.log('debug');
67
+ }
68
+
69
+ code += dependencies(component, root);
70
+
71
+ code += '\r\n';
72
+
73
+ code += `Binh.${component.type}(${component.toString()});\r\n`;
74
+
75
+ return code;
76
+ }
77
+
78
+ function htmltags(component) {
79
+ var code = '', list = [],
80
+ tags = distinctValues(component, 'htmltags');
81
+
82
+ tags.forEach(function(tag) {
83
+ list.push(`${tag} = Binh.el('${tag}')`);
84
+ });
85
+
86
+ if (list.length) {
87
+ code = `var ${list.join(',\r\n')};`;
88
+ }
89
+
90
+ code += code ? '\r\n' : '';
91
+
92
+ return code;
93
+ }
94
+
95
+ function prequire(component, codes) {
96
+ var code = '', links = distinctValues(component, 'links');
97
+
98
+ if (links.length) {
99
+ code = `Binh.prequire(['${links.join("','")}'], function() {\r\n\r\n${codes.join('\r\n')}\r\n});`;
100
+ }
101
+ else {
102
+ code = IIF(codes);
103
+ }
104
+
105
+ return code;
106
+ }
107
+
108
+ function IIF(codes) {
109
+ return `!function(){\r\n\r\n${codes.join('\r\n')}\r\n}();`
110
+ }
111
+
112
+ function distinctValues(component, key) {
113
+ var arrays = [component[key]];
114
+
115
+ component.module.children.forEach(function(child) {
116
+ arrays.push(child.exports[key]);
117
+ });
118
+
119
+ return uniquefy(arrays);
120
+ }
121
+
122
+ function uniquefy(arrays) {
123
+ var map = {};
124
+
125
+ if (!(arrays instanceof Array)) return;
126
+
127
+ arrays.forEach(function(array) {
128
+ if (!(array instanceof Array)) return;
129
+
130
+ array.forEach(function(value) {
131
+ map[value] = true;
132
+ });
133
+ });
134
+
135
+ return Object.keys(map);
136
+ }
137
+
138
+ module.exports = {
139
+ bundle,
140
+ htmltags,
141
+ prequire,
142
+ IIF
143
+ };
@@ -0,0 +1,108 @@
1
+
2
+ const { readdir, statSync, writeFile, existsSync, mkdirSync, copyFile, readFileSync } = require('fs');
3
+ const { join, dirname, parse } = require('path');
4
+ const CodeFormat = require('./code');
5
+
6
+ // TODO
7
+ // [-] Enhance code by removing sync logics (except for existsSync, mkdirSync): readdir, readFileSync, (statSync?)
8
+ // [-] Able to minify/beautify generated files
9
+
10
+ function generate(source, destination) {
11
+ if (source == undefined) return;
12
+ console.log('[BINHEND][COMPONENT] Start building components from:', source);
13
+ console.log('[BINHEND][COMPONENT] to:', destination);
14
+ processDirectory(source, source, destination);
15
+ }
16
+
17
+ function processDirectory(root, current, destination) {
18
+ readdir(current, function (error, dirents) {
19
+ if (error) {
20
+ showError('Failed scanning directory', filepath, error);
21
+ return;
22
+ }
23
+
24
+ dirents.forEach(function (dirent) {
25
+ var filepath = join(current, dirent);
26
+
27
+ try {
28
+ var stat = statSync(filepath);
29
+
30
+ if (stat.isFile()) {
31
+ var outpath = filepath.replace(root, destination);
32
+ ensureDirectoryExistence(outpath);
33
+
34
+ if (parse(dirent).ext !== '.js') {
35
+ return cloneFile(filepath, outpath);
36
+ }
37
+
38
+ try {
39
+ var component = require(filepath);
40
+ }
41
+ catch (error) {
42
+ var content = readFileSync(filepath, { encoding: 'utf8', flag: 'r' });
43
+ var isComponent = content.match(/\s*binh\s*.(ui|service|style)\s*\(\s*module\s*,.*\)/);
44
+ if (isComponent) {
45
+ showError('Failed requiring module', filepath, error);
46
+ return;
47
+ }
48
+ return cloneFile(filepath, outpath);
49
+ }
50
+
51
+ if (!(component instanceof Function) || component.constructor !== Component) {
52
+ return cloneFile(filepath, outpath);
53
+ }
54
+
55
+ var code = joinCodes(component, root);
56
+
57
+ writeFile(outpath, code, { encoding: 'utf8', flag: 'w' }, function(error) {
58
+ if (error) {
59
+ showError('Failed writing file', filepath, error);
60
+ return;
61
+ }
62
+ });
63
+ }
64
+ else if (stat.isDirectory()) {
65
+ processDirectory(root, filepath, destination);
66
+ }
67
+ }
68
+ catch (error) {
69
+ showError('Failed processing file', filepath, error);
70
+ }
71
+ });
72
+ });
73
+ }
74
+
75
+ function ensureDirectoryExistence(filepath) {
76
+ var dirpath = dirname(filepath);
77
+ if (existsSync(dirpath)) return true;
78
+ ensureDirectoryExistence(dirpath);
79
+ mkdirSync(dirpath);
80
+ }
81
+
82
+ function joinCodes(component, root) {
83
+ var fullcode = CodeFormat.prequire(component, [
84
+ CodeFormat.bundle(component, root),
85
+ CodeFormat.htmltags(component)
86
+ ]);
87
+
88
+ return fullcode;
89
+ }
90
+
91
+ function cloneFile(filepath, outpath) {
92
+ copyFile(filepath, outpath, function(error) {
93
+ if (error) {
94
+ showError('Failed copying file to', outpath, error);
95
+ }
96
+ });
97
+ }
98
+
99
+ function showError(message, id, error) {
100
+ console.log(`[BINHEND][COMPONENT] ${message}:`, id);
101
+ console.log('[BINHEND][COMPONENT] Error details:', error);
102
+ }
103
+
104
+ var Component = {
105
+ generate
106
+ };
107
+
108
+ module.exports = Component;
@@ -4,6 +4,10 @@ const algorithm = 'aes-256-cbc';
4
4
  const lenght_iv = 16;
5
5
  const lenght_key = 32;
6
6
 
7
+ function randomUUID(disableEntropyCache = true) {
8
+ crypto.randomUUID({ disableEntropyCache });
9
+ }
10
+
7
11
  function generateSecurityKey() {
8
12
  return crypto.randomBytes(lenght_key).toString('hex');
9
13
  }
@@ -45,5 +49,6 @@ function hash(text, encoding = 'hex', length = 256) {
45
49
  module.exports = {
46
50
  encrypt, decrypt, hash,
47
51
  generateSecurityKey,
48
- generateInitialVector
52
+ generateInitialVector,
53
+ randomUUID
49
54
  };
package/src/server.js CHANGED
@@ -3,10 +3,19 @@ const express = require('express');
3
3
  function Server(options) {
4
4
  const server = express();
5
5
  const PORT = options.port || 1300;
6
+ const WEB_DIRECTORY = options.web;
7
+
8
+ if (WEB_DIRECTORY) {
9
+ server.use(express.static(WEB_DIRECTORY));
10
+ }
6
11
 
7
12
  if (options.api instanceof Function) {
8
13
  server.use(options.api);
9
14
  }
15
+
16
+ if (WEB_DIRECTORY) {
17
+ server.get('/*', (req, res) => res.sendFile('index.html', { root: WEB_DIRECTORY }));
18
+ }
10
19
 
11
20
  server.listen(PORT, function() {
12
21
  console.log(`[NODE] Server is listening on http://localhost:${PORT}/`);
File without changes
File without changes