@makano/rew 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. package/bin/rew +9 -0
  2. package/bin/ui +0 -0
  3. package/bin/webkit_app +0 -0
  4. package/lib/coffeescript/browser.js +151 -0
  5. package/lib/coffeescript/cake.js +135 -0
  6. package/lib/coffeescript/coffeescript.js +409 -0
  7. package/lib/coffeescript/command.js +750 -0
  8. package/lib/coffeescript/grammar.js +2496 -0
  9. package/lib/coffeescript/helpers.js +477 -0
  10. package/lib/coffeescript/index.js +217 -0
  11. package/lib/coffeescript/lexer.js +1943 -0
  12. package/lib/coffeescript/nodes.js +9204 -0
  13. package/lib/coffeescript/optparse.js +230 -0
  14. package/lib/coffeescript/parser.js +1344 -0
  15. package/lib/coffeescript/register.js +100 -0
  16. package/lib/coffeescript/repl.js +305 -0
  17. package/lib/coffeescript/rewriter.js +1138 -0
  18. package/lib/coffeescript/scope.js +187 -0
  19. package/lib/coffeescript/sourcemap.js +229 -0
  20. package/lib/rew/cli/cli.js +117 -0
  21. package/lib/rew/cli/log.js +40 -0
  22. package/lib/rew/cli/run.js +20 -0
  23. package/lib/rew/cli/utils.js +122 -0
  24. package/lib/rew/const/default.js +35 -0
  25. package/lib/rew/const/files.js +15 -0
  26. package/lib/rew/css/theme.css +3 -0
  27. package/lib/rew/functions/core.js +85 -0
  28. package/lib/rew/functions/emitter.js +57 -0
  29. package/lib/rew/functions/export.js +9 -0
  30. package/lib/rew/functions/future.js +22 -0
  31. package/lib/rew/functions/id.js +13 -0
  32. package/lib/rew/functions/import.js +57 -0
  33. package/lib/rew/functions/map.js +17 -0
  34. package/lib/rew/functions/match.js +34 -0
  35. package/lib/rew/functions/sleep.js +5 -0
  36. package/lib/rew/functions/types.js +96 -0
  37. package/lib/rew/html/ui.html +223 -0
  38. package/lib/rew/main.js +17 -0
  39. package/lib/rew/models/enum.js +14 -0
  40. package/lib/rew/models/struct.js +41 -0
  41. package/lib/rew/modules/compiler.js +17 -0
  42. package/lib/rew/modules/context.js +50 -0
  43. package/lib/rew/modules/fs.js +19 -0
  44. package/lib/rew/modules/runtime.js +24 -0
  45. package/lib/rew/modules/utils.js +0 -0
  46. package/lib/rew/modules/yaml.js +36 -0
  47. package/lib/rew/pkgs/conf.js +92 -0
  48. package/lib/rew/pkgs/data.js +8 -0
  49. package/lib/rew/pkgs/date.js +98 -0
  50. package/lib/rew/pkgs/modules/data/bintree.js +66 -0
  51. package/lib/rew/pkgs/modules/data/doublylinked.js +100 -0
  52. package/lib/rew/pkgs/modules/data/linkedList.js +88 -0
  53. package/lib/rew/pkgs/modules/data/queue.js +28 -0
  54. package/lib/rew/pkgs/modules/data/stack.js +27 -0
  55. package/lib/rew/pkgs/modules/ui/classes.js +171 -0
  56. package/lib/rew/pkgs/pkgs.js +13 -0
  57. package/lib/rew/pkgs/ui.js +108 -0
  58. package/package.json +41 -0
@@ -0,0 +1,223 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>$OPTIONS(title)</title>
7
+
8
+ <style>/* $OPTIONS(style) */</style>
9
+
10
+ <script>
11
+ window.execContext = $OPTIONS(json.execContext);
12
+ </script>
13
+ <script>
14
+ window.exec = $OPTIONS(exec);
15
+ </script>
16
+ <script>
17
+ if(!window.execContext) window.execContext = {};
18
+ window.addEventListener("load", () => {
19
+ const ws = new WebSocket("ws://localhost:$OPTIONS(port)");
20
+ const DOM = [];
21
+
22
+ const findInDom = (id) =>
23
+ DOM.find((el) => el.widgetOptions.uuid == id) ||
24
+ DOM.find((el) => el.id == id);
25
+
26
+ const parseStyleValue = (val) => val;
27
+
28
+ const addTo = (el, parent) => {
29
+ if (parent == "null") {
30
+ document.body.appendChild(el);
31
+ } else {
32
+ findInDom(parent).appendChild(el);
33
+ }
34
+ };
35
+
36
+ const initElement = (el, options, update = false) => {
37
+ if(el.widgetOptions){
38
+ if (el.widgetOptions.style) {
39
+ for(let i in options.style){
40
+ el.style.removeProperty(i, el.widgetOptions.style[i]);
41
+ }
42
+ }
43
+ if (el.widgetOptions.attr) {
44
+ for(let i in el.widgetOptions.attr){
45
+ el.removeAttribute(i);
46
+ }
47
+ }
48
+ }
49
+
50
+ el.widgetOptions = options;
51
+ el.id = options.id;
52
+ el.textContent = options.data.text;
53
+
54
+ if (options.style) {
55
+ for(let i in options.style){
56
+ el.style.setProperty(i, options.style[i]);
57
+ }
58
+ }
59
+
60
+ if (options.attr) {
61
+ for(let i in options.attr){
62
+ el.setAttribute(i, options.attr[i]);
63
+ }
64
+ }
65
+
66
+ if (options.children.length) {
67
+ options.children.forEach((option) => {
68
+ option.parent = options.uuid;
69
+ if(update) updateElement(findInDom(option.uuid), option);
70
+ else createElement(option);
71
+ });
72
+ }
73
+
74
+ if (options.parent) {
75
+ addTo(el, options.parent);
76
+ }
77
+ }
78
+
79
+ const updateElement = (el, options) => {
80
+ if(!el) return;
81
+ initElement(el, options, true);
82
+ return el;
83
+ }
84
+
85
+ const events = [
86
+ "click", "dblclick", "mousedown", "mouseup", "mouseover", "mouseout",
87
+ "mousemove", "mouseenter", "mouseleave", "keydown", "keypress", "keyup",
88
+ "change", "input", "submit", "focus", "blur", "copy", "cut", "paste",
89
+ "scroll", "wheel", "resize", "contextmenu", "drag", "dragstart", "dragend",
90
+ "dragenter", "dragleave", "dragover", "drop", "error", "load", "abort"
91
+ ];
92
+ const handleListeners = (el) => {
93
+ events.forEach(event => {
94
+ el.addEventListener(event, (e) => {
95
+ ws.send(JSON.stringify({
96
+ action: 'hook:eventTrigger',
97
+ data: {
98
+ rid: 'event_trigger',
99
+ object: {
100
+ uuid: el.widgetOptions.uuid,
101
+ event,
102
+ data: {
103
+ mouse: { x: e.clientX, y: e.clientY },
104
+ key: { code: e.keyCode, key: e.key }
105
+ }
106
+ }
107
+ }
108
+ }))
109
+ });
110
+ });
111
+ }
112
+
113
+ function eventHandlerFunction({ uuid, hookID, event }){
114
+ return function(e){
115
+ ws.send(JSON.stringify({
116
+ action: 'hook:event_'+event,
117
+ data: {
118
+ rid: hookID,
119
+ object: {
120
+ uuid,
121
+ event,
122
+ data: {
123
+ mouse: { x: e.clientX, y: e.clientY },
124
+ key: { code: e.keyCode, key: e.key }
125
+ }
126
+ }
127
+ }
128
+ }));
129
+ }
130
+ }
131
+
132
+ const createElement = (options) => {
133
+ const el = document.createElement(options.element);
134
+ DOM.push(el);
135
+ initElement(el, options);
136
+ return el;
137
+ };
138
+
139
+ const stringifyJSON = (json) => {
140
+ try {
141
+ return JSON.stringify(json, null, 4);
142
+ } catch (e) {
143
+ return json.toString();
144
+ }
145
+ };
146
+
147
+ const log = (...strings) => {
148
+ window.webkit.messageHandlers.external.postMessage(
149
+ JSON.stringify({"action": "log", "data": strings
150
+ .map((r) =>
151
+ typeof r == "object" ? stringifyJSON(r) : `${r.toString()}`,
152
+ )
153
+ // .map((i) => i.replace(/\"/g, '\\\\"').replace(/\n/g, "\\\\n"))
154
+ .join("\n")}, null, 4)
155
+ );
156
+ };
157
+
158
+ if (
159
+ window.webkit &&
160
+ window.webkit.messageHandlers &&
161
+ window.webkit.messageHandlers.external &&
162
+ window.RUNID == "$OPTIONS(runId)"
163
+ ) {
164
+
165
+ ws.onmessage = (event, cb) => {
166
+ const edata = process_data(event.data);
167
+ if (edata.action == "init") {
168
+ document.title = edata.data.title;
169
+ window.webkit.messageHandlers.external.postMessage(
170
+ `{"action": "setTitle", "data": "${edata.data.title}"}`,
171
+ );
172
+ log("INIT::READY");
173
+ if(window.exec){
174
+ window.exec(window.execContext);
175
+ }
176
+ } else if(edata.action == 'eventListen') {
177
+ const el = findInDom(edata.data.uuid);
178
+ if(el){
179
+ el.addEventListener(edata.data.event, eventHandlerFunction(edata.data))
180
+ }
181
+ } else if (edata.action == "createElement") {
182
+ const options = edata.data;
183
+ try {
184
+ createElement(options);
185
+ } catch (e) {
186
+ log(e.toString());
187
+ }
188
+ } else if (edata.action == "addStyleSheet") {
189
+ const style = document.createElement('style');
190
+ style.textContent = edata.data;
191
+ document.head.appendChild(style);
192
+ } else if (edata.action == "updateElement") {
193
+ const options = edata.data;
194
+ try {
195
+ updateElement(findInDom(options.uuid), options);
196
+ } catch (e) {
197
+ log(e.toString());
198
+ }
199
+ } else if (edata.action == "findElement") {
200
+ const id = edata.data.id;
201
+ const rid = edata.data.rid;
202
+ try {
203
+ ws.send(JSON.stringify({ action: 'hook:findElement', data: { rid, object: findInDom(id)?.widgetOptions } }))
204
+ } catch (e) {
205
+ log(e.toString());
206
+ }
207
+ }
208
+ };
209
+ } else {
210
+ console.log("Not in a webkit window");
211
+ }
212
+
213
+ function process_data(data) {
214
+ return JSON.parse(data);
215
+ }
216
+ });
217
+ </script>
218
+ </head>
219
+
220
+ <body>
221
+
222
+ </body>
223
+ </html>
@@ -0,0 +1,17 @@
1
+ const { compileFile } = require("./modules/compiler");
2
+ const { exec, runPath } = require("./modules/runtime");
3
+ const fs = require("fs");
4
+ const { imp } = require("./functions/import");
5
+ const { FILES } = require("./const/files");
6
+
7
+ module.exports.run = function (filepath, options = {}, custom_context = {}) {
8
+ FILES.forEach(file => {
9
+ if(fs.existsSync(file.path)) return;
10
+ if(file.content){
11
+ fs.writeFileSync(file.path, file.content);
12
+ } else {
13
+ fs.mkdirSync(file.path, { recursive: true });
14
+ }
15
+ });
16
+ return runPath(filepath, options, custom_context);
17
+ };
@@ -0,0 +1,14 @@
1
+ module.exports.cenum = function cenum(values) {
2
+ var enumObj, i, len, value;
3
+ // Create an object to hold the enum values
4
+ enumObj = {};
5
+ for (i = 0, len = values.length; i < len; i++) {
6
+ value = values[i];
7
+ enumObj[value] = value;
8
+ }
9
+ // Add a method to check if a value is a valid enum value
10
+ enumObj.isValid = function (val) {
11
+ return indexOf.call(enumObj, val) >= 0;
12
+ };
13
+ return enumObj;
14
+ };
@@ -0,0 +1,41 @@
1
+ const { generateRandomID } = require("../functions/id");
2
+
3
+ module.exports.struct = function struct(template) {
4
+ var key, types, value;
5
+
6
+ types = {};
7
+ for (key in template) {
8
+ value = template[key];
9
+ types[key] = typeof value;
10
+ }
11
+
12
+ const fun = function (properties = {}) {
13
+ var defaultValue, instance;
14
+ instance = {};
15
+ for (key in template) {
16
+ defaultValue = template[key];
17
+ if (key in properties) {
18
+ value = properties[key];
19
+ if (defaultValue != "!any" && typeof value !== types[key]) {
20
+ throw new Error(
21
+ `Type error: Expected ${types[key]} for ${key}, got ${typeof value}`,
22
+ );
23
+ }
24
+ instance[key] = value;
25
+ } else {
26
+ instance[key] = defaultValue == "!any" ? null : defaultValue;
27
+ }
28
+ }
29
+ instance.__proto__ = { '@instance': fun };
30
+ return instance;
31
+ };
32
+
33
+ return fun;
34
+ };
35
+
36
+ module.exports.struct.inherits = function (struct, template) {
37
+ return module.exports.struct({
38
+ ...struct(),
39
+ ...template,
40
+ });
41
+ };
@@ -0,0 +1,17 @@
1
+ const { compile } = require("../../coffeescript/coffeescript");
2
+ const { getFile } = require("./fs");
3
+
4
+ const cpl = (module.exports.compile = function (file, options = {}) {
5
+ return compile(file.content, options);
6
+ });
7
+
8
+ module.exports.compileFile = function (filepath, options = {}) {
9
+ const f = getFile(filepath);
10
+ const compiled_code =
11
+ options.compile == false ? f.content : cpl(f, { ...options });
12
+
13
+ return {
14
+ compiled_code,
15
+ file: f,
16
+ };
17
+ };
@@ -0,0 +1,50 @@
1
+ const defaultContext = require("../const/default");
2
+ const emitter = require("../functions/emitter");
3
+ const { exportsFunction } = require("../functions/export");
4
+ const { imp } = require("../functions/import");
5
+
6
+ module.exports.prepareContext = function (
7
+ custom_context,
8
+ options,
9
+ filepath = "",
10
+ runPath = () => {},
11
+ ) {
12
+ let context = {
13
+ module: {
14
+ exports: null,
15
+ options,
16
+ filepath,
17
+ imports: []
18
+ },
19
+ };
20
+ if (options.useContext) {
21
+ context = {
22
+ ...context,
23
+ ...custom_context,
24
+ };
25
+ } else {
26
+ context = {
27
+ ...context,
28
+ ...defaultContext,
29
+ require: (package) => {
30
+ try {
31
+ return require(package);
32
+ } catch (e) {
33
+ throw new Error("Module not found");
34
+ }
35
+ },
36
+ ...custom_context,
37
+ };
38
+ context.imp = imp(runPath, context);
39
+ context.exports = exportsFunction(context);
40
+ }
41
+ if (!context.global) context.global = context;
42
+ if (!context.process)
43
+ context.process = {
44
+ argv: process.argv,
45
+ target: emitter(),
46
+ env: process.env,
47
+ };
48
+ // console.log(custom_context);
49
+ return context;
50
+ };
@@ -0,0 +1,19 @@
1
+ const { struct } = require("../models/struct");
2
+ const fs = require("fs");
3
+
4
+ const file = (module.exports.file = struct({
5
+ path: "",
6
+ content: "",
7
+ }));
8
+
9
+ const readFile = (module.exports.readFile = function readFile(file) {
10
+ return (file.content = fs.readFileSync(file.path, { encoding: "utf-8" }));
11
+ });
12
+
13
+ module.exports.getFile = function (filepath) {
14
+ const f = file({
15
+ path: filepath,
16
+ });
17
+ readFile(f);
18
+ return f;
19
+ };
@@ -0,0 +1,24 @@
1
+ const vm = require("vm");
2
+ const { compileFile } = require("./compiler");
3
+ const { prepareContext } = require("./context");
4
+
5
+ const exec = (module.exports.exec = function (code, context) {
6
+ return vm.runInNewContext(code, vm.createContext(context));
7
+ });
8
+
9
+ module.exports.runPath = function runPath(
10
+ filepath,
11
+ options = {},
12
+ custom_context = {},
13
+ ) {
14
+ const { compiled_code, file } = compileFile(filepath, options);
15
+ const context = prepareContext(custom_context, options, file.path, runPath);
16
+
17
+ context.module.compiled = compiled_code;
18
+ context.process.exit = (int) => process.exit(int);
19
+
20
+ return {
21
+ context,
22
+ returns: exec(compiled_code, context),
23
+ };
24
+ };
File without changes
@@ -0,0 +1,36 @@
1
+ const yaml = require("js-yaml");
2
+ const path = require("path");
3
+ const { getFile } = require("./fs");
4
+
5
+ function yamlFile(file) {
6
+ const schema = new yaml.Schema([
7
+ new yaml.Type("!import", {
8
+ kind: "scalar",
9
+ construct: (p) => importYaml(path.resolve(path.dirname(file.path), p)),
10
+ }),
11
+ new yaml.Type("!int", {
12
+ kind: "scalar",
13
+ construct: (data) => parseInt(data),
14
+ }),
15
+ new yaml.Type("!float", {
16
+ kind: "scalar",
17
+ construct: (data) => parseFloat(data),
18
+ }),
19
+ new yaml.Type("!bool", {
20
+ kind: "scalar",
21
+ construct: (data) => (data == "true" ? true : false),
22
+ }),
23
+ ]);
24
+
25
+ return yaml.load(file.content, { schema });
26
+ }
27
+
28
+ const importYaml = (module.exports.importYaml = function importYaml(
29
+ filepath,
30
+ file,
31
+ ) {
32
+ if (!file) {
33
+ file = getFile(filepath);
34
+ }
35
+ return yamlFile(file);
36
+ });
@@ -0,0 +1,92 @@
1
+ const fs = require('fs');
2
+ const jsYaml = require('js-yaml');
3
+ const path = require('path');
4
+
5
+ const CONFIG_PATH = path.resolve(process.env.HOME, '.config/rew');
6
+
7
+ const createPackageRoot = (packageName) => {
8
+ const rootPath = path.join(CONFIG_PATH, packageName);
9
+ fs.mkdirSync(rootPath, { recursive: true });
10
+ return rootPath;
11
+ }
12
+
13
+ module.exports = (context) => ({
14
+ CONFIG_PATH,
15
+ create: (packageName) => {
16
+ const rootPath = createPackageRoot(packageName);
17
+
18
+ const conf = {};
19
+
20
+ const dumpYaml = (val) => {
21
+ if(JSON.stringify(val) == '{}') return '';
22
+ else return jsYaml.dump(val);
23
+ }
24
+
25
+ const setData = (optionCenter, key, value) => {
26
+ conf[optionCenter.name][key] = value;
27
+ fs.writeFileSync(optionCenter.root, dumpYaml(conf[optionCenter.name]));
28
+ return true;
29
+ }
30
+
31
+ const removeData = (optionCenter, key) => {
32
+ delete conf[optionCenter.name][key];
33
+ fs.writeFileSync(optionCenter.root, dumpYaml(conf[optionCenter.name]));
34
+ return true;
35
+ }
36
+
37
+ const getData = (optionCenter, key) => {
38
+ return conf[optionCenter.name][key];
39
+ }
40
+
41
+ const staticFile = (name, defaultValue = "") => {
42
+ const fileRoot = path.join(rootPath, name);
43
+ const exists = fs.existsSync(fileRoot);
44
+ return {
45
+ create(value){
46
+ if(!fs.existsSync(path.dirname(fileRoot))) fs.mkdirSync(path.dirname(fileRoot), { recursive: true });
47
+ fs.writeFileSync(fileRoot, value || defaultValue);
48
+ },
49
+ fileRoot,
50
+ exists
51
+ }
52
+ }
53
+
54
+ const createOptionCenter = (name, defaults = {}) => {
55
+ const optionRoot = path.join(rootPath, name+'.yaml');
56
+ if(!fs.existsSync(path.dirname(optionRoot))) fs.mkdirSync(path.dirname(optionRoot), { recursive: true });
57
+ if(!fs.existsSync(optionRoot)) {
58
+ conf[name] = defaults;
59
+ fs.writeFileSync(optionRoot, dumpYaml(defaults));
60
+ } else {
61
+ conf[name] = jsYaml.load(fs.readFileSync(optionRoot, { encoding: 'utf-8' }));
62
+ }
63
+
64
+ const optionCenter = {
65
+ root: optionRoot,
66
+ name,
67
+ package: packageName
68
+ }
69
+
70
+ return {
71
+ get: (key) => getData(optionCenter, key),
72
+ set: (key, value) => setData(optionCenter, key, value),
73
+ remove: (key) => removeData(optionCenter, key),
74
+ reset: () => fs.writeFileSync(optionCenter.root, dumpYaml(defaults)) && (conf[name] = defaults),
75
+ getAll: (str = false) => str ? dumpYaml(conf[name]) : conf[name],
76
+ ...optionCenter
77
+ }
78
+ }
79
+
80
+ const defaultCenter = createOptionCenter('_default', { default: true });
81
+
82
+ return {
83
+ optionCenter: createOptionCenter,
84
+ staticFile: staticFile,
85
+ set: (key, value) => defaultCenter.set(key, value),
86
+ get: (key) => defaultCenter.get(key),
87
+ remove: (key) => defaultCenter.remove(key),
88
+ root: rootPath,
89
+ package: packageName
90
+ }
91
+ }
92
+ });
@@ -0,0 +1,8 @@
1
+ const { BinaryTree } = require("./modules/data/bintree");
2
+ const { DoublyLinkedList } = require("./modules/data/doublylinked");
3
+ const { LinkedList } = require("./modules/data/linkedList");
4
+ const { Queue } = require("./modules/data/queue");
5
+ const { Stack } = require("./modules/data/stack");
6
+
7
+
8
+ module.exports = (context) => ({ Stack, Queue, BinaryTree, DoublyLinkedList, LinkedList });
@@ -0,0 +1,98 @@
1
+ // Date and Time Module
2
+
3
+ // Formatting Functions
4
+
5
+ /**
6
+ * Format a date object to a string (YYYY-MM-DD).
7
+ * @param {Date} date - The date object.
8
+ * @return {string} - The formatted date string.
9
+ */
10
+ function formatDate(date) {
11
+ const year = date.getFullYear();
12
+ const month = String(date.getMonth() + 1).padStart(2, '0');
13
+ const day = String(date.getDate()).padStart(2, '0');
14
+ return `${year}-${month}-${day}`;
15
+ }
16
+
17
+ /**
18
+ * Format a time object to a string (HH:MM:SS).
19
+ * @param {Date} date - The date object.
20
+ * @return {string} - The formatted time string.
21
+ */
22
+ function formatTime(date) {
23
+ const hours = String(date.getHours()).padStart(2, '0');
24
+ const minutes = String(date.getMinutes()).padStart(2, '0');
25
+ const seconds = String(date.getSeconds()).padStart(2, '0');
26
+ return `${hours}:${minutes}:${seconds}`;
27
+ }
28
+
29
+ // Parsing Functions
30
+
31
+ /**
32
+ * Parse a date string (YYYY-MM-DD) into a date object.
33
+ * @param {string} dateString - The date string.
34
+ * @return {Date} - The parsed date object.
35
+ */
36
+ function parseDate(dateString) {
37
+ const [year, month, day] = dateString.split('-').map(Number);
38
+ return new Date(year, month - 1, day);
39
+ }
40
+
41
+ /**
42
+ * Parse a time string (HH:MM:SS) into a date object.
43
+ * @param {string} timeString - The time string.
44
+ * @return {Date} - The parsed date object.
45
+ */
46
+ function parseTime(timeString) {
47
+ const [hours, minutes, seconds] = timeString.split(':').map(Number);
48
+ const date = new Date();
49
+ date.setHours(hours, minutes, seconds, 0);
50
+ return date;
51
+ }
52
+
53
+ // Arithmetic Functions
54
+
55
+ /**
56
+ * Add days to a date.
57
+ * @param {Date} date - The date object.
58
+ * @param {number} days - The number of days to add.
59
+ * @return {Date} - The new date object.
60
+ */
61
+ function addDays(date, days) {
62
+ const result = new Date(date);
63
+ result.setDate(result.getDate() + days);
64
+ return result;
65
+ }
66
+
67
+ /**
68
+ * Subtract days from a date.
69
+ * @param {Date} date - The date object.
70
+ * @param {number} days - The number of days to subtract.
71
+ * @return {Date} - The new date object.
72
+ */
73
+ function subtractDays(date, days) {
74
+ return addDays(date, -days);
75
+ }
76
+
77
+ /**
78
+ * Calculate the difference in days between two dates.
79
+ * @param {Date} date1 - The first date object.
80
+ * @param {Date} date2 - The second date object.
81
+ * @return {number} - The difference in days.
82
+ */
83
+ function differenceInDays(date1, date2) {
84
+ const diffTime = date2 - date1;
85
+ return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
86
+ }
87
+
88
+
89
+ // Exporting the functions as a CommonJS module
90
+ module.exports = () => ({
91
+ formatDate,
92
+ formatTime,
93
+ parseDate,
94
+ parseTime,
95
+ addDays,
96
+ subtractDays,
97
+ differenceInDays
98
+ });