mage-obsidian 1.1.2 → 2.0.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 (111) hide show
  1. package/.github/workflows/ci.yml +38 -0
  2. package/.github/workflows/publish.yml +26 -25
  3. package/.oxlintrc.json +19 -0
  4. package/.prettierignore +7 -0
  5. package/.prettierrc.json +7 -0
  6. package/LICENSE +1 -1
  7. package/README.md +1 -0
  8. package/eslint.config.js +24 -0
  9. package/package.json +39 -13
  10. package/pnpm-workspace.yaml +4 -0
  11. package/src/cli/buildThemes.ts +263 -0
  12. package/src/config/default.ts +31 -0
  13. package/src/config/eslint.js +60 -0
  14. package/src/core/configResolver.ts +141 -0
  15. package/src/core/contractValidator.ts +56 -0
  16. package/src/core/cssResolver.ts +153 -0
  17. package/src/{service/generateInterceptors.js → core/generateInterceptors.ts} +79 -46
  18. package/src/core/generateJsconfig.ts +168 -0
  19. package/src/{service/moduleResolver.js → core/moduleResolver.ts} +79 -46
  20. package/src/core/preCompileFiles.ts +105 -0
  21. package/src/core/preCompileMagentoFiles.ts +34 -0
  22. package/src/core/themeResolverSync.ts +66 -0
  23. package/src/runtime/i18nCore.ts +113 -0
  24. package/src/runtime/interceptorManager.ts +186 -0
  25. package/src/runtime/islands.ts +84 -0
  26. package/src/runtime/sectionStoreCore.ts +259 -0
  27. package/src/utils/{findComponents.js → findComponents.ts} +29 -16
  28. package/src/utils/runWithConcurrency.ts +35 -0
  29. package/src/vite/defaultNodeResolver.ts +17 -0
  30. package/src/{service/inheritAssetsModuleResolver.js → vite/inheritAssetsModuleResolver.ts} +15 -11
  31. package/src/{service/inheritModuleResolver.js → vite/inheritModuleResolver.ts} +6 -10
  32. package/src/{service/interceptorsPlugin.js → vite/interceptorsPlugin.ts} +25 -19
  33. package/src/vite/magentoHrmRewrite.ts +44 -0
  34. package/src/vite/sharedPlugins.ts +54 -0
  35. package/src/vite/themeSourceWatcher.ts +96 -0
  36. package/src/vite/unresolvedModuleGuard.ts +87 -0
  37. package/tsconfig.json +34 -0
  38. package/vitest.config.js +18 -0
  39. package/jest.config.js +0 -5
  40. package/src/__tests__/__mocks__/configResolver.js +0 -35
  41. package/src/__tests__/fixtures/interceptors/emptyTarget.js +0 -2
  42. package/src/__tests__/fixtures/interceptors/pluginForNonFunction.js +0 -7
  43. package/src/__tests__/fixtures/interceptors/pluginModule.js +0 -13
  44. package/src/__tests__/fixtures/interceptors/targetModule.js +0 -12
  45. package/src/__tests__/fixtures/interceptors/targetNonFunction.js +0 -7
  46. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentA.vue +0 -0
  47. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentB.vue +0 -0
  48. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/css/module.extend.css +0 -0
  49. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/js/main.js +0 -0
  50. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/main.js +0 -0
  51. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameA/view/frontend/web/module.config.js +0 -9
  52. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentA.vue +0 -0
  53. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentB.vue +0 -0
  54. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/css/module.extend.css +0 -2
  55. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/js/main.js +0 -0
  56. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameB/view/frontend/web/module.config.js +0 -7
  57. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue +0 -0
  58. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue +0 -0
  59. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/css/module.extend.css +0 -2
  60. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js +0 -0
  61. package/src/__tests__/magento_scenarios/app/code/Vendor/ModuleNameC/view/frontend/web/module.config.js +0 -7
  62. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue +0 -0
  63. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue +0 -0
  64. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/css/module.extend.css +0 -0
  65. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js +0 -0
  66. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/module.config.js +0 -2
  67. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
  68. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
  69. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
  70. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js +0 -0
  71. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/module.config.js +0 -2
  72. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue +0 -0
  73. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue +0 -0
  74. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/css/module.extend.css +0 -0
  75. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js +0 -0
  76. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/module.config.js +0 -2
  77. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue +0 -0
  78. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue +0 -0
  79. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/css/theme.source.css +0 -6
  80. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/js/main.js +0 -0
  81. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-a/web/theme.config.js +0 -5
  82. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/css/theme.source.css +0 -6
  83. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-b/web/theme.config.js +0 -5
  84. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentA.vue +0 -0
  85. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentB.vue +0 -0
  86. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/css/module.extend.css +0 -0
  87. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/js/main.js +0 -0
  88. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/module.config.js +0 -2
  89. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/css/theme.source.css +0 -6
  90. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-c/web/theme.config.js +0 -2
  91. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/css/theme.source.css +0 -6
  92. package/src/__tests__/magento_scenarios/app/design/frontend/Vendor/theme-d/web/theme.config.js +0 -3
  93. package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_a.json +0 -53
  94. package/src/__tests__/magento_scenarios/app/etc/mage_obsidian_frontend_modules_b.json +0 -50
  95. package/src/__tests__/service/generateInterceptors.test.js +0 -196
  96. package/src/__tests__/service/inheritModuleResolver.test.js +0 -61
  97. package/src/__tests__/service/interceptorManager_magento_behavior.test.js +0 -137
  98. package/src/__tests__/service/moduleResolver.test.js +0 -194
  99. package/src/__tests__/service/themeResolverSync.test.js +0 -97
  100. package/src/__tests__/vite-plugins/interceptorsPlugin.test.js +0 -121
  101. package/src/config/default.js +0 -27
  102. package/src/scripts/buildThemes.js +0 -132
  103. package/src/service/configResolver.js +0 -63
  104. package/src/service/cssResolver.js +0 -73
  105. package/src/service/defaultNodeResolver.js +0 -16
  106. package/src/service/interceptorManager.js +0 -137
  107. package/src/service/magentoHrmRewrite.js +0 -43
  108. package/src/service/preCompileFiles.js +0 -37
  109. package/src/service/preCompileMagentoFiles.js +0 -16
  110. package/src/service/setupGlobals.js +0 -19
  111. package/src/service/themeResolverSync.js +0 -67
@@ -1,137 +0,0 @@
1
-
2
- import { jest } from '@jest/globals';
3
- import interceptorManager from '../../service/interceptorManager.js';
4
-
5
- describe('InterceptorManager Magento Behavior', () => {
6
- beforeEach(() => {
7
- // Reset interceptors before each test
8
- interceptorManager.interceptors = {};
9
- });
10
-
11
- test('Before interceptors: should chain arguments and handle null returns', async () => {
12
- const targetName = 'Test::beforeChain';
13
- const originalFn = jest.fn((arg1, arg2) => `Original: ${arg1}, ${arg2}`);
14
- const context = {};
15
-
16
- // Interceptor 1: Modifies arguments
17
- const beforeInterceptor1 = jest.fn((arg1, arg2) => {
18
- return [arg1 + '_mod1', arg2 + '_mod1'];
19
- });
20
-
21
- // Interceptor 2: Returns null (should keep arguments from Interceptor 1)
22
- const beforeInterceptor2 = jest.fn((arg1, arg2) => {
23
- return null;
24
- });
25
-
26
- // Interceptor 3: Modifies arguments again
27
- const beforeInterceptor3 = jest.fn((arg1, arg2) => {
28
- return [arg1 + '_mod3', arg2 + '_mod3'];
29
- });
30
-
31
- interceptorManager.addInterceptor(targetName, 'Interceptor1', 'before', beforeInterceptor1, 10);
32
- interceptorManager.addInterceptor(targetName, 'Interceptor2', 'before', beforeInterceptor2, 20);
33
- interceptorManager.addInterceptor(targetName, 'Interceptor3', 'before', beforeInterceptor3, 30);
34
-
35
- const result = await interceptorManager.execute(targetName, originalFn, context, 'A', 'B');
36
-
37
- // Verify Interceptor 1 received original args
38
- expect(beforeInterceptor1).toHaveBeenCalledWith('A', 'B');
39
-
40
- // Verify Interceptor 2 received args modified by Interceptor 1
41
- expect(beforeInterceptor2).toHaveBeenCalledWith('A_mod1', 'B_mod1');
42
-
43
- // Verify Interceptor 3 received args from Interceptor 1 (since Interceptor 2 returned null)
44
- expect(beforeInterceptor3).toHaveBeenCalledWith('A_mod1', 'B_mod1');
45
-
46
- // Verify Original received args modified by Interceptor 3
47
- expect(originalFn).toHaveBeenCalledWith('A_mod1_mod3', 'B_mod1_mod3');
48
-
49
- expect(result).toBe('Original: A_mod1_mod3, B_mod1_mod3');
50
- });
51
-
52
- test('Around interceptors: should wrap execution and modify args/result', async () => {
53
- const targetName = 'Test::aroundChain';
54
- const originalFn = jest.fn((arg) => `Original(${arg})`);
55
- const context = {};
56
-
57
- // Outer Around Interceptor
58
- const aroundInterceptor1 = jest.fn(async (proceed, arg) => {
59
- const result = await proceed(arg + '_outerIn');
60
- return `Outer(${result})`;
61
- });
62
-
63
- // Inner Around Interceptor
64
- const aroundInterceptor2 = jest.fn(async (proceed, arg) => {
65
- const result = await proceed(arg + '_innerIn');
66
- return `Inner(${result})`;
67
- });
68
-
69
- interceptorManager.addInterceptor(targetName, 'Interceptor1', 'around', aroundInterceptor1, 10);
70
- interceptorManager.addInterceptor(targetName, 'Interceptor2', 'around', aroundInterceptor2, 20);
71
-
72
- const result = await interceptorManager.execute(targetName, originalFn, context, 'Start');
73
-
74
- // Execution flow:
75
- // Interceptor1 (Start) -> calls proceed('Start_outerIn')
76
- // -> Interceptor2 ('Start_outerIn') -> calls proceed('Start_outerIn_innerIn')
77
- // -> Original ('Start_outerIn_innerIn') -> returns 'Original(Start_outerIn_innerIn)'
78
- // -> Interceptor2 returns 'Inner(Original(Start_outerIn_innerIn))'
79
- // -> Interceptor1 returns 'Outer(Inner(Original(Start_outerIn_innerIn)))'
80
-
81
- expect(originalFn).toHaveBeenCalledWith('Start_outerIn_innerIn');
82
- expect(result).toBe('Outer(Inner(Original(Start_outerIn_innerIn)))');
83
- });
84
-
85
- test('After interceptors: should chain results', async () => {
86
- const targetName = 'Test::afterChain';
87
- const originalFn = jest.fn(() => 'Original');
88
- const context = {};
89
-
90
- const afterInterceptor1 = jest.fn((result) => {
91
- return result + '_After1';
92
- });
93
-
94
- const afterInterceptor2 = jest.fn((result) => {
95
- return result + '_After2';
96
- });
97
-
98
- interceptorManager.addInterceptor(targetName, 'Interceptor1', 'after', afterInterceptor1, 10);
99
- interceptorManager.addInterceptor(targetName, 'Interceptor2', 'after', afterInterceptor2, 20);
100
-
101
- const result = await interceptorManager.execute(targetName, originalFn, context);
102
-
103
- expect(afterInterceptor1).toHaveBeenCalledWith('Original');
104
- expect(afterInterceptor2).toHaveBeenCalledWith('Original_After1');
105
- expect(result).toBe('Original_After1_After2');
106
- });
107
-
108
- test('Full Chain: Before -> Around -> Original -> After', async () => {
109
- const targetName = 'Test::fullChain';
110
- const originalFn = jest.fn((arg) => `Original(${arg})`);
111
- const context = {};
112
-
113
- // Before: Modifies arg
114
- interceptorManager.addInterceptor(targetName, 'Before', 'before', (arg) => [arg + '_Before'], 10);
115
-
116
- // Around: Wraps and modifies arg further
117
- interceptorManager.addInterceptor(targetName, 'Around', 'around', async (proceed, arg) => {
118
- const res = await proceed(arg + '_AroundIn');
119
- return `Around(${res})`;
120
- }, 20);
121
-
122
- // After: Modifies result
123
- interceptorManager.addInterceptor(targetName, 'After', 'after', (res) => res + '_After', 30);
124
-
125
- const result = await interceptorManager.execute(targetName, originalFn, context, 'Start');
126
-
127
- // Flow:
128
- // Before: Start -> Start_Before
129
- // Around: Start_Before -> calls proceed(Start_Before_AroundIn)
130
- // Original: Start_Before_AroundIn -> returns Original(Start_Before_AroundIn)
131
- // Around: returns Around(Original(Start_Before_AroundIn))
132
- // After: receives Around(...) -> returns Around(...)_After
133
-
134
- expect(originalFn).toHaveBeenCalledWith('Start_Before_AroundIn');
135
- expect(result).toBe('Around(Original(Start_Before_AroundIn))_After');
136
- });
137
- });
@@ -1,194 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import createMockConfigResolver from '../__mocks__/configResolver.js';
3
- import path from 'path';
4
- import {fileURLToPath} from 'url';
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
- const MAGENTO_SCENARIOS_PATH = path.resolve(__dirname,'../magento_scenarios');
8
-
9
- let scenarios = [
10
- {
11
- scenario: 'a',
12
- themes: [
13
- {
14
- code: 'Vendor/theme-a',
15
- expected: {
16
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
17
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
18
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
19
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue',
20
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue',
21
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js',
22
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
23
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
24
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
25
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
26
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
27
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js'
28
- }
29
- },
30
- {
31
- code: 'Vendor/theme-b',
32
- expected: {
33
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
34
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
35
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
36
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue',
37
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue',
38
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js',
39
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
40
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
41
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
42
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
43
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
44
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js'
45
- }
46
- },
47
- {
48
- code: 'Vendor/theme-c',
49
- expected: {
50
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
51
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
52
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
53
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentA.vue',
54
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentB.vue',
55
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/js/main.js',
56
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
57
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
58
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
59
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
60
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
61
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js'
62
- }
63
- },
64
- {
65
- code: 'Vendor/theme-d',
66
- expected: {
67
- 'Vendor_ModuleNameA/components/ComponentA': 'app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentA.vue',
68
- 'Vendor_ModuleNameA/components/ComponentB': 'app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentB.vue',
69
- 'Vendor_ModuleNameA/js/main': 'app/code/Vendor/ModuleNameA/view/frontend/web/js/main.js',
70
- 'Vendor_ModuleNameB/components/ComponentA': 'app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentA.vue',
71
- 'Vendor_ModuleNameB/components/ComponentB': 'app/code/Vendor/ModuleNameB/view/frontend/web/components/ComponentB.vue',
72
- 'Vendor_ModuleNameB/js/main': 'app/code/Vendor/ModuleNameB/view/frontend/web/js/main.js',
73
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
74
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
75
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
76
- }
77
- },
78
- ]
79
- },
80
- {
81
- scenario: 'b',
82
- themes: [
83
- {
84
- code: 'Vendor/theme-a',
85
- expected: {
86
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
87
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
88
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
89
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue',
90
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue',
91
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js',
92
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
93
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
94
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
95
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
96
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
97
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js',
98
- 'Vendor_ModuleNameNoConfig/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue',
99
- 'Vendor_ModuleNameNoConfig/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue',
100
- 'Vendor_ModuleNameNoConfig/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js',
101
- }
102
- },
103
- {
104
- code: 'Vendor/theme-b',
105
- expected: {
106
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
107
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
108
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
109
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentA.vue',
110
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/components/ComponentB.vue',
111
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameB/web/js/main.js',
112
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
113
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
114
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
115
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
116
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
117
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js',
118
- 'Vendor_ModuleNameNoConfig/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue',
119
- 'Vendor_ModuleNameNoConfig/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue',
120
- 'Vendor_ModuleNameNoConfig/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js',
121
- }
122
- },
123
- {
124
- code: 'Vendor/theme-c',
125
- expected: {
126
- 'Vendor_ModuleNameA/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentA.vue',
127
- 'Vendor_ModuleNameA/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/components/ComponentB.vue',
128
- 'Vendor_ModuleNameA/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameA/web/js/main.js',
129
- 'Vendor_ModuleNameB/components/ComponentA': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentA.vue',
130
- 'Vendor_ModuleNameB/components/ComponentB': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/components/ComponentB.vue',
131
- 'Vendor_ModuleNameB/js/main': 'app/design/frontend/Vendor/theme-c/Vendor_ModuleNameB/web/js/main.js',
132
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
133
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
134
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
135
- 'Theme/components/ComponentA': 'app/design/frontend/Vendor/theme-a/web/components/ComponentA.vue',
136
- 'Theme/components/ComponentB': 'app/design/frontend/Vendor/theme-a/web/components/ComponentB.vue',
137
- 'Theme/js/main': 'app/design/frontend/Vendor/theme-a/web/js/main.js',
138
- 'Vendor_ModuleNameNoConfig/components/ComponentA': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentA.vue',
139
- 'Vendor_ModuleNameNoConfig/components/ComponentB': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/components/ComponentB.vue',
140
- 'Vendor_ModuleNameNoConfig/js/main': 'app/design/frontend/Vendor/theme-a/Vendor_ModuleNameNoConfig/web/js/main.js',
141
- }
142
- },
143
- {
144
- code: 'Vendor/theme-d',
145
- expected: {
146
- 'Vendor_ModuleNameA/components/ComponentA': 'app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentA.vue',
147
- 'Vendor_ModuleNameA/components/ComponentB': 'app/code/Vendor/ModuleNameA/view/frontend/web/components/ComponentB.vue',
148
- 'Vendor_ModuleNameA/js/main': 'app/code/Vendor/ModuleNameA/view/frontend/web/js/main.js',
149
- 'Vendor_ModuleNameC/components/ComponentA': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentA.vue',
150
- 'Vendor_ModuleNameC/components/ComponentB': 'app/code/Vendor/ModuleNameC/view/frontend/web/components/ComponentB.vue',
151
- 'Vendor_ModuleNameC/js/main': 'app/code/Vendor/ModuleNameC/view/frontend/web/js/main.js',
152
- }
153
- },
154
- ]
155
- },
156
- ];
157
-
158
- for (const scenario of scenarios) {
159
- for (const key in scenario.themes) {
160
- let themes = scenario.themes[key];
161
- for (const key in themes.expected) {
162
- let expected = themes.expected[key];
163
- themes.expected[key] = path.resolve(MAGENTO_SCENARIOS_PATH, expected);
164
- }
165
- }
166
- }
167
-
168
- describe('getAllJsVueFilesWithInheritance', () => {
169
- let moduleResolver;
170
-
171
- beforeEach(async () => {
172
- jest.resetModules()
173
- });
174
-
175
- test.each(scenarios.flatMap(({ scenario, themes }) =>
176
- themes.map(({ code, expected }) => ([ scenario, code, expected ]))
177
- ))('Scenario "%s", Theme "%s"', async (scenario, code, expected) => {
178
- jest.unstable_mockModule(
179
- '#service/configResolver.js',
180
- () => ({
181
- __esModule: true,
182
- default: createMockConfigResolver(scenario).default
183
- })
184
- );
185
-
186
- const importedModule = await import('#service/moduleResolver.js');
187
- moduleResolver = importedModule.default;
188
-
189
- const result = await moduleResolver.getAllJsVueFilesWithInheritance(code);
190
-
191
- expect(result).toEqual(expected, `Failed for scenario "${scenario}", theme "${code}"`);
192
- });
193
- });
194
-
@@ -1,97 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- import createMockConfigResolver from '../__mocks__/configResolver.js';
3
- import path from 'path';
4
- import {fileURLToPath} from 'url';
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- let scenarios = [
9
- {
10
- scenario: 'a',
11
- themes: [
12
- {
13
- code: 'Vendor/theme-a',
14
- expected: {
15
- includeCssSourceFromParentThemes: true,
16
- ignoredCssFromModules: [
17
- 'Vendor_ModuleNameA'
18
- ],
19
- exposeNpmPackages: []
20
- }
21
- },
22
- {
23
- code: 'Vendor/theme-b',
24
- expected: {
25
- includeCssSourceFromParentThemes: true,
26
- ignoredCssFromModules: [
27
- 'Vendor_ModuleNameA',
28
- 'Vendor_ModuleNameNoConfig'
29
- ],
30
- exposeNpmPackages: []
31
- }
32
- },
33
- {
34
- code: 'Vendor/theme-c',
35
- expected: {
36
- includeCssSourceFromParentThemes: true,
37
- ignoredCssFromModules: [
38
- 'Vendor_ModuleNameA',
39
- 'Vendor_ModuleNameNoConfig'
40
- ],
41
- exposeNpmPackages: []
42
- }
43
- },
44
- {
45
- code: 'Vendor/theme-d',
46
- expected: {
47
- includeCssSourceFromParentThemes: false,
48
- ignoredCssFromModules: [],
49
- exposeNpmPackages: []
50
- }
51
- }
52
- ]
53
- }
54
- ];
55
-
56
- for (const scenario of scenarios) {
57
- for (const themeKey in scenario.themes) {
58
- let theme = scenario.themes[themeKey];
59
- const expected = theme.expected;
60
- }
61
- }
62
-
63
- async function setupThemeResolver(scenario) {
64
- const mock = createMockConfigResolver(scenario);
65
-
66
- jest.unstable_mockModule('#service/configResolver.js', () => ({
67
- ...mock,
68
- __esModule: true,
69
- }));
70
-
71
- const resolver = await import('#service/themeResolverSync.js');
72
- return resolver.default;
73
- }
74
-
75
-
76
- describe('getThemeConfig', () => {
77
- let themeResolver;
78
-
79
- beforeEach(() => {
80
- jest.resetModules();
81
- });
82
-
83
- test.each(scenarios.flatMap(({ scenario, themes }) =>
84
- themes.map(({ code, expected }) => ([ scenario, code, expected ]))
85
- ))('Scenario "%s", Theme "%s"', async ( scenario, code, expected ) => {
86
- themeResolver = await setupThemeResolver(scenario);
87
-
88
- const result = await themeResolver.getThemeConfig(code);
89
-
90
- expect(result).toEqual(
91
- expected,
92
- `Expected:\n${JSON.stringify(expected, null, 2)}\nReceived:\n${JSON.stringify(result, null, 2)}\nScenario: "${scenario}", Theme: "${code}"`
93
- );
94
- });
95
- });
96
-
97
-
@@ -1,121 +0,0 @@
1
-
2
- import { jest } from '@jest/globals';
3
- // import interceptorsPlugin from '../../service/interceptorsPlugin.js'; // Removed static import
4
-
5
- describe('interceptorsPlugin', () => {
6
- let plugin;
7
- let mockGenerateInterceptors;
8
- let mockResolve;
9
- const themeName = 'Vendor/theme-test';
10
-
11
- beforeEach(async () => {
12
- jest.resetModules(); // Reset modules to ensure fresh imports and mocks
13
- jest.clearAllMocks();
14
-
15
- // Mock configResolver to prevent process.exit
16
- jest.unstable_mockModule('../../service/configResolver.js', () => ({
17
- default: {
18
- resolveLibRealPath: jest.fn()
19
- }
20
- }));
21
-
22
- // Mock generateInterceptorsService
23
- mockGenerateInterceptors = jest.fn();
24
-
25
- // Mock the service module
26
- jest.unstable_mockModule('../../service/generateInterceptors.js', () => ({
27
- default: {
28
- generateInterceptors: mockGenerateInterceptors
29
- }
30
- }));
31
-
32
- // Re-import the plugin to use the mock
33
- const pluginModule = await import('../../service/interceptorsPlugin.js');
34
- const createPlugin = pluginModule.default;
35
-
36
- plugin = createPlugin({ themeName });
37
-
38
- // Mock Vite context
39
- mockResolve = jest.fn();
40
- plugin.resolve = mockResolve; // Bind mock to the plugin instance context if needed, but resolveId is called on context
41
- });
42
-
43
- test('should generate interceptors on buildStart', async () => {
44
- mockGenerateInterceptors.mockResolvedValue({});
45
- await plugin.buildStart.call({});
46
- expect(mockGenerateInterceptors).toHaveBeenCalledWith(themeName);
47
- });
48
-
49
- test('should resolve to virtual ID if interceptor exists', async () => {
50
- const targetPath = '/abs/path/to/target.js';
51
- const interceptors = {
52
- 'Target::Method': {
53
- targetPath: targetPath,
54
- source: 'export const intercepted = true;'
55
- }
56
- };
57
- mockGenerateInterceptors.mockResolvedValue(interceptors);
58
-
59
- // Initialize plugin
60
- await plugin.buildStart.call({});
61
-
62
- // Mock resolve to return the absolute path
63
- const context = {
64
- resolve: jest.fn().mockResolvedValue({ id: targetPath })
65
- };
66
-
67
- const result = await plugin.resolveId.call(context, './target.js', '/importer.js');
68
-
69
- expect(context.resolve).toHaveBeenCalledWith('./target.js', '/importer.js', { skipSelf: true });
70
- expect(result).toBe(`\0interceptor:${targetPath}`);
71
- });
72
-
73
- test('should NOT resolve to virtual ID if importer IS the virtual ID (loop prevention)', async () => {
74
- const targetPath = '/abs/path/to/target.js';
75
- const interceptors = {
76
- 'Target::Method': {
77
- targetPath: targetPath,
78
- source: 'export const intercepted = true;'
79
- }
80
- };
81
- mockGenerateInterceptors.mockResolvedValue(interceptors);
82
-
83
- await plugin.buildStart.call({});
84
-
85
- const context = {
86
- resolve: jest.fn().mockResolvedValue({ id: targetPath })
87
- };
88
-
89
- const virtualId = `\0interceptor:${targetPath}`;
90
- const result = await plugin.resolveId.call(context, './target.js', virtualId);
91
-
92
- expect(result).toBeNull();
93
- });
94
-
95
- test('should load generated source for virtual ID', async () => {
96
- const targetPath = '/abs/path/to/target.js';
97
- const sourceCode = 'export const intercepted = true;';
98
- const interceptors = {
99
- 'Target::Method': {
100
- targetPath: targetPath,
101
- source: sourceCode
102
- }
103
- };
104
- mockGenerateInterceptors.mockResolvedValue(interceptors);
105
-
106
- await plugin.buildStart.call({});
107
-
108
- const virtualId = `\0interceptor:${targetPath}`;
109
- const result = plugin.load.call({}, virtualId);
110
-
111
- expect(result).toBe(sourceCode);
112
- });
113
-
114
- test('should return null for unknown virtual ID', async () => {
115
- mockGenerateInterceptors.mockResolvedValue({});
116
- await plugin.buildStart.call({});
117
-
118
- const result = plugin.load.call({}, '\0interceptor:/unknown.js');
119
- expect(result).toBeNull();
120
- });
121
- });
@@ -1,27 +0,0 @@
1
- import path from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
-
4
- const BASE_PATH = process.cwd();
5
-
6
- export const DEPENDENCY_CONFIG_FILENAME = 'mage_obsidian_frontend_modules.json';
7
- export const MAGENTO_CONFIG_RELATIVE_PATH = 'app/etc/';
8
- export const DEPENDENCY_CONFIG_FILE_PATH = path.resolve(
9
- BASE_PATH,
10
- '..',
11
- MAGENTO_CONFIG_RELATIVE_PATH,
12
- DEPENDENCY_CONFIG_FILENAME
13
- );
14
-
15
- export const MODULE_WEB_PATH = 'view/frontend/web/';
16
- export const THEME_MODULE_WEB_PATH = 'web/';
17
- export const MODULE_CSS_FOLDER = 'css';
18
-
19
- export const THEME_CSS_FOLDER = 'css';
20
-
21
- export const OUTPUT_THEME_DIR = 'web/generated';
22
- export const OUTPUT_JS_DIR = 'js/';
23
- export const OUTPUT_CSS_DIR = 'css/';
24
- export const PRECOMPILED_FOLDER = '.precompiled';
25
- export const INTERCEPTORS_FOLDER = 'interceptors';
26
-
27
- export const ALL_JS_VUE_FILES_WITH_INHERITANCE_FILE_NAME = 'allJsVueFilesWithInheritance.json';