heroku 11.2.0-beta.0 → 11.2.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.
- package/CHANGELOG.md +5 -1
- package/dist/commands/addons/index.d.ts +1 -0
- package/dist/commands/addons/index.js +13 -13
- package/dist/commands/data/pg/credentials/index.d.ts +1 -0
- package/dist/commands/data/pg/credentials/index.js +3 -3
- package/dist/commands/domains/index.d.ts +1 -0
- package/dist/commands/domains/index.js +3 -1
- package/dist/commands/pg/credentials.d.ts +1 -0
- package/dist/commands/pg/credentials.js +3 -3
- package/dist/commands/ps/index.d.ts +1 -0
- package/dist/commands/ps/index.js +5 -5
- package/dist/lib/analytics-telemetry/telemetry-worker.js +17 -9
- package/dist/lib/run/colorize.js +5 -5
- package/dist/lib/utils/tableUtils.d.ts +4 -0
- package/dist/lib/utils/tableUtils.js +6 -0
- package/npm-shrinkwrap.json +237 -237
- package/oclif.manifest.json +2179 -2149
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,17 +4,20 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
## [11.2.0
|
|
7
|
+
## [11.2.0](https://github.com/heroku/cli/compare/v11.1.1...v11.2.0) (2026-04-08)
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
### Features
|
|
11
11
|
|
|
12
12
|
* adding --start-cmd flag to heroku local when no Procfile is present ([#3638](https://github.com/heroku/cli/issues/3638)) ([b9b8fed](https://github.com/heroku/cli/commit/b9b8fed8f44ad88946edc4141ec1fe41f157baac))
|
|
13
|
+
* include a --no-wrap flag for table displays ([#3613](https://github.com/heroku/cli/issues/3613)) ([1d27c09](https://github.com/heroku/cli/commit/1d27c09f3973c81bb610583c3afe418ff0c867a6))
|
|
13
14
|
* update color usage, telemetry activation logic, and command/util dependencies ([#3646](https://github.com/heroku/cli/issues/3646)) ([ede6655](https://github.com/heroku/cli/commit/ede665557ca3d387e3e57f5a438cd7ab7c27b1b3))
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
### Bug Fixes
|
|
17
18
|
|
|
19
|
+
* flaky apps:diff tests ([#3649](https://github.com/heroku/cli/issues/3649)) ([8c4f8c3](https://github.com/heroku/cli/commit/8c4f8c3e5c99f688cbbefcf91a44ed234ba6c65b))
|
|
20
|
+
* improve telemetry worker stderr cleanup ([#3648](https://github.com/heroku/cli/issues/3648)) ([150e74a](https://github.com/heroku/cli/commit/150e74abe77b7c51b6b9ea84c8e246fe3165c6b5))
|
|
18
21
|
* procfile comment parsing ([#3641](https://github.com/heroku/cli/issues/3641)) ([aae3751](https://github.com/heroku/cli/commit/aae37512b54bdcf2b832429254f0d2c0fe1f42d3))
|
|
19
22
|
|
|
20
23
|
|
|
@@ -26,6 +29,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
|
|
|
26
29
|
### Tests
|
|
27
30
|
|
|
28
31
|
* this fixes the mocking difference causing flappy tests and adds chore to PR release title ([#3640](https://github.com/heroku/cli/issues/3640)) ([32920f9](https://github.com/heroku/cli/commit/32920f9600cc6b06815aa7db532dd8bb352d90db))
|
|
32
|
+
* use Sinon stubs; parallel slug checksums ([#3650](https://github.com/heroku/cli/issues/3650)) ([73e4990](https://github.com/heroku/cli/commit/73e4990222d4a1b1dfec5fc64eae0c25f811c93c))
|
|
29
33
|
|
|
30
34
|
## [11.1.1](https://github.com/heroku/cli/compare/v11.1.0...v11.1.1) (2026-04-01)
|
|
31
35
|
|
|
@@ -7,6 +7,7 @@ export default class Addons extends Command {
|
|
|
7
7
|
all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
'no-wrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
remote: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
};
|
|
12
13
|
static topic: string;
|
|
@@ -3,6 +3,7 @@ import { color, hux } from '@heroku/heroku-cli-util';
|
|
|
3
3
|
import { ux } from '@oclif/core/ux';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
import { formatPrice, formatState, grandfatheredPrice } from '../../lib/addons/util.js';
|
|
6
|
+
import { huxTableNoWrapOptions } from '../../lib/utils/tableUtils.js';
|
|
6
7
|
const topic = 'addons';
|
|
7
8
|
export default class Addons extends Command {
|
|
8
9
|
static description = `Lists your add-ons and attachments.
|
|
@@ -20,6 +21,7 @@ export default class Addons extends Command {
|
|
|
20
21
|
all: flags.boolean({ char: 'A', description: 'show add-ons and attachments for all accessible apps' }),
|
|
21
22
|
app: flags.app(),
|
|
22
23
|
json: flags.boolean({ description: 'return add-ons in json format' }),
|
|
24
|
+
'no-wrap': flags.noWrap(),
|
|
23
25
|
remote: flags.remote(),
|
|
24
26
|
};
|
|
25
27
|
static topic = topic;
|
|
@@ -32,14 +34,14 @@ export default class Addons extends Command {
|
|
|
32
34
|
if (json)
|
|
33
35
|
displayJSON(addons);
|
|
34
36
|
else
|
|
35
|
-
displayForApp(app, addons);
|
|
37
|
+
displayForApp(app, addons, flags['no-wrap']);
|
|
36
38
|
}
|
|
37
39
|
else {
|
|
38
40
|
const addons = await addonGetter(this.heroku);
|
|
39
41
|
if (json)
|
|
40
42
|
displayJSON(addons);
|
|
41
43
|
else
|
|
42
|
-
displayAll(addons);
|
|
44
|
+
displayAll(addons, flags['no-wrap']);
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -111,7 +113,7 @@ async function addonGetter(api, app) {
|
|
|
111
113
|
});
|
|
112
114
|
return addons;
|
|
113
115
|
}
|
|
114
|
-
function displayAll(addons) {
|
|
116
|
+
function displayAll(addons, noWrap = false) {
|
|
115
117
|
addons = _.sortBy(addons, 'app.name', 'plan.name', 'addon.name');
|
|
116
118
|
if (addons.length === 0) {
|
|
117
119
|
ux.stdout('No add-ons.');
|
|
@@ -165,12 +167,10 @@ function displayAll(addons) {
|
|
|
165
167
|
return result;
|
|
166
168
|
},
|
|
167
169
|
},
|
|
168
|
-
},
|
|
169
|
-
overflow: 'wrap',
|
|
170
|
-
});
|
|
170
|
+
}, huxTableNoWrapOptions(noWrap));
|
|
171
171
|
/* eslint-enable perfectionist/sort-objects */
|
|
172
172
|
}
|
|
173
|
-
function displayForApp(app, addons) {
|
|
173
|
+
function displayForApp(app, addons, noWrap = false) {
|
|
174
174
|
if (addons.length === 0) {
|
|
175
175
|
ux.stdout(`No add-ons for app ${app}.`);
|
|
176
176
|
return;
|
|
@@ -184,13 +184,15 @@ function displayForApp(app, addons) {
|
|
|
184
184
|
}
|
|
185
185
|
const addonLine = `${service} (${name})`;
|
|
186
186
|
const atts = _.sortBy(addon.attachments, isForeignApp, 'app.name', 'name');
|
|
187
|
-
// render each attachment under the add-on
|
|
188
187
|
const attLines = atts.map((attachment, idx) => {
|
|
189
188
|
const isLast = (idx === addon.attachments.length - 1);
|
|
190
189
|
return renderAttachment(attachment, app, isLast);
|
|
191
190
|
});
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
const lines = [addonLine, ...attLines];
|
|
192
|
+
if (noWrap) {
|
|
193
|
+
return lines.join(' ');
|
|
194
|
+
}
|
|
195
|
+
return `${lines.join('\n')}\n`;
|
|
194
196
|
}
|
|
195
197
|
addons = _.sortBy(addons, isForeignApp, 'plan.name', 'name');
|
|
196
198
|
ux.stdout();
|
|
@@ -221,9 +223,7 @@ function displayForApp(app, addons) {
|
|
|
221
223
|
State: {
|
|
222
224
|
get: ({ state }) => formatState(state || ''),
|
|
223
225
|
},
|
|
224
|
-
},
|
|
225
|
-
overflow: 'wrap',
|
|
226
|
-
});
|
|
226
|
+
}, huxTableNoWrapOptions(noWrap));
|
|
227
227
|
ux.stdout(`The table above shows add-ons and the attachments to the current app (${color.app(app)}) or other apps.\n `);
|
|
228
228
|
}
|
|
229
229
|
function displayJSON(addons) {
|
|
@@ -7,6 +7,7 @@ export default class DataPgCredentialsIndex extends BaseCommand {
|
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
9
|
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'no-wrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
remote: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
@@ -4,6 +4,7 @@ import { Args, ux } from '@oclif/core';
|
|
|
4
4
|
import BaseCommand from '../../../../lib/data/baseCommand.js';
|
|
5
5
|
import { sortByOwnerAndName } from '../../../../lib/data/credentialUtils.js';
|
|
6
6
|
import { presentCredentialAttachments } from '../../../../lib/pg/util.js';
|
|
7
|
+
import { huxTableNoWrapOptions } from '../../../../lib/utils/tableUtils.js';
|
|
7
8
|
export default class DataPgCredentialsIndex extends BaseCommand {
|
|
8
9
|
static args = {
|
|
9
10
|
database: Args.string({
|
|
@@ -17,6 +18,7 @@ export default class DataPgCredentialsIndex extends BaseCommand {
|
|
|
17
18
|
];
|
|
18
19
|
static flags = {
|
|
19
20
|
app: Flags.app({ required: true }),
|
|
21
|
+
'no-wrap': Flags.noWrap(),
|
|
20
22
|
remote: Flags.remote(),
|
|
21
23
|
};
|
|
22
24
|
async run() {
|
|
@@ -55,8 +57,6 @@ export default class DataPgCredentialsIndex extends BaseCommand {
|
|
|
55
57
|
State: {
|
|
56
58
|
get: cred => cred.state,
|
|
57
59
|
},
|
|
58
|
-
},
|
|
59
|
-
overflow: 'wrap',
|
|
60
|
-
});
|
|
60
|
+
}, huxTableNoWrapOptions(flags['no-wrap']));
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -10,6 +10,7 @@ export default class DomainsIndex extends Command {
|
|
|
10
10
|
extended: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
11
|
filter: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'no-wrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
remote: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
15
|
sort: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
16
|
};
|
|
@@ -5,6 +5,7 @@ import { orderBy } from 'natural-orderby';
|
|
|
5
5
|
import Uri from 'urijs';
|
|
6
6
|
import parseKeyValue from '../../lib/utils/keyValueParser.js';
|
|
7
7
|
import { paginateRequest } from '../../lib/utils/paginator.js';
|
|
8
|
+
import { huxTableNoWrapOptions } from '../../lib/utils/tableUtils.js';
|
|
8
9
|
export default class DomainsIndex extends Command {
|
|
9
10
|
static description = 'list domains for an app';
|
|
10
11
|
static examples = [`${color.command('heroku domains')}
|
|
@@ -25,6 +26,7 @@ www.example.com CNAME www.example.herokudns.com`];
|
|
|
25
26
|
extended: flags.boolean({ char: 'x', description: 'show extra columns' }),
|
|
26
27
|
filter: flags.string({ description: 'filter property by partial string matching, ex: name=foo' }),
|
|
27
28
|
json: flags.boolean({ char: 'j', description: 'output in json format' }),
|
|
29
|
+
'no-wrap': flags.noWrap(),
|
|
28
30
|
remote: flags.remote(),
|
|
29
31
|
sort: flags.string({ description: 'sort by property' }),
|
|
30
32
|
};
|
|
@@ -182,7 +184,7 @@ www.example.com CNAME www.example.herokudns.com`];
|
|
|
182
184
|
}
|
|
183
185
|
else {
|
|
184
186
|
hux.table(customDomains, tableConfig, {
|
|
185
|
-
|
|
187
|
+
...huxTableNoWrapOptions(flags['no-wrap']),
|
|
186
188
|
sort: flags.sort ? { [sortProperty]: 'asc' } : undefined,
|
|
187
189
|
});
|
|
188
190
|
}
|
|
@@ -7,6 +7,7 @@ export default class Credentials extends Command {
|
|
|
7
7
|
static description: string;
|
|
8
8
|
static flags: {
|
|
9
9
|
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'no-wrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
remote: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
};
|
|
12
13
|
static topic: string;
|
|
@@ -2,6 +2,7 @@ import { hux, utils } from '@heroku/heroku-cli-util';
|
|
|
2
2
|
import { Command, flags } from '@heroku-cli/command';
|
|
3
3
|
import { Args } from '@oclif/core';
|
|
4
4
|
import { presentCredentialAttachments } from '../../lib/pg/util.js';
|
|
5
|
+
import { huxTableNoWrapOptions } from '../../lib/utils/tableUtils.js';
|
|
5
6
|
import { nls } from '../../nls.js';
|
|
6
7
|
export default class Credentials extends Command {
|
|
7
8
|
static args = {
|
|
@@ -10,6 +11,7 @@ export default class Credentials extends Command {
|
|
|
10
11
|
static description = 'show information on credentials in the database';
|
|
11
12
|
static flags = {
|
|
12
13
|
app: flags.app({ required: true }),
|
|
14
|
+
'no-wrap': flags.noWrap(),
|
|
13
15
|
remote: flags.remote(),
|
|
14
16
|
};
|
|
15
17
|
static topic = 'pg';
|
|
@@ -47,9 +49,7 @@ export default class Credentials extends Command {
|
|
|
47
49
|
State: {
|
|
48
50
|
get: cred => cred.state,
|
|
49
51
|
},
|
|
50
|
-
},
|
|
51
|
-
overflow: 'wrap',
|
|
52
|
-
});
|
|
52
|
+
}, huxTableNoWrapOptions(flags['no-wrap']));
|
|
53
53
|
}
|
|
54
54
|
sortByDefaultAndName(credentials) {
|
|
55
55
|
return credentials.sort((a, b) => {
|
|
@@ -6,6 +6,7 @@ export default class Index extends Command {
|
|
|
6
6
|
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
7
|
extended: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
'no-wrap': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
10
|
remote: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
};
|
|
11
12
|
static strict: boolean;
|
|
@@ -3,6 +3,7 @@ import { color, hux } from '@heroku/heroku-cli-util';
|
|
|
3
3
|
import { ux } from '@oclif/core/ux';
|
|
4
4
|
import tsheredoc from 'tsheredoc';
|
|
5
5
|
import { ago } from '../../lib/time.js';
|
|
6
|
+
import { huxTableNoWrapOptions } from '../../lib/utils/tableUtils.js';
|
|
6
7
|
const heredoc = tsheredoc.default;
|
|
7
8
|
export default class Index extends Command {
|
|
8
9
|
static description = 'list dynos for an app';
|
|
@@ -21,6 +22,7 @@ export default class Index extends Command {
|
|
|
21
22
|
app: flags.app({ required: true }),
|
|
22
23
|
extended: flags.boolean({ char: 'x', hidden: true }),
|
|
23
24
|
json: flags.boolean({ description: 'display as json' }),
|
|
25
|
+
'no-wrap': flags.noWrap(),
|
|
24
26
|
remote: flags.remote(),
|
|
25
27
|
};
|
|
26
28
|
static strict = false;
|
|
@@ -62,7 +64,7 @@ export default class Index extends Command {
|
|
|
62
64
|
if (json)
|
|
63
65
|
hux.styledJSON(selectedDynos);
|
|
64
66
|
else if (extended)
|
|
65
|
-
printExtended(selectedDynos);
|
|
67
|
+
printExtended(selectedDynos, flags['no-wrap']);
|
|
66
68
|
else {
|
|
67
69
|
await printAccountQuota(this.heroku, appInfo, accountInfo);
|
|
68
70
|
if (selectedDynos.length === 0)
|
|
@@ -159,7 +161,7 @@ function printDynos(dynos) {
|
|
|
159
161
|
ux.stdout();
|
|
160
162
|
});
|
|
161
163
|
}
|
|
162
|
-
function printExtended(dynos) {
|
|
164
|
+
function printExtended(dynos, noWrap = false) {
|
|
163
165
|
const sortedDynos = dynos.sort(byProcessTypeAndNumber);
|
|
164
166
|
/* eslint-disable perfectionist/sort-objects */
|
|
165
167
|
hux.table(sortedDynos, {
|
|
@@ -177,9 +179,7 @@ function printExtended(dynos) {
|
|
|
177
179
|
Command: { get: (dyno) => truncate(dyno.command) },
|
|
178
180
|
Route: { get: (dyno) => dyno.extended?.route ?? '' },
|
|
179
181
|
Size: { get: (dyno) => dyno.size },
|
|
180
|
-
},
|
|
181
|
-
overflow: 'wrap',
|
|
182
|
-
});
|
|
182
|
+
}, huxTableNoWrapOptions(noWrap));
|
|
183
183
|
/* eslint-enable perfectionist/sort-objects */
|
|
184
184
|
}
|
|
185
185
|
function truncate(s) {
|
|
@@ -10,21 +10,29 @@ import { telemetryDebug } from './telemetry-utils.js';
|
|
|
10
10
|
const MAX_WORKER_LIFETIME_MS = 10000;
|
|
11
11
|
/**
|
|
12
12
|
* Close stderr before exiting to avoid keeping parent process alive
|
|
13
|
-
* This is
|
|
13
|
+
* This is only necessary when stderr is inherited in DEBUG mode
|
|
14
14
|
*/
|
|
15
15
|
function exitWorker(code) {
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
setImmediate(() => {
|
|
16
|
+
// Close stderr if it was inherited (DEBUG mode)
|
|
17
|
+
if (process.env.DEBUG) {
|
|
19
18
|
try {
|
|
20
|
-
//
|
|
21
|
-
|
|
19
|
+
// End stderr gracefully, flushing all pending writes
|
|
20
|
+
// This properly releases the file descriptor reference to parent
|
|
21
|
+
process.stderr.end(() => {
|
|
22
|
+
process.exit(code);
|
|
23
|
+
});
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
+
finally {
|
|
26
|
+
// Fallback: ensure we exit even if end() fails or callback never fires
|
|
27
|
+
// Use setImmediate to give the end() callback a chance to run first
|
|
28
|
+
setImmediate(() => {
|
|
29
|
+
process.exit(code);
|
|
30
|
+
});
|
|
25
31
|
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
26
34
|
process.exit(code);
|
|
27
|
-
}
|
|
35
|
+
}
|
|
28
36
|
}
|
|
29
37
|
setTimeout(() => {
|
|
30
38
|
telemetryDebug('Worker timeout reached after %dms, force exiting', MAX_WORKER_LIFETIME_MS);
|
package/dist/lib/run/colorize.js
CHANGED
|
@@ -6,11 +6,11 @@ export const COLORS = [
|
|
|
6
6
|
s => color.cyan(s),
|
|
7
7
|
s => color.magenta(s),
|
|
8
8
|
s => color.blue(s),
|
|
9
|
-
s => color.
|
|
10
|
-
s => color.
|
|
11
|
-
s => color.
|
|
12
|
-
s => color.
|
|
13
|
-
s => color.
|
|
9
|
+
s => color.info(s),
|
|
10
|
+
s => color.name(s),
|
|
11
|
+
s => color.addon(s),
|
|
12
|
+
s => color.pipeline(s),
|
|
13
|
+
s => color.warning(s),
|
|
14
14
|
];
|
|
15
15
|
const assignedColors = {};
|
|
16
16
|
let isInitialized = false;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export declare function huxTableNoWrapOptions(noWrap: boolean): {
|
|
2
|
+
maxWidth: 'none' | undefined;
|
|
3
|
+
overflow: 'truncate' | 'wrap';
|
|
4
|
+
};
|
|
1
5
|
export declare const constructSortFilterTableOptions: (flags: Record<string, string>, tableColumns: Record<string, any>) => Record<string, any>;
|
|
2
6
|
export declare const outputCSV: (tableData: Record<string, any>[], tableColumns: Record<string, any>) => void;
|
|
3
7
|
export declare const constructTableColumns: (allTableColumns: Record<string, any>, baseColumnNames: string[], extended: boolean, columns?: string) => Record<string, any>;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { ux } from '@oclif/core/ux';
|
|
2
2
|
import parseKeyValue from './keyValueParser.js';
|
|
3
|
+
export function huxTableNoWrapOptions(noWrap) {
|
|
4
|
+
return {
|
|
5
|
+
maxWidth: noWrap ? 'none' : undefined,
|
|
6
|
+
overflow: noWrap ? 'truncate' : 'wrap',
|
|
7
|
+
};
|
|
8
|
+
}
|
|
3
9
|
export const constructSortFilterTableOptions = (flags, tableColumns) => {
|
|
4
10
|
const { filter, sort } = flags;
|
|
5
11
|
const columnNames = new Set(Object.keys(tableColumns).map(key => key.toLowerCase()));
|