handoff-app 1.1.3 → 1.2.0-1
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/config/config.template.js +21 -14
- package/config/config.template.ts +54 -0
- package/config/docs/system.md +2 -0
- package/dist/app-builder/build.js +31 -12
- package/dist/app-builder/config-diff/index.d.ts +4 -0
- package/dist/app-builder/config-diff/index.js +12 -0
- package/dist/app-builder/config-diff/registry.d.ts +9 -0
- package/dist/app-builder/config-diff/registry.js +30 -0
- package/dist/app-builder/config-diff/snapshot.d.ts +13 -0
- package/dist/app-builder/config-diff/snapshot.js +43 -0
- package/dist/app-builder/config-diff/strategies/pattern.d.ts +2 -0
- package/dist/app-builder/config-diff/strategies/pattern.js +106 -0
- package/dist/app-builder/config-diff/types.d.ts +33 -0
- package/dist/app-builder/config-diff/types.js +2 -0
- package/dist/app-builder/watchers/component.d.ts +15 -0
- package/dist/app-builder/watchers/component.js +69 -0
- package/dist/app-builder/watchers/utils.d.ts +14 -0
- package/dist/app-builder/watchers/utils.js +44 -0
- package/dist/app-builder/watchers.d.ts +10 -19
- package/dist/app-builder/watchers.js +65 -79
- package/dist/app-builder/websocket.js +10 -4
- package/dist/cache/build-cache.js +14 -5
- package/dist/cli/create.js +67 -23
- package/dist/cli/eject.js +48 -7
- package/dist/cli/make.js +29 -4
- package/dist/cli/scaffold.js +60 -19
- package/dist/cli.js +1 -1
- package/dist/config/helpers.d.ts +7 -0
- package/dist/config/helpers.js +31 -0
- package/dist/config/index.d.ts +2 -1
- package/dist/config/index.js +5 -1
- package/dist/config/loader.d.ts +10 -1
- package/dist/config/loader.js +92 -28
- package/dist/config/normalizers/declaration.d.ts +11 -0
- package/dist/config/normalizers/declaration.js +119 -0
- package/dist/config/normalizers/pattern.d.ts +8 -0
- package/dist/config/normalizers/pattern.js +35 -0
- package/dist/config/runtime.d.ts +9 -3
- package/dist/config/runtime.js +260 -33
- package/dist/declarations/helpers.d.ts +6 -0
- package/dist/declarations/helpers.js +19 -0
- package/dist/declarations/index.d.ts +2 -0
- package/dist/declarations/index.js +9 -0
- package/dist/declarations/types.d.ts +60 -0
- package/dist/declarations/types.js +2 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +34 -5
- package/dist/pipeline/index.d.ts +1 -0
- package/dist/pipeline/index.js +3 -1
- package/dist/pipeline/patterns.d.ts +8 -0
- package/dist/pipeline/patterns.js +21 -0
- package/dist/transformers/docgen/index.js +12 -2
- package/dist/transformers/plugins/csf-render.js +170 -34
- package/dist/transformers/plugins/ssr-render.js +18 -2
- package/dist/transformers/preview/component/api.js +16 -7
- package/dist/transformers/preview/component/builder.js +61 -8
- package/dist/transformers/preview/component/css.d.ts +8 -0
- package/dist/transformers/preview/component/css.js +6 -4
- package/dist/transformers/preview/component/html.js +14 -5
- package/dist/transformers/preview/component/javascript.d.ts +0 -1
- package/dist/transformers/preview/component/javascript.js +25 -14
- package/dist/transformers/preview/component/previews.d.ts +9 -0
- package/dist/transformers/preview/component/previews.js +10 -0
- package/dist/transformers/preview/pattern/api.d.ts +11 -0
- package/dist/transformers/preview/pattern/api.js +79 -0
- package/dist/transformers/preview/pattern/builder.d.ts +17 -0
- package/dist/transformers/preview/pattern/builder.js +167 -0
- package/dist/transformers/preview/pattern/html.d.ts +19 -0
- package/dist/transformers/preview/pattern/html.js +94 -0
- package/dist/transformers/preview/types.d.ts +54 -0
- package/dist/transformers/utils/csf.d.ts +16 -0
- package/dist/transformers/utils/csf.js +30 -0
- package/dist/transformers/utils/index.d.ts +1 -0
- package/dist/transformers/utils/index.js +2 -0
- package/dist/transformers/utils/module.d.ts +5 -0
- package/dist/transformers/utils/module.js +26 -13
- package/dist/transformers/utils/usage.d.ts +23 -0
- package/dist/transformers/utils/usage.js +294 -0
- package/dist/transformers/utils/vite-logger.js +4 -4
- package/dist/transformers/vite-config.js +2 -0
- package/dist/types/config.d.ts +32 -7
- package/dist/types/preview.d.ts +2 -0
- package/dist/utils/duration.d.ts +2 -0
- package/dist/utils/duration.js +6 -0
- package/dist/utils/logger.d.ts +42 -5
- package/dist/utils/logger.js +135 -15
- package/docs/cli.md +3 -3
- package/package.json +3 -1
- package/src/app/components/Component/PageSliceResolver.tsx +6 -6
- package/src/app/components/Component/Preview.tsx +17 -12
- package/src/app/components/Component/slices/ComponentDisplaySlice.tsx +16 -6
- package/src/app/components/Markdown/CodeHighlight.tsx +60 -11
- package/src/app/components/util/index.ts +71 -2
- package/src/app/pages/system/pattern/[pattern]/index.tsx +346 -0
- package/src/app/pages/system/pattern/index.tsx +14 -0
- package/src/app-builder/README.md +37 -9
- package/src/app-builder/build.ts +34 -12
- package/src/app-builder/config-diff/index.ts +4 -0
- package/src/app-builder/config-diff/registry.ts +23 -0
- package/src/app-builder/config-diff/snapshot.ts +51 -0
- package/src/app-builder/config-diff/strategies/pattern.ts +80 -0
- package/src/app-builder/config-diff/types.ts +36 -0
- package/src/app-builder/watchers/component.ts +72 -0
- package/src/app-builder/watchers/utils.ts +44 -0
- package/src/app-builder/watchers.ts +74 -80
- package/src/app-builder/websocket.ts +16 -5
- package/src/cache/build-cache.ts +14 -5
- package/src/cli/create.ts +86 -25
- package/src/cli/eject.ts +29 -7
- package/src/cli/make.ts +32 -5
- package/src/cli/scaffold.ts +68 -21
- package/src/cli.ts +1 -1
- package/src/config/README.md +10 -1
- package/src/config/helpers.ts +43 -0
- package/src/config/index.ts +4 -1
- package/src/config/loader.ts +110 -31
- package/src/config/normalizers/declaration.ts +176 -0
- package/src/config/normalizers/pattern.ts +56 -0
- package/src/config/runtime.ts +317 -35
- package/src/declarations/helpers.ts +36 -0
- package/src/declarations/index.ts +19 -0
- package/src/declarations/types.ts +70 -0
- package/src/index.ts +47 -6
- package/src/pipeline/index.ts +1 -0
- package/src/pipeline/patterns.ts +12 -0
- package/src/transformers/README.md +2 -2
- package/src/transformers/docgen/index.ts +13 -2
- package/src/transformers/plugins/csf-render.ts +216 -49
- package/src/transformers/plugins/ssr-render.ts +23 -7
- package/src/transformers/preview/component/api.ts +27 -7
- package/src/transformers/preview/component/builder.ts +82 -9
- package/src/transformers/preview/component/css.ts +6 -5
- package/src/transformers/preview/component/html.ts +18 -5
- package/src/transformers/preview/component/javascript.ts +29 -19
- package/src/transformers/preview/component/previews.ts +12 -0
- package/src/transformers/preview/pattern/api.ts +83 -0
- package/src/transformers/preview/pattern/builder.ts +192 -0
- package/src/transformers/preview/pattern/html.ts +107 -0
- package/src/transformers/preview/types.ts +58 -1
- package/src/transformers/utils/csf.ts +48 -0
- package/src/transformers/utils/index.ts +3 -0
- package/src/transformers/utils/module.ts +33 -18
- package/src/transformers/utils/usage.ts +319 -0
- package/src/transformers/utils/vite-logger.ts +4 -4
- package/src/transformers/vite-config.ts +2 -0
- package/src/types/README.md +1 -1
- package/src/types/config.ts +33 -7
- package/src/types/preview.ts +2 -0
- package/src/utils/duration.ts +3 -0
- package/src/utils/logger.ts +143 -16
- package/templates/default/components/button/Button.jsx.tpl +64 -0
- package/templates/default/components/button/button.react.handoff.js.tpl +31 -0
- package/templates/default/components/button/button.react.handoff.ts.tpl +31 -0
- package/templates/default/handoff.config.js.tpl +29 -16
- package/templates/default/handoff.config.ts.tpl +196 -0
- package/templates/default/handoff.config.with-examples.js.tpl +28 -17
- package/templates/default/handoff.config.with-examples.ts.tpl +195 -0
- package/templates/default/package.json.tpl +1 -3
- package/handoff.config.js +0 -90
- package/templates/default/components/button/button.js.tpl +0 -62
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
/** @type {import('handoff-app').Config} */
|
|
2
1
|
const path = require('path');
|
|
3
|
-
|
|
2
|
+
const { defineConfig } = require('handoff-app');
|
|
3
|
+
/** @typedef {import('handoff-app').Config} HandoffConfig */
|
|
4
|
+
|
|
5
|
+
/** @type {HandoffConfig} */
|
|
6
|
+
const config = {
|
|
4
7
|
// Set your Figma project ID here or in the environment variable HANDOFF_FIGMA_PROJECT_ID
|
|
5
|
-
|
|
8
|
+
figmaProjectId: null,
|
|
6
9
|
// Set the output directory for the exported components
|
|
7
10
|
exportsOutputDirectory: 'exported',
|
|
8
11
|
// Set the output directory for the sites
|
|
@@ -16,13 +19,13 @@ module.exports = {
|
|
|
16
19
|
// Set the client for the application, used in the footer
|
|
17
20
|
client: 'Handoff Technologies',
|
|
18
21
|
// Set the Google Tag Manager ID to add GTM scripts
|
|
19
|
-
|
|
22
|
+
googleTagManager: null,
|
|
20
23
|
// Set the attribution for the application
|
|
21
24
|
attribution: true, // Should we remove this?
|
|
22
25
|
// Set the type copy for the typeography page
|
|
23
|
-
|
|
26
|
+
typeCopy: 'Almost before we knew it, we had left the ground.',
|
|
24
27
|
// Set the type sort for the typeography page
|
|
25
|
-
|
|
28
|
+
typeSort: [
|
|
26
29
|
'Heading 1',
|
|
27
30
|
'Heading 2',
|
|
28
31
|
'Heading 3',
|
|
@@ -36,17 +39,16 @@ module.exports = {
|
|
|
36
39
|
'Link',
|
|
37
40
|
],
|
|
38
41
|
// Set the color sort for the color page
|
|
39
|
-
|
|
42
|
+
colorSort: ['primary', 'secondary', 'extra', 'system'],
|
|
40
43
|
// Set the component sort for the component page
|
|
41
|
-
|
|
44
|
+
componentSort: ['primary', 'secondary', 'transparent'],
|
|
42
45
|
// Set the base path for the application
|
|
43
|
-
|
|
46
|
+
basePath: '',
|
|
44
47
|
// Set the breakpoints for the application
|
|
45
48
|
breakpoints: {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
xl: { size: 1200, name: 'Extra Large' },
|
|
49
|
+
mobile: { size: 400, name: 'Mobile' },
|
|
50
|
+
tablet: { size: 800, name: 'Medium' },
|
|
51
|
+
desktop: { size: 1100, name: 'Large' },
|
|
50
52
|
},
|
|
51
53
|
// Set the ports for the application
|
|
52
54
|
ports: { app: 3000, websocket: 3001 },
|
|
@@ -56,9 +58,12 @@ module.exports = {
|
|
|
56
58
|
scss: './sass/main.scss',
|
|
57
59
|
js: './js/main.js',
|
|
58
60
|
components: ['./components'],
|
|
61
|
+
// Uncomment to enable pattern documentation pages.
|
|
62
|
+
// Patterns compose component previews into single-page views.
|
|
63
|
+
// patterns: ['./patterns'],
|
|
59
64
|
},
|
|
60
65
|
// These are the asset zip file download links
|
|
61
|
-
|
|
66
|
+
assetsZipLinks: {
|
|
62
67
|
icons: null,
|
|
63
68
|
logos: null,
|
|
64
69
|
},
|
|
@@ -86,3 +91,5 @@ module.exports = {
|
|
|
86
91
|
},
|
|
87
92
|
},
|
|
88
93
|
};
|
|
94
|
+
|
|
95
|
+
module.exports = defineConfig(config);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineConfig } from 'handoff-app';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
figmaProjectId: null,
|
|
5
|
+
exportsOutputDirectory: 'exported',
|
|
6
|
+
sitesOutputDirectory: 'out',
|
|
7
|
+
app: {
|
|
8
|
+
theme: 'default',
|
|
9
|
+
title: 'Handoff Design System',
|
|
10
|
+
client: 'Handoff Technologies',
|
|
11
|
+
googleTagManager: null,
|
|
12
|
+
attribution: true,
|
|
13
|
+
typeCopy: 'Almost before we knew it, we had left the ground.',
|
|
14
|
+
typeSort: [
|
|
15
|
+
'Heading 1',
|
|
16
|
+
'Heading 2',
|
|
17
|
+
'Heading 3',
|
|
18
|
+
'Heading 4',
|
|
19
|
+
'Heading 5',
|
|
20
|
+
'Heading 6',
|
|
21
|
+
'Paragraph',
|
|
22
|
+
'Subheading',
|
|
23
|
+
'Blockquote',
|
|
24
|
+
'Input Labels',
|
|
25
|
+
'Link',
|
|
26
|
+
],
|
|
27
|
+
colorSort: ['primary', 'secondary', 'extra', 'system'],
|
|
28
|
+
componentSort: ['primary', 'secondary', 'transparent'],
|
|
29
|
+
basePath: '',
|
|
30
|
+
breakpoints: {
|
|
31
|
+
mobile: { size: 400, name: 'Mobile' },
|
|
32
|
+
tablet: { size: 800, name: 'Medium' },
|
|
33
|
+
desktop: { size: 1100, name: 'Large' },
|
|
34
|
+
},
|
|
35
|
+
ports: { app: 3000, websocket: 3001 },
|
|
36
|
+
},
|
|
37
|
+
entries: {
|
|
38
|
+
scss: './sass/main.scss',
|
|
39
|
+
js: './js/main.js',
|
|
40
|
+
components: ['./components'],
|
|
41
|
+
// patterns: ['./patterns'],
|
|
42
|
+
},
|
|
43
|
+
assetsZipLinks: {
|
|
44
|
+
icons: null,
|
|
45
|
+
logos: null,
|
|
46
|
+
},
|
|
47
|
+
hooks: {
|
|
48
|
+
cssBuildConfig: (config) => config,
|
|
49
|
+
validateComponent: () => ({}),
|
|
50
|
+
clientBuildConfig: (config) => config,
|
|
51
|
+
htmlBuildConfig: (config) => config,
|
|
52
|
+
jsBuildConfig: (config) => config,
|
|
53
|
+
},
|
|
54
|
+
});
|
package/config/docs/system.md
CHANGED
|
@@ -17,6 +17,7 @@ const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
|
|
17
17
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
19
19
|
const components_1 = require("../pipeline/components");
|
|
20
|
+
const patterns_1 = require("../pipeline/patterns");
|
|
20
21
|
const css_1 = require("../transformers/preview/component/css");
|
|
21
22
|
const javascript_1 = require("../transformers/preview/component/javascript");
|
|
22
23
|
const builder_1 = __importDefault(require("../transformers/preview/component/builder"));
|
|
@@ -95,9 +96,10 @@ const buildApp = (handoff, skipComponents) => __awaiter(void 0, void 0, void 0,
|
|
|
95
96
|
skipComponents = skipComponents !== null && skipComponents !== void 0 ? skipComponents : false;
|
|
96
97
|
// Perform cleanup
|
|
97
98
|
yield cleanupAppDirectory(handoff);
|
|
98
|
-
// Build components
|
|
99
|
+
// Build components, then patterns (patterns depend on component output)
|
|
99
100
|
if (!skipComponents) {
|
|
100
101
|
yield (0, components_1.buildComponents)(handoff);
|
|
102
|
+
yield (0, patterns_1.buildPatterns)(handoff);
|
|
101
103
|
}
|
|
102
104
|
// Prepare app
|
|
103
105
|
const appPath = yield initializeProjectApp(handoff);
|
|
@@ -105,9 +107,11 @@ const buildApp = (handoff, skipComponents) => __awaiter(void 0, void 0, void 0,
|
|
|
105
107
|
// Build app
|
|
106
108
|
const buildResult = cross_spawn_1.default.sync('npx', ['next', 'build'], {
|
|
107
109
|
cwd: appPath,
|
|
108
|
-
stdio: 'inherit',
|
|
110
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
109
111
|
env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'production' }),
|
|
110
112
|
});
|
|
113
|
+
logger_1.Logger.childProcessBuffer(buildResult.stdout);
|
|
114
|
+
logger_1.Logger.childProcessBuffer(buildResult.stderr);
|
|
111
115
|
if (buildResult.status !== 0) {
|
|
112
116
|
let errorMsg = `Next.js build failed with exit code ${buildResult.status}`;
|
|
113
117
|
if (buildResult.error) {
|
|
@@ -137,6 +141,8 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
137
141
|
yield (0, builder_1.default)(handoff, undefined, undefined, { useCache: true });
|
|
138
142
|
yield (0, javascript_1.buildMainJS)(handoff);
|
|
139
143
|
yield (0, css_1.buildMainCss)(handoff);
|
|
144
|
+
// Build patterns after components are ready
|
|
145
|
+
yield (0, patterns_1.buildPatterns)(handoff);
|
|
140
146
|
const appPath = yield initializeProjectApp(handoff);
|
|
141
147
|
// Persist client configuration
|
|
142
148
|
yield (0, client_config_1.persistClientConfig)(handoff);
|
|
@@ -151,19 +157,28 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
151
157
|
// create empty directory
|
|
152
158
|
yield fs_extra_1.default.ensureDir(moduleOutput);
|
|
153
159
|
}
|
|
160
|
+
logger_1.Logger.info(`Starting Next.js dev server (Turbopack) at http://${hostname}:${port}…`);
|
|
154
161
|
const nextProcess = (0, cross_spawn_1.default)('npx', ['next', 'dev', '--turbopack', '--port', String(port)], {
|
|
155
162
|
cwd: appPath,
|
|
156
|
-
stdio: 'inherit',
|
|
163
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
157
164
|
env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'development' }),
|
|
158
165
|
});
|
|
159
|
-
logger_1.Logger.
|
|
166
|
+
logger_1.Logger.pipeChildStreams(nextProcess.stdout, nextProcess.stderr);
|
|
160
167
|
nextProcess.on('error', (error) => {
|
|
161
|
-
logger_1.Logger.error(`Next.js dev process
|
|
168
|
+
logger_1.Logger.error(`Next.js dev process failed to start: ${error}`);
|
|
162
169
|
process.exit(1);
|
|
163
170
|
});
|
|
164
|
-
nextProcess.on('close', (code) => {
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
nextProcess.on('close', (code, signal) => {
|
|
172
|
+
if (code === 0) {
|
|
173
|
+
logger_1.Logger.success(`Next.js dev process exited normally`);
|
|
174
|
+
}
|
|
175
|
+
else if (signal) {
|
|
176
|
+
logger_1.Logger.warn(`Next.js dev process stopped (${signal})`);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
logger_1.Logger.error(`Next.js dev process exited with code ${code}`);
|
|
180
|
+
}
|
|
181
|
+
process.exit(code !== null && code !== void 0 ? code : 1);
|
|
167
182
|
});
|
|
168
183
|
const wss = yield (0, websocket_1.createWebSocketServer)((_d = (_c = handoff.config.app.ports) === null || _c === void 0 ? void 0 : _c.websocket) !== null && _d !== void 0 ? _d : 3001);
|
|
169
184
|
const chokidarConfig = {
|
|
@@ -172,7 +187,8 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
172
187
|
ignoreInitial: true,
|
|
173
188
|
};
|
|
174
189
|
const state = {
|
|
175
|
-
|
|
190
|
+
busy: false,
|
|
191
|
+
pendingHandlers: new Map(),
|
|
176
192
|
runtimeComponentsWatcher: null,
|
|
177
193
|
runtimeConfigurationWatcher: null,
|
|
178
194
|
componentDirectoriesWatcher: null,
|
|
@@ -200,12 +216,15 @@ const devApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
200
216
|
}
|
|
201
217
|
// Persist client configuration
|
|
202
218
|
yield (0, client_config_1.persistClientConfig)(handoff);
|
|
203
|
-
|
|
204
|
-
|
|
219
|
+
const devPort = (_b = (_a = handoff.config.app.ports) === null || _a === void 0 ? void 0 : _a.app) !== null && _b !== void 0 ? _b : 3000;
|
|
220
|
+
logger_1.Logger.info(`Starting Next.js dev server (Turbopack) on port ${devPort}…`);
|
|
221
|
+
const devResult = cross_spawn_1.default.sync('npx', ['next', 'dev', '--turbopack', '--port', String(devPort)], {
|
|
205
222
|
cwd: appPath,
|
|
206
|
-
stdio: 'inherit',
|
|
223
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
207
224
|
env: Object.assign(Object.assign({}, process.env), { NODE_ENV: 'development' }),
|
|
208
225
|
});
|
|
226
|
+
logger_1.Logger.childProcessBuffer(devResult.stdout);
|
|
227
|
+
logger_1.Logger.childProcessBuffer(devResult.stderr);
|
|
209
228
|
if (devResult.status !== 0) {
|
|
210
229
|
let errorMsg = `Next.js dev failed with exit code ${devResult.status}`;
|
|
211
230
|
if (devResult.error) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { ConfigDiffStrategy, FinalizeContext, RebuildHandle } from './types';
|
|
2
|
+
export { type MapSnapshot, diffMapSnapshots, stableStringify } from './snapshot';
|
|
3
|
+
export { patternDiffStrategy } from './strategies/pattern';
|
|
4
|
+
export { getAllStrategies, getStrategy, runAllFinalizers } from './registry';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runAllFinalizers = exports.getStrategy = exports.getAllStrategies = exports.patternDiffStrategy = exports.stableStringify = exports.diffMapSnapshots = void 0;
|
|
4
|
+
var snapshot_1 = require("./snapshot");
|
|
5
|
+
Object.defineProperty(exports, "diffMapSnapshots", { enumerable: true, get: function () { return snapshot_1.diffMapSnapshots; } });
|
|
6
|
+
Object.defineProperty(exports, "stableStringify", { enumerable: true, get: function () { return snapshot_1.stableStringify; } });
|
|
7
|
+
var pattern_1 = require("./strategies/pattern");
|
|
8
|
+
Object.defineProperty(exports, "patternDiffStrategy", { enumerable: true, get: function () { return pattern_1.patternDiffStrategy; } });
|
|
9
|
+
var registry_1 = require("./registry");
|
|
10
|
+
Object.defineProperty(exports, "getAllStrategies", { enumerable: true, get: function () { return registry_1.getAllStrategies; } });
|
|
11
|
+
Object.defineProperty(exports, "getStrategy", { enumerable: true, get: function () { return registry_1.getStrategy; } });
|
|
12
|
+
Object.defineProperty(exports, "runAllFinalizers", { enumerable: true, get: function () { return registry_1.runAllFinalizers; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Handoff from '../..';
|
|
2
|
+
import { ConfigDiffStrategy, FinalizeContext } from './types';
|
|
3
|
+
export declare const getStrategy: (kind: string) => ConfigDiffStrategy | undefined;
|
|
4
|
+
export declare const getAllStrategies: () => ConfigDiffStrategy[];
|
|
5
|
+
/**
|
|
6
|
+
* Runs every registered strategy finalizer.
|
|
7
|
+
* Called after component rebuilds so derived artifacts stay up-to-date.
|
|
8
|
+
*/
|
|
9
|
+
export declare const runAllFinalizers: (handoff: Handoff, context?: FinalizeContext) => Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runAllFinalizers = exports.getAllStrategies = exports.getStrategy = void 0;
|
|
13
|
+
const pattern_1 = require("./strategies/pattern");
|
|
14
|
+
const strategies = new Map([
|
|
15
|
+
[pattern_1.patternDiffStrategy.kind, pattern_1.patternDiffStrategy],
|
|
16
|
+
]);
|
|
17
|
+
const getStrategy = (kind) => strategies.get(kind);
|
|
18
|
+
exports.getStrategy = getStrategy;
|
|
19
|
+
const getAllStrategies = () => Array.from(strategies.values());
|
|
20
|
+
exports.getAllStrategies = getAllStrategies;
|
|
21
|
+
/**
|
|
22
|
+
* Runs every registered strategy finalizer.
|
|
23
|
+
* Called after component rebuilds so derived artifacts stay up-to-date.
|
|
24
|
+
*/
|
|
25
|
+
const runAllFinalizers = (handoff, context) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
+
for (const strategy of strategies.values()) {
|
|
27
|
+
yield strategy.finalize(handoff, context);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
exports.runAllFinalizers = runAllFinalizers;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** outerKey -> Map<innerKey, serializedValue> */
|
|
2
|
+
export type MapSnapshot = Map<string, Map<string, string>>;
|
|
3
|
+
/**
|
|
4
|
+
* Deterministic JSON serializer that sorts object keys at every nesting level.
|
|
5
|
+
* Prevents false-positive diffs when identical values are constructed with
|
|
6
|
+
* different key insertion order across reloads.
|
|
7
|
+
*/
|
|
8
|
+
export declare const stableStringify: (value: unknown) => string;
|
|
9
|
+
/**
|
|
10
|
+
* Compares two MapSnapshots and returns the outer keys where the inner maps
|
|
11
|
+
* differ (added, removed, or values changed).
|
|
12
|
+
*/
|
|
13
|
+
export declare const diffMapSnapshots: (oldSnapshot: MapSnapshot, newSnapshot: MapSnapshot) => string[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffMapSnapshots = exports.stableStringify = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Deterministic JSON serializer that sorts object keys at every nesting level.
|
|
6
|
+
* Prevents false-positive diffs when identical values are constructed with
|
|
7
|
+
* different key insertion order across reloads.
|
|
8
|
+
*/
|
|
9
|
+
const stableStringify = (value) => JSON.stringify(value, (_, v) => v && typeof v === 'object' && !Array.isArray(v)
|
|
10
|
+
? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a.localeCompare(b)))
|
|
11
|
+
: v);
|
|
12
|
+
exports.stableStringify = stableStringify;
|
|
13
|
+
/**
|
|
14
|
+
* Compares two MapSnapshots and returns the outer keys where the inner maps
|
|
15
|
+
* differ (added, removed, or values changed).
|
|
16
|
+
*/
|
|
17
|
+
const diffMapSnapshots = (oldSnapshot, newSnapshot) => {
|
|
18
|
+
const affected = new Set();
|
|
19
|
+
for (const [key, oldEntries] of oldSnapshot) {
|
|
20
|
+
const newEntries = newSnapshot.get(key);
|
|
21
|
+
if (!newEntries) {
|
|
22
|
+
affected.add(key);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (oldEntries.size !== newEntries.size) {
|
|
26
|
+
affected.add(key);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
for (const [subKey, oldValue] of oldEntries) {
|
|
30
|
+
if (newEntries.get(subKey) !== oldValue) {
|
|
31
|
+
affected.add(key);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const key of newSnapshot.keys()) {
|
|
37
|
+
if (!oldSnapshot.has(key)) {
|
|
38
|
+
affected.add(key);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return Array.from(affected);
|
|
42
|
+
};
|
|
43
|
+
exports.diffMapSnapshots = diffMapSnapshots;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.patternDiffStrategy = void 0;
|
|
36
|
+
const patterns_1 = require("../../../pipeline/patterns");
|
|
37
|
+
const builder_1 = __importStar(require("../../../transformers/preview/component/builder"));
|
|
38
|
+
const builder_2 = require("../../../transformers/preview/pattern/builder");
|
|
39
|
+
const logger_1 = require("../../../utils/logger");
|
|
40
|
+
const snapshot_1 = require("../snapshot");
|
|
41
|
+
/**
|
|
42
|
+
* Snapshots every __pattern_{patternId}_* synthetic preview entry across all
|
|
43
|
+
* components. Outer key is component id, inner key is synthetic preview key.
|
|
44
|
+
*/
|
|
45
|
+
const snapshotPatternSynthetics = (handoff, patternId) => {
|
|
46
|
+
var _a, _b, _c, _d;
|
|
47
|
+
const components = (_c = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) !== null && _c !== void 0 ? _c : {};
|
|
48
|
+
const prefix = `__pattern_${patternId}_`;
|
|
49
|
+
const result = new Map();
|
|
50
|
+
for (const [componentId, component] of Object.entries(components)) {
|
|
51
|
+
const previews = (_d = component.internalPatternPreviews) !== null && _d !== void 0 ? _d : {};
|
|
52
|
+
const entries = new Map();
|
|
53
|
+
for (const [key, preview] of Object.entries(previews)) {
|
|
54
|
+
if (key.startsWith(prefix)) {
|
|
55
|
+
entries.set(key, (0, snapshot_1.stableStringify)(preview.values));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (entries.size > 0) {
|
|
59
|
+
result.set(componentId, entries);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
exports.patternDiffStrategy = {
|
|
65
|
+
kind: 'pattern',
|
|
66
|
+
capture(handoff, entityId) {
|
|
67
|
+
const oldSnapshot = snapshotPatternSynthetics(handoff, entityId);
|
|
68
|
+
return {
|
|
69
|
+
apply(handoff, entityIdAfterReload) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
const newSnapshot = entityIdAfterReload
|
|
72
|
+
? snapshotPatternSynthetics(handoff, entityIdAfterReload)
|
|
73
|
+
: new Map();
|
|
74
|
+
const affectedIds = (0, snapshot_1.diffMapSnapshots)(oldSnapshot, newSnapshot);
|
|
75
|
+
const displayId = entityIdAfterReload || entityId;
|
|
76
|
+
if (affectedIds.length > 0) {
|
|
77
|
+
logger_1.Logger.debug(`Pattern "${displayId}" changed: rebuilding ${affectedIds.length} affected component(s): ${affectedIds.join(', ')}`);
|
|
78
|
+
for (const componentId of affectedIds) {
|
|
79
|
+
yield (0, builder_1.default)(handoff, componentId, builder_1.ComponentSegment.Previews);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
logger_1.Logger.debug(`Pattern "${displayId}" changed: no synthetic previews affected, skipping component rebuild.`);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
finalize(handoff, context) {
|
|
90
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
if (context === null || context === void 0 ? void 0 : context.skipPatternFinalizer) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const componentIds = context === null || context === void 0 ? void 0 : context.patternRebuildComponentIds;
|
|
95
|
+
if (componentIds === null || componentIds === void 0 ? void 0 : componentIds.length) {
|
|
96
|
+
const patternIds = (0, builder_2.getPatternIdsReferencingComponents)(handoff, componentIds);
|
|
97
|
+
if (patternIds.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
yield (0, patterns_1.buildPatterns)(handoff, { onlyPatternIds: new Set(patternIds) });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
yield (0, patterns_1.buildPatterns)(handoff);
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Handoff from '../..';
|
|
2
|
+
/**
|
|
3
|
+
* Optional hints for post-build finalizers (e.g. selective pattern rebuild).
|
|
4
|
+
*/
|
|
5
|
+
export type FinalizeContext = {
|
|
6
|
+
/**
|
|
7
|
+
* Only patterns that reference at least one of these component ids are rebuilt.
|
|
8
|
+
* When omitted, all patterns are rebuilt.
|
|
9
|
+
*/
|
|
10
|
+
patternRebuildComponentIds?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* When true, skip pattern artifact generation (no component preview HTML changed).
|
|
13
|
+
*/
|
|
14
|
+
skipPatternFinalizer?: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Handle returned by ConfigDiffStrategy.capture().
|
|
18
|
+
*
|
|
19
|
+
* Captures the pre-reload state in a closure so the snapshot type stays
|
|
20
|
+
* fully encapsulated and the watcher only sees this opaque handle.
|
|
21
|
+
*/
|
|
22
|
+
export interface RebuildHandle {
|
|
23
|
+
apply(handoff: Handoff, entityIdAfterReload: string | undefined): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Encapsulates the snapshot -> reload -> diff -> selective-rebuild protocol
|
|
27
|
+
* for a single config-file entity kind.
|
|
28
|
+
*/
|
|
29
|
+
export interface ConfigDiffStrategy {
|
|
30
|
+
readonly kind: string;
|
|
31
|
+
capture(handoff: Handoff, entityId: string): RebuildHandle;
|
|
32
|
+
finalize(handoff: Handoff, context?: FinalizeContext): Promise<void>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Handoff from '../..';
|
|
2
|
+
import { ComponentSegment } from '../../transformers/preview/component/builder';
|
|
3
|
+
import { ComponentListObject } from '../../transformers/preview/types';
|
|
4
|
+
export type RuntimeComponentEntryType = keyof ComponentListObject['entries'];
|
|
5
|
+
/**
|
|
6
|
+
* Maps configuration entry types to component segments.
|
|
7
|
+
*/
|
|
8
|
+
export declare const mapEntryTypeToSegment: (type: RuntimeComponentEntryType) => ComponentSegment | undefined;
|
|
9
|
+
export declare const resolveComponentIdForChangedFile: (handoff: Handoff, changedFilePath: string) => string | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Gets the paths of runtime components to watch.
|
|
12
|
+
*
|
|
13
|
+
* @returns A map of paths to watch and their entry types.
|
|
14
|
+
*/
|
|
15
|
+
export declare const getRuntimeComponentsPathsToWatch: (handoff: Handoff) => Map<string, RuntimeComponentEntryType>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getRuntimeComponentsPathsToWatch = exports.resolveComponentIdForChangedFile = exports.mapEntryTypeToSegment = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const builder_1 = require("../../transformers/preview/component/builder");
|
|
10
|
+
const path_2 = require("../../utils/path");
|
|
11
|
+
/**
|
|
12
|
+
* Maps configuration entry types to component segments.
|
|
13
|
+
*/
|
|
14
|
+
const mapEntryTypeToSegment = (type) => {
|
|
15
|
+
return {
|
|
16
|
+
js: builder_1.ComponentSegment.JavaScript,
|
|
17
|
+
scss: builder_1.ComponentSegment.Style,
|
|
18
|
+
template: builder_1.ComponentSegment.Previews,
|
|
19
|
+
templates: builder_1.ComponentSegment.Previews,
|
|
20
|
+
component: builder_1.ComponentSegment.Previews,
|
|
21
|
+
story: builder_1.ComponentSegment.Previews,
|
|
22
|
+
}[type];
|
|
23
|
+
};
|
|
24
|
+
exports.mapEntryTypeToSegment = mapEntryTypeToSegment;
|
|
25
|
+
const resolveComponentIdForChangedFile = (handoff, changedFilePath) => {
|
|
26
|
+
var _a, _b, _c, _d;
|
|
27
|
+
const normalizedChangedPath = (0, path_2.normalizePathForCompare)(changedFilePath);
|
|
28
|
+
const runtimeComponents = (_c = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries) === null || _b === void 0 ? void 0 : _b.components) !== null && _c !== void 0 ? _c : {};
|
|
29
|
+
for (const [componentId, componentDef] of Object.entries(runtimeComponents)) {
|
|
30
|
+
const entries = (_d = componentDef.entries) !== null && _d !== void 0 ? _d : {};
|
|
31
|
+
for (const entryPath of Object.values(entries)) {
|
|
32
|
+
if (!entryPath)
|
|
33
|
+
continue;
|
|
34
|
+
const normalizedEntryPath = (0, path_2.normalizePathForCompare)(entryPath);
|
|
35
|
+
if (normalizedEntryPath === normalizedChangedPath) {
|
|
36
|
+
return componentId;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Fallback for legacy path conventions when exact match is unavailable.
|
|
41
|
+
return path_1.default.basename(path_1.default.dirname(changedFilePath));
|
|
42
|
+
};
|
|
43
|
+
exports.resolveComponentIdForChangedFile = resolveComponentIdForChangedFile;
|
|
44
|
+
/**
|
|
45
|
+
* Gets the paths of runtime components to watch.
|
|
46
|
+
*
|
|
47
|
+
* @returns A map of paths to watch and their entry types.
|
|
48
|
+
*/
|
|
49
|
+
const getRuntimeComponentsPathsToWatch = (handoff) => {
|
|
50
|
+
var _a, _b, _c;
|
|
51
|
+
const result = new Map();
|
|
52
|
+
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entries.components) !== null && _b !== void 0 ? _b : {})) {
|
|
53
|
+
const runtimeComponent = handoff.runtimeConfig.entries.components[runtimeComponentId];
|
|
54
|
+
for (const [runtimeComponentEntryType, runtimeComponentEntryPath] of Object.entries((_c = runtimeComponent.entries) !== null && _c !== void 0 ? _c : {})) {
|
|
55
|
+
const normalizedComponentEntryPath = runtimeComponentEntryPath;
|
|
56
|
+
if (fs_extra_1.default.existsSync(normalizedComponentEntryPath)) {
|
|
57
|
+
const entryType = runtimeComponentEntryType;
|
|
58
|
+
if (fs_extra_1.default.statSync(normalizedComponentEntryPath).isFile()) {
|
|
59
|
+
result.set(path_1.default.resolve(normalizedComponentEntryPath), entryType);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
result.set(normalizedComponentEntryPath, entryType);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
exports.getRuntimeComponentsPathsToWatch = getRuntimeComponentsPathsToWatch;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
export interface WatcherState {
|
|
3
|
+
busy: boolean;
|
|
4
|
+
pendingHandlers: Map<string, () => Promise<void>>;
|
|
5
|
+
runtimeComponentsWatcher: chokidar.FSWatcher | null;
|
|
6
|
+
runtimeConfigurationWatcher: chokidar.FSWatcher | null;
|
|
7
|
+
componentDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Schedules a handler for execution with mutual exclusion and per-source
|
|
11
|
+
* coalescing. When the lock is free the handler runs immediately. When busy,
|
|
12
|
+
* only the latest handler per source key is kept.
|
|
13
|
+
*/
|
|
14
|
+
export declare const scheduleHandler: (state: WatcherState, source: string, handler: () => Promise<void>) => Promise<void>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.scheduleHandler = void 0;
|
|
13
|
+
const logger_1 = require("../../utils/logger");
|
|
14
|
+
/**
|
|
15
|
+
* Schedules a handler for execution with mutual exclusion and per-source
|
|
16
|
+
* coalescing. When the lock is free the handler runs immediately. When busy,
|
|
17
|
+
* only the latest handler per source key is kept.
|
|
18
|
+
*/
|
|
19
|
+
const scheduleHandler = (state, source, handler) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
if (state.busy) {
|
|
21
|
+
state.pendingHandlers.set(source, handler);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
state.busy = true;
|
|
25
|
+
try {
|
|
26
|
+
yield handler();
|
|
27
|
+
while (state.pendingHandlers.size > 0) {
|
|
28
|
+
const entries = Array.from(state.pendingHandlers.entries());
|
|
29
|
+
state.pendingHandlers.clear();
|
|
30
|
+
for (const [pendingSource, pendingHandler] of entries) {
|
|
31
|
+
try {
|
|
32
|
+
yield pendingHandler();
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
logger_1.Logger.error(`Unhandled error in scheduled handler for source "${pendingSource}":`, e);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
state.busy = false;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
exports.scheduleHandler = scheduleHandler;
|