@walkeros/config 1.0.2 → 1.1.0-next-1771252576264
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/jest/index.mjs +66 -48
- package/package.json +1 -2
- package/tsconfig/base.json +2 -0
- package/tsup/__tests__/toSerializable.test.mjs +220 -0
- package/tsup/index.mjs +125 -2
package/jest/index.mjs
CHANGED
|
@@ -1,57 +1,75 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
|
-
import { readFileSync } from 'fs';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
function getDirectory(dir) {
|
|
15
|
-
return path.join(packagesDir, dir);
|
|
3
|
+
import { existsSync, readdirSync, readFileSync, realpathSync } from 'fs';
|
|
4
|
+
|
|
5
|
+
// Resolve symlinks so import.meta.url always points to the real file path,
|
|
6
|
+
// even when Jest resolves through node_modules symlinks.
|
|
7
|
+
const configDir = realpathSync(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
const packagesDir = path.join(configDir, '..', '..', '..', '/');
|
|
9
|
+
|
|
10
|
+
function escapeRegex(str) {
|
|
11
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
function getModuleMapper() {
|
|
19
|
-
|
|
15
|
+
const mapper = {};
|
|
16
|
+
const scanDir = path.join(packagesDir, 'packages');
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
18
|
+
function scanForPackages(dir) {
|
|
19
|
+
if (!existsSync(dir)) return;
|
|
20
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
21
|
+
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
if (!entry.isDirectory()) continue;
|
|
24
|
+
if (entry.name === 'node_modules' || entry.name === 'dist') continue;
|
|
25
|
+
|
|
26
|
+
const fullPath = path.join(dir, entry.name);
|
|
27
|
+
const pkgJsonPath = path.join(fullPath, 'package.json');
|
|
28
|
+
|
|
29
|
+
if (existsSync(pkgJsonPath)) {
|
|
30
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
|
|
31
|
+
|
|
32
|
+
if (pkg.name?.startsWith('@walkeros/') && existsSync(path.join(fullPath, 'src'))) {
|
|
33
|
+
// Map root export: @walkeros/core → packages/core/src/
|
|
34
|
+
mapper[`^${escapeRegex(pkg.name)}$`] = path.join(fullPath, 'src/');
|
|
35
|
+
|
|
36
|
+
// Map subpath exports: @walkeros/core/dev → packages/core/src/dev
|
|
37
|
+
if (pkg.exports) {
|
|
38
|
+
for (const subpath of Object.keys(pkg.exports)) {
|
|
39
|
+
if (subpath === '.' || !subpath.startsWith('./')) continue;
|
|
40
|
+
const subName = subpath.slice(2);
|
|
41
|
+
const srcFile = path.join(fullPath, 'src', subName);
|
|
42
|
+
if (
|
|
43
|
+
existsSync(srcFile + '.ts') ||
|
|
44
|
+
existsSync(srcFile + '.tsx') ||
|
|
45
|
+
existsSync(path.join(srcFile, 'index.ts'))
|
|
46
|
+
) {
|
|
47
|
+
mapper[`^${escapeRegex(pkg.name)}/${escapeRegex(subName)}$`] = srcFile;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Recurse into subdirectories (handles packages/web/core/, packages/server/destinations/api/, etc.)
|
|
55
|
+
scanForPackages(fullPath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
scanForPackages(path.join(packagesDir, 'packages'));
|
|
60
|
+
|
|
61
|
+
if (Object.keys(mapper).length === 0) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`[jest-config] moduleNameMapper is empty — no @walkeros/* packages found.\n` +
|
|
64
|
+
` packagesDir: ${packagesDir}\n` +
|
|
65
|
+
` scanDir: ${scanDir}\n` +
|
|
66
|
+
` scanDir exists: ${existsSync(scanDir)}\n` +
|
|
67
|
+
`This usually means a stale @walkeros/config copy was loaded from node_modules ` +
|
|
68
|
+
`instead of the workspace version. Run: npm dedupe @walkeros/config`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return mapper;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
75
|
function getGlobals() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/config",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0-next-1771252576264",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared development configuration for walkerOS packages (TypeScript, ESLint, Jest, tsup)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,7 +60,6 @@
|
|
|
60
60
|
"url": "https://github.com/elbwalker/walkerOS/issues"
|
|
61
61
|
},
|
|
62
62
|
"keywords": [
|
|
63
|
-
"walker",
|
|
64
63
|
"walkerOS",
|
|
65
64
|
"config",
|
|
66
65
|
"typescript",
|
package/tsconfig/base.json
CHANGED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { toSerializable } from '../index.mjs';
|
|
2
|
+
|
|
3
|
+
describe('toSerializable', () => {
|
|
4
|
+
// Primitives
|
|
5
|
+
it('passes through strings', () => {
|
|
6
|
+
expect(toSerializable('hello')).toBe('hello');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('passes through numbers', () => {
|
|
10
|
+
expect(toSerializable(42)).toBe(42);
|
|
11
|
+
expect(toSerializable(0)).toBe(0);
|
|
12
|
+
expect(toSerializable(-1.5)).toBe(-1.5);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('passes through booleans', () => {
|
|
16
|
+
expect(toSerializable(true)).toBe(true);
|
|
17
|
+
expect(toSerializable(false)).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('passes through null', () => {
|
|
21
|
+
expect(toSerializable(null)).toBeNull();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('passes through undefined', () => {
|
|
25
|
+
expect(toSerializable(undefined)).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Functions
|
|
29
|
+
it('converts functions to $code objects', () => {
|
|
30
|
+
const fn = () => 'test';
|
|
31
|
+
const result = toSerializable(fn);
|
|
32
|
+
expect(result).toEqual({ $code: fn.toString() });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('converts named functions to $code objects', () => {
|
|
36
|
+
function myFunc(a, b) {
|
|
37
|
+
return a + b;
|
|
38
|
+
}
|
|
39
|
+
const result = toSerializable(myFunc);
|
|
40
|
+
expect(result).toHaveProperty('$code');
|
|
41
|
+
expect(result.$code).toContain('myFunc');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Zod schema instances (objects with _def.typeName starting with 'Zod')
|
|
45
|
+
it('should filter out Zod schema instances', () => {
|
|
46
|
+
const zodSchema = {
|
|
47
|
+
parse: (val) => val,
|
|
48
|
+
safeParse: (val) => ({ success: true, data: val }),
|
|
49
|
+
_def: { typeName: 'ZodObject' },
|
|
50
|
+
};
|
|
51
|
+
expect(toSerializable(zodSchema)).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('filters out other Zod types', () => {
|
|
55
|
+
const zodString = { parse: () => {}, _def: { typeName: 'ZodString' } };
|
|
56
|
+
expect(toSerializable(zodString)).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('filters out Zod 4 instances (have _zod property)', () => {
|
|
60
|
+
// Zod 4 instances have _zod but no _def.typeName
|
|
61
|
+
const zod4Schema = {
|
|
62
|
+
parse: () => {},
|
|
63
|
+
safeParse: () => {},
|
|
64
|
+
_def: { type: 'object', shape: {} },
|
|
65
|
+
_zod: { def: {}, constr: {}, traits: new Set(), bag: {} },
|
|
66
|
+
};
|
|
67
|
+
expect(toSerializable(zod4Schema)).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('filters out Zod 4 instances from nested objects', () => {
|
|
71
|
+
const obj = {
|
|
72
|
+
settings: { type: 'object', properties: { url: { type: 'string' } } },
|
|
73
|
+
SettingsSchema: {
|
|
74
|
+
parse: () => {},
|
|
75
|
+
_zod: { def: {}, constr: {} },
|
|
76
|
+
},
|
|
77
|
+
MappingSchema: {
|
|
78
|
+
parse: () => {},
|
|
79
|
+
_def: { type: 'object' },
|
|
80
|
+
_zod: { def: {} },
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
const result = toSerializable(obj);
|
|
84
|
+
expect(result).toEqual({
|
|
85
|
+
settings: { type: 'object', properties: { url: { type: 'string' } } },
|
|
86
|
+
});
|
|
87
|
+
expect(result).not.toHaveProperty('SettingsSchema');
|
|
88
|
+
expect(result).not.toHaveProperty('MappingSchema');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should NOT filter out non-Zod objects that have a .parse method', () => {
|
|
92
|
+
const csvParser = { parse: (str) => str.split(','), data: [1, 2, 3] };
|
|
93
|
+
const result = toSerializable(csvParser);
|
|
94
|
+
expect(result).toEqual({ data: [1, 2, 3], parse: { $code: csvParser.parse.toString() } });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Plain objects
|
|
98
|
+
it('passes through plain objects', () => {
|
|
99
|
+
const obj = { a: 1, b: 'two', c: true };
|
|
100
|
+
expect(toSerializable(obj)).toEqual({ a: 1, b: 'two', c: true });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('handles nested objects', () => {
|
|
104
|
+
const obj = { outer: { inner: { value: 42 } } };
|
|
105
|
+
expect(toSerializable(obj)).toEqual({ outer: { inner: { value: 42 } } });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('strips Zod instances from nested objects', () => {
|
|
109
|
+
const obj = {
|
|
110
|
+
settings: { type: 'object', properties: {} },
|
|
111
|
+
SettingsSchema: { parse: () => {}, _def: { typeName: 'ZodObject' } },
|
|
112
|
+
};
|
|
113
|
+
const result = toSerializable(obj);
|
|
114
|
+
expect(result).toEqual({
|
|
115
|
+
settings: { type: 'object', properties: {} },
|
|
116
|
+
});
|
|
117
|
+
expect(result).not.toHaveProperty('SettingsSchema');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('converts nested functions to $code', () => {
|
|
121
|
+
const noop = () => {};
|
|
122
|
+
const obj = {
|
|
123
|
+
name: 'test',
|
|
124
|
+
handler: noop,
|
|
125
|
+
nested: { callback: noop },
|
|
126
|
+
};
|
|
127
|
+
const result = toSerializable(obj);
|
|
128
|
+
expect(result.name).toBe('test');
|
|
129
|
+
expect(result.handler).toEqual({ $code: noop.toString() });
|
|
130
|
+
expect(result.nested.callback).toEqual({ $code: noop.toString() });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Arrays
|
|
134
|
+
it('passes through arrays of primitives', () => {
|
|
135
|
+
expect(toSerializable([1, 2, 3])).toEqual([1, 2, 3]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('replaces Zod instances in arrays with undefined (preserves indices)', () => {
|
|
139
|
+
const arr = [
|
|
140
|
+
{ name: 'keep' },
|
|
141
|
+
{ parse: () => {}, _def: { typeName: 'ZodString' } },
|
|
142
|
+
{ name: 'also keep' },
|
|
143
|
+
];
|
|
144
|
+
const result = toSerializable(arr);
|
|
145
|
+
expect(result).toEqual([{ name: 'keep' }, undefined, { name: 'also keep' }]);
|
|
146
|
+
expect(result).toHaveLength(3);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('converts functions inside arrays', () => {
|
|
150
|
+
const fn = () => 'test';
|
|
151
|
+
const result = toSerializable([1, fn, 'three']);
|
|
152
|
+
expect(result).toEqual([1, { $code: fn.toString() }, 'three']);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('handles nested arrays', () => {
|
|
156
|
+
const result = toSerializable([[1, 2], [3, 4]]);
|
|
157
|
+
expect(result).toEqual([[1, 2], [3, 4]]);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Complex/realistic scenario
|
|
161
|
+
it('handles a realistic dev module export structure', () => {
|
|
162
|
+
const noop = () => Promise.resolve({ ok: true });
|
|
163
|
+
const devExports = {
|
|
164
|
+
env: {
|
|
165
|
+
init: { sendServer: undefined },
|
|
166
|
+
standard: { sendServer: noop },
|
|
167
|
+
},
|
|
168
|
+
events: {
|
|
169
|
+
pageView: { event: 'page view', data: { title: 'Home' } },
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const result = toSerializable(devExports);
|
|
174
|
+
|
|
175
|
+
// sendServer undefined should be stripped (key omitted)
|
|
176
|
+
expect(result.env.init).toEqual({});
|
|
177
|
+
// sendServer function should become $code
|
|
178
|
+
expect(result.env.standard.sendServer).toHaveProperty('$code');
|
|
179
|
+
expect(result.env.standard.sendServer.$code).toContain('Promise.resolve');
|
|
180
|
+
// Plain data passes through
|
|
181
|
+
expect(result.events.pageView).toEqual({
|
|
182
|
+
event: 'page view',
|
|
183
|
+
data: { title: 'Home' },
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// JSON roundtrip safety
|
|
188
|
+
it('produces JSON-safe output', () => {
|
|
189
|
+
const fn = (a) => a * 2;
|
|
190
|
+
const input = {
|
|
191
|
+
name: 'test',
|
|
192
|
+
handler: fn,
|
|
193
|
+
zodSchema: { parse: () => {}, _def: { typeName: 'ZodObject' } },
|
|
194
|
+
data: [1, 'two', { nested: true }],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const result = toSerializable(input);
|
|
198
|
+
const json = JSON.stringify(result);
|
|
199
|
+
const parsed = JSON.parse(json);
|
|
200
|
+
|
|
201
|
+
expect(parsed.name).toBe('test');
|
|
202
|
+
expect(parsed.handler.$code).toContain('a * 2');
|
|
203
|
+
expect(parsed).not.toHaveProperty('zodSchema');
|
|
204
|
+
expect(parsed.data).toEqual([1, 'two', { nested: true }]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Edge cases
|
|
208
|
+
it('handles empty objects', () => {
|
|
209
|
+
expect(toSerializable({})).toEqual({});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('handles empty arrays', () => {
|
|
213
|
+
expect(toSerializable([])).toEqual([]);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('does not treat objects with non-function .parse as Zod', () => {
|
|
217
|
+
const obj = { parse: 'not a function', value: 42 };
|
|
218
|
+
expect(toSerializable(obj)).toEqual({ parse: 'not a function', value: 42 });
|
|
219
|
+
});
|
|
220
|
+
});
|
package/tsup/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from 'tsup';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
import { resolve } from 'path';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
3
|
+
import { resolve, join } from 'path';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
4
5
|
|
|
5
6
|
const baseConfig = {
|
|
6
7
|
entry: ['src/index.ts'],
|
|
@@ -73,11 +74,133 @@ const buildES5 = (customConfig = {}) => ({
|
|
|
73
74
|
...customConfig,
|
|
74
75
|
});
|
|
75
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Deep-clone a value for JSON serialization.
|
|
79
|
+
*
|
|
80
|
+
* Conventions:
|
|
81
|
+
* - Functions → { $code: fn.toString() } — serialized source for documentation, not executable
|
|
82
|
+
* - Zod instances → filtered out (returns undefined)
|
|
83
|
+
* Zod 3: detected via _def.typeName starting with 'Zod'
|
|
84
|
+
* Zod 4: detected via _zod property
|
|
85
|
+
* - Everything else → recursively passed through
|
|
86
|
+
*/
|
|
87
|
+
const toSerializable = (value) => {
|
|
88
|
+
if (value === null || value === undefined) return value;
|
|
89
|
+
if (typeof value === 'function') return { $code: value.toString() };
|
|
90
|
+
if (
|
|
91
|
+
typeof value === 'object' &&
|
|
92
|
+
(value._def?.typeName?.startsWith?.('Zod') || '_zod' in value)
|
|
93
|
+
)
|
|
94
|
+
return undefined;
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
return value.map((item) => toSerializable(item));
|
|
97
|
+
}
|
|
98
|
+
if (typeof value === 'object') {
|
|
99
|
+
const result = {};
|
|
100
|
+
for (const [key, val] of Object.entries(value)) {
|
|
101
|
+
const serialized = toSerializable(val);
|
|
102
|
+
if (serialized !== undefined) result[key] = serialized;
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
return value;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Dev build: builds src/dev.ts and generates walkerOS.json
|
|
110
|
+
const buildDev = (customConfig = {}) => {
|
|
111
|
+
const { onSuccess: customOnSuccess, ...restConfig } = customConfig;
|
|
112
|
+
|
|
113
|
+
const modulesConfig = buildModules({
|
|
114
|
+
entry: ['src/dev.ts'],
|
|
115
|
+
...restConfig,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...modulesConfig,
|
|
120
|
+
async onSuccess() {
|
|
121
|
+
const cwd = process.cwd();
|
|
122
|
+
const packagePath = resolve(cwd, 'package.json');
|
|
123
|
+
let pkg = { name: 'unknown', version: '0.0.0' };
|
|
124
|
+
try {
|
|
125
|
+
pkg = JSON.parse(readFileSync(packagePath, 'utf8'));
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.warn('[buildDev] Could not read package.json:', error.message);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check the built module exists
|
|
131
|
+
const devMjsPath = resolve(cwd, 'dist/dev.mjs');
|
|
132
|
+
if (!existsSync(devMjsPath)) {
|
|
133
|
+
console.warn('[buildDev] dist/dev.mjs not found, skipping walkerOS.json generation');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Import the built module (cache-bust for watch mode rebuilds)
|
|
138
|
+
const devModulePath = pathToFileURL(devMjsPath).href;
|
|
139
|
+
let devModule;
|
|
140
|
+
try {
|
|
141
|
+
devModule = await import(`${devModulePath}?t=${Date.now()}`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn(
|
|
144
|
+
`[buildDev] Could not import dist/dev.mjs: ${error.message}. Skipping walkerOS.json generation`,
|
|
145
|
+
);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Extract schemas (Zod instances filtered by toSerializable)
|
|
150
|
+
const schemas = toSerializable(devModule.schemas || {}) || {};
|
|
151
|
+
|
|
152
|
+
// Extract examples (convert functions to $code strings)
|
|
153
|
+
const rawExamples = devModule.examples || {};
|
|
154
|
+
const examples = toSerializable(rawExamples) || {};
|
|
155
|
+
|
|
156
|
+
// Read type and platform from package.json walkerOS field
|
|
157
|
+
const walkerOS = pkg.walkerOS || {};
|
|
158
|
+
const meta = { package: pkg.name, version: pkg.version };
|
|
159
|
+
if (walkerOS.type) meta.type = walkerOS.type;
|
|
160
|
+
if (walkerOS.platform) meta.platform = walkerOS.platform;
|
|
161
|
+
|
|
162
|
+
const output = { $meta: meta, schemas, examples };
|
|
163
|
+
|
|
164
|
+
// Validate
|
|
165
|
+
if (Object.keys(schemas).length === 0) {
|
|
166
|
+
console.warn('[buildDev] Warning: schemas is empty');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Verify valid JSON roundtrip
|
|
170
|
+
const jsonString = JSON.stringify(output, null, 2);
|
|
171
|
+
try {
|
|
172
|
+
JSON.parse(jsonString);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(
|
|
175
|
+
'[buildDev] Error: output is not valid JSON:',
|
|
176
|
+
error.message,
|
|
177
|
+
);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Write to dist/walkerOS.json
|
|
182
|
+
const outDir = resolve(cwd, 'dist');
|
|
183
|
+
mkdirSync(outDir, { recursive: true });
|
|
184
|
+
writeFileSync(join(outDir, 'walkerOS.json'), jsonString);
|
|
185
|
+
console.log(
|
|
186
|
+
`[buildDev] Generated dist/walkerOS.json for ${pkg.name}@${pkg.version}`,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// Run custom onSuccess if provided
|
|
190
|
+
if (typeof customOnSuccess === 'function') {
|
|
191
|
+
await customOnSuccess();
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
|
|
76
197
|
export {
|
|
77
198
|
baseConfig,
|
|
78
199
|
buildModules,
|
|
79
200
|
buildExamples,
|
|
80
201
|
buildBrowser,
|
|
81
202
|
buildES5,
|
|
203
|
+
buildDev,
|
|
204
|
+
toSerializable,
|
|
82
205
|
defineConfig,
|
|
83
206
|
};
|