Skip to content

Commit 2443802

Browse files
authored
Merge pull request #812 from casual-simulation/feature/cli-check-aux
Add the `check-aux` CLI command
2 parents b80aa68 + 01abc24 commit 2443802

File tree

3 files changed

+172
-1
lines changed

3 files changed

+172
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
#### Date: TBD
66

7+
### :rocket: Features
8+
9+
- Added the `check-aux` CLI command.
10+
- It checks that the given file is in a valid format and that none of the scripts have syntax errors.
11+
712
### :bug: Bug Fixes
813

914
- Fixed an issue when trying to read cached default values from Redis.

src/casualos-cli/cli.ts

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,36 @@ import type {
3333
Bot,
3434
BotsState,
3535
BotTags,
36+
Result,
3637
StoredAux,
3738
StoredAuxVersion1,
3839
} from '@casual-simulation/aux-common';
3940
import {
41+
calculateStringTagValue,
4042
createBot,
4143
DATE_TAG_PREFIX,
4244
DNA_TAG_PREFIX,
45+
failure,
4346
getBotsStateFromStoredAux,
4447
getSessionKeyExpiration,
4548
getUploadState,
4649
hasValue,
4750
isExpired,
51+
isFailure,
52+
isFormula,
53+
isModule,
54+
isScript,
4855
LIBRARY_SCRIPT_PREFIX,
4956
merge,
5057
NUMBER_TAG_PREFIX,
58+
parseFormula,
59+
parseModule,
60+
parseScript,
5161
parseSessionKey,
5262
parseVersionNumber,
5363
ROTATION_TAG_PREFIX,
5464
STRING_TAG_PREFIX,
65+
success,
5566
tryParseJson,
5667
VECTOR_TAG_PREFIX,
5768
willExpire,
@@ -86,6 +97,8 @@ import {
8697
import standardMimeTypes from 'mime/types/standard.js';
8798
import otherMimeTypes from 'mime/types/other.js';
8899
import { parseEntitlements } from 'cli-utils';
100+
import { Transpiler } from '@casual-simulation/aux-runtime';
101+
import { groupBy } from 'es-toolkit';
89102

90103
const mime = new Mime(standardMimeTypes, otherMimeTypes, {
91104
'application/json': ['aux', 'json'],
@@ -358,6 +371,159 @@ program
358371
}
359372
});
360373

374+
program
375+
.command('check-aux')
376+
.description('Check if an AUX file is valid and can be loaded.')
377+
.argument('[input]', 'The AUX file to check.')
378+
.option(
379+
'--skip-scripts',
380+
'Whether to skip checking script tags. By default, script tags are checked and any errors in them will be reported.'
381+
)
382+
.action(async (input, options) => {
383+
// Implement the action for checking the AUX file here.
384+
385+
const skipScripts = options.skipScripts ?? false;
386+
const inputPath = path.resolve(input);
387+
const auxJson = tryParseJson(await readFile(inputPath, 'utf-8'));
388+
if (auxJson.success === false) {
389+
console.error(`Could not parse aux file: ${auxJson.error}`);
390+
process.exit(1);
391+
}
392+
393+
const aux = STORED_AUX_SCHEMA.safeParse(auxJson.value);
394+
395+
if (aux.success === false) {
396+
console.error(
397+
`Aux file is not a valid stored aux: ${aux.error.toString()}`
398+
);
399+
process.exit(1);
400+
}
401+
402+
const botsState = getBotsStateFromStoredAux(
403+
aux.data as StoredAuxVersion1
404+
);
405+
406+
interface ValueError {
407+
bot: Bot;
408+
tag: string;
409+
space: string;
410+
errorCode: string;
411+
errorMessage: string;
412+
}
413+
414+
const transpiler = new Transpiler();
415+
416+
function checkCode(
417+
bot: Bot,
418+
tag: string,
419+
space: string,
420+
code: string
421+
): Result<void, ValueError> {
422+
try {
423+
transpiler.transpile(code);
424+
} catch (err) {
425+
return failure({
426+
bot,
427+
tag,
428+
space,
429+
errorCode: 'invalid_script',
430+
errorMessage: err.toString(),
431+
});
432+
}
433+
434+
return success();
435+
}
436+
437+
function checkValue(
438+
bot: Bot,
439+
tag: string,
440+
space: string,
441+
value: any
442+
): Result<void, ValueError> {
443+
if (isFormula(value)) {
444+
const formula = parseFormula(value);
445+
const parsed = tryParseJson(formula);
446+
if (parsed.success === false) {
447+
return failure({
448+
bot,
449+
tag,
450+
space,
451+
errorCode: 'invalid_formula',
452+
errorMessage: parsed.error as string,
453+
});
454+
}
455+
} else if (!skipScripts) {
456+
if (isScript(value)) {
457+
const code = parseScript(value);
458+
return checkCode(bot, tag, space, code);
459+
} else if (isModule(value)) {
460+
const code = parseModule(value);
461+
return checkCode(bot, tag, space, code);
462+
}
463+
}
464+
465+
return success();
466+
}
467+
468+
const errors: ValueError[] = [];
469+
470+
for (let botId in botsState) {
471+
const bot = botsState[botId];
472+
for (let tag in bot.tags) {
473+
const value = bot.tags[tag];
474+
const result = checkValue(bot, tag, null, value);
475+
if (isFailure(result)) {
476+
errors.push(result.error);
477+
}
478+
}
479+
480+
for (let space in bot.masks) {
481+
const masks = bot.masks[space];
482+
for (let tag in masks) {
483+
const value = masks[tag];
484+
const result = checkValue(bot, tag, space, value);
485+
if (isFailure(result)) {
486+
errors.push(result.error);
487+
}
488+
}
489+
}
490+
}
491+
492+
if (errors.length > 0) {
493+
console.error(`Found ${errors.length} errors in aux file:`);
494+
const byBot = groupBy(errors, (error) => error.bot.id);
495+
496+
for (let botId in byBot) {
497+
const botErrors = byBot[botId];
498+
const bot = botErrors[0].bot;
499+
const system = calculateStringTagValue(
500+
null,
501+
bot,
502+
'system',
503+
null
504+
);
505+
console.error(
506+
`Bot: ${bot.id}${system ? `, System: ${system}` : ''}`
507+
);
508+
for (let error of botErrors) {
509+
console.error(
510+
` Tag: ${error.tag}${
511+
error.space ? `, Space: ${error.space}` : ''
512+
}, Error: (${error.errorCode}) ${error.errorMessage}`
513+
);
514+
}
515+
}
516+
517+
process.exit(2);
518+
} else {
519+
console.log(
520+
`Aux file is valid! No errors found in ${
521+
Object.keys(botsState).length
522+
} bots.`
523+
);
524+
}
525+
});
526+
361527
program
362528
.command('unpack-aux')
363529
.argument('[input]', 'The aux file/directory to convert to a file system.')

src/casualos-cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
"scripts": {
1212
"start": "node ./dist/cli.js",
13-
"dev": "npm run build && npm start",
13+
"dev": "pnpm build && pnpm start",
1414
"build": "node ./script/build-cli.mjs",
1515
"test": "jest",
1616
"test:watch": "jest --watchAll"

0 commit comments

Comments
 (0)