Switch from ESLint to Rome (#145)

This commit is contained in:
Piotr Rogowski 2022-12-01 22:51:23 +01:00 committed by GitHub
parent 4723c17887
commit 4000cf725d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 404 additions and 9671 deletions

View File

@ -1 +0,0 @@
/dist

View File

@ -1,50 +0,0 @@
---
parser: '@typescript-eslint/parser'
env:
node: true
es6: true
settings:
import/resolver:
node:
extensions:
- ".js"
- ".ts"
extends:
- eslint:recommended
- prettier
- plugin:import/errors
- plugin:import/warnings
- plugin:import/typescript
plugins:
- '@typescript-eslint'
- prettier
- modules-newline
rules:
indent: [2, 2, { "SwitchCase": 1 }]
semi:
- error
- always
comma-dangle:
- error
- always-multiline
import/extensions: 0
object-curly-spacing:
- error
- always
object-curly-newline: [1, {
"ImportDeclaration": { "multiline": true, "minProperties": 2 },
"ExportDeclaration": { "multiline": true, "minProperties": 1 }
}]
modules-newline/import-declaration-newline: 1
modules-newline/export-declaration-newline: 1
quotes:
- error
- single
no-console: 0
no-plusplus: 0
import/no-extraneous-dependencies: 0
no-undef: 1
no-unused-vars: 0
'@typescript-eslint/no-unused-vars': 1
no-shadow: 0
'@typescript-eslint/no-shadow': 2

2
.gitignore vendored
View File

@ -15,8 +15,6 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
.eslintcache
# # temp test data
# /test/data/tmp/*
# !/test/data/tmp/.keep

View File

@ -3,7 +3,8 @@
// for the documentation about the extensions.json format
"recommendations": [
"editorconfig.editorconfig",
"dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint"
"davidanson.vscode-markdownlint",
"streetsidesoftware.code-spell-checker",
"rome.rome"
]
}

12
.vscode/settings.json vendored
View File

@ -3,5 +3,15 @@
"cSpell.words": [
"hypertuner",
"rusefi"
]
],
"editor.formatOnSave": true,
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[typescript]": {
"editor.defaultFormatter": "rome.rome"
},
"[javascript]": {
"editor.defaultFormatter": "rome.rome"
}
}

9367
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,21 +19,21 @@
"build": "tsc",
"prepare": "npm run build",
"start": "tsc --watch",
"lint": "tsc && eslint --max-warnings=0 src/**/*.ts src/*.ts",
"generate": "npm run build && node test/test.js generate",
"test": "npm run build && node test/test.js",
"generate": "npm run build && node test/test.js generate"
"lint": "tsc && rome ci src",
"lint:fix": "rome format --write src && rome check --apply src",
"lint:fix:suggested": "rome check --apply-suggested src"
},
"devDependencies": {
"@hyper-tuner/eslint-config": "^0.1.7",
"@types/js-yaml": "^4.0.5",
"@types/node": "^18.11.9",
"@types/node": "^18.11.10",
"@types/parsimmon": "^1.10.6",
"eslint-plugin-modules-newline": "^0.0.6",
"eslint-plugin-prettier": "^4.2.1",
"typescript": "^4.8.4"
"rome": "^10.0.1",
"typescript": "^4.9.3"
},
"dependencies": {
"@hyper-tuner/types": "^0.4.1",
"@hyper-tuner/types": "^0.4.2",
"js-yaml": "^4.1.0",
"parsimmon": "^1.18.1"
}

27
rome.json Normal file
View File

@ -0,0 +1,27 @@
{
"formatter": {
"enabled": true,
"indentStyle": "space",
"lineWidth": 100,
"indentSize": 2,
"ignore": [
"node_modules",
"build"
]
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingComma": "all"
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"noImplicitBoolean": "off"
}
}
}
}

View File

@ -48,7 +48,7 @@ if (!command) {
}
switch (command) {
case Commands.VALIDATE:
case Commands.VALIDATE: {
if (!filename) {
console.info('❗️ Please provide a file name');
showUsage();
@ -57,13 +57,17 @@ switch (command) {
showVersion();
validate(filename);
break;
}
case Commands.VERSION:
case Commands.VERSION: {
showVersion();
break;
}
default:
console.info(`❗️ Unknown command: ${command}, please use one of: [${Object.values(Commands).join(', ')}]`);
console.info(
`❗️ Unknown command: ${command}, please use one of: [${Object.values(Commands).join(', ')}]`,
);
process.exit(1);
break;
}

View File

@ -1,9 +1,5 @@
import P from 'parsimmon';
import {
Config as ConfigType,
Constant,
GroupMenu,
} from '@hyper-tuner/types';
import { Config as ConfigType, Constant, GroupMenu } from '@hyper-tuner/types';
import { ParserInterface } from './parserInterface';
export class INI implements ParserInterface {
@ -69,7 +65,7 @@ export class INI implements ParserInterface {
this.inQuotes = this.notQuote.trim(this.space).wrap(...this.quotes);
this.values = P.regexp(/[^,;]*/).trim(this.space).sepBy(this.comma);
this.lines = (new TextDecoder()).decode(buffer).split('\n');
this.lines = new TextDecoder().decode(buffer).split('\n');
this.currentPage = undefined;
this.currentDialog = undefined;
@ -120,12 +116,15 @@ export class INI implements ParserInterface {
const line = raw.trim();
// skip empty lines and lines with comments only
// skip #if for now
if (line === '' || line.startsWith(';') || (line.startsWith('#') && !line.startsWith('#define'))) {
if (
line === '' ||
line.startsWith(';') ||
(line.startsWith('#') && !line.startsWith('#define'))
) {
return;
}
const result = P
.seqObj<any>(
const result = P.seqObj<any>(
['section', P.letters.wrap(P.string('['), P.string(']'))],
P.all,
).parse(line);
@ -144,39 +143,50 @@ export class INI implements ParserInterface {
private parseSectionLine(section: string, line: string) {
switch (section) {
case 'MegaTune':
case 'MegaTune': {
this.parseKeyValueFor('megaTune', line);
break;
case 'TunerStudio':
}
case 'TunerStudio': {
this.parseKeyValueFor('tunerStudio', line);
break;
case 'PcVariables':
}
case 'PcVariables': {
this.parsePcVariables(line);
break;
case 'Constants':
}
case 'Constants': {
this.parseConstants(line);
break;
case 'Menu':
}
case 'Menu': {
this.parseMenu(line);
break;
case 'SettingContextHelp':
}
case 'SettingContextHelp': {
this.parseKeyValueFor('help', line);
break;
case 'UserDefined':
}
case 'UserDefined': {
this.parseDialogs(line);
break;
case 'CurveEditor':
}
case 'CurveEditor': {
this.parseCurves(line);
break;
case 'TableEditor':
}
case 'TableEditor': {
this.parseTables(line);
break;
case 'OutputChannels':
}
case 'OutputChannels': {
this.parseOutputChannels(line);
break;
case 'Datalog':
}
case 'Datalog': {
this.parseDatalog(line);
break;
}
default:
break;
}
@ -185,35 +195,22 @@ export class INI implements ParserInterface {
private parseDatalog(line: string) {
const base: any = [
P.string('entry'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
...this.delimiter,
];
const type: any = [
...this.delimiter,
['type', P.regexp(/float|int/)],
];
const format: any = [
...this.delimiter,
['format', this.notQuote.wrap(...this.quotes)],
];
const type: any = [...this.delimiter, ['type', P.regexp(/float|int/)]];
const format: any = [...this.delimiter, ['format', this.notQuote.wrap(...this.quotes)]];
const noConditions = [
...base,
['label', this.notQuote.wrap(...this.quotes)],
...type,
...format,
];
const withConditions = [
...noConditions,
...this.delimiter,
['condition', this.expression],
];
const labelExpression = [
...base,
['label', this.expression],
...type,
...format,
];
const withConditions = [...noConditions, ...this.delimiter, ['condition', this.expression]];
const labelExpression = [...base, ['label', this.expression], ...type, ...format];
const labelExpressionWithCondition = [
...labelExpression,
...this.delimiter,
@ -245,35 +242,21 @@ export class INI implements ParserInterface {
offset: Number(result.offset),
units: INI.sanitize(result.units),
scale: INI.isNumber(result.scale) ? Number(result.scale) : INI.sanitize(result.scale),
transform: INI.isNumber(result.transform) ? Number(result.transform) : INI.sanitize(result.transform),
transform: INI.isNumber(result.transform)
? Number(result.transform)
: INI.sanitize(result.transform),
};
return;
} catch (_) {
const base: any = [
['name', this.name],
this.space, this.equal, this.space,
];
const base: any = [['name', this.name], this.space, this.equal, this.space];
// TODO: throttle = { tps }, "%"
// ochGetCommand = "r\$tsCanId\x30%2o%2c"
// ochBlockSize = 117
// coolant = { coolantRaw - 40 }
const result = P
.seqObj<any>(
...base,
['value', this.notQuote.wrap(...this.quotes)],
P.all,
)
.or(P.seqObj<any>(
...base,
['value', this.expression],
P.all,
))
.or(P.seqObj<any>(
...base,
['value', this.numbers],
P.all,
))
const result = P.seqObj<any>(...base, ['value', this.notQuote.wrap(...this.quotes)], P.all)
.or(P.seqObj<any>(...base, ['value', this.expression], P.all))
.or(P.seqObj<any>(...base, ['value', this.numbers], P.all))
.tryParse(line);
this.result.outputChannels[result.name] = {
@ -286,7 +269,9 @@ export class INI implements ParserInterface {
// table = veTable1Tbl, veTable1Map, "VE Table", 2
const tableResult = P.seqObj<any>(
P.string('table'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
...this.delimiter,
['map', this.name],
@ -318,7 +303,9 @@ export class INI implements ParserInterface {
// topicHelp = "http://speeduino.com/wiki/index.php/Tuning"
const helpResult = P.seqObj<any>(
P.string('topicHelp'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['help', this.inQuotes],
P.all,
).parse(line);
@ -338,9 +325,12 @@ export class INI implements ParserInterface {
// zBins = veTable
// gridOrient = 250, 0, 340
// upDownLabel = "(RICHER)", "(LEANER)"
const parseBins = (name: string) => P.seqObj<any>(
const parseBins = (name: string) =>
P.seqObj<any>(
P.string(name),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['values', this.values],
P.all,
).parse(line);
@ -350,10 +340,7 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].xBins = xBinsResult
.value
.values
.map(INI.sanitize);
this.result.tables[this.currentTable].xBins = xBinsResult.value.values.map(INI.sanitize);
return;
}
@ -363,10 +350,7 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].yBins = yBinsResult
.value
.values
.map(INI.sanitize);
this.result.tables[this.currentTable].yBins = yBinsResult.value.values.map(INI.sanitize);
return;
}
@ -376,10 +360,9 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].xyLabels = yxLabelsResult
.value
.values
.map(INI.sanitize);
this.result.tables[this.currentTable].xyLabels = yxLabelsResult.value.values.map(
INI.sanitize,
);
return;
}
@ -389,10 +372,7 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].zBins = zBinsResult
.value
.values
.map(INI.sanitize);
this.result.tables[this.currentTable].zBins = zBinsResult.value.values.map(INI.sanitize);
return;
}
@ -400,7 +380,9 @@ export class INI implements ParserInterface {
// gridHeight = 2.0
const gridHeightResult = P.seqObj<any>(
P.string('gridHeight'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['gridHeight', this.numbers],
P.all,
).parse(line);
@ -419,10 +401,7 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].gridOrient = gridOrientResult
.value
.values
.map(Number);
this.result.tables[this.currentTable].gridOrient = gridOrientResult.value.values.map(Number);
return;
}
@ -432,10 +411,9 @@ export class INI implements ParserInterface {
if (!this.currentTable) {
throw new Error('Table not set');
}
this.result.tables[this.currentTable].upDownLabel = upDownResult
.value
.values
.map(INI.sanitize);
this.result.tables[this.currentTable].upDownLabel = upDownResult.value.values.map(
INI.sanitize,
);
}
}
@ -443,7 +421,9 @@ export class INI implements ParserInterface {
// curve = time_accel_tpsdot_curve, "TPS based AE"
const curveResult = P.seqObj<any>(
P.string('curve'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
...this.delimiter,
['title', this.inQuotes],
@ -468,7 +448,9 @@ export class INI implements ParserInterface {
// columnLabel = "TPSdot", "Added"
const labelsResult = P.seqObj<any>(
P.string('columnLabel'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['labels', this.values],
P.all,
).parse(line);
@ -477,10 +459,7 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].labels = labelsResult
.value
.labels
.map(INI.sanitize);
this.result.curves[this.currentCurve].labels = labelsResult.value.labels.map(INI.sanitize);
return;
}
@ -489,9 +468,12 @@ export class INI implements ParserInterface {
// yAxis = 0, 1200, 6
// xBins = taeBins, TPSdot
// yBins = taeRates
const parseAxis = (name: string) => P.seqObj<any>(
const parseAxis = (name: string) =>
P.seqObj<any>(
P.string(name),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['values', this.values],
P.all,
).parse(line);
@ -501,10 +483,9 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].xAxis = xAxisResult
.value
.values
.map((val: string) => INI.isNumber(val) ? Number(val) : INI.sanitize(val));
this.result.curves[this.currentCurve].xAxis = xAxisResult.value.values.map((val: string) =>
INI.isNumber(val) ? Number(val) : INI.sanitize(val),
);
return;
}
@ -514,10 +495,9 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].yAxis = yAxisResult
.value
.values
.map((val: string) => INI.isNumber(val) ? Number(val) : INI.sanitize(val));
this.result.curves[this.currentCurve].yAxis = yAxisResult.value.values.map((val: string) =>
INI.isNumber(val) ? Number(val) : INI.sanitize(val),
);
return;
}
@ -527,10 +507,9 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].xBins = xBinsResult
.value
.values
.map((val: string) => INI.isNumber(val) ? Number(val) : INI.sanitize(val));
this.result.curves[this.currentCurve].xBins = xBinsResult.value.values.map((val: string) =>
INI.isNumber(val) ? Number(val) : INI.sanitize(val),
);
return;
}
@ -540,10 +519,9 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].yBins = yBinsResult
.value
.values
.map((val: string) => INI.isNumber(val) ? Number(val) : INI.sanitize(val));
this.result.curves[this.currentCurve].yBins = yBinsResult.value.values.map((val: string) =>
INI.isNumber(val) ? Number(val) : INI.sanitize(val),
);
return;
}
@ -553,23 +531,23 @@ export class INI implements ParserInterface {
if (!this.currentCurve) {
throw new Error('Curve not set');
}
this.result.curves[this.currentCurve].size = size
.value
.values
.map((val: string) => INI.isNumber(val) ? Number(val) : INI.sanitize(val));
this.result.curves[this.currentCurve].size = size.value.values.map((val: string) =>
INI.isNumber(val) ? Number(val) : INI.sanitize(val),
);
}
}
private parseDialogs(line: string) {
const dialogBase: any = [
P.string('dialog'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
...this.delimiter,
['title', this.inQuotes],
];
const dialogResult = P
.seqObj<any>(
const dialogResult = P.seqObj<any>(
...dialogBase,
...this.delimiter,
['layout', this.name],
@ -593,43 +571,27 @@ export class INI implements ParserInterface {
// panel = knock_window_angle_curve
const panelBase: any = [
P.string('panel'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
];
// panel = knock_window_angle_curve, West
const panelWithLayout = [
...panelBase,
...this.delimiter,
['layout', this.name],
];
const panelWithLayout = [...panelBase, ...this.delimiter, ['layout', this.name]];
// panel = flex_fuel_curve, { flexEnabled }
const panelWithCondition = [
...panelBase,
...this.delimiter,
['condition', this.expression],
];
const panelWithCondition = [...panelBase, ...this.delimiter, ['condition', this.expression]];
const panelResult = P
.seqObj<any>(
const panelResult = P.seqObj<any>(
...panelWithLayout,
...this.delimiter,
['condition', this.expression],
P.all,
)
.or(P.seqObj<any>(
...panelWithCondition,
P.all,
))
.or(P.seqObj<any>(
...panelWithLayout,
P.all,
))
.or(P.seqObj<any>(
...panelBase,
P.all,
))
.or(P.seqObj<any>(...panelWithCondition, P.all))
.or(P.seqObj<any>(...panelWithLayout, P.all))
.or(P.seqObj<any>(...panelBase, P.all))
.parse(line);
if (panelResult.status) {
@ -651,16 +613,14 @@ export class INI implements ParserInterface {
// field = "Injector Layout"
const fieldBase: any = [
P.string('field'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['title', this.notQuote.wrap(...this.quotes)],
];
// field = "Injector Layout", injLayout
const fieldWithName = [
...fieldBase,
...this.delimiter,
['name', this.name],
];
const fieldWithName = [...fieldBase, ...this.delimiter, ['name', this.name]];
// field = "Low (E0) ", flexFreqLow, { flexEnabled }
const fieldWithCondition = [
@ -679,23 +639,10 @@ export class INI implements ParserInterface {
['condition', this.expression],
];
const fieldResult = P
.seqObj<any>(
...fieldWithDoubleCondition,
P.all,
)
.or(P.seqObj<any>(
...fieldWithCondition,
P.all,
))
.or(P.seqObj<any>(
...fieldWithName,
P.all,
))
.or(P.seqObj<any>(
...fieldBase,
P.all,
))
const fieldResult = P.seqObj<any>(...fieldWithDoubleCondition, P.all)
.or(P.seqObj<any>(...fieldWithCondition, P.all))
.or(P.seqObj<any>(...fieldWithName, P.all))
.or(P.seqObj<any>(...fieldBase, P.all))
.parse(line);
if (fieldResult.status) {
@ -713,23 +660,21 @@ export class INI implements ParserInterface {
}
// topicHelp = "https://wiki.speeduino.com/en/configuration/Engine_Constants"
const helpResult = P
.seqObj<any>(
const helpResult = P.seqObj<any>(
P.string('topicHelp'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['help', this.notQuote.wrap(...this.quotes)],
P.all,
)
.parse(line);
).parse(line);
if (!this.currentDialog) {
throw new Error('Dialog not set');
}
if (helpResult.status) {
this.result.dialogs[this.currentDialog!].help = INI.sanitize(
helpResult.value.help,
);
this.result.dialogs[this.currentDialog!].help = INI.sanitize(helpResult.value.help);
}
// TODO: missing fields:
@ -751,29 +696,15 @@ export class INI implements ParserInterface {
}
private parseKeyValue(line: string) {
const base: any = [
['key', this.name],
this.space, this.equal, this.space,
];
const base: any = [['key', this.name], this.space, this.equal, this.space];
const result = P
.seqObj<any>(
...base,
['value', this.notQuote.wrap(...this.quotes)],
P.all,
)
.or(P.seqObj<any>(
...base,
['value', this.numbers],
P.all,
))
const result = P.seqObj<any>(...base, ['value', this.notQuote.wrap(...this.quotes)], P.all)
.or(P.seqObj<any>(...base, ['value', this.numbers], P.all))
.tryParse(line);
return {
key: result.key as string,
value: INI.isNumber(result.value)
? Number(result.value)
: INI.sanitize(result.value),
value: INI.isNumber(result.value) ? Number(result.value) : INI.sanitize(result.value),
};
}
@ -783,21 +714,18 @@ export class INI implements ParserInterface {
return;
}
const menuResult = P
.seqObj<any>(
const menuResult = P.seqObj<any>(
P.string('menu'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.inQuotes],
P.all,
).parse(line);
if (menuResult.status) {
const title = INI
.sanitize(menuResult.value.name)
.replace(/&/g, '');
const name = title
.toLowerCase()
.replace(/([^\w]\w)/g, (g) => g[1].toUpperCase()); // camelCase
const title = INI.sanitize(menuResult.value.name).replace(/&/g, '');
const name = title.toLowerCase().replace(/([^\w]\w)/g, (g) => g[1].toUpperCase()); // camelCase
this.currentMenu = name;
this.result.menus[this.currentMenu] = {
@ -811,21 +739,18 @@ export class INI implements ParserInterface {
if (this.currentMenu) {
// parse groupMenu
// groupMenu = "Engine Protection"
const groupMenuResult = P
.seqObj<any>(
const groupMenuResult = P.seqObj<any>(
P.string('groupMenu'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['title', this.notQuote.wrap(...this.quotes)],
P.all,
)
.parse(line);
).parse(line);
if (groupMenuResult.status) {
const title = INI
.sanitize(groupMenuResult.value.title);
const name = title
.toLowerCase()
.replace(/([^\w]\w)/g, (g) => g[1].toUpperCase()); // camelCase
const title = INI.sanitize(groupMenuResult.value.title);
const name = title.toLowerCase().replace(/([^\w]\w)/g, (g) => g[1].toUpperCase()); // camelCase
this.currentGroupMenu = name;
this.result.menus[this.currentMenu].subMenus[name] = {
@ -842,7 +767,9 @@ export class INI implements ParserInterface {
// groupChildMenu = std_separator
const base: any = [
P.string('groupChildMenu'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
];
@ -854,21 +781,20 @@ export class INI implements ParserInterface {
];
// groupChildMenu = revLimiterDialog, "Rev Limiters", { engineProtectType }
const full: any = [
...withTitle,
...this.delimiter,
['condition', this.expression],
P.all,
];
const full: any = [...withTitle, ...this.delimiter, ['condition', this.expression], P.all];
const groupChildMenuResult = P.seqObj<any>(...full, P.all)
.or(P.seqObj<any>(...withTitle, P.all))
.or(P.seqObj<any>(...base, P.all))
.tryParse(line);
(this.result.menus[this.currentMenu].subMenus[this.currentGroupMenu] as GroupMenu).groupChildMenus[groupChildMenuResult.name] = {
(
this.result.menus[this.currentMenu].subMenus[this.currentGroupMenu] as GroupMenu
).groupChildMenus[groupChildMenuResult.name] = {
title: INI.sanitize(groupChildMenuResult.title),
condition: groupChildMenuResult.condition ? INI.sanitize(groupChildMenuResult.condition) : '',
condition: groupChildMenuResult.condition
? INI.sanitize(groupChildMenuResult.condition)
: '',
};
return;
@ -877,7 +803,9 @@ export class INI implements ParserInterface {
// subMenu = std_separator
const base: any = [
P.string('subMenu'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['name', this.name],
];
@ -889,11 +817,7 @@ export class INI implements ParserInterface {
];
// subMenu = egoControl, "AFR/O2", 3
const withPage: any = [
...withTitle,
...this.delimiter,
['page', P.digits],
];
const withPage: any = [...withTitle, ...this.delimiter, ['page', P.digits]];
// subMenu = fuelTemp_curve, "Fuel Temp Correction", { flexEnabled }
const withCondition: any = [
@ -904,11 +828,7 @@ export class INI implements ParserInterface {
];
// subMenu = inj_trimad_B, "Sequential fuel trim (5-8)", 9, { nFuelChannels >= 5 }
const full: any = [
...withPage,
...this.delimiter,
['condition', this.expression],
];
const full: any = [...withPage, ...this.delimiter, ['condition', this.expression]];
const subMenuResult = P.seqObj<any>(...full, P.all)
.or(P.seqObj<any>(...withCondition, P.all))
@ -931,18 +851,18 @@ export class INI implements ParserInterface {
P.string('#define'),
this.space,
['name', this.name],
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['values', this.values],
P.all,
).tryParse(line);
this.result.defines[result.name] = result.values.map(INI.sanitize);
const resolved = this.result.defines[result.name].map((val) => (
val.startsWith('$')
? this.result.defines[val.slice(1)]
: val
)).flat();
const resolved = this.result.defines[result.name]
.map((val) => (val.startsWith('$') ? this.result.defines[val.slice(1)] : val))
.flat();
this.result.defines[result.name] = resolved;
}
@ -957,7 +877,7 @@ export class INI implements ParserInterface {
let constant = {} as Constant;
switch (result.type) {
case 'scalar':
case 'scalar': {
constant = {
type: result.type,
size: result.size,
@ -969,7 +889,8 @@ export class INI implements ParserInterface {
digits: Number(result.digits),
};
break;
case 'array':
}
case 'array': {
constant = {
type: result.type,
size: result.size,
@ -982,7 +903,8 @@ export class INI implements ParserInterface {
digits: Number(result.digits),
};
break;
case 'bits':
}
case 'bits': {
constant = {
type: result.type,
size: result.size,
@ -990,13 +912,15 @@ export class INI implements ParserInterface {
values: this.resolveBitsValues(result.name, result.values || []),
};
break;
case 'string':
}
case 'string': {
constant = {
type: result.type,
size: result.size,
length: Number(result.length),
};
break;
}
default:
break;
}
@ -1010,10 +934,11 @@ export class INI implements ParserInterface {
return;
}
const page = P
.seqObj<any>(
const page = P.seqObj<any>(
P.string('page'),
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['page', P.digits],
P.all,
).parse(line);
@ -1036,7 +961,7 @@ export class INI implements ParserInterface {
let constant = {} as Constant;
switch (result.type) {
case 'scalar':
case 'scalar': {
constant = {
type: result.type,
size: result.size,
@ -1049,7 +974,8 @@ export class INI implements ParserInterface {
digits: Number(result.digits),
};
break;
case 'array':
}
case 'array': {
constant = {
type: result.type,
size: result.size,
@ -1063,7 +989,8 @@ export class INI implements ParserInterface {
digits: Number(result.digits),
};
break;
case 'bits':
}
case 'bits': {
constant = {
type: result.type,
size: result.size,
@ -1072,6 +999,7 @@ export class INI implements ParserInterface {
values: this.resolveBitsValues(result.name, result.values || []),
};
break;
}
default:
break;
}
@ -1086,7 +1014,8 @@ export class INI implements ParserInterface {
}
private resolveBitsValues(name: string, values: string[]) {
return values.map((val: string) => {
return values
.map((val: string) => {
const resolve = () => {
const defineName = INI.sanitize(val.slice(1)); // name without $
const resolved = this.result.defines[defineName];
@ -1098,19 +1027,28 @@ export class INI implements ParserInterface {
};
return val.startsWith('$') ? resolve() : INI.sanitize(val);
}).flat().filter((val) => val !== '');
})
.flat()
.filter((val) => val !== '');
}
private parseConstAndVar(line: string, asPcVariable = false) {
const address: any = [
['address', P.regexp(/\d+:\d+/).trim(this.space).wrap(...this.sqrBrackets)],
[
'address',
P.regexp(/\d+:\d+/)
.trim(this.space)
.wrap(...this.sqrBrackets),
],
];
// first common (eg. name = scalar, U08, 3,)
const base: any = (type: string) => {
let list = [
['name', this.name],
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['type', P.string(type)],
...this.delimiter,
['size', this.size],
@ -1118,13 +1056,7 @@ export class INI implements ParserInterface {
// pcVariables don't have "offset"
if (!asPcVariable) {
list = [
...list,
...[
...this.delimiter,
['offset', P.digits],
],
];
list = [...list, ...[...this.delimiter, ['offset', P.digits]]];
}
return list;
@ -1150,11 +1082,7 @@ export class INI implements ParserInterface {
];
// normal scalar
const scalar = P.seqObj<any>(
...base('scalar'),
...this.delimiter,
...scalarRest,
);
const scalar = P.seqObj<any>(...base('scalar'), ...this.delimiter, ...scalarRest);
// short version of scalar (e.g. 'divider')
const scalarShort = P.seqObj<any>(
@ -1168,7 +1096,12 @@ export class INI implements ParserInterface {
const array = P.seqObj<any>(
...base('array'),
...this.delimiter,
['shape', P.regexp(/\d+\s*(x\s*\d+)*/).trim(this.space).wrap(...this.sqrBrackets)],
[
'shape',
P.regexp(/\d+\s*(x\s*\d+)*/)
.trim(this.space)
.wrap(...this.sqrBrackets),
],
...this.delimiter,
...scalarRest,
);
@ -1184,26 +1117,18 @@ export class INI implements ParserInterface {
);
// short version of bits
const bitsShort = P.seqObj<any>(
...base('bits'),
...this.delimiter,
...address,
P.all,
);
const bitsShort = P.seqObj<any>(...base('bits'), ...this.delimiter, ...address, P.all);
// string (in pcVariables)
const string = P.seqObj<any>(
...base('string'),
...this.delimiter,
['length', P.digits],
P.all,
);
const string = P.seqObj<any>(...base('string'), ...this.delimiter, ['length', P.digits], P.all);
// predefined constant continuousChannelValue (in pcVariables)
// TODO: investigate this
const continuousChannelValue = P.seqObj<any>(
['name', this.name],
this.space, this.equal, this.space,
this.space,
this.equal,
this.space,
['reference', this.name],
...this.delimiter,
['channel', this.name],
@ -1224,10 +1149,7 @@ export class INI implements ParserInterface {
INI.isNumber(val || '0') ? Number(val || 0) : INI.sanitize(`${val}`);
private static sanitize = (val: any) =>
val === undefined ? '' : `${val}`
.replace(/"/g, '')
.replace(/\s+/g, ' ')
.trim();
val === undefined ? '' : `${val}`.replace(/"/g, '').replace(/\s+/g, ' ').trim();
private static isNumber = (val: any) => !Number.isNaN(Number(val));
@ -1239,4 +1161,3 @@ export class INI implements ParserInterface {
};
};
}