diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c4069fd6..f2be97297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file. For change - put future changes here - Improve chinese translation -- Standardize on capitalizeFirstLetter meta key +- Standardize capitalizeFirstLetter meta key +- Change instructions object customization to options.hooks.tokenizedInstruction # 0.0.7 2016-11-10 diff --git a/Readme.md b/Readme.md index 96405aad9..0e8bb9f17 100644 --- a/Readme.md +++ b/Readme.md @@ -18,7 +18,10 @@ osrm-text-instructions transforms OSRM route responses into text instructions. I ### Javascript Usage ``` -var osrmTextInstructions = require('osrm-text-instructions')('v5', 'en'); +var version = 'v5'; +var language = 'en'; +var options = {}; +var osrmTextInstructions = require('osrm-text-instructions')(version, language, options); // make your request against the API @@ -29,6 +32,12 @@ response.legs.forEach(function(leg) { }); ``` +parameter | required? | values | description +---|----|----|--- +`version` | required | `v5` | Major OSRM version +`language` | required | `en` `de` `zh-Hans` `fr` `nl` | Language identifier +`options.hooks.tokenizedIstruction` | optional | `function(instruction)` | A function to change the raw instruction string before tokens are replaced. Useful to inject custom markup for tokens + ### Development #### Architecture diff --git a/index.js b/index.js index 3508b59fc..169f5f447 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,16 @@ -module.exports = function(version, language) { +module.exports = function(version, language, options) { + // load instructions var instructions = require('./instructions').get(language); if (Object !== instructions.constructor) throw 'instructions must be object'; - if (!instructions[version]) { throw 'invalid version ' + version; } - var o = { - instructions: instructions, + return { capitalizeFirstLetter: function(string) { return string.charAt(0).toUpperCase() + string.slice(1); }, ordinalize: function(number) { // Transform numbers to their translated ordinalized value - return this.instructions[version].constants.ordinalize[number.toString()] || ''; + return instructions[version].constants.ordinalize[number.toString()] || ''; }, directionFromDegree: function(degree) { // Transform degrees to their translated compass direction @@ -19,23 +18,23 @@ module.exports = function(version, language) { // step had no bearing_after degree, ignoring return ''; } else if (degree >= 0 && degree <= 20) { - return this.instructions[version].constants.direction.north; + return instructions[version].constants.direction.north; } else if (degree > 20 && degree < 70) { - return this.instructions[version].constants.direction.northeast; + return instructions[version].constants.direction.northeast; } else if (degree >= 70 && degree < 110) { - return this.instructions[version].constants.direction.east; + return instructions[version].constants.direction.east; } else if (degree >= 110 && degree <= 160) { - return this.instructions[version].constants.direction.southeast; + return instructions[version].constants.direction.southeast; } else if (degree > 160 && degree <= 200) { - return this.instructions[version].constants.direction.south; + return instructions[version].constants.direction.south; } else if (degree > 200 && degree < 250) { - return this.instructions[version].constants.direction.southwest; + return instructions[version].constants.direction.southwest; } else if (degree >= 250 && degree <= 290) { - return this.instructions[version].constants.direction.west; + return instructions[version].constants.direction.west; } else if (degree > 290 && degree < 340) { - return this.instructions[version].constants.direction.northwest; + return instructions[version].constants.direction.northwest; } else if (degree >= 340 && degree <= 360) { - return this.instructions[version].constants.direction.north; + return instructions[version].constants.direction.north; } else { throw new Error('Degree ' + degree + ' invalid'); } @@ -70,7 +69,7 @@ module.exports = function(version, language) { if (!type) { throw new Error('Missing step maneuver type'); } if (type !== 'depart' && type !== 'arrive' && !modifier) { throw new Error('Missing step maneuver modifier'); } - if (!this.instructions[version][type]) { + if (!instructions[version][type]) { // Log for debugging console.log('Encountered unknown instruction type: ' + type); // eslint-disable-line no-console // OSRM specification assumes turn types can be added without @@ -79,25 +78,25 @@ module.exports = function(version, language) { type = 'turn'; } - // Use special this.instructions if available, otherwise `defaultinstruction` + // Use special instructions if available, otherwise `defaultinstruction` var instructionObject; - if (this.instructions[version].modes[mode]) { - instructionObject = this.instructions[version].modes[mode]; - } else if (this.instructions[version][type][modifier]) { - instructionObject = this.instructions[version][type][modifier]; + if (instructions[version].modes[mode]) { + instructionObject = instructions[version].modes[mode]; + } else if (instructions[version][type][modifier]) { + instructionObject = instructions[version][type][modifier]; } else { - instructionObject = this.instructions[version][type].default; + instructionObject = instructions[version][type].default; } // Special case handling var laneInstruction; switch (type) { case 'use lane': - laneInstruction = this.instructions[version].constants.lanes[this.laneConfig(step)]; + laneInstruction = instructions[version].constants.lanes[this.laneConfig(step)]; if (!laneInstruction) { // If the lane combination is not found, default to continue straight - instructionObject = this.instructions[version]['use lane'].no_lanes; + instructionObject = instructions[version]['use lane'].no_lanes; } break; case 'rotary': @@ -148,6 +147,11 @@ module.exports = function(version, language) { instruction = instructionObject.default; } + var tokenizedInstructionHook = ((options || {}).hooks || {}).tokenizedInstruction; + if (tokenizedInstructionHook) { + instruction = tokenizedInstructionHook(instruction); + } + // Replace tokens // NOOP if they don't exist var nthWaypoint = ''; // TODO, add correct waypoint counting @@ -157,18 +161,16 @@ module.exports = function(version, language) { .replace('{exit_number}', this.ordinalize(step.maneuver.exit || 1)) .replace('{rotary_name}', step.rotary_name) .replace('{lane_instruction}', laneInstruction) - .replace('{modifier}', this.instructions[version].constants.modifier[modifier]) + .replace('{modifier}', instructions[version].constants.modifier[modifier]) .replace('{direction}', this.directionFromDegree(step.maneuver.bearing_after)) .replace('{nth}', nthWaypoint) .replace(/ {2}/g, ' '); // remove excess spaces - if (this.instructions.meta.capitalizeFirstLetter) { + if (instructions.meta.capitalizeFirstLetter) { instruction = this.capitalizeFirstLetter(instruction); } return instruction; } }; - - return o; }; diff --git a/test/index_test.js b/test/index_test.js index 7295e1781..6e2962dee 100644 --- a/test/index_test.js +++ b/test/index_test.js @@ -115,4 +115,23 @@ tape.test('v5 compile', function(t) { assert.end(); }); + + t.test('respects options.instructionStringHook', function(assert) { + var v5Instructions = instructions('v5', 'en', { + hooks: { + tokenizedInstruction: function(instruction) { + return instruction.replace('{way_name}', '{way_name}'); + } + } + }); + + assert.equal(v5Instructions.compile({ + "maneuver": { + "type": "turn", + "modifier": "left" + }, + "name": "Way Name" + }), 'Turn left onto Way Name'); + assert.end(); + }); });