diff --git a/package.json b/package.json index a957983a0354b..6f6064d945c33 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,17 @@ "trace" ], "default": "info" + }, + "parquet-viewer.jsonSpace": { + "markdownDescription": "JSON indentation space, passed to `JSON.stringify` as is, see [mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters) for details. Only applies when `#parquet-viewer.useParquetTools#` is `false`.", + "type": [ + "string", + "number" + ], + "default": 0, + "minimum": 0, + "maximum": 10, + "maxLength": 10 } } } diff --git a/src/parquets-backend.ts b/src/parquets-backend.ts index 7f46e028884ad..6e93d255b03dc 100644 --- a/src/parquets-backend.ts +++ b/src/parquets-backend.ts @@ -3,6 +3,7 @@ import { getLogger } from './logger'; import { ParquetReader } from '@dvirtz/parquets'; import * as os from 'os'; import { ParquetBackend } from './parquet-backend'; +import { jsonSpace } from './settings'; export class ParquetsBackend implements ParquetBackend { public async * toJson(parquetPath: string, token?: vscode.CancellationToken): AsyncGenerator { @@ -20,7 +21,7 @@ export class ParquetsBackend implements ParquetBackend { // read all records from the file and print them let record = null; while (!token?.isCancellationRequested && (record = await cursor.next())) { - yield `${JSON.stringify(record)}${os.EOL}`; + yield `${JSON.stringify(record, null, jsonSpace())}${os.EOL}`; } await reader.close(); diff --git a/src/settings.ts b/src/settings.ts index f02a78bbe4222..61f7818665f25 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -40,3 +40,7 @@ export async function setLogLevel(logLevel: LogLevel | undefined): Promise export function useParquetTools(): boolean { return settings().get('useParquetTools', false); } + +export function jsonSpace(): number | string | undefined { + return settings().get('jsonSpace'); +} diff --git a/test/unit/parquets-backend.test.ts b/test/unit/parquets-backend.test.ts index 6652c4a296a2b..a50cd23c2db07 100644 --- a/test/unit/parquets-backend.test.ts +++ b/test/unit/parquets-backend.test.ts @@ -4,6 +4,7 @@ import { createReadStream } from 'fs'; import * as path from 'path'; import { createInterface } from 'readline'; import { ParquetsBackend } from '../../src/parquets-backend'; +import { jsonSpace } from '../../src/settings'; const rootDir = path.join(__dirname, '..', '..'); @@ -20,13 +21,15 @@ jest.mock('vscode', () => { }; }); +jest.mock('../../src/settings'); + describe("ParquetsBackend tests", () => { const backend = new ParquetsBackend(); + const workspace = path.join(rootDir, 'test', 'workspace'); test.each( ["small", "large"] )('Converts %s parquet to JSON', async function (name) { - const workspace = path.join(rootDir, 'test', 'workspace'); const json = (await toArray(backend.toJson(path.join(workspace, `${name}.parquet`)))).map(line => line.trim()); const expected = await toArray(createInterface({input: createReadStream(path.join(workspace, `${name}.json`))})); @@ -38,4 +41,14 @@ describe("ParquetsBackend tests", () => { 'message': expect.stringMatching(/while reading no-such-file: Error: ENOENT: no such file or directory, stat '.*no-such-file'/) }); }); + + test.each([0, 2, 10, "\t", "###"])('Test space %s', async function (space) { + jest.mocked(jsonSpace).mockReturnValue(space); + + const json = (await toArray(backend.toJson(path.join(workspace, `small.parquet`)))).map(line => line.trim()); + const records = await toArray(createInterface({input: createReadStream(path.join(workspace, `small.json`))})); + const expected = records.map(record => JSON.stringify(JSON.parse(record), null, space)); + + expect(json).toEqual(expected); + }); });