Lazy decoration (part 1, metadata) (#4139)
* Make decoration lazy * Extract common * w/ Extrinsics * Storage lazy * V14 -> Latest * Util * Adjust to use create/lazy * Adjust * Add tests for errors & events (long-time outstanding)
This commit is contained in:
@@ -18,9 +18,7 @@ export function lazyMethod <T, K> (result: Record<string, T>, item: K, creator:
|
||||
});
|
||||
}
|
||||
|
||||
export function lazyMethods <T, K> (items: K[], creator: (v: K) => T, getName?: (m: K) => string): Record<string, T> {
|
||||
const result: Record<string, T> = {};
|
||||
|
||||
export function lazyMethods <T, K> (items: K[], creator: (v: K) => T, getName?: (m: K) => string, result: Record<string, T> = {}): Record<string, T> {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
lazyMethod(result, items[i], creator, getName);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,48 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { MetadataLatest } from '../../../interfaces';
|
||||
import type { MetadataLatest, PalletConstantMetadataLatest, PalletMetadataLatest } from '../../../interfaces';
|
||||
import type { Registry } from '../../../types';
|
||||
import type { ConstantCodec, Constants, ModuleConstants } from '../types';
|
||||
import type { ConstantCodec, Constants } from '../types';
|
||||
|
||||
import { hexToU8a, stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { lazyMethod, lazyMethods } from '../../../create/lazy';
|
||||
import { objectNameToCamel } from '../util';
|
||||
|
||||
function createConstantCodec (registry: Registry, constant: PalletConstantMetadataLatest): ConstantCodec {
|
||||
const codec = registry.createTypeUnsafe(registry.createLookupType(constant.type), [hexToU8a(constant.value.toHex())]) as ConstantCodec;
|
||||
|
||||
(codec as unknown as Record<string, unknown>).meta = constant;
|
||||
|
||||
return codec;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function decorateConstants (registry: Registry, { pallets }: MetadataLatest, _metaVersion: number): Constants {
|
||||
export function decorateConstants (registry: Registry, { pallets }: MetadataLatest, _version: number): Constants {
|
||||
const result: Constants = {};
|
||||
|
||||
const lazySection = ({ constants, name }: PalletMetadataLatest): void => {
|
||||
lazyMethod(
|
||||
result,
|
||||
constants,
|
||||
(constants: PalletConstantMetadataLatest[]) =>
|
||||
lazyMethods(
|
||||
constants,
|
||||
(constant: PalletConstantMetadataLatest) =>
|
||||
createConstantCodec(registry, constant),
|
||||
objectNameToCamel
|
||||
),
|
||||
() => stringCamelCase(name)
|
||||
);
|
||||
};
|
||||
|
||||
for (let p = 0; p < pallets.length; p++) {
|
||||
const { constants, name } = pallets[p];
|
||||
const pallet = pallets[p];
|
||||
|
||||
if (!constants.isEmpty) {
|
||||
const newModule: ModuleConstants = {};
|
||||
|
||||
for (let c = 0; c < constants.length; c++) {
|
||||
const meta = constants[c];
|
||||
const codec = registry.createTypeUnsafe(registry.createLookupType(meta.type), [hexToU8a(meta.value.toHex())]) as unknown;
|
||||
|
||||
(codec as Record<string, unknown>).meta = meta;
|
||||
newModule[stringCamelCase(meta.name)] = codec as ConstantCodec;
|
||||
}
|
||||
|
||||
// For access, we change the index names, i.e. Democracy.EnactmentPeriod -> democracy.enactmentPeriod
|
||||
result[stringCamelCase(name)] = newModule;
|
||||
if (!pallet.constants.isEmpty) {
|
||||
lazySection(pallet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import rpcMetadata from '@polkadot/types-support/metadata/static-substrate';
|
||||
|
||||
import { TypeRegistry } from '../../../create';
|
||||
import { Metadata } from '../../Metadata';
|
||||
import { decorateErrors } from '..';
|
||||
|
||||
const registry = new TypeRegistry();
|
||||
const metadata = new Metadata(registry, rpcMetadata);
|
||||
|
||||
registry.setMetadata(metadata);
|
||||
|
||||
const errors = decorateErrors(registry, metadata.asLatest, metadata.version);
|
||||
|
||||
describe('decorateErrors', (): void => {
|
||||
it('should return known errors', (): void => {
|
||||
expect(errors.balances.InsufficientBalance).toBeDefined();
|
||||
});
|
||||
|
||||
it('has the correct metadata for known errors', (): void => {
|
||||
expect(
|
||||
errors.proxy.NotProxy.meta.toJSON()
|
||||
).toEqual({
|
||||
args: [],
|
||||
docs: ['Sender is not a proxy of the account to be proxied.'],
|
||||
fields: [],
|
||||
index: 2,
|
||||
name: 'NotProxy'
|
||||
});
|
||||
});
|
||||
|
||||
it('should check against a specific error', (): void => {
|
||||
expect(
|
||||
errors.system.InvalidSpecName.is(
|
||||
registry.createType('DispatchErrorModule', {
|
||||
error: 0,
|
||||
index: 0
|
||||
})
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,16 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { DispatchErrorModule, MetadataLatest, PortableRegistry, SiField, SiVariant } from '../../../interfaces';
|
||||
import type { DispatchErrorModule, MetadataLatest, PalletMetadataLatest, PortableRegistry, SiField, SiVariant } from '../../../interfaces';
|
||||
import type { Text, u8 } from '../../../primitive';
|
||||
import type { Registry } from '../../../types';
|
||||
import type { Errors, ModuleErrors } from '../types';
|
||||
import type { Errors, IsError } from '../types';
|
||||
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { lazyMethod, lazyMethods } from '../../../create/lazy';
|
||||
import { objectNameToString } from '../util';
|
||||
|
||||
interface ItemMeta {
|
||||
args: string[];
|
||||
name: Text;
|
||||
@@ -25,33 +28,39 @@ export function variantToMeta (lookup: PortableRegistry, variant: SiVariant): It
|
||||
};
|
||||
}
|
||||
|
||||
function createIsError (registry: Registry, lookup: PortableRegistry, variant: SiVariant, sectionIndex: number): IsError {
|
||||
return {
|
||||
is: ({ error, index }: DispatchErrorModule) =>
|
||||
index.eq(sectionIndex) &&
|
||||
error.eq(variant.index),
|
||||
meta: registry.createType('ErrorMetadataLatest', variantToMeta(lookup, variant))
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function decorateErrors (registry: Registry, { lookup, pallets }: MetadataLatest, metaVersion: number): Errors {
|
||||
export function decorateErrors (registry: Registry, { lookup, pallets }: MetadataLatest, version: number): Errors {
|
||||
const result: Errors = {};
|
||||
|
||||
const lazySection = ({ errors, name }: PalletMetadataLatest, sectionIndex: number): void => {
|
||||
lazyMethod(
|
||||
result,
|
||||
lookup.getSiType(errors.unwrap().type).def.asVariant.variants,
|
||||
(variants: SiVariant[]) =>
|
||||
lazyMethods(
|
||||
variants,
|
||||
(variant: SiVariant) =>
|
||||
createIsError(registry, lookup, variant, sectionIndex),
|
||||
objectNameToString
|
||||
),
|
||||
() => stringCamelCase(name)
|
||||
);
|
||||
};
|
||||
|
||||
for (let p = 0; p < pallets.length; p++) {
|
||||
const { errors, index, name } = pallets[p];
|
||||
const pallet = pallets[p];
|
||||
|
||||
if (errors.isSome) {
|
||||
const sectionIndex = metaVersion >= 12
|
||||
? index.toNumber()
|
||||
: p;
|
||||
const newModule: ModuleErrors = {};
|
||||
const { variants } = lookup.getSiType(errors.unwrap().type).def.asVariant;
|
||||
|
||||
for (let v = 0; v < variants.length; v++) {
|
||||
const variant = variants[v];
|
||||
|
||||
// we don't camelCase the error name
|
||||
newModule[variant.name.toString()] = {
|
||||
is: ({ error, index }: DispatchErrorModule) =>
|
||||
index.eq(sectionIndex) &&
|
||||
error.eq(variant.index),
|
||||
meta: registry.createType('ErrorMetadataLatest', variantToMeta(lookup, variant))
|
||||
};
|
||||
}
|
||||
|
||||
result[stringCamelCase(name)] = newModule;
|
||||
if (pallet.errors.isSome) {
|
||||
lazySection(pallet, version >= 12 ? pallet.index.toNumber() : p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { AnyTuple, IEvent } from '../../../types';
|
||||
|
||||
import rpcMetadata from '@polkadot/types-support/metadata/static-substrate';
|
||||
|
||||
import { TypeRegistry } from '../../../create';
|
||||
import { Metadata } from '../../Metadata';
|
||||
import { decorateEvents } from '..';
|
||||
|
||||
const registry = new TypeRegistry();
|
||||
const metadata = new Metadata(registry, rpcMetadata);
|
||||
|
||||
registry.setMetadata(metadata);
|
||||
|
||||
const events = decorateEvents(registry, metadata.asLatest, metadata.version);
|
||||
|
||||
describe('decorateEvents', (): void => {
|
||||
it('should return known errors', (): void => {
|
||||
expect(events.balances.Transfer).toBeDefined();
|
||||
});
|
||||
|
||||
it('has the correct metadata for known errors', (): void => {
|
||||
expect(
|
||||
events.staking.Rewarded.meta.toJSON()
|
||||
).toEqual({
|
||||
args: ['AccountId32', 'u128'],
|
||||
docs: [
|
||||
'The nominator has been rewarded by this amount. \\[stash, amount\\]'
|
||||
],
|
||||
fields: [
|
||||
{ docs: [], name: null, type: 0, typeName: 'T::AccountId' },
|
||||
{ docs: [], name: null, type: 6, typeName: 'BalanceOf<T>' }
|
||||
],
|
||||
index: 1,
|
||||
name: 'Rewarded'
|
||||
});
|
||||
});
|
||||
|
||||
it('should check against a specific error', (): void => {
|
||||
expect(
|
||||
events.system.ExtrinsicSuccess.is({ index: [0, 0] } as unknown as IEvent<AnyTuple>)
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,44 +1,54 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { MetadataLatest, PalletMetadataV14 } from '../../../interfaces';
|
||||
import type { MetadataLatest, PalletMetadataLatest, PortableRegistry, SiVariant } from '../../../interfaces';
|
||||
import type { AnyTuple, IEvent, Registry } from '../../../types';
|
||||
import type { Events, ModuleEvents } from '../types';
|
||||
import type { Events, IsEvent } from '../types';
|
||||
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { lazyMethod, lazyMethods } from '../../../create/lazy';
|
||||
import { variantToMeta } from '../errors';
|
||||
import { objectNameToString } from '../util';
|
||||
|
||||
export function filterEventsSome ({ events }: PalletMetadataV14): boolean {
|
||||
export function filterEventsSome ({ events }: PalletMetadataLatest): boolean {
|
||||
return events.isSome;
|
||||
}
|
||||
|
||||
function createIsEvent (registry: Registry, lookup: PortableRegistry, variant: SiVariant, sectionIndex: number): IsEvent<AnyTuple> {
|
||||
return {
|
||||
is: <T extends AnyTuple> (eventRecord: IEvent<AnyTuple>): eventRecord is IEvent<T> =>
|
||||
sectionIndex === eventRecord.index[0] &&
|
||||
variant.index.eq(eventRecord.index[1]),
|
||||
meta: registry.createType('EventMetadataLatest', variantToMeta(lookup, variant))
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function decorateEvents (registry: Registry, { lookup, pallets }: MetadataLatest, metaVersion: number): Events {
|
||||
const filtered = pallets.filter(filterEventsSome);
|
||||
export function decorateEvents (registry: Registry, { lookup, pallets }: MetadataLatest, version: number): Events {
|
||||
const result: Events = {};
|
||||
|
||||
const lazySection = ({ events, name }: PalletMetadataLatest, sectionIndex: number): void => {
|
||||
lazyMethod(
|
||||
result,
|
||||
lookup.getSiType(events.unwrap().type).def.asVariant.variants,
|
||||
(variants: SiVariant[]) =>
|
||||
lazyMethods(
|
||||
variants,
|
||||
(variant: SiVariant) =>
|
||||
createIsEvent(registry, lookup, variant, sectionIndex),
|
||||
objectNameToString
|
||||
),
|
||||
() => stringCamelCase(name)
|
||||
);
|
||||
};
|
||||
|
||||
const filtered = pallets.filter(filterEventsSome);
|
||||
|
||||
for (let p = 0; p < filtered.length; p++) {
|
||||
const { events, index, name } = filtered[p];
|
||||
const sectionIndex = metaVersion >= 12
|
||||
? index.toNumber()
|
||||
: p;
|
||||
const newModule: ModuleEvents = {};
|
||||
const { variants } = lookup.getSiType(events.unwrap().type).def.asVariant;
|
||||
const pallet = filtered[p];
|
||||
|
||||
for (let v = 0; v < variants.length; v++) {
|
||||
const variant = variants[v];
|
||||
|
||||
// we don't camelCase the event name
|
||||
newModule[variant.name.toString()] = {
|
||||
is: <T extends AnyTuple> (eventRecord: IEvent<AnyTuple>): eventRecord is IEvent<T> =>
|
||||
eventRecord.index[0] === sectionIndex &&
|
||||
variant.index.eq(eventRecord.index[1]),
|
||||
meta: registry.createType('EventMetadataLatest', variantToMeta(lookup, variant))
|
||||
};
|
||||
}
|
||||
|
||||
result[stringCamelCase(name)] = newModule;
|
||||
lazySection(pallet, version >= 12 ? pallet.index.toNumber() : p);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,56 +1,73 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { MetadataLatest, PalletMetadataV14 } from '../../../interfaces';
|
||||
import type { Registry } from '../../../types';
|
||||
import type { Extrinsics, ModuleExtrinsics } from '../types';
|
||||
import type { MetadataLatest, PalletMetadataLatest, PortableRegistry, SiVariant } from '../../../interfaces';
|
||||
import type { CallFunction, Registry } from '../../../types';
|
||||
import type { Extrinsics } from '../types';
|
||||
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { lazyMethod, lazyMethods } from '../../../create/lazy';
|
||||
import { getSiName } from '../../util';
|
||||
import { objectNameToCamel } from '../util';
|
||||
import { createUnchecked } from './createUnchecked';
|
||||
|
||||
export function filterCallsSome ({ calls }: PalletMetadataV14): boolean {
|
||||
export function filterCallsSome ({ calls }: PalletMetadataLatest): boolean {
|
||||
return calls.isSome;
|
||||
}
|
||||
|
||||
function createCallFunction (registry: Registry, lookup: PortableRegistry, variant: SiVariant, sectionIndex: number, sectionName: string): CallFunction {
|
||||
const { fields, index } = variant;
|
||||
const args = new Array<Record<string, unknown>>(fields.length);
|
||||
|
||||
for (let a = 0; a < fields.length; a++) {
|
||||
const { name, type, typeName } = fields[a];
|
||||
|
||||
args[a] = {
|
||||
name: stringCamelCase(name.unwrapOr(`param${a}`)),
|
||||
type: getSiName(lookup, type),
|
||||
...(typeName.isSome
|
||||
? { typeName: typeName.unwrap() }
|
||||
: {}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
return createUnchecked(
|
||||
registry,
|
||||
sectionName,
|
||||
new Uint8Array([sectionIndex, index.toNumber()]),
|
||||
registry.createType('FunctionMetadataLatest', { ...variant, args })
|
||||
);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function decorateExtrinsics (registry: Registry, { lookup, pallets }: MetadataLatest, metaVersion: number): Extrinsics {
|
||||
const filtered = pallets.filter(filterCallsSome);
|
||||
export function decorateExtrinsics (registry: Registry, { lookup, pallets }: MetadataLatest, version: number): Extrinsics {
|
||||
const result: Extrinsics = {};
|
||||
|
||||
for (let p = 0; p < filtered.length; p++) {
|
||||
const { calls, index, name } = filtered[p];
|
||||
const lazySection = ({ calls, name }: PalletMetadataLatest, sectionIndex: number): void => {
|
||||
const sectionName = stringCamelCase(name);
|
||||
const sectionIndex = metaVersion >= 12
|
||||
? index.toNumber()
|
||||
: p;
|
||||
const newModule: ModuleExtrinsics = {};
|
||||
const { variants } = lookup.getSiType(calls.unwrap().type).def.asVariant;
|
||||
|
||||
for (let v = 0; v < variants.length; v++) {
|
||||
const variant = variants[v];
|
||||
const args = new Array<Record<string, unknown>>(variant.fields.length);
|
||||
lazyMethod(
|
||||
result,
|
||||
lookup.getSiType(calls.unwrap().type).def.asVariant.variants,
|
||||
(variants: SiVariant[]) =>
|
||||
lazyMethods(
|
||||
variants,
|
||||
(variant: SiVariant) =>
|
||||
createCallFunction(registry, lookup, variant, sectionIndex, sectionName),
|
||||
objectNameToCamel
|
||||
),
|
||||
() => sectionName
|
||||
);
|
||||
};
|
||||
|
||||
for (let a = 0; a < variant.fields.length; a++) {
|
||||
const { name, type, typeName } = variant.fields[a];
|
||||
const filtered = pallets.filter(filterCallsSome);
|
||||
|
||||
args[a] = {
|
||||
name: stringCamelCase(name.unwrapOr(`param${a}`)),
|
||||
type: getSiName(lookup, type),
|
||||
...(typeName.isSome
|
||||
? { typeName: typeName.unwrap() }
|
||||
: {}
|
||||
)
|
||||
};
|
||||
}
|
||||
for (let p = 0; p < filtered.length; p++) {
|
||||
const pallet = filtered[p];
|
||||
|
||||
const callMetadata = registry.createType('FunctionMetadataLatest', { ...variant, args });
|
||||
|
||||
newModule[stringCamelCase(callMetadata.name)] = createUnchecked(registry, sectionName, new Uint8Array([sectionIndex, callMetadata.index.toNumber()]), callMetadata);
|
||||
}
|
||||
|
||||
result[sectionName] = newModule;
|
||||
lazySection(pallet, version >= 12 ? pallet.index.toNumber() : p);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { MetadataLatest } from '../../../interfaces';
|
||||
import type { MetadataLatest, PalletMetadataLatest, StorageEntryMetadataLatest } from '../../../interfaces';
|
||||
import type { Registry } from '../../../types';
|
||||
import type { ModuleStorage, Storage } from '../types';
|
||||
import type { Storage } from '../types';
|
||||
|
||||
import { stringCamelCase, stringLowerFirst } from '@polkadot/util';
|
||||
import { stringCamelCase } from '@polkadot/util';
|
||||
|
||||
import { lazyMethod, lazyMethods } from '../../../create/lazy';
|
||||
import { objectNameFirstLower } from '../util';
|
||||
import { createFunction, createKeyRaw } from './createFunction';
|
||||
import { getStorage } from './getStorage';
|
||||
import { createRuntimeFunction } from './util';
|
||||
@@ -16,35 +18,37 @@ import { createRuntimeFunction } from './util';
|
||||
export function decorateStorage (registry: Registry, { pallets }: MetadataLatest, _metaVersion: number): Storage {
|
||||
const result: Storage = getStorage(registry);
|
||||
|
||||
const lazySection = ({ name, storage }: PalletMetadataLatest): void => {
|
||||
const section = stringCamelCase(name);
|
||||
const { items, prefix: _prefix } = storage.unwrap();
|
||||
const prefix = _prefix.toString();
|
||||
|
||||
lazyMethod(
|
||||
result,
|
||||
items,
|
||||
(items: StorageEntryMetadataLatest[]) =>
|
||||
lazyMethods(
|
||||
items,
|
||||
(meta: StorageEntryMetadataLatest) =>
|
||||
createFunction(registry, { meta, method: meta.name.toString(), prefix, section }, {}),
|
||||
objectNameFirstLower,
|
||||
{
|
||||
palletVersion: createRuntimeFunction(
|
||||
{ method: 'palletVersion', prefix, section },
|
||||
createKeyRaw(registry, { method: ':__STORAGE_VERSION__:', prefix: name.toString() }, [], [], []),
|
||||
{ docs: 'Returns the current pallet version from storage', type: 'u16' }
|
||||
)(registry)
|
||||
}
|
||||
),
|
||||
() => section
|
||||
);
|
||||
};
|
||||
|
||||
for (let p = 0; p < pallets.length; p++) {
|
||||
const { name, storage } = pallets[p];
|
||||
const pallet = pallets[p];
|
||||
|
||||
if (storage.isSome) {
|
||||
const section = stringCamelCase(name);
|
||||
const { items, prefix: _prefix } = storage.unwrap();
|
||||
const prefix = _prefix.toString();
|
||||
const newModule: ModuleStorage = {
|
||||
palletVersion: createRuntimeFunction(
|
||||
{ method: 'palletVersion', prefix, section },
|
||||
createKeyRaw(registry, { method: ':__STORAGE_VERSION__:', prefix: name.toString() }, [], [], []),
|
||||
{ docs: 'Returns the current pallet version from storage', type: 'u16' }
|
||||
)(registry)
|
||||
};
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const meta = items[i];
|
||||
const method = meta.name.toString();
|
||||
|
||||
// For access, we change the index names, i.e. System.Account -> system.account
|
||||
newModule[stringLowerFirst(method)] = createFunction(registry, {
|
||||
meta,
|
||||
method,
|
||||
prefix,
|
||||
section
|
||||
}, {});
|
||||
}
|
||||
|
||||
result[section] = newModule;
|
||||
if (pallet.storage.isSome) {
|
||||
lazySection(pallet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2017-2021 @polkadot/types authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Text } from '../../primitive';
|
||||
|
||||
import { stringCamelCase, stringLowerFirst } from '@polkadot/util';
|
||||
|
||||
export function objectNameFirstLower ({ name }: { name: string | Text }): string {
|
||||
return stringLowerFirst(name);
|
||||
}
|
||||
|
||||
export function objectNameToCamel ({ name }: { name: string | Text }): string {
|
||||
return stringCamelCase(name);
|
||||
}
|
||||
|
||||
export function objectNameToString ({ name }: { name: string | Text }): string {
|
||||
return name.toString();
|
||||
}
|
||||
Reference in New Issue
Block a user