1 | /**
|
2 | * @author Titus Wormer
|
3 | * @copyright 2015 Titus Wormer
|
4 | * @license MIT
|
5 | * @module mdast:utilities
|
6 | * @version 2.2.2
|
7 | * @fileoverview Collection of tiny helpers useful for
|
8 | * both parsing and compiling markdown.
|
9 | */
|
10 |
|
11 | ;
|
12 |
|
13 | /* eslint-env commonjs */
|
14 |
|
15 | /*
|
16 | * Dependencies.
|
17 | */
|
18 |
|
19 | var collapseWhiteSpace = require('collapse-white-space');
|
20 |
|
21 | /*
|
22 | * Expressions.
|
23 | */
|
24 |
|
25 | var EXPRESSION_LINE_BREAKS = /\r\n|\r/g;
|
26 | var EXPRESSION_SYMBOL_FOR_NEW_LINE = /\u2424/g;
|
27 | var EXPRESSION_BOM = /^\ufeff/;
|
28 |
|
29 | /**
|
30 | * Throw an exception with in its `message` `value`
|
31 | * and `name`.
|
32 | *
|
33 | * @param {*} value - Invalid value.
|
34 | * @param {string} name - Setting name.
|
35 | */
|
36 | function raise(value, name) {
|
37 | throw new Error(
|
38 | 'Invalid value `' + value + '` ' +
|
39 | 'for setting `' + name + '`'
|
40 | );
|
41 | }
|
42 |
|
43 | /**
|
44 | * Validate a value to be boolean. Defaults to `def`.
|
45 | * Raises an exception with `context[name]` when not
|
46 | * a boolean.
|
47 | *
|
48 | * @example
|
49 | * validateBoolean({foo: null}, 'foo', true) // true
|
50 | * validateBoolean({foo: false}, 'foo', true) // false
|
51 | * validateBoolean({foo: 'bar'}, 'foo', true) // Throws
|
52 | *
|
53 | * @throws {Error} - When a setting is neither omitted nor
|
54 | * a boolean.
|
55 | * @param {Object} context - Settings.
|
56 | * @param {string} name - Setting name.
|
57 | * @param {boolean} def - Default value.
|
58 | */
|
59 | function validateBoolean(context, name, def) {
|
60 | var value = context[name];
|
61 |
|
62 | if (value === null || value === undefined) {
|
63 | value = def;
|
64 | }
|
65 |
|
66 | if (typeof value !== 'boolean') {
|
67 | raise(value, 'options.' + name);
|
68 | }
|
69 |
|
70 | context[name] = value;
|
71 | }
|
72 |
|
73 | /**
|
74 | * Validate a value to be boolean. Defaults to `def`.
|
75 | * Raises an exception with `context[name]` when not
|
76 | * a boolean.
|
77 | *
|
78 | * @example
|
79 | * validateNumber({foo: null}, 'foo', 1) // 1
|
80 | * validateNumber({foo: 2}, 'foo', 1) // 2
|
81 | * validateNumber({foo: 'bar'}, 'foo', 1) // Throws
|
82 | *
|
83 | * @throws {Error} - When a setting is neither omitted nor
|
84 | * a number.
|
85 | * @param {Object} context - Settings.
|
86 | * @param {string} name - Setting name.
|
87 | * @param {number} def - Default value.
|
88 | */
|
89 | function validateNumber(context, name, def) {
|
90 | var value = context[name];
|
91 |
|
92 | if (value === null || value === undefined) {
|
93 | value = def;
|
94 | }
|
95 |
|
96 | if (typeof value !== 'number' || value !== value) {
|
97 | raise(value, 'options.' + name);
|
98 | }
|
99 |
|
100 | context[name] = value;
|
101 | }
|
102 |
|
103 | /**
|
104 | * Validate a value to be in `map`. Defaults to `def`.
|
105 | * Raises an exception with `context[name]` when not
|
106 | * not in `map`.
|
107 | *
|
108 | * @example
|
109 | * var map = {bar: true, baz: true};
|
110 | * validateString({foo: null}, 'foo', 'bar', map) // 'bar'
|
111 | * validateString({foo: 'baz'}, 'foo', 'bar', map) // 'baz'
|
112 | * validateString({foo: true}, 'foo', 'bar', map) // Throws
|
113 | *
|
114 | * @throws {Error} - When a setting is neither omitted nor
|
115 | * in `map`.
|
116 | * @param {Object} context - Settings.
|
117 | * @param {string} name - Setting name.
|
118 | * @param {string} def - Default value.
|
119 | * @param {Object} map - Enum.
|
120 | */
|
121 | function validateString(context, name, def, map) {
|
122 | var value = context[name];
|
123 |
|
124 | if (value === null || value === undefined) {
|
125 | value = def;
|
126 | }
|
127 |
|
128 | if (!(value in map)) {
|
129 | raise(value, 'options.' + name);
|
130 | }
|
131 |
|
132 | context[name] = value;
|
133 | }
|
134 |
|
135 | /**
|
136 | * Clean a string in preperation of parsing.
|
137 | *
|
138 | * @example
|
139 | * clean('\ufefffoo'); // 'foo'
|
140 | * clean('foo\r\nbar'); // 'foo\nbar'
|
141 | * clean('foo\u2424bar'); // 'foo\nbar'
|
142 | *
|
143 | * @param {string} value - Content to clean.
|
144 | * @return {string} - Cleaned content.
|
145 | */
|
146 | function clean(value) {
|
147 | return String(value)
|
148 | .replace(EXPRESSION_BOM, '')
|
149 | .replace(EXPRESSION_LINE_BREAKS, '\n')
|
150 | .replace(EXPRESSION_SYMBOL_FOR_NEW_LINE, '\n');
|
151 | }
|
152 |
|
153 | /**
|
154 | * Normalize an identifier. Collapses multiple white space
|
155 | * characters into a single space, and removes casing.
|
156 | *
|
157 | * @example
|
158 | * normalizeIdentifier('FOO\t bar'); // 'foo bar'
|
159 | *
|
160 | * @param {string} value - Content to normalize.
|
161 | * @return {string} - Normalized content.
|
162 | */
|
163 | function normalizeIdentifier(value) {
|
164 | return collapseWhiteSpace(value).toLowerCase();
|
165 | }
|
166 |
|
167 | /*
|
168 | * Expose `validate`.
|
169 | */
|
170 |
|
171 | exports.validate = {
|
172 | 'boolean': validateBoolean,
|
173 | 'string': validateString,
|
174 | 'number': validateNumber
|
175 | };
|
176 |
|
177 | /*
|
178 | * Expose.
|
179 | */
|
180 |
|
181 | exports.normalizeIdentifier = normalizeIdentifier;
|
182 | exports.clean = clean;
|
183 | exports.raise = raise;
|