Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stringify.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.stringifyNumber = stringifyNumber;
  6. exports.stringifyString = stringifyString;
  7. var _addComment = require("./addComment");
  8. var _constants = require("./constants");
  9. var _foldFlowLines = _interopRequireWildcard(require("./foldFlowLines"));
  10. var _options = require("./tags/options");
  11. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
  12. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  13. function stringifyNumber({
  14. format,
  15. minFractionDigits,
  16. tag,
  17. value
  18. }) {
  19. if (!isFinite(value)) return isNaN(value) ? '.nan' : value < 0 ? '-.inf' : '.inf';
  20. let n = JSON.stringify(value);
  21. if (!format && minFractionDigits && (!tag || tag === 'tag:yaml.org,2002:float') && /^\d/.test(n)) {
  22. let i = n.indexOf('.');
  23. if (i < 0) {
  24. i = n.length;
  25. n += '.';
  26. }
  27. let d = minFractionDigits - (n.length - i - 1);
  28. while (d-- > 0) n += '0';
  29. }
  30. return n;
  31. }
  32. function lineLengthOverLimit(str, limit) {
  33. const strLen = str.length;
  34. if (strLen <= limit) return false;
  35. for (let i = 0, start = 0; i < strLen; ++i) {
  36. if (str[i] === '\n') {
  37. if (i - start > limit) return true;
  38. start = i + 1;
  39. if (strLen - start <= limit) return false;
  40. }
  41. }
  42. return true;
  43. }
  44. function doubleQuotedString(value, {
  45. implicitKey,
  46. indent
  47. }) {
  48. const {
  49. jsonEncoding,
  50. minMultiLineLength
  51. } = _options.strOptions.doubleQuoted;
  52. const json = JSON.stringify(value);
  53. if (jsonEncoding) return json;
  54. let str = '';
  55. let start = 0;
  56. for (let i = 0, ch = json[i]; ch; ch = json[++i]) {
  57. if (ch === ' ' && json[i + 1] === '\\' && json[i + 2] === 'n') {
  58. // space before newline needs to be escaped to not be folded
  59. str += json.slice(start, i) + '\\ ';
  60. i += 1;
  61. start = i;
  62. ch = '\\';
  63. }
  64. if (ch === '\\') switch (json[i + 1]) {
  65. case 'u':
  66. {
  67. str += json.slice(start, i);
  68. const code = json.substr(i + 2, 4);
  69. switch (code) {
  70. case '0000':
  71. str += '\\0';
  72. break;
  73. case '0007':
  74. str += '\\a';
  75. break;
  76. case '000b':
  77. str += '\\v';
  78. break;
  79. case '001b':
  80. str += '\\e';
  81. break;
  82. case '0085':
  83. str += '\\N';
  84. break;
  85. case '00a0':
  86. str += '\\_';
  87. break;
  88. case '2028':
  89. str += '\\L';
  90. break;
  91. case '2029':
  92. str += '\\P';
  93. break;
  94. default:
  95. if (code.substr(0, 2) === '00') str += '\\x' + code.substr(2);else str += json.substr(i, 6);
  96. }
  97. i += 5;
  98. start = i + 1;
  99. }
  100. break;
  101. case 'n':
  102. if (implicitKey || json[i + 2] === '"' || json.length < minMultiLineLength) {
  103. i += 1;
  104. } else {
  105. // folding will eat first newline
  106. str += json.slice(start, i) + '\n\n';
  107. while (json[i + 2] === '\\' && json[i + 3] === 'n' && json[i + 4] !== '"') {
  108. str += '\n';
  109. i += 2;
  110. }
  111. str += indent; // space after newline needs to be escaped to not be folded
  112. if (json[i + 2] === ' ') str += '\\';
  113. i += 1;
  114. start = i + 1;
  115. }
  116. break;
  117. default:
  118. i += 1;
  119. }
  120. }
  121. str = start ? str + json.slice(start) : json;
  122. return implicitKey ? str : (0, _foldFlowLines.default)(str, indent, _foldFlowLines.FOLD_QUOTED, _options.strOptions.fold);
  123. }
  124. function singleQuotedString(value, ctx) {
  125. const {
  126. indent,
  127. implicitKey
  128. } = ctx;
  129. if (implicitKey) {
  130. if (/\n/.test(value)) return doubleQuotedString(value, ctx);
  131. } else {
  132. // single quoted string can't have leading or trailing whitespace around newline
  133. if (/[ \t]\n|\n[ \t]/.test(value)) return doubleQuotedString(value, ctx);
  134. }
  135. const res = "'" + value.replace(/'/g, "''").replace(/\n+/g, `$&\n${indent}`) + "'";
  136. return implicitKey ? res : (0, _foldFlowLines.default)(res, indent, _foldFlowLines.FOLD_FLOW, _options.strOptions.fold);
  137. }
  138. function blockString({
  139. comment,
  140. type,
  141. value
  142. }, ctx, onComment, onChompKeep) {
  143. // 1. Block can't end in whitespace unless the last line is non-empty.
  144. // 2. Strings consisting of only whitespace are best rendered explicitly.
  145. if (/\n[\t ]+$/.test(value) || /^\s*$/.test(value)) {
  146. return doubleQuotedString(value, ctx);
  147. }
  148. const indent = ctx.indent || (ctx.forceBlockIndent ? ' ' : '');
  149. const indentSize = indent ? '2' : '1'; // root is at -1
  150. const literal = type === _constants.Type.BLOCK_FOLDED ? false : type === _constants.Type.BLOCK_LITERAL ? true : !lineLengthOverLimit(value, _options.strOptions.fold.lineWidth - indent.length);
  151. let header = literal ? '|' : '>';
  152. if (!value) return header + '\n';
  153. let wsStart = '';
  154. let wsEnd = '';
  155. value = value.replace(/[\n\t ]*$/, ws => {
  156. const n = ws.indexOf('\n');
  157. if (n === -1) {
  158. header += '-'; // strip
  159. } else if (value === ws || n !== ws.length - 1) {
  160. header += '+'; // keep
  161. if (onChompKeep) onChompKeep();
  162. }
  163. wsEnd = ws.replace(/\n$/, '');
  164. return '';
  165. }).replace(/^[\n ]*/, ws => {
  166. if (ws.indexOf(' ') !== -1) header += indentSize;
  167. const m = ws.match(/ +$/);
  168. if (m) {
  169. wsStart = ws.slice(0, -m[0].length);
  170. return m[0];
  171. } else {
  172. wsStart = ws;
  173. return '';
  174. }
  175. });
  176. if (wsEnd) wsEnd = wsEnd.replace(/\n+(?!\n|$)/g, `$&${indent}`);
  177. if (wsStart) wsStart = wsStart.replace(/\n+/g, `$&${indent}`);
  178. if (comment) {
  179. header += ' #' + comment.replace(/ ?[\r\n]+/g, ' ');
  180. if (onComment) onComment();
  181. }
  182. if (!value) return `${header}${indentSize}\n${indent}${wsEnd}`;
  183. if (literal) {
  184. value = value.replace(/\n+/g, `$&${indent}`);
  185. return `${header}\n${indent}${wsStart}${value}${wsEnd}`;
  186. }
  187. value = value.replace(/\n+/g, '\n$&').replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g, '$1$2') // more-indented lines aren't folded
  188. // ^ ind.line ^ empty ^ capture next empty lines only at end of indent
  189. .replace(/\n+/g, `$&${indent}`);
  190. const body = (0, _foldFlowLines.default)(`${wsStart}${value}${wsEnd}`, indent, _foldFlowLines.FOLD_BLOCK, _options.strOptions.fold);
  191. return `${header}\n${indent}${body}`;
  192. }
  193. function plainString(item, ctx, onComment, onChompKeep) {
  194. const {
  195. comment,
  196. type,
  197. value
  198. } = item;
  199. const {
  200. actualString,
  201. implicitKey,
  202. indent,
  203. inFlow,
  204. tags
  205. } = ctx;
  206. if (implicitKey && /[\n[\]{},]/.test(value) || inFlow && /[[\]{},]/.test(value)) {
  207. return doubleQuotedString(value, ctx);
  208. }
  209. if (!value || /^[\n\t ,[\]{}#&*!|>'"%@`]|^[?-]$|^[?-][ \t]|[\n:][ \t]|[ \t]\n|[\n\t ]#|[\n\t :]$/.test(value)) {
  210. // not allowed:
  211. // - empty string, '-' or '?'
  212. // - start with an indicator character (except [?:-]) or /[?-] /
  213. // - '\n ', ': ' or ' \n' anywhere
  214. // - '#' not preceded by a non-space char
  215. // - end with ' ' or ':'
  216. return implicitKey || inFlow || value.indexOf('\n') === -1 ? value.indexOf('"') !== -1 && value.indexOf("'") === -1 ? singleQuotedString(value, ctx) : doubleQuotedString(value, ctx) : blockString(item, ctx, onComment, onChompKeep);
  217. }
  218. if (!implicitKey && !inFlow && type !== _constants.Type.PLAIN && value.indexOf('\n') !== -1) {
  219. // Where allowed & type not set explicitly, prefer block style for multiline strings
  220. return blockString(item, ctx, onComment, onChompKeep);
  221. }
  222. const str = value.replace(/\n+/g, `$&\n${indent}`); // Verify that output will be parsed as a string, as e.g. plain numbers and
  223. // booleans get parsed with those types in v1.2 (e.g. '42', 'true' & '0.9e-3'),
  224. // and others in v1.1.
  225. if (actualString && typeof tags.resolveScalar(str).value !== 'string') {
  226. return doubleQuotedString(value, ctx);
  227. }
  228. const body = implicitKey ? str : (0, _foldFlowLines.default)(str, indent, _foldFlowLines.FOLD_FLOW, _options.strOptions.fold);
  229. if (comment && !inFlow && (body.indexOf('\n') !== -1 || comment.indexOf('\n') !== -1)) {
  230. if (onComment) onComment();
  231. return (0, _addComment.addCommentBefore)(body, indent, comment);
  232. }
  233. return body;
  234. }
  235. function stringifyString(item, ctx, onComment, onChompKeep) {
  236. const {
  237. defaultType
  238. } = _options.strOptions;
  239. const {
  240. implicitKey,
  241. inFlow
  242. } = ctx;
  243. let {
  244. type,
  245. value
  246. } = item;
  247. if (typeof value !== 'string') {
  248. value = String(value);
  249. item = Object.assign({}, item, {
  250. value
  251. });
  252. }
  253. const _stringify = _type => {
  254. switch (_type) {
  255. case _constants.Type.BLOCK_FOLDED:
  256. case _constants.Type.BLOCK_LITERAL:
  257. return blockString(item, ctx, onComment, onChompKeep);
  258. case _constants.Type.QUOTE_DOUBLE:
  259. return doubleQuotedString(value, ctx);
  260. case _constants.Type.QUOTE_SINGLE:
  261. return singleQuotedString(value, ctx);
  262. case _constants.Type.PLAIN:
  263. return plainString(item, ctx, onComment, onChompKeep);
  264. default:
  265. return null;
  266. }
  267. };
  268. if (type !== _constants.Type.QUOTE_DOUBLE && /[\x00-\x08\x0b-\x1f\x7f-\x9f]/.test(value)) {
  269. // force double quotes on control characters
  270. type = _constants.Type.QUOTE_DOUBLE;
  271. } else if ((implicitKey || inFlow) && (type === _constants.Type.BLOCK_FOLDED || type === _constants.Type.BLOCK_LITERAL)) {
  272. // should not happen; blocks are not valid inside flow containers
  273. type = _constants.Type.QUOTE_DOUBLE;
  274. }
  275. let res = _stringify(type);
  276. if (res === null) {
  277. res = _stringify(defaultType);
  278. if (res === null) throw new Error(`Unsupported default string type ${defaultType}`);
  279. }
  280. return res;
  281. }