@karmaniverous/get-dotenv 5.0.0 → 5.1.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/dist/cliHost.cjs CHANGED
@@ -3,9 +3,9 @@
3
3
  var commander = require('commander');
4
4
  var fs = require('fs-extra');
5
5
  var packageDirectory = require('package-directory');
6
+ var url = require('url');
6
7
  var path = require('path');
7
8
  var zod = require('zod');
8
- var url = require('url');
9
9
  var YAML = require('yaml');
10
10
  var nanoid = require('nanoid');
11
11
  var dotenv = require('dotenv');
@@ -984,6 +984,8 @@ const computeContext = async (customOptions, plugins, hostMetaUrl) => {
984
984
 
985
985
  const HOST_META_URL = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cliHost.cjs', document.baseURI).href));
986
986
  const CTX_SYMBOL = Symbol('GetDotenvCli.ctx');
987
+ const OPTS_SYMBOL = Symbol('GetDotenvCli.options');
988
+ const HELP_HEADER_SYMBOL = Symbol('GetDotenvCli.helpHeader');
987
989
  /**
988
990
  * Plugin-first CLI host for get-dotenv. Extends Commander.Command.
989
991
  *
@@ -1000,15 +1002,33 @@ class GetDotenvCli extends commander.Command {
1000
1002
  _plugins = [];
1001
1003
  /** One-time installation guard */
1002
1004
  _installed = false;
1005
+ /** Optional header line to prepend in help output */
1006
+ [HELP_HEADER_SYMBOL];
1003
1007
  constructor(alias = 'getdotenv') {
1004
1008
  super(alias);
1005
1009
  // Ensure subcommands that use passThroughOptions can be attached safely.
1006
1010
  // Commander requires parent commands to enable positional options when a
1007
1011
  // child uses passThroughOptions.
1008
1012
  this.enablePositionalOptions();
1013
+ // Configure grouped help: show only base options in default "Options";
1014
+ // append App/Plugin sections after default help.
1015
+ this.configureHelp({
1016
+ visibleOptions: (cmd) => {
1017
+ const all = cmd.options ??
1018
+ [];
1019
+ return all.filter((opt) => {
1020
+ const group = opt.__group;
1021
+ return group === 'base';
1022
+ });
1023
+ },
1024
+ });
1025
+ this.addHelpText('beforeAll', () => {
1026
+ const header = this[HELP_HEADER_SYMBOL];
1027
+ return header && header.length > 0 ? `${header}\n\n` : '';
1028
+ });
1029
+ this.addHelpText('afterAll', (ctx) => this.#renderOptionGroups(ctx.command));
1009
1030
  // Skeleton preSubcommand hook: produce a context if absent, without
1010
- // mutating process.env. The passOptions hook (when installed) will
1011
- // compute the final context using merged CLI options; keeping
1031
+ // mutating process.env. The passOptions hook (when installed) will // compute the final context using merged CLI options; keeping
1012
1032
  // loadProcess=false here avoids leaking dotenv values into the parent
1013
1033
  // process env before subcommands execute.
1014
1034
  this.hook('preSubcommand', async () => {
@@ -1040,11 +1060,96 @@ class GetDotenvCli extends commander.Command {
1040
1060
  getCtx() {
1041
1061
  return this[CTX_SYMBOL];
1042
1062
  }
1063
+ /**
1064
+ * Retrieve the merged root CLI options bag (if set by passOptions()).
1065
+ * Downstream-safe: no generics required.
1066
+ */
1067
+ getOptions() {
1068
+ return this[OPTS_SYMBOL];
1069
+ }
1070
+ /** Internal: set the merged root options bag for this run. */
1071
+ _setOptionsBag(bag) {
1072
+ this[OPTS_SYMBOL] = bag;
1073
+ }
1043
1074
  /** * Convenience helper to create a namespaced subcommand.
1044
1075
  */
1045
1076
  ns(name) {
1046
1077
  return this.command(name);
1047
1078
  }
1079
+ /**
1080
+ * Tag options added during the provided callback as 'app' for grouped help.
1081
+ * Allows downstream apps to demarcate their root-level options.
1082
+ */
1083
+ tagAppOptions(fn) {
1084
+ const root = this;
1085
+ const originalAddOption = root.addOption.bind(root);
1086
+ const originalOption = root.option.bind(root);
1087
+ const tagLatest = (cmd, group) => {
1088
+ const optsArr = cmd.options;
1089
+ if (Array.isArray(optsArr) && optsArr.length > 0) {
1090
+ const last = optsArr[optsArr.length - 1];
1091
+ last.__group = group;
1092
+ }
1093
+ };
1094
+ root.addOption = function patchedAdd(opt) {
1095
+ opt.__group = 'app';
1096
+ return originalAddOption(opt);
1097
+ };
1098
+ root.option = function patchedOption(...args) {
1099
+ const ret = originalOption(...args);
1100
+ tagLatest(this, 'app');
1101
+ return ret;
1102
+ };
1103
+ try {
1104
+ return fn(root);
1105
+ }
1106
+ finally {
1107
+ root.addOption = originalAddOption;
1108
+ root.option = originalOption;
1109
+ }
1110
+ }
1111
+ /**
1112
+ * Branding helper: set CLI name/description/version and optional help header.
1113
+ * If version is omitted and importMetaUrl is provided, attempts to read the
1114
+ * nearest package.json version (best-effort; non-fatal on failure).
1115
+ */
1116
+ async brand(args) {
1117
+ const { name, description, version, importMetaUrl, helpHeader } = args;
1118
+ if (typeof name === 'string' && name.length > 0)
1119
+ this.name(name);
1120
+ if (typeof description === 'string')
1121
+ this.description(description);
1122
+ let v = version;
1123
+ if (!v && importMetaUrl) {
1124
+ try {
1125
+ const fromUrl = url.fileURLToPath(importMetaUrl);
1126
+ const pkgDir = await packageDirectory.packageDirectory({ cwd: fromUrl });
1127
+ if (pkgDir) {
1128
+ const txt = await fs.readFile(`${pkgDir}/package.json`, 'utf-8');
1129
+ const pkg = JSON.parse(txt);
1130
+ if (pkg.version)
1131
+ v = pkg.version;
1132
+ }
1133
+ }
1134
+ catch {
1135
+ // best-effort only
1136
+ }
1137
+ }
1138
+ if (v)
1139
+ this.version(v);
1140
+ // Help header:
1141
+ // - If caller provides helpHeader, use it.
1142
+ // - Otherwise, when a version is known, default to "<name> v<version>".
1143
+ if (typeof helpHeader === 'string') {
1144
+ this[HELP_HEADER_SYMBOL] = helpHeader;
1145
+ }
1146
+ else if (v) {
1147
+ // Use the current command name (possibly overridden by 'name' above).
1148
+ const header = `${this.name()} v${v}`;
1149
+ this[HELP_HEADER_SYMBOL] = header;
1150
+ }
1151
+ return this;
1152
+ }
1048
1153
  /**
1049
1154
  * Register a plugin for installation (parent level).
1050
1155
  * Installation occurs on first resolveAndLoad() (or explicit install()).
@@ -1083,7 +1188,71 @@ class GetDotenvCli extends commander.Command {
1083
1188
  for (const p of this._plugins)
1084
1189
  await run(p);
1085
1190
  }
1191
+ // Render App/Plugin grouped options appended after default help.
1192
+ #renderOptionGroups(cmd) {
1193
+ const all = cmd.options ?? [];
1194
+ const byGroup = new Map();
1195
+ for (const o of all) {
1196
+ const opt = o;
1197
+ const g = opt.__group;
1198
+ if (!g || g === 'base')
1199
+ continue; // base handled by default help
1200
+ const rows = byGroup.get(g) ?? [];
1201
+ rows.push({
1202
+ flags: opt.flags ?? '',
1203
+ description: opt.description ?? '',
1204
+ });
1205
+ byGroup.set(g, rows);
1206
+ }
1207
+ if (byGroup.size === 0)
1208
+ return '';
1209
+ const renderRows = (title, rows) => {
1210
+ const width = Math.min(40, rows.reduce((m, r) => Math.max(m, r.flags.length), 0));
1211
+ const lines = rows
1212
+ .map((r) => {
1213
+ const pad = ' '.repeat(Math.max(2, width - r.flags.length + 2));
1214
+ return ` ${r.flags}${pad}${r.description}`.trimEnd();
1215
+ })
1216
+ .join('\n');
1217
+ return `\n${title}:\n${lines}\n`;
1218
+ };
1219
+ let out = '';
1220
+ // App options (if any)
1221
+ const app = byGroup.get('app');
1222
+ if (app && app.length > 0) {
1223
+ out += renderRows('App options', app);
1224
+ }
1225
+ // Plugin groups sorted by id
1226
+ const pluginKeys = Array.from(byGroup.keys()).filter((k) => k.startsWith('plugin:'));
1227
+ pluginKeys.sort((a, b) => a.localeCompare(b));
1228
+ for (const k of pluginKeys) {
1229
+ const id = k.slice('plugin:'.length) || '(unknown)';
1230
+ const rows = byGroup.get(k) ?? [];
1231
+ if (rows.length > 0) {
1232
+ out += renderRows(`Plugin options — ${id}`, rows);
1233
+ }
1234
+ }
1235
+ return out;
1236
+ }
1086
1237
  }
1087
1238
 
1239
+ /**
1240
+ * Helper to retrieve the merged root options bag from any action handler
1241
+ * that only has access to thisCommand. Avoids structural casts.
1242
+ */
1243
+ const readMergedOptions = (cmd) => {
1244
+ // Ascend to the root command
1245
+ let root = cmd;
1246
+ while (root.parent) {
1247
+ root = root.parent;
1248
+ }
1249
+ const hostAny = root;
1250
+ return typeof hostAny.getOptions === 'function'
1251
+ ? hostAny.getOptions()
1252
+ : root
1253
+ .getDotenvCliOptions;
1254
+ };
1255
+
1088
1256
  exports.GetDotenvCli = GetDotenvCli;
1089
1257
  exports.definePlugin = definePlugin;
1258
+ exports.readMergedOptions = readMergedOptions;
@@ -1,5 +1,13 @@
1
- import { ZodType } from 'zod';
2
1
  import { Command } from 'commander';
2
+ import { ZodType } from 'zod';
3
+
4
+ /**
5
+ * Scripts table shape (configurable shell type).
6
+ */
7
+ type ScriptsTable<TShell extends string | boolean = string | boolean> = Record<string, string | {
8
+ cmd: string;
9
+ shell?: TShell;
10
+ }>;
3
11
 
4
12
  /**
5
13
  * A minimal representation of an environment key/value mapping.
@@ -95,6 +103,76 @@ interface GetDotenvOptions {
95
103
  useConfigLoader?: boolean;
96
104
  }
97
105
 
106
+ type Scripts = Record<string, string | {
107
+ cmd: string;
108
+ shell?: string | boolean;
109
+ }>;
110
+ /**
111
+ * Options passed programmatically to `getDotenvCli`.
112
+ */
113
+ interface GetDotenvCliOptions extends Omit<GetDotenvOptions, 'paths' | 'vars'> {
114
+ /**
115
+ * Logs CLI internals when true.
116
+ */
117
+ debug?: boolean;
118
+ /**
119
+ * When true, capture child stdout/stderr and re-emit after completion.
120
+ * Useful for tests/CI. Default behavior is streaming via stdio: 'inherit'.
121
+ */
122
+ capture?: boolean;
123
+ /**
124
+ * A delimited string of paths to dotenv files.
125
+ */
126
+ paths?: string;
127
+ /**
128
+ * A delimiter string with which to split `paths`. Only used if
129
+ * `pathsDelimiterPattern` is not provided.
130
+ */
131
+ pathsDelimiter?: string;
132
+ /**
133
+ * A regular expression pattern with which to split `paths`. Supersedes
134
+ * `pathsDelimiter`.
135
+ */
136
+ pathsDelimiterPattern?: string;
137
+ /**
138
+ * Scripts that can be executed from the CLI, either individually or via the batch subcommand.
139
+ */
140
+ scripts?: Scripts;
141
+ /**
142
+ * Determines how commands and scripts are executed. If `false` or
143
+ * `undefined`, commands are executed as plain Javascript using the default
144
+ * execa parser. If `true`, commands are executed using the default OS shell
145
+ * parser. Otherwise the user may provide a specific shell string (e.g.
146
+ * `/bin/bash`)
147
+ */
148
+ shell?: string | boolean;
149
+ /**
150
+ * A delimited string of key-value pairs declaratively specifying variables &
151
+ * values to be loaded in addition to any dotenv files.
152
+ */
153
+ vars?: string;
154
+ /**
155
+ * A string with which to split keys from values in `vars`. Only used if
156
+ * `varsDelimiterPattern` is not provided.
157
+ */
158
+ varsAssignor?: string;
159
+ /**
160
+ * A regular expression pattern with which to split variable names from values
161
+ * in `vars`. Supersedes `varsAssignor`.
162
+ */
163
+ varsAssignorPattern?: string;
164
+ /**
165
+ * A string with which to split `vars` into key-value pairs. Only used if
166
+ * `varsDelimiterPattern` is not provided.
167
+ */
168
+ varsDelimiter?: string;
169
+ /**
170
+ * A regular expression pattern with which to split `vars` into key-value
171
+ * pairs. Supersedes `varsDelimiter`.
172
+ */
173
+ varsDelimiterPattern?: string;
174
+ }
175
+
98
176
  /** * Per-invocation context shared with plugins and actions. */
99
177
  type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
100
178
  optionsResolved: TOptions;
@@ -102,6 +180,7 @@ type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
102
180
  plugins?: Record<string, unknown>;
103
181
  pluginConfigs?: Record<string, unknown>;
104
182
  };
183
+ declare const HELP_HEADER_SYMBOL: unique symbol;
105
184
  /**
106
185
  * Plugin-first CLI host for get-dotenv. Extends Commander.Command.
107
186
  *
@@ -114,10 +193,13 @@ type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
114
193
  * NOTE: This host is additive and does not alter the legacy CLI.
115
194
  */
116
195
  declare class GetDotenvCli<TOptions extends GetDotenvOptions = GetDotenvOptions> extends Command {
196
+ #private;
117
197
  /** Registered top-level plugins (composition happens via .use()) */
118
198
  private _plugins;
119
199
  /** One-time installation guard */
120
200
  private _installed;
201
+ /** Optional header line to prepend in help output */
202
+ private [HELP_HEADER_SYMBOL];
121
203
  constructor(alias?: string);
122
204
  /**
123
205
  * Resolve options (strict) and compute dotenv context. * Stores the context on the instance under a symbol.
@@ -127,9 +209,33 @@ declare class GetDotenvCli<TOptions extends GetDotenvOptions = GetDotenvOptions>
127
209
  * Retrieve the current invocation context (if any).
128
210
  */
129
211
  getCtx(): GetDotenvCliCtx<TOptions> | undefined;
212
+ /**
213
+ * Retrieve the merged root CLI options bag (if set by passOptions()).
214
+ * Downstream-safe: no generics required.
215
+ */
216
+ getOptions(): GetDotenvCliOptions | undefined;
217
+ /** Internal: set the merged root options bag for this run. */
218
+ _setOptionsBag(bag: GetDotenvCliOptions): void;
130
219
  /** * Convenience helper to create a namespaced subcommand.
131
220
  */
132
221
  ns(name: string): Command;
222
+ /**
223
+ * Tag options added during the provided callback as 'app' for grouped help.
224
+ * Allows downstream apps to demarcate their root-level options.
225
+ */
226
+ tagAppOptions<T>(fn: (root: Command) => T): T;
227
+ /**
228
+ * Branding helper: set CLI name/description/version and optional help header.
229
+ * If version is omitted and importMetaUrl is provided, attempts to read the
230
+ * nearest package.json version (best-effort; non-fatal on failure).
231
+ */
232
+ brand(args: {
233
+ name?: string;
234
+ description?: string;
235
+ version?: string;
236
+ importMetaUrl?: string;
237
+ helpHeader?: string;
238
+ }): Promise<this>;
133
239
  /**
134
240
  * Register a plugin for installation (parent level).
135
241
  * Installation occurs on first resolveAndLoad() (or explicit install()).
@@ -187,5 +293,11 @@ type DefineSpec = Omit<GetDotenvCliPlugin, 'children' | 'use'> & {
187
293
  */
188
294
  declare const definePlugin: (spec: DefineSpec) => GetDotenvCliPlugin;
189
295
 
190
- export { GetDotenvCli, definePlugin };
191
- export type { DefineSpec, GetDotenvCliPlugin };
296
+ /**
297
+ * Helper to retrieve the merged root options bag from any action handler
298
+ * that only has access to thisCommand. Avoids structural casts.
299
+ */
300
+ declare const readMergedOptions: (cmd: Command) => GetDotenvCliOptions | undefined;
301
+
302
+ export { GetDotenvCli, definePlugin, readMergedOptions };
303
+ export type { DefineSpec, GetDotenvCliCtx, GetDotenvCliOptions, GetDotenvCliPlugin, ScriptsTable };
@@ -1,5 +1,13 @@
1
- import { ZodType } from 'zod';
2
1
  import { Command } from 'commander';
2
+ import { ZodType } from 'zod';
3
+
4
+ /**
5
+ * Scripts table shape (configurable shell type).
6
+ */
7
+ type ScriptsTable<TShell extends string | boolean = string | boolean> = Record<string, string | {
8
+ cmd: string;
9
+ shell?: TShell;
10
+ }>;
3
11
 
4
12
  /**
5
13
  * A minimal representation of an environment key/value mapping.
@@ -95,6 +103,76 @@ interface GetDotenvOptions {
95
103
  useConfigLoader?: boolean;
96
104
  }
97
105
 
106
+ type Scripts = Record<string, string | {
107
+ cmd: string;
108
+ shell?: string | boolean;
109
+ }>;
110
+ /**
111
+ * Options passed programmatically to `getDotenvCli`.
112
+ */
113
+ interface GetDotenvCliOptions extends Omit<GetDotenvOptions, 'paths' | 'vars'> {
114
+ /**
115
+ * Logs CLI internals when true.
116
+ */
117
+ debug?: boolean;
118
+ /**
119
+ * When true, capture child stdout/stderr and re-emit after completion.
120
+ * Useful for tests/CI. Default behavior is streaming via stdio: 'inherit'.
121
+ */
122
+ capture?: boolean;
123
+ /**
124
+ * A delimited string of paths to dotenv files.
125
+ */
126
+ paths?: string;
127
+ /**
128
+ * A delimiter string with which to split `paths`. Only used if
129
+ * `pathsDelimiterPattern` is not provided.
130
+ */
131
+ pathsDelimiter?: string;
132
+ /**
133
+ * A regular expression pattern with which to split `paths`. Supersedes
134
+ * `pathsDelimiter`.
135
+ */
136
+ pathsDelimiterPattern?: string;
137
+ /**
138
+ * Scripts that can be executed from the CLI, either individually or via the batch subcommand.
139
+ */
140
+ scripts?: Scripts;
141
+ /**
142
+ * Determines how commands and scripts are executed. If `false` or
143
+ * `undefined`, commands are executed as plain Javascript using the default
144
+ * execa parser. If `true`, commands are executed using the default OS shell
145
+ * parser. Otherwise the user may provide a specific shell string (e.g.
146
+ * `/bin/bash`)
147
+ */
148
+ shell?: string | boolean;
149
+ /**
150
+ * A delimited string of key-value pairs declaratively specifying variables &
151
+ * values to be loaded in addition to any dotenv files.
152
+ */
153
+ vars?: string;
154
+ /**
155
+ * A string with which to split keys from values in `vars`. Only used if
156
+ * `varsDelimiterPattern` is not provided.
157
+ */
158
+ varsAssignor?: string;
159
+ /**
160
+ * A regular expression pattern with which to split variable names from values
161
+ * in `vars`. Supersedes `varsAssignor`.
162
+ */
163
+ varsAssignorPattern?: string;
164
+ /**
165
+ * A string with which to split `vars` into key-value pairs. Only used if
166
+ * `varsDelimiterPattern` is not provided.
167
+ */
168
+ varsDelimiter?: string;
169
+ /**
170
+ * A regular expression pattern with which to split `vars` into key-value
171
+ * pairs. Supersedes `varsDelimiter`.
172
+ */
173
+ varsDelimiterPattern?: string;
174
+ }
175
+
98
176
  /** * Per-invocation context shared with plugins and actions. */
99
177
  type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
100
178
  optionsResolved: TOptions;
@@ -102,6 +180,7 @@ type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
102
180
  plugins?: Record<string, unknown>;
103
181
  pluginConfigs?: Record<string, unknown>;
104
182
  };
183
+ declare const HELP_HEADER_SYMBOL: unique symbol;
105
184
  /**
106
185
  * Plugin-first CLI host for get-dotenv. Extends Commander.Command.
107
186
  *
@@ -114,10 +193,13 @@ type GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> = {
114
193
  * NOTE: This host is additive and does not alter the legacy CLI.
115
194
  */
116
195
  declare class GetDotenvCli<TOptions extends GetDotenvOptions = GetDotenvOptions> extends Command {
196
+ #private;
117
197
  /** Registered top-level plugins (composition happens via .use()) */
118
198
  private _plugins;
119
199
  /** One-time installation guard */
120
200
  private _installed;
201
+ /** Optional header line to prepend in help output */
202
+ private [HELP_HEADER_SYMBOL];
121
203
  constructor(alias?: string);
122
204
  /**
123
205
  * Resolve options (strict) and compute dotenv context. * Stores the context on the instance under a symbol.
@@ -127,9 +209,33 @@ declare class GetDotenvCli<TOptions extends GetDotenvOptions = GetDotenvOptions>
127
209
  * Retrieve the current invocation context (if any).
128
210
  */
129
211
  getCtx(): GetDotenvCliCtx<TOptions> | undefined;
212
+ /**
213
+ * Retrieve the merged root CLI options bag (if set by passOptions()).
214
+ * Downstream-safe: no generics required.
215
+ */
216
+ getOptions(): GetDotenvCliOptions | undefined;
217
+ /** Internal: set the merged root options bag for this run. */
218
+ _setOptionsBag(bag: GetDotenvCliOptions): void;
130
219
  /** * Convenience helper to create a namespaced subcommand.
131
220
  */
132
221
  ns(name: string): Command;
222
+ /**
223
+ * Tag options added during the provided callback as 'app' for grouped help.
224
+ * Allows downstream apps to demarcate their root-level options.
225
+ */
226
+ tagAppOptions<T>(fn: (root: Command) => T): T;
227
+ /**
228
+ * Branding helper: set CLI name/description/version and optional help header.
229
+ * If version is omitted and importMetaUrl is provided, attempts to read the
230
+ * nearest package.json version (best-effort; non-fatal on failure).
231
+ */
232
+ brand(args: {
233
+ name?: string;
234
+ description?: string;
235
+ version?: string;
236
+ importMetaUrl?: string;
237
+ helpHeader?: string;
238
+ }): Promise<this>;
133
239
  /**
134
240
  * Register a plugin for installation (parent level).
135
241
  * Installation occurs on first resolveAndLoad() (or explicit install()).
@@ -187,5 +293,11 @@ type DefineSpec = Omit<GetDotenvCliPlugin, 'children' | 'use'> & {
187
293
  */
188
294
  declare const definePlugin: (spec: DefineSpec) => GetDotenvCliPlugin;
189
295
 
190
- export { GetDotenvCli, definePlugin };
191
- export type { DefineSpec, GetDotenvCliPlugin };
296
+ /**
297
+ * Helper to retrieve the merged root options bag from any action handler
298
+ * that only has access to thisCommand. Avoids structural casts.
299
+ */
300
+ declare const readMergedOptions: (cmd: Command) => GetDotenvCliOptions | undefined;
301
+
302
+ export { GetDotenvCli, definePlugin, readMergedOptions };
303
+ export type { DefineSpec, GetDotenvCliCtx, GetDotenvCliOptions, GetDotenvCliPlugin, ScriptsTable };