@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 +78 -17
- package/Logger.ts +44 -47
- package/PluginSetup.ts +0 -5
- package/StaticEmbed.ts +278 -0
- package/VersionMon.ts +22 -19
- package/dist/index.js +57148 -225
- package/index.ts +35 -40
- package/package.json +17 -2
- package/rollup.config.js +6 -1
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('
|
|
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('
|
|
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
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
};
|