gunshi 0.35.0 → 0.35.2

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.
@@ -1,12 +1,20 @@
1
- import "./constants-CQq1R_68.js";
2
- import { o as resolveLazyCommand, s as kebabnize } from "./utils-DNVHO9MQ.js";
3
- import { t as plugin } from "./core-CFEvRYOJ.js";
1
+ import "./context-CAPhwgJJ.js";
2
+ import { n as kebabnize } from "./utils-BKhsrjPW.js";
3
+ import { resolveLazyCommand } from "./utils.js";
4
+ import { n as ArgsValidationErrorKeys, r as isArgsValidationError } from "./resolver-UFOtObbe.js";
5
+ import { i as isCommandNotFoundError } from "./error-xSnOOdnr.js";
6
+ import { t as plugin } from "./plugin-DhJZVIbl.js";
7
+ /**
8
+ * @author kazuya kawaguchi (a.k.a. kazupon)
9
+ * @license MIT
10
+ */
4
11
  /**
5
12
  * @author kazuya kawaguchi (a.k.a. kazupon)
6
13
  * @license MIT
7
14
  */
8
15
  const BUILD_IN_PREFIX_AND_KEY_SEPARATOR = `_:`;
9
16
  const ARG_PREFIX_AND_KEY_SEPARATOR = `arg:`;
17
+ const ERROR_PREFIX_AND_KEY_SEPARATOR = `err:`;
10
18
  const COMMON_ARGS = {
11
19
  help: {
12
20
  type: "boolean",
@@ -35,7 +43,15 @@ var en_US_default = {
35
43
  DEFAULT: "default",
36
44
  CHOICES: "choices",
37
45
  help: "Display this help message",
38
- version: "Display this version"
46
+ version: "Display this version",
47
+ "err:arg:required-option": "Optional argument {$displayName} is required",
48
+ "err:arg:required-positional": "Positional argument {$name} is required",
49
+ "err:arg:invalid-type": "Invalid value for {$displayName}: expected {$expected}",
50
+ "err:arg:invalid-choice": "Invalid value for {$displayName}: expected one of {$choices}",
51
+ "err:arg:custom-parse": "Invalid value for {$displayName}: {$reason}",
52
+ "err:arg:unknown-option": "Unknown option: {$rawName}",
53
+ "err:cmd:not-found": "Command not found: {$commandName}",
54
+ "err:suggestion:did-you-mean": "Did you mean {$name}?"
39
55
  };
40
56
  //#endregion
41
57
  //#region ../shared/src/utils.ts
@@ -144,7 +160,8 @@ function makeShortLongOptionPair(schema, name, toKebab) {
144
160
  function localizable(ctx, cmd, translate) {
145
161
  async function localize(key, values) {
146
162
  if (translate) return translate(key, values);
147
- if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) return en_US_default[key.slice(BUILD_IN_PREFIX_AND_KEY_SEPARATOR.length)] || key;
163
+ if (key.startsWith(BUILD_IN_PREFIX_AND_KEY_SEPARATOR)) return resolveAndFormatResource(key.slice(BUILD_IN_PREFIX_AND_KEY_SEPARATOR.length), key, values);
164
+ if (key.startsWith(ERROR_PREFIX_AND_KEY_SEPARATOR)) return resolveAndFormatResource(key, key, values);
148
165
  const namaspacedArgKey = resolveKey(ARG_PREFIX_AND_KEY_SEPARATOR, ctx.name);
149
166
  if (key.startsWith(namaspacedArgKey)) {
150
167
  let argKey = key.slice(namaspacedArgKey.length);
@@ -163,6 +180,21 @@ function localizable(ctx, cmd, translate) {
163
180
  }
164
181
  return localize;
165
182
  }
183
+ function resolveAndFormatResource(resourceKey, fallbackKey, values) {
184
+ return formatResource(en_US_default[resourceKey], values) || fallbackKey;
185
+ }
186
+ /**
187
+ * Format a resource message by replacing placeholder values.
188
+ *
189
+ * @param resource - Resource message template
190
+ * @param values - Placeholder values
191
+ * @returns Formatted resource message
192
+ */
193
+ function formatResource(resource, values = Object.create(null)) {
194
+ return resource?.replaceAll(/\{\$(\w+)\}/g, (_, name) => {
195
+ return values[name] == null ? "" : String(values[name]);
196
+ });
197
+ }
166
198
  //#endregion
167
199
  //#region ../shared/src/index.ts
168
200
  /**
@@ -525,17 +557,50 @@ function isRequiredSinglePositionalArg(arg) {
525
557
  * @author kazuya kawaguchi (a.k.a. kazupon)
526
558
  * @license MIT
527
559
  */
560
+ const i18nPluginId$1 = namespacedId("i18n");
528
561
  /**
529
562
  * Render the validation errors.
530
563
  *
531
- * @param _ctx - A {@link CommandContext | command context}
564
+ * @param ctx - A {@link CommandContext | command context}
532
565
  * @param error - An {@link AggregateError} of option in `args-token` validation
533
566
  * @returns A rendered validation error.
534
567
  */
535
- function renderValidationErrors(_ctx, error) {
568
+ async function renderValidationErrors(ctx, error) {
536
569
  const messages = [];
537
- for (const err of error.errors) messages.push(err.message);
538
- return Promise.resolve(messages.join("\n"));
570
+ for (const err of error.errors) messages.push(await renderValidationError(ctx, err));
571
+ return messages.join("\n");
572
+ }
573
+ async function renderValidationError(ctx, error) {
574
+ if (isCommandNotFoundError(error) && error.code) {
575
+ const message = await localize(ctx, error.code, error.values);
576
+ if (message && message !== error.code) return message;
577
+ }
578
+ if (isArgsValidationError(error) && error.code) {
579
+ const values = await resolveValidationValues(ctx, error);
580
+ const message = await localize(ctx, error.code, values);
581
+ if (message && message !== error.code) return message;
582
+ }
583
+ return error.message;
584
+ }
585
+ async function resolveValidationValues(ctx, error) {
586
+ if (error.code !== ArgsValidationErrorKeys.customParse) return error.values;
587
+ const { reasonKey, reasonValues } = error.values;
588
+ if (typeof reasonKey !== "string") return error.values;
589
+ const key = resolveKey(reasonKey, ctx.name);
590
+ const localizedReason = await localize(ctx, key, toRecord(reasonValues));
591
+ if (!localizedReason || localizedReason === key) return error.values;
592
+ return {
593
+ ...error.values,
594
+ reason: localizedReason
595
+ };
596
+ }
597
+ async function localize(ctx, key, values) {
598
+ const i18n = ctx.extensions?.[i18nPluginId$1];
599
+ if (i18n?.translate) return i18n.translate(key, values);
600
+ return key;
601
+ }
602
+ function toRecord(value) {
603
+ return value != null && typeof value === "object" ? value : Object.create(null);
539
604
  }
540
605
  //#endregion
541
606
  //#region ../plugin-renderer/src/index.ts
@@ -1,4 +1,4 @@
1
- import { i as Args, n as ArgSchema, o as ArgToken, r as ArgValues, t as ArgExplicitlyProvided } from "./resolver-mxPNDBm_.js";
1
+ import { i as Args, n as ArgSchema, r as ArgValues, t as ArgExplicitlyProvided, u as ArgToken } from "./resolver-CgkhQ6Tt.js";
2
2
 
3
3
  //#region src/plugin/context.d.ts
4
4
  /**
@@ -529,6 +529,13 @@ interface CommandEnvironment<G extends GunshiParamsConstraint = DefaultGunshiPar
529
529
  * @see {@linkcode CliOptions.usageSilent}
530
530
  */
531
531
  usageSilent: boolean;
532
+ /**
533
+ * Whether to treat undefined options as argument validation errors.
534
+ *
535
+ * @default false
536
+ * @see {@linkcode CliOptions.strict}
537
+ */
538
+ strict: boolean;
532
539
  /**
533
540
  * Sub commands.
534
541
  *
@@ -616,6 +623,16 @@ interface CliOptions<G extends GunshiParamsConstraint = DefaultGunshiParams> {
616
623
  * Whether to display the command usage.
617
624
  */
618
625
  usageSilent?: boolean;
626
+ /**
627
+ * Whether to treat undefined options as argument validation errors.
628
+ *
629
+ * When enabled, option tokens that are not declared by the resolved command
630
+ * arguments or installed global options are reported as validation errors
631
+ * before the command runner is executed.
632
+ *
633
+ * @default false
634
+ */
635
+ strict?: boolean;
619
636
  /**
620
637
  * Render function the command usage.
621
638
  */
@@ -0,0 +1,32 @@
1
+ //#region ../../node_modules/.pnpm/args-tokens@0.28.0/node_modules/args-tokens/lib/utils.js
2
+ /**
3
+ * Entry point of utils.
4
+ *
5
+ * Note that this entry point is used by gunshi to import utility functions.
6
+ *
7
+ * @module
8
+ */
9
+ /**
10
+ * @author kazuya kawaguchi (a.k.a. kazupon)
11
+ * @license MIT
12
+ */
13
+ /**
14
+ * Convert a string to kebab-case.
15
+ *
16
+ * @param str - A string to convert
17
+ * @returns Converted string into kebab-case.
18
+ */
19
+ function kebabnize(str) {
20
+ return str.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
21
+ }
22
+ /**
23
+ * Format allowed argument choices for validation error values and fallback messages.
24
+ *
25
+ * @param choices - Choice values to format
26
+ * @returns JSON-quoted choices joined with `, `.
27
+ */
28
+ function formatChoices(choices) {
29
+ return choices.map((value) => JSON.stringify(value)).join(", ");
30
+ }
31
+ //#endregion
32
+ export { kebabnize as n, formatChoices as t };
package/lib/utils.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { b as GunshiParamsConstraint, m as DefaultGunshiParams, p as Commandable, r as Command, x as LazyCommand } from "./types-DZ0S_FSe.js";
1
+ import { b as GunshiParamsConstraint, m as DefaultGunshiParams, p as Commandable, r as Command, x as LazyCommand } from "./types-CD5eRJFK.js";
2
2
 
3
- //#region ../../node_modules/.pnpm/args-tokens@0.27.0/node_modules/args-tokens/lib/utils.d.ts
3
+ //#region ../../node_modules/.pnpm/args-tokens@0.28.0/node_modules/args-tokens/lib/utils.d.ts
4
4
 
5
5
  //#region src/utils.d.ts
6
6
  /**
@@ -21,7 +21,12 @@ import { b as GunshiParamsConstraint, m as DefaultGunshiParams, p as Commandable
21
21
  * @returns Converted string into kebab-case.
22
22
  */
23
23
  declare function kebabnize(str: string): string;
24
- //#endregion
24
+ /**
25
+ * Format allowed argument choices for validation error values and fallback messages.
26
+ *
27
+ * @param choices - Choice values to format
28
+ * @returns JSON-quoted choices joined with `, `.
29
+ */
25
30
  //#endregion
26
31
  //#region src/utils.d.ts
27
32
  /**
package/lib/utils.js CHANGED
@@ -1,2 +1,110 @@
1
- import { a as log, i as isLazyCommand, n as deepFreeze, o as resolveLazyCommand, r as getCommandSubCommands, s as kebabnize, t as create } from "./utils-DNVHO9MQ.js";
1
+ import { n as kebabnize } from "./utils-BKhsrjPW.js";
2
+ //#region src/utils.ts
3
+ /**
4
+ * @author kazuya kawaguchi (a.k.a. kazupon)
5
+ * @license MIT
6
+ */
7
+ /**
8
+ * Check if the given command is a {@link LazyCommand}.
9
+ *
10
+ * @param cmd - A command to check
11
+ * @returns `true` if the command is a {@link LazyCommand}, otherwise `false
12
+ */
13
+ function isLazyCommand(cmd) {
14
+ return typeof cmd === "function" && "commandName" in cmd && !!cmd.commandName;
15
+ }
16
+ /**
17
+ * Resolve a lazy command to a {@link Command}.
18
+ *
19
+ * @param cmd - A {@link Commandable} or {@link LazyCommand} to resolve
20
+ * @param name - Optional name of the command, if not provided, it will use the name from the command itself.
21
+ * @param needRunResolving - Whether to run the resolving function of the lazy command.
22
+ * @returns A resolved {@link Command}
23
+ */
24
+ async function resolveLazyCommand(cmd, name, needRunResolving = false) {
25
+ let command;
26
+ if (isLazyCommand(cmd)) {
27
+ const baseCommand = {
28
+ name: cmd.commandName,
29
+ description: cmd.description,
30
+ args: cmd.args,
31
+ examples: cmd.examples,
32
+ internal: cmd.internal,
33
+ entry: cmd.entry,
34
+ subCommands: cmd.subCommands
35
+ };
36
+ if ("resource" in cmd && cmd.resource) baseCommand.resource = cmd.resource;
37
+ command = Object.assign(create(), baseCommand);
38
+ if (needRunResolving) {
39
+ const loaded = await cmd();
40
+ if (typeof loaded === "function") command.run = loaded;
41
+ else if (typeof loaded === "object") {
42
+ if (loaded.run == null) throw new TypeError(`'run' is required in command: ${cmd.name || name}`);
43
+ command.run = loaded.run;
44
+ command.name = loaded.name;
45
+ command.description = loaded.description;
46
+ command.args = loaded.args;
47
+ command.examples = loaded.examples;
48
+ command.internal = loaded.internal;
49
+ command.entry = loaded.entry;
50
+ command.subCommands = loaded.subCommands || cmd.subCommands;
51
+ if ("resource" in loaded && loaded.resource) command.resource = loaded.resource;
52
+ } else throw new TypeError(`Cannot resolve command: ${cmd.name || name}`);
53
+ }
54
+ } else command = Object.assign(create(), cmd);
55
+ if (command.name == null && name) command.name = name;
56
+ return deepFreeze(command);
57
+ }
58
+ /**
59
+ * Create an object with the specified prototype. A shorthand for `Object.create`.
60
+ *
61
+ * @param obj - An object to use as the prototype for the new object. If `null`, it will create an object with no prototype.
62
+ * @returns A new object with the specified prototype
63
+ */
64
+ function create(obj = null) {
65
+ return Object.create(obj);
66
+ }
67
+ /**
68
+ * Log a message to the console.
69
+ *
70
+ * @param args - Arguments to log
71
+ */
72
+ function log(...args) {
73
+ console.log(...args);
74
+ }
75
+ /**
76
+ * Get the sub-commands of a command as a normalized Map.
77
+ *
78
+ * @param cmd - A command or lazy command
79
+ * @returns A Map of sub-commands, or undefined if the command has no sub-commands.
80
+ */
81
+ function getCommandSubCommands(cmd) {
82
+ const subCommands = isLazyCommand(cmd) ? cmd.subCommands : typeof cmd === "object" ? cmd.subCommands : void 0;
83
+ if (!subCommands) return;
84
+ if (subCommands instanceof Map) return subCommands.size > 0 ? subCommands : void 0;
85
+ if (typeof subCommands === "object") {
86
+ const entries = Object.entries(subCommands);
87
+ if (entries.length === 0) return;
88
+ const map = /* @__PURE__ */ new Map();
89
+ for (const [name, cmd] of entries) map.set(name, cmd);
90
+ return map;
91
+ }
92
+ }
93
+ /**
94
+ * Deep freeze an object, making it immutable.
95
+ *
96
+ * @param obj - The object to freeze
97
+ * @param ignores - Properties to ignore during freezing
98
+ * @returns A frozen object
99
+ */
100
+ function deepFreeze(obj, ignores = []) {
101
+ if (obj === null || typeof obj !== "object") return obj;
102
+ for (const key of Object.keys(obj)) {
103
+ const value = obj[key];
104
+ if (ignores.includes(key)) continue;
105
+ if (typeof value === "object" && value !== null) deepFreeze(value, ignores);
106
+ }
107
+ return Object.freeze(obj);
108
+ }
109
+ //#endregion
2
110
  export { create, deepFreeze, getCommandSubCommands, isLazyCommand, kebabnize, log, resolveLazyCommand };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gunshi",
3
3
  "description": "Modern javascript command-line library",
4
- "version": "0.35.0",
4
+ "version": "0.35.2",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -108,7 +108,7 @@
108
108
  }
109
109
  },
110
110
  "devDependencies": {
111
- "args-tokens": "^0.27.0",
111
+ "args-tokens": "^0.28.0",
112
112
  "deno": "^2.7.14",
113
113
  "jsr": "^0.14.3",
114
114
  "jsr-exports-lint": "^0.4.2",
@@ -116,11 +116,11 @@
116
116
  "std-env": "^4.1.0",
117
117
  "tsdown": "0.21.0",
118
118
  "zod": "^4.4.3",
119
- "@gunshi/plugin-i18n": "0.35.0",
120
- "@gunshi/plugin-global": "0.35.0",
121
- "@gunshi/plugin-renderer": "0.35.0",
122
- "@gunshi/resources": "0.35.0",
123
- "@gunshi/shared": "0.35.0"
119
+ "@gunshi/plugin-renderer": "0.35.2",
120
+ "@gunshi/plugin-i18n": "0.35.2",
121
+ "@gunshi/plugin-global": "0.35.2",
122
+ "@gunshi/resources": "0.35.2",
123
+ "@gunshi/shared": "0.35.2"
124
124
  },
125
125
  "scripts": {
126
126
  "build": "tsdown",
@@ -1,11 +0,0 @@
1
- import { m as DefaultGunshiParams, n as CliOptions } from "./types-DZ0S_FSe.js";
2
-
3
- //#region src/constants.d.ts
4
- /**
5
- * @author kazuya kawaguchi (a.k.a. kazupon)
6
- * @license MIT
7
- */
8
- declare const ANONYMOUS_COMMAND_NAME = "(anonymous)";
9
- declare const CLI_OPTIONS_DEFAULT: CliOptions<DefaultGunshiParams>;
10
- //#endregion
11
- export { CLI_OPTIONS_DEFAULT as n, ANONYMOUS_COMMAND_NAME as t };
@@ -1,29 +0,0 @@
1
- //#region src/constants.ts
2
- /**
3
- * @author kazuya kawaguchi (a.k.a. kazupon)
4
- * @license MIT
5
- */
6
- const ANONYMOUS_COMMAND_NAME = "(anonymous)";
7
- /**
8
- * A no-operation function.
9
- */
10
- const NOOP = () => {};
11
- const CLI_OPTIONS_DEFAULT = {
12
- name: void 0,
13
- description: void 0,
14
- version: void 0,
15
- cwd: void 0,
16
- usageSilent: false,
17
- subCommands: void 0,
18
- leftMargin: 2,
19
- middleMargin: 10,
20
- usageOptionType: false,
21
- usageOptionValue: true,
22
- renderHeader: void 0,
23
- renderUsage: void 0,
24
- renderValidationErrors: void 0,
25
- plugins: void 0,
26
- fallbackToEntry: false
27
- };
28
- //#endregion
29
- export { CLI_OPTIONS_DEFAULT as n, NOOP as r, ANONYMOUS_COMMAND_NAME as t };
@@ -1,131 +0,0 @@
1
- //#region ../../node_modules/.pnpm/args-tokens@0.27.0/node_modules/args-tokens/lib/utils.js
2
- /**
3
- * Entry point of utils.
4
- *
5
- * Note that this entry point is used by gunshi to import utility functions.
6
- *
7
- * @module
8
- */
9
- /**
10
- * @author kazuya kawaguchi (a.k.a. kazupon)
11
- * @license MIT
12
- */
13
- /**
14
- * Convert a string to kebab-case.
15
- *
16
- * @param str - A string to convert
17
- * @returns Converted string into kebab-case.
18
- */
19
- function kebabnize(str) {
20
- return str.replace(/[A-Z]/g, (match, offset) => (offset > 0 ? "-" : "") + match.toLowerCase());
21
- }
22
- //#endregion
23
- //#region src/utils.ts
24
- /**
25
- * @author kazuya kawaguchi (a.k.a. kazupon)
26
- * @license MIT
27
- */
28
- /**
29
- * Check if the given command is a {@link LazyCommand}.
30
- *
31
- * @param cmd - A command to check
32
- * @returns `true` if the command is a {@link LazyCommand}, otherwise `false
33
- */
34
- function isLazyCommand(cmd) {
35
- return typeof cmd === "function" && "commandName" in cmd && !!cmd.commandName;
36
- }
37
- /**
38
- * Resolve a lazy command to a {@link Command}.
39
- *
40
- * @param cmd - A {@link Commandable} or {@link LazyCommand} to resolve
41
- * @param name - Optional name of the command, if not provided, it will use the name from the command itself.
42
- * @param needRunResolving - Whether to run the resolving function of the lazy command.
43
- * @returns A resolved {@link Command}
44
- */
45
- async function resolveLazyCommand(cmd, name, needRunResolving = false) {
46
- let command;
47
- if (isLazyCommand(cmd)) {
48
- const baseCommand = {
49
- name: cmd.commandName,
50
- description: cmd.description,
51
- args: cmd.args,
52
- examples: cmd.examples,
53
- internal: cmd.internal,
54
- entry: cmd.entry,
55
- subCommands: cmd.subCommands
56
- };
57
- if ("resource" in cmd && cmd.resource) baseCommand.resource = cmd.resource;
58
- command = Object.assign(create(), baseCommand);
59
- if (needRunResolving) {
60
- const loaded = await cmd();
61
- if (typeof loaded === "function") command.run = loaded;
62
- else if (typeof loaded === "object") {
63
- if (loaded.run == null) throw new TypeError(`'run' is required in command: ${cmd.name || name}`);
64
- command.run = loaded.run;
65
- command.name = loaded.name;
66
- command.description = loaded.description;
67
- command.args = loaded.args;
68
- command.examples = loaded.examples;
69
- command.internal = loaded.internal;
70
- command.entry = loaded.entry;
71
- command.subCommands = loaded.subCommands || cmd.subCommands;
72
- if ("resource" in loaded && loaded.resource) command.resource = loaded.resource;
73
- } else throw new TypeError(`Cannot resolve command: ${cmd.name || name}`);
74
- }
75
- } else command = Object.assign(create(), cmd);
76
- if (command.name == null && name) command.name = name;
77
- return deepFreeze(command);
78
- }
79
- /**
80
- * Create an object with the specified prototype. A shorthand for `Object.create`.
81
- *
82
- * @param obj - An object to use as the prototype for the new object. If `null`, it will create an object with no prototype.
83
- * @returns A new object with the specified prototype
84
- */
85
- function create(obj = null) {
86
- return Object.create(obj);
87
- }
88
- /**
89
- * Log a message to the console.
90
- *
91
- * @param args - Arguments to log
92
- */
93
- function log(...args) {
94
- console.log(...args);
95
- }
96
- /**
97
- * Get the sub-commands of a command as a normalized Map.
98
- *
99
- * @param cmd - A command or lazy command
100
- * @returns A Map of sub-commands, or undefined if the command has no sub-commands.
101
- */
102
- function getCommandSubCommands(cmd) {
103
- const subCommands = isLazyCommand(cmd) ? cmd.subCommands : typeof cmd === "object" ? cmd.subCommands : void 0;
104
- if (!subCommands) return;
105
- if (subCommands instanceof Map) return subCommands.size > 0 ? subCommands : void 0;
106
- if (typeof subCommands === "object") {
107
- const entries = Object.entries(subCommands);
108
- if (entries.length === 0) return;
109
- const map = /* @__PURE__ */ new Map();
110
- for (const [name, cmd] of entries) map.set(name, cmd);
111
- return map;
112
- }
113
- }
114
- /**
115
- * Deep freeze an object, making it immutable.
116
- *
117
- * @param obj - The object to freeze
118
- * @param ignores - Properties to ignore during freezing
119
- * @returns A frozen object
120
- */
121
- function deepFreeze(obj, ignores = []) {
122
- if (obj === null || typeof obj !== "object") return obj;
123
- for (const key of Object.keys(obj)) {
124
- const value = obj[key];
125
- if (ignores.includes(key)) continue;
126
- if (typeof value === "object" && value !== null) deepFreeze(value, ignores);
127
- }
128
- return Object.freeze(obj);
129
- }
130
- //#endregion
131
- export { log as a, isLazyCommand as i, deepFreeze as n, resolveLazyCommand as o, getCommandSubCommands as r, kebabnize as s, create as t };