Skip to content

Commit b2d07cc

Browse files
committed
Implement stringify
1 parent e632c2b commit b2d07cc

File tree

5 files changed

+256
-1
lines changed

5 files changed

+256
-1
lines changed

index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Pos, ZamlError, Schema} from './src/util'
22
import {parseSchema} from './src/schema'
3+
import {stringify as str, StringifyOptions} from './src/stringify'
34
import {lex, parseZaml, ParseOptions} from './src/parser'
45

56
export {parseSchema} from './src/schema'
@@ -25,3 +26,7 @@ export function parse (source: string, schema: string | Schema.Block, options: P
2526
throw e
2627
}
2728
}
29+
30+
export function stringify (value: any, schema: string | Schema.Block, options: StringifyOptions={}) {
31+
return str(value, typeof schema === 'string' ? parseSchema(schema) : schema, options) + '\n'
32+
}

src/parser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,9 @@ function parseArgs (
389389
}
390390
continue
391391
}
392-
throw new ZamlError('syntax-error', pos, unexp(c2, ' (did you forget a comma?)'))
392+
if (pos.i < source.length) {
393+
throw new ZamlError('syntax-error', pos, unexp(c2, ' (did you forget a comma?)'))
394+
}
393395
}
394396

395397
return args

src/stringify.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { Schema } from './util'
2+
3+
export type StringifyOptions = {
4+
indentDepth?: number
5+
}
6+
7+
8+
export function stringify (data: any, blockSchema: Schema.Block, opts: StringifyOptions): string {
9+
const parts: string[] = []
10+
11+
const depth = opts.indentDepth || 0
12+
const i_1 = indentation(depth)
13+
14+
const dataItems = blockSchema.type === 'hash'
15+
? Object.keys(blockSchema.schema).map(configKey => [configKey, data[configKey]])
16+
: data
17+
18+
for (let [key, _value] of dataItems) {
19+
console.log("Serialize", key, _value)
20+
21+
if ( _value === undefined ) continue;
22+
23+
let t = blockSchema.schema[key]
24+
let [value, block] = ('block' in t && t.type !== 'list')
25+
? _value
26+
: [_value, null]
27+
28+
if (
29+
t.type === 'num' ||
30+
t.type === 'str' ||
31+
t.type === 'bool' ||
32+
t.type === 'enum'
33+
) {
34+
parts.push(i_1 + `${key} ${value}`)
35+
}
36+
else if (t.type === 'list') {
37+
let i_2 = indentation(depth + 1)
38+
39+
parts.push(i_1 + `${key} {`)
40+
41+
if (Array.isArray(value)) {
42+
for (let item of value) {
43+
44+
if (t.block) {
45+
let [itemValue, itemBlock] = item
46+
parts.push(i_2 + itemValue)
47+
if (itemBlock) {
48+
addBlockBracket(parts)
49+
parts.push(stringify(itemBlock, t.block, indent(depth+1, opts)))
50+
parts.push(i_2 + '}')
51+
}
52+
}
53+
else {
54+
parts.push(i_2 + item)
55+
}
56+
}
57+
}
58+
parts.push(i_1 + '}')
59+
}
60+
else if (t.type === 'kv') {
61+
let i_2 = indentation(depth + 1)
62+
parts.push(i_1 + `${key} {`)
63+
64+
for (let key in value) {
65+
parts.push(i_2 + `${key} ${value[key]}`)
66+
}
67+
68+
parts.push(i_1 + '}')
69+
}
70+
else if (t.type === 'tuple') {
71+
parts.push(i_1 + `${key} ${value.join(', ')}`)
72+
}
73+
else if (t.type === 'hash' || t.type === 'array') {
74+
parts.push(i_1 + `${key} {`)
75+
76+
parts.push(stringify(value, t, indent(depth, opts)))
77+
78+
parts.push(i_1 + '}')
79+
}
80+
81+
if ('block' in t && t.block && block) {
82+
addBlockBracket(parts)
83+
84+
parts.push(stringify(block, t.block, indent(depth, opts)))
85+
86+
parts.push(i_1 + '}')
87+
}
88+
}
89+
90+
return parts.join('\n')
91+
}
92+
93+
function indentation (n: number) {
94+
let result = ''
95+
for (let i=0; i < n; i++) {
96+
result += ' '
97+
}
98+
return result
99+
}
100+
101+
function indent (depth: number, opts: StringifyOptions) {
102+
return { ...opts, indentDepth: depth+1 }
103+
}
104+
105+
function addBlockBracket (parts: string[]) {
106+
parts[parts.length-1] = parts[parts.length-1] + ' {'
107+
}

tests/regression-tests.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ o.spec("Regression tests", function () {
2323
}
2424
})
2525
})
26+
27+
o("list eof", function () {
28+
var result = parse('nums 10, 20', '{nums:list}')
29+
o(result).deepEquals({ nums: ['10','20'] })
30+
})
2631
})

tests/stringify-test.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
var o = require("ospec")
2+
var {stringify} = require('../dist/index.js')
3+
4+
o.spec("Stringify", function () {
5+
6+
o("basic", function () {
7+
var result = stringify({
8+
a: 10,
9+
b: true,
10+
c: 'cool',
11+
d: 'x',
12+
e: 'ignored'
13+
}, '{a:num,b:bool,c,d:enum(x,y)}')
14+
15+
o(result).deepEquals(
16+
`a 10
17+
b true
18+
c cool
19+
d x
20+
`
21+
)
22+
})
23+
24+
o("list", function () {
25+
var result = stringify({
26+
a: 'A',
27+
b: [10,20,30],
28+
c: 'C'
29+
}, '{a,b:list,c}')
30+
31+
o(result).deepEquals(
32+
`a A
33+
b {
34+
10
35+
20
36+
30
37+
}
38+
c C
39+
`
40+
)
41+
})
42+
43+
o("kv", function () {
44+
var result = stringify({
45+
k: { a: 10, b: 20 }
46+
}, '{k:kv}')
47+
48+
o(result).deepEquals(
49+
`k {
50+
a 10
51+
b 20
52+
}
53+
`
54+
)
55+
})
56+
57+
o("tuple", function () {
58+
var result = stringify({
59+
t: [10, 20]
60+
}, '{t:(num,str)}')
61+
62+
o(result).deepEquals(`t 10, 20\n`)
63+
})
64+
65+
o("hash", function () {
66+
var result = stringify({
67+
top: {
68+
title: 'Nice'
69+
}
70+
}, '{top:{title}}')
71+
72+
o(result).deepEquals(
73+
`top {
74+
title Nice
75+
}
76+
`
77+
)
78+
})
79+
80+
o("array", function () {
81+
var result = stringify({
82+
top: [
83+
['title', 'Nice'],
84+
['stuff', [10,20]],
85+
]
86+
}, '{top:[title, stuff:list]}')
87+
88+
o(result).deepEquals(
89+
`top {
90+
title Nice
91+
stuff {
92+
10
93+
20
94+
}
95+
}
96+
`
97+
)
98+
})
99+
100+
o("value with block", function () {
101+
var result = stringify({
102+
user: ['alice', {
103+
admin: true
104+
}]
105+
}, '{user:str{admin:bool}}')
106+
107+
o(result).deepEquals(
108+
`user alice {
109+
admin true
110+
}
111+
`
112+
)
113+
})
114+
115+
o("list with block", function () {
116+
var result = stringify({
117+
letters: [
118+
['x'],
119+
['y', { special: true }],
120+
['z'],
121+
]
122+
}, '{letters:list{special:bool}}')
123+
124+
o(result).deepEquals(
125+
`letters {
126+
x
127+
y {
128+
special true
129+
}
130+
z
131+
}
132+
`
133+
)
134+
})
135+
136+
})

0 commit comments

Comments
 (0)