tape-six 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,150 @@
1
+ const defaultOptions = {offset: 0, levelOffset: 2, string: ' ', maxDepth: 5};
2
+
3
+ const repeatString = (n, string = ' ') => {
4
+ let acc = '',
5
+ buffer = string;
6
+ for (; n > 0; n >>= 1, buffer += buffer) {
7
+ n & 1 && (acc += buffer);
8
+ }
9
+ return acc;
10
+ };
11
+
12
+ const hasNewline = /\n/,
13
+ hasColon = /:/,
14
+ forceQuotes = /^(?:@|`|\s|$|true$|false$|null$|.+\s$)/;
15
+
16
+ const getDataEncoding = value => {
17
+ switch (typeof value) {
18
+ case 'string':
19
+ if (hasNewline.test(value)) return {inline: true, string: value.split('\n')};
20
+ if (forceQuotes.test(value)) return {inline: true, string: '"' + value + '"'};
21
+ if (!isNaN(value)) return {inline: true, string: '"' + value + '"'};
22
+ {
23
+ const encoded = JSON.stringify(value);
24
+ if (value.length + 2 === encoded.length) return {inline: true, string: value};
25
+ return {inline: true, string: encoded};
26
+ }
27
+ case 'boolean':
28
+ return {inline: true, string: String(value)};
29
+ case 'number':
30
+ if (value === Infinity) return {inline: true, string: '.inf'};
31
+ if (value === -Infinity) return {inline: true, string: '-.inf'};
32
+ if (isNaN(value)) return {inline: true, string: '.nan'};
33
+ return {inline: true, string: String(value)};
34
+ case 'object':
35
+ break;
36
+ default:
37
+ return {skip: true};
38
+ }
39
+ if (value === null) return {inline: true, string: 'null'};
40
+ if (value instanceof Date) return {inline: true, string: value.toUTCString()};
41
+ if (value instanceof Set || value instanceof Map) return {skip: true};
42
+ if (Array.isArray(value) && !value.length) return {inline: true, string: '[]'};
43
+ const keys = Object.keys(value);
44
+ if (!keys.length) return {inline: true, string: '{}'};
45
+ return {};
46
+ };
47
+
48
+ const getKeyEncoding = key => {
49
+ if (forceQuotes.test(key)) return {string: '"' + key + '"'};
50
+ if (hasNewline.test(key)) return {string: key.split('\n')};
51
+ const encoded = JSON.stringify(key);
52
+ if (key.length + 2 === encoded.length) {
53
+ if (hasColon.test(key)) return {string: key};
54
+ return {inline: true, string: key};
55
+ }
56
+ return {inline: true, string: encoded};
57
+ };
58
+
59
+ const format = (value, options, level, offset, lines) => {
60
+ if (level > options.maxDepth) return;
61
+ const result = getDataEncoding(value);
62
+ if (result.skip) return;
63
+ if (result.inline) {
64
+ if (typeof result.string == 'string') {
65
+ lines.push(offset + result.string);
66
+ return;
67
+ }
68
+ lines.push(offset + '|+');
69
+ offset += options.levelOffset;
70
+ result.string.forEach(line => lines.push(offset + line));
71
+ return;
72
+ }
73
+
74
+ // array
75
+ if (Array.isArray(value)) {
76
+ if (level + 1 > options.maxDepth) {
77
+ lines.push(offset + '[]');
78
+ return;
79
+ }
80
+ value.forEach(v => {
81
+ const valueResult = getDataEncoding(v);
82
+ if (valueResult.skip) return;
83
+ if (valueResult.inline) {
84
+ if (typeof valueResult.string == 'string') {
85
+ lines.push(offset + '- ' + valueResult.string);
86
+ return;
87
+ }
88
+ lines.push(offset + '- |+');
89
+ const nextOffset = offset + options.levelOffset;
90
+ valueResult.string.forEach(line => lines.push(nextOffset + line));
91
+ return;
92
+ }
93
+ lines.push(offset + '-');
94
+ format(v, options, level + 1, offset + options.levelOffset, lines);
95
+ });
96
+ return;
97
+ }
98
+
99
+ // regular object
100
+ if (level + 1 > options.maxDepth) {
101
+ lines.push(offset + '{}');
102
+ return;
103
+ }
104
+ for (let k in value) {
105
+ const v = value[k],
106
+ valueResult = getDataEncoding(v);
107
+ if (valueResult.skip) continue;
108
+ const keyResult = getKeyEncoding(k);
109
+ if (!keyResult.inline) {
110
+ if (typeof keyResult.string == 'string') {
111
+ lines.push(offset + '? ' + keyResult.string);
112
+ } else {
113
+ lines.push(offset + '? |+');
114
+ const nextOffset = offset + options.levelOffset;
115
+ keyResult.string.forEach(line => lines.push(nextOffset + line));
116
+ }
117
+ }
118
+ const key = keyResult.inline ? keyResult.string : '';
119
+ if (valueResult.inline) {
120
+ if (typeof valueResult.string == 'string') {
121
+ lines.push(offset + key + ': ' + valueResult.string);
122
+ continue;
123
+ }
124
+ lines.push(offset + key + ': |+');
125
+ const nextOffset = offset + options.levelOffset;
126
+ valueResult.string.forEach(line => lines.push(nextOffset + line));
127
+ continue;
128
+ }
129
+ lines.push(offset + key + ':');
130
+ format(v, options, level + 1, offset + options.levelOffset, lines);
131
+ }
132
+ };
133
+
134
+ const yamlFormatter = (object, options) => {
135
+ options = {...defaultOptions, ...options};
136
+ const lines = [],
137
+ string = options.string || ' ',
138
+ offset = !isNaN(options.offset) && options.offset > 0 ? repeatString(options.offset, string) : typeof options.offset == 'string' ? options.offset : '',
139
+ levelOffset =
140
+ !isNaN(options.levelOffset) && options.levelOffset > 0
141
+ ? repeatString(options.levelOffset, string)
142
+ : typeof options.levelOffset == 'string'
143
+ ? options.levelOffset
144
+ : '',
145
+ opts = {levelOffset, maxDepth: options.maxDepth};
146
+ format(object, opts, 0, offset, lines);
147
+ return lines;
148
+ };
149
+
150
+ export default yamlFormatter;