UNPKG

arduino-cli

Version:

JS-wrapper over arduino-cli

175 lines (138 loc) 6.33 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.patchBoardsWithOptions = exports.parseOptions = exports.convertIntermediateOptions = exports.parseIntermediateOptions = exports.parseOptionNames = exports.getBoardsTxtPath = exports.getLines = undefined; var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _ramda = require('ramda'); var R = _interopRequireWildcard(_ramda); var _fsExtra = require('fs-extra'); var fse = _interopRequireWildcard(_fsExtra); var _promiseAllProperties = require('promise-all-properties'); var _promiseAllProperties2 = _interopRequireDefault(_promiseAllProperties); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * One bright day this module will be burned. * See: https://github.com/arduino/arduino-cli/issues/45 */ const PACKAGES_DIR = 'packages'; const HARDWARE_DIR = 'hardware'; const BOARDS_FNAME = 'boards.txt'; /** * Types * * OptionValue :: { * name: String, // Human-readable name. E.G. "80 MHz" * value: String, // Option value. E.G. "80" * } * * OptionName :: String // Human-readable option name. E.G. "CPU Frequency" * OptionId :: String // Option id as is in the `boards.txt`, E.G. "CpuFrequency" * * Option :: { * optionName: OptionName, * optionId: OptionId, * values: [OptionValue], * } */ // ============================================================================= // // Utils // // ============================================================================= // :: String -> [String] const getLines = exports.getLines = R.compose(R.reject(R.test(/^(#|$)/)), R.map(R.trim), R.split(/$/gm)); const menuRegExp = /^menu\./; const optionNameRegExp = /^menu\.([a-zA-Z0-9_]+)=(.+)$/; const boardOptionRegExp = /^([a-zA-Z0-9_]+)\.menu\.([a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)=(.+)$/; const disableRtsOptionRegExp = /^([a-zA-Z0-9_]+)\.serial\.disableRTS=(.+)$/; const osRegExp = /(linux|macosx|windows)/; // ============================================================================= // // Parsers // // ============================================================================= // :: Path -> FQBN -> String -> Path const getBoardsTxtPath = exports.getBoardsTxtPath = R.curry((dataPath, fqbn, version) => { const [packageName, archName] = R.split(':', fqbn); return _path2.default.resolve(dataPath, PACKAGES_DIR, packageName, HARDWARE_DIR, archName, version, BOARDS_FNAME); }); /** * Parses human-readable option names from `boards.txt` contents. * * E.G. * `menu.CpuFrequency=CPU Frequency` * will become * `{ CpuFrequency: 'CPU Frequency' }` * * :: [String] -> Map OptionId OptionName */ const parseOptionNames = exports.parseOptionNames = R.compose(R.fromPairs, R.map(R.pipe(R.match(optionNameRegExp), R.tail)), R.filter(R.test(menuRegExp))); /** * Parses options for boards indexed by board ID ("uno", "wifi_slot" and etc) * * :: [String] -> Map BoardId (Map OptionId [OptionValue]) */ const parseIntermediateOptions = exports.parseIntermediateOptions = R.compose(R.reduce((acc, line) => { const boardOption = R.match(boardOptionRegExp, line); if (boardOption.length < 5) return acc; const [, boardId, optionId, optionVal, optionName] = boardOption; const option = { name: optionName, value: optionVal }; return R.over(R.lensPath([boardId, optionId]), R.append(option), acc); }, {}), R.reject(R.either(R.test(menuRegExp), R.test(osRegExp)))); // :: Map OptionId OptionName -> Map OptionId [OptionValue] -> [Option] const convertIntermediateOptions = exports.convertIntermediateOptions = R.curry((optionNames, intOptions) => R.compose(R.values, R.mapObjIndexed((val, key) => ({ optionName: optionNames[key], optionId: key, values: val })))(intOptions)); // :: String -> Map BoardId [Option] /** * Parses boards.txt options into Object, that could be merged with Board objects * by board id (last part of FQBN). * * :: String -> Map BoardId [Option] */ const parseOptions = exports.parseOptions = R.compose(lines => { const optionNames = parseOptionNames(lines); const options = parseIntermediateOptions(lines); return R.map(convertIntermediateOptions(optionNames), options); }, getLines); const parseDisableRts = R.compose(R.fromPairs, R.map(([, boardId, value]) => [boardId, value === 'true']), R.reject(R.isEmpty), R.map(R.match(disableRtsOptionRegExp)), getLines); // ============================================================================= // // API // // ============================================================================= /** * Loads `boards.txt` of installed cores and patches Board objects with options. * Normalises 'FQBN' to 'fqbn' for compatability across xod packages. * * :: Path -> [Core] -> [InstalledBoard | AvailableBoard] -> [InstalledBoard | AvailableBoard] */ const patchBoardsWithOptions = exports.patchBoardsWithOptions = R.curry(async (dataPath, cores, boards) => { if (!boards) return []; // Map CoreID Object const boardTxtContentsByCoreId = await R.compose(_promiseAllProperties2.default, R.map(txtPath => fse.readFile(txtPath, 'utf8')), R.map(core => getBoardsTxtPath(dataPath, core.ID, core.Installed)), R.indexBy(R.prop('ID')))(cores); const optionsByCoreAndBoard = R.map(boardsTxtContents => ({ disableRts: parseDisableRts(boardsTxtContents), options: parseOptions(boardsTxtContents) }), boardTxtContentsByCoreId); return R.map(board => { if (!R.has('FQBN', board)) return board; const fqbn = board.FQBN; const fqbnParts = fqbn.split(':'); const coreId = R.compose(R.join(':'), R.init)(fqbnParts); const boardId = R.last(fqbnParts); const options = R.pathOr([], [coreId, 'options', boardId], optionsByCoreAndBoard); const disableRts = R.pathOr(false, [coreId, 'disableRts', boardId], optionsByCoreAndBoard); return R.merge({ options, disableRts, fqbn }, R.omit(['FQBN'], board)); }, boards); }); //# sourceMappingURL=optionParser.js.map