@tixyel/cli 2.7.1 → 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/api.d.mts ADDED
@@ -0,0 +1,128 @@
1
+ import { JSX } from "react";
2
+ import cssnano from "cssnano";
3
+ import autoprefixer from "autoprefixer";
4
+ import { Options } from "html-minifier-terser";
5
+ import { ObfuscatorOptions } from "javascript-obfuscator";
6
+
7
+ //#region src/types/workspace.d.ts
8
+ declare namespace WorkspaceScaffold {
9
+ type Type = "file" | "folder";
10
+ type Item<T extends Type = Type> = T extends Type ? {
11
+ name: string;
12
+ type: T;
13
+ content?: T extends "file" ? string | JSX.Element : Item[];
14
+ } : never;
15
+ type Scaffold = Item[];
16
+ }
17
+ type BuildFindMap = Record<string, string[]>;
18
+ type BuildResultMap<Find extends BuildFindMap = BuildFindMap> = Record<string, keyof Find | (keyof Find)[]>;
19
+ /**
20
+ * Workspace config schema, defines the structure of the workspace configuration file (tixyel.config.{ts,.js,.json,.jsonc})
21
+ * Not provided options will fall back to default values defined in the CLI
22
+ */
23
+ interface WorkspaceConfig<Find extends BuildFindMap = BuildFindMap> {
24
+ /**
25
+ * Search options for locating widget files in the workspace
26
+ */
27
+ search?: {
28
+ /**
29
+ * Maximum directory depth to search for widget files
30
+ */
31
+ maxDepth?: number;
32
+ /**
33
+ * Folders and files to ignore during search for widget files, supports glob patterns
34
+ */
35
+ ignore?: string[];
36
+ };
37
+ /**
38
+ * Metadata applied to all widgets in the workspace, can be overridden by individual widget metadata
39
+ */
40
+ metadata?: {
41
+ name?: string;
42
+ author?: string;
43
+ clientId?: string;
44
+ description?: string;
45
+ tags?: string[];
46
+ };
47
+ /**
48
+ * Directory structure configuration for widget entry files, output files, and compacted files
49
+ */
50
+ dirs?: {
51
+ /**
52
+ * Directory where widget entry files are located, supports glob patterns
53
+ */
54
+ entry?: string;
55
+ /**
56
+ * Directory where built widget files will be output, supports glob patterns
57
+ */
58
+ output?: string;
59
+ /**
60
+ * Directory where compacted widget files will be output, supports glob patterns
61
+ */
62
+ extension?: string;
63
+ };
64
+ /**
65
+ * Scaffold structure to create when generating a new widget, defines the files and folders to create with their content (string or JSX.Element)
66
+ */
67
+ scaffold?: WorkspaceScaffold.Item[];
68
+ /**
69
+ * Build configuration for widget builds, including options for parallel builds, verbose logging, file finding patterns, build results mapping, and obfuscation settings for JavaScript, CSS, and HTML
70
+ */
71
+ build?: {
72
+ /**
73
+ * Run builds in parallel to improve build times, especially for larger workspaces with many widgets
74
+ */
75
+ parallel?: boolean;
76
+ /**
77
+ * Enable verbose output during build process for debugging and insight into build steps, file processing, and potential issues
78
+ */
79
+ verbose?: boolean;
80
+ /**
81
+ * Patterns for finding widget files to build, defined as a mapping of build names to glob patterns or arrays of glob patterns that specify the location of widget files in the workspace
82
+ */
83
+ find?: Find;
84
+ /**
85
+ * Mapping of output files to find keys, defines how the found widget files should be mapped to output file names, allowing for flexible naming conventions and organization of built widget files
86
+ */
87
+ result?: BuildResultMap<Find>;
88
+ /**
89
+ * Mapping of widgetIO output files to find keys, similar to the result mapping but specifically for widgetIO output files, allowing for separate handling and organization of widgetIO builds
90
+ */
91
+ widgetIO?: BuildResultMap<Find>;
92
+ /**
93
+ * Obfuscation and minification settings for JavaScript, CSS, and HTML files during the build process, allowing for enhanced security and reduced file sizes for production builds
94
+ */
95
+ obfuscation?: {
96
+ /**
97
+ * HTML minification options, defined using the Options type from the html-minifier-terser package, allowing for various HTML minification techniques such as removing comments, collapsing whitespace, and minifying inline CSS and JavaScript to create smaller HTML files for production
98
+ */
99
+ html?: Options;
100
+ /**
101
+ * CSS minification options, allowing for configuration of CSS minification using cssnano and autoprefixer, including options for removing nesting, adding vendor prefixes, and optimizing CSS for production
102
+ */
103
+ css?: {
104
+ /**
105
+ * Remove nesting rules from CSS, which can help reduce file size and improve compatibility with older browsers that do not support CSS nesting
106
+ */
107
+ removeNesting?: boolean;
108
+ /**
109
+ * Autoprefixer options, defined using the Options type from the autoprefixer package, allowing for automatic addition of vendor prefixes to CSS rules based on browser compatibility data, ensuring that the CSS works across different browsers and versions
110
+ */
111
+ autoprefixer?: autoprefixer.Options;
112
+ /**
113
+ * cssnano options, defined using the Options type from the cssnano package, allowing for various CSS optimization techniques such as merging rules, reducing colors, and removing whitespace to create smaller CSS files for production
114
+ */
115
+ cssnano?: cssnano.Options;
116
+ };
117
+ /**
118
+ * JavaScript obfuscation options, defined using the ObfuscatorOptions type from the javascript-obfuscator package, allowing for various obfuscation techniques such as control flow flattening, string array encoding, and dead code injection to make the JavaScript code more difficult to reverse engineer
119
+ */
120
+ javascript?: ObfuscatorOptions;
121
+ };
122
+ };
123
+ }
124
+ //#endregion
125
+ //#region src/api.d.ts
126
+ declare function defineConfig<const Find extends BuildFindMap = BuildFindMap>(config: WorkspaceConfig<Find>): WorkspaceConfig<Find>;
127
+ //#endregion
128
+ export { type WorkspaceConfig, defineConfig as default, defineConfig };
package/dist/api.mjs ADDED
@@ -0,0 +1 @@
1
+ import{t as e}from"./workspace-Dp9KM2gK.mjs";function t(t){return e.Service.mergeConfig(t)}export{t as default,t as defineConfig};
@@ -0,0 +1 @@
1
+ import { Command } from "commander";
package/dist/index.mjs ADDED
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ import{n as e,t}from"./workspace-Dp9KM2gK.mjs";import{Command as n}from"commander";import{createRequire as r}from"module";import{existsSync as i,readdirSync as a,unlink as o}from"fs";import s,{basename as c,join as l,relative as u,resolve as d}from"path";import{readFile as f,writeFile as p}from"fs/promises";import m from"inquirer";import{exec as h}from"child_process";import g from"ora";import _ from"cli-spinners";const v=new n;v.name(`tixyel cli`).description(`CLI tool for streamelements widgets made by Tixyel`).version((()=>{try{let{version:e}=r(import.meta.url)(`../package.json`);return e??`dev`}catch{return`dev`}})());const y=[`@tixyel/cli`,`@tixyel/streamelements`,`comfy.js`,`motion`,`typescript`,`@types/node`,`@types/jquery`,`lottie-web`],b={npm:(e,t)=>`npm install ${e.join(` `)}${t?` --no-cache`:``}`,yarn:(e,t)=>`yarn add ${e.join(` `)}${t?` --no-cache`:``}`,pnpm:(e,t)=>`pnpm add ${e.join(` `)}${t?` --no-cache`:``}`,bun:(e,t)=>`bun add ${e.join(` `)}${t?` --no-cache`:``}`};function x(){let e=process.env.npm_config_user_agent;if(e){if(e.includes(`yarn`))return`yarn`;if(e.includes(`pnpm`))return`pnpm`;if(e.includes(`bun`))return`bun`}return`npm`}v.command(`init`).aliases([`initialize`,`start`,`i`,`setup`]).description(`Initialize a new workspace for widget development`).option(`-f --force`,`Force initialization by overwriting existing configuration without confirmation`).action(async(e={})=>{let n=g({color:`magenta`,text:`Checking for existing workspace configuration...`,spinner:_.dotsCircle}).start(),r=await new t.Service({path:process.cwd(),spinner:n}).loadConfig().catch(e=>{n.fail(`Failed to load workspace configuration`),process.exit(1)});if(r&&!e.force){n.stop();let{force:t}=await m.prompt({type:`confirm`,name:`force`,message:`A workspace configuration already exists. Do you want to overwrite it?`,default:!1});if(!t){console.log(`Existing workspace configuration found. Initialization aborted.`);return}e.force=!0,n.start()}if(!r||r&&e.force){let t=d(process.cwd(),`tixyel.config.ts`),a=`import { defineConfig } from '@tixyel/cli/api';
3
+
4
+ export default defineConfig({
5
+ search: {
6
+ maxDepth: 3,
7
+ ignore: ['node_modules', 'dist', 'build', '.git'],
8
+ },
9
+
10
+ metadata: {
11
+ author: 'Your Name',
12
+ },
13
+
14
+ dirs: {
15
+ entry: 'development',
16
+ output: 'finished',
17
+ extension: 'widgetIO',
18
+ },
19
+
20
+ scaffold: [
21
+ {
22
+ name: 'development',
23
+ type: 'folder',
24
+ content: [
25
+ {
26
+ name: 'index.html',
27
+ type: 'file',
28
+ content: \`\`,
29
+ },
30
+ {
31
+ name: 'style.css',
32
+ type: 'file',
33
+ content: \`\`,
34
+ },
35
+ {
36
+ name: 'script.js',
37
+ type: 'file',
38
+ content: \`\`,
39
+ },
40
+ {
41
+ name: 'fields.json',
42
+ type: 'file',
43
+ content: '{}',
44
+ },
45
+ {
46
+ name: 'data.json',
47
+ type: 'file',
48
+ content: '{}',
49
+ },
50
+ ],
51
+ },
52
+ {
53
+ name: 'finished',
54
+ type: 'folder',
55
+ },
56
+ {
57
+ name: 'widgetIO',
58
+ type: 'folder',
59
+ },
60
+ ],
61
+
62
+ build: {
63
+ parallel: true,
64
+ verbose: false,
65
+
66
+ find: {
67
+ html: ['index.html'],
68
+ script: ['script.js'],
69
+ css: ['style.css'],
70
+ fields: ['fields.json', 'fields.jsonc'],
71
+ },
72
+ result: {
73
+ 'HTML.html': 'html',
74
+ 'SCRIPT.js': 'script',
75
+ 'CSS.css': 'css',
76
+ 'FIELDS.json': 'fields',
77
+ },
78
+ widgetIO: {
79
+ 'html.txt': 'html',
80
+ 'js.txt': 'script',
81
+ 'css.txt': 'css',
82
+ 'fields.txt': 'fields',
83
+ },
84
+
85
+ obfuscation: {
86
+ javascript: {
87
+ compact: true,
88
+ log: false,
89
+ debugProtection: false,
90
+ selfDefending: false,
91
+ deadCodeInjection: false,
92
+ controlFlowFlattening: false,
93
+ stringArray: false,
94
+ simplify: false,
95
+ identifierNamesGenerator: 'mangled',
96
+ },
97
+ css: {
98
+ removeNesting: true,
99
+ autoprefixer: {
100
+ overrideBrowserslist: ['Chrome 127'],
101
+ },
102
+ cssnano: {
103
+ preset: 'default',
104
+ },
105
+ },
106
+ html: {
107
+ removeComments: true,
108
+ collapseWhitespace: true,
109
+ minifyCSS: true,
110
+ minifyJS: true,
111
+ removeAttributeQuotes: false,
112
+ },
113
+ },
114
+ },
115
+ });`;i(t)&&r&&e.force?(o(r.path,e=>{if(e){console.error(`Failed to remove existing configuration: ${e}`);return}}),await p(t,a),n.text=`Existing configuration overwritten. Creating new workspace configuration...`):(await p(t,a),n.text=`Workspace configuration created.`)}n.succeed(`Workspace initialization complete!`);let{install:a}=await m.prompt({type:`confirm`,name:`install`,message:`Do you want to install the default dependencies now?`,default:!0});if(a){n.start(`Installing default dependencies...`);let e=x(),t=b[e](y,!1);n.text=`Installing dependencies using ${e}... It might take a few moments.`;try{await new Promise(e=>{h(t,(t,r,i)=>{if(t){n.fail(`Failed to install dependencies: ${t.message}`);return}n.succeed(`Dependencies installed successfully!`),e(r)})})}catch(e){n.fail(`Failed to execute install command: ${e}`)}}console.log(``),console.log(`🎉 Workspace setup is complete!`),console.log(` Edit ${r?.file??`tixyel.config.ts`} to customize your widget development experience.`),console.log(` Run 'tixyel generate' to create your first widget!`),console.log(` Run 'tixyel build' to build your widgets for use!`),console.log(``)});async function S(e){try{if(!i(e))return`01`;let t=a(e).filter(e=>/^\d+\s*-\s*/.test(e)).map(e=>parseInt(e.split(`-`)[0],10)).filter(e=>!isNaN(e)),n=t.length>0?Math.max(...t):0;return String(n+1).padStart(2,`0`)}catch{return`01`}}v.command(`generate [path] [name] [description] [tags]`).aliases([`new`,`create`,`g`,`c`,`widget`]).description(`Generate a new widget in the current workspace`).action(async(e,n,r,i)=>{let a=g({color:`magenta`,text:`Loading workspace configuration...`,spinner:_.aesthetic}).start(),o=new t.Service({path:process.cwd(),spinner:a});await o.loadConfig().catch(e=>{a.fail(`Failed to load workspace configuration`),process.exit(1)})||(a.color=`red`,a.fail(`No workspace configuration found. Please run "tixyel init" to initialize a workspace before generating a widget.`),process.exit(1)),a.text=`Generating widget...`,a.color=`green`;let s=e?d(o.root,e.replace(/[/\\]$/,``)):o.root,u=e?e.endsWith(`/`)||e.endsWith(`\\`):!1,f=n;if(u)f=c(s);else if(!f){a.stop();let e=`${await S(o.root)} - Custom Widget`,{name:t}=await m.prompt({name:`name`,type:`input`,message:`Enter a name for the widget:`,default:e});t||(console.log(`Widget name is required. Widget generation aborted.`),process.exit(1)),f=t}if(!r){let{description:e}=await m.prompt({name:`description`,type:`input`,message:`Enter a description for the widget:`});r=e??``}if(!i){let{tags:e}=await m.prompt({name:`tags`,type:`input`,message:`Enter tags for the widget (comma separated):`});i=e??``}a.start(),a.text=`📂 Creating widget ${n} at ${s}`;let p=await o.createWidget(l(o.root,f),{name:f.replace(/^\d+\s*-\s*/,``),description:r,tags:i?i.split(`,`).map(e=>e.trim()):[]});a.succeed(`Widget "${f}" generated successfully at ${s}`),console.log(``),p.config.description.length&&console.log(` - Description: ${p.config.description}`),p.config.metadata?.tags?.length&&console.log(` - Tags: ${p.config.metadata?.tags.join(`, `)}`),(p.content.files||p.content.folders)&&console.log(` - Scaffold created with ${p.content.folders} folders and ${p.content.files} files`),p.config.config&&console.log(` - Config path: ${p.config.config}`),console.log(``)}),v.command(`build`).aliases([`b`,`compact`,`compie`,`bundle`]).description(`Build the widgets in the current workspace`).option(`-p --parallel`,`Build widgets in parallel`).option(`-d --depth <number>`,`Maximum directory depth to search for widget files`,parseInt).option(`-v --verbose`,`Enable verbose logging during the build process`).option(`-w --widgets <names...>`,`Specify which widgets to build by name`,e=>e===`*`?`*`:String(e??``).split(`,`).map(e=>e.trim())).option(`-b --bump <type>`,`Bump version of built widgets (none, patch, minor, major)`).action(async n=>{let r=g({text:`Loading workspace configuration...`,color:`magenta`,spinner:_.dotsCircle}).start(),a=new t.Service({spinner:r});if(i(`.tixyel`)){let t=JSON.parse(await f(`.tixyel`,`utf-8`)),n=new e.Service({relativePath:u(process.cwd(),t.path),config:t,path:process.cwd(),workspace:a});console.log(`ahadsfuihauidbhwa`),n.config.config||(r.fail(`Invalid widget configuration found in .tixyel file`),process.exit(1)),a.root=s.join(process.cwd(),n.config.config),n.relativePath=u(a.root,n.path),r.succeed(`Loaded widget configuration from .tixyel file`)}let o=await a.loadConfig().catch(e=>{console.error(`Failed to load workspace configuration:`,e),process.exit(1)});o||(r.fail(`No workspace configuration found. Please run "tixyel init" to create a workspace configuration before building.`),process.exit(1));let c=o.data.search?.maxDepth;r.start(`🔎 Searching for widgets (max depth: ${c})...`);let l=await a.findWidgets(n.depth??void 0);l.length||(r.fail(`No widgets found in the workspace. Please ensure you have widgets configured correctly.`),process.exit(1));let d=[];if(n.widgets&&n.widgets&&n.widgets!==void 0)n.widgets===`*`?(d=l.map(e=>e.path),r.succeed(`Auto-selected widgets for build (${d.length} widgets)`),await new Promise(e=>setTimeout(e,1e3))):(d=l.filter(e=>n.widgets.some(t=>e.config.name===t||e.path.includes(t))).map(e=>e.path),d.length||(r.fail(`No widgets matched the specified names. Please check the --widgets option and try again.`),process.exit(1)),r.text=`Selected widgets for build (${d.length} widgets)`);else if(l.length===1)d=[l[0].path],r.start(),r.succeed(`Auto-selected single widget for build: ${l[0].config.name}`);else{r.stop();let e=Math.max(...l.map(e=>e.config.name.length))+2,t=l.map(t=>({name:`${t.config.name.padEnd(e,` `)} (${t.relativePath.startsWith(`.`)?t.relativePath.replace(/\\/g,`/`):`./${t.relativePath}`.replace(/\\/g,`/`)})`,value:t.path,checked:!1})),{selected:n}=await m.prompt({type:`checkbox`,name:`selected`,message:`Select which widgets to build:`,choices:t,pageSize:10,loop:!1,theme:{checkbox:{on:`[x]`,off:`[ ]`}}});d=n,r.start()}d.length||(r.isSpinning?r.fail(`No widgets selected for build. Please select at least one widget to build.`):console.log(`❌ No widgets selected for build. Please select at least one widget to build.`));let p=`none`;if(n.bump){r.start();let e=[`none`,`patch`,`minor`,`major`];e.includes(n.bump)||(r.fail(`Invalid bump type "${n.bump}". Valid options are: ${e.join(`, `)}. Defaulting to "none".`),process.exit(1)),p=n.bump,r.succeed(`📌 Version bump: ${p}`)}else{r.stop();let{version:e}=await m.prompt({type:`select`,name:`version`,message:`Select version bump type for built widgets:`,choices:[{name:`None (keep current version)`,value:`none`},{name:`Patch (x.x.1)`,value:`patch`},{name:`Minor (x.1.0)`,value:`minor`},{name:`Major (1.0.0)`,value:`major`}],default:`none`,loop:!1,pageSize:4});p=e}let h=n.parallel??a.config.data.build?.parallel??!1,v=n.verbose??a.config.data.build?.verbose??!1;if(r.start(),r.text=`🚀 Starting build for ${d.length} widget(s) with${h?` parallel`:``} build and${v?` verbose logging`:``}...`,h)await Promise.all(d.map(async e=>new Promise(async t=>{let n=l.find(t=>t.path===e);return n&&await n.build(v,p).catch(t=>{r.fail(`Failed to build widget at ${e}: ${t}`)}),t(n),n})));else for await(let e of d){let t=l.find(t=>t.path===e);t&&(r.text=`🚀 Building widget: ${t.config.name} (${t.relativePath})...`,await t.build(v,p).catch(t=>{r.fail(`Failed to build widget at ${e}: ${t}`)}))}r.succeed(`Build process complete!`)}),process.on(`unhandledRejection`,(e,t)=>{process.exit(0)}).on(`uncaughtException`,e=>{if(e instanceof Error&&e.name===`ExitPromptError`)console.log(`👋 until next time!`);else throw e}).on(`SIGINT`,()=>{process.exit(0)}),v.parse();export{};
@@ -0,0 +1,34 @@
1
+ import{existsSync as e,mkdirSync as t,readFileSync as n,unlinkSync as r,writeFileSync as i}from"fs";import{dirname as a,extname as o,join as s,relative as c,resolve as l}from"path";import{mkdir as u,readFile as d,writeFile as f}from"fs/promises";import{transform as p,transformSync as m}from"esbuild";import{renderToStaticMarkup as h}from"react-dom/server";import{isValidElement as g}from"react";import{parse as _}from"jsonc-parser";import v from"postcss";import y from"cssnano";import b from"jszip";import x from"postcss-nested";import S from"autoprefixer";import{minify as C}from"html-minifier-terser";import w from"javascript-obfuscator";import T from"fast-glob";const E={entry:`development`,output:`finished`,extension:`widgetIO`},D=[`tixyel.config.ts`,`tixyel.config.tsx`,`tixyel.config.js`,`tixyel.config.mjs`,`tixyel.config.cjs`,`tixyel.config.json`,`tixyel.config.jsonc`,`.tixyelrc`,`.tixyelrc.json`,`.tixyelrc.jsonc`,`.tixyelrc.js`,`.tixyelrc.ts`,`.tixyelrc.mjs`,`.tixyelrc.cjs`],O={search:{maxDepth:3,ignore:[`node_modules`,`dist`,`build`,`out`,`coverage`,`.git`,`.svn`,`.hg`]},dirs:E,scaffold:[{name:`development`,type:`folder`,content:[{name:`index.html`,type:`file`,content:``},{name:`style.css`,type:`file`,content:``},{name:`script.js`,type:`file`,content:``},{name:`fields.json`,type:`file`,content:`{}`},{name:`data.json`,type:`file`,content:`{}`}]},{name:`finished`,type:`folder`},{name:`resources`,type:`folder`}],build:{parallel:!0,verbose:!1,find:{html:[`index.html`],css:[`style.css`],script:[`script.js`],fields:[`fields.json`]},result:{"HTML.html":`html`,"CSS.css":`css`,"SCRIPT.js":`script`,"FIELDS.json":`fields`},widgetIO:{"html.txt":`html`,"css.txt":`css`,"js.txt":`script`,"fields.txt":`fields`},obfuscation:{html:{},css:{removeNesting:!0,autoprefixer:{overrideBrowserslist:[`Chrome 127`]},cssnano:{}},javascript:{}}}};var k=` ____ _ _ _
2
+ / __ \\ | |_ (_) __ __ _ _ ___ | |
3
+ / / _\` | | __| | | \\ \\/ / | | | | / _ \\ | |
4
+ | | (_| | | |_ | | > < | |_| | | __/ | |
5
+ \\ \\__,_| \\__| |_| /_/\\_\\ \\__, | \\___| |_|
6
+ \\____/ |___/
7
+ `;const A={html(e){return[`<!---`,k,`Generated by @Tixyel Widgets SDK`,`Widget name: ${e.config.name}`,`Version: ${e.config.version}`,`Description: ${e.config.description}`,`Tags: ${e.config.metadata?.tags?.join(`, `)}`,`Made by: ${e.config.metadata?.author}`,e.config.metadata?.clientId?`Made for: ${e.config.metadata?.clientId}`:void 0,...Object.entries(e.config.metadata||{}).filter(([e])=>![`tags`,`author`,`clientId`].includes(e)).map(([e,t])=>`${e}: ${t}`),` `,`DO NOT EDIT, SHARE OR DISTRIBUTE THIS CODE WITHOUT PERMISSION FROM THE AUTHOR`,`--->`].filter(Boolean).join(`
8
+ `)},css(e){return[`/**`,k,`Generated by @Tixyel Widgets SDK`,`Widget name: ${e.config.name}`,`Version: ${e.config.version}`,`Description: ${e.config.description}`,`Tags: ${e.config.metadata?.tags?.join(`, `)}`,`Made by: ${e.config.metadata?.author}`,e.config.metadata?.clientId?`Made for: ${e.config.metadata?.clientId}`:void 0,...Object.entries(e.config.metadata||{}).filter(([e])=>![`tags`,`author`,`clientId`].includes(e)).map(([e,t])=>`${e}: ${t}`),` `,`DO NOT EDIT, SHARE OR DISTRIBUTE THIS CODE WITHOUT PERMISSION FROM THE AUTHOR`,`*/`].filter(Boolean).join(`
9
+ `)},script(e){return[`/**`,k,`Generated by @Tixyel Widgets SDK`,`Widget name: ${e.config.name}`,`Version: ${e.config.version}`,`Description: ${e.config.description}`,`Tags: ${e.config.metadata?.tags?.join(`, `)}`,`Made by: ${e.config.metadata?.author}`,e.config.metadata?.clientId?`Made for: ${e.config.metadata?.clientId}`:void 0,...Object.entries(e.config.metadata||{}).filter(([e])=>![`tags`,`author`,`clientId`].includes(e)).map(([e,t])=>`${e}: ${t}`),` `,`DO NOT EDIT, SHARE OR DISTRIBUTE THIS CODE WITHOUT PERMISSION FROM THE AUTHOR`,`*/`].filter(Boolean).join(`
10
+ `)}};let j;(function(r){class a{constructor(e){this.content={folders:0,files:0},this.path=e.path,this.config=e.config,this.workspace=e.workspace,this.spinner=this.workspace.spinner,this.relativePath=e.relativePath,this.content=e.content??{folders:0,files:0}}async build(r=this.workspace.config.data.build?.verbose??!1,a=`none`){a!==`none`&&await this.bumpVersion(a);try{let a=s(this.path,this.config.dirs?.entry??this.workspace.config.data.dirs?.entry??`development`),o=s(this.path,this.config.dirs?.output??this.workspace.config.data.dirs?.output??`finished`),c=s(this.path,this.config.dirs?.extension??this.workspace.config.data.dirs?.extension??`widgetIO`);if(!e(a))throw Error(`Entry directory does not exist: ${a}`);t(o,{recursive:!0});let l=this.config.build?.find??this.workspace.config.data.build?.find??{html:[`index.html`],script:[`script.js`],typescript:[`script.ts`],css:[`styles.css`],fields:[`fields.json`]},u=this.config.build?.result??this.workspace.config.data.build?.result??{"HTML.html":`html`,"SCRIPT.js":`script`,"CSS.css":`css`,"FIELDS.json":`fields`},d=this.config.build?.widgetIO??this.workspace.config.data.build?.widgetIO??{"html.txt":`html`,"js.txt":`script`,"css.txt":`css`,"fields.txt":`fields`},f=e=>Array.isArray(e)?e.filter(Boolean):[],p=(t,r)=>{let i={};for(let a of r){let r=s(t,a);e(r)&&(i[a]=n(r,`utf-8`))}return i},h=new Set,g=new Set,T=Object.fromEntries(await Promise.all(Object.entries(l).map(async([e,t])=>{let n=``,i=f(t.filter(e=>!g.has(e)));if(!i.length)return[e,``];let o=(t,n)=>(!Array.isArray(t)&&(t=[t]),!Array.isArray(n)&&(n=[n]),t.some(t=>e.toLowerCase()===t.toLowerCase())||i.some(e=>n.some(t=>e.toLowerCase().endsWith(t.toLowerCase())))),s=new Set;if(o(`html`,`.html`)){h.has(`html`)||(n+=A.html(this)+`
11
+ `),h.add(`html`);let t=i.filter(e=>e.endsWith(`.html`)&&!g.has(e));r&&console.log(` - Processing HTML for ${this.config.name} [${e}, ${t.join(`, `)}]...`);let o=p(a,t),c=``;for await(let[e,t]of Object.entries(o)){let n=t.match(/<body[^>]*>([\s\S]*?)<\/body>/i);n&&n[1]&&(c+=n[1].trim()+`
12
+ `,g.add(e))}let l=await C(c,this.workspace.config.data.build?.obfuscation?.html);n+=l.trim(),s.add(`html`)}if(o([`css`,`style`,`styles`],`.css`)){h.has(`css`)||(n+=A.css(this)+`
13
+ `),h.add(`css`);let t=i.filter(e=>e.endsWith(`.css`)&&!g.has(e));r&&console.log(` - Processing CSS for ${this.config.name} [${e}, ${t.join(`, `)}]...`);let o=p(a,t),c=``;for await(let[e,t]of Object.entries(o)){let n=[S({overrideBrowserslist:[`Chrome 127`],...this.workspace.config.data.build?.obfuscation?.css?.autoprefixer}),y(this.workspace.config.data.build?.obfuscation?.css?.cssnano)];this.workspace.config.data.build?.obfuscation?.css?.removeNesting&&n.unshift(x());let r=await v(n).process(t,{from:void 0});c+=r.css+`
14
+ `,g.add(e)}s.has(`html`)?n=n+=`<style>${c.trim()}</style>`:n+=c.trim(),s.add(`css`)}if(o([`typescript`,`ts`],`.ts`)){h.has(`script`)||(n+=A.script(this)+`
15
+ `),h.add(`script`);let t=i.filter(e=>e.endsWith(`.ts`)&&!g.has(e));r&&console.log(` - Processing TypeScript for ${this.config.name} [${e}, ${t.join(`, `)}]...`);let o=p(a,t),c=``;for await(let[e,t]of Object.entries(o))try{let e=m(t,{loader:`ts`,target:`es2020`,format:`cjs`});c+=e.code+`
16
+ `}catch(e){throw console.warn(` ⚠️ Failed to compile TypeScript: ${e}`),e}finally{g.add(e)}let l=w.obfuscate(c.trim(),this.workspace.config.data.build?.obfuscation?.javascript);s.has(`html`)?n=n+=`<script>${l.getObfuscatedCode()}<\/script>\n`:n+=l.getObfuscatedCode()+`
17
+ `,s.add(`typescript`)}if(o([`script`,`js`,`javascript`],`.js`)){h.has(`script`)||(n+=A.script(this)+`
18
+ `),h.add(`script`);let t=i.filter(e=>e.endsWith(`.js`)&&!g.has(e));r&&console.log(` - Processing JavaScript for ${this.config.name} [${e}, ${t.join(`, `)}]...`);let o=p(a,t),c=``;for await(let[e,t]of Object.entries(o)){let n=w.obfuscate(t,this.workspace.config.data.build?.obfuscation?.javascript);c+=n.getObfuscatedCode()+`
19
+ `,g.add(e)}s.has(`html`)?n=n+=`<script>${c.trim()}<\/script>`:n+=c.trim(),s.add(`script`)}if(o([`fields`,`fielddata`,`fieldData`,`cf`,`customfields`],`.json`)){let t=i.filter(e=>e.endsWith(`.json`)&&!g.has(e));r&&console.log(` - Processing JSON for ${this.config.name} [${e}, ${t.join(`, `)}]...`);let o=p(a,t),c={};for await(let[e,t]of Object.entries(o))try{let e=_(t),n=JSON.parse(JSON.stringify(e));Object.assign(c,n)}catch(e){throw console.warn(` ⚠️ Failed to parse fields JSON: ${e}`),e}s.size||(n+=JSON.stringify(c,null,2)),s.add(`fields`)}return n.length||(r&&console.log(` - Unknown build key: ${e}, the available keys are html, css, script and fields.`),n+=``),[e,n]})));for await(let[e,t]of Object.entries(u)){let n=``;if(typeof t==`string`)n=T[t];else if(Array.isArray(t))for await(let e of t){let t=T[e];t&&(n+=`
20
+ `+t,r&&console.log(` ✓ Merged part for: ${e}`))}if(n){let t=s(o,e);i(t,n,`utf-8`),r&&console.log(` ✓ Written: ${t}`)}}try{let e=new b;for await(let[t,n]of Object.entries(d)){let i=``;if(typeof n==`string`)i=T[n];else if(Array.isArray(n))for await(let e of n){let t=T[e];t&&(i+=`
21
+ `+t,r&&console.log(` ✓ Merged part for ZIP: ${e}`))}i&&(e.file(t,i),r&&console.log(` ✓ Added to ZIP: ${t}`))}e.file(`widget.ini`,`[HTML]
22
+ path = "html.txt"
23
+
24
+ [CSS]
25
+ path = "css.txt"
26
+
27
+ [JS]
28
+ path = "js.txt"
29
+
30
+ [FIELDS]
31
+ path = "fields.txt"
32
+
33
+ [DATA]
34
+ path = "data.txt"`);let n=T.data||`{}`;e.file(`data.txt`,n);let a=await e.generateInternalStream({type:`base64`}).accumulate().then(e=>e),o=s(c+`/`+(this.config.version||`0.0.0`),`${this.config.name}.zip`);t(c+`/`+(this.config.version||`0.0.0`),{recursive:!0}),i(o,a,`base64`)}catch(e){throw Error(`Failed to create ZIP archive: ${e}`)}}catch(e){throw Error(`Failed to build widget: ${e}`)}}async bumpVersion(e){let t=l(this.path,`.tixyel`),n=this.config;n.version||=`0.0.0`;let[r,i,a]=n.version.split(`.`).map(Number),o;switch(e){case`major`:o=`${r+1}.0.0`;break;case`minor`:o=`${r}.${i+1}.0`;break;case`patch`:o=`${r}.${i}.${a+1}`;break}return n.version=o,await f(t,JSON.stringify(n,null,2),`utf-8`),o}static async readConfig(t){try{let n=l(t,`.tixyel`);if(!e(n))return null;let r=_(await d(n,`utf-8`));return typeof r!=`object`||!r||r===null||!r?.name||typeof r.name!=`string`||!r.name.trim().length?null:a.mergeConfig(r)}catch{}return null}static async mergeConfig(e){return{...e,version:e.version??`0.0.0`,description:e.description??``,metadata:{...e.metadata},dirs:{entry:e.dirs?.entry??`development`,output:e.dirs?.output??`finished`,extension:e.dirs?.extension??`widgetIO`}}}}r.Service=a})(j||={});let M;(function(t){class s{constructor(e){this.root=e?.path??process.cwd(),this.config=e?.config??{data:O,path:this.root,file:`tixyel.config.ts`},this.spinner=e?.spinner}async loadConfig(){let t=D.find(t=>e(l(this.root,t)));if(!t)return null;let r,i=l(this.root,t);try{if(t.endsWith(`.ts`)||t.endsWith(`.tsx`))r=await s.loadTsConfig(this.root,i);else if(t.endsWith(`.js`)||t.endsWith(`.mjs`)||t.endsWith(`.cjs`)){let e=await import(i);r=e.default??e.config}else if(t.endsWith(`.json`)||t.endsWith(`.jsonc`)||t===`.tixyelrc`){let e=n(i,`utf-8`);r=JSON.parse(e)}else throw Error(`Unsupported configuration file format: ${t}`)}catch(e){throw Error(`Failed to load workspace configuration: ${e}`)}finally{if(!r)return null;r=s.mergeConfig(r);let e={data:r,path:i,file:t};return this.config=e,e}}async createWidget(e,t){try{await u(e,{recursive:!0});let n=c(e,this.config.path).replace(/\\/g,`/`),r={name:t?.name,description:t?.description,version:`0.0.0`,config:n.startsWith(`.`)?n:`./${n}`,metadata:{...this.config.data.metadata,...t,name:void 0,description:void 0},dirs:this.config.data.dirs??{entry:`development`,output:`finished`,extension:`widgetIO`}};await f(l(e,`.tixyel`),JSON.stringify(r,null,2),`utf-8`);let i=this.config.data.scaffold??[],a={files:0,folders:0};async function o(e){return e===void 0||e===void 0||!e?``:typeof e==`string`?e:g(e)?h(e):String(e??``)}async function s(e,t){let n=l(t,e.name);e.type===`folder`?(await u(n,{recursive:!0}),a.folders++,e.content&&Array.isArray(e.content)&&e.content.length&&await Promise.all(e.content.map(e=>s(e,n)))):e.type===`file`&&(await f(n,await o(e.content),`utf-8`),a.files++)}return await Promise.all(i.map(t=>s(t,e))),new j.Service({relativePath:c(this.root,e),config:r,content:a,path:e,workspace:this})}catch(e){throw Error(`Failed to create widget: ${e}`)}}async findWidgets(e=this.config.data.search?.maxDepth??5,t=this.config.data.search?.ignore??[]){let n=await T(`{${Array.from({length:e},(e,t)=>`*`.repeat(t+1)).join(`,`)}}/.tixyel`,{cwd:this.root,absolute:!0,onlyFiles:!0,ignore:[`node_modules`,`.git`,`dist`,...t]});return(await Promise.all(n.map(e=>new Promise(async t=>{let n=a(e),r=await j.Service.readConfig(n);if(!r||r===null)return t(null),null;let i=new j.Service({path:n,config:r,relativePath:c(this.root,n),workspace:this});return t(i),i})))).filter(e=>e!==null)}static mergeConfig(e){let t=O;return{...e||{},search:{...t.search,...e?.search||{}},metadata:{...t.metadata,...e?.metadata||{}},dirs:{...t.dirs,...e?.dirs||{}},scaffold:e?.scaffold||t.scaffold,build:{...t.build,...e?.build||{},obfuscation:{...t.build?.obfuscation,...e?.build?.obfuscation||{}}}}}static async loadTsConfig(e,t){let a=l(e,`.temp.tixyel.config.mjs`),s=n(t,`utf-8`),c=o(t).toLowerCase(),u=c===`.tsx`?`tsx`:c===`.jsx`?`jsx`:`ts`,{code:d}=await p(s,{loader:u,format:`esm`,target:`es2022`,...u===`tsx`||u===`jsx`?{jsx:`automatic`}:{}});i(a,d,`utf-8`);try{let e=await import(`file://${a}?t=${Date.now()}`);try{r(a)}catch(e){throw Error(`Failed to clean up temporary configuration file: ${e}`)}return e.default??e.config}catch(e){throw Error(`Failed to load TypeScript workspace configuration: ${e}`)}}}t.Service=s})(M||={});export{j as n,M as t};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tixyel/cli",
3
- "version": "2.7.1",
3
+ "version": "3.0.0",
4
4
  "description": "CLI tool for streamelements widgets",
5
5
  "keywords": [
6
6
  "cli",
@@ -27,20 +27,20 @@
27
27
  "type": "module",
28
28
  "private": false,
29
29
  "bin": {
30
- "tixyel": "./dist/index.js"
30
+ "tixyel": "./dist/index.mjs"
31
31
  },
32
- "main": "./dist/index.js",
33
- "types": "./dist/index.d.ts",
32
+ "main": "./dist/index.mjs",
33
+ "types": "./dist/index.d.mts",
34
34
  "exports": {
35
35
  ".": {
36
- "types": "./dist/index.d.ts",
37
- "import": "./dist/index.js",
38
- "default": "./dist/index.js"
36
+ "types": "./dist/index.d.mts",
37
+ "import": "./dist/index.mjs",
38
+ "default": "./dist/index.mjs"
39
39
  },
40
40
  "./api": {
41
- "types": "./dist/api.d.ts",
42
- "import": "./dist/api.js",
43
- "default": "./dist/api.js"
41
+ "types": "./dist/api.d.mts",
42
+ "import": "./dist/api.mjs",
43
+ "default": "./dist/api.mjs"
44
44
  }
45
45
  },
46
46
  "files": [
@@ -48,17 +48,19 @@
48
48
  "package.json"
49
49
  ],
50
50
  "scripts": {
51
- "build": "cross-env TIXYEL_VERSION=$npm_package_version tsc",
52
- "dev": "cross-env TIXYEL_VERSION=$npm_package_version tsc --watch",
51
+ "build": "cross-env TIXYEL_VERSION=$npm_package_version tsdown",
52
+ "dev": "cross-env TIXYEL_VERSION=$npm_package_version tsdown --watch",
53
53
  "check-types": "tsc --noEmit",
54
- "test": "bun test"
54
+ "test": "bun test",
55
+ "cli": "cross-env TIXYEL_VERSION=$npm_package_version bun run src/index.ts"
55
56
  },
56
57
  "dependencies": {
57
58
  "autoprefixer": "^10.4.22",
59
+ "chokidar": "^3.6.0",
60
+ "cli-spinners": "^3.4.0",
58
61
  "commander": "^14.0.2",
59
62
  "cross-env": "^10.1.0",
60
63
  "cssnano": "^7.1.2",
61
- "chokidar": "^3.6.0",
62
64
  "esbuild": "^0.25.12",
63
65
  "fast-glob": "^3.3.3",
64
66
  "html-minifier-terser": "^7.2.0",
@@ -66,6 +68,7 @@
66
68
  "javascript-obfuscator": "4.1.1",
67
69
  "jsonc-parser": "^3.3.1",
68
70
  "jszip": "^3.10.1",
71
+ "ora": "^9.3.0",
69
72
  "postcss": "^8.5.6",
70
73
  "postcss-nested": "^7.0.2",
71
74
  "react": "^19.2.1",
@@ -80,6 +83,8 @@
80
83
  "@types/react": "^19.2.7",
81
84
  "@types/react-dom": "^19.2.3",
82
85
  "@types/ws": "^8.5.12",
86
+ "@typescript/native-preview": "^7.0.0-dev.20260216.1",
87
+ "tsdown": "^0.20.3",
83
88
  "typescript": "^5.9.3"
84
89
  },
85
90
  "publishConfig": {
package/dist/api.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export { defineWorkspaceConfig } from './workspace.js';
2
- export type { WorkspaceConfig } from './workspace.js';
package/dist/api.js DELETED
@@ -1 +0,0 @@
1
- export { defineWorkspaceConfig } from './workspace.js';
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};