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', 'logic.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 |
|
40 | maybeProcess()
|
41 | }
|
42 |
|
43 | function maybeProcess() {
|
44 |
|
45 | clearTimeout(skipTimeout)
|
46 | skipTimeout = null
|
47 | if (processEventsPromise) {
|
48 | skipTimeout = setTimeout(maybeProcess, 200)
|
49 | return
|
50 | }
|
51 | processEvents()
|
52 | }
|
53 |
|
54 | async function processEvents() {
|
55 | if (queue.length === 0 || processEventsPromise) {
|
56 | return
|
57 | }
|
58 |
|
59 | let queueClone = [...queue]
|
60 | queue = []
|
61 | processEventsPromise = new Promise(async resolve => {
|
62 | try {
|
63 | await processQueue({ queue: queueClone, morpher })
|
64 | } catch (error) {
|
65 | console.error(error)
|
66 | } finally {
|
67 | resolve()
|
68 | processEventsPromise = null
|
69 | }
|
70 | })
|
71 | }
|
72 |
|
73 | watcher.on('add', file => onEvent({ file, op: 'add' }))
|
74 | watcher.on('change', file => onEvent({ file, op: 'change' }))
|
75 | watcher.on('unlink', file => onEvent({ file, op: 'unlink' }))
|
76 |
|
77 | return watcher
|
78 | }
|
79 |
|
80 | async function processQueue({ queue, morpher }) {
|
81 | let filesToProcess = {
|
82 | filesView: new Set(),
|
83 | filesViewLogic: new Set(),
|
84 | filesViewCustom: new Set(),
|
85 | filesFontCustom: new Set(),
|
86 | }
|
87 |
|
88 | await processUnlinked({
|
89 | files: queue.filter(item => item.op === 'unlink'),
|
90 | morpher,
|
91 | filesToProcess,
|
92 | })
|
93 |
|
94 | await processAddedOrChanged({
|
95 | files: queue.filter(item => item.op !== 'unlink'),
|
96 | morpher,
|
97 | filesToProcess,
|
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 && console.log(chalk.magenta('X'), file)
|
116 |
|
117 | if (await isFontCustomFile(file)) {
|
118 | let id = getFontId(file)
|
119 | let font = morpher.customFonts.get(id)
|
120 | font.delete(file)
|
121 |
|
122 | if (font.size === 0) {
|
123 | morpher.customFonts.delete(id)
|
124 | }
|
125 | } else {
|
126 | let view = morpher.viewsToFiles.get(path.dirname(file))
|
127 | if (!view) return
|
128 |
|
129 | processPointsOfUse({ view, morpher, filesToProcess })
|
130 |
|
131 | filesToProcess.filesView.delete(view.file)
|
132 | morpher.viewsById.delete(view.id)
|
133 | morpher.viewsToFiles.delete(view.file)
|
134 |
|
135 | try {
|
136 | fs.unlink(view.file)
|
137 | } catch (error) {}
|
138 |
|
139 | if (await isViewFile(file)) {
|
140 | filesToProcess.filesView.delete(file)
|
141 | } else if (await isViewLogicFile(file)) {
|
142 | filesToProcess.filesView.add(view.file)
|
143 | filesToProcess.filesViewLogic.delete(file)
|
144 | } else if (await isViewCustomFile(file)) {
|
145 | filesToProcess.filesViewCustom.delete(file)
|
146 | }
|
147 | }
|
148 | })
|
149 | )
|
150 | }
|
151 |
|
152 | function processAddedOrChanged({ files, morpher, filesToProcess }) {
|
153 | return Promise.all(
|
154 | files.map(async ({ file, op }) => {
|
155 | morpher.verbose && console.log(chalk.yellow(op), file)
|
156 |
|
157 | if (await isFontCustomFile(file)) {
|
158 | filesToProcess.filesFontCustom.add(file)
|
159 | } else {
|
160 | if (await isViewFile(file)) {
|
161 | filesToProcess.filesView.add(file)
|
162 |
|
163 | let logicFile = path.join(path.dirname(file), 'logic.js')
|
164 | if (existsSync(logicFile)) {
|
165 | filesToProcess.filesViewLogic.add(logicFile)
|
166 | }
|
167 | } else if (await isViewLogicFile(file)) {
|
168 | filesToProcess.filesView.add(file.replace('logic.js', 'view.blocks'))
|
169 | filesToProcess.filesViewLogic.add(file)
|
170 | } else if (await isViewCustomFile(file)) {
|
171 | filesToProcess.filesViewCustom.add(file)
|
172 | }
|
173 |
|
174 | let view = morpher.viewsToFiles.get(path.dirname(file))
|
175 | if (!view) return
|
176 |
|
177 | processPointsOfUse({ view, morpher, filesToProcess })
|
178 | }
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | })
|
189 | )
|
190 | }
|
191 |
|
192 | function processPointsOfUse({ view, morpher, filesToProcess }) {
|
193 | let { filesView, filesViewLogic } = getPointsOfUse({
|
194 | view,
|
195 | viewsToFiles: morpher.viewsToFiles,
|
196 | })
|
197 | for (let file of filesView) {
|
198 | filesToProcess.filesView.add(file)
|
199 | }
|
200 | for (let file of filesViewLogic) {
|
201 | filesToProcess.filesViewLogic.add(file)
|
202 | }
|
203 | }
|