1 | import {
|
2 | MATCH,
|
3 | isFontCustomFile,
|
4 | isViewCustomFile,
|
5 | isViewFile,
|
6 | isViewLogicFile,
|
7 | } from './match-files.js'
|
8 | import { promises as fs, existsSync } from 'fs'
|
9 | import { getFontId } from './fonts.js'
|
10 | import chalk from 'chalk'
|
11 | import chokidar from 'chokidar'
|
12 | import getPointsOfUse from './get-points-of-use.js'
|
13 | import path from 'path'
|
14 |
|
15 | export 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 |
|
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 |
|
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 |
|
79 | async 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
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | }
|
111 |
|
112 | function 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 |
|
157 | function 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 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | })
|
210 | )
|
211 | }
|
212 |
|
213 | function 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 | }
|