@tixyel/cli 1.0.0 → 2.0.1

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.
@@ -1,162 +0,0 @@
1
- /**
2
- * Default CLI configuration
3
- */
4
- export const DEFAULT_CLI_CONFIG = {
5
- search: {
6
- maxDepth: 3,
7
- ignore: ['node_modules', 'dist', '.git', '.turbo'],
8
- },
9
- generationDefaults: {
10
- author: 'Tixyel',
11
- minify: true,
12
- platform: 'streamelements',
13
- scaffold: [
14
- {
15
- name: 'development',
16
- type: 'folder',
17
- content: [
18
- {
19
- name: 'index.html',
20
- type: 'file',
21
- content: `<!DOCTYPE html>
22
- <html lang="en">
23
- <head>
24
- <meta charset="UTF-8">
25
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
26
- <title>Widget</title>
27
- <link rel="stylesheet" href="style.css">
28
- </head>
29
- <body>
30
- <div id="widget">
31
- <!-- Widget content here -->
32
- </div>
33
- <script src="script.js"></script>
34
- </body>
35
- </html>`,
36
- },
37
- {
38
- name: 'script.js',
39
- type: 'file',
40
- content: `// Widget script
41
- console.log('Widget loaded');
42
- `,
43
- },
44
- {
45
- name: 'fields.json',
46
- type: 'file',
47
- content: `{
48
- "title": "Widget Fields",
49
- "fields": []
50
- }`,
51
- },
52
- {
53
- name: 'data.json',
54
- type: 'file',
55
- content: `{
56
- "title": "Widget Data"
57
- }`,
58
- },
59
- {
60
- name: 'style.css',
61
- type: 'file',
62
- content: `/* Widget styles */
63
- body {
64
- margin: 0;
65
- padding: 0;
66
- }
67
-
68
- #widget {
69
- /* Add your styles here */
70
- }`,
71
- },
72
- ],
73
- },
74
- {
75
- name: 'finished',
76
- type: 'folder',
77
- },
78
- ],
79
- },
80
- build: {
81
- parallel: false,
82
- verbose: false,
83
- find: {
84
- html: ['index.html'],
85
- css: ['style.css'],
86
- script: ['resources.js', 'script.js'],
87
- fields: ['cf.json', 'fields.json'],
88
- },
89
- finished: {
90
- 'HTML.html': 'html',
91
- 'CSS.css': 'css',
92
- 'SCRIPT.js': 'script',
93
- 'FIELDS.json': 'fields',
94
- },
95
- obfuscation: {
96
- javascript: {
97
- compact: true,
98
- log: false,
99
- debugProtection: false,
100
- selfDefending: false,
101
- deadCodeInjection: false,
102
- controlFlowFlattening: false,
103
- stringArray: false,
104
- simplify: false,
105
- identifierNamesGenerator: 'mangled',
106
- },
107
- css: {
108
- removeNesting: true,
109
- autoprefixer: {
110
- overrideBrowserslist: ['Chrome 127'],
111
- },
112
- cssnano: {
113
- preset: 'default',
114
- },
115
- },
116
- html: {
117
- removeComments: true,
118
- collapseWhitespace: true,
119
- minifyCSS: true,
120
- minifyJS: true,
121
- removeAttributeQuotes: false,
122
- },
123
- },
124
- },
125
- };
126
- /**
127
- * Merges user config with defaults
128
- */
129
- export function mergeCliConfig(userConfig) {
130
- return {
131
- search: {
132
- maxDepth: userConfig?.search?.maxDepth ?? DEFAULT_CLI_CONFIG.search.maxDepth,
133
- ignore: userConfig?.search?.ignore ?? DEFAULT_CLI_CONFIG.search.ignore,
134
- },
135
- generationDefaults: {
136
- author: userConfig?.generationDefaults?.author ?? DEFAULT_CLI_CONFIG.generationDefaults.author,
137
- minify: userConfig?.generationDefaults?.minify ?? DEFAULT_CLI_CONFIG.generationDefaults.minify,
138
- platform: userConfig?.generationDefaults?.platform ?? DEFAULT_CLI_CONFIG.generationDefaults.platform,
139
- scaffold: userConfig?.generationDefaults?.scaffold ?? DEFAULT_CLI_CONFIG.generationDefaults.scaffold,
140
- },
141
- build: {
142
- parallel: userConfig?.build?.parallel ?? DEFAULT_CLI_CONFIG.build.parallel,
143
- verbose: userConfig?.build?.verbose ?? DEFAULT_CLI_CONFIG.build.verbose,
144
- find: {
145
- html: userConfig?.build?.find?.html ?? DEFAULT_CLI_CONFIG.build.find.html,
146
- css: userConfig?.build?.find?.css ?? DEFAULT_CLI_CONFIG.build.find.css,
147
- script: userConfig?.build?.find?.script ?? DEFAULT_CLI_CONFIG.build.find.script,
148
- fields: userConfig?.build?.find?.fields ?? DEFAULT_CLI_CONFIG.build.find.fields,
149
- },
150
- finished: userConfig?.build?.finished ?? DEFAULT_CLI_CONFIG.build.finished,
151
- obfuscation: {
152
- javascript: userConfig?.build?.obfuscation?.javascript ?? DEFAULT_CLI_CONFIG.build.obfuscation.javascript,
153
- css: {
154
- removeNesting: userConfig?.build?.obfuscation?.css?.removeNesting ?? DEFAULT_CLI_CONFIG.build.obfuscation.css.removeNesting,
155
- autoprefixer: userConfig?.build?.obfuscation?.css?.autoprefixer ?? DEFAULT_CLI_CONFIG.build.obfuscation.css.autoprefixer,
156
- cssnano: userConfig?.build?.obfuscation?.css?.cssnano ?? DEFAULT_CLI_CONFIG.build.obfuscation.css.cssnano,
157
- },
158
- html: userConfig?.build?.obfuscation?.html ?? DEFAULT_CLI_CONFIG.build.obfuscation.html,
159
- },
160
- },
161
- };
162
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * Schema for .tixyel configuration file
3
- */
4
- export interface TixyelConfig {
5
- /**
6
- * Widget name
7
- */
8
- name: string;
9
- /**
10
- * Widget version (default: 1.0.0)
11
- */
12
- version?: string;
13
- /**
14
- * Widget description
15
- */
16
- description?: string;
17
- /**
18
- * Entry point directory (default: development)
19
- */
20
- entry?: string;
21
- /**
22
- * Output directory (default: finished)
23
- */
24
- outDir?: string;
25
- /**
26
- * Relative path to tixyel.config.ts from this file's directory
27
- * Auto-calculated during widget generation
28
- */
29
- configPath?: string;
30
- /**
31
- * Additional build configuration
32
- */
33
- build?: {
34
- /**
35
- * Minify output
36
- */
37
- minify?: boolean;
38
- /**
39
- * File patterns to find and merge
40
- */
41
- find?: {
42
- html?: string[];
43
- css?: string[];
44
- script?: string[];
45
- fields?: string[];
46
- };
47
- /**
48
- * Output file mapping
49
- */
50
- finished?: {
51
- [key: string]: 'html' | 'css' | 'script' | 'fields';
52
- };
53
- };
54
- /**
55
- * Widget metadata
56
- */
57
- metadata?: {
58
- author?: string;
59
- tags?: string[];
60
- /**
61
- * Platform - currently only StreamElements is supported
62
- */
63
- platform?: 'streamelements';
64
- };
65
- }
66
- /**
67
- * Default configuration values
68
- */
69
- export declare const DEFAULT_TIXYEL_CONFIG: {
70
- readonly version: "1.0.0";
71
- readonly entry: "development";
72
- readonly outDir: "finished";
73
- };
74
- /**
75
- * Validates a Tixyel configuration object
76
- */
77
- export declare function validateTixyelConfig(config: unknown): config is TixyelConfig;
78
- /**
79
- * Applies default values to a configuration object
80
- */
81
- export declare function applyDefaults(config: TixyelConfig): Omit<Required<TixyelConfig>, 'configPath'> & {
82
- configPath?: string;
83
- };
@@ -1,43 +0,0 @@
1
- /**
2
- * Default configuration values
3
- */
4
- export const DEFAULT_TIXYEL_CONFIG = {
5
- version: '1.0.0',
6
- entry: 'development',
7
- outDir: 'finished',
8
- };
9
- /**
10
- * Validates a Tixyel configuration object
11
- */
12
- export function validateTixyelConfig(config) {
13
- if (typeof config !== 'object' || config === null) {
14
- return false;
15
- }
16
- const cfg = config;
17
- // Required fields
18
- if (typeof cfg.name !== 'string' || !cfg.name) {
19
- return false;
20
- }
21
- return true;
22
- }
23
- /**
24
- * Applies default values to a configuration object
25
- */
26
- export function applyDefaults(config) {
27
- return {
28
- name: config.name,
29
- version: config.version || DEFAULT_TIXYEL_CONFIG.version,
30
- description: config.description ?? '',
31
- entry: config.entry ?? DEFAULT_TIXYEL_CONFIG.entry,
32
- outDir: config.outDir ?? DEFAULT_TIXYEL_CONFIG.outDir,
33
- configPath: config.configPath,
34
- build: config.build
35
- ? {
36
- minify: config.build.minify ?? false,
37
- find: config.build.find,
38
- finished: config.build.finished,
39
- }
40
- : { minify: false },
41
- metadata: config.metadata ?? { platform: 'streamelements' },
42
- };
43
- }
@@ -1,12 +0,0 @@
1
- import type { TixyelConfig } from '../types/tixyel-config.js';
2
- import type { RequiredCliConfig } from '../types/tixyel-cli-config.js';
3
- export interface BuildOptions {
4
- widgetPath: string;
5
- config: TixyelConfig;
6
- cliConfig: RequiredCliConfig;
7
- verbose?: boolean;
8
- }
9
- /**
10
- * Processes and builds a widget
11
- */
12
- export declare function buildWidget(options: BuildOptions): Promise<void>;
@@ -1,156 +0,0 @@
1
- import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';
2
- import { join } from 'path';
3
- import { minify as minifyHTML } from 'html-minifier-terser';
4
- import JavaScriptObfuscator from 'javascript-obfuscator';
5
- import postcss from 'postcss';
6
- import autoprefixer from 'autoprefixer';
7
- import cssnano from 'cssnano';
8
- import nested from 'postcss-nested';
9
- /**
10
- * Processes and builds a widget
11
- */
12
- export async function buildWidget(options) {
13
- const { widgetPath, config, cliConfig, verbose } = options;
14
- const entryDir = join(widgetPath, config.entry || 'development');
15
- const outDir = join(widgetPath, config.outDir || 'finished');
16
- if (!existsSync(entryDir)) {
17
- throw new Error(`Entry directory not found: ${entryDir}`);
18
- }
19
- // Create output directory
20
- mkdirSync(outDir, { recursive: true });
21
- // Get file patterns - use widget config first, fallback to CLI config defaults
22
- const findPatterns = config.build?.find || cliConfig.build.find;
23
- const finishedMapping = config.build?.finished || cliConfig.build.finished;
24
- // Process each type
25
- const results = {};
26
- const normalizeList = (value) => (Array.isArray(value) ? value.filter(Boolean) : []);
27
- const htmlList = normalizeList(findPatterns.html);
28
- const cssList = normalizeList(findPatterns.css);
29
- const scriptList = normalizeList(findPatterns.script);
30
- const fieldsList = normalizeList(findPatterns.fields);
31
- // Process HTML
32
- if (htmlList.length > 0) {
33
- if (verbose)
34
- console.log(` Processing HTML...`);
35
- results.html = await processHTML(entryDir, htmlList, cliConfig);
36
- }
37
- // Process CSS
38
- if (cssList.length > 0) {
39
- if (verbose)
40
- console.log(` Processing CSS...`);
41
- results.css = await processCSS(entryDir, cssList, cliConfig);
42
- }
43
- // Process JavaScript
44
- if (scriptList.length > 0) {
45
- if (verbose)
46
- console.log(` Processing JavaScript...`);
47
- results.script = await processJavaScript(entryDir, scriptList, cliConfig);
48
- }
49
- // Process Fields (JSON)
50
- if (fieldsList.length > 0) {
51
- if (verbose)
52
- console.log(` Processing Fields...`);
53
- results.fields = await processFields(entryDir, fieldsList);
54
- }
55
- // Write output files based on finished mapping
56
- for (const [filename, type] of Object.entries(finishedMapping)) {
57
- const content = results[type];
58
- if (content) {
59
- const outputPath = join(outDir, filename);
60
- writeFileSync(outputPath, content, 'utf-8');
61
- if (verbose)
62
- console.log(` ✓ Written: ${filename}`);
63
- }
64
- }
65
- }
66
- /**
67
- * Finds and reads files matching pattern
68
- */
69
- function findAndReadFiles(baseDir, filenames) {
70
- const contents = [];
71
- for (const filename of filenames) {
72
- const filePath = join(baseDir, filename);
73
- if (existsSync(filePath)) {
74
- contents.push(readFileSync(filePath, 'utf-8'));
75
- }
76
- }
77
- return contents;
78
- }
79
- /**
80
- * Processes HTML files - extracts <body> content only
81
- */
82
- async function processHTML(baseDir, filenames, cliConfig) {
83
- const files = findAndReadFiles(baseDir, filenames);
84
- let mergedHTML = '';
85
- for (const content of files) {
86
- // Extract body content
87
- const bodyMatch = content.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
88
- if (bodyMatch) {
89
- mergedHTML += bodyMatch[1] + '\n';
90
- }
91
- // Extract and inline <style> tags
92
- const styleMatches = content.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi);
93
- for (const match of styleMatches) {
94
- mergedHTML += `<style>${match[1]}</style>\n`;
95
- }
96
- // Extract and inline <script> tags
97
- const scriptMatches = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/gi);
98
- for (const match of scriptMatches) {
99
- mergedHTML += `<script>${match[1]}</script>\n`;
100
- }
101
- }
102
- // Minify HTML
103
- const minified = await minifyHTML(mergedHTML, cliConfig.build.obfuscation.html);
104
- return minified;
105
- }
106
- /**
107
- * Processes CSS files
108
- */
109
- async function processCSS(baseDir, filenames, cliConfig) {
110
- const files = findAndReadFiles(baseDir, filenames);
111
- let mergedCSS = '';
112
- for (const content of files) {
113
- // Process each file separately
114
- const plugins = [
115
- autoprefixer({ overrideBrowserslist: ['Chrome 127'], ...cliConfig.build.obfuscation.css.autoprefixer }),
116
- cssnano(cliConfig.build.obfuscation.css.cssnano),
117
- ];
118
- if (cliConfig.build.obfuscation.css.removeNesting) {
119
- plugins.unshift(nested());
120
- }
121
- const result = await postcss(plugins).process(content, { from: undefined });
122
- mergedCSS += result.css + '\n';
123
- }
124
- return mergedCSS.trim();
125
- }
126
- /**
127
- * Processes JavaScript files
128
- */
129
- async function processJavaScript(baseDir, filenames, cliConfig) {
130
- const files = findAndReadFiles(baseDir, filenames);
131
- let mergedJS = '';
132
- for (const content of files) {
133
- // Obfuscate each file separately
134
- const obfuscated = JavaScriptObfuscator.obfuscate(content, cliConfig.build.obfuscation.javascript);
135
- mergedJS += obfuscated.getObfuscatedCode() + '\n';
136
- }
137
- return mergedJS.trim();
138
- }
139
- /**
140
- * Processes Fields JSON files
141
- */
142
- async function processFields(baseDir, filenames) {
143
- const files = findAndReadFiles(baseDir, filenames);
144
- // Merge all fields
145
- let mergedFields = {};
146
- for (const content of files) {
147
- try {
148
- const parsed = JSON.parse(content);
149
- mergedFields = { ...mergedFields, ...parsed };
150
- }
151
- catch (error) {
152
- console.warn(` ⚠️ Failed to parse fields JSON: ${error}`);
153
- }
154
- }
155
- return JSON.stringify(mergedFields);
156
- }
@@ -1,23 +0,0 @@
1
- import type { TixyelConfig } from '../types/tixyel-config.js';
2
- /**
3
- * Default search depth for finding .tixyel files
4
- */
5
- export declare const DEFAULT_MAX_DEPTH = 3;
6
- /**
7
- * Reads and parses a .tixyel configuration file (supports JSONC)
8
- * Applies default values for missing properties
9
- */
10
- export declare function readTixyelConfig(directory: string): Promise<TixyelConfig | null>;
11
- /**
12
- * Configuration for CLI settings
13
- */
14
- export interface CliConfig {
15
- /**
16
- * Maximum depth to search for .tixyel files
17
- */
18
- maxDepth: number;
19
- }
20
- /**
21
- * Default CLI configuration
22
- */
23
- export declare const defaultCliConfig: CliConfig;
@@ -1,34 +0,0 @@
1
- import { readFile } from 'fs/promises';
2
- import { join } from 'path';
3
- import { parse } from 'jsonc-parser';
4
- import { validateTixyelConfig, applyDefaults } from '../types/tixyel-config.js';
5
- /**
6
- * Default search depth for finding .tixyel files
7
- */
8
- export const DEFAULT_MAX_DEPTH = 3;
9
- /**
10
- * Reads and parses a .tixyel configuration file (supports JSONC)
11
- * Applies default values for missing properties
12
- */
13
- export async function readTixyelConfig(directory) {
14
- try {
15
- const configPath = join(directory, '.tixyel');
16
- const content = await readFile(configPath, 'utf-8');
17
- const config = parse(content);
18
- if (!validateTixyelConfig(config)) {
19
- console.error(`Invalid .tixyel configuration in ${directory}`);
20
- return null;
21
- }
22
- // Apply defaults and return the original config with defaults merged
23
- return applyDefaults(config);
24
- }
25
- catch (error) {
26
- return null;
27
- }
28
- }
29
- /**
30
- * Default CLI configuration
31
- */
32
- export const defaultCliConfig = {
33
- maxDepth: DEFAULT_MAX_DEPTH,
34
- };
@@ -1,19 +0,0 @@
1
- import type { TixyelConfig } from '../types/tixyel-config.js';
2
- export interface WidgetInfo {
3
- /**
4
- * Absolute path to the widget directory
5
- */
6
- path: string;
7
- /**
8
- * Relative path from the root directory
9
- */
10
- relativePath: string;
11
- /**
12
- * Parsed .tixyel configuration
13
- */
14
- config: TixyelConfig;
15
- }
16
- /**
17
- * Finds all .tixyel files in the workspace up to a specified depth
18
- */
19
- export declare function findWidgets(rootPath: string, maxDepth?: number, ignorePatterns?: string[]): Promise<WidgetInfo[]>;
@@ -1,35 +0,0 @@
1
- import fastGlobModule from 'fast-glob';
2
- import { dirname, relative } from 'path';
3
- import { readTixyelConfig } from './config.js';
4
- const glob = fastGlobModule;
5
- /**
6
- * Finds all .tixyel files in the workspace up to a specified depth
7
- */
8
- export async function findWidgets(rootPath, maxDepth = 3, ignorePatterns = []) {
9
- // Build glob pattern with depth limit
10
- const depthPattern = Array.from({ length: maxDepth }, (_, i) => '*'.repeat(i + 1)).join(',');
11
- const pattern = `{${depthPattern}}/.tixyel`;
12
- // Build ignore patterns
13
- const ignore = ['node_modules', '.git', 'dist', ...ignorePatterns];
14
- // Find all .tixyel files
15
- const configFiles = await glob(pattern, {
16
- cwd: rootPath,
17
- absolute: true,
18
- onlyFiles: true,
19
- ignore,
20
- });
21
- // Read and parse each config
22
- const widgets = [];
23
- for (const configFile of configFiles) {
24
- const widgetPath = dirname(configFile);
25
- const config = await readTixyelConfig(widgetPath);
26
- if (config) {
27
- widgets.push({
28
- path: widgetPath,
29
- relativePath: relative(rootPath, widgetPath),
30
- config,
31
- });
32
- }
33
- }
34
- return widgets;
35
- }
@@ -1,5 +0,0 @@
1
- import type { RequiredCliConfig } from '../types/tixyel-cli-config.js';
2
- /**
3
- * Loads tixyel.config.ts or tixyel.config.js from the workspace root
4
- */
5
- export declare function loadCliConfig(rootPath: string): Promise<RequiredCliConfig>;
@@ -1,66 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
2
- import { resolve } from 'path';
3
- import { mergeCliConfig } from '../types/tixyel-cli-config.js';
4
- /**
5
- * Loads tixyel.config.ts or tixyel.config.js from the workspace root
6
- */
7
- export async function loadCliConfig(rootPath) {
8
- const configTs = resolve(rootPath, 'tixyel.config.ts');
9
- const configJs = resolve(rootPath, 'tixyel.config.js');
10
- const configMjs = resolve(rootPath, 'tixyel.config.mjs');
11
- let userConfig;
12
- try {
13
- // Try .mjs first (already ES module)
14
- if (existsSync(configMjs)) {
15
- const module = await import(`file://${configMjs}`);
16
- userConfig = module.default || module.config;
17
- }
18
- // Try .js (if package.json has type: module)
19
- else if (existsSync(configJs)) {
20
- const module = await import(`file://${configJs}`);
21
- userConfig = module.default || module.config;
22
- }
23
- // Try .ts file (compile on-the-fly)
24
- else if (existsSync(configTs)) {
25
- userConfig = await loadTypeScriptConfig(configTs, rootPath);
26
- }
27
- }
28
- catch (error) {
29
- console.warn(`⚠️ Failed to load tixyel.config: ${error}`);
30
- }
31
- return mergeCliConfig(userConfig);
32
- }
33
- /**
34
- * Loads TypeScript config by compiling it on-the-fly
35
- */
36
- async function loadTypeScriptConfig(configPath, rootPath) {
37
- const tempJs = resolve(rootPath, '.tixyel.config.temp.mjs');
38
- try {
39
- // Read TypeScript content
40
- const tsContent = readFileSync(configPath, 'utf-8');
41
- // Simple conversion: remove type imports and convert to JS
42
- const jsContent = tsContent
43
- .replace(/import type .+ from .+;/g, '') // Remove type imports
44
- .replace(/: TixyelCliConfig/g, ''); // Remove type annotations
45
- // Write temporary .mjs file
46
- writeFileSync(tempJs, jsContent, 'utf-8');
47
- // Import the temporary file
48
- const module = await import(`file://${tempJs}?t=${Date.now()}`);
49
- const config = module.default || module.config;
50
- return config;
51
- }
52
- catch (error) {
53
- throw new Error(`Failed to load TypeScript config: ${error}`);
54
- }
55
- finally {
56
- // Clean up temporary file
57
- if (existsSync(tempJs)) {
58
- try {
59
- unlinkSync(tempJs);
60
- }
61
- catch {
62
- // Ignore cleanup errors
63
- }
64
- }
65
- }
66
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Version bump types
3
- */
4
- export type VersionBump = 'major' | 'minor' | 'patch';
5
- /**
6
- * Bumps the version of a widget configuration
7
- */
8
- export declare function bumpWidgetVersion(widgetPath: string, bumpType?: VersionBump): Promise<string | null>;
9
- /**
10
- * Prompts user to select version bump type
11
- */
12
- export declare function promptVersionBump(): Promise<VersionBump>;