إنه عصر ES6 وTypescript. أنت تعمل حاليًا مع الفئات والكائنات المُنشئة أكثر من أي وقت مضى. يسمح لك محول الفصل بتحويل كائن عادي إلى مثيل للفئة والعكس. كما يسمح بإجراء تسلسل/إلغاء تسلسل الكائن بناءً على المعايير. هذه الأداة مفيدة للغاية على كل من الواجهة الأمامية والخلفية.
مثال على كيفية الاستخدام مع angular 2 في المكبس. كود المصدر متاح هنا.
يوجد في JavaScript نوعان من الكائنات:
الكائنات البسيطة هي كائنات تمثل مثيلات لفئة Object
. في بعض الأحيان يطلق عليها كائنات حرفية ، عند إنشائها عبر تدوين {}
. كائنات الفئة هي مثيلات للفئات ذات مُنشئ وخصائص وأساليب محددة. عادةً ما تقوم بتعريفها عبر تدوين class
.
إذن، ما هي المشكلة؟
في بعض الأحيان تريد تحويل كائن جافا سكريبت العادي إلى فئات ES6 الموجودة لديك. على سبيل المثال، إذا كنت تقوم بتحميل ملف json من الواجهة الخلفية لديك، أو بعض واجهات برمجة التطبيقات (api) أو من ملف json، وبعد JSON.parse
، يكون لديك كائن جافا سكريبت عادي، وليس مثيل للفئة التي لديك.
على سبيل المثال، لديك قائمة بالمستخدمين في ملف users.json
الذي تقوم بتحميله:
[
{
"id" : 1 ,
"firstName" : " Johny " ,
"lastName" : " Cage " ,
"age" : 27
},
{
"id" : 2 ,
"firstName" : " Ismoil " ,
"lastName" : " Somoni " ,
"age" : 50
},
{
"id" : 3 ,
"firstName" : " Luke " ,
"lastName" : " Dacascos " ,
"age" : 12
}
]
ولديك فئة User
:
export class User {
id : number ;
firstName : string ;
lastName : string ;
age : number ;
getName ( ) {
return this . firstName + ' ' + this . lastName ;
}
isAdult ( ) {
return this . age > 36 && this . age < 60 ;
}
}
أنت تفترض أنك تقوم بتنزيل مستخدمين من النوع User
من ملف users.json
وقد ترغب في كتابة الكود التالي:
fetch ( 'users.json' ) . then ( ( users : User [ ] ) => {
// you can use users here, and type hinting also will be available to you,
// but users are not actually instances of User class
// this means that you can't use methods of User class
} ) ;
في هذا الكود يمكنك استخدام users[0].id
، ويمكنك أيضًا استخدام users[0].firstName
و users[0].lastName
. ومع ذلك، لا يمكنك استخدام users[0].getName()
أو users[0].isAdult()
لأن "users" عبارة عن مجموعة من كائنات جافا سكريبت العادية، وليست مثيلات لكائن المستخدم. لقد كذبت بالفعل على المترجم عندما قلت أن users: User[]
.
إذن ماذا تفعل؟ كيفية إنشاء مجموعة users
من مثيلات كائنات User
بدلاً من كائنات جافا سكريبت العادية؟ الحل هو إنشاء مثيلات جديدة لكائن المستخدم ونسخ جميع الخصائص يدويًا إلى كائنات جديدة. لكن الأمور قد تسوء بسرعة كبيرة بمجرد أن يكون لديك تسلسل هرمي أكثر تعقيدًا للكائنات.
البدائل؟ نعم، يمكنك استخدام محول الفئة. الغرض من هذه المكتبة هو مساعدتك في تعيين كائنات جافا سكريبت العادية الخاصة بك إلى مثيلات الفئات الموجودة لديك.
تعتبر هذه المكتبة أيضًا رائعة للنماذج المعروضة في واجهات برمجة التطبيقات الخاصة بك، لأنها توفر أدوات رائعة للتحكم في ما تعرضه نماذجك في واجهة برمجة التطبيقات الخاصة بك. هنا مثال كيف سيبدو:
fetch ( 'users.json' ) . then ( ( users : Object [ ] ) => {
const realUsers = plainToInstance ( User , users ) ;
// now each user in realUsers is an instance of User class
} ) ;
يمكنك الآن استخدام أساليب users[0].getName()
و users[0].isAdult()
.
تثبيت الوحدة:
npm install class-transformer --save
مطلوب شريحة reflect-metadata
، قم بتثبيتها أيضًا:
npm install reflect-metadata --save
وتأكد من استيراده في مكان عالمي، مثل app.ts:
import 'reflect-metadata' ;
يتم استخدام ميزات ES6، إذا كنت تستخدم الإصدار القديم من Node.js فقد تحتاج إلى تثبيت es6-shim:
npm install es6-shim --save
واستيراده في مكان عالمي مثل app.ts:
import 'es6-shim' ;
تثبيت الوحدة:
npm install class-transformer --save
مطلوب شريحة reflect-metadata
، قم بتثبيتها أيضًا:
npm install reflect-metadata --save
أضف <script>
لتعكس البيانات الوصفية في رأس index.html
الخاص بك:
< html >
< head >
<!-- ... -->
< script src =" node_modules/reflect-metadata/Reflect.js " > </ script >
</ head >
<!-- ... -->
</ html >
إذا كنت تستخدم angular 2، فيجب أن تكون هذه الرقائق مثبتة بالفعل.
إذا كنت تستخدم system.js فقد ترغب في إضافة هذا إلى تكوين map
package
:
{
"map" : {
"class-transformer" : " node_modules/class-transformer "
},
"packages" : {
"class-transformer" : { "main" : " index.js " , "defaultExtension" : " js " }
}
}
تقوم هذه الطريقة بتحويل كائن جافا سكريبت العادي إلى مثيل لفئة معينة.
import { plainToInstance } from 'class-transformer' ;
let users = plainToInstance ( User , userJson ) ; // to convert user plain object a single user. also supports arrays
تقوم هذه الطريقة بتحويل كائن عادي إلى مثيل باستخدام كائن معبأ بالفعل وهو مثيل للفئة المستهدفة.
const defaultUser = new User ( ) ;
defaultUser . role = 'user' ;
let mixedUser = plainToClassFromExist ( defaultUser , user ) ; // mixed user should have the value role = user when no value is set otherwise.
تقوم هذه الطريقة بتحويل كائن الفئة الخاص بك مرة أخرى إلى كائن جافا سكريبت عادي، والذي يمكن أن يكون JSON.stringify
لاحقًا.
import { instanceToPlain } from 'class-transformer' ;
let photo = instanceToPlain ( photo ) ;
تقوم هذه الطريقة بتحويل كائن الفئة الخاص بك إلى مثيل جديد لكائن الفئة. قد يتم التعامل مع هذا على أنه استنساخ عميق لأشياءك.
import { instanceToInstance } from 'class-transformer' ;
let photo = instanceToInstance ( photo ) ;
يمكنك أيضًا استخدام خيار ignoreDecorators
في خيارات التحويل لتجاهل جميع أدوات الديكور التي تستخدمها فئاتك.
يمكنك إجراء تسلسل لنموذجك مباشرة إلى json باستخدام طريقة serialize
:
import { serialize } from 'class-transformer' ;
let photo = serialize ( photo ) ;
يعمل serialize
مع كل من المصفوفات وغير المصفوفات.
يمكنك إلغاء تسلسل النموذج الخاص بك من json باستخدام طريقة deserialize
:
import { deserialize } from 'class-transformer' ;
let photo = deserialize ( Photo , photo ) ;
لتفعيل عملية إلغاء التسلسل مع المصفوفات، استخدم التابع deserializeArray
:
import { deserializeArray } from 'class-transformer' ;
let photos = deserializeArray ( Photo , photos ) ;
السلوك الافتراضي للأسلوب plainToInstance
هو تعيين كافة الخصائص من الكائن العادي، حتى تلك التي لم يتم تحديدها في الفئة.
import { plainToInstance } from 'class-transformer' ;
class User {
id : number ;
firstName : string ;
lastName : string ;
}
const fromPlainUser = {
unkownProp : 'hello there' ,
firstName : 'Umed' ,
lastName : 'Khudoiberdiev' ,
} ;
console . log ( plainToInstance ( User , fromPlainUser ) ) ;
// User {
// unkownProp: 'hello there',
// firstName: 'Umed',
// lastName: 'Khudoiberdiev',
// }
إذا كان هذا السلوك لا يناسب احتياجاتك، فيمكنك استخدام خيار excludeExtraneousValues
في طريقة plainToInstance
أثناء الكشف عن جميع خصائص فئتك كشرط.
import { Expose , plainToInstance } from 'class-transformer' ;
class User {
@ Expose ( ) id : number ;
@ Expose ( ) firstName : string ;
@ Expose ( ) lastName : string ;
}
const fromPlainUser = {
unkownProp : 'hello there' ,
firstName : 'Umed' ,
lastName : 'Khudoiberdiev' ,
} ;
console . log ( plainToInstance ( User , fromPlainUser , { excludeExtraneousValues : true } ) ) ;
// User {
// id: undefined,
// firstName: 'Umed',
// lastName: 'Khudoiberdiev'
// }
عندما تحاول تحويل كائنات تحتوي على كائنات متداخلة، فمن الضروري معرفة نوع الكائن الذي تحاول تحويله. بما أن Typescript لا تتمتع بقدرات انعكاس جيدة حتى الآن، فيجب أن نحدد ضمنيًا نوع الكائن الذي تحتويه كل خاصية. يتم ذلك باستخدام @Type
Decorator.
لنفترض أن لدينا ألبومًا يحتوي على صور. ونحن نحاول تحويل كائن الألبوم العادي إلى كائن فئة:
import { Type , plainToInstance } from 'class-transformer' ;
export class Album {
id : number ;
name : string ;
@ Type ( ( ) => Photo )
photos : Photo [ ] ;
}
export class Photo {
id : number ;
filename : string ;
}
let album = plainToInstance ( Album , albumJson ) ;
// now album is Album object with Photo objects inside
في حالة إمكانية أن يكون الكائن المتداخل من أنواع مختلفة، يمكنك توفير كائن خيارات إضافي يحدد أداة التمييز. يجب أن يحدد خيار التمييز property
تحمل اسم النوع الفرعي للكائن والأنواع subTypes
المحتملة التي يمكن للكائن المتداخل التحويل إليها. يحتوي النوع الفرعي على value
تحمل مُنشئ النوع name
الذي يمكن أن يتطابق مع property
المُميِّز.
لنفترض أن لدينا ألبومًا يحتوي على أفضل الصور. ولكن هذه الصورة يمكن أن تكون من أنواع مختلفة معينة. ونحن نحاول تحويل كائن الألبوم العادي إلى كائن فئة. يجب أن يحدد إدخال الكائن العادي الخاصية الإضافية __type
. تتم إزالة هذه الخاصية أثناء التحويل بشكل افتراضي:
إدخال جسون :
{
"id" : 1 ,
"name" : " foo " ,
"topPhoto" : {
"id" : 9 ,
"filename" : " cool_wale.jpg " ,
"depth" : 1245 ,
"__type" : " underwater "
}
}
import { Type , plainToInstance } from 'class-transformer' ;
export abstract class Photo {
id : number ;
filename : string ;
}
export class Landscape extends Photo {
panorama : boolean ;
}
export class Portrait extends Photo {
person : Person ;
}
export class UnderWater extends Photo {
depth : number ;
}
export class Album {
id : number ;
name : string ;
@ Type ( ( ) => Photo , {
discriminator : {
property : '__type' ,
subTypes : [
{ value : Landscape , name : 'landscape' } ,
{ value : Portrait , name : 'portrait' } ,
{ value : UnderWater , name : 'underwater' } ,
] ,
} ,
} )
topPhoto : Landscape | Portrait | UnderWater ;
}
let album = plainToInstance ( Album , albumJson ) ;
// now album is Album object with a UnderWater object without `__type` property.
تلميح: الأمر نفسه ينطبق على المصفوفات ذات الأنواع الفرعية المختلفة. علاوة على ذلك، يمكنك تحديد keepDiscriminatorProperty: true
في الخيارات للاحتفاظ بخاصية التمييز أيضًا داخل الفئة الناتجة.
يمكنك الكشف عن ما يُرجعه أسلوبك أو أسلوبك عن طريق تعيين مُزخرف @Expose()
لتلك الحروف أو الأساليب:
import { Expose } from 'class-transformer' ;
export class User {
id : number ;
firstName : string ;
lastName : string ;
password : string ;
@ Expose ( )
get name ( ) {
return this . firstName + ' ' + this . lastName ;
}
@ Expose ( )
getFullName ( ) {
return this . firstName + ' ' + this . lastName ;
}
}
إذا كنت تريد الكشف عن بعض الخصائص باسم مختلف، فيمكنك القيام بذلك عن طريق تحديد خيار name
لـ @Expose
Decorator:
import { Expose } from 'class-transformer' ;
export class User {
@ Expose ( { name : 'uid' } )
id : number ;
firstName : string ;
lastName : string ;
@ Expose ( { name : 'secretKey' } )
password : string ;
@ Expose ( { name : 'fullName' } )
getFullName ( ) {
return this . firstName + ' ' + this . lastName ;
}
}
في بعض الأحيان تريد تخطي بعض الخصائص أثناء التحويل. يمكن القيام بذلك باستخدام @Exclude
Decorator:
import { Exclude } from 'class-transformer' ;
export class User {
id : number ;
email : string ;
@ Exclude ( )
password : string ;
}
الآن عندما تقوم بتحويل مستخدم، سيتم تخطي خاصية password
ولن يتم تضمينها في النتيجة المحولة.
يمكنك التحكم في العملية التي ستستبعد فيها خاصية ما. استخدم خيارات toClassOnly
أو toPlainOnly
:
import { Exclude } from 'class-transformer' ;
export class User {
id : number ;
email : string ;
@ Exclude ( { toPlainOnly : true } )
password : string ;
}
الآن سيتم استبعاد خاصية password
فقط أثناء عملية instanceToPlain
. والعكس صحيح، استخدم خيار toClassOnly
.
يمكنك تخطي كافة خصائص الفئة، وكشف فقط تلك المطلوبة بشكل صريح:
import { Exclude , Expose } from 'class-transformer' ;
@ Exclude ( )
export class User {
@ Expose ( )
id : number ;
@ Expose ( )
email : string ;
password : string ;
}
سيتم الآن كشف id
والبريد email
، وسيتم استبعاد كلمة المرور أثناء التحويل. وبدلاً من ذلك، يمكنك تعيين استراتيجية الاستبعاد أثناء التحويل:
import { instanceToPlain } from 'class-transformer' ;
let photo = instanceToPlain ( photo , { strategy : 'excludeAll' } ) ;
في هذه الحالة لا تحتاج إلى @Exclude()
فصل دراسي كامل.
إذا قمت بتسمية خصائصك الخاصة ببادئة، فلنقل بـ _
، فيمكنك استبعاد هذه الخصائص من التحويل أيضًا:
import { instanceToPlain } from 'class-transformer' ;
let photo = instanceToPlain ( photo , { excludePrefixes : [ '_' ] } ) ;
سيؤدي هذا إلى تخطي كافة الخصائص التي تبدأ بـ _
البادئة. يمكنك تمرير أي عدد من البادئات وسيتم تجاهل كافة الخصائص التي تبدأ بهذه البادئات. على سبيل المثال:
import { Expose , instanceToPlain } from 'class-transformer' ;
export class User {
id : number ;
private _firstName : string ;
private _lastName : string ;
_password : string ;
setName ( firstName : string , lastName : string ) {
this . _firstName = firstName ;
this . _lastName = lastName ;
}
@ Expose ( )
get name ( ) {
return this . _firstName + ' ' + this . _lastName ;
}
}
const user = new User ( ) ;
user . id = 1 ;
user . setName ( 'Johny' , 'Cage' ) ;
user . _password = '123' ;
const plainUser = instanceToPlain ( user , { excludePrefixes : [ '_' ] } ) ;
// here plainUser will be equal to
// { id: 1, name: "Johny Cage" }
يمكنك استخدام المجموعات للتحكم في البيانات التي سيتم الكشف عنها والبيانات التي لن يتم الكشف عنها:
import { Exclude , Expose , instanceToPlain } from 'class-transformer' ;
export class User {
id : number ;
name : string ;
@ Expose ( { groups : [ 'user' , 'admin' ] } ) // this means that this data will be exposed only to users and admins
email : string ;
@ Expose ( { groups : [ 'user' ] } ) // this means that this data will be exposed only to users
password : string ;
}
let user1 = instanceToPlain ( user , { groups : [ 'user' ] } ) ; // will contain id, name, email and password
let user2 = instanceToPlain ( user , { groups : [ 'admin' ] } ) ; // will contain id, name and email
إذا كنت تقوم بإنشاء واجهة برمجة تطبيقات لها إصدارات مختلفة، فإن class-transformer لديه أدوات مفيدة للغاية لذلك. يمكنك التحكم في خصائص النموذج الخاص بك التي يجب كشفها أو استبعادها في أي إصدار. مثال:
import { Exclude , Expose , instanceToPlain } from 'class-transformer' ;
export class User {
id : number ;
name : string ;
@ Expose ( { since : 0.7 , until : 1 } ) // this means that this property will be exposed for version starting from 0.7 until 1
email : string ;
@ Expose ( { since : 2.1 } ) // this means that this property will be exposed for version starting from 2.1
password : string ;
}
let user1 = instanceToPlain ( user , { version : 0.5 } ) ; // will contain id and name
let user2 = instanceToPlain ( user , { version : 0.7 } ) ; // will contain id, name and email
let user3 = instanceToPlain ( user , { version : 1 } ) ; // will contain id and name
let user4 = instanceToPlain ( user , { version : 2 } ) ; // will contain id and name
let user5 = instanceToPlain ( user , { version : 2.1 } ) ; // will contain id, name and password
في بعض الأحيان يكون لديك تاريخ في كائن جافا سكريبت العادي الذي تم استلامه بتنسيق سلسلة. وتريد إنشاء كائن تاريخ جافا سكريبت حقيقي منه. يمكنك القيام بذلك ببساطة عن طريق تمرير كائن Date إلى مُزخرف @Type
:
import { Type } from 'class-transformer' ;
export class User {
id : number ;
email : string ;
password : string ;
@ Type ( ( ) => Date )
registrationDate : Date ;
}
يمكن استخدام نفس الأسلوب مع الأنواع البدائية Number
و String
و Boolean
عندما تريد تحويل قيمك إلى هذه الأنواع.
عند استخدام المصفوفات، يجب عليك توفير نوع الكائن الذي تحتوي عليه المصفوفة. هذا النوع، تحدده في مصمم الديكور @Type()
:
import { Type } from 'class-transformer' ;
export class Photo {
id : number ;
name : string ;
@ Type ( ( ) => Album )
albums : Album [ ] ;
}
يمكنك أيضًا استخدام أنواع المصفوفات المخصصة:
import { Type } from 'class-transformer' ;
export class AlbumCollection extends Array < Album > {
// custom array functions ...
}
export class Photo {
id : number ;
name : string ;
@ Type ( ( ) => Album )
albums : AlbumCollection ;
}
ستتعامل المكتبة مع التحويل المناسب تلقائيًا.
تتطلب مجموعات ES6 Set
and Map
أيضًا أداة تزيين @Type
:
export class Skill {
name : string ;
}
export class Weapon {
name : string ;
range : number ;
}
export class Player {
name : string ;
@ Type ( ( ) => Skill )
skills : Set < Skill > ;
@ Type ( ( ) => Weapon )
weapons : Map < string , Weapon > ;
}
يمكنك إجراء تحويل إضافي للبيانات باستخدام @Transform
Decorator. على سبيل المثال، تريد أن تجعل كائن Date
الخاص بك كائنًا moment
عندما تقوم بتحويل الكائن من عادي إلى فئة:
import { Transform } from 'class-transformer' ;
import * as moment from 'moment' ;
import { Moment } from 'moment' ;
export class Photo {
id : number ;
@ Type ( ( ) => Date )
@ Transform ( ( { value } ) => moment ( value ) , { toClassOnly : true } )
date : Moment ;
}
الآن عندما تتصل بـ plainToInstance
وترسل تمثيلًا عاديًا لكائن الصورة، فإنه سيتم تحويل قيمة التاريخ في كائن الصورة الخاص بك إلى تاريخ اللحظة. يدعم @Transform
Decorator أيضًا المجموعات والإصدارات.
يُعطى مصمم الديكور @Transform
المزيد من الوسائط للسماح لك بتكوين الطريقة التي تريد بها إجراء التحويل.
@ Transform ( ( { value , key , obj , type } ) => value )
دعوى | وصف |
---|---|
value | قيمة العقار قبل التحويل. |
key | اسم العقار المحول. |
obj | كائن مصدر التحويل. |
type | نوع التحول. |
options | تم تمرير كائن الخيارات إلى طريقة التحويل. |
إمضاء | مثال | وصف |
---|---|---|
@TransformClassToPlain | @TransformClassToPlain({ groups: ["user"] }) | قم بتحويل طريقة الإرجاع باستخدام المثيلToPlain وكشف الخصائص الموجودة في الفصل. |
@TransformClassToClass | @TransformClassToClass({ groups: ["user"] }) | قم بتحويل طريقة الإرجاع باستخدام المثيلToInstance واكشف عن الخصائص الموجودة في الفصل. |
@TransformPlainToClass | @TransformPlainToClass(User, { groups: ["user"] }) | قم بتحويل طريقة الإرجاع باستخدام plainToInstance واكشف عن الخصائص الموجودة في الفصل. |
تقبل أدوات الديكور المذكورة أعلاه وسيطًا اختياريًا واحدًا: ClassTransformOptions - خيارات التحويل مثل المجموعات والإصدار والاسم
مثال:
@ Exclude ( )
class User {
id : number ;
@ Expose ( )
firstName : string ;
@ Expose ( )
lastName : string ;
@ Expose ( { groups : [ 'user.email' ] } )
email : string ;
password : string ;
}
class UserController {
@ TransformClassToPlain ( { groups : [ 'user.email' ] } )
getUser ( ) {
const user = new User ( ) ;
user . firstName = 'Snir' ;
user . lastName = 'Segal' ;
user . password = 'imnosuperman' ;
return user ;
}
}
const controller = new UserController ( ) ;
const user = controller . getUser ( ) ;
سيحتوي متغير user
على الاسم الأول واسم العائلة وخصائص البريد الإلكتروني فقط لأنها المتغيرات المكشوفة. خاصية البريد الإلكتروني مكشوفة أيضًا لأننا ذكرنا المجموعة "user.email".
الأدوية العامة غير مدعومة لأن TypeScript لا تتمتع بقدرات انعكاس جيدة حتى الآن. بمجرد أن يقدم لنا فريق TypeScript أدوات أفضل لانعكاس النوع في وقت التشغيل، سيتم تنفيذ الأدوية العامة. هناك بعض التعديلات التي يمكنك استخدامها، والتي ربما يمكن أن تحل مشكلتك. الخروج من هذا المثال.
ملاحظة: إذا كنت تستخدم أداة التحقق من الفئة مع محول الفئة، فربما لا ترغب في تمكين هذه الوظيفة.
لتمكين التحويل التلقائي بين الأنواع المضمنة بناءً على معلومات النوع المقدمة بواسطة Typescript. معطل افتراضيا.
import { IsString } from 'class-validator' ;
class MyPayload {
@ IsString ( )
prop : string ;
}
const result1 = plainToInstance ( MyPayload , { prop : 1234 } , { enableImplicitConversion : true } ) ;
const result2 = plainToInstance ( MyPayload , { prop : 1234 } , { enableImplicitConversion : false } ) ;
/**
* result1 will be `{ prop: "1234" }` - notice how the prop value has been converted to string.
* result2 will be `{ prop: 1234 }` - default behaviour
*/
يتم تجاهل المراجع الدائرية. على سبيل المثال، إذا كنت تقوم بتحويل فئة User
التي تحتوي على photos
خاصية بنوع Photo
، وتحتوي Photo
على رابط user
إلى User
الأصلي، فسيتم تجاهل user
أثناء التحويل. لا يتم تجاهل المراجع الدائرية فقط أثناء عملية instanceToInstance
.
لنفترض أنك تريد تنزيل المستخدمين وتريد أن يتم تعيينهم تلقائيًا إلى مثيلات فئة User
.
import { plainToInstance } from 'class-transformer' ;
this . http
. get ( 'users.json' )
. map ( res => res . json ( ) )
. map ( res => plainToInstance ( User , res as Object [ ] ) )
. subscribe ( users => {
// now "users" is type of User[] and each user has getName() and isAdult() methods available
console . log ( users ) ;
} ) ;
يمكنك أيضًا إدخال فئة ClassTransformer
كخدمة في providers
واستخدام أساليبها.
مثال على كيفية الاستخدام مع الزاوي 2 في المكبس. كود المصدر هنا .
قم بإلقاء نظرة على العينات في ./sample لمزيد من الأمثلة على الاستخدامات.
اطلع على المعلومات حول التغييرات العاجلة وملاحظات الإصدار هنا.