funkophile 0.0.4 → 0.0.6

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 (5) hide show
  1. package/index.d.ts +2 -1
  2. package/index.js +280 -247
  3. package/index.ts +394 -342
  4. package/package.json +1 -1
  5. package/tsconfig.json +11 -11
package/index.ts CHANGED
@@ -1,343 +1,395 @@
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"
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
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
-
7
+ import path from "path";
8
+ import Promise from "bluebird";
9
+
10
+ export default () => {
11
+ if (
12
+ process.argv[2] &&
13
+ (process.argv[3] === "watch" || process.argv[3] === "build")
14
+ ) {
15
+ const configFile = path.resolve(process.argv[2]);
16
+ const mode = process.argv[3];
17
+
18
+ // console.log("configfile", configFile);
19
+ import(configFile).then((funkophileConfigModule) => {
20
+ const funkophileConfig = funkophileConfigModule.default;
21
+ // console.log("funkophileConfig", (funkophileConfig));
22
+ Promise.config({
23
+ cancellation: true,
24
+ });
25
+
26
+ const INITIALIZE = "INITIALIZE";
27
+ const UPSERT = "UPSERT";
28
+ const REMOVE = "REMOVE";
29
+
30
+ const previousState: any = {};
31
+ let outputPromise = Promise.resolve();
32
+
33
+ const logger = {
34
+ watchError: (p: string) => console.log("\u001b[7m ! \u001b[0m" + p),
35
+ watchReady: (p: string) =>
36
+ console.log("\u001b[7m\u001b[36m < \u001b[0m" + p),
37
+ watchAdd: (p: string) =>
38
+ console.log("\u001b[7m\u001b[34m + \u001b[0m./" + p),
39
+ watchChange: (p: string) =>
40
+ console.log("\u001b[7m\u001b[35m * \u001b[0m" + p),
41
+ watchUnlink: (p: string) =>
42
+ console.log("\u001b[7m\u001b[31m - \u001b[0m./" + p),
43
+ stateChange: () =>
44
+ console.log(
45
+ "\u001b[7m\u001b[31m --- Redux state changed --- \u001b[0m"
46
+ ),
47
+ cleaningEmptyfolder: (p: string) =>
48
+ console.log("\u001b[31m\u001b[7m XXX! \u001b[0m" + p),
49
+ readingFile: (p: string) => console.log("\u001b[31m <-- \u001b[0m" + p),
50
+ removedFile: (p: string) =>
51
+ console.log("\u001b[31m\u001b[7m ??? \u001b[0m./" + p),
52
+ writingString: (p: string) =>
53
+ console.log("\u001b[32m --> \u001b[0m" + p),
54
+ writingFunction: (p: string) =>
55
+ console.log("\u001b[33m ... \u001b[0m" + p),
56
+ writingPromise: (p: string) =>
57
+ console.log("\u001b[33m ... \u001b[0m" + p),
58
+ writingError: (p: string, message: string) =>
59
+ console.log("\u001b[31m !!! \u001b[0m" + p + " " + message),
60
+
61
+ waiting: () =>
62
+ console.log(
63
+ "\u001b[7m Funkophile is done for now but waiting on changes...\u001b[0m "
64
+ ),
65
+ done: () => console.log("\u001b[7m Funkophile is done!\u001b[0m "),
66
+ };
67
+
68
+ function cleanEmptyFoldersRecursively(folder: string) {
69
+ var isDir = fs.statSync(folder).isDirectory();
70
+ if (!isDir) {
71
+ return;
72
+ }
73
+ var files = fs.readdirSync(folder);
74
+ if (files.length > 0) {
75
+ files.forEach(function (file) {
76
+ var fullPath = path.join(folder, file);
77
+ });
78
+
79
+ // re-evaluate files; after deleting subfolder
80
+ // we may have parent folder empty now
81
+ files = fs.readdirSync(folder);
82
+ }
83
+
84
+ if (files.length == 0) {
85
+ logger.cleaningEmptyfolder(folder);
86
+
87
+ fs.rmdirSync(folder);
88
+ return;
89
+ }
90
+ }
91
+
92
+ const dispatchUpsert = (
93
+ store: Store,
94
+ key: string,
95
+ file: string,
96
+ encodings: Record<string, string[]>
97
+ ) => {
98
+ const fileType: string = file.split(".").slice(-2, -1)[0] as string;
99
+ let encoding: BufferEncoding = Object.keys(encodings).find((e) =>
100
+ (encodings[e] as string[]).includes(fileType)
101
+ ) as BufferEncoding;
102
+
103
+ if (!fileType || !encoding) {
104
+ console.log(`Unknown file type for `, file, `Defaulting to utf8`);
105
+ encoding = "utf8";
106
+ }
107
+ // console.log("dispatchUpsert", encoding, file)
108
+ logger.readingFile(file);
109
+ store.dispatch({
110
+ type: UPSERT,
111
+ payload: {
112
+ key: key,
113
+ src: file,
114
+ contents: fse.readFileSync(file, encoding),
115
+ },
116
+ });
117
+ };
118
+
119
+ function omit(key: string, obj: any) {
120
+ const { [key]: omitted, ...rest } = obj;
121
+ return rest;
122
+ }
123
+
124
+ const store: Store<any, Action<string>, any> = createStore(
125
+ (
126
+ state = {
127
+ initialLoad: true,
128
+ ...funkophileConfig.initialState,
129
+ timestamp: Date.now(),
130
+ },
131
+ action
132
+ ) => {
133
+ // console.log("\u001b[7m\u001b[35m ||| Redux recieved action \u001b[0m", action.type)
134
+ if (!action.type.includes("@@redux")) {
135
+ if (action.type === INITIALIZE) {
136
+ return {
137
+ ...state,
138
+ initialLoad: false,
139
+ timestamp: Date.now(),
140
+ };
141
+ } else if (action.type === UPSERT) {
142
+ return {
143
+ ...state,
144
+ [action["payload"].key]: {
145
+ ...state[action.payload.key],
146
+ ...{
147
+ [action["payload"].src]: action["payload"].contents,
148
+ },
149
+ },
150
+ timestamp: Date.now(),
151
+ };
152
+ } else if (action.type === REMOVE) {
153
+ return {
154
+ ...state,
155
+ [action["payload"].key]: omit(
156
+ action["payload"].file,
157
+ state[action["payload"].key]
158
+ ),
159
+ timestamp: Date.now(),
160
+ };
161
+ } else {
162
+ console.error(
163
+ "Redux was asked to handle an unknown action type: " +
164
+ action.type
165
+ );
166
+ process.exit(-1);
167
+ }
168
+ // return state
169
+ }
170
+ }
171
+ );
172
+
173
+ const finalSelector = funkophileConfig.outputs(
174
+ Object.keys(funkophileConfig.inputs).reduce((mm, inputKey) => {
175
+ return {
176
+ ...mm,
177
+ [inputKey]: createSelector([(x) => x], (root) => root[inputKey]),
178
+ };
179
+ }, {})
180
+ );
181
+
182
+ // Wait for all the file watchers to check in
183
+ Promise.all(
184
+ Object.keys(funkophileConfig.inputs)
185
+ .map((inputRuleKey) => {
186
+ const p = path.resolve(
187
+ `./${funkophileConfig.options.inFolder}/${
188
+ funkophileConfig.inputs[inputRuleKey] || ""
189
+ }`
190
+ );
191
+
192
+ return new Promise((fulfill, reject) => {
193
+ if (mode === "build") {
194
+ glob(p, {})
195
+ .then((files: string[]) => {
196
+ files.forEach((file) => {
197
+ dispatchUpsert(
198
+ store,
199
+ inputRuleKey,
200
+ file,
201
+ funkophileConfig.encodings
202
+ );
203
+ });
204
+ })
205
+ .then(() => {
206
+ fulfill();
207
+ });
208
+ } else if (mode === "watch") {
209
+ chokidar
210
+ .watch(p, {})
211
+ .on("error", (error) => {
212
+ logger.watchError(p);
213
+ })
214
+ .on("ready", () => {
215
+ logger.watchReady(p);
216
+ fulfill();
217
+ })
218
+ .on("add", (p) => {
219
+ logger.watchAdd(p);
220
+ dispatchUpsert(
221
+ store,
222
+ inputRuleKey,
223
+ "./" + p,
224
+ funkophileConfig.encodings
225
+ );
226
+ })
227
+ .on("change", (p) => {
228
+ logger.watchChange(p);
229
+ dispatchUpsert(
230
+ store,
231
+ inputRuleKey,
232
+ "./" + p,
233
+ funkophileConfig.encodings
234
+ );
235
+ })
236
+ .on("unlink", (p) => {
237
+ logger.watchUnlink(p);
238
+ store.dispatch({
239
+ type: REMOVE,
240
+ payload: {
241
+ key: inputRuleKey,
242
+ file: "./" + p,
243
+ },
244
+ });
245
+ })
246
+ .on("unlinkDir", (p) => {
247
+ logger.watchUnlink(p);
248
+ });
249
+ // .on('raw', (event, p, details) => { // internal
250
+ // log('Raw event info:', event, p, details);
251
+ // })
252
+ } else {
253
+ console.error(
254
+ `The 3rd argument should be 'watch' or 'build', not "${mode}"`
255
+ );
256
+ process.exit(-1);
257
+ }
258
+ });
259
+ })
260
+ ).then(function () {
261
+ // listen for changes to the store
262
+ store.subscribe(() => {
263
+ const s = store.getState();
264
+
265
+ logger.stateChange();
266
+ const outputs = finalSelector(s);
267
+
268
+ if (outputPromise.isPending()) {
269
+ console.log("cancelling previous write!");
270
+ outputPromise.cancel();
271
+ }
272
+
273
+ outputPromise = Promise.all(
274
+ Array.from(
275
+ new Set(Object.keys(previousState).concat(Object.keys(outputs)))
276
+ ).map((key) => {
277
+ return new Promise((fulfill, reject) => {
278
+ if (!outputs[key]) {
279
+ const file = funkophileConfig.options.outFolder + "/" + key;
280
+ logger.removedFile(file);
281
+
282
+ try {
283
+ fse.unlinkSync("./" + file);
284
+ cleanEmptyFoldersRecursively(
285
+ "./" + file.substring(0, file.lastIndexOf("/"))
286
+ );
287
+ } catch (ex) {
288
+ // console.error('inner', ex.message);
289
+ // throw ex;
290
+ } finally {
291
+ // console.log('finally');
292
+ return;
293
+ }
294
+ // delete previousState[key]
295
+ // fulfill()
296
+ } else {
297
+ if (outputs[key] !== previousState[key]) {
298
+ previousState[key] = outputs[key];
299
+
300
+ const relativeFilePath =
301
+ "./" + funkophileConfig.options.outFolder + "/" + key;
302
+ const contents = outputs[key];
303
+
304
+ if (typeof contents === "function") {
305
+ logger.writingFunction(relativeFilePath);
306
+ contents((err, res) => {
307
+ fse.outputFile(relativeFilePath, res, fulfill);
308
+ logger.writingString(relativeFilePath);
309
+ });
310
+ } else if (typeof contents === "string") {
311
+ fse.outputFile(relativeFilePath, contents, fulfill);
312
+ logger.writingString(relativeFilePath);
313
+ } else if (Buffer.isBuffer(contents)) {
314
+ fse.outputFile(relativeFilePath, contents, fulfill);
315
+ logger.writingString(relativeFilePath);
316
+ } else if (Array.isArray(contents)) {
317
+ fse.outputFile(
318
+ relativeFilePath,
319
+ JSON.stringify(contents),
320
+ fulfill
321
+ );
322
+ logger.writingString(relativeFilePath);
323
+ } else if (typeof contents.then === "function") {
324
+ logger.writingPromise(relativeFilePath);
325
+ Promise.resolve(contents).then(
326
+ function (value) {
327
+ if (value instanceof Error) {
328
+ logger.writingError(
329
+ relativeFilePath,
330
+ value.message
331
+ );
332
+ } else {
333
+ fse.outputFile(relativeFilePath, value, fulfill);
334
+ logger.writingString(relativeFilePath);
335
+ }
336
+ },
337
+ function (value) {
338
+ // not called
339
+ }
340
+ );
341
+ } else if (typeof contents === "object") {
342
+ fse.outputFile(
343
+ relativeFilePath,
344
+ JSON.stringify(contents),
345
+ fulfill
346
+ );
347
+ logger.writingString(relativeFilePath);
348
+ } else {
349
+ console.log(
350
+ `I don't recognize what this is but I will try to write it to a file: ` +
351
+ relativeFilePath,
352
+ typeof contents,
353
+ contents
354
+ );
355
+ fse.outputFile(relativeFilePath, contents, fulfill);
356
+ logger.writingString(relativeFilePath);
357
+ }
358
+ } else {
359
+ fulfill();
360
+ }
361
+ }
362
+ });
363
+ })
364
+ ).then(() => {
365
+ cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
366
+
367
+ if (mode === "build") {
368
+ logger.done();
369
+ } else if (mode === "watch") {
370
+ logger.waiting();
371
+ } else {
372
+ console.error(
373
+ `The 3rd argument should be 'watch' or 'build', not "${mode}"`
374
+ );
375
+ process.exit(-1);
376
+ }
377
+ });
378
+ });
379
+
380
+ // lastly, turn the store `on`.
381
+ // This is to prevent unecessary recomputations when initialy adding files to redux
382
+ store.dispatch({
383
+ type: INITIALIZE,
384
+ payload: true,
385
+ });
386
+ });
387
+ });
388
+ } else {
389
+ console.error("command line arguments do not make sense");
390
+ console.error("first argument should be a funkophile config file");
391
+ console.error("second argument should be a 'build' or 'watch'");
392
+ console.error("You passed", process.argv);
393
+ process.exit(-1);
394
+ }
395
+ };