diff options
| author | ST-DDT <[email protected]> | 2022-02-01 17:31:52 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-02-01 17:31:52 +0100 |
| commit | 5e6754da61b63019fd063fad26adbeeabd8b789b (patch) | |
| tree | 954f7730feba92d951f66862d9165b99645f8981 /src/definitions | |
| parent | 18b4349af05ca671f1fc4cff0c04d359e914f001 (diff) | |
| download | faker-5e6754da61b63019fd063fad26adbeeabd8b789b.tar.xz faker-5e6754da61b63019fd063fad26adbeeabd8b789b.zip | |
feat(types): provide strong typing for locales (#363)
Diffstat (limited to 'src/definitions')
| -rw-r--r-- | src/definitions/address.ts | 115 | ||||
| -rw-r--r-- | src/definitions/animal.ts | 41 | ||||
| -rw-r--r-- | src/definitions/commerce.ts | 51 | ||||
| -rw-r--r-- | src/definitions/company.ts | 50 | ||||
| -rw-r--r-- | src/definitions/database.ts | 33 | ||||
| -rw-r--r-- | src/definitions/date.ts | 44 | ||||
| -rw-r--r-- | src/definitions/definitions.ts | 111 | ||||
| -rw-r--r-- | src/definitions/finance.ts | 50 | ||||
| -rw-r--r-- | src/definitions/hacker.ts | 47 | ||||
| -rw-r--r-- | src/definitions/index.ts | 27 | ||||
| -rw-r--r-- | src/definitions/internet.ts | 28 | ||||
| -rw-r--r-- | src/definitions/lorem.ts | 16 | ||||
| -rw-r--r-- | src/definitions/music.ts | 16 | ||||
| -rw-r--r-- | src/definitions/name.ts | 73 | ||||
| -rw-r--r-- | src/definitions/phone_number.ts | 21 | ||||
| -rw-r--r-- | src/definitions/system.ts | 33 | ||||
| -rw-r--r-- | src/definitions/utils.ts | 8 | ||||
| -rw-r--r-- | src/definitions/vehicle.ts | 38 | ||||
| -rw-r--r-- | src/definitions/word.ts | 27 |
19 files changed, 829 insertions, 0 deletions
diff --git a/src/definitions/address.ts b/src/definitions/address.ts new file mode 100644 index 00000000..a5bf2d1c --- /dev/null +++ b/src/definitions/address.ts @@ -0,0 +1,115 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to addresses. + */ +export interface AddressDefinitions { + /** + * Postcodes patterns by state + */ + // TODO ST-DDT 2022-01-31: address.zipCodeByState() expects only { [state: string]: { min: number; max: number } } + postcode_by_state: + | string[] + | { [state: string]: { min: number; max: number } }; + /** + * Postcodes patterns (Fake-Pattern | Fake-Pattern[]). + */ + postcode: string | string[]; + + /** + * Names of actual cities + */ + city_name?: string[]; + /** + * Common city prefixes + */ + city_prefix: string[]; + /** + * Common city suffixes + */ + city_suffix: string[]; + + /** + * The names of all countries + */ + country: string[]; + /** + * The names of this country's states + */ + state: string[]; + /** + * The abbreviated names of this country's states + */ + state_abbr: string[]; + /** + * The names of counties inside the country or state + */ + county: string[]; + + /** + * The names of the compass directions. + * First the 4 cardinal directions, then the 4 ordinal directions + */ + direction: string[]; + /** + * The abbreviated names of the compass directions. + * First the 4 cardinal directions, then the 4 ordinal directions + */ + direction_abbr: string[]; + + /** + * Common street prefixes + */ + street_prefix: string[]; + /** + * Common street suffixes + */ + street_suffix: string[]; + + /** + * The address "inside" an address/e.g. an apartment or office. + */ + secondary_address: string[]; + + /** + * The ISO-3166-1 ALPHA-2 country codes + */ + country_code: string[]; + /** + * The ISO-3166-1 ALPHA-3 country codes + */ + country_code_alpha_3: string[]; + + // A list of timezones names. + time_zone: string[]; +} + +/** + * Internal: A list of all keys for the AddressDefinitions. + */ +export const ADDRESS = allOf<keyof AddressDefinitions>()( + 'postcode_by_state', + 'postcode', + + 'city_name', + 'city_prefix', + 'city_suffix', + + 'country', + 'state', + 'state_abbr', + 'county', + + 'direction_abbr', + 'direction', + + 'street_prefix', + 'street_suffix', + + 'secondary_address', + + 'country_code', + 'country_code_alpha_3', + + 'time_zone' +); diff --git a/src/definitions/animal.ts b/src/definitions/animal.ts new file mode 100644 index 00000000..68fe0db2 --- /dev/null +++ b/src/definitions/animal.ts @@ -0,0 +1,41 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to animals. + */ +export interface AnimalDefinitions { + bear: string[]; + bird: string[]; + cat: string[]; + cetacean: string[]; + cow: string[]; + crocodilia: string[]; + dog: string[]; + fish: string[]; + horse: string[]; + insect: string[]; + lion: string[]; + rabbit: string[]; + snake: string[]; + type: string[]; +} + +/** + * Internal: A list of all keys for the AnimalDefinitions. + */ +export const ANIMAL = allOf<keyof AnimalDefinitions>()( + 'dog', + 'cat', + 'snake', + 'bear', + 'lion', + 'cetacean', + 'insect', + 'crocodilia', + 'cow', + 'bird', + 'fish', + 'rabbit', + 'horse', + 'type' +); diff --git a/src/definitions/commerce.ts b/src/definitions/commerce.ts new file mode 100644 index 00000000..dbe22f69 --- /dev/null +++ b/src/definitions/commerce.ts @@ -0,0 +1,51 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to commerce. + */ +export interface CommerceDefinitions { + /** + * Human readable color names + */ + color: string[]; + /** + * Department names inside a shop. + */ + department: string[]; + /** + * Product name generation definitions. + */ + product_name: CommerceProductNameDefinitions; + /** + * Descriptions for products. + */ + product_description: string[]; +} + +/** + * The possible definitions related to product name generation. + */ +export interface CommerceProductNameDefinitions { + /** + * Adjectives describing a product (e.g. tasty). + */ + adjective: string[]; + /** + * Materials describing a product (e.g. wood). + */ + material: string[]; + /** + * Types of products (e.g. chair). + */ + product: string[]; +} + +/** + * Internal: A list of all keys for the CommerceDefinitions. + */ +export const COMMERCE = allOf<keyof CommerceDefinitions>()( + 'color', + 'department', + 'product_name', + 'product_description' +); diff --git a/src/definitions/company.ts b/src/definitions/company.ts new file mode 100644 index 00000000..35947bde --- /dev/null +++ b/src/definitions/company.ts @@ -0,0 +1,50 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to companies. + */ +export interface CompanyDefinitions { + /** + * Business/products related adjectives. + */ + bs_adjective: string[]; + /** + * Business/products related nouns. + */ + bs_noun: string[]; + /** + * Business/products related verbs. + */ + bs_verb: string[]; + /** + * Catch phrase adjectives. + */ + adjective: string[]; + /** + * Catch phrase adjectives. + */ + descriptor: string[]; + /** + * Catch phrase adjectives. + */ + noun: string[]; + /** + * Company suffixes + */ + suffix: string[]; +} + +/** + * Internal: A list of all keys for the CompanyDefinitions. + */ +export const COMPANY = allOf<keyof CompanyDefinitions>()( + 'bs_adjective', + 'bs_noun', + 'bs_verb', + + 'adjective', + 'descriptor', + 'noun', + + 'suffix' +); diff --git a/src/definitions/database.ts b/src/definitions/database.ts new file mode 100644 index 00000000..935f35fc --- /dev/null +++ b/src/definitions/database.ts @@ -0,0 +1,33 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to databases. + */ +export interface DatabaseDefinitions { + /** + * Database Engine + */ + engine: string[]; + /** + * Database Collation + */ + collation: string[]; + /** + * Column names + */ + column: string[]; + /** + * Column types + */ + type: string[]; +} + +/** + * Internal: A list of all keys for the DatabaseDefinitions. + */ +export const DATABASE = allOf<keyof DatabaseDefinitions>()( + 'collation', + 'column', + 'engine', + 'type' +); diff --git a/src/definitions/date.ts b/src/definitions/date.ts new file mode 100644 index 00000000..2738bdb5 --- /dev/null +++ b/src/definitions/date.ts @@ -0,0 +1,44 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to dates. + */ +export interface DateDefinitions { + /** + * The translations for months (January - December). + */ + month: DateEntryDefinition; + /** + * The translations for weekdays (Sunday - Saturday). + */ + weekday: DateEntryDefinition; +} + +/** + * The possible definitions related to date entries. + */ +export interface DateEntryDefinition { + /** + * The long name of the entry. + */ + wide: string[]; + /** + * The short name/abbreviation of the entry. + */ + abbr: string[]; + /** + * The wide name of the entry when used in context. If absent wide will be used instead. + * It is used to specify a word in context, which may differ from a stand-alone word. + */ + wide_context?: string[]; + /** + * The short name/abbreviation name of the entry when used in context. If absent abbr will be used instead. + * It is used to specify a word in context, which may differ from a stand-alone word. + */ + abbr_context?: string[]; +} + +/** + * Internal: A list of all keys for the DateDefinitions. + */ +export const DATE = allOf<keyof DateDefinitions>()('month', 'weekday'); diff --git a/src/definitions/definitions.ts b/src/definitions/definitions.ts new file mode 100644 index 00000000..d59f84fc --- /dev/null +++ b/src/definitions/definitions.ts @@ -0,0 +1,111 @@ +import type { AddressDefinitions } from './address'; +import { ADDRESS } from './address'; +import type { AnimalDefinitions } from './animal'; +import { ANIMAL } from './animal'; +import type { CommerceDefinitions } from './commerce'; +import { COMMERCE } from './commerce'; +import type { CompanyDefinitions } from './company'; +import { COMPANY } from './company'; +import type { DatabaseDefinitions } from './database'; +import { DATABASE } from './database'; +import type { DateDefinitions } from './date'; +import { DATE } from './date'; +import type { FinanceDefinitions } from './finance'; +import { FINANCE } from './finance'; +import type { HackerDefinitions } from './hacker'; +import { HACKER } from './hacker'; +import type { InternetDefinitions } from './internet'; +import { INTERNET } from './internet'; +import type { LoremDefinitions } from './lorem'; +import { LOREM } from './lorem'; +import type { MusicDefinitions } from './music'; +import { MUSIC } from './music'; +import type { NameDefinitions } from './name'; +import { NAME } from './name'; +import type { PhoneNumberDefinitions } from './phone_number'; +import { PHONE_NUMBER } from './phone_number'; +import type { SystemDefinitions } from './system'; +import { SYSTEM } from './system'; +import type { VehicleDefinitions } from './vehicle'; +import { VEHICLE } from './vehicle'; +import type { WordDefinitions } from './word'; +import { WORD } from './word'; + +/** + * The definitions as used by the Faker modules. + */ +interface Definitions { + address: AddressDefinitions; + animal: AnimalDefinitions; + commerce: CommerceDefinitions; + company: CompanyDefinitions; + database: DatabaseDefinitions; + date: DateDefinitions; + finance: FinanceDefinitions; + hacker: HackerDefinitions; + internet: InternetDefinitions; + lorem: LoremDefinitions; + music: MusicDefinitions; + name: NameDefinitions; + phone_number: PhoneNumberDefinitions; + system: SystemDefinitions; + vehicle: VehicleDefinitions; + word: WordDefinitions; +} + +/** + * The definitions as used by the translations/locales. + * This is basically the same as Definitions with the exception, + * that most properties are optional and extra properties are allowed. + */ +export type LocaleDefinition = { + /** + * The name of the language. + */ + title: string; + separator?: string; +} & { + // Known modules + [module in keyof Definitions]?: Partial<Definitions[module]>; +} & { + // Unsupported & custom modules + [group: string]: Record<string, any> | string; +}; + +/** + * Internal: Compatibility type to ensure all modules have access to fallback locales. + * This should be replaced with a Proxy based property access + * that don't require prior getter generation in the future. + */ +export type DefinitionTypes = { + readonly title: string; + readonly separator: string; +} & { + readonly [module in keyof Definitions]: Array<keyof Definitions[module]>; +}; + +/** + * Internal: List off all modules and their properties, + * that needs to have a fallback generated in Faker.loadDefinitions(). + */ +export const DEFINITIONS: DefinitionTypes = { + title: '', + separator: '', + + address: ADDRESS, + animal: ANIMAL, + company: COMPANY, + commerce: COMMERCE, + database: DATABASE, + date: DATE, + finance: FINANCE, + hacker: HACKER, + internet: INTERNET, + lorem: LOREM, + music: MUSIC, + name: NAME, + phone_number: PHONE_NUMBER, + system: SYSTEM, + vehicle: VEHICLE, + word: WORD, +}; diff --git a/src/definitions/finance.ts b/src/definitions/finance.ts new file mode 100644 index 00000000..afe3639b --- /dev/null +++ b/src/definitions/finance.ts @@ -0,0 +1,50 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to finances. + */ +export interface FinanceDefinitions { + /** + * The types of accounts/purposes of an account (e.g. `Savings` account). + */ + account_type: string[]; + /** + * The pattern by provider used to generate credit card codes. + * `L` will be replaced by the check bit. + * + * @see Helpers.replaceCreditCardSymbols() + */ + credit_card: { [provider: string]: string[] }; + /** + * Currencies by their full name and their symbols (e.g. `US Dollar` -> `USD` / `$`). + */ + currency: { [currencyName: string]: FinanceCurrencyEntryDefinitions }; + /** + * Types of transactions (e.g. `deposit`). + */ + transaction_type: string[]; +} + +/** + * The possible definitions related to currency entries. + */ +export interface FinanceCurrencyEntryDefinitions { + /** + * The code/short text/abbreviation for the currency (e.g. `USD`). + */ + code: string; + /** + * The symbol for the currency (e.g. `$`). + */ + symbol: string; +} + +/** + * Internal: A list of all keys for the FinanceDefinitions. + */ +export const FINANCE = allOf<keyof FinanceDefinitions>()( + 'account_type', + 'credit_card', + 'currency', + 'transaction_type' +); diff --git a/src/definitions/hacker.ts b/src/definitions/hacker.ts new file mode 100644 index 00000000..00aa3a40 --- /dev/null +++ b/src/definitions/hacker.ts @@ -0,0 +1,47 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to computers. + */ +export interface HackerDefinitions { + /** + * Generic computer related abbreviations (e.g. `RAM`, `EXE`). + */ + abbreviation: string[]; + /** + * Some computer related adjectives or descriptors (e.g. `digital`, `bluetooth`) + */ + adjective: string[]; + /** + * Some computer related verbs for continuous actions (en: `ing` suffix; e.g. `hacking`). + */ + ingverb: string[]; + /** + * Some computer related nouns (e.g. `protocol`, `sensor`) + */ + noun: string[]; + /** + * Some phrases that will be injected with random hacker words. + * May use any of the HackerDefinition keys wrapped in double braces. + * (e.g. `I'm {{ingverb}} {{adjective}} {{noun}}` ) + * + * @see Helpers.mustache() + */ + phrase: string[]; + /** + * Some computer related verbs (e.g. `hack`). + */ + verb: string[]; +} + +/** + * Internal: A list of all keys for the HackerDefinitions. + */ +export const HACKER = allOf<keyof HackerDefinitions>()( + 'abbreviation', + 'adjective', + 'ingverb', + 'noun', + 'phrase', + 'verb' +); diff --git a/src/definitions/index.ts b/src/definitions/index.ts new file mode 100644 index 00000000..e4659e0a --- /dev/null +++ b/src/definitions/index.ts @@ -0,0 +1,27 @@ +export type { AddressDefinitions } from './address'; +export type { AnimalDefinitions } from './animal'; +export type { + CommerceDefinitions, + CommerceProductNameDefinitions, +} from './commerce'; +export type { CompanyDefinitions } from './company'; +export type { DatabaseDefinitions } from './database'; +export type { DateDefinitions, DateEntryDefinition } from './date'; +export type { DefinitionTypes, LocaleDefinition } from './definitions'; +export { DEFINITIONS } from './definitions'; +export type { + FinanceCurrencyEntryDefinitions, + FinanceDefinitions, +} from './finance'; +export type { HackerDefinitions } from './hacker'; +export type { InternetDefinitions } from './internet'; +export type { LoremDefinitions } from './lorem'; +export type { MusicDefinitions } from './music'; +export type { NameDefinitions, NameTitleDefinitions } from './name'; +export type { PhoneNumberDefinitions } from './phone_number'; +export type { + SystemDefinitions, + SystemMimeTypeEntryDefinitions, +} from './system'; +export type { VehicleDefinitions } from './vehicle'; +export type { WordDefinitions } from './word'; diff --git a/src/definitions/internet.ts b/src/definitions/internet.ts new file mode 100644 index 00000000..55448841 --- /dev/null +++ b/src/definitions/internet.ts @@ -0,0 +1,28 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to internet stuff. + */ +export interface InternetDefinitions { + /** + * Common top level and similar domains (e.g `de`, `co.uk`). + */ + domain_suffix: string[]; + /** + * Some email domains containing `example` (e.g. `example.com`). + */ + example_email: string[]; + /** + * Some free-mail domains used in that country (e.g. `gmail.de`). + */ + free_email: string[]; +} + +/** + * Internal: A list of all keys for the InternetDefinitions. + */ +export const INTERNET = allOf<keyof InternetDefinitions>()( + 'domain_suffix', + 'example_email', + 'free_email' +); diff --git a/src/definitions/lorem.ts b/src/definitions/lorem.ts new file mode 100644 index 00000000..eb548e46 --- /dev/null +++ b/src/definitions/lorem.ts @@ -0,0 +1,16 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to lorem texts. + */ +export interface LoremDefinitions { + /** + * Lorem words used to generate dummy texts. + */ + words: string[]; +} + +/** + * Internal: A list of all keys for the LoremDefinitions. + */ +export const LOREM = allOf<keyof LoremDefinitions>()('words'); diff --git a/src/definitions/music.ts b/src/definitions/music.ts new file mode 100644 index 00000000..1f2ffdd8 --- /dev/null +++ b/src/definitions/music.ts @@ -0,0 +1,16 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to music. + */ +export interface MusicDefinitions { + /** + * The names of some music genres. + */ + genre: string[]; +} + +/** + * Internal: A list of all keys for the MusicDefinitions. + */ +export const MUSIC = allOf<keyof MusicDefinitions>()('genre'); diff --git a/src/definitions/name.ts b/src/definitions/name.ts new file mode 100644 index 00000000..57926649 --- /dev/null +++ b/src/definitions/name.ts @@ -0,0 +1,73 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to people's names. + */ +export interface NameDefinitions { + gender: string[]; + binary_gender: string[]; + + prefix?: string[]; + female_prefix?: string[]; + male_prefix?: string[]; + + first_name?: string[]; + female_first_name?: string[]; + male_first_name?: string[]; + + middle_name?: string[]; + female_middle_name?: string[]; + male_middle_name?: string[]; + + last_name?: string[]; + female_last_name?: string[]; + male_last_name?: string[]; + + suffix: string[]; + + /** + * A list of patterns used to generate names (Fake-Pattern[]). + */ + name: string[]; + + title: NameTitleDefinitions; +} + +/** + * The possible definitions related to people's titles. + */ +export interface NameTitleDefinitions { + descriptor?: string[]; + job: string[]; + level?: string[]; +} + +/** + * Internal: A list of all keys for the NameDefinitions. + */ +export const NAME = allOf<keyof NameDefinitions>()( + 'gender', + 'binary_gender', + + 'prefix', + 'female_prefix', + 'male_prefix', + + 'first_name', + 'female_first_name', + 'male_first_name', + + 'middle_name', + 'female_middle_name', + 'male_middle_name', + + 'last_name', + 'female_last_name', + 'male_last_name', + + 'suffix', + + 'name', + + 'title' +); diff --git a/src/definitions/phone_number.ts b/src/definitions/phone_number.ts new file mode 100644 index 00000000..ed7353b5 --- /dev/null +++ b/src/definitions/phone_number.ts @@ -0,0 +1,21 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to phone numbers. + */ +export interface PhoneNumberDefinitions { + /** + * Some patterns used to generate phone numbers. + * `#` will be replaced by a random digit (0-9). + * `!` will be replaced by a random digit (2-9). + * (e.g. `!##-!##-####` -> 272-285-0453) + * + * @see Helpers.replaceSymbolWithNumber(format) + */ + formats: string[]; +} + +/** + * Internal: A list of all keys for the PhoneNumberDefinitions. + */ +export const PHONE_NUMBER = allOf<keyof PhoneNumberDefinitions>()('formats'); diff --git a/src/definitions/system.ts b/src/definitions/system.ts new file mode 100644 index 00000000..5c9039b4 --- /dev/null +++ b/src/definitions/system.ts @@ -0,0 +1,33 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to files and the system. + */ +export interface SystemDefinitions { + /** + * Returns some common file paths. + */ + directoryPaths: string[]; + /** + * The mime type definitions with some additional information. + */ + mimeTypes: { [mimeType: string]: SystemMimeTypeEntryDefinitions }; +} + +/** + * The mime type entry details. + */ +export interface SystemMimeTypeEntryDefinitions { + source?: string; + extensions?: string[]; + compressible?: boolean; + charset?: string; +} + +/** + * Internal: A list of all keys for the SystemDefinitions. + */ +export const SYSTEM = allOf<keyof SystemDefinitions>()( + 'directoryPaths', + 'mimeTypes' +); diff --git a/src/definitions/utils.ts b/src/definitions/utils.ts new file mode 100644 index 00000000..b7b826a1 --- /dev/null +++ b/src/definitions/utils.ts @@ -0,0 +1,8 @@ +// https://stackoverflow.com/a/53395649/4573065 +export type AllOf<T> = ['Needs to be all of', T]; + +export function allOf<T>(): <U extends T[]>( + ...array: U & ([T] extends [U[number]] ? unknown : AllOf<T>[]) +) => U & ([T] extends [U[number]] ? unknown : AllOf<T>[]) { + return (...array) => array; +} diff --git a/src/definitions/vehicle.ts b/src/definitions/vehicle.ts new file mode 100644 index 00000000..7fdc11f1 --- /dev/null +++ b/src/definitions/vehicle.ts @@ -0,0 +1,38 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to vehicles. + */ +export interface VehicleDefinitions { + /** + * Some types of bicycles. + */ + bicycle_type: string[]; + /** + * Some types of fuel (e.g. `Gasoline`). + */ + fuel: string[]; + /** + * Some brands of manufactures (e.g. `Tesla`). + */ + manufacturer: string[]; + /** + * Some names of models (e.g. `Fiesta`). + */ + model: string[]; + /** + * Some types of vehicles (e.g. `Minivan`). + */ + type: string[]; +} + +/** + * Internal: A list of all keys for the VehicleDefinitions. + */ +export const VEHICLE = allOf<keyof VehicleDefinitions>()( + 'bicycle_type', + 'fuel', + 'manufacturer', + 'model', + 'type' +); diff --git a/src/definitions/word.ts b/src/definitions/word.ts new file mode 100644 index 00000000..dcbe47dd --- /dev/null +++ b/src/definitions/word.ts @@ -0,0 +1,27 @@ +import { allOf } from './utils'; + +/** + * The possible definitions related to words. + */ +export interface WordDefinitions { + adjective: string[]; + adverb: string[]; + conjunction: string[]; + interjection: string[]; + noun: string[]; + preposition: string[]; + verb: string[]; +} + +/** + * Internal: A list of all keys for the WordDefinitions. + */ +export const WORD = allOf<keyof WordDefinitions>()( + 'adjective', + 'adverb', + 'conjunction', + 'interjection', + 'noun', + 'preposition', + 'verb' +); |
