@tixyel/cli 2.7.0 → 3.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.
package/dist/widget.js DELETED
@@ -1,551 +0,0 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
2
- import { minify as minifyHTML } from 'html-minifier-terser';
3
- import JavaScriptObfuscator from 'javascript-obfuscator';
4
- import { dirname, join, relative, resolve } from 'path';
5
- import { readFile as readFilePromise } from 'fs/promises';
6
- import { renderToStaticMarkup } from 'react-dom/server';
7
- import { mkdir, writeFile } from 'fs/promises';
8
- import autoprefixer from 'autoprefixer';
9
- import { isValidElement } from 'react';
10
- import { parse } from 'jsonc-parser';
11
- import nested from 'postcss-nested';
12
- import FastGlob from 'fast-glob';
13
- import inquirer from 'inquirer';
14
- import postcss from 'postcss';
15
- import cssnano from 'cssnano';
16
- import JSZip from 'jszip';
17
- import { transformSync } from 'esbuild';
18
- import { watermark } from './utils/watermark.js';
19
- export async function createWidget(path, metadata, config, root) {
20
- try {
21
- console.log(`📁 Creating ${metadata?.name} at: ${path}`);
22
- // Create directory
23
- await mkdir(path, { recursive: true });
24
- // Calculate config path if workspace root is provided
25
- const configPath = root ? getConfigPathFromWidget(path, root) : undefined;
26
- // Prompt for metadata if not provided
27
- const widgetMetadata = await getMetadata(metadata);
28
- // Create .tixyel configuration
29
- const dotTixyel = {
30
- name: metadata?.name,
31
- version: '0.0.0',
32
- description: widgetMetadata?.description || '',
33
- config: configPath,
34
- metadata: {
35
- ...config.metadata,
36
- ...widgetMetadata,
37
- name: undefined,
38
- description: undefined,
39
- },
40
- dirs: config.dirs || {
41
- entry: 'development',
42
- output: 'finished',
43
- compacted: 'compacted',
44
- },
45
- };
46
- await writeFile(resolve(path, '.tixyel'), JSON.stringify(dotTixyel, null, 2), 'utf-8');
47
- // Create scaffold files from the workspace config
48
- const scaffold = config.scaffold || [];
49
- let created = { files: 0, folders: 0 };
50
- async function serializeScaffoldContent(content) {
51
- if (content === undefined || content === null)
52
- return '';
53
- if (typeof content === 'string')
54
- return content;
55
- if (isValidElement(content)) {
56
- return renderToStaticMarkup(content);
57
- }
58
- // Fallback to string conversion for unexpected types
59
- return String(content ?? '');
60
- }
61
- async function processScaffoldItem(item, basePath) {
62
- const fullPath = resolve(basePath, item.name);
63
- if (item.type === 'folder') {
64
- await mkdir(fullPath, { recursive: true });
65
- created.folders++;
66
- // Process folder children if any
67
- if (item.content && Array.isArray(item.content) && item.content.length) {
68
- for (const child of item.content) {
69
- await processScaffoldItem(child, fullPath);
70
- }
71
- }
72
- }
73
- else if (item.type === 'file') {
74
- const content = await serializeScaffoldContent(item.content);
75
- await writeFile(fullPath, content, 'utf-8');
76
- created.files++;
77
- }
78
- }
79
- for (const item of scaffold) {
80
- await processScaffoldItem(item, path);
81
- }
82
- console.log(`✅ Widget ${dotTixyel.name} created successfully!`);
83
- if (dotTixyel.description && dotTixyel.description.length) {
84
- console.log(` - Description: ${dotTixyel.description}`);
85
- }
86
- if (dotTixyel.metadata?.tags && dotTixyel.metadata?.tags.length) {
87
- console.log(` - Tags: ${dotTixyel.metadata.tags.join(', ')}`);
88
- }
89
- if (dotTixyel.config) {
90
- console.log(` - Config Path: ${dotTixyel.config}`);
91
- }
92
- if (created.folders > 0 || created.files > 0) {
93
- console.log(` - Scaffolded: ${created.folders} folders, ${created.files} files`);
94
- }
95
- }
96
- catch (error) {
97
- console.error('❌ Failed to create widget:', error);
98
- throw error;
99
- }
100
- }
101
- async function getMetadata(existingMetadata) {
102
- const answers = await inquirer.prompt([
103
- {
104
- type: 'input',
105
- name: 'description',
106
- message: 'Widget description:',
107
- default: existingMetadata?.description || '',
108
- },
109
- {
110
- type: 'input',
111
- name: 'tags',
112
- message: 'Widget tags (comma-separated):',
113
- default: existingMetadata?.tags ? existingMetadata.tags.join(', ') : '',
114
- },
115
- ]);
116
- const tagsArray = answers.tags
117
- ? answers.tags
118
- .split(',')
119
- .map((tag) => tag.trim())
120
- .filter((tag) => tag.length)
121
- : [];
122
- return {
123
- description: answers.description,
124
- tags: tagsArray,
125
- };
126
- }
127
- function getConfigPathFromWidget(widgetPath, workspaceRoot) {
128
- const configTs = resolve(workspaceRoot, 'tixyel.config.ts');
129
- const configJs = resolve(workspaceRoot, 'tixyel.config.js');
130
- const configPathMjs = resolve(workspaceRoot, 'tixyel.config.mjs');
131
- const targetConfig = existsSync(configTs) ? configTs : existsSync(configJs) ? configJs : existsSync(configPathMjs) ? configPathMjs : null;
132
- if (!targetConfig) {
133
- throw new Error('❌ Workspace configuration file not found.');
134
- }
135
- const relativePath = relative(widgetPath, targetConfig);
136
- const normalized = relativePath.replace(/\\/g, '/');
137
- return normalized.startsWith('.') ? normalized : `./${normalized}`;
138
- }
139
- export async function getNextWidgetNumber(parentPath) {
140
- try {
141
- if (!existsSync(parentPath)) {
142
- return '01';
143
- }
144
- const entries = readdirSync(parentPath);
145
- const widgetNumbers = entries
146
- .filter((name) => /^\d+\s*-\s*/.test(name))
147
- .map((name) => parseInt(name.split('-')[0], 10))
148
- .filter((num) => !isNaN(num));
149
- const maxNum = widgetNumbers.length > 0 ? Math.max(...widgetNumbers) : 0;
150
- return String(maxNum + 1).padStart(2, '0');
151
- }
152
- catch (error) {
153
- return '01';
154
- }
155
- }
156
- async function merge(config) {
157
- const merged = {
158
- ...config,
159
- version: config.version || '0.0.0',
160
- description: config.description || '',
161
- metadata: {
162
- ...config.metadata,
163
- },
164
- dirs: {
165
- entry: 'development',
166
- output: 'finished',
167
- compacted: 'compacted',
168
- ...config.dirs,
169
- },
170
- };
171
- return merged;
172
- }
173
- export function validateDotTixyel(config) {
174
- if (typeof config !== 'object' || !config || config === null || !config.name || typeof config.name !== 'string' || !config.name.trim().length) {
175
- throw new Error('❌ Invalid .tixyel: "name" is required and must be a non-empty string.');
176
- }
177
- return true;
178
- }
179
- export async function readDotTixyel(path) {
180
- try {
181
- const dotTixyelPath = resolve(path, '.tixyel');
182
- if (!existsSync(dotTixyelPath)) {
183
- return null;
184
- }
185
- const content = await readFilePromise(dotTixyelPath, 'utf-8');
186
- const config = parse(content);
187
- if (!validateDotTixyel(config)) {
188
- console.error(`Invalid .tixyel configuration in ${path}`);
189
- return null;
190
- }
191
- return merge(config);
192
- }
193
- catch (error) {
194
- return null;
195
- }
196
- }
197
- export async function findWidgets(root, depth, ignore) {
198
- // Build glob pattern with depth limit
199
- const depthPattern = Array.from({ length: depth }, (_, i) => '*'.repeat(i + 1)).join(',');
200
- const pattern = `{${depthPattern}}/.tixyel`;
201
- // Build ignore patterns (folders and files)
202
- const ignorePatterns = ['node_modules', '.git', 'dist', ...ignore];
203
- // Find all .tixyel files
204
- const dotTixyels = await FastGlob(pattern, {
205
- cwd: root,
206
- absolute: true,
207
- onlyFiles: true,
208
- ignore: ignorePatterns,
209
- });
210
- const widgets = [];
211
- for (const dotTixyelPath of dotTixyels) {
212
- const path = dirname(dotTixyelPath);
213
- const config = await readDotTixyel(path);
214
- if (config) {
215
- widgets.push({
216
- path,
217
- relativePath: relative(root, path),
218
- config,
219
- });
220
- }
221
- }
222
- return widgets;
223
- }
224
- export async function build(widget, versionBump, verbose = false, workspaceConfig) {
225
- console.log(`🔨 Building widget: ${widget.config.name}`);
226
- if (verbose) {
227
- console.log(` - Path: ${widget.path}`);
228
- }
229
- if (versionBump !== 'none') {
230
- const newVersion = await bumpVersion(widget.path, versionBump);
231
- if (newVersion) {
232
- console.log(` - Bumped version to: ${newVersion}`);
233
- widget.config.version = newVersion;
234
- }
235
- }
236
- if (widget.config && workspaceConfig) {
237
- try {
238
- await processBuild(widget, workspaceConfig, verbose);
239
- }
240
- catch (error) {
241
- console.error(`❌ Build failed for widget ${widget.config.name}:`, error);
242
- throw error;
243
- }
244
- }
245
- else {
246
- console.warn(`⚠️ Skipping build for widget ${widget.config.name}: Missing configuration.`);
247
- throw new Error('Missing configuration for build process.');
248
- }
249
- console.log(`✅ Build completed for widget: ${widget.config.name}`);
250
- }
251
- export async function processBuild(widget, workspaceConfig, verbose = false) {
252
- const entryDir = join(widget.path, widget.config.dirs?.entry || workspaceConfig.dirs?.entry || 'development');
253
- const outDir = join(widget.path, widget.config.dirs?.output || workspaceConfig.dirs?.output || 'finished');
254
- const compactedDir = join(widget.path, widget.config.dirs?.compacted || workspaceConfig.dirs?.compacted || 'widgetIO');
255
- if (!existsSync(entryDir)) {
256
- throw new Error(`Entry directory not found: ${entryDir}`);
257
- }
258
- mkdirSync(outDir, { recursive: true });
259
- const findPatterns = workspaceConfig.build?.find || {
260
- html: ['index.html'],
261
- script: ['script.js'],
262
- typescript: ['script.ts'],
263
- css: ['styles.css'],
264
- fields: ['fields.json'],
265
- };
266
- const resultMapping = workspaceConfig.build?.result || {
267
- 'HTML.html': 'html',
268
- 'SCRIPT.js': 'script',
269
- 'CSS.css': 'css',
270
- 'FIELDS.json': 'fields',
271
- };
272
- const compactedMapping = workspaceConfig.build?.widgetIO || {
273
- 'html.txt': 'html',
274
- 'js.txt': 'script',
275
- 'css.txt': 'css',
276
- 'fields.txt': 'fields',
277
- };
278
- // const results: Record<string, string> = {};
279
- const normalizeList = (value) => (Array.isArray(value) ? value.filter(Boolean) : []);
280
- const findAndRead = (baseDir, patterns) => {
281
- const contents = {};
282
- for (const pattern of patterns) {
283
- const fullPath = join(baseDir, pattern);
284
- if (existsSync(fullPath)) {
285
- const content = readFileSync(fullPath, 'utf-8');
286
- contents[pattern] = content;
287
- }
288
- }
289
- return contents;
290
- };
291
- const usedWatermarks = new Set();
292
- const processedFile = new Set();
293
- /**
294
- * Build results processing
295
- * Find all files based on patterns and process them according to their type
296
- * (html, css, script, fields)
297
- * Group results based on resultMapping and compactedMapping
298
- * Compact/minify where applicable
299
- */
300
- const results = Object.fromEntries(await Promise.all(Object.entries(findPatterns).map(async ([key, patterns]) => {
301
- let result = '';
302
- let list = normalizeList(patterns.filter((p) => !processedFile.has(p)));
303
- if (!list.length)
304
- return [key, ''];
305
- const check = (keys, formats) => {
306
- !Array.isArray(keys) && (keys = [keys]);
307
- !Array.isArray(formats) && (formats = [formats]);
308
- return (
309
- // check keys
310
- keys.some((k) => key.toLowerCase() === k.toLowerCase()) ||
311
- // check formats
312
- list.some((p) => formats.some((f) => p.toLowerCase().endsWith(f.toLowerCase()))));
313
- };
314
- const processed = new Set();
315
- // Process HTML
316
- if (check('html', '.html')) {
317
- if (!usedWatermarks.has('html'))
318
- result += watermark.html(widget) + '\n';
319
- usedWatermarks.add('html');
320
- const fileList = list.filter((e) => e.endsWith('.html') && !processedFile.has(e));
321
- if (verbose)
322
- console.log(` - Processing HTML for ${widget.config.name} [${key}, ${fileList.join(', ')}]...`);
323
- const files = findAndRead(entryDir, fileList);
324
- let mergedHTML = '';
325
- for await (const [pattern, fileContent] of Object.entries(files)) {
326
- // Extract body content
327
- const bodyMatch = fileContent.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
328
- if (bodyMatch && bodyMatch[1]) {
329
- mergedHTML += bodyMatch[1].trim() + '\n';
330
- processedFile.add(pattern);
331
- }
332
- }
333
- const minified = await minifyHTML(mergedHTML, workspaceConfig.build?.obfuscation?.html);
334
- result += minified.trim();
335
- processed.add('html');
336
- }
337
- if (check(['css', 'style', 'styles'], '.css')) {
338
- if (!usedWatermarks.has('css'))
339
- result += watermark.css(widget) + '\n';
340
- usedWatermarks.add('css');
341
- const fileList = list.filter((e) => e.endsWith('.css') && !processedFile.has(e));
342
- if (verbose)
343
- console.log(` - Processing CSS for ${widget.config.name} [${key}, ${fileList.join(', ')}]...`);
344
- const files = findAndRead(entryDir, fileList);
345
- let mergedCSS = '';
346
- for await (const [pattern, content] of Object.entries(files)) {
347
- const plugin = [
348
- autoprefixer({
349
- overrideBrowserslist: ['Chrome 127'],
350
- ...workspaceConfig.build?.obfuscation?.css?.autoprefixer,
351
- }),
352
- cssnano(workspaceConfig.build?.obfuscation?.css?.cssnano),
353
- ];
354
- if (workspaceConfig.build?.obfuscation?.css?.removeNesting) {
355
- plugin.unshift(nested());
356
- }
357
- const processed = await postcss(plugin).process(content, { from: undefined });
358
- mergedCSS += processed.css + '\n';
359
- processedFile.add(pattern);
360
- }
361
- if (processed.has('html')) {
362
- result = result += `<style>${mergedCSS.trim()}</style>`;
363
- }
364
- else
365
- result += mergedCSS.trim();
366
- processed.add('css');
367
- }
368
- if (check(['typescript', 'ts'], '.ts')) {
369
- if (!usedWatermarks.has('script'))
370
- result += watermark.script(widget) + '\n';
371
- usedWatermarks.add('script');
372
- const fileList = list.filter((e) => e.endsWith('.ts') && !processedFile.has(e));
373
- if (verbose)
374
- console.log(` - Processing TypeScript for ${widget.config.name} [${key}, ${fileList.join(', ')}]...`);
375
- const files = findAndRead(entryDir, fileList);
376
- let mergedTS = '';
377
- for await (const [pattern, content] of Object.entries(files)) {
378
- try {
379
- const transpiled = transformSync(content, {
380
- loader: 'ts',
381
- target: 'es2020',
382
- format: 'cjs',
383
- });
384
- mergedTS += transpiled.code + '\n';
385
- }
386
- catch (error) {
387
- console.warn(` ⚠️ Failed to compile TypeScript: ${error}`);
388
- throw error;
389
- }
390
- finally {
391
- processedFile.add(pattern);
392
- }
393
- }
394
- // Obfuscate the compiled JavaScript
395
- const obfuscated = JavaScriptObfuscator.obfuscate(mergedTS.trim(), workspaceConfig.build?.obfuscation?.javascript);
396
- if (processed.has('html')) {
397
- result = result += `<script>${obfuscated.getObfuscatedCode()}</script>\n`;
398
- }
399
- else
400
- result += obfuscated.getObfuscatedCode() + '\n';
401
- processed.add('typescript');
402
- }
403
- if (check(['script', 'js', 'javascript'], '.js')) {
404
- if (!usedWatermarks.has('script'))
405
- result += watermark.script(widget) + '\n';
406
- usedWatermarks.add('script');
407
- const fileList = list.filter((e) => e.endsWith('.js') && !processedFile.has(e));
408
- if (verbose)
409
- console.log(` - Processing JavaScript for ${widget.config.name} [${key}, ${fileList.join(', ')}]...`);
410
- const files = findAndRead(entryDir, fileList);
411
- let mergedJS = '';
412
- for await (const [pattern, content] of Object.entries(files)) {
413
- const obfuscated = JavaScriptObfuscator.obfuscate(content, workspaceConfig.build?.obfuscation?.javascript);
414
- mergedJS += obfuscated.getObfuscatedCode() + '\n';
415
- processedFile.add(pattern);
416
- }
417
- if (processed.has('html')) {
418
- result = result += `<script>${mergedJS.trim()}</script>`;
419
- }
420
- else
421
- result += mergedJS.trim();
422
- processed.add('script');
423
- }
424
- if (check(['fields', 'fielddata', 'fieldData', 'cf', 'customfields'], '.json')) {
425
- const fileList = list.filter((e) => e.endsWith('.json') && !processedFile.has(e));
426
- if (verbose)
427
- console.log(` - Processing JSON for ${widget.config.name} [${key}, ${fileList.join(', ')}]...`);
428
- const files = findAndRead(entryDir, fileList);
429
- let mergedFields = {};
430
- for await (const [pattern, content] of Object.entries(files)) {
431
- try {
432
- const noComments = parse(content);
433
- const parsed = JSON.parse(JSON.stringify(noComments));
434
- Object.assign(mergedFields, parsed);
435
- }
436
- catch (error) {
437
- console.warn(` ⚠️ Failed to parse fields JSON: ${error}`);
438
- throw error;
439
- }
440
- }
441
- if (!processed.size)
442
- result += JSON.stringify(mergedFields, null, 2);
443
- processed.add('fields');
444
- }
445
- if (!result.length) {
446
- if (verbose)
447
- console.log(` - Unknown build key: ${key}, the available keys are html, css, script and fields.`);
448
- result += '';
449
- }
450
- return [key, result];
451
- })));
452
- if (verbose) {
453
- console.log(` - Build results:`, Object.keys(results)
454
- .map((k) => `${k}: ${results[k].length} bytes`)
455
- .join(', '));
456
- }
457
- for await (const [filename, key] of Object.entries(resultMapping)) {
458
- let content = '';
459
- if (typeof key === 'string')
460
- content = results[key];
461
- else if (Array.isArray(key)) {
462
- for await (const k of key) {
463
- const part = results[k];
464
- if (part) {
465
- content += '\n' + part;
466
- if (verbose)
467
- console.log(` ✓ Merged part for: ${k}`);
468
- }
469
- }
470
- }
471
- if (content) {
472
- const outPath = join(outDir, filename);
473
- writeFileSync(outPath, content, 'utf-8');
474
- if (verbose)
475
- console.log(` ✓ Written: ${outPath}`);
476
- }
477
- }
478
- // widgetIO zip
479
- try {
480
- const zip = new JSZip();
481
- for await (const [filename, key] of Object.entries(compactedMapping)) {
482
- let content = '';
483
- if (typeof key === 'string')
484
- content = results[key];
485
- else if (Array.isArray(key)) {
486
- for await (const k of key) {
487
- const part = results[k];
488
- if (part) {
489
- content += '\n' + part;
490
- if (verbose)
491
- console.log(` ✓ Merged part for ZIP: ${k}`);
492
- }
493
- }
494
- }
495
- if (content) {
496
- zip.file(filename, content);
497
- if (verbose)
498
- console.log(` ✓ Added to ZIP: ${filename}`);
499
- }
500
- }
501
- zip.file('widget.ini', `[HTML]\npath = "html.txt"\n\n[CSS]\npath = "css.txt"\n\n[JS]\npath = "js.txt"\n\n[FIELDS]\npath = "fields.txt"\n\n[DATA]\npath = "data.txt"`);
502
- // check if data.txt exists in results, otherwise create empty
503
- const dataContent = results['data'] || '{}';
504
- zip.file('data.txt', dataContent);
505
- const result = await zip
506
- .generateInternalStream({ type: 'base64' })
507
- .accumulate()
508
- .then((data) => data);
509
- const zipPath = join(compactedDir + '/' + widget.config.version || '0.0.0', `${widget.config.name}.zip`);
510
- mkdirSync(compactedDir + '/' + widget.config.version, { recursive: true });
511
- writeFileSync(zipPath, result, 'base64');
512
- }
513
- catch (error) {
514
- console.error(`❌ Failed to create widgetIO ZIP for widget ${widget.config.name}:`, error);
515
- throw error;
516
- }
517
- }
518
- export async function bumpVersion(widgetPath, bumpType = 'patch') {
519
- try {
520
- const configPath = join(widgetPath, '.tixyel');
521
- const content = await readFilePromise(configPath, 'utf-8');
522
- const config = parse(content);
523
- if (!config.version) {
524
- config.version = '0.0.0';
525
- }
526
- const [major, minor, patch] = config.version.split('.').map(Number);
527
- let newVersion;
528
- switch (bumpType) {
529
- case 'major': {
530
- newVersion = `${major + 1}.0.0`;
531
- break;
532
- }
533
- case 'minor': {
534
- newVersion = `${major}.${minor + 1}.0`;
535
- break;
536
- }
537
- case 'patch': {
538
- newVersion = `${major}.${minor}.${patch + 1}`;
539
- break;
540
- }
541
- }
542
- config.version = newVersion;
543
- const formattedContent = JSON.stringify(config, null, 2);
544
- await writeFile(configPath, formattedContent, 'utf-8');
545
- return newVersion;
546
- }
547
- catch (error) {
548
- console.error(`Failed to bump version in ${widgetPath}:`, error);
549
- return null;
550
- }
551
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,14 +0,0 @@
1
- import { describe, expect, it } from 'bun:test';
2
- import { transformSync } from 'esbuild';
3
- describe('Should parse typescript into javascript', () => {
4
- const tsContent = `function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms));}`;
5
- const transpiled = transformSync(tsContent, {
6
- loader: 'ts',
7
- target: 'es2020',
8
- format: 'cjs',
9
- });
10
- it('should transpile TypeScript to JavaScript', () => {
11
- expect(transpiled.code).toContain('function wait(ms) {');
12
- expect(transpiled.code).toContain('return new Promise((resolve) => setTimeout(resolve, ms));');
13
- });
14
- });
@@ -1,113 +0,0 @@
1
- import type { Options as HtmlMinifierOptions } from 'html-minifier-terser';
2
- import type { ObfuscatorOptions } from 'javascript-obfuscator';
3
- import type autoprefixer from 'autoprefixer';
4
- import type cssnanoPlugin from 'cssnano';
5
- import type { JSX } from 'react';
6
- export type ScaffoldItem = ScaffoldFile | ScaffoldFolder;
7
- export interface ScaffoldFile {
8
- name: string;
9
- type: 'file';
10
- content: string | JSX.Element;
11
- }
12
- export interface ScaffoldFolder {
13
- name: string;
14
- type: 'folder';
15
- content?: ScaffoldItem[];
16
- }
17
- export interface WorkspaceConfig<Find extends BuildFindMap = BuildFindMap> {
18
- /**
19
- * Search options for locating widget files
20
- */
21
- search?: {
22
- /**
23
- * Maximum directory depth to search
24
- */
25
- maxDepth?: number;
26
- /**
27
- * Folders and files to ignore during search
28
- */
29
- ignore?: string[];
30
- };
31
- /**
32
- * Metadata applied to all widgets in the workspace
33
- */
34
- metadata?: {
35
- name?: string;
36
- author?: string;
37
- clientId?: string;
38
- description?: string;
39
- tags?: string[];
40
- };
41
- dirs?: {
42
- entry?: string;
43
- output?: string;
44
- compacted?: string;
45
- };
46
- /**
47
- * Scaffold structure to create when generating a new widget
48
- */
49
- scaffold?: ScaffoldItem[];
50
- /**
51
- * Build configuration
52
- */
53
- build?: {
54
- /**
55
- * Run builds in parallel
56
- */
57
- parallel?: boolean;
58
- /**
59
- * Verbose output during build
60
- */
61
- verbose?: boolean;
62
- /**
63
- * File patterns to locate widget files
64
- */
65
- find?: Find;
66
- /**
67
- * Mapping of output files to find keys
68
- */
69
- result?: BuildResultMap<Find>;
70
- /**
71
- * Mapping of widgetIO output files to find keys
72
- */
73
- widgetIO?: BuildResultMap<Find>;
74
- /**
75
- * Obfuscation and minification settings
76
- */
77
- obfuscation?: {
78
- /**
79
- * JavaScript obfuscation options
80
- */
81
- javascript?: ObfuscatorOptions;
82
- /**
83
- * CSS minification options
84
- */
85
- css?: {
86
- /**
87
- * Remove nesting rules
88
- */
89
- removeNesting?: boolean;
90
- /**
91
- * Autoprefixer options
92
- */
93
- autoprefixer?: autoprefixer.Options;
94
- /**
95
- * cssnano options
96
- */
97
- cssnano?: cssnanoPlugin.Options;
98
- };
99
- /**
100
- * HTML minification options
101
- */
102
- html?: HtmlMinifierOptions;
103
- };
104
- };
105
- }
106
- type BuildFindMap = Record<string, string[]>;
107
- type BuildResultMap<Find extends BuildFindMap> = Record<string, keyof Find | (keyof Find)[]>;
108
- export declare function defineWorkspaceConfig<const Find extends BuildFindMap>(config: WorkspaceConfig<Find>): WorkspaceConfig<Find>;
109
- export declare function resolveConfig(path: string): Promise<WorkspaceConfig>;
110
- export declare function findWorkspaceRoot(startPath?: string): Promise<string | null>;
111
- export declare function validateWorkspace(): Promise<string>;
112
- export declare function loadWorkspace(path: string): Promise<WorkspaceConfig<BuildFindMap>>;
113
- export {};