funkophile 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/funkophileHelpers.d.ts +108 -0
- package/funkophileHelpers.js +45 -44
- package/funkophileHelpers.ts +41 -0
- package/index.d.ts +1 -0
- package/index.js +298 -327
- package/index.ts +343 -0
- package/package.json +27 -3
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export declare const contentsOfFiles: (selector: any) => ((state: unknown) => string) & {
|
|
2
|
+
clearCache: () => void;
|
|
3
|
+
resultsCount: () => number;
|
|
4
|
+
resetResultsCount: () => void;
|
|
5
|
+
} & {
|
|
6
|
+
resultFunc: (resultFuncArgs_0: any) => string;
|
|
7
|
+
memoizedResultFunc: ((resultFuncArgs_0: any) => string) & {
|
|
8
|
+
clearCache: () => void;
|
|
9
|
+
resultsCount: () => number;
|
|
10
|
+
resetResultsCount: () => void;
|
|
11
|
+
};
|
|
12
|
+
lastResult: () => string;
|
|
13
|
+
dependencies: [any];
|
|
14
|
+
recomputations: () => number;
|
|
15
|
+
resetRecomputations: () => void;
|
|
16
|
+
dependencyRecomputations: () => number;
|
|
17
|
+
resetDependencyRecomputations: () => void;
|
|
18
|
+
} & {
|
|
19
|
+
argsMemoize: typeof import("reselect").weakMapMemoize;
|
|
20
|
+
memoize: typeof import("reselect").weakMapMemoize;
|
|
21
|
+
};
|
|
22
|
+
export declare const contentOfFile: (selector: any) => ((state: unknown) => any) & {
|
|
23
|
+
clearCache: () => void;
|
|
24
|
+
resultsCount: () => number;
|
|
25
|
+
resetResultsCount: () => void;
|
|
26
|
+
} & {
|
|
27
|
+
resultFunc: (resultFuncArgs_0: any) => any;
|
|
28
|
+
memoizedResultFunc: ((resultFuncArgs_0: any) => any) & {
|
|
29
|
+
clearCache: () => void;
|
|
30
|
+
resultsCount: () => number;
|
|
31
|
+
resetResultsCount: () => void;
|
|
32
|
+
};
|
|
33
|
+
lastResult: () => any;
|
|
34
|
+
dependencies: [any];
|
|
35
|
+
recomputations: () => number;
|
|
36
|
+
resetRecomputations: () => void;
|
|
37
|
+
dependencyRecomputations: () => number;
|
|
38
|
+
resetDependencyRecomputations: () => void;
|
|
39
|
+
} & {
|
|
40
|
+
argsMemoize: typeof import("reselect").weakMapMemoize;
|
|
41
|
+
memoize: typeof import("reselect").weakMapMemoize;
|
|
42
|
+
};
|
|
43
|
+
export declare const srcAndContentOfFile: (selector: any, key: string) => ((state: unknown) => {
|
|
44
|
+
src: string;
|
|
45
|
+
content: any;
|
|
46
|
+
}) & {
|
|
47
|
+
clearCache: () => void;
|
|
48
|
+
resultsCount: () => number;
|
|
49
|
+
resetResultsCount: () => void;
|
|
50
|
+
} & {
|
|
51
|
+
resultFunc: (resultFuncArgs_0: any) => {
|
|
52
|
+
src: string;
|
|
53
|
+
content: any;
|
|
54
|
+
};
|
|
55
|
+
memoizedResultFunc: ((resultFuncArgs_0: any) => {
|
|
56
|
+
src: string;
|
|
57
|
+
content: any;
|
|
58
|
+
}) & {
|
|
59
|
+
clearCache: () => void;
|
|
60
|
+
resultsCount: () => number;
|
|
61
|
+
resetResultsCount: () => void;
|
|
62
|
+
};
|
|
63
|
+
lastResult: () => {
|
|
64
|
+
src: string;
|
|
65
|
+
content: any;
|
|
66
|
+
};
|
|
67
|
+
dependencies: [any];
|
|
68
|
+
recomputations: () => number;
|
|
69
|
+
resetRecomputations: () => void;
|
|
70
|
+
dependencyRecomputations: () => number;
|
|
71
|
+
resetDependencyRecomputations: () => void;
|
|
72
|
+
} & {
|
|
73
|
+
argsMemoize: typeof import("reselect").weakMapMemoize;
|
|
74
|
+
memoize: typeof import("reselect").weakMapMemoize;
|
|
75
|
+
};
|
|
76
|
+
export declare const srcAndContentOfFiles: (selector: any) => ((state: unknown) => {
|
|
77
|
+
src: string;
|
|
78
|
+
content: any;
|
|
79
|
+
}[]) & {
|
|
80
|
+
clearCache: () => void;
|
|
81
|
+
resultsCount: () => number;
|
|
82
|
+
resetResultsCount: () => void;
|
|
83
|
+
} & {
|
|
84
|
+
resultFunc: (resultFuncArgs_0: any) => {
|
|
85
|
+
src: string;
|
|
86
|
+
content: any;
|
|
87
|
+
}[];
|
|
88
|
+
memoizedResultFunc: ((resultFuncArgs_0: any) => {
|
|
89
|
+
src: string;
|
|
90
|
+
content: any;
|
|
91
|
+
}[]) & {
|
|
92
|
+
clearCache: () => void;
|
|
93
|
+
resultsCount: () => number;
|
|
94
|
+
resetResultsCount: () => void;
|
|
95
|
+
};
|
|
96
|
+
lastResult: () => {
|
|
97
|
+
src: string;
|
|
98
|
+
content: any;
|
|
99
|
+
}[];
|
|
100
|
+
dependencies: [any];
|
|
101
|
+
recomputations: () => number;
|
|
102
|
+
resetRecomputations: () => void;
|
|
103
|
+
dependencyRecomputations: () => number;
|
|
104
|
+
resetDependencyRecomputations: () => void;
|
|
105
|
+
} & {
|
|
106
|
+
argsMemoize: typeof import("reselect").weakMapMemoize;
|
|
107
|
+
memoize: typeof import("reselect").weakMapMemoize;
|
|
108
|
+
};
|
package/funkophileHelpers.js
CHANGED
|
@@ -1,44 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.srcAndContentOfFiles = exports.srcAndContentOfFile = exports.contentOfFile = exports.contentsOfFiles = void 0;
|
|
4
|
+
var reselect_1 = require("reselect");
|
|
5
|
+
var contentsOfFiles = function (selector) {
|
|
6
|
+
return (0, reselect_1.createSelector)([selector], function (selected) {
|
|
7
|
+
return Object.keys(selected).reduce(function (mm, k) { return mm + selected[k]; }, "");
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
exports.contentsOfFiles = contentsOfFiles;
|
|
11
|
+
var contentOfFile = function (selector) {
|
|
12
|
+
return (0, reselect_1.createSelector)([selector], function (selected) {
|
|
13
|
+
try {
|
|
14
|
+
return selected[Object.keys(selected)[0]];
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
console.error("error in contentOfFile", e);
|
|
18
|
+
console.error("selected", selected);
|
|
19
|
+
console.error("selector", selector);
|
|
20
|
+
process.exit(-1);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
exports.contentOfFile = contentOfFile;
|
|
25
|
+
var srcAndContentOfFile = function (selector, key) {
|
|
26
|
+
return (0, reselect_1.createSelector)([selector], function (selected) {
|
|
27
|
+
return {
|
|
28
|
+
src: key,
|
|
29
|
+
content: selected[key],
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
exports.srcAndContentOfFile = srcAndContentOfFile;
|
|
34
|
+
var srcAndContentOfFiles = function (selector) {
|
|
35
|
+
return (0, reselect_1.createSelector)([selector], function (selected) {
|
|
36
|
+
var keys = Object.keys(selected);
|
|
37
|
+
return keys.map(function (key) {
|
|
38
|
+
return {
|
|
39
|
+
src: key,
|
|
40
|
+
content: selected[key],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
exports.srcAndContentOfFiles = srcAndContentOfFiles;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createSelector } from "reselect";
|
|
2
|
+
|
|
3
|
+
export const contentsOfFiles = (selector) => {
|
|
4
|
+
return createSelector([selector], (selected) => {
|
|
5
|
+
return Object.keys(selected).reduce((mm, k) => mm + selected[k], "");
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const contentOfFile = (selector) => {
|
|
10
|
+
return createSelector([selector], (selected) => {
|
|
11
|
+
try {
|
|
12
|
+
return selected[Object.keys(selected)[0]];
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error("error in contentOfFile", e);
|
|
15
|
+
console.error("selected", selected);
|
|
16
|
+
console.error("selector", selector);
|
|
17
|
+
process.exit(-1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const srcAndContentOfFile = (selector, key: string) => {
|
|
23
|
+
return createSelector([selector], (selected) => {
|
|
24
|
+
return {
|
|
25
|
+
src: key,
|
|
26
|
+
content: selected[key],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const srcAndContentOfFiles = (selector) => {
|
|
32
|
+
return createSelector([selector], (selected) => {
|
|
33
|
+
const keys = Object.keys(selected);
|
|
34
|
+
return keys.map((key) => {
|
|
35
|
+
return {
|
|
36
|
+
src: key,
|
|
37
|
+
content: selected[key],
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/index.js
CHANGED
|
@@ -1,329 +1,300 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Promise.config({
|
|
13
|
-
cancellation: true
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const configFile = path.resolve(process.argv[2]);
|
|
17
|
-
const funkophileConfig = require(configFile)
|
|
18
|
-
const mode = process.argv[3]
|
|
19
|
-
const keyToWatch = process.argv[4]
|
|
20
|
-
|
|
21
|
-
const INITIALIZE = 'INITIALIZE';
|
|
22
|
-
const UPSERT = 'UPSERT';
|
|
23
|
-
const REMOVE = 'REMOVE';
|
|
24
|
-
|
|
25
|
-
const previousState = {}
|
|
26
|
-
let outputPromise = Promise.resolve();
|
|
27
|
-
|
|
28
|
-
const logger = {
|
|
29
|
-
watchError: (p) => console.log("\u001b[7m ! \u001b[0m" + p),
|
|
30
|
-
watchReady: (p) => console.log("\u001b[7m\u001b[36m < \u001b[0m" + p),
|
|
31
|
-
watchAdd: (p) => console.log("\u001b[7m\u001b[34m + \u001b[0m./" + p),
|
|
32
|
-
watchChange: (p) => console.log("\u001b[7m\u001b[35m * \u001b[0m" + p),
|
|
33
|
-
watchUnlink: (p) => console.log("\u001b[7m\u001b[31m - \u001b[0m./" + p),
|
|
34
|
-
|
|
35
|
-
stateChange: () => console.log("\u001b[7m\u001b[31m --- Redux state changed --- \u001b[0m"),
|
|
36
|
-
|
|
37
|
-
cleaningEmptyfolder: (p) => console.log("\u001b[31m\u001b[7m XXX! \u001b[0m" + p),
|
|
38
|
-
|
|
39
|
-
readingFile: (p) => console.log("\u001b[31m <-- \u001b[0m" + p),
|
|
40
|
-
removedFile: (p) => console.log("\u001b[31m\u001b[7m ??? \u001b[0m./" + p),
|
|
41
|
-
|
|
42
|
-
writingString: (p) => console.log("\u001b[32m --> \u001b[0m" + p),
|
|
43
|
-
writingFunction: (p) => console.log("\u001b[33m ... \u001b[0m" + p),
|
|
44
|
-
writingPromise: (p) => console.log("\u001b[33m ... \u001b[0m" + p),
|
|
45
|
-
writingError: (p, message) => console.log("\u001b[31m !!! \u001b[0m" + p + " " + message),
|
|
46
|
-
|
|
47
|
-
waiting: () => console.log("\u001b[7m Funkophile is done for now but waiting on changes...\u001b[0m "),
|
|
48
|
-
done: () => console.log("\u001b[7m Funkophile is done!\u001b[0m ")
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function cleanEmptyFoldersRecursively(folder) {
|
|
53
|
-
var isDir = fs.statSync(folder).isDirectory();
|
|
54
|
-
if (!isDir) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
var files = fs.readdirSync(folder);
|
|
58
|
-
if (files.length > 0) {
|
|
59
|
-
files.forEach(function(file) {
|
|
60
|
-
var fullPath = path.join(folder, file);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// re-evaluate files; after deleting subfolder
|
|
64
|
-
// we may have parent folder empty now
|
|
65
|
-
files = fs.readdirSync(folder);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (files.length == 0) {
|
|
69
|
-
logger.cleaningEmptyfolder(folder)
|
|
70
|
-
|
|
71
|
-
fs.rmdirSync(folder);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const dispatchUpsert = (store, key, file, encodings) => {
|
|
77
|
-
logger.readingFile(file)
|
|
78
|
-
store.dispatch({
|
|
79
|
-
type: UPSERT,
|
|
80
|
-
payload: {
|
|
81
|
-
key: key,
|
|
82
|
-
src: file,
|
|
83
|
-
contents: fse.readFileSync(file, Object.keys(encodings).find((e) => encodings[e].includes(file.split('.')[1])))
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// const filetype = file.split('.')[2]
|
|
88
|
-
// const encoding = Object.keys(encodings).find((e) => encodings[e].includes(filetype))
|
|
89
|
-
// const relativeFilePath = './' + file;
|
|
90
|
-
// console.log("\u001b[31m <-- \u001b[0m" + file)
|
|
91
|
-
// fse.readFile(file, encoding).then((contents) => {
|
|
92
|
-
// store.dispatch({
|
|
93
|
-
// type: UPSERT,
|
|
94
|
-
// payload: {
|
|
95
|
-
// key: key,
|
|
96
|
-
// src: file,
|
|
97
|
-
// contents: contents
|
|
98
|
-
// }
|
|
99
|
-
// });
|
|
100
|
-
// });
|
|
101
|
-
|
|
102
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
103
12
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
13
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
14
|
+
var t = {};
|
|
15
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
16
|
+
t[p] = s[p];
|
|
17
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
18
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
19
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
20
|
+
t[p[i]] = s[p[i]];
|
|
21
|
+
}
|
|
22
|
+
return t;
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
var chokidar_1 = require("chokidar");
|
|
26
|
+
var reselect_1 = require("reselect");
|
|
27
|
+
var redux_1 = require("redux");
|
|
28
|
+
var fs_1 = require("fs");
|
|
29
|
+
var fs_extra_1 = require("fs-extra");
|
|
30
|
+
var glob_promise_1 = require("glob-promise");
|
|
31
|
+
var path_1 = require("path");
|
|
32
|
+
var bluebird_1 = require("bluebird");
|
|
33
|
+
if (process.argv[2] && (process.argv[3] === "watch" || process.argv[3] === "build")) {
|
|
34
|
+
var configFile = path_1.default.resolve(process.argv[2]);
|
|
35
|
+
var mode_1 = process.argv[3];
|
|
36
|
+
// console.log("configfile", configFile);
|
|
37
|
+
Promise.resolve("".concat(configFile)).then(function (s) { return require(s); }).then(function (funkophileConfigModule) {
|
|
38
|
+
var funkophileConfig = funkophileConfigModule.default;
|
|
39
|
+
// console.log("funkophileConfig", (funkophileConfig));
|
|
40
|
+
bluebird_1.default.config({
|
|
41
|
+
cancellation: true
|
|
42
|
+
});
|
|
43
|
+
var INITIALIZE = 'INITIALIZE';
|
|
44
|
+
var UPSERT = 'UPSERT';
|
|
45
|
+
var REMOVE = 'REMOVE';
|
|
46
|
+
var previousState = {};
|
|
47
|
+
var outputPromise = bluebird_1.default.resolve();
|
|
48
|
+
var logger = {
|
|
49
|
+
watchError: function (p) { return console.log("\u001b[7m ! \u001b[0m" + p); },
|
|
50
|
+
watchReady: function (p) { return console.log("\u001b[7m\u001b[36m < \u001b[0m" + p); },
|
|
51
|
+
watchAdd: function (p) { return console.log("\u001b[7m\u001b[34m + \u001b[0m./" + p); },
|
|
52
|
+
watchChange: function (p) { return console.log("\u001b[7m\u001b[35m * \u001b[0m" + p); },
|
|
53
|
+
watchUnlink: function (p) { return console.log("\u001b[7m\u001b[31m - \u001b[0m./" + p); },
|
|
54
|
+
stateChange: function () { return console.log("\u001b[7m\u001b[31m --- Redux state changed --- \u001b[0m"); },
|
|
55
|
+
cleaningEmptyfolder: function (p) { return console.log("\u001b[31m\u001b[7m XXX! \u001b[0m" + p); },
|
|
56
|
+
readingFile: function (p) { return console.log("\u001b[31m <-- \u001b[0m" + p); },
|
|
57
|
+
removedFile: function (p) { return console.log("\u001b[31m\u001b[7m ??? \u001b[0m./" + p); },
|
|
58
|
+
writingString: function (p) { return console.log("\u001b[32m --> \u001b[0m" + p); },
|
|
59
|
+
writingFunction: function (p) { return console.log("\u001b[33m ... \u001b[0m" + p); },
|
|
60
|
+
writingPromise: function (p) { return console.log("\u001b[33m ... \u001b[0m" + p); },
|
|
61
|
+
writingError: function (p, message) { return console.log("\u001b[31m !!! \u001b[0m" + p + " " + message); },
|
|
62
|
+
waiting: function () { return console.log("\u001b[7m Funkophile is done for now but waiting on changes...\u001b[0m "); },
|
|
63
|
+
done: function () { return console.log("\u001b[7m Funkophile is done!\u001b[0m "); }
|
|
64
|
+
};
|
|
65
|
+
function cleanEmptyFoldersRecursively(folder) {
|
|
66
|
+
var isDir = fs_1.default.statSync(folder).isDirectory();
|
|
67
|
+
if (!isDir) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
var files = fs_1.default.readdirSync(folder);
|
|
71
|
+
if (files.length > 0) {
|
|
72
|
+
files.forEach(function (file) {
|
|
73
|
+
var fullPath = path_1.default.join(folder, file);
|
|
74
|
+
});
|
|
75
|
+
// re-evaluate files; after deleting subfolder
|
|
76
|
+
// we may have parent folder empty now
|
|
77
|
+
files = fs_1.default.readdirSync(folder);
|
|
78
|
+
}
|
|
79
|
+
if (files.length == 0) {
|
|
80
|
+
logger.cleaningEmptyfolder(folder);
|
|
81
|
+
fs_1.default.rmdirSync(folder);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
var dispatchUpsert = function (store, key, file, encodings) {
|
|
86
|
+
var fileType = file.split('.').slice(-2, -1)[0];
|
|
87
|
+
var encoding = Object.keys(encodings).find(function (e) { return encodings[e].includes(fileType); });
|
|
88
|
+
if (!fileType || !encoding) {
|
|
89
|
+
console.log("Unknown file type for ", file, "Defaulting to utf8");
|
|
90
|
+
encoding = 'utf8';
|
|
91
|
+
}
|
|
92
|
+
// console.log("dispatchUpsert", encoding, file)
|
|
93
|
+
logger.readingFile(file);
|
|
94
|
+
store.dispatch({
|
|
95
|
+
type: UPSERT,
|
|
96
|
+
payload: {
|
|
97
|
+
key: key,
|
|
98
|
+
src: file,
|
|
99
|
+
contents: fs_extra_1.default.readFileSync(file, encoding)
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
function omit(key, obj) {
|
|
104
|
+
var _a = obj, _b = key, omitted = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
|
|
105
|
+
return rest;
|
|
106
|
+
}
|
|
107
|
+
var store = (0, redux_1.createStore)(function (state, action) {
|
|
108
|
+
var _a, _b, _c;
|
|
109
|
+
if (state === void 0) { state = __assign(__assign({ initialLoad: true }, funkophileConfig.initialState), { timestamp: Date.now() }); }
|
|
110
|
+
// console.log("\u001b[7m\u001b[35m ||| Redux recieved action \u001b[0m", action.type)
|
|
111
|
+
if (!action.type.includes('@@redux')) {
|
|
112
|
+
if (action.type === INITIALIZE) {
|
|
113
|
+
return __assign(__assign({}, state), { initialLoad: false, timestamp: Date.now() });
|
|
114
|
+
}
|
|
115
|
+
else if (action.type === UPSERT) {
|
|
116
|
+
return __assign(__assign({}, state), (_a = {}, _a[action['payload'].key] = __assign(__assign({}, state[action.payload.key]), (_b = {},
|
|
117
|
+
_b[action['payload'].src] = action['payload'].contents,
|
|
118
|
+
_b)), _a.timestamp = Date.now(), _a));
|
|
119
|
+
}
|
|
120
|
+
else if (action.type === REMOVE) {
|
|
121
|
+
return __assign(__assign({}, state), (_c = {}, _c[action['payload'].key] = omit(action['payload'].file, state[action['payload'].key]), _c.timestamp = Date.now(), _c));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.error("Redux was asked to handle an unknown action type: " + action.type);
|
|
125
|
+
process.exit(-1);
|
|
126
|
+
}
|
|
127
|
+
// return state
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
var finalSelector = funkophileConfig.outputs(Object.keys(funkophileConfig.inputs).reduce(function (mm, inputKey) {
|
|
131
|
+
var _a;
|
|
132
|
+
return __assign(__assign({}, mm), (_a = {}, _a[inputKey] = (0, reselect_1.createSelector)([function (x) { return x; }], function (root) { return root[inputKey]; }), _a));
|
|
133
|
+
}, {}));
|
|
134
|
+
// Wait for all the file watchers to check in
|
|
135
|
+
bluebird_1.default.all(Object.keys(funkophileConfig.inputs)
|
|
136
|
+
.map(function (inputRuleKey) {
|
|
137
|
+
var p = path_1.default.resolve("./".concat(funkophileConfig.options.inFolder, "/").concat(funkophileConfig.inputs[inputRuleKey] || ''));
|
|
138
|
+
return new bluebird_1.default(function (fulfill, reject) {
|
|
139
|
+
if (mode_1 === "build") {
|
|
140
|
+
(0, glob_promise_1.default)(p, {}).then(function (files) {
|
|
141
|
+
files.forEach(function (file) {
|
|
142
|
+
dispatchUpsert(store, inputRuleKey, file, funkophileConfig.encodings);
|
|
143
|
+
});
|
|
144
|
+
}).then(function () {
|
|
145
|
+
fulfill();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else if (mode_1 === "watch") {
|
|
149
|
+
chokidar_1.default.watch(p, {})
|
|
150
|
+
.on('error', function (error) {
|
|
151
|
+
logger.watchError(p);
|
|
152
|
+
})
|
|
153
|
+
.on('ready', function () {
|
|
154
|
+
logger.watchReady(p);
|
|
155
|
+
fulfill();
|
|
156
|
+
})
|
|
157
|
+
.on('add', function (p) {
|
|
158
|
+
logger.watchAdd(p);
|
|
159
|
+
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
160
|
+
})
|
|
161
|
+
.on('change', function (p) {
|
|
162
|
+
logger.watchChange(p);
|
|
163
|
+
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
164
|
+
})
|
|
165
|
+
.on('unlink', function (p) {
|
|
166
|
+
logger.watchUnlink(p);
|
|
167
|
+
store.dispatch({
|
|
168
|
+
type: REMOVE,
|
|
169
|
+
payload: {
|
|
170
|
+
key: inputRuleKey,
|
|
171
|
+
file: './' + p
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
})
|
|
175
|
+
.on('unlinkDir', function (p) {
|
|
176
|
+
logger.watchUnlink(p);
|
|
177
|
+
});
|
|
178
|
+
// .on('raw', (event, p, details) => { // internal
|
|
179
|
+
// log('Raw event info:', event, p, details);
|
|
180
|
+
// })
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
console.error("The 3rd argument should be 'watch' or 'build', not \"".concat(mode_1, "\""));
|
|
184
|
+
process.exit(-1);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
})).then(function () {
|
|
188
|
+
// listen for changes to the store
|
|
189
|
+
store.subscribe(function () {
|
|
190
|
+
var s = store.getState();
|
|
191
|
+
logger.stateChange();
|
|
192
|
+
var outputs = finalSelector(s);
|
|
193
|
+
if (outputPromise.isPending()) {
|
|
194
|
+
console.log('cancelling previous write!');
|
|
195
|
+
outputPromise.cancel();
|
|
196
|
+
}
|
|
197
|
+
outputPromise = bluebird_1.default.all(Array.from(new Set(Object.keys(previousState).concat(Object.keys(outputs))))
|
|
198
|
+
.map(function (key) {
|
|
199
|
+
return new bluebird_1.default(function (fulfill, reject) {
|
|
200
|
+
if (!outputs[key]) {
|
|
201
|
+
var file = funkophileConfig.options.outFolder + "/" + key;
|
|
202
|
+
logger.removedFile(file);
|
|
203
|
+
try {
|
|
204
|
+
fs_extra_1.default.unlinkSync('./' + file);
|
|
205
|
+
cleanEmptyFoldersRecursively('./' + file.substring(0, file.lastIndexOf("/")));
|
|
206
|
+
}
|
|
207
|
+
catch (ex) {
|
|
208
|
+
// console.error('inner', ex.message);
|
|
209
|
+
// throw ex;
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
// console.log('finally');
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// delete previousState[key]
|
|
216
|
+
// fulfill()
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
if (outputs[key] !== previousState[key]) {
|
|
220
|
+
previousState[key] = outputs[key];
|
|
221
|
+
var relativeFilePath_1 = './' + funkophileConfig.options.outFolder + "/" + key;
|
|
222
|
+
var contents = outputs[key];
|
|
223
|
+
if (typeof contents === "function") {
|
|
224
|
+
logger.writingFunction(relativeFilePath_1);
|
|
225
|
+
contents(function (err, res) {
|
|
226
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, res, fulfill);
|
|
227
|
+
logger.writingString(relativeFilePath_1);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else if (typeof contents === 'string') {
|
|
231
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, contents, fulfill);
|
|
232
|
+
logger.writingString(relativeFilePath_1);
|
|
233
|
+
}
|
|
234
|
+
else if (Buffer.isBuffer(contents)) {
|
|
235
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, contents, fulfill);
|
|
236
|
+
logger.writingString(relativeFilePath_1);
|
|
237
|
+
}
|
|
238
|
+
else if (Array.isArray(contents)) {
|
|
239
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, JSON.stringify(contents), fulfill);
|
|
240
|
+
logger.writingString(relativeFilePath_1);
|
|
241
|
+
}
|
|
242
|
+
else if (typeof contents.then === 'function') {
|
|
243
|
+
logger.writingPromise(relativeFilePath_1);
|
|
244
|
+
bluebird_1.default.resolve(contents).then(function (value) {
|
|
245
|
+
if (value instanceof Error) {
|
|
246
|
+
logger.writingError(relativeFilePath_1, value.message);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, value, fulfill);
|
|
250
|
+
logger.writingString(relativeFilePath_1);
|
|
251
|
+
}
|
|
252
|
+
}, function (value) {
|
|
253
|
+
// not called
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
else if (typeof contents === 'object') {
|
|
257
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, JSON.stringify(contents), fulfill);
|
|
258
|
+
logger.writingString(relativeFilePath_1);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
console.log("I don't recognize what this is but I will try to write it to a file: " + relativeFilePath_1, typeof contents, contents);
|
|
262
|
+
fs_extra_1.default.outputFile(relativeFilePath_1, contents, fulfill);
|
|
263
|
+
logger.writingString(relativeFilePath_1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
fulfill();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
})).then(function () {
|
|
272
|
+
cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
|
|
273
|
+
if (mode_1 === "build") {
|
|
274
|
+
logger.done();
|
|
275
|
+
}
|
|
276
|
+
else if (mode_1 === "watch") {
|
|
277
|
+
logger.waiting();
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
console.error("The 3rd argument should be 'watch' or 'build', not \"".concat(mode_1, "\""));
|
|
281
|
+
process.exit(-1);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
// lastly, turn the store `on`.
|
|
286
|
+
// This is to prevent unecessary recomputations when initialy adding files to redux
|
|
287
|
+
store.dispatch({
|
|
288
|
+
type: INITIALIZE,
|
|
289
|
+
payload: true
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
console.error("command line arguments do not make sense");
|
|
296
|
+
console.error("first argument should be a funkophile config file");
|
|
297
|
+
console.error("second argument should be a 'build' or 'watch'");
|
|
298
|
+
console.error("You passed", process.argv);
|
|
299
|
+
process.exit(-1);
|
|
110
300
|
}
|
|
111
|
-
|
|
112
|
-
const store = createStore((state = {
|
|
113
|
-
initialLoad: true,
|
|
114
|
-
...funkophileConfig.initialState,
|
|
115
|
-
timestamp: Date.now()
|
|
116
|
-
}, action) => {
|
|
117
|
-
// console.log("\u001b[7m\u001b[35m ||| Redux recieved action \u001b[0m", action.type)
|
|
118
|
-
if (!action.type.includes('@@redux')) {
|
|
119
|
-
|
|
120
|
-
if (action.type === INITIALIZE) {
|
|
121
|
-
return {
|
|
122
|
-
...state,
|
|
123
|
-
initialLoad: false,
|
|
124
|
-
timestamp: Date.now()
|
|
125
|
-
}
|
|
126
|
-
} else if (action.type === UPSERT) {
|
|
127
|
-
return {
|
|
128
|
-
...state,
|
|
129
|
-
[action.payload.key]: {
|
|
130
|
-
...state[action.payload.key],
|
|
131
|
-
...{
|
|
132
|
-
[action.payload.src]: action.payload.contents
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
timestamp: Date.now()
|
|
136
|
-
}
|
|
137
|
-
} else if (action.type === REMOVE) {
|
|
138
|
-
return {
|
|
139
|
-
...state,
|
|
140
|
-
[action.payload.key]: omit(action.payload.file, state[action.payload.key]),
|
|
141
|
-
timestamp: Date.now()
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
console.error("Redux was asked to handle an unknown action type: " + action.type)
|
|
145
|
-
process.exit(-1)
|
|
146
|
-
}
|
|
147
|
-
return state
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
const finalSelector = funkophileConfig.outputs(Object.keys(funkophileConfig.inputs).reduce((mm, inputKey) => {
|
|
152
|
-
return {
|
|
153
|
-
...mm,
|
|
154
|
-
[inputKey]: createSelector([(x) => x], (root) => root[inputKey])
|
|
155
|
-
}
|
|
156
|
-
}, {}))
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// Wait for all the file watchers to check in
|
|
160
|
-
Promise.all(
|
|
161
|
-
Object.keys(funkophileConfig.inputs)
|
|
162
|
-
// ['FUNKYBUNDLE']
|
|
163
|
-
.map((inputRuleKey) => {
|
|
164
|
-
const p = path.resolve(`./${funkophileConfig.options.inFolder}/${funkophileConfig.inputs[inputRuleKey] || ''}`)
|
|
165
|
-
|
|
166
|
-
// console.log("mark3", p)
|
|
167
|
-
|
|
168
|
-
return new Promise((fulfill, reject) => {
|
|
169
|
-
if (mode === "build") {
|
|
170
|
-
glob(p, {}).then((files) => {
|
|
171
|
-
files.forEach((file) => {
|
|
172
|
-
dispatchUpsert(store, inputRuleKey, file, funkophileConfig.encodings);
|
|
173
|
-
})
|
|
174
|
-
}).then(() => {
|
|
175
|
-
fulfill()
|
|
176
|
-
})
|
|
177
|
-
} else if (mode === "watch") {
|
|
178
|
-
|
|
179
|
-
chokidar.watch(p, {})
|
|
180
|
-
.on('error', error => {
|
|
181
|
-
logger.watchError(p)
|
|
182
|
-
})
|
|
183
|
-
.on('ready', () => {
|
|
184
|
-
logger.watchReady(p)
|
|
185
|
-
fulfill()
|
|
186
|
-
})
|
|
187
|
-
.on('add', p => {
|
|
188
|
-
logger.watchAdd(p)
|
|
189
|
-
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
190
|
-
})
|
|
191
|
-
.on('change', p => {
|
|
192
|
-
logger.watchChange(p)
|
|
193
|
-
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
194
|
-
})
|
|
195
|
-
.on('unlink', p => {
|
|
196
|
-
logger.watchUnlink(p)
|
|
197
|
-
store.dispatch({
|
|
198
|
-
type: REMOVE,
|
|
199
|
-
payload: {
|
|
200
|
-
key: inputRuleKey,
|
|
201
|
-
file: './' + p
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
})
|
|
205
|
-
.on('unlinkDir', p => {
|
|
206
|
-
logger.watchUnlink(p)
|
|
207
|
-
})
|
|
208
|
-
// .on('raw', (event, p, details) => { // internal
|
|
209
|
-
// log('Raw event info:', event, p, details);
|
|
210
|
-
// })
|
|
211
|
-
|
|
212
|
-
} else {
|
|
213
|
-
console.error(`The 3rd argument should be 'watch' or 'build', not "${mode}"`)
|
|
214
|
-
process.exit(-1)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
});
|
|
218
|
-
})).then(function() {
|
|
219
|
-
|
|
220
|
-
// listen for changes to the store
|
|
221
|
-
store.subscribe(() => {
|
|
222
|
-
const s = store.getState()
|
|
223
|
-
|
|
224
|
-
logger.stateChange()
|
|
225
|
-
const outputs = finalSelector(s)
|
|
226
|
-
|
|
227
|
-
if (outputPromise.isPending()) {
|
|
228
|
-
console.log('cancelling previous write!')
|
|
229
|
-
outputPromise.cancel()
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
outputPromise = Promise.all(
|
|
233
|
-
Array.from(new Set(Object.keys(previousState).concat(Object.keys(outputs))))
|
|
234
|
-
.map((key) => {
|
|
235
|
-
|
|
236
|
-
return new Promise((fulfill, reject) => {
|
|
237
|
-
if (!outputs[key]) {
|
|
238
|
-
|
|
239
|
-
const file = funkophileConfig.options.outFolder + "/" + key
|
|
240
|
-
logger.removedFile(file)
|
|
241
|
-
|
|
242
|
-
try {
|
|
243
|
-
fse.unlinkSync('./' + file)
|
|
244
|
-
cleanEmptyFoldersRecursively('./' + file.substring(0, file.lastIndexOf("/")))
|
|
245
|
-
} catch (ex) {
|
|
246
|
-
// console.error('inner', ex.message);
|
|
247
|
-
// throw ex;
|
|
248
|
-
} finally {
|
|
249
|
-
// console.log('finally');
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
delete previousState[key]
|
|
253
|
-
fulfill()
|
|
254
|
-
} else {
|
|
255
|
-
if (outputs[key] !== previousState[key]) {
|
|
256
|
-
previousState[key] = outputs[key]
|
|
257
|
-
|
|
258
|
-
const relativeFilePath = './' + funkophileConfig.options.outFolder + "/" + key;
|
|
259
|
-
const contents = outputs[key];
|
|
260
|
-
|
|
261
|
-
if (typeof contents === "function") {
|
|
262
|
-
logger.writingFunction(relativeFilePath)
|
|
263
|
-
contents((err, res) => {
|
|
264
|
-
fse.outputFile(relativeFilePath, res, fulfill);
|
|
265
|
-
logger.writingString(relativeFilePath);
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
} else if (typeof contents === 'string') {
|
|
269
|
-
fse.outputFile(relativeFilePath, contents, fulfill);
|
|
270
|
-
logger.writingString(relativeFilePath);
|
|
271
|
-
|
|
272
|
-
} else if (Buffer.isBuffer(contents)) {
|
|
273
|
-
fse.outputFile(relativeFilePath, contents, fulfill);
|
|
274
|
-
logger.writingString(relativeFilePath);
|
|
275
|
-
|
|
276
|
-
} else if (Array.isArray(contents)) {
|
|
277
|
-
fse.outputFile(relativeFilePath, JSON.stringify(contents), fulfill);
|
|
278
|
-
logger.writingString(relativeFilePath);
|
|
279
|
-
|
|
280
|
-
} else if (typeof contents.then === 'function') {
|
|
281
|
-
logger.writingPromise(relativeFilePath)
|
|
282
|
-
Promise.resolve(contents).then(function(value) {
|
|
283
|
-
|
|
284
|
-
if (value instanceof Error) {
|
|
285
|
-
logger.writingError(relativeFilePath, value.message)
|
|
286
|
-
} else {
|
|
287
|
-
fse.outputFile(relativeFilePath, value, fulfill);
|
|
288
|
-
logger.writingString(relativeFilePath);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
}, function(value) {
|
|
292
|
-
// not called
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
} else {
|
|
296
|
-
console.log(`I don't recognize what this is but I will try to write it to a file: ` + relativeFilePath, contents)
|
|
297
|
-
fse.outputFile(relativeFilePath, JSON.stringify(contents, null, 2), fulfill);
|
|
298
|
-
logger.writingString(relativeFilePath);
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
fulfill()
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
})
|
|
307
|
-
).then(() => {
|
|
308
|
-
cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
|
|
309
|
-
|
|
310
|
-
if (mode === "build") {
|
|
311
|
-
logger.done()
|
|
312
|
-
} else if (mode === "watch") {
|
|
313
|
-
logger.waiting()
|
|
314
|
-
} else {
|
|
315
|
-
console.error(`The 3rd argument should be 'watch' or 'build', not "${mode}"`)
|
|
316
|
-
process.exit(-1)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
})
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
// lastly, turn the store `on`.
|
|
323
|
-
// This is to prevent unecessary recomputations when initialy adding files to redux
|
|
324
|
-
store.dispatch({
|
|
325
|
-
type: INITIALIZE,
|
|
326
|
-
payload: true
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
})
|
package/index.ts
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import { createSelector } from 'reselect';
|
|
3
|
+
import { Action, createStore, Store } from 'redux';
|
|
4
|
+
import fs from "fs"
|
|
5
|
+
import fse from "fs-extra"
|
|
6
|
+
import glob from "glob-promise";
|
|
7
|
+
import path from "path"
|
|
8
|
+
import Promise from "bluebird"
|
|
9
|
+
|
|
10
|
+
if (process.argv[2] && (process.argv[3] === "watch" || process.argv[3] === "build")) {
|
|
11
|
+
const configFile = path.resolve(process.argv[2]);
|
|
12
|
+
const mode = process.argv[3]
|
|
13
|
+
|
|
14
|
+
// console.log("configfile", configFile);
|
|
15
|
+
import(configFile).then((funkophileConfigModule) => {
|
|
16
|
+
const funkophileConfig = funkophileConfigModule.default;
|
|
17
|
+
// console.log("funkophileConfig", (funkophileConfig));
|
|
18
|
+
Promise.config({
|
|
19
|
+
cancellation: true
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const INITIALIZE = 'INITIALIZE';
|
|
23
|
+
const UPSERT = 'UPSERT';
|
|
24
|
+
const REMOVE = 'REMOVE';
|
|
25
|
+
|
|
26
|
+
const previousState: any = {}
|
|
27
|
+
let outputPromise = Promise.resolve();
|
|
28
|
+
|
|
29
|
+
const logger = {
|
|
30
|
+
watchError: (p: string) => console.log("\u001b[7m ! \u001b[0m" + p),
|
|
31
|
+
watchReady: (p: string) => console.log("\u001b[7m\u001b[36m < \u001b[0m" + p),
|
|
32
|
+
watchAdd: (p: string) => console.log("\u001b[7m\u001b[34m + \u001b[0m./" + p),
|
|
33
|
+
watchChange: (p: string) => console.log("\u001b[7m\u001b[35m * \u001b[0m" + p),
|
|
34
|
+
watchUnlink: (p: string) => console.log("\u001b[7m\u001b[31m - \u001b[0m./" + p),
|
|
35
|
+
stateChange: () => console.log("\u001b[7m\u001b[31m --- Redux state changed --- \u001b[0m"),
|
|
36
|
+
cleaningEmptyfolder: (p: string) => console.log("\u001b[31m\u001b[7m XXX! \u001b[0m" + p),
|
|
37
|
+
readingFile: (p: string) => console.log("\u001b[31m <-- \u001b[0m" + p),
|
|
38
|
+
removedFile: (p: string) => console.log("\u001b[31m\u001b[7m ??? \u001b[0m./" + p),
|
|
39
|
+
writingString: (p: string) => console.log("\u001b[32m --> \u001b[0m" + p),
|
|
40
|
+
writingFunction: (p: string) => console.log("\u001b[33m ... \u001b[0m" + p),
|
|
41
|
+
writingPromise: (p: string) => console.log("\u001b[33m ... \u001b[0m" + p),
|
|
42
|
+
writingError: (p: string, message: string) => console.log("\u001b[31m !!! \u001b[0m" + p + " " + message),
|
|
43
|
+
|
|
44
|
+
waiting: () => console.log("\u001b[7m Funkophile is done for now but waiting on changes...\u001b[0m "),
|
|
45
|
+
done: () => console.log("\u001b[7m Funkophile is done!\u001b[0m ")
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function cleanEmptyFoldersRecursively(folder: string) {
|
|
50
|
+
var isDir = fs.statSync(folder).isDirectory();
|
|
51
|
+
if (!isDir) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
var files = fs.readdirSync(folder);
|
|
55
|
+
if (files.length > 0) {
|
|
56
|
+
files.forEach(function (file) {
|
|
57
|
+
var fullPath = path.join(folder, file);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// re-evaluate files; after deleting subfolder
|
|
61
|
+
// we may have parent folder empty now
|
|
62
|
+
files = fs.readdirSync(folder);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (files.length == 0) {
|
|
66
|
+
logger.cleaningEmptyfolder(folder)
|
|
67
|
+
|
|
68
|
+
fs.rmdirSync(folder);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const dispatchUpsert = (
|
|
74
|
+
store: Store,
|
|
75
|
+
key: string,
|
|
76
|
+
file: string,
|
|
77
|
+
encodings: Record<string, string[]>
|
|
78
|
+
) => {
|
|
79
|
+
const fileType: string = file.split('.').slice(-2, -1)[0] as string;
|
|
80
|
+
let encoding: BufferEncoding = Object.keys(encodings).find((e) => (encodings[e] as string[]).includes(fileType)) as BufferEncoding;
|
|
81
|
+
|
|
82
|
+
if (!fileType || !encoding) {
|
|
83
|
+
console.log(`Unknown file type for `, file, `Defaulting to utf8`);
|
|
84
|
+
encoding = 'utf8';
|
|
85
|
+
}
|
|
86
|
+
// console.log("dispatchUpsert", encoding, file)
|
|
87
|
+
logger.readingFile(file)
|
|
88
|
+
store.dispatch({
|
|
89
|
+
type: UPSERT,
|
|
90
|
+
payload: {
|
|
91
|
+
key: key,
|
|
92
|
+
src: file,
|
|
93
|
+
contents: fse.readFileSync(
|
|
94
|
+
file,
|
|
95
|
+
encoding
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function omit(key: string, obj: any) {
|
|
102
|
+
const {
|
|
103
|
+
[key]: omitted, ...rest
|
|
104
|
+
} = obj;
|
|
105
|
+
return rest;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const store: Store<
|
|
109
|
+
any, Action<string>, any
|
|
110
|
+
>
|
|
111
|
+
= createStore((state = {
|
|
112
|
+
initialLoad: true,
|
|
113
|
+
...funkophileConfig.initialState,
|
|
114
|
+
timestamp: Date.now()
|
|
115
|
+
}, action) => {
|
|
116
|
+
// console.log("\u001b[7m\u001b[35m ||| Redux recieved action \u001b[0m", action.type)
|
|
117
|
+
if (!action.type.includes('@@redux')) {
|
|
118
|
+
|
|
119
|
+
if (action.type === INITIALIZE) {
|
|
120
|
+
return {
|
|
121
|
+
...state,
|
|
122
|
+
initialLoad: false,
|
|
123
|
+
timestamp: Date.now()
|
|
124
|
+
}
|
|
125
|
+
} else if (action.type === UPSERT) {
|
|
126
|
+
return {
|
|
127
|
+
...state,
|
|
128
|
+
[action['payload'].key]: {
|
|
129
|
+
...state[action.payload.key],
|
|
130
|
+
...{
|
|
131
|
+
[action['payload'].src]: action['payload'].contents
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
timestamp: Date.now()
|
|
135
|
+
}
|
|
136
|
+
} else if (action.type === REMOVE) {
|
|
137
|
+
return {
|
|
138
|
+
...state,
|
|
139
|
+
[action['payload'].key]: omit(action['payload'].file, state[action['payload'].key]),
|
|
140
|
+
timestamp: Date.now()
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
console.error("Redux was asked to handle an unknown action type: " + action.type)
|
|
144
|
+
process.exit(-1)
|
|
145
|
+
}
|
|
146
|
+
// return state
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const finalSelector = funkophileConfig.outputs(Object.keys(funkophileConfig.inputs).reduce((mm, inputKey) => {
|
|
151
|
+
return {
|
|
152
|
+
...mm,
|
|
153
|
+
[inputKey]: createSelector([(x) => x], (root) => root[inputKey])
|
|
154
|
+
}
|
|
155
|
+
}, {}))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
// Wait for all the file watchers to check in
|
|
159
|
+
Promise.all(
|
|
160
|
+
Object.keys(funkophileConfig.inputs)
|
|
161
|
+
|
|
162
|
+
.map((inputRuleKey) => {
|
|
163
|
+
const p = path.resolve(`./${funkophileConfig.options.inFolder}/${funkophileConfig.inputs[inputRuleKey] || ''}`)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
return new Promise((fulfill, reject) => {
|
|
167
|
+
if (mode === "build") {
|
|
168
|
+
glob(p, {}).then((files: string[]) => {
|
|
169
|
+
files.forEach((file) => {
|
|
170
|
+
dispatchUpsert(store, inputRuleKey, file, funkophileConfig.encodings);
|
|
171
|
+
})
|
|
172
|
+
}).then(() => {
|
|
173
|
+
fulfill()
|
|
174
|
+
})
|
|
175
|
+
} else if (mode === "watch") {
|
|
176
|
+
|
|
177
|
+
chokidar.watch(p, {})
|
|
178
|
+
.on('error', error => {
|
|
179
|
+
logger.watchError(p)
|
|
180
|
+
})
|
|
181
|
+
.on('ready', () => {
|
|
182
|
+
logger.watchReady(p)
|
|
183
|
+
fulfill()
|
|
184
|
+
})
|
|
185
|
+
.on('add', p => {
|
|
186
|
+
logger.watchAdd(p)
|
|
187
|
+
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
188
|
+
})
|
|
189
|
+
.on('change', p => {
|
|
190
|
+
logger.watchChange(p)
|
|
191
|
+
dispatchUpsert(store, inputRuleKey, './' + p, funkophileConfig.encodings);
|
|
192
|
+
})
|
|
193
|
+
.on('unlink', p => {
|
|
194
|
+
logger.watchUnlink(p)
|
|
195
|
+
store.dispatch({
|
|
196
|
+
type: REMOVE,
|
|
197
|
+
payload: {
|
|
198
|
+
key: inputRuleKey,
|
|
199
|
+
file: './' + p
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
.on('unlinkDir', p => {
|
|
204
|
+
logger.watchUnlink(p)
|
|
205
|
+
})
|
|
206
|
+
// .on('raw', (event, p, details) => { // internal
|
|
207
|
+
// log('Raw event info:', event, p, details);
|
|
208
|
+
// })
|
|
209
|
+
|
|
210
|
+
} else {
|
|
211
|
+
console.error(`The 3rd argument should be 'watch' or 'build', not "${mode}"`)
|
|
212
|
+
process.exit(-1)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
});
|
|
216
|
+
})).then(function () {
|
|
217
|
+
|
|
218
|
+
// listen for changes to the store
|
|
219
|
+
store.subscribe(() => {
|
|
220
|
+
const s = store.getState()
|
|
221
|
+
|
|
222
|
+
logger.stateChange()
|
|
223
|
+
const outputs = finalSelector(s)
|
|
224
|
+
|
|
225
|
+
if (outputPromise.isPending()) {
|
|
226
|
+
console.log('cancelling previous write!')
|
|
227
|
+
outputPromise.cancel()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
outputPromise = Promise.all(
|
|
231
|
+
Array.from(new Set(Object.keys(previousState).concat(Object.keys(outputs))))
|
|
232
|
+
.map((key) => {
|
|
233
|
+
|
|
234
|
+
return new Promise((fulfill, reject) => {
|
|
235
|
+
if (!outputs[key]) {
|
|
236
|
+
|
|
237
|
+
const file = funkophileConfig.options.outFolder + "/" + key
|
|
238
|
+
logger.removedFile(file)
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
fse.unlinkSync('./' + file)
|
|
242
|
+
cleanEmptyFoldersRecursively('./' + file.substring(0, file.lastIndexOf("/")))
|
|
243
|
+
} catch (ex) {
|
|
244
|
+
// console.error('inner', ex.message);
|
|
245
|
+
// throw ex;
|
|
246
|
+
} finally {
|
|
247
|
+
// console.log('finally');
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
// delete previousState[key]
|
|
251
|
+
// fulfill()
|
|
252
|
+
} else {
|
|
253
|
+
if (outputs[key] !== previousState[key]) {
|
|
254
|
+
previousState[key] = outputs[key]
|
|
255
|
+
|
|
256
|
+
const relativeFilePath = './' + funkophileConfig.options.outFolder + "/" + key;
|
|
257
|
+
const contents = outputs[key];
|
|
258
|
+
|
|
259
|
+
if (typeof contents === "function") {
|
|
260
|
+
logger.writingFunction(relativeFilePath)
|
|
261
|
+
contents((err, res) => {
|
|
262
|
+
fse.outputFile(relativeFilePath, res, fulfill);
|
|
263
|
+
logger.writingString(relativeFilePath);
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
} else if (typeof contents === 'string') {
|
|
267
|
+
fse.outputFile(relativeFilePath, contents, fulfill);
|
|
268
|
+
logger.writingString(relativeFilePath);
|
|
269
|
+
|
|
270
|
+
} else if (Buffer.isBuffer(contents)) {
|
|
271
|
+
fse.outputFile(relativeFilePath, contents, fulfill);
|
|
272
|
+
logger.writingString(relativeFilePath);
|
|
273
|
+
|
|
274
|
+
} else if (Array.isArray(contents)) {
|
|
275
|
+
fse.outputFile(relativeFilePath, JSON.stringify(contents), fulfill);
|
|
276
|
+
logger.writingString(relativeFilePath);
|
|
277
|
+
|
|
278
|
+
} else if (typeof contents.then === 'function') {
|
|
279
|
+
logger.writingPromise(relativeFilePath)
|
|
280
|
+
Promise.resolve(contents).then(function (value) {
|
|
281
|
+
|
|
282
|
+
if (value instanceof Error) {
|
|
283
|
+
logger.writingError(relativeFilePath, value.message)
|
|
284
|
+
} else {
|
|
285
|
+
fse.outputFile(relativeFilePath, value, fulfill);
|
|
286
|
+
logger.writingString(relativeFilePath);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
}, function (value) {
|
|
290
|
+
// not called
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
} else if (typeof contents === 'object') {
|
|
294
|
+
fse.outputFile(relativeFilePath, JSON.stringify(contents), fulfill);
|
|
295
|
+
logger.writingString(relativeFilePath);
|
|
296
|
+
|
|
297
|
+
} else {
|
|
298
|
+
console.log(`I don't recognize what this is but I will try to write it to a file: ` + relativeFilePath, typeof contents, contents)
|
|
299
|
+
fse.outputFile(relativeFilePath, contents, fulfill);
|
|
300
|
+
logger.writingString(relativeFilePath);
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
fulfill()
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
})
|
|
309
|
+
).then(() => {
|
|
310
|
+
cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
|
|
311
|
+
|
|
312
|
+
if (mode === "build") {
|
|
313
|
+
logger.done()
|
|
314
|
+
} else if (mode === "watch") {
|
|
315
|
+
logger.waiting()
|
|
316
|
+
} else {
|
|
317
|
+
console.error(`The 3rd argument should be 'watch' or 'build', not "${mode}"`)
|
|
318
|
+
process.exit(-1)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
// lastly, turn the store `on`.
|
|
325
|
+
// This is to prevent unecessary recomputations when initialy adding files to redux
|
|
326
|
+
store.dispatch({
|
|
327
|
+
type: INITIALIZE,
|
|
328
|
+
payload: true
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
} else {
|
|
336
|
+
console.error("command line arguments do not make sense");
|
|
337
|
+
console.error("first argument should be a funkophile config file");
|
|
338
|
+
console.error("second argument should be a 'build' or 'watch'");
|
|
339
|
+
console.error("You passed", process.argv);
|
|
340
|
+
process.exit(-1);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
package/package.json
CHANGED
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "funkophile",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"main": "index.js",
|
|
3
|
+
"version": "0.0.4",
|
|
5
4
|
"repository": "git@github.com:adamwong246/funkophile.git",
|
|
6
5
|
"author": "adam wong <adamwong246@gmail.com>",
|
|
7
|
-
"license": "MIT"
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"help": "cat help.txt",
|
|
12
|
+
"transpile": "tsc --declaration index.ts funkophileHelpers.ts"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@tsconfig/node-lts-strictest-esm": "^18.12.1",
|
|
16
|
+
"@types/bluebird": "^3.5.42",
|
|
17
|
+
"@types/chokidar": "^2.1.7",
|
|
18
|
+
"@types/fs-extra": "^11.0.4",
|
|
19
|
+
"@types/redux": "^3.6.0",
|
|
20
|
+
"@types/reselect": "^2.2.0",
|
|
21
|
+
"tsc": "^2.0.4",
|
|
22
|
+
"typescript": "^5.8.2"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
"./index": {
|
|
26
|
+
"import": "./index.ts"
|
|
27
|
+
},
|
|
28
|
+
"./funkophileHelpers": {
|
|
29
|
+
"import": "./funkophileHelpers.ts"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
8
32
|
}
|