@emulsify/core 4.2.1 → 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.
- package/.storybook/main-vite.js +91 -36
- package/README.md +185 -56
- package/config/a11y.config.js +2 -1
- package/config/vite/entries.js +4 -4
- package/config/vite/plugins/{copy-src-assets.js → assets/copy-src-assets.js} +1 -1
- package/config/vite/plugins/{copy-twig-files.js → assets/copy-twig-files.js} +1 -1
- package/config/vite/plugins/{css-asset-relativizer.js → assets/css-asset-relativizer.js} +9 -0
- package/config/vite/plugins/{mirror-components.js → assets/mirror-components.js} +2 -28
- package/config/vite/plugins/{source-file-index.js → assets/source-file-index.js} +1 -1
- package/config/vite/plugins/{svg-sprite.js → assets/svg-sprite.js} +2 -2
- package/config/vite/plugins/index.js +23 -14
- package/config/vite/plugins/reporter/asset-resolver.js +541 -0
- package/config/vite/plugins/reporter/build-errors.js +284 -0
- package/config/vite/plugins/reporter/diagnostics.js +366 -0
- package/config/vite/plugins/reporter/format.js +199 -0
- package/config/vite/plugins/reporter/index.js +308 -0
- package/config/vite/plugins/reporter/render.js +758 -0
- package/config/vite/plugins/reporter/sass-logger.js +237 -0
- package/config/vite/plugins/reporter/vite-logger.js +188 -0
- package/config/vite/plugins/reporter/watch-mode.js +40 -0
- package/config/vite/plugins/{twig-extension-installers.js → twig/extension-installers.js} +1 -1
- package/config/vite/{twig-extensions.js → plugins/twig/extensions.js} +2 -2
- package/config/vite/plugins/{twig-module.js → twig/twig-module.js} +197 -85
- package/config/vite/plugins/{virtual-twig-asset-sources.js → twig/virtual-twig-asset-sources.js} +37 -136
- package/config/vite/plugins/{virtual-twig-globs.js → twig/virtual-twig-globs.js} +3 -32
- package/config/vite/plugins/{vituum-patch.js → twig/vituum-patch.js} +3 -3
- package/config/vite/plugins.js +1 -1
- package/config/vite/project-config.js +1 -1
- package/config/vite/project-structure.js +1 -1
- package/config/vite/utils/lru.js +77 -0
- package/config/vite/utils/package-version.js +42 -0
- package/config/vite/utils/paths.js +1 -9
- package/config/vite/utils/react-singleton.js +1 -1
- package/config/vite/vite.config.js +51 -5
- package/package.json +93 -58
- package/scripts/a11y.js +115 -23
- package/scripts/audit/checks/core-imports.js +78 -0
- package/scripts/audit/checks/css-asset-references.js +99 -0
- package/scripts/audit/checks/drupal-assumptions.js +48 -0
- package/scripts/audit/checks/files-outside-roots.js +53 -0
- package/scripts/audit/checks/generated-package-scripts.js +113 -0
- package/scripts/audit/checks/legacy-twig-stories.js +33 -0
- package/scripts/audit/checks/package-overrides.js +91 -0
- package/scripts/audit/checks/project-config.js +71 -0
- package/scripts/audit/checks/story-discovery.js +35 -0
- package/scripts/audit/checks/twig-references.js +69 -0
- package/scripts/audit/checks/twig-volume.js +54 -0
- package/scripts/audit/checks/webpack-patterns.js +86 -0
- package/scripts/audit/index.js +177 -0
- package/scripts/audit/lib/css.js +165 -0
- package/scripts/audit/lib/files.js +168 -0
- package/scripts/audit/lib/findings.js +31 -0
- package/scripts/audit/lib/package-json.js +65 -0
- package/scripts/audit/lib/twig.js +227 -0
- package/scripts/audit/report.js +273 -0
- package/scripts/audit-twig-stories.js +115 -78
- package/scripts/audit.js +150 -1632
- package/scripts/check-node-version.js +136 -10
- package/scripts/inspect-components.js +456 -0
- package/scripts/lib/cli.js +179 -0
- package/scripts/lib/fs.js +31 -0
- package/scripts/lib/proc.js +78 -0
- package/scripts/lib/text.js +14 -0
- package/scripts/loadYaml.js +2 -2
- package/src/extensions/shared/attributes.js +3 -3
- package/src/extensions/shared/lists.js +2 -6
- package/src/extensions/shared/root-relative.js +38 -0
- package/src/storybook/index.js +4 -0
- package/src/storybook/render-twig.js +1 -1
- package/src/storybook/render-web-component.js +459 -0
- package/src/storybook/twig/asset-source-runtime.js +193 -0
- package/src/storybook/twig/{source-extensions.js → constants.js} +3 -1
- package/src/storybook/twig/reference-paths.js +2 -13
- package/src/storybook/twig/setup.js +12 -2
- package/src/storybook/twig/source-function.js +5 -2
- package/config/vite/utils/unique.js +0 -36
- package/src/storybook/twig/include.js +0 -28
- package/src/storybook/twig/source-events.js +0 -5
|
@@ -9,9 +9,22 @@ import { relative, resolve } from 'node:path';
|
|
|
9
9
|
import { globSync } from 'glob';
|
|
10
10
|
import { resolveProjectConfig } from '../config/vite/project-config.js';
|
|
11
11
|
import { toPosixPath } from '../config/vite/utils/paths.js';
|
|
12
|
+
import {
|
|
13
|
+
createUsage,
|
|
14
|
+
isCliEntrypoint,
|
|
15
|
+
parseArgs as parseCliArgs,
|
|
16
|
+
} from './lib/cli.js';
|
|
17
|
+
import {
|
|
18
|
+
formatAuditJsonErrorReport,
|
|
19
|
+
formatAuditJsonReport,
|
|
20
|
+
} from './audit/report.js';
|
|
21
|
+
import { lineNumberAt } from './lib/text.js';
|
|
12
22
|
|
|
13
23
|
const STORY_GLOB = '**/*.stories.{js,jsx,ts,tsx}';
|
|
14
24
|
const IDENTIFIER_PATTERN = '[A-Za-z_$][\\w$]*';
|
|
25
|
+
const LEGACY_TWIG_STORY_DOCS =
|
|
26
|
+
'https://github.com/emulsify-ds/emulsify-core/blob/4.x/docs/storybook.md#legacy-twig-story-compatibility';
|
|
27
|
+
const cliFailureExitCode = 2;
|
|
15
28
|
const DEFAULT_IGNORES = [
|
|
16
29
|
'**/node_modules/**',
|
|
17
30
|
'**/dist/**',
|
|
@@ -29,17 +42,6 @@ function escapeRegExp(value) {
|
|
|
29
42
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
30
43
|
}
|
|
31
44
|
|
|
32
|
-
/**
|
|
33
|
-
* Find the 1-based line number for a character index.
|
|
34
|
-
*
|
|
35
|
-
* @param {string} source - File source.
|
|
36
|
-
* @param {number} index - Character index.
|
|
37
|
-
* @returns {number} 1-based line number.
|
|
38
|
-
*/
|
|
39
|
-
function lineNumberAt(source, index) {
|
|
40
|
-
return source.slice(0, index).split('\n').length;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
45
|
/**
|
|
44
46
|
* Find imported Twig template identifiers.
|
|
45
47
|
*
|
|
@@ -226,6 +228,35 @@ export function auditTwigStories(options = {}) {
|
|
|
226
228
|
};
|
|
227
229
|
}
|
|
228
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Adapt the focused Twig analysis to the shared machine-readable contract.
|
|
233
|
+
*
|
|
234
|
+
* @param {{projectDir: string, files: string[], findings: object[]}} result
|
|
235
|
+
* Twig story audit result.
|
|
236
|
+
* @returns {object} Combined audit-compatible result.
|
|
237
|
+
*/
|
|
238
|
+
function createJsonAuditResult(result) {
|
|
239
|
+
return {
|
|
240
|
+
projectDir: result.projectDir,
|
|
241
|
+
files: {
|
|
242
|
+
stories: result.files.length,
|
|
243
|
+
twig: 0,
|
|
244
|
+
code: result.files.length,
|
|
245
|
+
styles: 0,
|
|
246
|
+
},
|
|
247
|
+
findings: result.findings.map((finding) => ({
|
|
248
|
+
id: 'legacy-twig-story',
|
|
249
|
+
severity: 'warn',
|
|
250
|
+
filePath: finding.filePath,
|
|
251
|
+
line: finding.directTemplateReturns[0]?.line,
|
|
252
|
+
message:
|
|
253
|
+
'Twig story appears to return an HTML string directly. This remains compatible, but renderTwig() is preferred for active migrations.',
|
|
254
|
+
details: finding.reasons,
|
|
255
|
+
docs: LEGACY_TWIG_STORY_DOCS,
|
|
256
|
+
})),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
229
260
|
/**
|
|
230
261
|
* Format audit findings for terminal output.
|
|
231
262
|
*
|
|
@@ -280,46 +311,24 @@ export function formatAuditReport(result) {
|
|
|
280
311
|
* Parsed options.
|
|
281
312
|
*/
|
|
282
313
|
function parseArgs(argv) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (arg === '--json') {
|
|
302
|
-
options.json = true;
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
if (arg === '--root') {
|
|
306
|
-
const value = argv[index + 1];
|
|
307
|
-
if (!value || value.startsWith('--')) {
|
|
308
|
-
throw new Error('--root requires a project directory.');
|
|
309
|
-
}
|
|
310
|
-
options.projectDir = value;
|
|
311
|
-
index += 1;
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if (arg.startsWith('--root=')) {
|
|
315
|
-
options.projectDir = arg.slice('--root='.length);
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
throw new Error(`Unknown option: ${arg}`);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return options;
|
|
314
|
+
return parseCliArgs(argv, {
|
|
315
|
+
defaults: {
|
|
316
|
+
projectDir: process.cwd(),
|
|
317
|
+
failOnFound: false,
|
|
318
|
+
json: false,
|
|
319
|
+
help: false,
|
|
320
|
+
},
|
|
321
|
+
flags: {
|
|
322
|
+
'--fail-on-found': 'failOnFound',
|
|
323
|
+
'--json': 'json',
|
|
324
|
+
},
|
|
325
|
+
options: {
|
|
326
|
+
'--root': {
|
|
327
|
+
key: 'projectDir',
|
|
328
|
+
missingMessage: '--root requires a project directory.',
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
});
|
|
323
332
|
}
|
|
324
333
|
|
|
325
334
|
/**
|
|
@@ -328,15 +337,15 @@ function parseArgs(argv) {
|
|
|
328
337
|
* @returns {string} Usage text.
|
|
329
338
|
*/
|
|
330
339
|
function usage() {
|
|
331
|
-
return
|
|
340
|
+
return createUsage(
|
|
332
341
|
'Usage: emulsify-audit-twig-stories [--root <dir>] [--json] [--fail-on-found]',
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
342
|
+
[
|
|
343
|
+
' --root <dir> Project root to scan. Defaults to the current directory.',
|
|
344
|
+
' --json Print machine-readable JSON.',
|
|
345
|
+
' --fail-on-found Exit with code 1 when migration candidates are found.',
|
|
346
|
+
' --help Print this help text.',
|
|
347
|
+
],
|
|
348
|
+
);
|
|
340
349
|
}
|
|
341
350
|
|
|
342
351
|
/**
|
|
@@ -346,33 +355,61 @@ function usage() {
|
|
|
346
355
|
* @returns {number} Process exit code.
|
|
347
356
|
*/
|
|
348
357
|
export function runCli(argv = process.argv.slice(2)) {
|
|
349
|
-
const
|
|
358
|
+
const jsonRequested = argv.includes('--json');
|
|
359
|
+
let options;
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
options = parseArgs(argv);
|
|
363
|
+
if (options.help && options.json) {
|
|
364
|
+
throw new Error('--json cannot be combined with --help.');
|
|
365
|
+
}
|
|
366
|
+
} catch (error) {
|
|
367
|
+
if (jsonRequested) {
|
|
368
|
+
console.log(
|
|
369
|
+
formatAuditJsonErrorReport(error, {
|
|
370
|
+
code: 'invalid-arguments',
|
|
371
|
+
}),
|
|
372
|
+
);
|
|
373
|
+
} else {
|
|
374
|
+
console.error(`${error.message || error}\n\n${usage()}`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return cliFailureExitCode;
|
|
378
|
+
}
|
|
350
379
|
|
|
351
380
|
if (options.help) {
|
|
352
381
|
console.log(usage());
|
|
353
382
|
return 0;
|
|
354
383
|
}
|
|
355
384
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
385
|
+
try {
|
|
386
|
+
const result = auditTwigStories({
|
|
387
|
+
projectDir: options.projectDir,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
if (options.json) {
|
|
391
|
+
console.log(formatAuditJsonReport(createJsonAuditResult(result)));
|
|
392
|
+
} else {
|
|
393
|
+
console.log(formatAuditReport(result));
|
|
394
|
+
}
|
|
359
395
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
396
|
+
return options.failOnFound && result.findings.length ? 1 : 0;
|
|
397
|
+
} catch (error) {
|
|
398
|
+
if (options.json) {
|
|
399
|
+
console.log(
|
|
400
|
+
formatAuditJsonErrorReport(error, {
|
|
401
|
+
code: 'audit-failed',
|
|
402
|
+
projectDir: resolve(options.projectDir),
|
|
403
|
+
}),
|
|
404
|
+
);
|
|
405
|
+
} else {
|
|
406
|
+
console.error(`Audit failed: ${error.message || error}`);
|
|
407
|
+
}
|
|
365
408
|
|
|
366
|
-
|
|
409
|
+
return cliFailureExitCode;
|
|
410
|
+
}
|
|
367
411
|
}
|
|
368
412
|
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
process.exitCode = runCli();
|
|
372
|
-
} catch (error) {
|
|
373
|
-
console.error(error.message || error);
|
|
374
|
-
console.error('');
|
|
375
|
-
console.error(usage());
|
|
376
|
-
process.exitCode = 1;
|
|
377
|
-
}
|
|
413
|
+
if (isCliEntrypoint(['audit-twig-stories.js', 'emulsify-audit-twig-stories'])) {
|
|
414
|
+
process.exitCode = runCli();
|
|
378
415
|
}
|