set-options.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. 'use strict';
  2. var xtend = require('xtend');
  3. var encode = require('stringify-entities');
  4. var defaults = require('./defaults');
  5. var escapeFactory = require('./escape');
  6. var returner = require('./util/returner');
  7. module.exports = setOptions;
  8. /* Map of applicable enum's. */
  9. var maps = {
  10. entities: {true: true, false: true, numbers: true, escape: true},
  11. bullet: {'*': true, '-': true, '+': true},
  12. rule: {'-': true, _: true, '*': true},
  13. listItemIndent: {tab: true, mixed: true, 1: true},
  14. emphasis: {_: true, '*': true},
  15. strong: {_: true, '*': true},
  16. fence: {'`': true, '~': true}
  17. };
  18. /* Expose `validate`. */
  19. var validate = {
  20. boolean: validateBoolean,
  21. string: validateString,
  22. number: validateNumber,
  23. function: validateFunction
  24. };
  25. /* Set options. Does not overwrite previously set
  26. * options. */
  27. function setOptions(options) {
  28. var self = this;
  29. var current = self.options;
  30. var ruleRepetition;
  31. var key;
  32. if (options == null) {
  33. options = {};
  34. } else if (typeof options === 'object') {
  35. options = xtend(options);
  36. } else {
  37. throw new Error('Invalid value `' + options + '` for setting `options`');
  38. }
  39. for (key in defaults) {
  40. validate[typeof defaults[key]](options, key, current[key], maps[key]);
  41. }
  42. ruleRepetition = options.ruleRepetition;
  43. if (ruleRepetition && ruleRepetition < 3) {
  44. raise(ruleRepetition, 'options.ruleRepetition');
  45. }
  46. self.encode = encodeFactory(String(options.entities));
  47. self.escape = escapeFactory(options);
  48. self.options = options;
  49. return self;
  50. }
  51. /* Throw an exception with in its `message` `value`
  52. * and `name`. */
  53. function raise(value, name) {
  54. throw new Error('Invalid value `' + value + '` for setting `' + name + '`');
  55. }
  56. /* Validate a value to be boolean. Defaults to `def`.
  57. * Raises an exception with `context[name]` when not
  58. * a boolean. */
  59. function validateBoolean(context, name, def) {
  60. var value = context[name];
  61. if (value == null) {
  62. value = def;
  63. }
  64. if (typeof value !== 'boolean') {
  65. raise(value, 'options.' + name);
  66. }
  67. context[name] = value;
  68. }
  69. /* Validate a value to be boolean. Defaults to `def`.
  70. * Raises an exception with `context[name]` when not
  71. * a boolean. */
  72. function validateNumber(context, name, def) {
  73. var value = context[name];
  74. if (value == null) {
  75. value = def;
  76. }
  77. if (isNaN(value)) {
  78. raise(value, 'options.' + name);
  79. }
  80. context[name] = value;
  81. }
  82. /* Validate a value to be in `map`. Defaults to `def`.
  83. * Raises an exception with `context[name]` when not
  84. * in `map`. */
  85. function validateString(context, name, def, map) {
  86. var value = context[name];
  87. if (value == null) {
  88. value = def;
  89. }
  90. value = String(value);
  91. if (!(value in map)) {
  92. raise(value, 'options.' + name);
  93. }
  94. context[name] = value;
  95. }
  96. /* Validate a value to be function. Defaults to `def`.
  97. * Raises an exception with `context[name]` when not
  98. * a function. */
  99. function validateFunction(context, name, def) {
  100. var value = context[name];
  101. if (value == null) {
  102. value = def;
  103. }
  104. if (typeof value !== 'function') {
  105. raise(value, 'options.' + name);
  106. }
  107. context[name] = value;
  108. }
  109. /* Factory to encode HTML entities.
  110. * Creates a no-operation function when `type` is
  111. * `'false'`, a function which encodes using named
  112. * references when `type` is `'true'`, and a function
  113. * which encodes using numbered references when `type` is
  114. * `'numbers'`. */
  115. function encodeFactory(type) {
  116. var options = {};
  117. if (type === 'false') {
  118. return returner;
  119. }
  120. if (type === 'true') {
  121. options.useNamedReferences = true;
  122. }
  123. if (type === 'escape') {
  124. options.escapeOnly = true;
  125. options.useNamedReferences = true;
  126. }
  127. return wrapped;
  128. /* Encode HTML entities using the bound options. */
  129. function wrapped(value) {
  130. return encode(value, options);
  131. }
  132. }