-
Notifications
You must be signed in to change notification settings - Fork 0
Code standards #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Code standards #20
Changes from 8 commits
f299b7a
5e551af
b385cf6
90c9a8e
aca255c
36b421c
4418ee3
8331545
336be51
e106407
c790ac7
d0c549c
09e282d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| import { sym } from '#library/symbol.library.js'; | ||
| import { getType, protoType, asType } from '#library/type.library.js'; | ||
| import type { Type, Primitive, Nullish, Temporals, Property, GetType } from '#library/type.library.js'; | ||
|
|
||
| /** assert value is one of a list of Types */ | ||
| export const isType = <T>(obj: unknown, ...types: Type[]): obj is T => types.includes(getType(obj)); | ||
|
|
||
| /** Type-Guards: assert \<obj> is of \<type> */ | ||
| export const isPrimitive = (obj?: unknown): obj is Primitive => isType(obj, 'String', 'Number', 'BigInt', 'Boolean', 'Symbol', 'Undefined', 'Void', 'Null', 'Empty'); | ||
| export const isReference = (obj?: unknown): obj is Object => !isPrimitive(obj); | ||
| export const isIterable = <T>(obj: unknown): obj is Iterable<T> => Symbol.iterator in Object(obj) && !isString(obj); | ||
|
|
||
| export const isString = <T>(obj?: T): obj is Extract<T, string> => isType(obj, 'String'); | ||
| export const isNumber = <T>(obj?: T): obj is Extract<T, number> => isType(obj, 'Number') && isFinite(obj as number); | ||
|
|
||
| /** test if can convert String to Numeric */ | ||
| export function isNumeric(str?: any): boolean { | ||
| const type = typeof str; | ||
| switch (type) { | ||
| case 'number': return isFinite(str); | ||
| case 'bigint': return true; | ||
| case 'string': { | ||
| const val = str.trim(); | ||
| if (val.length === 0) return false; | ||
| return /^-?[0-9]+n$/.test(val) || (!isNaN(parseFloat(val)) && isFinite(Number(val))); | ||
| } | ||
| default: return false; | ||
| } | ||
| } | ||
| export const isInteger = <T>(obj?: T): obj is Extract<T, bigint> => isType(obj, 'BigInt'); | ||
| export const isIntegerLike = <T>(obj?: T): obj is Extract<T, string> => isType(obj, 'String') && /^-?[0-9]+n$/.test(obj as string); | ||
| export const isDigit = <T>(obj?: T): obj is Extract<T, number | bigint> => isType(obj, 'Number', 'BigInt'); | ||
| export const isBoolean = <T>(obj?: T): obj is Extract<T, boolean> => isType(obj, 'Boolean'); | ||
| export const isArray = <T>(obj: unknown): obj is T[] => isType(obj, 'Array'); | ||
| export const isArrayLike = <T>(obj: any): obj is ArrayLike<T> => protoType(obj) === 'Object' && 'length' in obj && Object.keys(obj).every(key => key === 'length' || !isNaN(Number(key))); | ||
| export const isObject = <T>(obj?: T): obj is Extract<T, object> => isType(obj, 'Object'); | ||
| export const isDate = <T>(obj?: T): obj is Extract<T, Date> => isType(obj, 'Date'); | ||
| export const isRegExp = <T>(obj?: T): obj is Extract<T, RegExp> => isType(obj, 'RegExp'); | ||
| export const isRegExpLike = <T>(obj?: T): obj is Extract<T, string> => isType(obj, 'String') && /^\/.*\/$/.test(obj as string); | ||
| export const isSymbol = <T>(obj?: T): obj is Extract<T, symbol> => isType(obj, 'Symbol'); | ||
| export const isSymbolFor = <T>(obj?: T): obj is Extract<T, symbol> => isType<symbol>(obj, 'Symbol') && Symbol.keyFor(obj) !== undefined; | ||
| export const isPropertyKey = (obj?: unknown): obj is PropertyKey => isType<PropertyKey>(obj, 'String', 'Number', 'Symbol'); | ||
|
|
||
| export const isNull = <T>(obj?: T): obj is Extract<T, null> => isType(obj, 'Null'); | ||
| export const isNullish = <T>(obj: T): obj is Extract<T, Nullish> => isType<undefined | null | void>(obj, 'Null', 'Undefined', 'Void', 'Empty'); | ||
| export const isUndefined = <T>(obj?: T): obj is undefined => isType<undefined>(obj, 'Undefined', 'Void', 'Empty'); | ||
| export const isDefined = <T>(obj: T): obj is NonNullable<T> => !isNullish(obj); | ||
|
|
||
| export const isClass = <T>(obj?: T): obj is Extract<T, Function> => isType(obj, 'Class'); | ||
| export const isFunction = <T>(obj?: T): obj is Extract<T, Function> => isType(obj, 'Function', 'AsyncFunction'); | ||
| export const isPromise = <T>(obj?: T): obj is Extract<T, Promise<any>> => isType(obj, 'Promise'); | ||
| export const isMap = <T, K = any, V = any>(obj?: T): obj is Extract<T, Map<K, V>> => isType(obj, 'Map'); | ||
| export const isSet = <T, K = any>(obj?: T): obj is Extract<T, Set<K>> => isType(obj, 'Set'); | ||
| export const isError = <T>(err?: T): err is Extract<T, Error> => isType(err, 'Error'); | ||
|
|
||
| export const isTemporal = <T>(obj: T): obj is Extract<T, Temporals> => protoType(obj).startsWith('Temporal.') || (!!(globalThis as any).Temporal && ( | ||
| (obj as any) instanceof (globalThis as any).Temporal.Instant || | ||
| (obj as any) instanceof (globalThis as any).Temporal.ZonedDateTime || | ||
| (obj as any) instanceof (globalThis as any).Temporal.PlainDate || | ||
| (obj as any) instanceof (globalThis as any).Temporal.PlainTime || | ||
| (obj as any) instanceof (globalThis as any).Temporal.PlainDateTime || | ||
| (obj as any) instanceof (globalThis as any).Temporal.Duration || | ||
| (obj as any) instanceof (globalThis as any).Temporal.PlainYearMonth || | ||
| (obj as any) instanceof (globalThis as any).Temporal.PlainMonthDay | ||
| )); | ||
|
|
||
| export const isInstant = <T>(obj: T): obj is Extract<T, Temporal.Instant> => isType(obj, 'Temporal.Instant') || (!!(globalThis as any).Temporal?.Instant && (obj as any) instanceof (globalThis as any).Temporal.Instant) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.Instant') || (!!obj && typeof (obj as any).toZonedDateTimeISO === 'function' && isUndefined((obj as any).timeZoneId)); | ||
| export const isZonedDateTime = <T>(obj: T): obj is Extract<T, Temporal.ZonedDateTime> => isType(obj, 'Temporal.ZonedDateTime') || (!!(globalThis as any).Temporal?.ZonedDateTime && (obj as any) instanceof (globalThis as any).Temporal.ZonedDateTime) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.ZonedDateTime') || (!!obj && typeof (obj as any).toInstant === 'function' && isDefined((obj as any).timeZoneId)); | ||
| export const isPlainDate = <T>(obj: T): obj is Extract<T, Temporal.PlainDate> => isType(obj, 'Temporal.PlainDate') || (!!(globalThis as any).Temporal?.PlainDate && (obj as any) instanceof (globalThis as any).Temporal.PlainDate) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.PlainDate') || (!!obj && typeof (obj as any).toZonedDateTime === 'function' && isUndefined((obj as any).timeZoneId) && isDefined((obj as any).daysInMonth)); | ||
| export const isPlainTime = <T>(obj: T): obj is Extract<T, Temporal.PlainTime> => isType(obj, 'Temporal.PlainTime') || (!!(globalThis as any).Temporal?.PlainTime && (obj as any) instanceof (globalThis as any).Temporal.PlainTime) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.PlainTime') || (!!obj && typeof (obj as any).toPlainDateTime === 'function' && isUndefined((obj as any).daysInMonth)); | ||
| export const isPlainDateTime = <T>(obj: T): obj is Extract<T, Temporal.PlainDateTime> => isType(obj, 'Temporal.PlainDateTime') || (!!(globalThis as any).Temporal?.PlainDateTime && (obj as any) instanceof (globalThis as any).Temporal.PlainDateTime) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.PlainDateTime') || (!!obj && typeof (obj as any).toZonedDateTime === 'function' && isUndefined((obj as any).timeZoneId) && isUndefined((obj as any).daysInMonth)); | ||
|
magmacomputing marked this conversation as resolved.
Outdated
|
||
| export const isDuration = <T>(obj: T): obj is Extract<T, Temporal.Duration> => isType(obj, 'Temporal.Duration') || (!!(globalThis as any).Temporal?.Duration && (obj as any) instanceof (globalThis as any).Temporal.Duration) || (!!obj && (obj as any)[Symbol.toStringTag] === 'Temporal.Duration'); | ||
| export const isDurationLike = <T>(obj: T): obj is Extract<T, Temporal.DurationLike | string | Temporal.Duration> => isString(obj) || isDuration(obj) || (isObject(obj) && ( | ||
| 'years' in obj || 'months' in obj || 'weeks' in obj || 'days' in obj || | ||
| 'hours' in obj || 'minutes' in obj || 'seconds' in obj || | ||
| 'milliseconds' in obj || 'microseconds' in obj || 'nanoseconds' in obj | ||
| )); | ||
| export const isZonedDateTimeLike = <T>(obj: T): obj is Extract<T, Temporal.ZonedDateTimeLike | string | Temporal.ZonedDateTime> => isString(obj) || isZonedDateTime(obj) || (isObject(obj) && ( | ||
| 'year' in obj || 'month' in obj || 'day' in obj || 'hour' in obj || 'minute' in obj || 'second' in obj || | ||
| 'millisecond' in obj || 'microsecond' in obj || 'nanosecond' in obj || 'monthCode' in obj || 'offset' in obj || 'timeZone' in obj || 'calendar' in obj | ||
| )); | ||
| export const isPlainYearMonth = <T>(obj: T): obj is Extract<T, Temporal.PlainYearMonth> => isType(obj, 'Temporal.PlainYearMonth') || (!!(globalThis as any).Temporal?.PlainYearMonth && (obj as any) instanceof (globalThis as any).Temporal.PlainYearMonth); | ||
| export const isPlainMonthDay = <T>(obj: T): obj is Extract<T, Temporal.PlainMonthDay> => isType(obj, 'Temporal.PlainMonthDay') || (!!(globalThis as any).Temporal?.PlainMonthDay && (obj as any) instanceof (globalThis as any).Temporal.PlainMonthDay); | ||
|
|
||
| // non-standard Objects | ||
| export const isEnum = <T, E extends Property<any>>(obj?: T): obj is Extract<T, GetType<'Enumify', E>> => isType(obj, 'Enumify'); | ||
| export const isPledge = <T, P = any>(obj?: T): obj is Extract<T, GetType<'Pledge', P>> => isType(obj, 'Pledge'); | ||
|
|
||
| /** assert value for secure() */ | ||
| export const isExtensible = (obj: any): obj is any => !!(obj?.[sym.$Extensible]); | ||
| export const isTarget = (obj: any): obj is any => !!(obj?.[sym.$Target]); | ||
|
|
||
| /** object has no values */ | ||
| export const isEmpty = <T>(obj?: T) => false | ||
| || isNullish(obj) | ||
| || (isObject(obj) && (Reflect.ownKeys(obj).length === 0)) | ||
| || (isString(obj) && (obj.trim().length === 0)) | ||
| || (isNumber(obj) && (isNaN(obj as any) === true)) | ||
| || (isArray(obj) && (obj.length === 0)) | ||
| || (isSet(obj) && (obj.size === 0)) | ||
| || (isMap(obj) && (obj.size === 0)) | ||
|
magmacomputing marked this conversation as resolved.
|
||
|
|
||
| export function assertCondition(condition: boolean, message?: string): asserts condition { | ||
| if (!condition) | ||
| throw new Error(message); | ||
| } | ||
| export function assertString(str: unknown): asserts str is string { assertCondition(isString(str), `Invalid string: ${str}`) }; | ||
| export function assertNever(val: never): asserts val is never { throw new Error(`Unexpected object: ${val}`) }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| import { Immutable } from '#library/class.library.js'; | ||
| import lib, { markConfig } from '#library/symbol.library.js'; | ||
| import { asType, isObject, isEmpty, type ValueOf } from '#library/type.library.js'; | ||
| import { sym, markConfig } from '#library/symbol.library.js'; | ||
| import { asType } from '#library/type.library.js'; | ||
| import { isObject, isEmpty } from '#library/assertion.library.js'; | ||
| import type { ValueOf } from '#library/type.library.js'; | ||
|
|
||
| const Method = { | ||
| Log: 'log', | ||
|
|
@@ -10,22 +12,33 @@ const Method = { | |
| Error: 'error', | ||
| } as const | ||
|
|
||
| const Level = { | ||
| [Method.Error]: 1, | ||
| [Method.Warn]: 2, | ||
| [Method.Info]: 3, | ||
| [Method.Log]: 3, | ||
| [Method.Debug]: 4, | ||
| } as const; | ||
|
|
||
| /** | ||
| * provide standard logging methods to the console for a class | ||
| */ | ||
| @Immutable | ||
| export class Logify { | ||
| #name: string; | ||
| #opts: Logify.Constructor = { [lib.$Logify]: true }; | ||
| #opts: Logify.Constructor = { [sym.$Logify]: true }; | ||
|
|
||
| /** | ||
| * if {catch:true} then show a warning on the console and return | ||
| * otherwise show an error on the console and re-throw the error | ||
| */ | ||
| #trap(method: Logify.Method, ...msg: any[]) { | ||
| const config = (isObject(msg[0]) && (msg[0] as any)[lib.$Logify] === true) ? msg.shift() : this.#opts; | ||
| const config = (isObject(msg[0]) && (msg[0] as any)[sym.$Logify] === true) ? msg.shift() : this.#opts; | ||
| const currentLevel = (typeof config.debug === 'number') ? config.debug : (config.debug ? Level[Method.Debug] : Level[Method.Error]); | ||
| const methodLevel = Level[method] ?? 0; | ||
|
Comment on lines
+47
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doc mismatch between The JSDoc here (Line 117) and the runtime mapping (Line 49) both say 🤖 Prompt for AI Agents |
||
|
|
||
| if (methodLevel > currentLevel) return; | ||
|
|
||
| if (method === Method.Debug && !config.debug) return; | ||
|
|
||
| const output = msg.map(m => { | ||
| if (m instanceof Error) return m.message; | ||
|
|
@@ -89,9 +102,9 @@ export namespace Logify { | |
| export type Method = ValueOf<typeof Method> | ||
|
|
||
| export interface Constructor { | ||
| debug?: boolean | undefined, | ||
| debug?: boolean | number | undefined, | ||
| catch?: boolean | undefined, | ||
| silent?: boolean | undefined, | ||
| [lib.$Logify]?: boolean | undefined | ||
| [sym.$Logify]?: boolean | undefined | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.