• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16package std.core;
17
18/**
19 * @deprecated
20*/
21export type NullishType = Any
22
23/**
24 * @deprecated
25*/
26export type NullableType = Object | null
27
28/**
29 * @deprecated
30*/
31export type Nullish<T> = T | null | undefined
32
33export type PropertyKey = string
34
35export const ARRAY_LENGTH_MEMBER_NAME      = "length"
36export const FUNCTION_LENGTH_MEMBER_NAME   = "length"
37export const FUNCTION_NAME_MEMBER_NAME     = "name"
38
39export const OBJECT_TO_STRING_MEMBER_NAME: string          = "toString"
40export const OBJECT_TO_LOCALE_STRING_MEMBER_NAME: string   = "toLocaleString"
41export const OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME: string   = "hasOwnProperty"
42
43type EntryType = [PropertyKey, NullishType]
44type NullishEntryType = EntryType | null | undefined
45
46/**
47 * `object` is an alias for type `Object`
48 */
49export type object = Object;
50
51/**
52 * Common ancestor amongst all other classes
53 */
54export class Object {
55    /**
56    * Constructs a new blank Object
57    */
58    constructor () {};
59
60    /**
61    * Converts this object to a string
62    *
63    * @returns result of the conversion
64    */
65    public toString(): String {
66        return Value.of(this).toString()
67    }
68
69    /**
70    * Converts this object to locale-specific string representation
71    *
72    * @returns result of the conversion
73    */
74    public toLocaleString(): String {
75        return Value.of(this).toLocaleString()
76    }
77
78    /**
79    * Returns a hash code (integer representation) for this instance
80    *
81    * @returns representation of this instance
82    */
83    public $_hashCode(): int {
84        return Runtime.getHashCode(this);
85    }
86
87    /**
88     * Returns an array of a given record property names
89     *
90     * @param rec a record
91     *
92     * @returns an array of strings representing the given record's property names
93     */
94    public static keys(rec: Record<PropertyKey, NullishType>): string[] {
95        const keys: string[] = new string[rec.size.toInt()]
96
97        let i = 0
98        for (const key of rec.keys()) {
99            keys[i] = key
100            i++
101        }
102
103        return keys
104    }
105
106    private static generateKeyArray(length: Number): string[] {
107        const len = length.toInt();
108        if (len == 0) {
109            return new string[0]
110        }
111        let res: string[] = new string[len]
112        for (let i = 0; i < len; i++) {
113            res[i] = new Int(i).toString()
114        }
115        return res
116    }
117
118    /**
119    * Returns the names of the fields of an object
120    *
121    * @param o an object
122    *
123    * @returns an array of strings representing the given object's own string-keyed field keys.
124    */
125    public static keys(o: Object): string[] {
126        // Char, Boolean and Numeric types doesn't have keys
127        if (o instanceof Char ||
128            o instanceof Boolean ||
129            o instanceof Byte ||
130            o instanceof Short ||
131            o instanceof Int ||
132            o instanceof Long ||
133            o instanceof Float ||
134            o instanceof Double) {
135            return new string[0]
136        }
137        // "Keys" for the string type is enumeration from 0 to str.length - 1
138        if (o instanceof String) {
139            return Object.generateKeyArray(o.getLength())
140        } else if (o instanceof Array) {
141            return Object.generateKeyArray(o.length)
142        }
143        const t = Type.of(o)
144        if (t instanceof ClassType) {
145            const ct = t as ClassType
146            const fnum = ct.getFieldsNum()
147            if (fnum == 0) {
148                return new string[0]
149            }
150            let n: int = 0
151            for (let i = 0; i < fnum; i++) {
152                if (!ct.getField(i).isStatic()) {
153                    n++
154                }
155            }
156            let res: string[] = new string[n]
157            let j: int = 0
158            for (let i = 0; i < fnum; i++) {
159                let f = ct.getField(i)
160                if (!f.isStatic()) {
161                    res[j] = f.getName()
162                    j++
163                }
164            }
165            return res
166        } else if (t instanceof ArrayType) {
167            const av = Value.of(o) as ArrayValue
168            return Object.generateKeyArray(av.getLength())
169        } else if (t instanceof LambdaType) {
170            return new string[0]
171        } else if (t instanceof EnumType) {
172            // NOTE(shumilov-petr): Not implemented
173            throw new Error("Not implemented")
174        } else if (t instanceof UnionType) {
175            // NOTE(shumilov-petr): Not implemented
176            throw new Error("Not implemented")
177        } else if (t instanceof TupleType) {
178            // NOTE(shumilov-petr): Not implemented
179            throw new Error("Not implemented")
180        }
181
182        throw new AssertionError("Invalid object type");
183    }
184
185    public static values(rec: Record<PropertyKey, NullishType>): NullishType[] {
186        const vals: NullishType[] = new NullishType[rec.size.toInt()]
187
188        let i = 0
189        for (let val of rec.values()) {
190            vals[i] = val
191            i++
192        }
193
194        return vals
195    }
196
197    /**
198    * Returns the values of the fields of an object
199    *
200    * @param o an object
201    *
202    * @returns an array containing the given object's own string-keyed field values
203    */
204    public static values(o: Object): NullishType[] {
205        if (o instanceof Char ||
206            o instanceof Boolean ||
207            o instanceof Byte ||
208            o instanceof Short ||
209            o instanceof Int ||
210            o instanceof Long ||
211            o instanceof Float ||
212            o instanceof Double) {
213            return new NullishType[0]
214        }
215        if (o instanceof String) {
216            const sv = o as string
217            const len = sv.getLength()
218            if (len == 0) {
219                return new NullishType[0]
220            }
221            let res: NullishType[] = new NullishType[len]
222            for (let i = 0; i < len; i++) {
223                // NOTE(shumilov-petr): must be replaced by `sv.charAt(i) as string` when #15731 will be fixed
224                res[i] = new Char(sv.charAt(i)).toString()
225            }
226            return res
227        }
228        const t = Type.of(o)
229        if (t instanceof ClassType) {
230            const cv = Value.of(o) as ClassValue
231            if (cv.getFieldsNum() == 0) {
232                return new NullishType[0]
233            }
234            const keys = Object.keys(o)
235            const len = keys.length
236            let res: NullishType[] = new NullishType[len]
237            for (let i = 0; i < len; i++) {
238                res[i] = cv.getFieldByName(keys[i]).getData()
239            }
240            return res
241        } else if (t instanceof ArrayType) {
242            const av = Value.of(o) as ArrayValue
243            const len = av.getLength()
244            if (len == 0) {
245                return new NullishType[0]
246            }
247            let res: NullishType[] = new NullishType[len.toInt()]
248            for (let i = 0; i < len; i++) {
249                res[i] = av.getElement(i).getData()
250            }
251            return res
252        } else if (t instanceof LambdaType) {
253            return new NullishType[0]
254        } else if (t instanceof EnumType) {
255            // NOTE(shumilov-petr): Not implemented
256            throw new Error("Not implemented")
257        } else if (t instanceof UnionType) {
258            // NOTE(shumilov-petr): Not implemented
259            throw new Error("Not implemented")
260        } else if (t instanceof TupleType) {
261            // NOTE(shumilov-petr): Not implemented
262            throw new Error("Not implemented")
263        }
264
265        throw new AssertionError("Invalid object type")
266    }
267
268    /**
269    * Returns an array of key/values of properties of a record
270    *
271    * @param rec record that contains the fields
272    *
273    * @returns array representation of key/value
274    */
275    public static entries(rec: Record<PropertyKey, NullishType>): NullishEntryType[] {
276        const entries: NullishEntryType[] = new NullishEntryType[rec.size.toInt()]
277
278        let i = 0
279        for (const entry of rec.entries()) {
280            entries[i] = entry
281            i++
282        }
283
284        return entries
285    }
286
287    /**
288    * Returns an array of key/values of properties of an object
289    *
290    * @param o object that contains the fields
291    *
292    * @returns array representation of key/value
293    */
294    public static entries(o: Object): NullishEntryType[] {
295        if (o instanceof Char ||
296            o instanceof Boolean ||
297            o instanceof Byte ||
298            o instanceof Short ||
299            o instanceof Int ||
300            o instanceof Long ||
301            o instanceof Float ||
302            o instanceof Double) {
303            return new NullishEntryType[0]
304        }
305        if (o instanceof String) {
306            const sv = o as string
307            const len = sv.getLength()
308            if (len == 0) {
309                return new NullishEntryType[0]
310            }
311            let res: NullishEntryType[] = new NullishEntryType[len]
312            for (let i = 0; i < len; i++) {
313                res[i] = [new Int(i).toString(), new Char(sv.charAt(i)).toString()] as EntryType
314            }
315            return res
316        }
317        const t = Type.of(o)
318        if (t instanceof ClassType) {
319            const cv = Value.of(o) as ClassValue
320            if (cv.getFieldsNum() == 0) {
321                return new NullishEntryType[0]
322            }
323            const keys = Object.keys(o)
324            const len = keys.length
325            let res: NullishEntryType[] = new NullishEntryType[len]
326            for (let i = 0; i < len; i++) {
327                res[i] = [keys[i], cv.getFieldByName(keys[i]).getData()] as EntryType
328            }
329            return res
330        } else if (t instanceof ArrayType) {
331            const av = Value.of(o) as ArrayValue
332            const len = av.getLength()
333            if (len == 0) {
334                return new NullishEntryType[0]
335            }
336            let res: NullishEntryType[] = new NullishEntryType[len.toInt()]
337            for (let i = 0; i < len; i++) {
338                res[i] = [new Int(i).toString(), av.getElement(i).getData()] as EntryType
339            }
340            return res
341        } else if (t instanceof LambdaType) {
342            return new NullishEntryType[0]
343        } else if (t instanceof EnumType) {
344            // NOTE(shumilov-petr): Not implemented
345            throw new Error("Not implemented")
346        } else if (t instanceof UnionType) {
347            // NOTE(shumilov-petr): Not implemented
348            throw new Error("Not implemented")
349        } else if (t instanceof TupleType) {
350            // NOTE(shumilov-petr): Not implemented
351            throw new Error("Not implemented")
352        }
353
354        throw new AssertionError("Invalid object type")
355    }
356
357    public static getOwnPropertyNames(rec: Record<PropertyKey, NullishType>): string[] {
358        return Object.keys(rec)
359    }
360
361    /**
362    * Returns the names of the own fields of an object
363    *
364    * @param o object that contains the own fields
365    *
366    * @returns array representation of names
367    */
368    public static getOwnPropertyNames(o: Object): string[] {
369        if (o instanceof Char ||
370            o instanceof Boolean ||
371            o instanceof Byte ||
372            o instanceof Short ||
373            o instanceof Int ||
374            o instanceof Long ||
375            o instanceof Float ||
376            o instanceof Double) {
377            return new string[0]
378        }
379        const t = Type.of(o)
380        if (t instanceof StringType || t instanceof ArrayType || o instanceof Array) {
381            const keys = Object.keys(o)
382            const len = keys.length
383            let res: string[] = new string[len + 1]
384            for (let i = 0; i < len; i++) {
385                res[i] = keys[i]
386            }
387            res[len] = ARRAY_LENGTH_MEMBER_NAME
388            return res
389        }
390        if (t instanceof ClassType) {
391            return Object.keys(o)
392        } else if (t instanceof LambdaType) {
393            return [FUNCTION_LENGTH_MEMBER_NAME, FUNCTION_NAME_MEMBER_NAME]
394        } else if (t instanceof EnumType) {
395            // NOTE(shumilov-petr): Not implemented
396            throw new Error("Not implemented")
397        } else if (t instanceof UnionType) {
398            // NOTE(shumilov-petr): Not implemented
399            throw new Error("Not implemented")
400        } else if (t instanceof TupleType) {
401            // NOTE(shumilov-petr): Not implemented
402            throw new Error("Not implemented")
403        }
404
405        throw new AssertionError("Invalid object type")
406    }
407
408    /**
409    * Determines whether an object has a field with the specified name
410    *
411    * @param key the string name of the field to test
412    *
413    * @returns true if the object has the specified field; false otherwise
414    */
415    public hasOwnProperty(key: string): boolean {
416        const keys = Object.getOwnPropertyNames(this)
417        const len = keys.length
418        for(let i = 0; i < len; i++) {
419            if (keys[i] == key) {
420                return true
421            }
422        }
423        return false
424    }
425
426    /**
427    * Determines whether an object has a element with the specified index
428    *
429    * @param index the number index of the element to test
430    *
431    * @returns true if the object has the specified element; false otherwise
432    */
433    public hasOwnProperty(index: number): boolean {
434        if ((this) instanceof String) {
435            const sv = this as String
436            const len = sv.getLength()
437            const idx = index.toLong()
438            return (0 <= idx && idx < len)
439        }
440        const t = Type.of(this)
441        if (t instanceof ArrayType) {
442            const av = Value.of(this) as ArrayValue
443            const len = av.getLength()
444            const idx = index.toLong()
445            return (0 <= idx && idx < len)
446        } else if (t instanceof EnumType) {
447            // NOTE(shumilov-petr): Not implemented
448            throw new Error("Not implemented")
449        } else if (t instanceof UnionType) {
450            // NOTE(shumilov-petr): Not implemented
451            throw new Error("Not implemented")
452        } else if (t instanceof TupleType) {
453            // NOTE(shumilov-petr): Not implemented
454            throw new Error("Not implemented")
455        }
456        return false
457    }
458
459    /**
460    * Determines whether an object has a field with the specified name
461    *
462    * @param target an object
463    *
464    * @param key the string name of the field to test
465    *
466    * @returns true if the object has the specified field; false otherwise
467    */
468    public static hasOwn(target: Object, key: PropertyKey): boolean {
469        return target.hasOwnProperty(key)
470    }
471
472    /**
473    * Determines whether an object has a element with the specified index
474    *
475    * @param target an object
476    *
477    * @param index the number index of the element to test
478    *
479    * @returns true if the object has the specified element; false otherwise
480    */
481    public static hasOwn(target: Object, index: number): boolean {
482        return target.hasOwnProperty(index)
483    }
484
485    /**
486    * Transforms key-value pairs into a Record.
487    *
488    * @param entries an Iterable object that contains key-value pairs
489    *
490    * @returns new Record whose properties are given by the elements of the Iterable
491    */
492    public static fromEntries<T = NullishType>(entries: Iterable<[PropertyKey, T]>): Record<PropertyKey, T> {
493        const result = new Record<PropertyKey, T>()
494
495        const entriesIter = entries.$_iterator()
496
497        let entriesIterResult = entriesIter.next()
498        while (!entriesIterResult.done) {
499            const entry: [PropertyKey, T] | undefined = entriesIterResult.value
500            if (entry != undefined) {
501                result[entry[0] as PropertyKey] = entry[1] as T
502            }
503
504            entriesIterResult = entriesIter.next()
505        }
506
507        return result
508    }
509
510    /**
511    * Copies all own properties from one or more source objects to a target Record.
512    *
513    * @param target target Record -- what to apply the sources' properties to
514    *
515    * @param source objects containing the properties you want to apply
516    *
517    * @returns the modified target Record
518    */
519    public static assign(target: Record<PropertyKey, NullishType>,  ...source: FixedArray<Object>): Record<PropertyKey, NullishType> {
520        for (const s of source) {
521            const entries = Object.entries(s)
522            for (const e of entries) {
523                target.set(e![0] as PropertyKey, e![1] as NullishType)
524            }
525        }
526        return target
527    }
528}
529