A simple parser for Valve's KeyValue text file format (VDF) https://developer.valvesoftware.com/wiki/KeyValues. Written in JavaScript (TypeScript).
Support both returning an object OR piping readable stream to the parser streaming out key-value pairs.
Pick your favorite package manager. For example using npm:
npm install @hinw/vdf-parser
import { VdfParser } from '@hinw/vdf-parser'; // file content: "key" { "nested_key" "value" }" const filePath = 'input/sample.vdf'; const parser = new VdfParser(); const result = await parser.parseFile(filePath); // assert.assertEqual(result, { key: { nested_key: 'value' }});
import stream from 'node:stream'; import { VdfParser } from '@hinw/vdf-parser'; const readStream = stream.Readable.from(`"key" { "nested_key" "value" }"`); const parser = new VdfParser(); const result = await parser.parseStream(readStream); // assert.assertEqual(result, { key: { nested_key: 'value' }});
import { VdfParser } from '@hinw/vdf-parser'; const input = `"key" { "nested_key" "value" }"`; const parser = new VdfParser(); const result = await parser.parseText(input); // assert.assertEqual(result, { key: { nested_key: 'value' }});
import fs from 'node:fs' import { VdfParser } from '@hinw/vdf-parser'; // file content: "key" { "nested_key" "value" }" const filePath = 'input/sample.vdf'; const parser = new VdfParser(); const fileStream = fs.createReadStream(filePath) const parserStream = fileStream.pipe(parser) for await (const pair of parserStream) { // assert.assertEqual(pair, { keyParts: ['key', 'nested_key'], value: 'value' }); }
// You can build the object from the stream using async iterator interface: const fileStream = fs.createReadStream(filePath) const parserStream = fileStream.pipe(parser) const result = await parser.condensePairsAsync(parserStream) // Or you can store the pairs somewhere, and build it afterwards with normal iterator interface: const fileStream = fs.createReadStream(filePath) const parserStream = fileStream.pipe(parser) const pairs = await Array.fromAsync(parserStream) const result = parser.condensePairs(pairs)
By default, the parser will handle escape sequence. To disable this behavior, you can set disableEscape to true.
import { VdfParser } from '@hinw/vdf-parser'; const input = `"\\"quoted key\\"" "value"`; const parser = new VdfParser({ disableEscape: true }); const result = await parser.parseText(input); // assert.assertEqual(result, { '\\"quoted key\\"': 'value' });
If the values of the duplicated keys are all maps, they will be merged together
import { VdfParser } from '@hinw/vdf-parser'; const input = `"key" { "nested_key" "value" }" "key" { "nested_key_2" "value" }"`; const parser = new VdfParser({ useLatestValue: true }); const result = await parser.parseText(input); // assert.assertEqual(result, { key: { nested_key: 'value', nested_key_2: 'value' }});
By default, the parser will use the earliest seen value for the duplicated keys.
import { VdfParser } from '@hinw/vdf-parser'; const input = `"key" { "nested_key" "value" }" "key" "value"`; const parser = new VdfParser(); const result = await parser.parseText(input); // assert.assertEqual(result, { key: { nested_key: 'value' }});
However, you can set useLatestValue to true to use the latest seen value instead.
import { VdfParser } from '@hinw/vdf-parser'; const input = `"key" { "nested_key" "value" }" "key" "value"`; const parser = new VdfParser({ useLatestValue: true }); const result = await parser.parseText(input); // assert.assertEqual(result, { key: 'value' });
Since the VDF specification does not contain any type info, it would be a guess work to convert some value to a certain type. To keep this library simple, it would not provide an option to do auto type detection / conversion. In theory if the user is interested in using the values of a VDF they should know the schema of the file well and it is the responsibiliy for the user to convert the types instead of this library doing the guess work.