@steambrew/ttc 1.4.2 → 2.4.3

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/Compiler.ts CHANGED
@@ -3,9 +3,14 @@ import json from '@rollup/plugin-json';
3
3
  import commonjs from '@rollup/plugin-commonjs';
4
4
  import replace from '@rollup/plugin-replace';
5
5
  import typescript from '@rollup/plugin-typescript';
6
- import resolve from '@rollup/plugin-node-resolve';
6
+ import resolve, { nodeResolve } from '@rollup/plugin-node-resolve';
7
7
  import terser from '@rollup/plugin-terser';
8
8
  import babel from '@rollup/plugin-babel';
9
+ import nodePolyfills from 'rollup-plugin-polyfill-node';
10
+ import url from '@rollup/plugin-url';
11
+
12
+ import scss from 'rollup-plugin-scss';
13
+ import * as sass from 'sass';
9
14
 
10
15
  import chalk from 'chalk';
11
16
  import { Logger } from './Logger';
@@ -14,11 +19,12 @@ import fs from 'fs';
14
19
  import injectProcessEnv from 'rollup-plugin-inject-process-env';
15
20
  import dotenv from 'dotenv';
16
21
  import { ExecutePluginModule, InitializePlugins } from './PluginSetup';
22
+ import constSysfsExpr from './StaticEmbed';
17
23
 
18
24
  const envConfig = dotenv.config().parsed || {};
19
25
 
20
26
  if (envConfig) {
21
- Logger.Info('Injecting environment variables...');
27
+ Logger.Info('envVars', 'Processing ' + Object.keys(envConfig).length + ' environment variables... ' + chalk.green.bold('okay'));
22
28
  }
23
29
 
24
30
  const envVars = Object.keys(envConfig).reduce((acc: any, key) => {
@@ -64,7 +70,7 @@ function InsertMillennium(type: ComponentType, props: TranspilerProps) {
64
70
  continue;
65
71
  }
66
72
 
67
- Logger.Info('Injecting Millennium shims into ' + ComponentType[type] + ' module... ' + chalk.green.bold('okay'));
73
+ Logger.Info('millenniumAPI', 'Bundling into ' + ComponentType[type] + ' module... ' + chalk.green.bold('okay'));
68
74
 
69
75
  bundle[fileName].code = ConstructFunctions([
70
76
  `const MILLENNIUM_IS_CLIENT_MODULE = ${type === ComponentType.Plugin ? 'true' : 'false'};`,
@@ -83,21 +89,71 @@ function InsertMillennium(type: ComponentType, props: TranspilerProps) {
83
89
  return { name: String(), generateBundle };
84
90
  }
85
91
 
86
- function GetPluginComponents(props: TranspilerProps) {
87
- let tsConfigPath = `./${GetFrontEndDirectory()}/tsconfig.json`;
92
+ async function GetCustomUserPlugins() {
93
+ const ttcConfigPath = new URL(`file://${process.cwd().replace(/\\/g, '/')}/ttc.config.mjs`).href;
94
+
95
+ if (fs.existsSync('./ttc.config.mjs')) {
96
+ const { MillenniumCompilerPlugins } = await import(ttcConfigPath);
97
+
98
+ Logger.Info('millenniumAPI', 'Loading custom plugins from ttc.config.mjs... ' + chalk.green.bold('okay'));
99
+ return MillenniumCompilerPlugins;
100
+ }
101
+
102
+ return [];
103
+ }
104
+
105
+ async function MergePluginList(plugins: any[]) {
106
+ const customPlugins = await GetCustomUserPlugins();
107
+
108
+ // Filter out custom plugins that have the same name as input plugins
109
+ const filteredCustomPlugins = customPlugins.filter((customPlugin: any) => !plugins.some((plugin: any) => plugin.name === customPlugin.name));
110
+
111
+ // Merge input plugins with the filtered custom plugins
112
+ return [...plugins, ...filteredCustomPlugins];
113
+ }
114
+
115
+ async function GetPluginComponents(props: TranspilerProps) {
116
+ let tsConfigPath = '';
117
+ const frontendDir = GetFrontEndDirectory();
118
+
119
+ if (frontendDir === '.' || frontendDir === './') {
120
+ tsConfigPath = './tsconfig.json';
121
+ } else {
122
+ tsConfigPath = `./${frontendDir}/tsconfig.json`;
123
+ }
88
124
 
89
125
  if (!fs.existsSync(tsConfigPath)) {
90
126
  tsConfigPath = './tsconfig.json';
91
127
  }
92
128
 
93
- const pluginList = [
129
+ Logger.Info('millenniumAPI', 'Loading tsconfig from ' + chalk.cyan.bold(tsConfigPath) + '... ' + chalk.green.bold('okay'));
130
+
131
+ let pluginList = [
132
+ url({
133
+ include: ['**/*.gif', '**/*.webm', '**/*.svg'], // Add all non-JS assets you use
134
+ limit: 0, // Set to 0 to always copy the file instead of inlining as base64
135
+ fileName: '[hash][extname]', // Optional: custom output naming
136
+ }),
94
137
  InsertMillennium(ComponentType.Plugin, props),
138
+ commonjs(),
139
+ nodePolyfills(),
140
+ nodeResolve({
141
+ browser: true,
142
+ }),
95
143
  typescript({
144
+ include: ['**/*.ts', '**/*.tsx', 'src/**/*.ts', 'src/**/*.tsx'],
96
145
  tsconfig: tsConfigPath,
97
146
  }),
147
+ scss({
148
+ output: false,
149
+ outputStyle: 'compressed',
150
+ sourceMap: false,
151
+ watch: 'src/styles',
152
+ sass: sass,
153
+ }),
98
154
  resolve(),
99
- commonjs(),
100
155
  json(),
156
+ constSysfsExpr(),
101
157
  injectProcessEnv(envVars),
102
158
  replace({
103
159
  delimiters: ['', ''],
@@ -117,15 +173,22 @@ function GetPluginComponents(props: TranspilerProps) {
117
173
  return pluginList;
118
174
  }
119
175
 
120
- function GetWebkitPluginComponents(props: TranspilerProps) {
121
- const pluginList = [
176
+ async function GetWebkitPluginComponents(props: TranspilerProps) {
177
+ let pluginList = [
122
178
  InsertMillennium(ComponentType.Webkit, props),
123
179
  typescript({
124
180
  tsconfig: './webkit/tsconfig.json',
125
181
  }),
182
+ url({
183
+ include: ['**/*.mp4', '**/*.webm', '**/*.ogg'],
184
+ limit: 0, // do NOT inline
185
+ fileName: '[name][extname]',
186
+ destDir: 'dist/assets', // or adjust as needed
187
+ }),
126
188
  resolve(),
127
189
  commonjs(),
128
190
  json(),
191
+ constSysfsExpr(),
129
192
  injectProcessEnv(envVars),
130
193
  replace({
131
194
  delimiters: ['', ''],
@@ -140,6 +203,8 @@ function GetWebkitPluginComponents(props: TranspilerProps) {
140
203
  }),
141
204
  ];
142
205
 
206
+ pluginList = await MergePluginList(pluginList);
207
+
143
208
  props.bTersePlugin && pluginList.push(terser());
144
209
  return pluginList;
145
210
  }
@@ -156,7 +221,7 @@ const GetFrontEndDirectory = () => {
156
221
  export const TranspilerPluginComponent = async (props: TranspilerProps) => {
157
222
  const frontendRollupConfig: RollupOptions = {
158
223
  input: `./${GetFrontEndDirectory()}/index.tsx`,
159
- plugins: GetPluginComponents(props),
224
+ plugins: await GetPluginComponents(props),
160
225
  context: 'window',
161
226
  external: (id) => {
162
227
  if (id === '@steambrew/webkit') {
@@ -182,17 +247,13 @@ export const TranspilerPluginComponent = async (props: TranspilerProps) => {
182
247
  },
183
248
  };
184
249
 
185
- Logger.Info('Starting build; this may take a few moments...');
186
-
187
250
  try {
188
251
  await (await rollup(frontendRollupConfig)).write(frontendRollupConfig.output as OutputOptions);
189
252
 
190
253
  if (fs.existsSync(`./webkit/index.tsx`)) {
191
- Logger.Info('Compiling webkit module...');
192
-
193
254
  const webkitRollupConfig: RollupOptions = {
194
255
  input: `./webkit/index.tsx`,
195
- plugins: GetWebkitPluginComponents(props),
256
+ plugins: await GetWebkitPluginComponents(props),
196
257
  context: 'window',
197
258
  external: (id) => {
198
259
  if (id === '@steambrew/client') {
@@ -218,9 +279,9 @@ export const TranspilerPluginComponent = async (props: TranspilerProps) => {
218
279
  await (await rollup(webkitRollupConfig)).write(webkitRollupConfig.output as OutputOptions);
219
280
  }
220
281
 
221
- Logger.Info('Build succeeded!', Number((performance.now() - global.PerfStartTime).toFixed(3)), 'ms elapsed.');
282
+ Logger.Info('build', 'Succeeded passing all tests in', Number((performance.now() - global.PerfStartTime).toFixed(3)), 'ms elapsed.');
222
283
  } catch (exception) {
223
- Logger.Error('Build failed!', exception);
284
+ Logger.Error('error', 'Build failed!', exception);
224
285
  process.exit(1);
225
286
  }
226
287
  };
package/Logger.ts CHANGED
@@ -1,49 +1,46 @@
1
- import chalk from 'chalk'
1
+ import chalk from 'chalk';
2
2
 
3
3
  const Logger = {
4
-
5
- Info: (...LogMessage: any) => {
6
- console.log(chalk.magenta.bold("++"), ...LogMessage)
7
- },
8
-
9
- Warn: (...LogMessage: any) => {
10
- console.log(chalk.yellow.bold("**"), ...LogMessage)
11
- },
12
-
13
- Error: (...LogMessage: any) => {
14
- console.error(chalk.red.bold("!!"), ...LogMessage)
15
- },
16
-
17
- Tree: (strTitle: string, LogObject: any) => {
18
-
19
- console.log(chalk.magenta.bold("++"), strTitle);
20
-
21
- const isLocalPath = (strTestPath: string): boolean => {
22
- // Regular expression to match common file path patterns
23
- const filePathRegex = /^(\/|\.\/|\.\.\/|\w:\/)?([\w-.]+\/)*[\w-.]+\.\w+$/;
24
- return filePathRegex.test(strTestPath);
25
- }
26
-
27
- const entries = Object.entries(LogObject);
28
- const totalEntries = entries.length;
29
-
30
- for (const [index, [key, value]] of entries.entries()) {
31
-
32
- const connector = index === totalEntries - 1 ? " " : " "
33
- let color = chalk.white
34
-
35
- switch (typeof value) {
36
- case typeof String(): {
37
- color = isLocalPath(value as string) ? chalk.blueBright : chalk.white;
38
- break
39
- }
40
- case typeof Boolean(): color = chalk.green; break
41
- case typeof Number(): color = chalk.yellow; break
42
- }
43
-
44
- console.log(chalk.magenta.bold(` ${connector}──${key}:`), color(value))
45
- }
46
- }
47
- }
48
-
49
- export { Logger }
4
+ Info: (name: string, ...LogMessage: any) => {
5
+ console.log(chalk.magenta.bold(name), ...LogMessage);
6
+ },
7
+
8
+ Warn: (...LogMessage: any) => {
9
+ console.log(chalk.yellow.bold('**'), ...LogMessage);
10
+ },
11
+
12
+ Error: (...LogMessage: any) => {
13
+ console.error(chalk.red.bold('!!'), ...LogMessage);
14
+ },
15
+
16
+ Tree: (name: string, strTitle: string, LogObject: any) => {
17
+ const fixedPadding = 15; // <-- always pad keys to 15 characters
18
+
19
+ console.log(chalk.greenBright.bold(name).padEnd(fixedPadding), strTitle);
20
+
21
+ const isLocalPath = (strTestPath: string): boolean => {
22
+ const filePathRegex = /^(\/|\.\/|\.\.\/|\w:\/)?([\w-.]+\/)*[\w-.]+\.\w+$/;
23
+ return filePathRegex.test(strTestPath);
24
+ };
25
+
26
+ for (const [key, value] of Object.entries(LogObject)) {
27
+ let color = chalk.white;
28
+
29
+ switch (typeof value) {
30
+ case 'string':
31
+ color = isLocalPath(value) ? chalk.blueBright : chalk.white;
32
+ break;
33
+ case 'boolean':
34
+ color = chalk.green;
35
+ break;
36
+ case 'number':
37
+ color = chalk.yellow;
38
+ break;
39
+ }
40
+
41
+ console.log(chalk.greenBright.bold(`${key}: `).padEnd(fixedPadding), color(String(value)));
42
+ }
43
+ },
44
+ };
45
+
46
+ export { Logger };
package/PluginSetup.ts CHANGED
@@ -141,11 +141,6 @@ function InitializePlugins() {
141
141
  MillenniumStore.ignoreProxyFlag = false;
142
142
 
143
143
  function DelegateToBackend(pluginName: string, name: string, value: any) {
144
- console.log(`Delegating ${name} to backend`, value);
145
- // print stack trace
146
- const stack = new Error().stack?.split('\n').slice(2).join('\n');
147
- console.log(stack);
148
-
149
144
  return MILLENNIUM_BACKEND_IPC.postMessage(IPCType.CallServerMethod, {
150
145
  pluginName,
151
146
  methodName: '__builtins__.__update_settings_value__',
package/StaticEmbed.ts ADDED
@@ -0,0 +1,278 @@
1
+ import { Plugin, SourceDescription, TransformPluginContext } from 'rollup';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { createFilter } from '@rollup/pluginutils';
5
+ import MagicString from 'magic-string';
6
+ import * as parser from '@babel/parser';
7
+ import traverse from '@babel/traverse';
8
+ import * as glob from 'glob';
9
+ import chalk from 'chalk';
10
+
11
+ interface EmbedPluginOptions {
12
+ include?: string | RegExp | (string | RegExp)[];
13
+ exclude?: string | RegExp | (string | RegExp)[];
14
+ encoding?: BufferEncoding;
15
+ }
16
+
17
+ interface CallOptions {
18
+ basePath?: string;
19
+ include?: string;
20
+ encoding?: BufferEncoding;
21
+ }
22
+
23
+ interface FileInfo {
24
+ content: string;
25
+ filePath: string;
26
+ fileName: string;
27
+ }
28
+
29
+ const Log = (...message: any) => {
30
+ console.log(chalk.blueBright.bold('constSysfsExpr'), ...message);
31
+ };
32
+
33
+ export default function constSysfsExpr(options: EmbedPluginOptions = {}): Plugin {
34
+ const filter = createFilter(options.include, options.exclude);
35
+ const pluginName = 'millennium-const-sysfs-expr';
36
+
37
+ return {
38
+ name: pluginName,
39
+
40
+ transform(this: TransformPluginContext, code: string, id: string): SourceDescription | null {
41
+ if (!filter(id)) return null;
42
+ if (!code.includes('constSysfsExpr')) return null;
43
+
44
+ const magicString = new MagicString(code);
45
+ let hasReplaced = false;
46
+
47
+ try {
48
+ const stringVariables = new Map<string, string>();
49
+
50
+ const ast = parser.parse(code, {
51
+ sourceType: 'module',
52
+ plugins: ['typescript', 'jsx', 'objectRestSpread', 'classProperties', 'optionalChaining', 'nullishCoalescingOperator'],
53
+ });
54
+
55
+ traverse(ast, {
56
+ VariableDeclarator(path) {
57
+ const init = path.node.init;
58
+ const id = path.node.id;
59
+ if (id.type === 'Identifier' && init && init.type === 'StringLiteral') {
60
+ stringVariables.set(id.name, init.value);
61
+ }
62
+ },
63
+ });
64
+
65
+ traverse(ast, {
66
+ CallExpression: (nodePath) => {
67
+ const node = nodePath.node;
68
+ if (node.callee.type === 'Identifier' && node.callee.name === 'constSysfsExpr') {
69
+ if (typeof node.start !== 'number' || typeof node.end !== 'number') {
70
+ if (node.loc) {
71
+ this.warn(`Missing start/end offset info for constSysfsExpr call.`, node.loc.start.index);
72
+ }
73
+ return;
74
+ }
75
+
76
+ const args = node.arguments;
77
+ let pathOrPattern: string | null = null;
78
+ const callOptions: Required<Omit<CallOptions, 'fileName'>> = {
79
+ basePath: '',
80
+ include: '**/*',
81
+ encoding: options.encoding || 'utf8',
82
+ };
83
+
84
+ if (args.length >= 1 && (args[0].type === 'StringLiteral' || args[0].type === 'Identifier')) {
85
+ const firstArg = args[0];
86
+ if (firstArg.type === 'StringLiteral') {
87
+ pathOrPattern = firstArg.value;
88
+ } else if (firstArg.type === 'Identifier') {
89
+ const varName = firstArg.name;
90
+ if (stringVariables.has(varName)) {
91
+ pathOrPattern = stringVariables.get(varName) || null;
92
+ } else {
93
+ this.warn(
94
+ `Unable to resolve variable "${varName}" for constSysfsExpr path/pattern. Only simple string literal assignments are supported.`,
95
+ firstArg.loc?.start.index,
96
+ );
97
+ return;
98
+ }
99
+ }
100
+
101
+ if (args.length > 1 && args[1].type === 'ObjectExpression') {
102
+ const optionsObj = args[1];
103
+ for (const prop of optionsObj.properties) {
104
+ if (prop.type !== 'ObjectProperty') continue;
105
+ let keyName: string | undefined;
106
+ if (prop.key.type === 'Identifier') keyName = prop.key.name;
107
+ else if (prop.key.type === 'StringLiteral') keyName = prop.key.value;
108
+ else continue;
109
+
110
+ if (!['basePath', 'include', 'encoding'].includes(keyName)) continue;
111
+
112
+ const valueNode = prop.value;
113
+ if (valueNode.type === 'StringLiteral') {
114
+ const value = (valueNode as any).extra?.rawValue !== undefined ? (valueNode as any).extra.rawValue : valueNode.value;
115
+ if (keyName === 'basePath') callOptions.basePath = value;
116
+ else if (keyName === 'include') callOptions.include = value;
117
+ else if (keyName === 'encoding') callOptions.encoding = value as BufferEncoding;
118
+ } else {
119
+ this.warn(
120
+ `Option "${keyName}" for constSysfsExpr must be a string literal. Found type: ${valueNode.type}`,
121
+ valueNode.loc?.start.index,
122
+ );
123
+ }
124
+ }
125
+ }
126
+ } else if (args.length >= 1 && args[0].type === 'ObjectExpression') {
127
+ const optionsObj = args[0];
128
+ for (const prop of optionsObj.properties) {
129
+ if (prop.type !== 'ObjectProperty') continue;
130
+ let keyName: string | undefined;
131
+ if (prop.key.type === 'Identifier') keyName = prop.key.name;
132
+ else if (prop.key.type === 'StringLiteral') keyName = prop.key.value;
133
+ else continue;
134
+
135
+ // In this case, we need to look for 'basePath' and 'include' within the options object itself
136
+ if (!['basePath', 'include', 'encoding'].includes(keyName)) continue;
137
+
138
+ const valueNode = prop.value;
139
+ if (valueNode.type === 'StringLiteral') {
140
+ const value = (valueNode as any).extra?.rawValue !== undefined ? (valueNode as any).extra.rawValue : valueNode.value;
141
+ if (keyName === 'basePath') callOptions.basePath = value;
142
+ else if (keyName === 'include') callOptions.include = value;
143
+ else if (keyName === 'encoding') callOptions.encoding = value as BufferEncoding;
144
+ } else {
145
+ this.warn(
146
+ `Option "${keyName}" for constSysfsExpr must be a string literal. Found type: ${valueNode.type}`,
147
+ valueNode.loc?.start.index,
148
+ );
149
+ }
150
+ }
151
+
152
+ if (callOptions.include !== '**/*') {
153
+ pathOrPattern = callOptions.include;
154
+ } else {
155
+ if (!callOptions.basePath) {
156
+ this.warn(
157
+ `constSysfsExpr called with only an options object requires at least 'include' or 'basePath' for a pattern.`,
158
+ node.loc?.start.index,
159
+ );
160
+ return;
161
+ }
162
+ this.warn(`constSysfsExpr called with only an options object requires an explicit 'include' pattern.`, node.loc?.start.index);
163
+ return;
164
+ }
165
+ } else {
166
+ this.warn(`constSysfsExpr requires a path/pattern string/variable or an options object as the first argument.`, node.loc?.start.index);
167
+ return;
168
+ }
169
+
170
+ if (!pathOrPattern) {
171
+ this.warn(`Invalid or unresolved path/pattern argument for constSysfsExpr.`, args[0]?.loc?.start.index);
172
+ return;
173
+ }
174
+
175
+ try {
176
+ const currentLocString = node.loc?.start ? ` at ${id}:${node.loc.start.line}:${node.loc.start.column}` : ` in ${id}`;
177
+
178
+ const searchBasePath = callOptions.basePath
179
+ ? path.isAbsolute(callOptions.basePath)
180
+ ? callOptions.basePath
181
+ : path.resolve(path.dirname(id), callOptions.basePath)
182
+ : path.isAbsolute(pathOrPattern) && !/[?*+!@()[\]{}]/.test(pathOrPattern)
183
+ ? path.dirname(pathOrPattern)
184
+ : path.resolve(path.dirname(id), path.dirname(pathOrPattern));
185
+
186
+ let embeddedContent: string;
187
+ let embeddedCount = 0;
188
+
189
+ const isPotentialPattern = /[?*+!@()[\]{}]/.test(pathOrPattern);
190
+
191
+ if (
192
+ !isPotentialPattern &&
193
+ fs.existsSync(path.resolve(searchBasePath, pathOrPattern)) &&
194
+ fs.statSync(path.resolve(searchBasePath, pathOrPattern)).isFile()
195
+ ) {
196
+ const singleFilePath = path.resolve(searchBasePath, pathOrPattern);
197
+ Log(`Mode: Single file (first argument "${pathOrPattern}" resolved to "${singleFilePath}" relative to "${searchBasePath}")`);
198
+
199
+ try {
200
+ const rawContent: string | Buffer = fs.readFileSync(singleFilePath, callOptions.encoding);
201
+ const contentString = rawContent.toString();
202
+ const fileInfo: FileInfo = {
203
+ content: contentString,
204
+ filePath: singleFilePath,
205
+ fileName: path.relative(searchBasePath, singleFilePath),
206
+ };
207
+ embeddedContent = JSON.stringify(fileInfo);
208
+ embeddedCount = 1;
209
+ Log(`Embedded 1 specific file for call${currentLocString}`);
210
+ } catch (fileError: unknown) {
211
+ let message = String(fileError instanceof Error ? fileError.message : fileError ?? 'Unknown file read error');
212
+ this.error(`Error reading file ${singleFilePath}: ${message}`, node.loc?.start.index);
213
+ return;
214
+ }
215
+ } else {
216
+ Log(`Mode: Multi-file (first argument "${pathOrPattern}" is pattern or not a single file)`);
217
+
218
+ Log(`Searching with pattern "${pathOrPattern}" in directory "${searchBasePath}" (encoding: ${callOptions.encoding})`);
219
+
220
+ const matchingFiles = glob.sync(pathOrPattern, {
221
+ cwd: searchBasePath,
222
+ nodir: true,
223
+ absolute: true,
224
+ });
225
+
226
+ const fileInfoArray: FileInfo[] = [];
227
+ for (const fullPath of matchingFiles) {
228
+ try {
229
+ const rawContent: string | Buffer = fs.readFileSync(fullPath, callOptions.encoding);
230
+ const contentString = rawContent.toString();
231
+ fileInfoArray.push({
232
+ content: contentString,
233
+ filePath: fullPath,
234
+ fileName: path.relative(searchBasePath, fullPath),
235
+ });
236
+ } catch (fileError: unknown) {
237
+ let message = String(fileError instanceof Error ? fileError.message : fileError ?? 'Unknown file read error');
238
+ this.warn(`Error reading file ${fullPath}: ${message}`);
239
+ }
240
+ }
241
+ embeddedContent = JSON.stringify(fileInfoArray);
242
+ embeddedCount = fileInfoArray.length;
243
+ Log(`Embedded ${embeddedCount} file(s) matching pattern for call${currentLocString}`);
244
+ }
245
+
246
+ // Replace the call expression with the generated content string
247
+ magicString.overwrite(node.start, node.end, embeddedContent);
248
+ hasReplaced = true;
249
+ } catch (error: unknown) {
250
+ console.error(`Failed to process files for constSysfsExpr call in ${id}:`, error);
251
+ const message = String(error instanceof Error ? error.message : error ?? 'Unknown error during file processing');
252
+ this.error(`Could not process files for constSysfsExpr: ${message}`, node.loc?.start.index);
253
+ return;
254
+ }
255
+ }
256
+ },
257
+ });
258
+ } catch (error: unknown) {
259
+ console.error(`Error parsing or traversing ${id}:`, error);
260
+ const message = String(error instanceof Error ? error.message : error ?? 'Unknown parsing error');
261
+ this.error(`Failed to parse ${id}: ${message}`);
262
+ return null;
263
+ }
264
+
265
+ // If no replacements were made, return null
266
+ if (!hasReplaced) {
267
+ return null;
268
+ }
269
+
270
+ // Return the modified code and source map
271
+ const result: SourceDescription = {
272
+ code: magicString.toString(),
273
+ map: magicString.generateMap({ hires: true }),
274
+ };
275
+ return result;
276
+ },
277
+ };
278
+ }
package/VersionMon.ts CHANGED
@@ -5,24 +5,27 @@ import { dirname } from 'path';
5
5
  import { Logger } from './Logger';
6
6
 
7
7
  export const CheckForUpdates = async (): Promise<boolean> => {
8
- return new Promise<boolean>(async (resolve) => {
9
- const packageJsonPath = path.resolve(dirname(fileURLToPath(import.meta.url)), '../package.json');
10
- const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
11
-
12
- fetch("https://registry.npmjs.org/@steambrew/ttc").then(response => response.json()).then(json => {
8
+ return new Promise<boolean>(async (resolve) => {
9
+ const packageJsonPath = path.resolve(dirname(fileURLToPath(import.meta.url)), '../package.json');
10
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
13
11
 
14
- if (json?.["dist-tags"]?.latest != packageJson.version) {
15
-
16
- Logger.Tree(`@steambrew/ttc@${packageJson.version} requires update to ${json?.["dist-tags"]?.latest}`, {
17
- cmd: `run "npm install @steambrew/ttc@${json?.["dist-tags"]?.latest}" to get latest updates!`
18
- })
12
+ fetch('https://registry.npmjs.org/@steambrew/ttc')
13
+ .then((response) => response.json())
14
+ .then((json) => {
15
+ if (json?.['dist-tags']?.latest != packageJson.version) {
16
+ Logger.Tree('versionMon', `@steambrew/ttc@${packageJson.version} requires update to ${json?.['dist-tags']?.latest}`, {
17
+ cmd: `run "npm install @steambrew/ttc@${json?.['dist-tags']?.latest}" to get latest updates!`,
18
+ });
19
19
 
20
- resolve(true)
21
- }
22
- else {
23
- Logger.Info(`@steambrew/ttc@${packageJson.version} is up-to-date!`)
24
- resolve(false)
25
- }
26
- })
27
- })
28
- }
20
+ resolve(true);
21
+ } else {
22
+ Logger.Info('versionMon', `@steambrew/ttc@${packageJson.version} is up-to-date!`);
23
+ resolve(false);
24
+ }
25
+ })
26
+ .catch((exception) => {
27
+ Logger.Error('Failed to check for updates: ' + exception);
28
+ resolve(false);
29
+ });
30
+ });
31
+ };