@esmx/core 3.0.0-rc.59 → 3.0.0-rc.60
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/dist/core.mjs +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +0 -6
- package/dist/manifest-json.d.ts +8 -21
- package/dist/module-config.d.ts +39 -144
- package/dist/module-config.mjs +145 -57
- package/dist/module-config.test.mjs +620 -509
- package/dist/pack-config.d.ts +2 -2
- package/dist/utils/import-map.d.ts +9 -5
- package/dist/utils/import-map.mjs +36 -23
- package/dist/utils/import-map.test.mjs +1139 -103
- package/package.json +3 -3
- package/src/core.ts +5 -4
- package/src/index.ts +14 -9
- package/src/manifest-json.ts +8 -22
- package/src/module-config.test.ts +636 -637
- package/src/module-config.ts +242 -257
- package/src/pack-config.ts +2 -2
- package/src/utils/import-map.test.ts +1207 -110
- package/src/utils/import-map.ts +63 -29
|
@@ -1,798 +1,797 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
3
|
import {
|
|
4
4
|
type ModuleConfig,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
addPackageExportsToScopes,
|
|
6
|
+
createDefaultExports,
|
|
7
|
+
getEnvironmentExports,
|
|
8
|
+
getEnvironmentImports,
|
|
9
|
+
getEnvironmentScopes,
|
|
10
|
+
getEnvironments,
|
|
11
|
+
getLinks,
|
|
12
|
+
parseModuleConfig,
|
|
13
|
+
parsedExportValue,
|
|
14
|
+
processExportArray,
|
|
15
|
+
processObjectExport,
|
|
16
|
+
processStringExport,
|
|
17
|
+
resolveExportFile
|
|
10
18
|
} from './module-config';
|
|
11
19
|
|
|
12
|
-
describe('
|
|
13
|
-
const testModuleName = 'test-module';
|
|
14
|
-
const testRoot = '/test/root';
|
|
15
|
-
|
|
20
|
+
describe('Module Config Parser', () => {
|
|
16
21
|
describe('parseModuleConfig', () => {
|
|
17
|
-
it('should parse
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
it('should parse basic module config with name and root', () => {
|
|
23
|
+
const result = parseModuleConfig('test-module', '/test/root');
|
|
24
|
+
expect(result.name).toBe('test-module');
|
|
25
|
+
expect(result.root).toBe('/test/root');
|
|
26
|
+
expect(result.links).toBeDefined();
|
|
27
|
+
expect(result.environments).toBeDefined();
|
|
28
|
+
});
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
const result = parseModuleConfig(
|
|
30
|
+
it('should handle empty config object', () => {
|
|
31
|
+
const result = parseModuleConfig('test-module', '/test/root', {});
|
|
32
|
+
expect(result.name).toBe('test-module');
|
|
33
|
+
expect(result.root).toBe('/test/root');
|
|
34
|
+
});
|
|
23
35
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
expect(result.
|
|
36
|
+
it('should handle undefined config parameter', () => {
|
|
37
|
+
const result = parseModuleConfig(
|
|
38
|
+
'test-module',
|
|
39
|
+
'/test/root',
|
|
40
|
+
undefined
|
|
41
|
+
);
|
|
42
|
+
expect(result.name).toBe('test-module');
|
|
43
|
+
expect(result.root).toBe('/test/root');
|
|
31
44
|
});
|
|
32
45
|
|
|
33
|
-
it('should
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
it('should process links configuration', () => {
|
|
47
|
+
const config: ModuleConfig = {
|
|
48
|
+
links: {
|
|
49
|
+
'custom-link': '/custom/path'
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const result = parseModuleConfig(
|
|
53
|
+
'test-module',
|
|
54
|
+
'/test/root',
|
|
55
|
+
config
|
|
56
|
+
);
|
|
57
|
+
expect(result.links['custom-link']).toBeDefined();
|
|
58
|
+
});
|
|
36
59
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
expect(result.
|
|
40
|
-
expect(result.
|
|
60
|
+
it('should generate client and server environments', () => {
|
|
61
|
+
const result = parseModuleConfig('test-module', '/test/root');
|
|
62
|
+
expect(result.environments.client).toBeDefined();
|
|
63
|
+
expect(result.environments.server).toBeDefined();
|
|
41
64
|
});
|
|
42
65
|
|
|
43
|
-
it('should
|
|
44
|
-
// Arrange
|
|
66
|
+
it('should handle absolute and relative paths in links', () => {
|
|
45
67
|
const config: ModuleConfig = {
|
|
46
68
|
links: {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
imports: {
|
|
51
|
-
axios: 'shared-lib/axios',
|
|
52
|
-
lodash: 'shared-lib/lodash'
|
|
53
|
-
},
|
|
54
|
-
exports: {
|
|
55
|
-
axios: 'axios',
|
|
56
|
-
'src/utils/format': './src/utils/format.ts',
|
|
57
|
-
'custom-api': './src/api/custom.ts'
|
|
69
|
+
absolute: '/absolute/path',
|
|
70
|
+
relative: 'relative/path'
|
|
58
71
|
}
|
|
59
72
|
};
|
|
73
|
+
const result = parseModuleConfig(
|
|
74
|
+
'test-module',
|
|
75
|
+
'/test/root',
|
|
76
|
+
config
|
|
77
|
+
);
|
|
78
|
+
expect(result.links.absolute.root).toBe('/absolute/path');
|
|
79
|
+
expect(result.links.relative.root).toBe('relative/path');
|
|
80
|
+
});
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
const result = parseModuleConfig(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
expect(result.
|
|
66
|
-
expect(result.
|
|
67
|
-
expect(result.imports).toEqual(config.imports);
|
|
68
|
-
expect(result.links).toHaveProperty('shared-lib');
|
|
69
|
-
expect(result.links).toHaveProperty('api-utils');
|
|
70
|
-
expect(result.exports).toHaveProperty('axios');
|
|
71
|
-
expect(result.exports).toHaveProperty('src/utils/format');
|
|
72
|
-
expect(result.exports).toHaveProperty('custom-api');
|
|
82
|
+
it('should maintain type safety across transformations', () => {
|
|
83
|
+
const result = parseModuleConfig('test-module', '/test/root');
|
|
84
|
+
expect(typeof result.name).toBe('string');
|
|
85
|
+
expect(typeof result.root).toBe('string');
|
|
86
|
+
expect(typeof result.links).toBe('object');
|
|
87
|
+
expect(typeof result.environments).toBe('object');
|
|
73
88
|
});
|
|
74
89
|
});
|
|
75
90
|
|
|
76
|
-
describe('
|
|
77
|
-
it('should create
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// Act
|
|
82
|
-
const result = parseModuleConfig(testModuleName, testRoot, config);
|
|
83
|
-
|
|
84
|
-
// Assert
|
|
85
|
-
const selfLink = result.links[testModuleName];
|
|
86
|
-
expect(selfLink).toBeDefined();
|
|
87
|
-
expect(selfLink.name).toBe(testModuleName);
|
|
88
|
-
expect(selfLink.root).toBe(path.resolve(testRoot, 'dist'));
|
|
89
|
-
expect(selfLink.client).toBe(path.resolve(testRoot, 'dist/client'));
|
|
90
|
-
expect(selfLink.server).toBe(path.resolve(testRoot, 'dist/server'));
|
|
91
|
-
expect(selfLink.clientManifestJson).toBe(
|
|
92
|
-
path.resolve(testRoot, 'dist/client/manifest.json')
|
|
93
|
-
);
|
|
94
|
-
expect(selfLink.serverManifestJson).toBe(
|
|
95
|
-
path.resolve(testRoot, 'dist/server/manifest.json')
|
|
96
|
-
);
|
|
91
|
+
describe('getLinks', () => {
|
|
92
|
+
it('should create default link for module name', () => {
|
|
93
|
+
const result = getLinks('test-module', '/test/root', {});
|
|
94
|
+
expect(result['test-module']).toBeDefined();
|
|
95
|
+
expect(result['test-module'].name).toBe('test-module');
|
|
97
96
|
});
|
|
98
97
|
|
|
99
|
-
it('should process
|
|
100
|
-
// Arrange
|
|
98
|
+
it('should process custom links configuration', () => {
|
|
101
99
|
const config: ModuleConfig = {
|
|
102
100
|
links: {
|
|
103
|
-
'
|
|
101
|
+
'custom-link': '/custom/path'
|
|
104
102
|
}
|
|
105
103
|
};
|
|
104
|
+
const result = getLinks('test-module', '/test/root', config);
|
|
105
|
+
expect(result['custom-link']).toBeDefined();
|
|
106
|
+
expect(result['custom-link'].name).toBe('custom-link');
|
|
107
|
+
});
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
const result =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const sharedLibLink = result.links['shared-lib'];
|
|
112
|
-
expect(sharedLibLink.name).toBe('shared-lib');
|
|
113
|
-
expect(sharedLibLink.root).toBe('../shared-lib/dist');
|
|
114
|
-
expect(sharedLibLink.client).toBe(
|
|
115
|
-
path.resolve(testRoot, '../shared-lib/dist/client')
|
|
116
|
-
);
|
|
117
|
-
expect(sharedLibLink.server).toBe(
|
|
118
|
-
path.resolve(testRoot, '../shared-lib/dist/server')
|
|
119
|
-
);
|
|
109
|
+
it('should handle empty links object', () => {
|
|
110
|
+
const result = getLinks('test-module', '/test/root', {});
|
|
111
|
+
expect(Object.keys(result)).toHaveLength(1);
|
|
112
|
+
expect(result['test-module']).toBeDefined();
|
|
120
113
|
});
|
|
121
114
|
|
|
122
|
-
it('should
|
|
123
|
-
// Arrange
|
|
124
|
-
const absolutePath = '/absolute/path/api-utils/dist';
|
|
115
|
+
it('should resolve absolute paths correctly', () => {
|
|
125
116
|
const config: ModuleConfig = {
|
|
126
117
|
links: {
|
|
127
|
-
'
|
|
118
|
+
absolute: '/absolute/path'
|
|
128
119
|
}
|
|
129
120
|
};
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const result = parseModuleConfig(testModuleName, testRoot, config);
|
|
133
|
-
|
|
134
|
-
// Assert
|
|
135
|
-
const apiUtilsLink = result.links['api-utils'];
|
|
136
|
-
expect(apiUtilsLink.name).toBe('api-utils');
|
|
137
|
-
expect(apiUtilsLink.root).toBe(absolutePath);
|
|
138
|
-
expect(apiUtilsLink.client).toBe(
|
|
139
|
-
path.resolve(absolutePath, 'client')
|
|
140
|
-
);
|
|
141
|
-
expect(apiUtilsLink.server).toBe(
|
|
142
|
-
path.resolve(absolutePath, 'server')
|
|
143
|
-
);
|
|
121
|
+
const result = getLinks('test-module', '/test/root', config);
|
|
122
|
+
expect(result.absolute.root).toBe('/absolute/path');
|
|
144
123
|
});
|
|
145
124
|
|
|
146
|
-
it('should
|
|
147
|
-
// Arrange
|
|
125
|
+
it('should resolve relative paths from root', () => {
|
|
148
126
|
const config: ModuleConfig = {
|
|
149
127
|
links: {
|
|
150
|
-
|
|
151
|
-
lib2: '/absolute/lib2/dist',
|
|
152
|
-
lib3: './relative/lib3/dist'
|
|
128
|
+
relative: 'relative/path'
|
|
153
129
|
}
|
|
154
130
|
};
|
|
131
|
+
const result = getLinks('test-module', '/test/root', config);
|
|
132
|
+
expect(result.relative.root).toBe('relative/path');
|
|
133
|
+
});
|
|
155
134
|
|
|
156
|
-
|
|
157
|
-
const result =
|
|
135
|
+
it('should generate client and server manifest paths', () => {
|
|
136
|
+
const result = getLinks('test-module', '/test/root', {});
|
|
137
|
+
const link = result['test-module'];
|
|
138
|
+
const expectedRoot = path.resolve('/test/root', 'dist');
|
|
139
|
+
expect(link.client).toBe(path.resolve(expectedRoot, 'client'));
|
|
140
|
+
expect(link.clientManifestJson).toBe(
|
|
141
|
+
path.resolve(expectedRoot, 'client/manifest.json')
|
|
142
|
+
);
|
|
143
|
+
expect(link.server).toBe(path.resolve(expectedRoot, 'server'));
|
|
144
|
+
expect(link.serverManifestJson).toBe(
|
|
145
|
+
path.resolve(expectedRoot, 'server/manifest.json')
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should handle Windows path separators', () => {
|
|
150
|
+
const result = getLinks('test-module', 'C:\\test\\root', {});
|
|
151
|
+
const link = result['test-module'];
|
|
152
|
+
expect(link.client).toMatch(/[/\\]/);
|
|
153
|
+
expect(link.server).toMatch(/[/\\]/);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle Unix path separators', () => {
|
|
157
|
+
const result = getLinks('test-module', '/test/root', {});
|
|
158
|
+
const link = result['test-module'];
|
|
159
|
+
const expectedRoot = path.resolve('/test/root', 'dist');
|
|
160
|
+
expect(link.client).toBe(path.resolve(expectedRoot, 'client'));
|
|
161
|
+
expect(link.server).toBe(path.resolve(expectedRoot, 'server'));
|
|
162
|
+
});
|
|
158
163
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
expect(
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
it('should handle paths with special characters', () => {
|
|
165
|
+
const result = getLinks('test-module', '/test/root@1.0.0', {});
|
|
166
|
+
const link = result['test-module'];
|
|
167
|
+
expect(link.root).toBe(path.resolve('/test/root@1.0.0', 'dist'));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should handle paths with spaces', () => {
|
|
171
|
+
const result = getLinks(
|
|
172
|
+
'test-module',
|
|
173
|
+
'/test/root with spaces',
|
|
174
|
+
{}
|
|
175
|
+
);
|
|
176
|
+
const link = result['test-module'];
|
|
177
|
+
expect(link.root).toBe(
|
|
178
|
+
path.resolve('/test/root with spaces', 'dist')
|
|
179
|
+
);
|
|
165
180
|
});
|
|
166
181
|
});
|
|
167
182
|
|
|
168
|
-
describe('
|
|
169
|
-
describe('
|
|
170
|
-
it('should
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
);
|
|
183
|
+
describe('Environment Import Functions', () => {
|
|
184
|
+
describe('getEnvironmentImports', () => {
|
|
185
|
+
it('should filter imports by environment', () => {
|
|
186
|
+
const imports = {
|
|
187
|
+
react: 'react',
|
|
188
|
+
vue: {
|
|
189
|
+
client: 'vue',
|
|
190
|
+
server: 'vue/server'
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const clientResult = getEnvironmentImports('client', imports);
|
|
194
|
+
const serverResult = getEnvironmentImports('server', imports);
|
|
180
195
|
|
|
181
|
-
|
|
182
|
-
expect(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
expect(clientResult.react).toBe('react');
|
|
197
|
+
expect(clientResult.vue).toBe('vue');
|
|
198
|
+
expect(serverResult.vue).toBe('vue/server');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should handle string import values', () => {
|
|
202
|
+
const imports = {
|
|
203
|
+
react: 'react'
|
|
204
|
+
};
|
|
205
|
+
const result = getEnvironmentImports('client', imports);
|
|
206
|
+
expect(result.react).toBe('react');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should handle object import values with matching environment', () => {
|
|
210
|
+
const imports = {
|
|
211
|
+
vue: {
|
|
212
|
+
client: 'vue',
|
|
213
|
+
server: 'vue/server'
|
|
188
214
|
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
expect(result.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
215
|
+
};
|
|
216
|
+
const result = getEnvironmentImports('client', imports);
|
|
217
|
+
expect(result.vue).toBe('vue');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('should skip imports when environment value is undefined', () => {
|
|
221
|
+
const imports = {
|
|
222
|
+
vue: {
|
|
223
|
+
client: 'vue',
|
|
224
|
+
server: 'vue/server'
|
|
197
225
|
}
|
|
198
|
-
}
|
|
226
|
+
};
|
|
227
|
+
const result = getEnvironmentImports('server', imports);
|
|
228
|
+
expect(result.vue).toBe('vue/server');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should handle empty imports object', () => {
|
|
232
|
+
const result = getEnvironmentImports('client', {});
|
|
233
|
+
expect(Object.keys(result)).toHaveLength(0);
|
|
199
234
|
});
|
|
200
235
|
});
|
|
201
236
|
|
|
202
|
-
describe('
|
|
203
|
-
it('should process
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
237
|
+
describe('getEnvironmentScopes', () => {
|
|
238
|
+
it('should process scoped imports per environment', () => {
|
|
239
|
+
const scopes = {
|
|
240
|
+
utils: {
|
|
241
|
+
lodash: 'lodash',
|
|
242
|
+
moment: {
|
|
243
|
+
client: 'moment',
|
|
244
|
+
server: 'moment/server'
|
|
245
|
+
}
|
|
246
|
+
}
|
|
207
247
|
};
|
|
248
|
+
const result = getEnvironmentScopes('client', scopes);
|
|
249
|
+
expect(result.utils.lodash).toBe('lodash');
|
|
250
|
+
expect(result.utils.moment).toBe('moment');
|
|
251
|
+
});
|
|
208
252
|
|
|
209
|
-
|
|
210
|
-
const result =
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
);
|
|
253
|
+
it('should handle empty scopes object', () => {
|
|
254
|
+
const result = getEnvironmentScopes('client', {});
|
|
255
|
+
expect(Object.keys(result)).toHaveLength(0);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
215
258
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
expect(result.exports.lodash).toEqual({
|
|
227
|
-
name: 'lodash',
|
|
228
|
-
rewrite: false,
|
|
229
|
-
entryPoints: {
|
|
230
|
-
client: 'lodash',
|
|
231
|
-
server: 'lodash'
|
|
259
|
+
describe('getEnvironments', () => {
|
|
260
|
+
it('should combine imports, exports and scopes', () => {
|
|
261
|
+
const config: ModuleConfig = {
|
|
262
|
+
imports: {
|
|
263
|
+
react: 'react'
|
|
264
|
+
},
|
|
265
|
+
scopes: {
|
|
266
|
+
utils: {
|
|
267
|
+
lodash: 'lodash'
|
|
268
|
+
}
|
|
232
269
|
}
|
|
233
|
-
}
|
|
270
|
+
};
|
|
271
|
+
const result = getEnvironments(config, 'client', 'test-module');
|
|
272
|
+
expect(result.imports.react).toBe('react');
|
|
273
|
+
expect(result.scopes.utils.lodash).toBe('lodash');
|
|
274
|
+
expect(result.exports).toBeDefined();
|
|
234
275
|
});
|
|
235
276
|
|
|
236
|
-
it('should
|
|
237
|
-
// Arrange
|
|
277
|
+
it('should preserve import mapping types', () => {
|
|
238
278
|
const config: ModuleConfig = {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
'root:src/api/client.js'
|
|
243
|
-
]
|
|
279
|
+
imports: {
|
|
280
|
+
react: 'react'
|
|
281
|
+
}
|
|
244
282
|
};
|
|
283
|
+
const result = getEnvironments(config, 'client', 'test-module');
|
|
284
|
+
expect(typeof result.imports).toBe('object');
|
|
285
|
+
expect(typeof result.exports).toBe('object');
|
|
286
|
+
expect(typeof result.scopes).toBe('object');
|
|
287
|
+
});
|
|
245
288
|
|
|
246
|
-
|
|
247
|
-
const result = parseModuleConfig(
|
|
248
|
-
testModuleName,
|
|
249
|
-
testRoot,
|
|
250
|
-
config
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// Assert
|
|
254
|
-
expect(result.exports['src/utils/format']).toEqual({
|
|
255
|
-
name: 'src/utils/format',
|
|
256
|
-
rewrite: true,
|
|
257
|
-
entryPoints: {
|
|
258
|
-
client: './src/utils/format',
|
|
259
|
-
server: './src/utils/format'
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
expect(result.exports['src/components/Button']).toEqual({
|
|
264
|
-
name: 'src/components/Button',
|
|
265
|
-
rewrite: true,
|
|
266
|
-
entryPoints: {
|
|
267
|
-
client: './src/components/Button',
|
|
268
|
-
server: './src/components/Button'
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
expect(result.exports['src/api/client']).toEqual({
|
|
273
|
-
name: 'src/api/client',
|
|
274
|
-
rewrite: true,
|
|
275
|
-
entryPoints: {
|
|
276
|
-
client: './src/api/client',
|
|
277
|
-
server: './src/api/client'
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it('should handle all supported file extensions', () => {
|
|
283
|
-
// Arrange
|
|
284
|
-
const extensions = [
|
|
285
|
-
'js',
|
|
286
|
-
'mjs',
|
|
287
|
-
'cjs',
|
|
288
|
-
'jsx',
|
|
289
|
-
'mjsx',
|
|
290
|
-
'cjsx',
|
|
291
|
-
'ts',
|
|
292
|
-
'mts',
|
|
293
|
-
'cts',
|
|
294
|
-
'tsx',
|
|
295
|
-
'mtsx',
|
|
296
|
-
'ctsx'
|
|
297
|
-
];
|
|
289
|
+
it('should add pkg exports to scopes with empty string key', () => {
|
|
298
290
|
const config: ModuleConfig = {
|
|
299
|
-
exports:
|
|
291
|
+
exports: ['pkg:lodash', 'pkg:react', './src/component']
|
|
300
292
|
};
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
// Assert
|
|
310
|
-
extensions.forEach((ext) => {
|
|
311
|
-
expect(result.exports['src/test']).toBeDefined();
|
|
312
|
-
});
|
|
293
|
+
const result = getEnvironments(config, 'client', 'test-module');
|
|
294
|
+
const emptyScope = result.scopes[''];
|
|
295
|
+
expect(emptyScope).toBeDefined();
|
|
296
|
+
expect(emptyScope.lodash).toBe('test-module/lodash');
|
|
297
|
+
expect(emptyScope.react).toBe('test-module/react');
|
|
298
|
+
expect(emptyScope['./src/component']).toBeUndefined();
|
|
313
299
|
});
|
|
314
300
|
|
|
315
|
-
it('should
|
|
316
|
-
// Arrange
|
|
301
|
+
it('should not override existing empty string scope', () => {
|
|
317
302
|
const config: ModuleConfig = {
|
|
318
|
-
exports: [
|
|
319
|
-
|
|
320
|
-
{
|
|
321
|
-
|
|
322
|
-
utils: {
|
|
323
|
-
input: './src/utils/index.ts',
|
|
324
|
-
rewrite: true
|
|
325
|
-
}
|
|
303
|
+
exports: ['pkg:lodash'],
|
|
304
|
+
scopes: {
|
|
305
|
+
'': {
|
|
306
|
+
existing: 'existing-value'
|
|
326
307
|
}
|
|
327
|
-
|
|
308
|
+
}
|
|
328
309
|
};
|
|
310
|
+
const result = getEnvironments(config, 'client', 'test-module');
|
|
311
|
+
const emptyScope = result.scopes[''];
|
|
312
|
+
expect(emptyScope).toBeDefined();
|
|
313
|
+
expect(emptyScope.existing).toBe('existing-value');
|
|
314
|
+
expect(emptyScope.lodash).toBe('test-module/lodash');
|
|
315
|
+
});
|
|
316
|
+
});
|
|
329
317
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
318
|
+
describe('addPackageExportsToScopes', () => {
|
|
319
|
+
it('should create scopes for pkg exports', () => {
|
|
320
|
+
const exports = {
|
|
321
|
+
lodash: { name: 'lodash', file: 'lodash', pkg: true },
|
|
322
|
+
react: { name: 'react', file: 'react', pkg: true },
|
|
323
|
+
'./src/component': {
|
|
324
|
+
name: './src/component',
|
|
325
|
+
file: './src/component',
|
|
326
|
+
pkg: false
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const scopes: Record<string, Record<string, string>> = {};
|
|
330
|
+
const result = addPackageExportsToScopes(
|
|
331
|
+
exports,
|
|
332
|
+
scopes,
|
|
333
|
+
'test-module'
|
|
335
334
|
);
|
|
335
|
+
const emptyScope = result[''];
|
|
336
|
+
expect(emptyScope).toBeDefined();
|
|
337
|
+
expect(emptyScope.lodash).toBe('test-module/lodash');
|
|
338
|
+
expect(emptyScope.react).toBe('test-module/react');
|
|
339
|
+
expect(emptyScope['./src/component']).toBeUndefined();
|
|
340
|
+
});
|
|
336
341
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
name: '
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
expect(result.exports.utils).toEqual({
|
|
348
|
-
name: 'utils',
|
|
349
|
-
rewrite: true,
|
|
350
|
-
entryPoints: {
|
|
351
|
-
client: './src/utils/index.ts',
|
|
352
|
-
server: './src/utils/index.ts'
|
|
342
|
+
it('should not override existing empty string scope', () => {
|
|
343
|
+
const exports = {
|
|
344
|
+
lodash: { name: 'lodash', file: 'lodash', pkg: true }
|
|
345
|
+
};
|
|
346
|
+
const scopes = {
|
|
347
|
+
'': {
|
|
348
|
+
existing: 'existing-value'
|
|
353
349
|
}
|
|
354
|
-
}
|
|
350
|
+
};
|
|
351
|
+
const result = addPackageExportsToScopes(
|
|
352
|
+
exports,
|
|
353
|
+
scopes,
|
|
354
|
+
'test-module'
|
|
355
|
+
);
|
|
356
|
+
const emptyScope = result[''];
|
|
357
|
+
expect(emptyScope.existing).toBe('existing-value');
|
|
358
|
+
expect(emptyScope.lodash).toBe('test-module/lodash');
|
|
355
359
|
});
|
|
356
360
|
|
|
357
|
-
it('should handle
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
361
|
+
it('should handle empty exports', () => {
|
|
362
|
+
const exports = {};
|
|
363
|
+
const scopes: Record<string, Record<string, string>> = {};
|
|
364
|
+
const result = addPackageExportsToScopes(
|
|
365
|
+
exports,
|
|
366
|
+
scopes,
|
|
367
|
+
'test-module'
|
|
368
|
+
);
|
|
369
|
+
expect(Object.keys(result)).toHaveLength(0);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
});
|
|
365
373
|
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
describe('Export Processing Functions', () => {
|
|
375
|
+
describe('createDefaultExports', () => {
|
|
376
|
+
it('should generate client default exports', () => {
|
|
377
|
+
const result = createDefaultExports('client');
|
|
378
|
+
expect(result['src/entry.client'].file).toBe(
|
|
379
|
+
'./src/entry.client'
|
|
380
|
+
);
|
|
381
|
+
expect(result['src/entry.server'].file).toBe('');
|
|
382
|
+
});
|
|
368
383
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
384
|
+
it('should generate server default exports', () => {
|
|
385
|
+
const result = createDefaultExports('server');
|
|
386
|
+
expect(result['src/entry.client'].file).toBe('');
|
|
387
|
+
expect(result['src/entry.server'].file).toBe(
|
|
388
|
+
'./src/entry.server'
|
|
372
389
|
);
|
|
373
|
-
|
|
374
|
-
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('should handle client environment switch case', () => {
|
|
393
|
+
const result = createDefaultExports('client');
|
|
394
|
+
expect(result['src/entry.client'].file).toBe(
|
|
395
|
+
'./src/entry.client'
|
|
375
396
|
);
|
|
397
|
+
expect(result['src/entry.server'].file).toBe('');
|
|
398
|
+
});
|
|
376
399
|
|
|
377
|
-
|
|
400
|
+
it('should handle server environment switch case', () => {
|
|
401
|
+
const result = createDefaultExports('server');
|
|
402
|
+
expect(result['src/entry.client'].file).toBe('');
|
|
403
|
+
expect(result['src/entry.server'].file).toBe(
|
|
404
|
+
'./src/entry.server'
|
|
405
|
+
);
|
|
378
406
|
});
|
|
379
407
|
});
|
|
380
408
|
|
|
381
|
-
describe('
|
|
382
|
-
it('should
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
409
|
+
describe('processStringExport', () => {
|
|
410
|
+
it('should parse simple string export', () => {
|
|
411
|
+
const result = processStringExport('./src/component');
|
|
412
|
+
expect(result['./src/component']).toBeDefined();
|
|
413
|
+
expect(result['./src/component'].file).toBe('./src/component');
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
describe('processObjectExport', () => {
|
|
418
|
+
it('should handle environment-specific exports', () => {
|
|
419
|
+
const exportObject = {
|
|
420
|
+
'./src/component': {
|
|
421
|
+
client: './src/component.client',
|
|
422
|
+
server: './src/component.server'
|
|
388
423
|
}
|
|
389
424
|
};
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
testModuleName,
|
|
394
|
-
testRoot,
|
|
395
|
-
config
|
|
425
|
+
const result = processObjectExport(exportObject, 'client');
|
|
426
|
+
expect(result['./src/component'].file).toBe(
|
|
427
|
+
'./src/component.client'
|
|
396
428
|
);
|
|
397
|
-
|
|
398
|
-
// Assert
|
|
399
|
-
expect(result.exports.axios).toEqual({
|
|
400
|
-
name: 'axios',
|
|
401
|
-
rewrite: true,
|
|
402
|
-
entryPoints: {
|
|
403
|
-
client: 'axios',
|
|
404
|
-
server: 'axios'
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
expect(result.exports.utils).toEqual({
|
|
409
|
-
name: 'utils',
|
|
410
|
-
rewrite: true,
|
|
411
|
-
entryPoints: {
|
|
412
|
-
client: './src/utils/index.ts',
|
|
413
|
-
server: './src/utils/index.ts'
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
429
|
});
|
|
417
430
|
|
|
418
|
-
it('should process
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
client: './src/storage/indexedDB.ts',
|
|
425
|
-
server: './src/storage/filesystem.ts'
|
|
426
|
-
},
|
|
427
|
-
rewrite: true
|
|
428
|
-
},
|
|
429
|
-
'npm-package': {
|
|
430
|
-
input: 'some-package',
|
|
431
|
-
rewrite: false
|
|
432
|
-
}
|
|
431
|
+
it('should process mixed string and object exports', () => {
|
|
432
|
+
const exportObject = {
|
|
433
|
+
'./src/utils': './src/utils',
|
|
434
|
+
'./src/component': {
|
|
435
|
+
client: './src/component.client',
|
|
436
|
+
server: './src/component.server'
|
|
433
437
|
}
|
|
434
438
|
};
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
testRoot,
|
|
440
|
-
config
|
|
439
|
+
const result = processObjectExport(exportObject, 'client');
|
|
440
|
+
expect(result['./src/utils'].file).toBe('./src/utils');
|
|
441
|
+
expect(result['./src/component'].file).toBe(
|
|
442
|
+
'./src/component.client'
|
|
441
443
|
);
|
|
444
|
+
});
|
|
442
445
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
server: './src/storage/filesystem.ts'
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
expect(result.exports['npm-package']).toEqual({
|
|
454
|
-
name: 'npm-package',
|
|
455
|
-
rewrite: false,
|
|
456
|
-
entryPoints: {
|
|
457
|
-
client: 'some-package',
|
|
458
|
-
server: 'some-package'
|
|
459
|
-
}
|
|
460
|
-
});
|
|
446
|
+
it('should handle string config values in export object', () => {
|
|
447
|
+
const exportObject = {
|
|
448
|
+
'./src/utils': './src/utils'
|
|
449
|
+
};
|
|
450
|
+
const result = processObjectExport(exportObject, 'client');
|
|
451
|
+
expect(result['./src/utils'].file).toBe('./src/utils');
|
|
461
452
|
});
|
|
462
453
|
|
|
463
|
-
it('should handle
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
'
|
|
468
|
-
entryPoints: {
|
|
469
|
-
client: './src/client-feature.ts',
|
|
470
|
-
server: false
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
'server-only': {
|
|
474
|
-
entryPoints: {
|
|
475
|
-
client: false,
|
|
476
|
-
server: './src/server-feature.ts'
|
|
477
|
-
}
|
|
478
|
-
}
|
|
454
|
+
it('should handle object config values in export object', () => {
|
|
455
|
+
const exportObject = {
|
|
456
|
+
'./src/component': {
|
|
457
|
+
client: './src/component.client',
|
|
458
|
+
server: './src/component.server'
|
|
479
459
|
}
|
|
480
460
|
};
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
testModuleName,
|
|
485
|
-
testRoot,
|
|
486
|
-
config
|
|
461
|
+
const result = processObjectExport(exportObject, 'client');
|
|
462
|
+
expect(result['./src/component'].file).toBe(
|
|
463
|
+
'./src/component.client'
|
|
487
464
|
);
|
|
465
|
+
});
|
|
488
466
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
rewrite: true,
|
|
493
|
-
entryPoints: {
|
|
494
|
-
client: './src/client-feature.ts',
|
|
495
|
-
server: false
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
expect(result.exports['server-only']).toEqual({
|
|
500
|
-
name: 'server-only',
|
|
501
|
-
rewrite: true,
|
|
502
|
-
entryPoints: {
|
|
503
|
-
client: false,
|
|
504
|
-
server: './src/server-feature.ts'
|
|
505
|
-
}
|
|
506
|
-
});
|
|
467
|
+
it('should handle empty export object', () => {
|
|
468
|
+
const result = processObjectExport({}, 'client');
|
|
469
|
+
expect(Object.keys(result)).toHaveLength(0);
|
|
507
470
|
});
|
|
508
471
|
});
|
|
509
472
|
|
|
510
|
-
describe('
|
|
511
|
-
it('should handle
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
simple: './src/simple.ts',
|
|
517
|
-
|
|
518
|
-
// Complete object with entryPoints
|
|
519
|
-
complex: {
|
|
520
|
-
entryPoints: {
|
|
521
|
-
client: './src/complex.client.ts',
|
|
522
|
-
server: './src/complex.server.ts'
|
|
523
|
-
},
|
|
524
|
-
rewrite: false
|
|
525
|
-
},
|
|
526
|
-
|
|
527
|
-
// Object with just input
|
|
528
|
-
'with-input': {
|
|
529
|
-
input: './src/with-input.ts'
|
|
530
|
-
},
|
|
531
|
-
|
|
532
|
-
// Object with just rewrite
|
|
533
|
-
'with-rewrite': {
|
|
534
|
-
rewrite: false
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
// Act
|
|
540
|
-
const result = parseModuleConfig(
|
|
541
|
-
testModuleName,
|
|
542
|
-
testRoot,
|
|
543
|
-
config
|
|
473
|
+
describe('resolveExportFile', () => {
|
|
474
|
+
it('should handle string config', () => {
|
|
475
|
+
const result = resolveExportFile(
|
|
476
|
+
'./src/component',
|
|
477
|
+
'client',
|
|
478
|
+
'component'
|
|
544
479
|
);
|
|
480
|
+
expect(result).toBe('./src/component');
|
|
481
|
+
});
|
|
545
482
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
expect(result.exports.complex).toEqual({
|
|
557
|
-
name: 'complex',
|
|
558
|
-
rewrite: false,
|
|
559
|
-
entryPoints: {
|
|
560
|
-
client: './src/complex.client.ts',
|
|
561
|
-
server: './src/complex.server.ts'
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
expect(result.exports['with-input']).toEqual({
|
|
566
|
-
name: 'with-input',
|
|
567
|
-
rewrite: true,
|
|
568
|
-
entryPoints: {
|
|
569
|
-
client: './src/with-input.ts',
|
|
570
|
-
server: './src/with-input.ts'
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
expect(result.exports['with-rewrite']).toEqual({
|
|
575
|
-
name: 'with-rewrite',
|
|
576
|
-
rewrite: false,
|
|
577
|
-
entryPoints: {
|
|
578
|
-
client: 'with-rewrite',
|
|
579
|
-
server: 'with-rewrite'
|
|
580
|
-
}
|
|
581
|
-
});
|
|
483
|
+
it('should return string config directly', () => {
|
|
484
|
+
const result = resolveExportFile(
|
|
485
|
+
'./src/component',
|
|
486
|
+
'client',
|
|
487
|
+
'component'
|
|
488
|
+
);
|
|
489
|
+
expect(result).toBe('./src/component');
|
|
582
490
|
});
|
|
583
|
-
});
|
|
584
491
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
exports: {
|
|
590
|
-
'test-export': {
|
|
591
|
-
input: './src/test.ts'
|
|
592
|
-
// rewrite not specified, should default to true
|
|
593
|
-
}
|
|
594
|
-
}
|
|
492
|
+
it('should resolve environment-specific paths', () => {
|
|
493
|
+
const config = {
|
|
494
|
+
client: './src/component.client',
|
|
495
|
+
server: './src/component.server'
|
|
595
496
|
};
|
|
497
|
+
const result = resolveExportFile(config, 'client', 'component');
|
|
498
|
+
expect(result).toBe('./src/component.client');
|
|
499
|
+
});
|
|
596
500
|
|
|
597
|
-
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
);
|
|
501
|
+
it('should return empty string when value is false', () => {
|
|
502
|
+
const config = {
|
|
503
|
+
client: false as const,
|
|
504
|
+
server: './src/component.server'
|
|
505
|
+
};
|
|
506
|
+
const result = resolveExportFile(config, 'client', 'component');
|
|
507
|
+
expect(result).toBe('');
|
|
508
|
+
});
|
|
603
509
|
|
|
604
|
-
|
|
605
|
-
|
|
510
|
+
it('should return name when value is empty string', () => {
|
|
511
|
+
const config = {
|
|
512
|
+
client: '',
|
|
513
|
+
server: './src/component.server'
|
|
514
|
+
};
|
|
515
|
+
const result = resolveExportFile(config, 'client', 'component');
|
|
516
|
+
expect(result).toBe('component');
|
|
606
517
|
});
|
|
607
518
|
|
|
608
|
-
it(
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
'fallback-test': {
|
|
613
|
-
// No input or entryPoints specified
|
|
614
|
-
rewrite: false
|
|
615
|
-
}
|
|
616
|
-
}
|
|
519
|
+
it("should return environment value when it's a string", () => {
|
|
520
|
+
const config = {
|
|
521
|
+
client: './src/component.client',
|
|
522
|
+
server: './src/component.server'
|
|
617
523
|
};
|
|
524
|
+
const result = resolveExportFile(config, 'client', 'component');
|
|
525
|
+
expect(result).toBe('./src/component.client');
|
|
526
|
+
});
|
|
618
527
|
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
);
|
|
528
|
+
it('should return name when environment value is undefined', () => {
|
|
529
|
+
const config = {
|
|
530
|
+
client: './src/component.client'
|
|
531
|
+
} as any;
|
|
532
|
+
const result = resolveExportFile(config, 'server', 'component');
|
|
533
|
+
expect(result).toBe('component');
|
|
534
|
+
});
|
|
625
535
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
536
|
+
it('should handle invalid config types gracefully', () => {
|
|
537
|
+
const result = resolveExportFile(
|
|
538
|
+
{} as any,
|
|
539
|
+
'client',
|
|
540
|
+
'component'
|
|
541
|
+
);
|
|
542
|
+
expect(result).toBe('component');
|
|
631
543
|
});
|
|
632
544
|
});
|
|
633
|
-
});
|
|
634
545
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
};
|
|
643
|
-
const config: ModuleConfig = { imports };
|
|
546
|
+
describe('processExportArray', () => {
|
|
547
|
+
it('should combine multiple export configurations', () => {
|
|
548
|
+
const exportArray = ['./src/component1', './src/component2'];
|
|
549
|
+
const result = processExportArray(exportArray, 'client');
|
|
550
|
+
expect(result['./src/component1']).toBeDefined();
|
|
551
|
+
expect(result['./src/component2']).toBeDefined();
|
|
552
|
+
});
|
|
644
553
|
|
|
645
|
-
|
|
646
|
-
|
|
554
|
+
it('should handle string items in export array', () => {
|
|
555
|
+
const exportArray = ['./src/component'];
|
|
556
|
+
const result = processExportArray(exportArray, 'client');
|
|
557
|
+
expect(result['./src/component']).toBeDefined();
|
|
558
|
+
});
|
|
647
559
|
|
|
648
|
-
|
|
649
|
-
|
|
560
|
+
it('should handle object items in export array', () => {
|
|
561
|
+
const exportArray = [
|
|
562
|
+
{
|
|
563
|
+
'./src/component': './src/component'
|
|
564
|
+
}
|
|
565
|
+
];
|
|
566
|
+
const result = processExportArray(exportArray, 'client');
|
|
567
|
+
expect(result['./src/component']).toBeDefined();
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
it('should handle empty export array', () => {
|
|
571
|
+
const result = processExportArray([], 'client');
|
|
572
|
+
expect(Object.keys(result)).toHaveLength(0);
|
|
573
|
+
});
|
|
650
574
|
});
|
|
651
575
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
576
|
+
describe('getEnvironmentExports', () => {
|
|
577
|
+
it('should merge default and user exports', () => {
|
|
578
|
+
const config: ModuleConfig = {
|
|
579
|
+
exports: ['./src/custom']
|
|
580
|
+
};
|
|
581
|
+
const result = getEnvironmentExports(config, 'client');
|
|
582
|
+
expect(result['src/entry.client']).toBeDefined();
|
|
583
|
+
expect(result['./src/custom']).toBeDefined();
|
|
584
|
+
});
|
|
655
585
|
|
|
656
|
-
|
|
657
|
-
|
|
586
|
+
it('should handle config without exports property', () => {
|
|
587
|
+
const result = getEnvironmentExports({}, 'client');
|
|
588
|
+
expect(result['src/entry.client']).toBeDefined();
|
|
589
|
+
});
|
|
658
590
|
|
|
659
|
-
|
|
660
|
-
|
|
591
|
+
it('should handle config with exports property', () => {
|
|
592
|
+
const config: ModuleConfig = {
|
|
593
|
+
exports: ['./src/custom']
|
|
594
|
+
};
|
|
595
|
+
const result = getEnvironmentExports(config, 'client');
|
|
596
|
+
expect(result['./src/custom']).toBeDefined();
|
|
597
|
+
});
|
|
661
598
|
});
|
|
599
|
+
});
|
|
662
600
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
601
|
+
describe('parsedExportValue', () => {
|
|
602
|
+
it('should handle pkg: prefixed exports', () => {
|
|
603
|
+
const result = parsedExportValue('pkg:lodash');
|
|
604
|
+
expect(result.name).toBe('lodash');
|
|
605
|
+
expect(result.pkg).toBe(true);
|
|
606
|
+
expect(result.file).toBe('lodash');
|
|
607
|
+
});
|
|
670
608
|
|
|
671
|
-
|
|
672
|
-
const result =
|
|
609
|
+
it('should handle root: prefixed exports', () => {
|
|
610
|
+
const result = parsedExportValue('root:src/component.tsx');
|
|
611
|
+
expect(result.name).toBe('src/component');
|
|
612
|
+
expect(result.pkg).toBe(false);
|
|
613
|
+
expect(result.file).toBe('./src/component.tsx');
|
|
614
|
+
});
|
|
673
615
|
|
|
674
|
-
|
|
675
|
-
|
|
616
|
+
it('should process regular file exports', () => {
|
|
617
|
+
const result = parsedExportValue('./src/component');
|
|
618
|
+
expect(result.name).toBe('./src/component');
|
|
619
|
+
expect(result.pkg).toBe(false);
|
|
620
|
+
expect(result.file).toBe('./src/component');
|
|
676
621
|
});
|
|
677
|
-
});
|
|
678
622
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
623
|
+
it('should handle pkg: prefixed values correctly', () => {
|
|
624
|
+
const result = parsedExportValue('pkg:@scope/package');
|
|
625
|
+
expect(result.name).toBe('@scope/package');
|
|
626
|
+
expect(result.pkg).toBe(true);
|
|
627
|
+
expect(result.file).toBe('@scope/package');
|
|
628
|
+
});
|
|
685
629
|
|
|
686
|
-
|
|
687
|
-
const result =
|
|
630
|
+
it('should handle root: prefixed values with extension removal', () => {
|
|
631
|
+
const result = parsedExportValue('root:src/component.tsx');
|
|
632
|
+
expect(result.name).toBe('src/component');
|
|
633
|
+
expect(result.pkg).toBe(false);
|
|
634
|
+
expect(result.file).toBe('./src/component.tsx');
|
|
635
|
+
});
|
|
688
636
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
expect(result.
|
|
692
|
-
expect(result.
|
|
693
|
-
expect(
|
|
637
|
+
it('should handle root: prefixed values without extensions', () => {
|
|
638
|
+
const result = parsedExportValue('root:src/utils');
|
|
639
|
+
expect(result.name).toBe('src/utils');
|
|
640
|
+
expect(result.pkg).toBe(false);
|
|
641
|
+
expect(result.file).toBe('./src/utils');
|
|
694
642
|
});
|
|
695
643
|
|
|
696
|
-
it('should handle
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
644
|
+
it('should handle regular values without prefixes', () => {
|
|
645
|
+
const result = parsedExportValue('./src/component.tsx');
|
|
646
|
+
expect(result.name).toBe('./src/component.tsx');
|
|
647
|
+
expect(result.pkg).toBe(false);
|
|
648
|
+
expect(result.file).toBe('./src/component.tsx');
|
|
649
|
+
});
|
|
701
650
|
|
|
702
|
-
|
|
703
|
-
const result =
|
|
651
|
+
it('should preserve file extensions for non-root exports', () => {
|
|
652
|
+
const result = parsedExportValue('./src/component.tsx');
|
|
653
|
+
expect(result.file).toBe('./src/component.tsx');
|
|
654
|
+
});
|
|
704
655
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
expect(result.
|
|
708
|
-
expect(result.
|
|
709
|
-
expect(
|
|
656
|
+
it('should handle malformed pkg: values', () => {
|
|
657
|
+
const result = parsedExportValue('pkg:');
|
|
658
|
+
expect(result.name).toBe('');
|
|
659
|
+
expect(result.pkg).toBe(true);
|
|
660
|
+
expect(result.file).toBe('');
|
|
710
661
|
});
|
|
711
662
|
|
|
712
|
-
it('should handle
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
};
|
|
663
|
+
it('should handle malformed root: values', () => {
|
|
664
|
+
const result = parsedExportValue('root:');
|
|
665
|
+
expect(result.name).toBe('');
|
|
666
|
+
expect(result.pkg).toBe(false);
|
|
667
|
+
expect(result.file).toBe('./');
|
|
668
|
+
});
|
|
719
669
|
|
|
720
|
-
|
|
721
|
-
const result =
|
|
670
|
+
it('should handle file extensions correctly in root: prefix', () => {
|
|
671
|
+
const result = parsedExportValue('root:src/component.tsx');
|
|
672
|
+
expect(result.name).toBe('src/component');
|
|
673
|
+
expect(result.file).toBe('./src/component.tsx');
|
|
674
|
+
});
|
|
722
675
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
expect(result.
|
|
726
|
-
expect(result.
|
|
727
|
-
expect(result.
|
|
676
|
+
it('should handle nested paths in pkg: prefix', () => {
|
|
677
|
+
const result = parsedExportValue('pkg:@scope/package/subpath');
|
|
678
|
+
expect(result.name).toBe('@scope/package/subpath');
|
|
679
|
+
expect(result.pkg).toBe(true);
|
|
680
|
+
expect(result.file).toBe('@scope/package/subpath');
|
|
728
681
|
});
|
|
682
|
+
});
|
|
729
683
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
const specialModuleName = 'test-module_with.special@chars';
|
|
684
|
+
describe('Integration Tests', () => {
|
|
685
|
+
it('should work end-to-end with complex configuration', () => {
|
|
733
686
|
const config: ModuleConfig = {
|
|
734
687
|
links: {
|
|
735
|
-
|
|
688
|
+
shared: '/shared/modules'
|
|
736
689
|
},
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
690
|
+
imports: {
|
|
691
|
+
react: 'react',
|
|
692
|
+
vue: {
|
|
693
|
+
client: 'vue',
|
|
694
|
+
server: 'vue/server'
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
scopes: {
|
|
698
|
+
utils: {
|
|
699
|
+
lodash: 'lodash'
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
exports: [
|
|
703
|
+
'./src/component',
|
|
704
|
+
{
|
|
705
|
+
'./src/utils': {
|
|
706
|
+
client: './src/utils.client',
|
|
707
|
+
server: './src/utils.server'
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
]
|
|
740
711
|
};
|
|
741
|
-
|
|
742
|
-
// Act
|
|
743
712
|
const result = parseModuleConfig(
|
|
744
|
-
|
|
745
|
-
|
|
713
|
+
'test-module',
|
|
714
|
+
'/test/root',
|
|
746
715
|
config
|
|
747
716
|
);
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
expect(result.
|
|
751
|
-
expect(result.
|
|
752
|
-
expect(result.
|
|
717
|
+
expect(result.name).toBe('test-module');
|
|
718
|
+
expect(result.links.shared).toBeDefined();
|
|
719
|
+
expect(result.environments.client.imports.react).toBe('react');
|
|
720
|
+
expect(result.environments.client.imports.vue).toBe('vue');
|
|
721
|
+
expect(result.environments.server.imports.vue).toBe('vue/server');
|
|
753
722
|
});
|
|
754
|
-
});
|
|
755
723
|
|
|
756
|
-
|
|
757
|
-
it('should maintain type safety for ParsedModuleConfig', () => {
|
|
758
|
-
// Arrange
|
|
724
|
+
it('should correctly filter environment-specific exports', () => {
|
|
759
725
|
const config: ModuleConfig = {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
726
|
+
exports: [
|
|
727
|
+
{
|
|
728
|
+
'./src/component': {
|
|
729
|
+
client: './src/component.client',
|
|
730
|
+
server: './src/component.server'
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
]
|
|
763
734
|
};
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
735
|
+
const clientResult = parseModuleConfig(
|
|
736
|
+
'test-module',
|
|
737
|
+
'/test/root',
|
|
738
|
+
config
|
|
739
|
+
);
|
|
740
|
+
const serverResult = parseModuleConfig(
|
|
741
|
+
'test-module',
|
|
742
|
+
'/test/root',
|
|
769
743
|
config
|
|
770
744
|
);
|
|
771
745
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
expect(
|
|
776
|
-
|
|
777
|
-
|
|
746
|
+
expect(
|
|
747
|
+
clientResult.environments.client.exports['./src/component'].file
|
|
748
|
+
).toBe('./src/component.client');
|
|
749
|
+
expect(
|
|
750
|
+
serverResult.environments.server.exports['./src/component'].file
|
|
751
|
+
).toBe('./src/component.server');
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
it('should maintain cross-environment consistency', () => {
|
|
755
|
+
const result = parseModuleConfig('test-module', '/test/root');
|
|
756
|
+
expect(
|
|
757
|
+
result.environments.client.exports['src/entry.client'].file
|
|
758
|
+
).toBe('./src/entry.client');
|
|
759
|
+
expect(
|
|
760
|
+
result.environments.server.exports['src/entry.server'].file
|
|
761
|
+
).toBe('./src/entry.server');
|
|
778
762
|
});
|
|
779
763
|
|
|
780
|
-
it('should
|
|
781
|
-
// Arrange
|
|
764
|
+
it('should work with path resolution across different environments', () => {
|
|
782
765
|
const config: ModuleConfig = {
|
|
783
|
-
|
|
766
|
+
links: {
|
|
767
|
+
relative: 'relative/path'
|
|
768
|
+
}
|
|
784
769
|
};
|
|
770
|
+
const result = parseModuleConfig(
|
|
771
|
+
'test-module',
|
|
772
|
+
'/test/root',
|
|
773
|
+
config
|
|
774
|
+
);
|
|
775
|
+
expect(result.links.relative.root).toBe('relative/path');
|
|
776
|
+
});
|
|
777
|
+
});
|
|
785
778
|
|
|
786
|
-
|
|
787
|
-
|
|
779
|
+
describe('Error Handling', () => {
|
|
780
|
+
it('should handle invalid config types gracefully in resolveExportFile', () => {
|
|
781
|
+
const result = resolveExportFile({} as any, 'client', 'component');
|
|
782
|
+
expect(result).toBe('component');
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
it('should handle malformed pkg: values in parsedExportValue', () => {
|
|
786
|
+
const result = parsedExportValue('pkg:');
|
|
787
|
+
expect(result.name).toBe('');
|
|
788
|
+
expect(result.pkg).toBe(true);
|
|
789
|
+
});
|
|
788
790
|
|
|
789
|
-
|
|
790
|
-
const
|
|
791
|
-
expect(
|
|
792
|
-
expect(
|
|
793
|
-
expect(typeof exportConfig.entryPoints).toBe('object');
|
|
794
|
-
expect(typeof exportConfig.entryPoints.client).toBe('string');
|
|
795
|
-
expect(typeof exportConfig.entryPoints.server).toBe('string');
|
|
791
|
+
it('should handle malformed root: values in parsedExportValue', () => {
|
|
792
|
+
const result = parsedExportValue('root:');
|
|
793
|
+
expect(result.name).toBe('');
|
|
794
|
+
expect(result.pkg).toBe(false);
|
|
796
795
|
});
|
|
797
796
|
});
|
|
798
797
|
});
|