@emulsify/core 4.4.0 → 4.5.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.
@@ -18,6 +18,12 @@ import {
18
18
  formatAuditJsonErrorReport,
19
19
  formatAuditJsonReport,
20
20
  } from './audit/report.js';
21
+ import {
22
+ findRenderTwigBindings,
23
+ findTwigTemplateBindings,
24
+ parseStoryModule,
25
+ } from './audit/lib/story-ast.js';
26
+ import { classifyStoryRenderPaths } from './audit/lib/story-render-paths.js';
21
27
  import { lineNumberAt } from './lib/text.js';
22
28
 
23
29
  const STORY_GLOB = '**/*.stories.{js,jsx,ts,tsx}';
@@ -115,13 +121,13 @@ export function findDirectTemplateReturns(source, templateNames = []) {
115
121
  }
116
122
 
117
123
  /**
118
- * Analyze one Storybook story source string.
124
+ * Analyze one Storybook story with the legacy regex implementation.
119
125
  *
120
126
  * @param {string} source - Story source.
121
- * @param {string} [filePath=''] - Story file path.
127
+ * @param {string} filePath - Story file path.
122
128
  * @returns {object} Story analysis.
123
129
  */
124
- export function analyzeStorySource(source, filePath = '') {
130
+ function analyzeStorySourceWithRegex(source, filePath) {
125
131
  const twigImports = findTwigImports(source);
126
132
  const templateNames = twigImports.map((item) => item.name);
127
133
  const hasRenderTwig = importsRenderTwig(source);
@@ -160,6 +166,70 @@ export function analyzeStorySource(source, filePath = '') {
160
166
  };
161
167
  }
162
168
 
169
+ /**
170
+ * Analyze one Storybook story source string.
171
+ *
172
+ * @param {string} source - Story source.
173
+ * @param {string} [filePath=''] - Story file path.
174
+ * @returns {object} Story analysis.
175
+ */
176
+ export function analyzeStorySource(source, filePath = '') {
177
+ const parsed = parseStoryModule(source, filePath);
178
+ if (!parsed) return analyzeStorySourceWithRegex(source, filePath);
179
+
180
+ const twigImports = findTwigTemplateBindings(parsed.ast);
181
+ const renderTwigNames = findRenderTwigBindings(parsed.ast);
182
+ const hasRenderTwig = renderTwigNames.size > 0;
183
+ const reasons = [];
184
+
185
+ if (!twigImports.length) {
186
+ return {
187
+ filePath,
188
+ twigImports,
189
+ hasRenderTwig,
190
+ directTemplateReturns: [],
191
+ reasons,
192
+ shouldUpgrade: false,
193
+ };
194
+ }
195
+
196
+ const classification = classifyStoryRenderPaths(parsed.ast, {
197
+ templateNames: twigImports.map((item) => item.name),
198
+ renderTwigNames,
199
+ });
200
+ const fallbackLine = Number.isInteger(twigImports[0]?.line)
201
+ ? twigImports[0].line
202
+ : 1;
203
+ const directTemplateReturns = classification.legacy.map((item) => ({
204
+ name: item.name || twigImports[0].name,
205
+ line: Number.isInteger(item.line) ? item.line : fallbackLine,
206
+ }));
207
+
208
+ if (!hasRenderTwig && classification.legacy.length) {
209
+ reasons.push('imports Twig templates without renderTwig()');
210
+ }
211
+
212
+ if (classification.legacy.length) {
213
+ reasons.push('appears to return Twig HTML strings directly');
214
+ }
215
+
216
+ if (reasons.length && !directTemplateReturns.length) {
217
+ directTemplateReturns.push({
218
+ name: twigImports[0].name,
219
+ line: fallbackLine,
220
+ });
221
+ }
222
+
223
+ return {
224
+ filePath,
225
+ twigImports,
226
+ hasRenderTwig,
227
+ directTemplateReturns,
228
+ reasons,
229
+ shouldUpgrade: reasons.length > 0,
230
+ };
231
+ }
232
+
163
233
  /**
164
234
  * Resolve Storybook source roots for the project.
165
235
  *