neonctl 2.22.2 → 2.23.1

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.
Files changed (113) hide show
  1. package/README.md +84 -0
  2. package/analytics.js +5 -2
  3. package/commands/branches.js +9 -1
  4. package/commands/connection_string.js +9 -1
  5. package/commands/functions.js +268 -0
  6. package/commands/index.js +4 -0
  7. package/commands/neon_auth.js +1013 -0
  8. package/commands/projects.js +9 -1
  9. package/commands/psql.js +6 -1
  10. package/functions_api.js +43 -0
  11. package/package.json +15 -5
  12. package/psql/cli.js +51 -0
  13. package/psql/command/cmd_cond.js +437 -0
  14. package/psql/command/cmd_connect.js +815 -0
  15. package/psql/command/cmd_copy.js +1025 -0
  16. package/psql/command/cmd_describe.js +1810 -0
  17. package/psql/command/cmd_format.js +909 -0
  18. package/psql/command/cmd_io.js +2187 -0
  19. package/psql/command/cmd_lo.js +385 -0
  20. package/psql/command/cmd_meta.js +970 -0
  21. package/psql/command/cmd_misc.js +187 -0
  22. package/psql/command/cmd_pipeline.js +1141 -0
  23. package/psql/command/cmd_restrict.js +171 -0
  24. package/psql/command/cmd_show.js +751 -0
  25. package/psql/command/dispatch.js +343 -0
  26. package/psql/command/inputQueue.js +42 -0
  27. package/psql/command/shared.js +71 -0
  28. package/psql/complete/filenames.js +139 -0
  29. package/psql/complete/index.js +104 -0
  30. package/psql/complete/matcher.js +314 -0
  31. package/psql/complete/psqlVars.js +247 -0
  32. package/psql/complete/queries.js +491 -0
  33. package/psql/complete/rules.js +2387 -0
  34. package/psql/core/common.js +1250 -0
  35. package/psql/core/help.js +576 -0
  36. package/psql/core/mainloop.js +1353 -0
  37. package/psql/core/prompt.js +437 -0
  38. package/psql/core/settings.js +684 -0
  39. package/psql/core/sqlHelp.js +1066 -0
  40. package/psql/core/startup.js +840 -0
  41. package/psql/core/syncVars.js +116 -0
  42. package/psql/core/variables.js +287 -0
  43. package/psql/describe/formatters.js +1277 -0
  44. package/psql/describe/processNamePattern.js +270 -0
  45. package/psql/describe/queries.js +2373 -0
  46. package/psql/describe/versionGate.js +43 -0
  47. package/psql/index.js +2005 -0
  48. package/psql/io/history.js +299 -0
  49. package/psql/io/input.js +120 -0
  50. package/psql/io/lineEditor/buffer.js +323 -0
  51. package/psql/io/lineEditor/complete.js +227 -0
  52. package/psql/io/lineEditor/filename.js +159 -0
  53. package/psql/io/lineEditor/index.js +891 -0
  54. package/psql/io/lineEditor/keymap.js +738 -0
  55. package/psql/io/lineEditor/vt100.js +363 -0
  56. package/psql/io/pgpass.js +202 -0
  57. package/psql/io/pgservice.js +194 -0
  58. package/psql/io/psqlrc.js +422 -0
  59. package/psql/print/aligned.js +1756 -0
  60. package/psql/print/asciidoc.js +248 -0
  61. package/psql/print/crosstab.js +460 -0
  62. package/psql/print/csv.js +92 -0
  63. package/psql/print/html.js +258 -0
  64. package/psql/print/json.js +96 -0
  65. package/psql/print/latex.js +396 -0
  66. package/psql/print/pager.js +265 -0
  67. package/psql/print/troff.js +258 -0
  68. package/psql/print/unaligned.js +118 -0
  69. package/psql/print/units.js +135 -0
  70. package/psql/scanner/slash.js +513 -0
  71. package/psql/scanner/sql.js +910 -0
  72. package/psql/scanner/stringutils.js +390 -0
  73. package/psql/types/backslash.js +1 -0
  74. package/psql/types/connection.js +1 -0
  75. package/psql/types/index.js +7 -0
  76. package/psql/types/printer.js +1 -0
  77. package/psql/types/repl.js +1 -0
  78. package/psql/types/scanner.js +24 -0
  79. package/psql/types/settings.js +1 -0
  80. package/psql/types/variables.js +1 -0
  81. package/psql/wire/connection.js +2844 -0
  82. package/psql/wire/copy.js +108 -0
  83. package/psql/wire/notify.js +59 -0
  84. package/psql/wire/pipeline.js +519 -0
  85. package/psql/wire/protocol.js +466 -0
  86. package/psql/wire/sasl.js +296 -0
  87. package/psql/wire/tls.js +596 -0
  88. package/test_utils/fixtures.js +1 -0
  89. package/utils/esbuild.js +147 -0
  90. package/utils/psql.js +107 -11
  91. package/utils/zip.js +4 -0
  92. package/writer.js +1 -1
  93. package/commands/auth.test.js +0 -211
  94. package/commands/branches.test.js +0 -460
  95. package/commands/checkout.test.js +0 -170
  96. package/commands/connection_string.test.js +0 -196
  97. package/commands/data_api.test.js +0 -169
  98. package/commands/databases.test.js +0 -39
  99. package/commands/help.test.js +0 -9
  100. package/commands/init.test.js +0 -56
  101. package/commands/ip_allow.test.js +0 -59
  102. package/commands/link.test.js +0 -381
  103. package/commands/operations.test.js +0 -7
  104. package/commands/orgs.test.js +0 -7
  105. package/commands/projects.test.js +0 -144
  106. package/commands/psql.test.js +0 -49
  107. package/commands/roles.test.js +0 -37
  108. package/commands/set_context.test.js +0 -159
  109. package/commands/vpc_endpoints.test.js +0 -69
  110. package/context.test.js +0 -119
  111. package/env.test.js +0 -55
  112. package/utils/formats.test.js +0 -32
  113. package/writer.test.js +0 -104
@@ -1,159 +0,0 @@
1
- import { tmpdir } from 'node:os';
2
- import { join } from 'node:path';
3
- import { rmSync, writeFileSync, readFileSync } from 'node:fs';
4
- import { describe, expect } from 'vitest';
5
- import { test as originalTest } from '../test_utils/fixtures';
6
- const CONTEXT_FILE = join(tmpdir(), `neon_${Date.now()}`);
7
- const test = originalTest.extend({
8
- // eslint-disable-next-line no-empty-pattern
9
- cleanupFile: async ({}, use) => {
10
- let writtenFilename;
11
- await use((name) => (writtenFilename = name));
12
- if (writtenFilename) {
13
- rmSync(writtenFilename);
14
- }
15
- },
16
- writeFile: async ({ cleanupFile }, use) => {
17
- await use((name, content) => {
18
- writeFileSync(name, JSON.stringify(content));
19
- cleanupFile(name);
20
- });
21
- },
22
- readFile: async ({ cleanupFile }, use) => {
23
- await use((name) => {
24
- const content = readFileSync(name, 'utf-8');
25
- cleanupFile(name);
26
- return content;
27
- });
28
- },
29
- });
30
- describe('set_context', () => {
31
- describe('should set the context to project', () => {
32
- test('set-context', async ({ testCliCommand, readFile }) => {
33
- await testCliCommand([
34
- 'set-context',
35
- '--project-id',
36
- 'test',
37
- '--context-file',
38
- CONTEXT_FILE,
39
- ]);
40
- expect(readFile(CONTEXT_FILE)).toMatchSnapshot();
41
- });
42
- test('list branches selecting project from the context', async ({ testCliCommand, writeFile, }) => {
43
- writeFile(CONTEXT_FILE, {
44
- projectId: 'test',
45
- });
46
- await testCliCommand([
47
- 'branches',
48
- 'list',
49
- '--context-file',
50
- CONTEXT_FILE,
51
- ]);
52
- });
53
- const overrideContextFile = join(tmpdir(), `neon_override_ctx_${Date.now()}`);
54
- test('get project id overrides context set project', async ({ testCliCommand, writeFile, }) => {
55
- writeFile(overrideContextFile, {
56
- projectId: 'new-project id',
57
- });
58
- await testCliCommand([
59
- 'project',
60
- 'get',
61
- 'project-id-123',
62
- '--context-file',
63
- overrideContextFile,
64
- ]);
65
- });
66
- test('set the branchId and projectId is from context', async ({ testCliCommand, writeFile, }) => {
67
- writeFile(overrideContextFile, {
68
- projectId: 'test',
69
- branchId: 'test_branch',
70
- });
71
- await testCliCommand([
72
- 'databases',
73
- 'list',
74
- '--context-file',
75
- overrideContextFile,
76
- ]);
77
- });
78
- test('set the branchId and projectId is from context', async ({ testCliCommand, writeFile, }) => {
79
- writeFile(overrideContextFile, {
80
- projectId: 'project-id-123',
81
- branchId: 'test_branch',
82
- });
83
- await testCliCommand([
84
- 'databases',
85
- 'list',
86
- '--project-id',
87
- 'test',
88
- '--context-file',
89
- overrideContextFile,
90
- ], {
91
- code: 1,
92
- stderr: 'ERROR: Not Found',
93
- });
94
- });
95
- });
96
- describe('should set the context to organization', () => {
97
- test('set-context', async ({ testCliCommand, readFile }) => {
98
- await testCliCommand([
99
- 'set-context',
100
- '--org-id',
101
- 'org-2',
102
- '--context-file',
103
- CONTEXT_FILE,
104
- ]);
105
- expect(readFile(CONTEXT_FILE)).toMatchSnapshot();
106
- });
107
- test('list projects selecting organization from the context', async ({ testCliCommand, writeFile, }) => {
108
- writeFile(CONTEXT_FILE, {
109
- orgId: 'org-2',
110
- });
111
- await testCliCommand([
112
- 'projects',
113
- 'list',
114
- '--context-file',
115
- CONTEXT_FILE,
116
- ]);
117
- });
118
- test('list projects with explicit org id overrides context', async ({ testCliCommand, writeFile, }) => {
119
- writeFile(CONTEXT_FILE, {
120
- orgId: 'org-2',
121
- });
122
- await testCliCommand([
123
- 'project',
124
- 'list',
125
- '--org-id',
126
- 'org-3',
127
- '--context-file',
128
- CONTEXT_FILE,
129
- ]);
130
- });
131
- test('create projects selecting organization from the context', async ({ testCliCommand, writeFile, }) => {
132
- writeFile(CONTEXT_FILE, {
133
- orgId: 'org-2',
134
- });
135
- await testCliCommand([
136
- 'projects',
137
- 'create',
138
- '--name',
139
- 'test_project',
140
- '--context-file',
141
- CONTEXT_FILE,
142
- ]);
143
- });
144
- });
145
- describe('can set the context to project and organization at the same time', () => {
146
- test('set-context', async ({ testCliCommand, readFile }) => {
147
- await testCliCommand([
148
- 'set-context',
149
- '--project-id',
150
- 'test_project',
151
- '--org-id',
152
- 'org-2',
153
- '--context-file',
154
- CONTEXT_FILE,
155
- ]);
156
- expect(readFile(CONTEXT_FILE)).toMatchSnapshot();
157
- });
158
- });
159
- });
@@ -1,69 +0,0 @@
1
- import { describe } from 'vitest';
2
- import { test } from '../test_utils/fixtures';
3
- describe('vpc-endpoints', () => {
4
- test('list org VPC endpoints', async ({ testCliCommand }) => {
5
- await testCliCommand(['vpc', 'endpoint', 'list', '--org-id', '1', '--region-id', 'test'], { mockDir: 'single_org' });
6
- });
7
- test('list org VPC endpoints implicit org', async ({ testCliCommand }) => {
8
- await testCliCommand(['vpc', 'endpoint', 'list', '--region-id', 'test'], {
9
- mockDir: 'single_org',
10
- });
11
- });
12
- test('update org VPC endpoint', async ({ testCliCommand }) => {
13
- await testCliCommand([
14
- 'vpc',
15
- 'endpoint',
16
- 'update',
17
- 'vpc-test',
18
- '--label',
19
- 'newlabel',
20
- '--region-id',
21
- 'test',
22
- ], { mockDir: 'single_org' });
23
- });
24
- test('delete org VPC endpoint', async ({ testCliCommand }) => {
25
- await testCliCommand(['vpc', 'endpoint', 'remove', 'vpc-test', '--region-id', 'test'], { mockDir: 'single_org' });
26
- });
27
- test('get org VPC endpoint status', async ({ testCliCommand }) => {
28
- await testCliCommand(['vpc', 'endpoint', 'status', 'vpc-test', '--region-id', 'test'], { mockDir: 'single_org' });
29
- });
30
- test('set org VPC endpoint in azure', async ({ testCliCommand }) => {
31
- await testCliCommand([
32
- 'vpc',
33
- 'endpoint',
34
- 'update',
35
- 'vpc-test',
36
- '--label',
37
- 'newlabel',
38
- '--region-id',
39
- 'azure-test',
40
- ], {
41
- mockDir: 'single_org',
42
- stderr: 'INFO: VPC endpoint configuration is not supported for Azure regions',
43
- });
44
- });
45
- test('list project VPC endpoint restrictions', async ({ testCliCommand }) => {
46
- await testCliCommand([
47
- 'vpc',
48
- 'project',
49
- 'list',
50
- '--region-id',
51
- 'test',
52
- '--project-id',
53
- 'test-project-123456',
54
- ], { mockDir: 'single_org' });
55
- });
56
- test('list project VPC endpoint restrictions with implicit project', async ({ testCliCommand, }) => {
57
- await testCliCommand(['vpc', 'project', 'list', '--region-id', 'test'], {
58
- mockDir: 'single_org',
59
- });
60
- });
61
- test('set project VPC endpoint restrictions', async ({ testCliCommand }) => {
62
- await testCliCommand(['vpc', 'project', 'update', 'vpc-test', '--label', 'newlabel'], { mockDir: 'single_org' });
63
- });
64
- test('delete project VPC endpoint restrictions', async ({ testCliCommand, }) => {
65
- await testCliCommand(['vpc', 'project', 'remove', 'vpc-test'], {
66
- mockDir: 'single_org',
67
- });
68
- });
69
- });
package/context.test.js DELETED
@@ -1,119 +0,0 @@
1
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { afterEach, beforeEach, describe, expect, test } from 'vitest';
5
- import { applyContext, currentContextFile, ensureGitignored, } from './context.js';
6
- describe('currentContextFile', () => {
7
- let workspace;
8
- beforeEach(() => {
9
- workspace = mkdtempSync(join(tmpdir(), 'neonctl-ctx-'));
10
- });
11
- afterEach(() => {
12
- rmSync(workspace, { recursive: true, force: true });
13
- });
14
- test('defaults to <cwd>/.neon when no .neon exists anywhere upward', () => {
15
- const sub = join(workspace, 'sub');
16
- mkdirSync(sub);
17
- expect(currentContextFile(sub)).toBe(join(sub, '.neon'));
18
- });
19
- test('walks up to an existing .neon in a parent directory', () => {
20
- writeFileSync(join(workspace, '.neon'), JSON.stringify({ projectId: 'parent-project' }));
21
- const sub = join(workspace, 'nested', 'deeper');
22
- mkdirSync(sub, { recursive: true });
23
- expect(currentContextFile(sub)).toBe(join(workspace, '.neon'));
24
- });
25
- test('does NOT walk up for unrelated project markers (package.json, .git)', () => {
26
- // Regression: previously `currentContextFile` treated `package.json` and
27
- // `.git` as project markers and walked up to them, which made
28
- // `neonctl link` from a fresh sub-directory inside an existing repo land
29
- // its `.neon` at the parent repo's root instead of the cwd.
30
- writeFileSync(join(workspace, 'package.json'), '{}');
31
- mkdirSync(join(workspace, '.git'));
32
- const sub = join(workspace, 'fresh-sub');
33
- mkdirSync(sub);
34
- expect(currentContextFile(sub)).toBe(join(sub, '.neon'));
35
- });
36
- });
37
- describe('ensureGitignored', () => {
38
- let workspace;
39
- beforeEach(() => {
40
- workspace = mkdtempSync(join(tmpdir(), 'neonctl-gi-'));
41
- });
42
- afterEach(() => {
43
- rmSync(workspace, { recursive: true, force: true });
44
- });
45
- test('creates a .gitignore listing .neon when none exists', () => {
46
- const contextFile = join(workspace, '.neon');
47
- ensureGitignored(contextFile);
48
- const gitignore = readFileSync(join(workspace, '.gitignore'), 'utf-8');
49
- expect(gitignore).toBe('.neon\n');
50
- });
51
- test('appends .neon to an existing .gitignore that does not have it', () => {
52
- const gi = join(workspace, '.gitignore');
53
- writeFileSync(gi, 'node_modules\ndist\n');
54
- ensureGitignored(join(workspace, '.neon'));
55
- expect(readFileSync(gi, 'utf-8')).toBe('node_modules\ndist\n.neon\n');
56
- });
57
- test('does not duplicate .neon when already present', () => {
58
- const gi = join(workspace, '.gitignore');
59
- writeFileSync(gi, 'node_modules\n.neon\ndist\n');
60
- ensureGitignored(join(workspace, '.neon'));
61
- expect(readFileSync(gi, 'utf-8')).toBe('node_modules\n.neon\ndist\n');
62
- });
63
- test('tolerates a .gitignore that has no trailing newline', () => {
64
- const gi = join(workspace, '.gitignore');
65
- writeFileSync(gi, 'node_modules');
66
- ensureGitignored(join(workspace, '.neon'));
67
- expect(readFileSync(gi, 'utf-8')).toBe('node_modules\n.neon\n');
68
- });
69
- test('treats surrounding whitespace as part of the line', () => {
70
- const gi = join(workspace, '.gitignore');
71
- // Trailing spaces around the entry should still count as a match.
72
- writeFileSync(gi, ' .neon \n');
73
- ensureGitignored(join(workspace, '.neon'));
74
- expect(readFileSync(gi, 'utf-8')).toBe(' .neon \n');
75
- });
76
- test('does NOT match partial entries like *.neon or foo/.neon', () => {
77
- const gi = join(workspace, '.gitignore');
78
- writeFileSync(gi, '*.neon\nfoo/.neon\n');
79
- ensureGitignored(join(workspace, '.neon'));
80
- expect(readFileSync(gi, 'utf-8')).toBe('*.neon\nfoo/.neon\n.neon\n');
81
- });
82
- });
83
- describe('applyContext', () => {
84
- let workspace;
85
- beforeEach(() => {
86
- workspace = mkdtempSync(join(tmpdir(), 'neonctl-apply-'));
87
- });
88
- afterEach(() => {
89
- rmSync(workspace, { recursive: true, force: true });
90
- });
91
- test('scaffolds .gitignore only when the context file is created', () => {
92
- const file = join(workspace, '.neon');
93
- applyContext(file, {
94
- orgId: 'org-x',
95
- projectId: 'proj-y',
96
- branchId: 'br-z',
97
- });
98
- expect(JSON.parse(readFileSync(file, 'utf-8'))).toEqual({
99
- orgId: 'org-x',
100
- projectId: 'proj-y',
101
- branchId: 'br-z',
102
- });
103
- expect(readFileSync(join(workspace, '.gitignore'), 'utf-8')).toBe('.neon\n');
104
- });
105
- test('does NOT re-add .neon to .gitignore on updates to an existing file', () => {
106
- const file = join(workspace, '.neon');
107
- // First write creates the file and scaffolds .gitignore.
108
- applyContext(file, { projectId: 'proj-y', branchId: 'br-1' });
109
- // The user deliberately un-ignores .neon (e.g. to commit shared context).
110
- writeFileSync(join(workspace, '.gitignore'), 'node_modules\n');
111
- // A subsequent update must NOT re-add the entry.
112
- applyContext(file, { projectId: 'proj-y', branchId: 'br-2' });
113
- expect(JSON.parse(readFileSync(file, 'utf-8'))).toEqual({
114
- projectId: 'proj-y',
115
- branchId: 'br-2',
116
- });
117
- expect(readFileSync(join(workspace, '.gitignore'), 'utf-8')).toBe('node_modules\n');
118
- });
119
- });
package/env.test.js DELETED
@@ -1,55 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { getGithubEnvVars } from './env';
3
- describe('getGithubEnvVars', () => {
4
- it('success all keys', () => {
5
- const env = {
6
- GITHUB_ACTION_PATH: '1',
7
- GITHUB_REPOSITORY: '2',
8
- GITHUB_RUN_ID: '3',
9
- GITHUB_RUN_NUMBER: '4',
10
- GITHUB_SERVER_URL: '5',
11
- GITHUB_WORKFLOW_REF: '6',
12
- RUNNER_ARCH: '7',
13
- RUNNER_ENVIRONMENT: '8',
14
- RUNNER_OS: '9',
15
- unrelated: 'unrelated',
16
- };
17
- const ret = {
18
- GITHUB_ACTION_PATH: '1',
19
- GITHUB_REPOSITORY: '2',
20
- GITHUB_RUN_ID: '3',
21
- GITHUB_RUN_NUMBER: '4',
22
- GITHUB_SERVER_URL: '5',
23
- GITHUB_WORKFLOW_REF: '6',
24
- RUNNER_ARCH: '7',
25
- RUNNER_ENVIRONMENT: '8',
26
- RUNNER_OS: '9',
27
- };
28
- expect(getGithubEnvVars(env)).toEqual(ret);
29
- });
30
- it('empty all keys', () => {
31
- expect(getGithubEnvVars({})).toEqual({});
32
- });
33
- it('action path', () => {
34
- expect(getGithubEnvVars({
35
- GITHUB_ACTION_PATH: '/home/runner/work/_actions/neondatabase/create-branch-action/v5',
36
- })).toEqual({
37
- GITHUB_ACTION_PATH: 'neondatabase/create-branch-action/v5',
38
- });
39
- expect(getGithubEnvVars({
40
- GITHUB_ACTION_PATH: '/home/runner/actions-runner/_work/actions/neondatabase/create-branch-action/v5',
41
- })).toEqual({
42
- GITHUB_ACTION_PATH: 'neondatabase/create-branch-action/v5',
43
- });
44
- expect(getGithubEnvVars({
45
- GITHUB_ACTION_PATH: 'C:\\b\\_actions\\neondatabase\\create-branch-action\\v5',
46
- })).toEqual({
47
- GITHUB_ACTION_PATH: 'C:\\b\\_actions\\neondatabase\\create-branch-action\\v5',
48
- });
49
- expect(getGithubEnvVars({
50
- GITHUB_ACTION_PATH: '/home/runner/work/app/app/./.github/actions/custom-action',
51
- })).toEqual({
52
- GITHUB_ACTION_PATH: 'custom-action',
53
- });
54
- });
55
- });
@@ -1,32 +0,0 @@
1
- import { test, describe, expect } from 'vitest';
2
- import { looksLikeBranchId, looksLikeLSN, looksLikeTimestamp } from './formats';
3
- describe('branch formats', () => {
4
- test('branch name', () => {
5
- expect(looksLikeBranchId('master')).toBe(false);
6
- });
7
- test('initial short', () => {
8
- expect(looksLikeBranchId('br-flower-sunshine-123456')).toBe(true);
9
- });
10
- test('update 1, longer version', () => {
11
- expect(looksLikeBranchId('br-flower-sunshine-12345678')).toBe(true);
12
- });
13
- test('update 2, includes region', () => {
14
- expect(looksLikeBranchId('br-bold-recipe-a13oexw7')).toBe(true);
15
- });
16
- });
17
- describe('timestamp formats', () => {
18
- test('valid', () => {
19
- expect(looksLikeTimestamp('2021-03-13T19:47:33.000Z')).toBe(true);
20
- });
21
- test('invalid', () => {
22
- expect(looksLikeTimestamp('branch_name')).toBe(false);
23
- });
24
- });
25
- describe('LSN formats', () => {
26
- test('valid', () => {
27
- expect(looksLikeLSN('0/1F56000')).toBe(true);
28
- });
29
- test('invalid', () => {
30
- expect(looksLikeLSN('branch_name')).toBe(false);
31
- });
32
- });
package/writer.test.js DELETED
@@ -1,104 +0,0 @@
1
- import { PassThrough } from 'node:stream';
2
- import { describe, it, expect } from 'vitest';
3
- import { writer } from './writer.js';
4
- const getMockWritable = () => {
5
- const chunks = [];
6
- const stream = new PassThrough();
7
- stream.on('data', (chunk) => {
8
- chunks.push(chunk.toString());
9
- });
10
- return {
11
- stream,
12
- getData: () => {
13
- return chunks.join('');
14
- },
15
- };
16
- };
17
- describe('writer', () => {
18
- describe('outputs yaml', () => {
19
- it('outputs single data', () => {
20
- const { stream, getData } = getMockWritable();
21
- const out = writer({ output: 'yaml', out: stream });
22
- out.end({ foo: 'bar' }, { fields: ['foo'] });
23
- expect(getData()).toMatchSnapshot();
24
- });
25
- it('outputs single data with title', () => {
26
- const { stream, getData } = getMockWritable();
27
- const out = writer({ output: 'yaml', out: stream });
28
- out.end({ foo: 'bar' }, { fields: ['foo'], title: 'baz' });
29
- expect(getData()).toMatchSnapshot();
30
- });
31
- it('outputs multiple data', () => {
32
- const { stream, getData } = getMockWritable();
33
- const out = writer({ output: 'yaml', out: stream });
34
- out
35
- .write({ foo: 'bar' }, { fields: ['foo'], title: 'T1' })
36
- .write({ baz: 'xyz' }, { fields: ['baz'], title: 'T2' })
37
- .end();
38
- expect(getData()).toMatchSnapshot();
39
- });
40
- });
41
- describe('outputs json', () => {
42
- it('outputs single data', () => {
43
- const { stream, getData } = getMockWritable();
44
- const out = writer({ output: 'json', out: stream });
45
- out.end({ foo: 'bar' }, { fields: ['foo'] });
46
- expect(getData()).toMatchSnapshot();
47
- });
48
- it('outputs single data with title', () => {
49
- const { stream, getData } = getMockWritable();
50
- const out = writer({ output: 'json', out: stream });
51
- out.end({ foo: 'bar' }, { fields: ['foo'], title: 'baz' });
52
- expect(getData()).toMatchSnapshot();
53
- });
54
- it('outputs multiple data', () => {
55
- const { stream, getData } = getMockWritable();
56
- const out = writer({ output: 'json', out: stream });
57
- out
58
- .write({ foo: 'bar' }, { fields: ['foo'], title: 'T1' })
59
- .write({ baz: 'xyz' }, { fields: ['baz'], title: 'T2' })
60
- .end();
61
- expect(getData()).toMatchSnapshot();
62
- });
63
- });
64
- describe('outputs table', () => {
65
- it('outputs single data', () => {
66
- const { stream, getData } = getMockWritable();
67
- const out = writer({ output: 'table', out: stream });
68
- out.end({ foo: 'bar', extra: 'extra' }, { fields: ['foo'] });
69
- expect(getData()).toMatchSnapshot();
70
- });
71
- it('outputs single data with title', () => {
72
- const { stream, getData } = getMockWritable();
73
- const out = writer({ output: 'table', out: stream });
74
- out.end({ foo: 'bar', extra: 'extra' }, { fields: ['foo'], title: 'baz' });
75
- expect(getData()).toMatchSnapshot();
76
- });
77
- it('outputs multiple data', () => {
78
- const { stream, getData } = getMockWritable();
79
- const out = writer({ output: 'table', out: stream });
80
- out
81
- .write({ foo: 'bar', extra: 'extra' }, { fields: ['foo'], title: 'T1' })
82
- .write({ baz: 'xyz', extra: 'extra' }, { fields: ['baz'], title: 'T2' })
83
- .end();
84
- expect(getData()).toMatchSnapshot();
85
- });
86
- it('outputs table with custom renderer', () => {
87
- const { stream, getData } = getMockWritable();
88
- const out = writer({
89
- output: 'table',
90
- out: stream,
91
- });
92
- out
93
- .write({ foo: 'bar' }, {
94
- fields: ['foo'],
95
- title: 'T1',
96
- renderColumns: {
97
- foo: ({ foo }) => `Here is: ${foo}`,
98
- },
99
- })
100
- .end();
101
- expect(getData()).toMatchSnapshot();
102
- });
103
- });
104
- });