UNPKG

6.34 kBJavaScriptView Raw
1import {
2 MATCH,
3 isFontCustomFile,
4 isViewCustomFile,
5 isViewFile,
6 isViewLogicFile,
7} from './match-files.js'
8import { promises as fs, existsSync } from 'fs'
9import { getFontId } from './fonts.js'
10import chalk from 'chalk'
11import chokidar from 'chokidar'
12import getPointsOfUse from './get-points-of-use.js'
13import path from 'path'
14
15export default async function watchFiles({ morpher }) {
16 let watcher = chokidar.watch(MATCH, {
17 cwd: morpher.src,
18 ignored: [
19 path.join('**', 'node_modules', '**'),
20 path.join('**', 'view.js'),
21 path.join('**', 'DesignSystem', 'Fonts', '*.js'),
22 path.join('**', 'Logic', 'ViewsFlow.js'),
23 path.join('**', 'Logic', 'useIsMedia.js'),
24 path.join('**', 'Logic', 'useIsBefore.js'),
25 path.join('**', 'Logic', 'useIsHovered.js'),
26 path.join('**', 'Logic', 'ViewsTools.js'),
27 path.join('**', 'Data', 'ViewsData.js'),
28 ],
29 ignoreInitial: true,
30 // awaitWriteFinish: true,
31 })
32
33 let skipTimeout = null
34 let processEventsPromise = null
35 let queue = []
36
37 function onEvent({ file, op }) {
38 queue.push({ file: path.join(morpher.src, file), op })
39 maybeProcess()
40 }
41
42 function maybeProcess() {
43 // if busy, try again in a bit
44 clearTimeout(skipTimeout)
45 skipTimeout = null
46 if (processEventsPromise) {
47 skipTimeout = setTimeout(maybeProcess, 50)
48 return
49 }
50 processEvents()
51 }
52
53 async function processEvents() {
54 if (queue.length === 0 || processEventsPromise) {
55 return
56 }
57
58 let queueClone = [...queue]
59 queue = []
60 processEventsPromise = new Promise(async resolve => {
61 try {
62 await processQueue({ queue: queueClone, morpher })
63 } catch (error) {
64 console.error(error)
65 } finally {
66 resolve()
67 processEventsPromise = null
68 }
69 })
70 }
71
72 watcher.on('add', file => onEvent({ file, op: 'add' }))
73 watcher.on('change', file => onEvent({ file, op: 'change' }))
74 watcher.on('unlink', file => onEvent({ file, op: 'unlink' }))
75
76 return watcher
77}
78
79async function processQueue({ queue, morpher }) {
80 let filesToProcess = {
81 filesView: new Set(),
82 filesViewLogic: new Set(),
83 filesViewCustom: new Set(),
84 filesFontCustom: new Set(),
85 }
86
87 await Promise.all([
88 processUnlinked({
89 files: queue.filter(item => item.op === 'unlink'),
90 morpher,
91 filesToProcess,
92 }),
93 processAddedOrChanged({
94 files: queue.filter(item => item.op !== 'unlink'),
95 morpher,
96 filesToProcess,
97 }),
98 ])
99
100 await morpher.processFiles(filesToProcess)
101
102 if (!morpher.verbose) return // && viewsId.size > 0) {
103
104 // Object.entries(filesToProcess).forEach(([key, value]) => {
105 // console.log(chalk.greenBright(key), [...value])
106 // })
107
108 // console.log(chalk.green('M'), [...viewsId].join(', '))
109 // }
110}
111
112function processUnlinked({ files, morpher, filesToProcess }) {
113 return Promise.all(
114 files.map(async ({ file }) => {
115 morpher.verbose &&
116 console.log(
117 chalk.magenta('X'),
118 path.basename(path.dirname(file)),
119 chalk.dim(file.replace(morpher.src, '').replace(/^\//, ''))
120 )
121
122 if (await isFontCustomFile(file)) {
123 let id = getFontId(file)
124 let font = morpher.customFonts.get(id)
125 font.delete(file)
126
127 if (font.size === 0) {
128 morpher.customFonts.delete(id)
129 }
130 } else {
131 let viewFile = path.join(path.dirname(file), 'view.blocks')
132 let view = morpher.viewsToFiles.get(viewFile)
133 if (!view) return
134
135 processPointsOfUse({ view, morpher, filesToProcess })
136
137 filesToProcess.filesView.delete(view.file)
138 morpher.viewsById.delete(view.id)
139 morpher.viewsToFiles.delete(view.file)
140
141 if (await isViewFile(file)) {
142 filesToProcess.filesView.delete(file)
143 try {
144 await fs.unlink(file.replace('view.blocks', 'view.js'))
145 } catch (error) {}
146 } else if (await isViewLogicFile(file)) {
147 filesToProcess.filesView.add(view.file)
148 filesToProcess.filesViewLogic.delete(file)
149 } else if (await isViewCustomFile(file)) {
150 filesToProcess.filesViewCustom.delete(file)
151 }
152 }
153 })
154 )
155}
156
157function processAddedOrChanged({ files, morpher, filesToProcess }) {
158 return Promise.all(
159 files.map(async ({ file, op }) => {
160 morpher.verbose &&
161 console.log(
162 chalk.yellow(op.toUpperCase()[0]),
163 path.basename(path.dirname(file)),
164 chalk.dim(file.replace(morpher.src, '').replace(/^\//, ''))
165 )
166
167 if (await isFontCustomFile(file)) {
168 filesToProcess.filesFontCustom.add(file)
169 } else {
170 if (await isViewFile(file)) {
171 filesToProcess.filesView.add(file)
172
173 let logicFile = path.join(path.dirname(file), 'logic.js')
174 if (existsSync(logicFile)) {
175 filesToProcess.filesViewLogic.add(logicFile)
176 }
177
178 let parentFile = path.join(
179 path.dirname(path.dirname(file)),
180 'view.blocks'
181 )
182 if (existsSync(parentFile)) {
183 filesToProcess.filesView.add(parentFile)
184 }
185 } else if (await isViewLogicFile(file)) {
186 filesToProcess.filesView.add(
187 path.join(path.dirname(file), 'view.blocks')
188 )
189 filesToProcess.filesViewLogic.add(file)
190 } else if (await isViewCustomFile(file)) {
191 filesToProcess.filesViewCustom.add(file)
192 }
193
194 let viewFile = path.join(path.dirname(file), 'view.blocks')
195 let view = morpher.viewsToFiles.get(viewFile)
196 if (!view) return
197
198 processPointsOfUse({ view, morpher, filesToProcess })
199 }
200
201 // morpher.verbose &&
202 // console.log(
203 // op === 'add'
204 // ? `${chalk.yellow('A')} ${chalk.green('M')}`
205 // : chalk.green('M'),
206 // getViewIdFromFile(file),
207 // chalk.dim(`-> ${file}`)
208 // )
209 })
210 )
211}
212
213function processPointsOfUse({ view, morpher, filesToProcess }) {
214 let { filesView, filesViewLogic } = getPointsOfUse({
215 view,
216 viewsToFiles: morpher.viewsToFiles,
217 })
218
219 for (let file of filesView) {
220 filesToProcess.filesView.add(file)
221 }
222 for (let file of filesViewLogic) {
223 filesToProcess.filesViewLogic.add(file)
224 }
225}