@emulsify/core 4.2.0 → 4.3.0

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 (79) hide show
  1. package/.storybook/main-vite.js +91 -36
  2. package/README.md +185 -56
  3. package/config/a11y.config.js +2 -1
  4. package/config/vite/entries.js +4 -4
  5. package/config/vite/plugins/{copy-src-assets.js → assets/copy-src-assets.js} +1 -1
  6. package/config/vite/plugins/{copy-twig-files.js → assets/copy-twig-files.js} +1 -1
  7. package/config/vite/plugins/{css-asset-relativizer.js → assets/css-asset-relativizer.js} +9 -0
  8. package/config/vite/plugins/{mirror-components.js → assets/mirror-components.js} +2 -28
  9. package/config/vite/plugins/{source-file-index.js → assets/source-file-index.js} +1 -1
  10. package/config/vite/plugins/{svg-sprite.js → assets/svg-sprite.js} +2 -2
  11. package/config/vite/plugins/index.js +23 -14
  12. package/config/vite/plugins/reporter/asset-resolver.js +541 -0
  13. package/config/vite/plugins/reporter/build-errors.js +284 -0
  14. package/config/vite/plugins/reporter/diagnostics.js +366 -0
  15. package/config/vite/plugins/reporter/format.js +199 -0
  16. package/config/vite/plugins/reporter/index.js +308 -0
  17. package/config/vite/plugins/reporter/render.js +758 -0
  18. package/config/vite/plugins/reporter/sass-logger.js +237 -0
  19. package/config/vite/plugins/reporter/vite-logger.js +188 -0
  20. package/config/vite/plugins/reporter/watch-mode.js +40 -0
  21. package/config/vite/plugins/{twig-extension-installers.js → twig/extension-installers.js} +1 -1
  22. package/config/vite/{twig-extensions.js → plugins/twig/extensions.js} +2 -2
  23. package/config/vite/plugins/{twig-module.js → twig/twig-module.js} +387 -115
  24. package/config/vite/plugins/{virtual-twig-asset-sources.js → twig/virtual-twig-asset-sources.js} +37 -136
  25. package/config/vite/plugins/{virtual-twig-globs.js → twig/virtual-twig-globs.js} +3 -32
  26. package/config/vite/plugins/{vituum-patch.js → twig/vituum-patch.js} +3 -3
  27. package/config/vite/plugins.js +1 -1
  28. package/config/vite/project-config.js +1 -1
  29. package/config/vite/project-structure.js +1 -1
  30. package/config/vite/utils/lru.js +77 -0
  31. package/config/vite/utils/package-version.js +42 -0
  32. package/config/vite/utils/paths.js +1 -9
  33. package/config/vite/utils/react-singleton.js +1 -1
  34. package/config/vite/vite.config.js +51 -5
  35. package/package.json +93 -58
  36. package/scripts/a11y.js +115 -23
  37. package/scripts/audit/checks/core-imports.js +78 -0
  38. package/scripts/audit/checks/css-asset-references.js +99 -0
  39. package/scripts/audit/checks/drupal-assumptions.js +48 -0
  40. package/scripts/audit/checks/files-outside-roots.js +53 -0
  41. package/scripts/audit/checks/generated-package-scripts.js +113 -0
  42. package/scripts/audit/checks/legacy-twig-stories.js +33 -0
  43. package/scripts/audit/checks/package-overrides.js +91 -0
  44. package/scripts/audit/checks/project-config.js +71 -0
  45. package/scripts/audit/checks/story-discovery.js +35 -0
  46. package/scripts/audit/checks/twig-references.js +69 -0
  47. package/scripts/audit/checks/twig-volume.js +54 -0
  48. package/scripts/audit/checks/webpack-patterns.js +86 -0
  49. package/scripts/audit/index.js +177 -0
  50. package/scripts/audit/lib/css.js +165 -0
  51. package/scripts/audit/lib/files.js +168 -0
  52. package/scripts/audit/lib/findings.js +31 -0
  53. package/scripts/audit/lib/package-json.js +65 -0
  54. package/scripts/audit/lib/twig.js +227 -0
  55. package/scripts/audit/report.js +273 -0
  56. package/scripts/audit-twig-stories.js +115 -78
  57. package/scripts/audit.js +150 -1632
  58. package/scripts/check-node-version.js +136 -10
  59. package/scripts/inspect-components.js +456 -0
  60. package/scripts/lib/cli.js +179 -0
  61. package/scripts/lib/fs.js +31 -0
  62. package/scripts/lib/proc.js +78 -0
  63. package/scripts/lib/text.js +14 -0
  64. package/scripts/loadYaml.js +2 -2
  65. package/src/extensions/shared/attributes.js +3 -3
  66. package/src/extensions/shared/lists.js +2 -6
  67. package/src/extensions/shared/root-relative.js +38 -0
  68. package/src/storybook/index.js +4 -0
  69. package/src/storybook/render-twig.js +1 -1
  70. package/src/storybook/render-web-component.js +459 -0
  71. package/src/storybook/twig/asset-source-runtime.js +193 -0
  72. package/src/storybook/twig/{source-extensions.js → constants.js} +3 -1
  73. package/src/storybook/twig/reference-paths.js +2 -13
  74. package/src/storybook/twig/resolver.js +20 -3
  75. package/src/storybook/twig/setup.js +12 -2
  76. package/src/storybook/twig/source-function.js +5 -2
  77. package/config/vite/utils/unique.js +0 -36
  78. package/src/storybook/twig/include.js +0 -28
  79. package/src/storybook/twig/source-events.js +0 -5
@@ -0,0 +1,237 @@
1
+ /**
2
+ * @file Sass logger that feeds the Emulsify develop reporter.
3
+ *
4
+ * Dart Sass prints a fully formatted warning — message, source excerpt, caret,
5
+ * and import chain — for every deprecation it encounters, every time it
6
+ * encounters it. A project with a handful of legacy `$space/2` divisions in a
7
+ * shared partial can emit several hundred lines per build, because each entry
8
+ * that imports the partial re-triggers the same warning.
9
+ *
10
+ * Supplying a custom logger replaces that output entirely. Rather than calling
11
+ * `silenceDeprecations`, which hides the warnings and the fact that they exist,
12
+ * this logger routes each report into the shared diagnostics collector so the
13
+ * reporter can print one deduplicated summary with a migration hint. The debt
14
+ * stays visible; only the repetition goes away.
15
+ *
16
+ * @see https://sass-lang.com/documentation/js-api/interfaces/logger/
17
+ */
18
+
19
+ import { fileURLToPath } from 'node:url';
20
+
21
+ /**
22
+ * What each Sass deprecation means and how to resolve it.
23
+ *
24
+ * `fix` is the substitution to make, written as `before → after` so the row
25
+ * reads as an instruction rather than an identifier. A deprecation ID like
26
+ * `slash-div` tells a themer nothing on its own; `$a/$b → math.div($a, $b)`
27
+ * tells them exactly what to type.
28
+ *
29
+ * `migrator` names the `sass-migrator` migration that rewrites the code
30
+ * automatically, and is omitted for deprecations that have to be fixed by hand.
31
+ * The migrator only ships five migrations, so most IDs here have no entry.
32
+ *
33
+ * @type {Record<string, {fix: string, migrator?: string}>}
34
+ * @see https://sass-lang.com/documentation/cli/migrator/
35
+ */
36
+ export const DEPRECATION_GUIDE = {
37
+ 'slash-div': {
38
+ fix: '$a/$b → math.div($a, $b)',
39
+ migrator: 'division',
40
+ },
41
+ 'global-builtin': {
42
+ fix: 'map-get() → map.get()',
43
+ migrator: 'module',
44
+ },
45
+ import: {
46
+ fix: '@import → @use',
47
+ migrator: 'module',
48
+ },
49
+ 'color-functions': {
50
+ fix: 'lighten()/darken() → color.adjust()',
51
+ migrator: 'color',
52
+ },
53
+ 'if-function': {
54
+ fix: 'if() → CSS if()',
55
+ migrator: 'if',
56
+ },
57
+ 'color-4-api': { fix: 'color.red($c) → color.channel($c, "red")' },
58
+ 'legacy-js-api': { fix: 'render() → compile()' },
59
+ 'mixed-decls': { fix: 'move declarations above nested rules' },
60
+ 'strict-unary': { fix: '$a -$b → $a - $b' },
61
+ 'abs-percent': { fix: 'abs(10%) → math.abs(10%)' },
62
+ 'duplicate-var-flags': { fix: 'remove the repeated !default or !global' },
63
+ 'null-alpha': { fix: 'rgb($c, null) → rgb($c)' },
64
+ 'feature-exists': { fix: 'remove meta.feature-exists()' },
65
+ 'moz-document': { fix: 'remove @-moz-document' },
66
+ 'bogus-combinators': { fix: 'remove the dangling combinator' },
67
+ elseif: { fix: '@elseif → @else if' },
68
+ 'call-string': { fix: 'call($name) → call(get-function($name))' },
69
+ 'new-global': { fix: 'declare the variable before assigning it !global' },
70
+ };
71
+
72
+ /**
73
+ * Look up the human-readable fix for a deprecation ID.
74
+ *
75
+ * @param {string} id - Sass deprecation ID.
76
+ * @returns {string|undefined} Fix instruction, when one is known.
77
+ */
78
+ export function deprecationFix(id) {
79
+ return DEPRECATION_GUIDE[id]?.fix;
80
+ }
81
+
82
+ /**
83
+ * Look up the `sass-migrator` migration that resolves a deprecation ID.
84
+ *
85
+ * @param {string} id - Sass deprecation ID.
86
+ * @returns {string|undefined} Migration name, when one exists.
87
+ */
88
+ export function deprecationMigrator(id) {
89
+ return DEPRECATION_GUIDE[id]?.migrator;
90
+ }
91
+
92
+ /**
93
+ * Convert a Sass span URL into a readable filesystem path.
94
+ *
95
+ * Spans carry a `URL` for on-disk stylesheets, but string URLs and custom
96
+ * importer schemes both appear in practice, so every branch is guarded.
97
+ *
98
+ * @param {URL|string|undefined} url - Span URL.
99
+ * @returns {string|undefined} Filesystem path, or undefined when unavailable.
100
+ */
101
+ export function spanUrlToPath(url) {
102
+ if (!url) return undefined;
103
+
104
+ const href = typeof url === 'string' ? url : url.href;
105
+ if (!href) return undefined;
106
+ if (!href.startsWith('file:')) return href;
107
+
108
+ try {
109
+ return fileURLToPath(href);
110
+ } catch {
111
+ return href;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Read the 1-based line number from a Sass span.
117
+ *
118
+ * Sass reports zero-based line numbers; editors and the rest of the Emulsify
119
+ * tooling are one-based.
120
+ *
121
+ * @param {{start?: {line?: number}}|undefined} span - Sass source span.
122
+ * @returns {number|undefined} 1-based line number, when available.
123
+ */
124
+ export function spanLineNumber(span) {
125
+ const line = span?.start?.line;
126
+ return typeof line === 'number' ? line + 1 : undefined;
127
+ }
128
+
129
+ /**
130
+ * Reduce a multi-line Sass message to its first meaningful line.
131
+ *
132
+ * @param {string|undefined} message - Raw Sass message.
133
+ * @returns {string|undefined} Condensed message.
134
+ */
135
+ export function condenseMessage(message) {
136
+ if (typeof message !== 'string') return undefined;
137
+ const [firstLine] = message.split('\n');
138
+ return firstLine?.trim() || undefined;
139
+ }
140
+
141
+ /**
142
+ * Detect Dart Sass's own truncation notice.
143
+ *
144
+ * Without `verbose`, Sass prints at most five instances of each deprecation and
145
+ * then emits `"N repetitive deprecation warnings omitted."` as a warning with no
146
+ * span attached. That notice is not a problem in the stylesheet — it is Sass
147
+ * reporting that it hid some. Recording it would put a locationless row in the
148
+ * summary and, worse, imply the reporter's totals are complete when they are
149
+ * short by exactly the number Sass suppressed.
150
+ *
151
+ * {@link createSassOptions} sets `verbose` so the notice should never appear,
152
+ * but a project that overrides `preprocessorOptions` could reintroduce it.
153
+ *
154
+ * @param {string|undefined} message - Raw Sass message.
155
+ * @returns {boolean} TRUE when the message is a truncation notice.
156
+ */
157
+ export function isRepetitionNotice(message) {
158
+ if (typeof message !== 'string') return false;
159
+ return /^\s*\d+\s+repetitive\s+deprecation\s+warnings?\s+omitted\b/i.test(
160
+ message,
161
+ );
162
+ }
163
+
164
+ /**
165
+ * Create a Sass logger that records into a diagnostics collector.
166
+ *
167
+ * @param {ReturnType<import('./diagnostics.js').createDiagnosticsCollector>} collector - Shared collector.
168
+ * @param {{passthrough?: (message: string, options: object) => void}} [options] - Logger options.
169
+ * @returns {{warn: Function, debug: Function}} Sass logger.
170
+ */
171
+ export function createSassLogger(collector, { passthrough } = {}) {
172
+ return {
173
+ /**
174
+ * Record a Sass warning instead of printing it.
175
+ *
176
+ * @param {string} message - Warning message.
177
+ * @param {object} [options] - Sass warning metadata.
178
+ * @returns {void}
179
+ */
180
+ warn(message, options = {}) {
181
+ // Sass counting its own suppressed warnings is not a finding to report.
182
+ if (isRepetitionNotice(message)) return;
183
+
184
+ const file = spanUrlToPath(options.span?.url);
185
+ const line = spanLineNumber(options.span);
186
+
187
+ if (options.deprecation) {
188
+ collector.recordDeprecation({
189
+ id: options.deprecationType?.id,
190
+ file,
191
+ line,
192
+ });
193
+ } else {
194
+ collector.recordWarning({
195
+ message: condenseMessage(message),
196
+ file,
197
+ line,
198
+ });
199
+ }
200
+
201
+ // Projects that want the original firehose back can opt in per build.
202
+ if (typeof passthrough === 'function') {
203
+ passthrough(message, options);
204
+ }
205
+ },
206
+
207
+ /**
208
+ * Discard Sass debug output.
209
+ *
210
+ * `@debug` is a authoring aid and has no place in the develop summary.
211
+ *
212
+ * @returns {void}
213
+ */
214
+ debug() {},
215
+ };
216
+ }
217
+
218
+ /**
219
+ * Build the Sass preprocessor options used by the develop watcher.
220
+ *
221
+ * `verbose` and the custom logger have to travel together. Dart Sass caps each
222
+ * deprecation at five reported instances by default, so a reporter that counts
223
+ * what the logger receives would silently undercount — a project with 135 real
224
+ * occurrences would be told it had 85. Turning `verbose` on hands every
225
+ * occurrence to the logger, which then deduplicates them properly. The console
226
+ * stays quiet either way, because the logger prints nothing.
227
+ *
228
+ * @param {ReturnType<import('./diagnostics.js').createDiagnosticsCollector>} collector - Shared collector.
229
+ * @param {{passthrough?: (message: string, options: object) => void}} [options] - Logger options.
230
+ * @returns {{logger: {warn: Function, debug: Function}, verbose: boolean}} Sass options.
231
+ */
232
+ export function createSassOptions(collector, options = {}) {
233
+ return {
234
+ logger: createSassLogger(collector, options),
235
+ verbose: true,
236
+ };
237
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * @file Vite logger wrapper for the Emulsify develop reporter.
3
+ *
4
+ * Sass warnings reach the reporter through a Sass logger, but Vite emits its
5
+ * own diagnostics through `config.logger`. The most common of those in an
6
+ * Emulsify project is the unresolved CSS asset notice:
7
+ *
8
+ * ../images/bg-lines.png referenced in ../images/bg-lines.png didn't resolve
9
+ * at build time, it will remain unchanged to be resolved at runtime
10
+ *
11
+ * Vite emits one per `url()` it cannot resolve, mid-build, so they land
12
+ * interleaved with transform progress and Storybook's startup. The wording is
13
+ * also unhelpful: the "referenced in" file is frequently identical to the URL
14
+ * itself, and nothing in the sentence says whether this is a problem.
15
+ *
16
+ * This wrapper intercepts those and routes them into the shared diagnostics
17
+ * collector so they surface once, grouped, in the build summary. Every other
18
+ * message passes straight through to Vite's own logger untouched.
19
+ */
20
+
21
+ /**
22
+ * Matches Vite's unresolved CSS asset notice.
23
+ *
24
+ * @type {RegExp}
25
+ * @see https://github.com/vitejs/vite - `vite:css` url replacer
26
+ */
27
+ const UNRESOLVED_ASSET_PATTERN =
28
+ /^(.+?) referenced in (.+?) didn't resolve at build time/;
29
+
30
+ /**
31
+ * Remove ANSI escape sequences so pattern matching sees plain text.
32
+ *
33
+ * @param {string} value - Possibly styled text.
34
+ * @returns {string} Plain text.
35
+ */
36
+ const stripAnsi = (value) =>
37
+ // eslint-disable-next-line no-control-regex
38
+ String(value).replace(/\[[0-9;]*m/g, '');
39
+
40
+ /**
41
+ * Matches Rolldown's raw failure dump.
42
+ *
43
+ * The dump repeats every error up to three times — message, cause, and stack —
44
+ * and appends a Dart Sass JS trace that points into `sass.dart.js` rather than
45
+ * anywhere in the project.
46
+ *
47
+ * @type {RegExp}
48
+ */
49
+ const RAW_BUILD_DUMP =
50
+ /^\s*(?:Build failed with \d+ error|\[plugin [\w:-]+\]|Error: \[sass\]|\[sass\] )/;
51
+
52
+ /**
53
+ * Matches a Dart Sass JS stack frame.
54
+ *
55
+ * These point into the compiler bundle rather than the project and are noise
56
+ * wherever they appear, so their presence alone identifies a raw dump.
57
+ *
58
+ * @type {RegExp}
59
+ */
60
+ const DART_SASS_FRAME = /\bsass\.dart\.js:\d+/;
61
+
62
+ /**
63
+ * Detect a message that is nothing but JavaScript stack frames.
64
+ *
65
+ * Rolldown emits the trailing stack of a failure as its own log call. Those
66
+ * frames point into `lightningcss`, `vite`, or `sass` internals rather than
67
+ * anywhere in the project, so a message made only of them carries nothing once
68
+ * the failure itself has been reported.
69
+ *
70
+ * @param {string} message - Plain-text log message.
71
+ * @returns {boolean} TRUE when every line is a stack frame.
72
+ */
73
+ function isBareStackTrace(message) {
74
+ const lines = message.split('\n').filter((line) => line.trim());
75
+
76
+ return lines.length > 0 && lines.every((line) => /^\s*at\s+\S/.test(line));
77
+ }
78
+
79
+ /**
80
+ * Determine whether the reporter should stand aside and let Vite speak.
81
+ *
82
+ * @param {object} [env] - Environment variables.
83
+ * @returns {boolean} TRUE when raw output should pass through.
84
+ */
85
+ export function isVerbose(env = process.env) {
86
+ return Boolean(env.EMULSIFY_VERBOSE) && env.EMULSIFY_VERBOSE !== '0';
87
+ }
88
+
89
+ /**
90
+ * Parse Vite's unresolved CSS asset notice.
91
+ *
92
+ * @param {string} message - Raw log message.
93
+ * @returns {{url: string, importer: string|undefined}|undefined} Parsed notice.
94
+ */
95
+ export function parseUnresolvedAsset(message) {
96
+ if (typeof message !== 'string') return undefined;
97
+
98
+ const match = UNRESOLVED_ASSET_PATTERN.exec(stripAnsi(message).trim());
99
+ if (!match) return undefined;
100
+
101
+ const [, url, importer] = match;
102
+
103
+ return {
104
+ url,
105
+ // Vite reports the URL as its own importer when the referencing stylesheet
106
+ // is not known. Recording that adds nothing, so it is dropped.
107
+ importer: importer === url ? undefined : importer,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Wrap a Vite logger so reportable diagnostics are collected instead of printed.
113
+ *
114
+ * The wrapper delegates rather than spreading, because `hasWarned` is a mutable
115
+ * property that Vite reads back after logging; a spread copy would freeze it.
116
+ *
117
+ * @param {ReturnType<import('./diagnostics.js').createDiagnosticsCollector>} collector - Shared collector.
118
+ * @param {import('vite').Logger} baseLogger - Logger to delegate to.
119
+ * @returns {import('vite').Logger} Wrapped logger.
120
+ */
121
+ export function createReporterLogger(collector, baseLogger, { verbose } = {}) {
122
+ const passRawThrough = verbose === undefined ? isVerbose() : verbose;
123
+
124
+ /**
125
+ * Record a message if it is one the reporter owns.
126
+ *
127
+ * @param {string} message - Raw log message.
128
+ * @returns {boolean} TRUE when the message was captured.
129
+ */
130
+ const capture = (message) => {
131
+ const unresolvedAsset = parseUnresolvedAsset(message);
132
+ if (!unresolvedAsset) return false;
133
+
134
+ collector.recordUnresolvedAsset(unresolvedAsset);
135
+ return true;
136
+ };
137
+
138
+ /**
139
+ * Determine whether a failure dump has already been reported in table form.
140
+ *
141
+ * Output is only ever dropped once the reporter holds the same information
142
+ * in a readable shape; an error it failed to parse still reaches the user.
143
+ *
144
+ * @param {string} message - Raw log message.
145
+ * @returns {boolean} TRUE when the dump is redundant.
146
+ */
147
+ const isRedundantDump = (message) => {
148
+ if (passRawThrough) return false;
149
+ if (!collector.hasCapturedBuildErrors?.()) return false;
150
+
151
+ const plain = stripAnsi(String(message));
152
+
153
+ return (
154
+ RAW_BUILD_DUMP.test(plain) ||
155
+ DART_SASS_FRAME.test(plain) ||
156
+ isBareStackTrace(plain)
157
+ );
158
+ };
159
+
160
+ return {
161
+ get hasWarned() {
162
+ return baseLogger.hasWarned;
163
+ },
164
+
165
+ set hasWarned(value) {
166
+ baseLogger.hasWarned = value;
167
+ },
168
+
169
+ info: (message, options) => baseLogger.info(message, options),
170
+
171
+ warn(message, options) {
172
+ if (!capture(message)) baseLogger.warn(message, options);
173
+ },
174
+
175
+ warnOnce(message, options) {
176
+ if (!capture(message)) baseLogger.warnOnce(message, options);
177
+ },
178
+
179
+ error(message, options) {
180
+ if (isRedundantDump(message)) return;
181
+ baseLogger.error(message, options);
182
+ },
183
+
184
+ clearScreen: (type) => baseLogger.clearScreen(type),
185
+
186
+ hasErrorLogged: (error) => baseLogger.hasErrorLogged(error),
187
+ };
188
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file Watch-invocation detection for the Emulsify develop reporter.
3
+ *
4
+ * The reporter and its quiet Sass logger should only take over output for the
5
+ * long-running watcher that `npm run develop` starts. Every other command that
6
+ * loads this Vite config — `npm run build`, `storybook build`, `storybook dev`,
7
+ * and the release fixture verifications — must keep its current output exactly
8
+ * as it is today.
9
+ *
10
+ * Vite resolves `command: 'build'` for both `vite build` and
11
+ * `vite build --watch`, so the resolved config cannot distinguish them at the
12
+ * point where `css.preprocessorOptions` has to be decided. The CLI flag is the
13
+ * only signal available that early, so it is read directly. The plugin
14
+ * independently confirms the decision against `config.build.watch` once the
15
+ * config is resolved, which covers projects that enable watch mode through
16
+ * their own config patch rather than the flag.
17
+ */
18
+
19
+ /**
20
+ * Flags that put the Vite CLI into watch mode.
21
+ *
22
+ * @type {string[]}
23
+ */
24
+ const WATCH_FLAGS = ['--watch', '-w'];
25
+
26
+ /**
27
+ * Determine whether the current process was invoked as a Vite watch build.
28
+ *
29
+ * @param {string[]} [argv] - Process arguments.
30
+ * @returns {boolean} TRUE when a watch flag is present.
31
+ */
32
+ export function isWatchInvocation(argv = process.argv) {
33
+ if (!Array.isArray(argv)) return false;
34
+
35
+ return argv.some(
36
+ (arg) =>
37
+ WATCH_FLAGS.includes(arg) ||
38
+ WATCH_FLAGS.some((flag) => arg.startsWith(`${flag}=`)),
39
+ );
40
+ }
@@ -2,7 +2,7 @@
2
2
  * @file Virtual Twig.js extension installer module for Storybook.
3
3
  */
4
4
 
5
- import { generateTwigExtensionInstallersModule } from '../twig-extensions.js';
5
+ import { generateTwigExtensionInstallersModule } from './extensions.js';
6
6
 
7
7
  export const VIRTUAL_TWIG_EXTENSION_INSTALLERS_ID =
8
8
  'virtual:emulsify-twig-extension-installers';
@@ -60,7 +60,7 @@ function normalizeInstaller(moduleValue) {
60
60
  * @param {object} [env={}] - Normalized Emulsify environment or Twig options.
61
61
  * @returns {object} The provided Twig.js instance.
62
62
  */
63
- export function registerConfiguredTwigExtensions(twig, env = {}) {
63
+ export function installProjectTwigExtensions(twig, env = {}) {
64
64
  if (shouldRegisterDrupalTwigFilters(env)) {
65
65
  const installer = normalizeInstaller(require('twig-drupal-filters'));
66
66
  if (installer) {
@@ -98,7 +98,7 @@ const installers = [${installerNames}].filter(
98
98
 
99
99
  export const twigExtensionInstallers = installers;
100
100
 
101
- export function registerConfiguredTwigExtensions(Twig) {
101
+ export function installProjectTwigExtensions(Twig) {
102
102
  for (const installer of installers) {
103
103
  installer(Twig);
104
104
  }