يقوم
ts-proto
بتحويل ملفات.proto
الخاصة بك إلى ملفات نوعية مطلقة بقوة!
قام الإصدار 2.x من TS-Proto بترحيل بروتوبوف ذي المستوى المنخفض الذي يسلسله أن طريقة encode
decode
تستخدم من حزمة الموقرة ، ولكن للشيخوخة protobufjs
، إلى @bufbuild/protobuf
.
إذا استخدمت أساليب encode
وفك decode
فقط ، فيجب أن يكون هذا تغييرًا غير محظور إلى حد كبير.
ومع ذلك ، إذا استخدمت أي رمز استخدمت فئات Writer
أو Reader
protobufjs
القديم ، فستحتاج إلى تحديث الكود الخاص بك لاستخدام فئات @bufbuild/protobuf
الجديدة:
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
إذا كان الترحيل إلى @bufbuild/protobuf
هو مانع لك ، فيمكنك تثبيت إصدار ts-proto
الخاص بك إلى 1.x
إخلاء المسئولية والاعتذار: كنت أنوي إطلاق TS-Proto 2.x كإصدار ألفا ، لكن لم أحصل على تكوين الإفراج الدلالي بشكل صحيح ، وبالتالي تم نشر TS-Proto 2.x كإصدار رئيسي بدون ألفا مناسب /دورة بيتا.
إذا تمكنت من تقديم تقارير (أو أفضل PRS!) لأي مشكلات تصادفها بينما لا يزال الإصدار جديدًا ، فسيكون ذلك موضع تقدير كبير.
أي نصائح أو حيل للآخرين على الهجرة سيكون موضع تقدير أيضًا!
TS-Proto
جدول المحتويات
ملخص
Quickstart
buf
ESM
الأهداف
غير المميزين
أنواع مثال
أبرز
الوقاية التلقائية / N+1
الاستخدام
الخيارات المدعومة
دعم NESTJS
وضع الساعة
تنفيذ GRPC الأساسي
الرعاة
تطوير
الافتراضات
تودو
معالجة واحدة
القيم الافتراضية والحقول
أنواع معروفة
أنواع الغلاف
أنواع JSON (أنواع الهيكل)
الطابع الزمني
أنواع الأرقام
الحالة الحالية للقيم الاختيارية
يقوم TS-Proto بإنشاء أنواع Typescript من مخططات Protobuf.
أي إعطاء person.proto
مخطط بروتو مثل:
رسالة الشخص {string name = 1 ؛ }
سيقوم TS-Proto بإنشاء ملف person.ts
مثل:
واجهة الشخص { الاسم: string} const person = { Encode (شخص): كاتب {...} Decode (reader): شخص {...} Tojson (شخص): غير معروف {...} FromJson (Data): شخص {...}}
كما أنه يعرف عن الخدمات وسوف يولد أنواعًا لهم أيضًا ، أي:
تصدير واجهة Pingservice { ping (طلب: pingrequest): وعد <pingresponse> ؛}
كما أنه سيولد تطبيقات العميل من PingService
؛ حاليًا يتم دعم TWIRP و GRPC-WEB و GRPC-JS و NESTJS.
npm install ts-proto
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./simple.proto
(لاحظ أن اسم معلمة الإخراج ، ts_proto_out
، تم تسميته بناءً على لاحقة اسم المكون الإضافي ، أي "TS_PROTO" في _out
في --plugin=./node_modules/.bin/protoc-gen-ts_proto
لكل مؤتمرات CLI من protoc
.)
على Windows ، استخدم protoc --plugin=protoc-gen-ts_proto=".node_modules.binprotoc-gen-ts_proto.cmd" --ts_proto_out=. ./simple.proto
(انظر #93)
تأكد من أنك تستخدم protoc
الحديث (انظر تعليمات التثبيت لمنصة الخاص بك ، أي protoc
v 3.0.0
لا يدعم علامة _opt
سيؤدي ذلك إلى إنشاء ملفات مصدر *.ts
لأنواع *.proto
.
إذا كنت ترغب في حزم هذه الملفات المصدر في حزمة NPM لتوزيعها على العملاء ، فما عليك سوى تشغيل tsc
عليها كالمعتاد لإنشاء ملفات .js
/ .d.ts
، ونشر الإخراج كحزمة NPM العادية.
إذا كنت تستخدم BUF ، فاقبت strategy: all
في ملف buf.gen.yaml
الخاص بك (مستندات).
الإصدار: v1plugins: -الاسم: tsout: ../gen/tsstrategy: allpath: ../node_modules/ts-proto/protoc-gen-ts_proto
لمنع buf push
من قراءة ملفات .proto
غير ذي صلة ، تكوين buf.yaml
مثل ذلك:
بناء: يستبعد: [node_modules]
يمكنك أيضًا استخدام المكون الإضافي الرسمي المنشور في سجل BUF.
الإصدار: v1plugins: -البرنامج المساعد: buf.build/community/stephenh-ts-protoout: ../gen/tsopt: - OutdServices = ... - useExactTypes = ...
إذا كنت تستخدم إعداد TS الحديث إما مع esModuleInterop
أو تشغيل في بيئة ESM ، فستحتاج إلى تمرير ts_proto_opt
s من:
esModuleInterop=true
إذا كان استخدام esModuleInterop
في tsconfig.json
الخاص بك ، و
importSuffix=.js
إذا كان تنفيذ رمز TS-Proto الذي تم إنشاؤه في بيئة ESM
من حيث الرمز الذي يولده ts-proto
، فإن الأهداف العامة هي:
أنواع typecript/es6 الاصطلاحية
ts-proto
عبارة عن استراحة نظيفة إما من رمز Google/Java-esque JS الخاص بـ protoc
أو "Make .d.ts
file the *.js
" نهج protobufjs
(من الناحية الفنية ، يتم استخدام protobufjs/minimal
من الحزمة لقراءة/كتابة بايت.)
إخراج TypeScript-First
واجهات فوق الفصول
قدر الإمكان ، الأنواع هي مجرد واجهات ، بحيث يمكنك العمل مع الرسائل مثل تجزئة/هياكل البيانات العادية.
يدعم فقط codegen *.proto
-to- *.ts
سير العمل ، حاليًا لا يوجد انعكاس في وقت التشغيل/تحميل ملفات .proto
dynamic
لاحظ أن TS-Proto ليس إطارًا خارج الصندوق RPC ؛ بدلاً من ذلك ، يكون أكثر من سكين سويسري الذراع (كما شهدته العديد من خيارات التكوين الخاصة به) ، مما يتيح لك إنشاء إطار عمل RPC بالضبط الذي تريده فوقه (أي أنه يتكامل بشكل أفضل مع نظام ProtoBuf الخاص بشركتك ؛ للأفضل أو للأسوأ ، لا يزال Protobuf RPC نظامًا بيئيًا مجزأًا إلى حد ما).
إذا كنت ترغب في إطار عمل RPC خارج الصندوق المبني على رأس TS-Proto ، فهناك بعض الأمثلة:
لطيفة GRPC
Starpc
(لاحظ للمساهمين المحتملين ، إذا قمت بتطوير أطر أخرى/مواجهة صغيرة ، أو حتى منشورات/دروس في المدونة ، على استخدام ts-proto
، يسعدنا الارتباط بها.)
نحن أيضًا لا ندعم العملاء لـ google.api.http
-based google cloud APIs ، راجع #948 إذا كنت ترغب في إرسال العلاقات العامة.
الأنواع التي تم إنشاؤها هي "بيانات فقط" ، أي:
واجهة التصدير البسيطة { الاسم: سلسلة. العمر: العدد ؛ أنشأت: التاريخ | غير محدد الطفل: طفل | غير محدد الدولة: Stateenum ؛ أحفاد: طفل [] ؛ العملات المعدنية: رقم [] ؛}
جنبا إلى جنب مع طرق المصنع encode
/ decode
:
تصدير conc simple = { إنشاء (baseObject؟: deeppartial <simple>): بسيط {...} ، ENCODE (رسالة: بسيط ، الكاتب: الكاتب = الكاتب.)): كاتب {...} ، Decode (القارئ: القارئ ، الطول؟: رقم): بسيط {...} ، FromJson (كائن: أي): بسيط {...} ، FromPartial (الكائن: Deeppartial <simple>): بسيط {...} ، tojson (الرسالة: بسيطة): غير معروف {...} ،} ؛
هذا يسمح باستخدام TS/JS Idiomatic مثل:
const bytes = simple.encode ({name: ... ، العمر: ... ، ...}). Finish () ؛ cONC SIMPLE = Simple.Decode (reader.create (bytes)) ؛ const {name ، age } = بسيط ؛
والتي يمكن أن تخفف التكامل بشكل كبير عند التحويل إلى/من طبقات أخرى دون إنشاء فئة والاتصال بـ GetTers/المستقلين المناسبين.
محاولة الرجل المسكين في "من فضلك أعجبنا أنواعًا اختيارية"
يتم تعيين أنواع غلاف البروتوبوف الكنسي ، أي google.protobuf.StringValue
، كقيم اختيارية ، أي string | undefined
، مما يعني بالنسبة للبدائل ، يمكننا نوعًا من التظاهر بأن نظام نوع protobuf لديه أنواع اختيارية.
( تحديث : يدعم TS-Proto الآن أيضًا الكلمة الرئيسية optional
Proto3.)
يتم تعيين الطوابع الزمنية Date
(قابلة للتكوين مع المعلمة useDate
.)
fromJSON
/ toJSON
استخدم تنسيق ترميز JSON Canonical Canonical (مثل Timestamps هي سلاسل ISO) ، على عكس protobufjs
.
يمكن تعيين ObjectIDs على أنها mongodb.ObjectId
(قابلة للتكوين مع معلمة useMongoObjectId
.)
(ملاحظة: يتم دعم هذا حاليًا فقط من قبل عملاء TWIRP.)
إذا كنت تستخدم عملاء TS-Proto للاتصال بالخدمات الصغيرة الخلفية ، على غرار مشكلة N+1 في تطبيقات SQL ، فمن السهل على عملاء الخدمة الصغيرة (عند تقديم طلب فردي) تشغيل مكالمات RPC منفصلة متعددة عن غير قصد "Get Book 1" ، "Get Book 2" ، "Get Book 3" ، يجب أن يتم تجميعها حقًا في "Get Books [1 ، 2 ، 3]" (على افتراض أن الواجهة الخلفية تدعم طريقة RPC الموجهة نحو الدفعة).
يمكن أن تساعد TS-Proto في هذا الأمر ، وبشكل تلقائي للمكالمات الفردية "Get Book" في مكالمات Get Bootsed "Get Books".
لكي تقوم TS-Proto بذلك ، تحتاج إلى تنفيذ أساليب RPC الخاصة بخدمتك من خلال اتفاقية تجديد:
اسم طريقة Batch<OperationName>
يحتوي نوع الإدخال Batch<OperationName>
على حقل متكرر واحد (أي repeated string ids = 1
)
يحتوي نوع الإخراج على Batch<OperationName>
حقل متكرر واحد (أي repeated Foo foos = 1
) حيث يكون ترتيب الإخراج هو نفسه ترتيب ids
الإدخال ، أو
خريطة الإدخال إلى الإخراج (أي map<string, Entity> entities = 1;
)
عندما يتعرف TS-Proto على أساليب هذا النمط ، فإنه سيقوم تلقائيًا بإنشاء إصدار "غير مدفوع" من <OperationName>
للعميل ، أي client.Get<OperationName>
يوفر هذا رمز العميل مع الوهم بأنه يمكن أن يجعل المكالمات الفردية Get<OperationName>
(والتي تكون أفضل/أسهل عمومًا عند تنفيذ منطق عمل العميل) ، لكن التنفيذ الفعلي الذي يوفره TS-Proto سينتهي به Batch<OperationName>
مكالمات إلى خدمة الخلفية.
تحتاج أيضًا إلى تمكين معلمة useContext=true
Building وقت ، والتي تمنح جميع أساليب العميل معلمة ctx
على غرار GO ، مع طريقة getDataLoaders
التي تتيح لـ TS-Proto Cache/ResoloSs Resolve Dataloaders ، والتي توفر أدوات تلقائية أساسية الكشف عن سلوك/تدفق السلوك.
راجع ملف batching.proto
والاختبارات ذات الصلة للحصول على أمثلة/مزيد من التفاصيل.
لكن التأثير الصافي هو أن TS-Proto يمكن أن يوفر الوقاية من N+1 على غرار SQL- / ORM لمكالمات العملاء ، والتي يمكن أن تكون حاسمة خاصة في التطبيقات ذات الحجم الكبير / المتوازي مثل GraphQL الأمامي الواجبات التي تستدعي الخدمات الخلفية الخلفية .
ts-proto
هو مكون إضافي protoc
، لذلك يمكنك تشغيله (إما مباشرة في مشروعك ، أو على الأرجح في خط أنابيب مخطط Mono-Repo الخاص بك ، أي مثل Ibotta أو أي:
أضف ts-proto
إلى package.json
الخاصة بك. json
قم بتشغيل npm install
لتنزيله
استدعاء protoc
مع معلمة plugin
مثل:
protoc-plugin = node_modules/ts-proto/protoc-gen-ts_proto ./batching.proto -i.
يمكن أيضًا استدعاء ts-proto
باستخدام Gradle باستخدام protobuf-regle-plugin:
protobuf { يمكن استبدال المكونات الإضافية {// `ts` بأي اسم مكون إضافي غير مستخدم ، مثل tsproto`ts { path = 'path/to/plugin'} } // هذا القسم مطلوب فقط إذا قمت بتقديم خيارات مكون الإضافي generateprotoSks { all (). كل {task -> task.plugins {// يجب أن يطابق معرف البرنامج المساعد المعلن عن abovets { خيار 'foo = bar'} } } } }
سيتم وضع رمز تم إنشاؤه في دليل إنشاء Gradle.
مع- --ts_proto_opt=globalThisPolyfill=true
، ستتضمن TS-Proto polyfill لـ GlobalTis.
الإعدادات الافتراضية إلى false
، أي نفترض أن globalThis
متاح.
مع- --ts_proto_opt=context=true
، سيكون للخدمات معلمة ctx
على غرار GO ، وهي مفيدة للتتبع/التسجيل/الخ. إذا كنت لا تستخدم واجهة برمجة async_hooks
في Node لأسباب الأداء.
مع- --ts_proto_opt=forceLong=long
، سيتم تحليل جميع الأرقام 64 بت كحالات Long
(باستخدام المكتبة الطويلة).
مع- --ts_proto_opt=forceLong=string
، سيتم إخراج جميع الأرقام 64 بت كسلاسل.
مع- --ts_proto_opt=forceLong=bigint
، سيتم إخراج جميع الأرقام 64 بت BigInt
s. لا يزال هذا الخيار يستخدم المكتبة long
لتشفير/فك تشفير داخليًا داخل protobuf.js
، ولكن بعد ذلك يتحول إلى/من BigInt
S في الكود الذي تم إنشاؤه بواسطة TS-Proto.
السلوك الافتراضي هو forceLong=number
، والذي لا يزال يستخدم داخليًا المكتبة long
لتشفير/فك تشفير القيم على السلك (لذلك ستظل ترى util.Long = Long
في الإخراج) ، ولكن ستحول القيم long
إلى number
تلقائيا بالنسبة لك. لاحظ أنه يتم طرح خطأ في وقت التشغيل إذا ، أثناء القيام بهذا التحويل ، تكون قيمة 64 بت أكبر مما يمكن تخزينه بشكل صحيح number
.
مع- --ts_proto_opt=useJsTypeOverride
، سيتم إخراج أرقام 64 بت كمؤسس. هذا يأخذ الأسبقية على خيار forceLong
المقدم.
مع --ts_proto_opt=esModuleInterop=true
ليكون متوافقًا مع esModuleInterop
.
على وجه التحديد ، سيتم إنشاء الواردات Long
import Long from 'long'
بدلاً من import * as Long from 'long'
.
باستخدام- --ts_proto_opt=env=node
أو browser
أو both
، فإن TS-proto سيجعل افتراضات خاصة بالبيئة في مخرجاتك. هذا الافتراضيات both
، مما لا يجعل أي افتراضات خاصة بالبيئة.
يؤدي استخدام node
إلى تغيير أنواع bytes
من Uint8Array
إلى Buffer
لتكامل أسهل مع النظام الإيكولوجي للعقدة والذي يستخدم Buffer
عمومًا.
لا يحتوي browser
حاليًا على أي سلوك محدد بخلاف "وليس node
". ربما سوف قريبا/في مرحلة ما.
مع --ts_proto_opt=useOptionals=messages
(لحقول الرسائل) أو --ts_proto_opt=useOptionals=all
(للرسالة والحقول العددية) ، يتم إعلان الحقول كمفاتيح اختيارية ، على سبيل المثال field?: Message
بدلاً من field: Message | undefined
.
الإعدادات الافتراضية TS-Proto إلى useOptionals=none
لأنها:
للوقاية من الأخطاء المطبعية ، تجعل الحقول الاختيارية من السهل على الحقول الإضافية أن تنزلق إلى رسالة (حتى نحصل على أنواع دقيقة) ، أي:
واجهة somemessage { FirstName: String ؛ lastName: string ؛} // تم الإعلان عنها باستخدام بيانات typoconst = {firstName: "a" ، lasttypo: "b"} ؛ // with useOptionals = none ، فشل هذا بشكل صحيح في التجميع ؛ إذا كان `lastName` اختياريًا ، فلن يكون رسالة: somemessage = {... data} ؛
للحصول على واجهة برمجة تطبيقات متسقة ، إذا كان SomeMessage.lastName
هو lastName?
، ثم يتعين على القراء التحقق من شرطين فارغين: أ) lastName
undefined
(b/c تم إنشاؤه في الذاكرة والخلع الأيسر) ، أو ب) lastName
frank string (b/c نقرأ SomeMessage
قبالة السلك ، وباللأول المواصفات proto3 ، lastName
العائلة إلى سلسلة فارغة)؟
لضمان التهيئة السليم ، إذا تمت إضافة SomeMessage.middleInitial
في وقت لاحق ، ولكن تم تمييزها على أنها middleInitial?
، قد يكون لديك العديد من مواقع الاتصال في رمز الإنتاج والتي يجب أن تمر الآن middleInitial
لإنشاء SomeMessage
صحيح ، ولكن ليس كذلك.
لذلك ، بين إعادة الانتهاء المطبعية ، والتناقض القارئ ، والتهيئة السليم ، توصي TS-Proto باستخدام useOptionals=none
كخيار "الأكثر أمانًا".
كل ما قيل ، هذا النهج يتطلب من الكتاب/المبدعين تعيين كل حقل (على الرغم من أن fromPartial
و create
من المقصود معالجة هذا) ، لذلك إذا كنت لا تزال ترغب في الحصول على مفاتيح اختيارية ، فيمكنك تعيين useOptionals=messages
أو useOptionals=all
.
(انظر هذه المسألة وهذه القضية للمناقشات حول useOptional
.)
يمنع الأخطاء المطبعية عند تهيئة الرسائل ، و
يوفر واجهة برمجة التطبيقات الأكثر اتساقًا للقراء
يضمن تهيئة رسائل الإنتاج بشكل صحيح مع جميع الحقول.
مع --ts_proto_opt=exportCommonSymbols=false
، لن تكون أنواع الأدوات المساعدة مثل DeepPartial
و protobufPackage
export
d.
هذا يجب أن يجعل من الممكن استخدام إنشاء واردات برميل للإخراج الذي تم إنشاؤه ، أي import * from ./foo
و import * from ./bar
.
لاحظ أنه إذا كان لديك نفس اسم الرسالة المستخدمة في ملفات متعددة *.proto
، فستظل تحصل على تعارضات استيراد.
مع --ts_proto_opt=oneof=unions
، سيتم إنشاء حقول oneof
كـ ADTs.
انظر قسم "معالجة Oneof".
مع --ts_proto_opt=unrecognizedEnumName=<NAME>
سوف تحتوي التعدادات على مفتاح <NAME>
مع قيمة خيار unrecognizedEnumValue
.
الإعدادات الافتراضية إلى UNRECOGNIZED
.
مع --ts_proto_opt=unrecognizedEnumValue=<NUMBER>
سيحتوي التعدادات على مفتاح يوفره خيار unrecognizedEnumName
مع قيمة <NUMBER>
.
الإعدادات الافتراضية إلى -1
.
مع --ts_proto_opt=unrecognizedEnum=false
على مفتاح التعداد غير المعترف به والقيمة كما هو منصوص عليه في خيارات unrecognizedEnumName
وخيارات unrecognizedEnumValue
.
مع --ts_proto_opt=removeEnumPrefix=true
سوف يتم إزالة اسم التعداد من الأعضاء.
FooBar.FOO_BAR_BAZ = "FOO_BAR_BAZ"
إنشاء FooBar.BAZ = "FOO_BAR_BAZ"
باستخدام- --ts_proto_opt=lowerCaseServiceMethods=true
، سيتم تخفيض أسماء طرق أساليب الخدمة/حالة الإبل ، ie service.findFoo
بدلاً من service.FindFoo
.
باستخدام --ts_proto_opt=snakeToCamel=false
، سيتم الاحتفاظ بالحقول في حالة ثعبان في كل من مفاتيح الرسائل وأساليب toJSON
/ fromJSON
.
يمكن أيضًا تعيين snakeToCamel
_
من السلاسل المخصصة (تم حجز الفاصلة على أنها محددة العلم) ، أي --ts_proto_opt=snakeToCamel=keys_json
، حيث ستقوم بما في json
keys
أن تجعل مفاتيح الرسائل عبارة قضية الجمال.
ستؤدي السلسلة الفارغة ، أي snakeToCamel=
، إلى الحفاظ على مفاتيح الرسائل ومفاتيح JSON
كحالة ثعبان (إنها نفس snakeToCamel=false
).
لاحظ أنه لاستخدام سمة json_name
، يجب عليك استخدام json
.
السلوك الافتراضي هو keys_json
، أي كلاهما سيكون جمل ، وسيتم استخدام json_name
إذا تم تعيينه.
مع- --ts_proto_opt=outputEncodeMethods=false
، لن يتم إخراج Message.encode
و Message.decode
للعمل مع البيانات التي ترميزها protobuf/الثنائية.
هذا مفيد إذا كنت تريد "الأنواع فقط".
مع- --ts_proto_opt=outputJsonMethods=false
، لن يتم إخراج Message.fromJSON
و Message.toJSON
للعمل مع البيانات المشفرة JSON.
هذا مفيد أيضًا إذا كنت تريد "أنواع فقط".
مع- --ts_proto_opt=outputJsonMethods=to-only
و --ts_proto_opt=outputJsonMethods=from-only
ستتمكن من تصدير واحد فقط بين Message.toJSON
و Message.fromJSON
.
هذا مفيد إذا كنت تستخدم TS-Proto فقط encode
أو decode
وليس لكليهما.
مع- --ts_proto_opt=outputPartialMethods=false
، لن يتم إخراج Message.fromPartial
و Message.create
.
مع- --ts_proto_opt=stringEnums=true
، ستكون أنواع التعدادات التي تم إنشاؤها قائمة على السلسلة بدلاً من int.
يعد هذا مفيدًا إذا كنت تريد "أنواع فقط" وتستخدم بوابة REF GRPC التي تم تكوينها لتسلسل التعدادات كسلاسل.
(يتطلب outputEncodeMethods=false
.)
مع- --ts_proto_opt=outputClientImpl=false
، فإن تطبيقات العميل ، أي FooServiceClientImpl
، التي تنفذ جانب العميل (في twirp ، انظر الخيار التالي لواجهات grpc-web
) لن يتم إخراجها.
مع- --ts_proto_opt=outputClientImpl=grpc-web
، ستستخدم تطبيقات العميل ، أي FooServiceClientImpl
، مكتبة @eng-eng/grpc-web في وقت التشغيل لإرسال رسائل GRPC إلى دعم GRPC-Web.
(لاحظ أن هذا يستخدم فقط وقت تشغيل GRPC-Web ، فأنت لا تحتاج إلى استخدام أي من الكود الذي تم إنشاؤه ، أي أن إخراج TS-Proto يحل محل إخراج ts-protoc-gen
الخاص بهم.)
ستحتاج إلى إضافة @improbable-eng/grpc-web
ونقل إلى package.json
مشروعك. راجع دليل integration/grpc-web
للحصول على مثال عمل. انظر أيضًا #504 للتكامل مع GRPC-Web-Devtools.
مع --ts_proto_opt=returnObservable=true
، يمكن Observable<T>
بدلاً من Promise<T>
.
مع --ts_proto_opt=addGrpcMetadata=true
، ستقبل الوسيطة الأخيرة من أساليب الخدمة نوع Metadata
GRPC ، والذي يحتوي على معلومات إضافية مع المكالمة (أي الوصول إلى الرموز/إلخ).
(يتطلب nestJs=true
.)
مع --ts_proto_opt=addNestjsRestParameter=true
، ستكون الوسيطة الأخيرة من أساليب الخدمة هي معلمة REST مع أي نوع. وبهذه الطريقة ، يمكنك استخدام ديكورات مخصصة يمكنك استخدامها عادة في NESTJS.
(يتطلب nestJs=true
.)
باستخدام- --ts_proto_opt=nestJs=true
، ستتغير الافتراضات لإنشاء أنواع وواجهات خدمة NESTJS ProtoBuf التي يمكن استخدامها في كل من تطبيقات العميل وجانب خادم تطبيقات NESTJS. راجع NESTJS README لمزيد من المعلومات وأمثلة التنفيذ.
على وجه التحديد ، سيكون كل outputEncodeMethods
و outputJsonMethods
و outputClientImpl
خاطئة ، وسوف تكون lowerCaseServiceMethods
صحيحة وسيتم تجاهل outputServices
.
لاحظ أن addGrpcMetadata
و addNestjsRestParameter
و returnObservable
سيظلون خاطئين.
مع --ts_proto_opt=useDate=false
، لن يتم تعيين حقول من google.protobuf.Timestamp
لكتابة Date
في الأنواع التي تم إنشاؤها. انظر الطابع الزمني لمزيد من التفاصيل.
باستخدام --ts_proto_opt=useMongoObjectId=true
، سيتم تعيين الحقول من نوع يسمى ObjectID حيث يتم إنشاء الرسالة على الحقل المسمى القيمة التي تكون سلسلة لكتابة mongodb.ObjectId
في الأنواع التي تم إنشاؤها. سيتطلب ذلك مشروعك لتثبيت حزمة MongoDB NPM. انظر ObjectID لمزيد من التفاصيل.
مع- --ts_proto_opt=annotateFilesWithVersion=false
، لن تحتوي الملفات التي تم إنشاؤها على إصدارات protoc
و ts-proto
المستخدمة لإنشاء الملف. عادة ما يتم تعيين هذا الخيار على true
، بحيث تسرد الملفات الإصدارات المستخدمة.
مع --ts_proto_opt=outputSchema=true
، سيتم إنشاء طباعات التعريف التي يمكن استخدامها لاحقًا في مولدات الرموز الأخرى.
مع- --ts_proto_opt=outputSchema=no-file-descriptor
، سيتم إنشاء طباعة meta ، لكننا لا ندرج واصف الملف في المخطط الذي تم إنشاؤه. هذا مفيد إذا كنت تحاول تقليل حجم المخطط الذي تم إنشاؤه.
باستخدام- --ts_proto_opt=outputSchema=const
، سيتم إنشاء طباعات meta as const
، مما يتيح الوصول الآمن إلى جميع خصائصه. (يعمل فقط مع TypeScript 4.9 وما فوق ، لأنه يستخدم أيضًا المشغل satisfies
). يمكن دمجها مع خيار no-file-descriptor
( outputSchema=const,outputSchema=no-file-descriptor
) لعدم تضمين واصف الملف في المخطط الذي تم إنشاؤه.
باستخدام- --ts_proto_opt=outputTypeAnnotations=true
، سيتم إعطاء كل رسالة حقل $type
يحتوي على اسمه المؤهل بالكامل. يمكنك استخدام- --ts_proto_opt=outputTypeAnnotations=static-only
لإلغاءه من إعلان interface
، أو- --ts_proto_opt=outputTypeAnnotations=optional
لجعله خاصية اختيارية على تعريف interface
. قد يكون الخيار الأخير مفيدًا إذا كنت ترغب في استخدام حقل $type
لفحص نوع وقت التشغيل على الاستجابات من خادم.
باستخدام- --ts_proto_opt=outputTypeRegistry=true
، سيتم إنشاء سجل النوع الذي يمكن استخدامه لحل أنواع الرسائل عن طريق الاسم المؤهل بالكامل. أيضًا ، سيتم منح كل رسالة حقل $type
يحتوي على اسمه المؤهل بالكامل.
مع- --ts_proto_opt=outputServices=grpc-js
، ستقوم TS-proto بإخراج تعريفات الخدمة والخادم / العميل بتنسيق GRPC-JS.
مع- --ts_proto_opt=outputServices=generic-definitions
، ستخرج TS-Proto تعريفات الخدمة العامة (الإطار الغذائي). تحتوي هذه التعريفات على واصفات لكل طريقة مع روابط لأنواع الطلب والاستجابة ، والتي تسمح بإنشاء كعب الخادم والعميل في وقت التشغيل ، وكذلك إنشاء أنواع قوية لهم في وقت الترجمة. مثال على المكتبة التي تستخدم هذا النهج هو GRPC لطيف.
مع- --ts_proto_opt=outputServices=nice-grpc
، ستقوم TS-proto بإخراج خادم وعبادة العميل لـ NICE-GRPC. يجب استخدام هذا جنبًا إلى جنب مع التعاريف العامة ، أي يجب عليك تحديد خيارين: outputServices=nice-grpc,outputServices=generic-definitions
.
مع- --ts_proto_opt=metadataType=Foo@./some-file
باستخدام- --ts_proto_opt=outputServices=generic-definitions,outputServices=default
، سوف يخرج TS-proto من التعريفات والواجهات العامة. هذا مفيد إذا كنت ترغب في الاعتماد على الواجهات ، ولكن لديك أيضًا بعض إمكانيات الانعكاس في وقت التشغيل.
مع- --ts_proto_opt=outputServices=false
، أو =none
، لن يقوم TS-Proto بإخراج أي تعريفات خدمة.
باستخدام- --ts_proto_opt=rpcBeforeRequest=true
، ستضيف TS-proto تعريف وظيفة إلى تعريف واجهة RPC مع التوقيع: beforeRequest(service: string, message: string, request: <RequestType>)
. كما سيتم تعيين outputServices=default
. ستستدعي كل من أساليب الخدمة beforeRequest
قبل تنفيذ طلبها.
مع- --ts_proto_opt=rpcAfterResponse=true
، ستضيف TS-proto تعريف وظيفة إلى تعريف واجهة RPC مع التوقيع: afterResponse(service: string, message: string, response: <ResponseType>)
. كما سيتم تعيين outputServices=default
. ستتصل كل من أساليب الخدمة afterResponse
قبل إعادة الاستجابة.
باستخدام- --ts_proto_opt=rpcErrorHandler=true
، ستضيف TS-proto تعريف الوظيفة إلى تعريف واجهة RPC مع التوقيع: handleError(service: string, message: string, error: Error)
. كما سيتم تعيين outputServices=default
.
مع --ts_proto_opt=useAbortSignal=true
، ستقبل الخدمات التي تم إنشاؤها AbortSignal
لإلغاء مكالمات RPC.
مع --ts_proto_opt=useAsyncIterable=true
، ستستخدم الخدمات التي تم إنشاؤها AsyncIterable
بدلاً من Observable
.
مع- --ts_proto_opt=emitImportedFiles=false
، لن تنبعث TS-proto google/protobuf/*
ما لم تقم بصحة إضافة ملفات إلى protoc
مثل هذا protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto my_message.proto google/protobuf/duration.proto
باستخدام- --ts_proto_opt=fileSuffix=<SUFFIX>
، سوف ينبعث TS-proto ملفات تم إنشاؤها باستخدام اللاحقة المحددة. سيتم إنشاء ملف helloworld.proto
مع fileSuffix=.pb
كـ helloworld.pb.ts
. هذا سلوك شائع في الإضافات الأخرى لـ Protoc ويوفر طريقة لربط جميع الملفات التي تم إنشاؤها بسرعة.
مع- --ts_proto_opt=importSuffix=<SUFFIX>
، سوف ينبعث TS-proto واردات الملفات باستخدام اللاحقة المحددة. استيراد helloworld.ts
مع fileSuffix=.js
سوف يولد import "helloworld.js"
. الافتراضي هو الاستيراد بدون تمديد ملف. بدعم من TypeScript 4.7.x وما فوق.
مع- --ts_proto_opt=enumsAsLiterals=true
، ستكون أنواع التعدادات التي تم إنشاؤها كائن enum-ish مع as const
.
مع --ts_proto_opt=useExactTypes=false
، لن يستخدم الأساليب التي تم إنشاؤها fromPartial
create
أنواعًا دقيقة.
السلوك الافتراضي هو useExactTypes=true
، مما يجعل fromPartial
create
نوع دقيق للوسيطة لجعل TypeScript يرفض أي خصائص غير معروفة.
مع --ts_proto_opt=unknownFields=true
، سيتم تحليل جميع الحقول غير المعروفة والإخراج كصفائف من المخازن المؤقتة.
مع --ts_proto_opt=onlyTypes=true
، سيتم استبعاد الأنواع فقط ، وسيتم استبعاد الواردات لفترة long
و protobufjs/minimal
.
هذا هو نفسه تعيين outputJsonMethods=false,outputEncodeMethods=false,outputClientImpl=false,nestJs=false
مع --ts_proto_opt=usePrototypeForDefaults=true
، سوف يلف الرمز الذي تم إنشاؤه كائنات جديدة باستخدام Object.create
.
يتيح هذا الكود القيام بفحص Hazzer للكشف عند تطبيق القيم الافتراضية ، والذي نظرًا لسلوك Proto3 لعدم وضع القيم الافتراضية على السلك ، عادة ما يكون مفيدًا فقط للتفاعل مع رسائل Proto2.
عند تمكينه ، يتم توريث القيم الافتراضية من نموذج أولي ، وبالتالي يمكن أن يستخدم الكود Object.Keys (). يتضمن ("Somefield") اكتشاف ما إذا كان Somefield قد تم فك تشفيره بالفعل أم لا.
لاحظ أنه ، كما هو مبين ، هذا يعني أن Object.Keys لن يتضمن حقولًا محددة من حيث الفواصل ، لذلك إذا كان لديك رمز يتكرر على مفاتيح الرسائل بطريقة عامة ، فسيتعين عليها أيضًا التكرار عبر المفاتيح الموروثة من النموذج الأولي.
مع --ts_proto_opt=useJsonName=true
، سيتم استخدام json_name
في البروتوفيل بدلاً من أسماء حقل الرسائل.
مع --ts_proto_opt=useJsonWireFormat=true
، سوف يعكس الرمز الذي تم إنشاؤه تمثيل JSON لرسائل protobuf.
يتطلب onlyTypes=true
. يعني استخدام useDate=string
و stringEnums=true
. هذا الخيار هو إنشاء أنواع يمكن استخدامها مباشرة مع Marchalling/Unmarshalling Protobuf رسائل مسلسل كـ JSON. قد ترغب أيضًا في تعيين useOptionals=all
، حيث لا يلزم بوابات GRPC إرسال القيمة الافتراضية لقيم العددية.
مع --ts_proto_opt=useNumericEnumForJson=true
، سيقوم محول JSON ( toJSON
) بتشفير قيم التعداد على أنها int ، بدلاً من سلسلة حرفية.
مع --ts_proto_opt=initializeFieldsAsUndefined=false
، سيتم حذف جميع أجهزة التهيئة الحقل الاختيارية من مثيلات أساسية تم إنشاؤها.
مع --ts_proto_opt=disableProto2Optionals=true
، لن يتم تعيين جميع الحقول الاختيارية على ملفات proto2 لتكون اختيارية. يرجى ملاحظة أن هذه العلامة هي في المقام الأول للحفاظ على معالجة TS-Proto القديمة لملفات proto2 ، لتجنب كسر التغييرات ، ونتيجة لذلك ، لا يُقصد استخدامها إلى الأمام.
مع --ts_proto_opt=disableProto2DefaultValues=true
، فإن جميع الحقول في ملفات proto2 التي تحدد القيمة الافتراضية لن تستخدم هذه القيمة الافتراضية بالفعل. يرجى ملاحظة أن هذه العلامة هي في المقام الأول للحفاظ على معالجة TS-Proto القديمة لملفات proto2 ، لتجنب كسر التغييرات ، ونتيجة لذلك ، لا يُقصد استخدامها إلى الأمام.
مع- --ts_proto_opt=Mgoogle/protobuf/empty.proto=./google3/protobuf/empty
./google/protobuf/empty.ts
سوف يعكس ./google/protobuf/empty.ts
القيمة المتجاوز:
Mfoo/bar.proto=@myorg/some-lib
سوف يقوم بتخطيط foo/bar.proto
الواردات في import ... from '@myorg/some-lib'
.
Mfoo/bar.proto=./some/local/lib
سوف يرسم foo/bar.proto
الواردات إلى import ... from './some/local/lib'
.
Mfoo/bar.proto=some-modules/some-lib
سوف تقوم بتخطيط foo/bar.proto
إلى import ... from 'some-module/some-lib'
.
ملاحظة : تتراكم الاستخدامات ، لذلك من المتوقع أن تكون هناك قيم متعددة في شكل --ts_proto_opt=M... --ts_proto_opt=M...
(واحد ts_proto_opt
لكل تعيين).
ملاحظة : لن يتم إنشاء ملفات proto التي تتطابق مع الواردات المعينة.
باستخدام --ts_proto_opt=useMapType=true
، سيصبح الرمز الذي تم إنشاؤه map<key_type, value_type>
Map<key_type, value_type>
التي تستخدم نوع خريطة JavaScript.
السلوك الافتراضي هو useMapType=false
، مما يجعله ينشئ الرمز map<key_type, value_type
مع زوج قيمة المفاتيح مثل {[key: key_type]: value_type}
.
مع --ts_proto_opt=useReadonlyTypes=true
، سيتم الإعلان عن الأنواع التي تم إنشاؤها على أنها غير قابلة للتغيير باستخدام المعدل readonly
الخاص بـ TypeScript.
مع --ts_proto_opt=useSnakeTypeName=false
سوف يزيل غلاف الأفعى من الأنواع.
مثال protobuf
مربع الرسالة {message element {message image {enum alignment {left = 1 ؛ المركز = 2 ؛ اليمين = 3 ؛ } } } }
بشكل افتراضي ، يتم تمكين هذا والذي من شأنه إنشاء نوع من Box_Element_Image_Alignment
. من خلال تعطيل هذا الخيار ، سيكون النوع الذي تم إنشاؤه هو BoxElementImageAlignment
.
مع --ts_proto_opt=outputExtensions=true
، سيتضمن الرمز الذي تم إنشاؤه امتدادات proto2
تتوافق طرق تشفير/فك تشفير الامتداد مع خيار outputEncodeMethods
، وإذا كان unknownFields=true
، فسيتم إنشاء طرق setExtension
و getExtension
للرسائل القابلة للتمديد ، كما تمثلها إخراج outputEncodeMethods
(setextension = encode ، getextension = decode).
باستخدام --ts_proto_opt=outputIndex=true
، سيتم إنشاء ملفات الفهرس بناءً على مساحات أسماء حزمة proto.
سيؤدي ذلك إلى تعطيل exportCommonSymbols
لتجنب تصادمات الاسم على الرموز الشائعة.
مع- --ts_proto_opt=emitDefaultValues=json-methods
، ستنبعث طريقة Tojson التي تم إنشاؤها من المقالين مثل 0
و ""
كحقول JSON.
باستخدام --ts_proto_opt=comments=false
، لن يتم نسخ التعليقات من ملفات proto إلى الكود الذي تم إنشاؤه.
مع --ts_proto_opt=bigIntLiteral=false
، سوف يستخدم الكود الذي تم إنشاؤه BigInt("0")
بدلاً من 0n
للحرفية Bigint. لا تدعم TypeInt Distscript Bigint TypeScript عندما يتم تعيين خيار برنامج التحويل البرمجي "الهدف" على شيء أقدم من "ES2020".
مع --ts_proto_opt=useNullAsOptional=true
، سيتم تحويل القيم undefined
إلى null
، وإذا كنت تستخدم التسمية optional
في ملف .proto
الخاص بك ، فسيكون للحقل نوعًا undefined
أيضًا. على سبيل المثال:
مع --ts_proto_opt=typePrefix=MyPrefix
، سيكون للواجهات والتعداد والمصانع التي تم إنشاؤها بادئة MyPrefix
في أسمائها.
مع --ts_proto_opt=typeSuffix=MySuffix
، سيكون للواجهات والتعداد والمصانع التي تم إنشاؤها لاحقة من MySuffix
في أسمائها.
message profileInfo {int32 id = 1 ؛ String Bio = 2 ؛ String Phone = 3 ؛ } قسم الرسائل {int32 id = 1 ؛ اسم السلسلة = 2 ؛ } message user {int32 id = 1 ؛ user username = 2 ؛/* profileInfo سيكون اختياريًا في typeScript ، سيكون النوع هو profileInfo | فارغ | غير محدد هذا مطلوب في الحالات التي لا تريد تقديم فيها أي قيمة لملف التعريف. */ملف تعريف الملف الشخصي الاختياري = 3 ؛/* يقبل القسم فقط نوع القسم أو الفارغ ، لذلك هذا يعني أنه يتعين عليك تمريره الفارغ إذا لم تكن هناك قيمة متاحة. */قسم القسم = 4 ؛ }
ستكون الواجهات التي تم إنشاؤها:
تصدير واجهة profileInfo { معرف: رقم ؛ السيرة الذاتية: سلسلة ؛ الهاتف: سلسلة ؛} قسم واجهة التصدير { معرف: رقم ؛ الاسم: string ؛} مستخدم واجهة التصدير { معرف: رقم ؛ اسم المستخدم: سلسلة ؛ الملف الشخصي؟: profileInfo | فارغ | غير محدد // تحقق من هذا القسم: قسم | باطل؛ // تحقق من هذا}
مع --ts_proto_opt=noDefaultsForOptionals=true
، لن يتم افتراض القيم البدائية undefined
وفقًا لمواصفات protobuf. بالإضافة إلى ذلك ، على عكس السلوك القياسي ، عندما يتم تعيين حقل على القيمة الافتراضية القياسية ، سيتم ترميزه مما يسمح بإرساله عبر السلك والتمييز عن القيم غير المحددة. على سبيل المثال ، إذا لم تضع الرسالة قيمة منطقية ، فسيتم ذلك عادةً ما يتم تخلفه إلى false
وهو مختلف عن كونه غير محدد.
يسمح هذا الخيار للمكتبة بالعمل بطريقة متوافقة مع تنفيذ الأسلاك الذي يتم الحفاظ عليه واستخدامه بواسطة Square/Block. ملاحظة: يجب استخدام هذا الخيار فقط مع رمز العميل/الخادم الآخر الذي تم إنشاؤه باستخدام Wire أو TS-Proto مع تمكين هذا الخيار.
لدينا طريقة رائعة للعمل مع Nestjs. يقوم ts-proto
بإنشاء interfaces
decorators
لك ، العميل. لمزيد من المعلومات ، راجع Nestjs ReadMe.
إذا كنت ترغب في تشغيل ts-proto
على كل تغيير في ملف proto ، فستحتاج إلى استخدام أداة مثل Chokidar-Cli واستخدامها كنصوص في package.json
:
"proto: إنشاء": C "NPM Run Proto: إنشاء" "
ts-proto
هو RPC Framework Adostic - كيف تنقل بياناتك من وإلى مصدر البيانات الخاص بك متروك لك. تتوقع تطبيقات العميل التي تم إنشاؤها جميعًا معلمة rpc
، أي نوع يتم تعريفه على هذا النحو:
واجهة RPC { طلب (الخدمة: سلسلة ، الطريقة: السلسلة ، البيانات: uint8array): وعد <Uint8array> ؛}
إذا كنت تعمل مع GRPC ، فقد يبدو التنفيذ البسيط هكذا:
const conn = new grpc.client ( "المضيف المحلي: 8765" ، grpc.credentials.createinsecure ()) ؛ اكتب rpcimpl = (الخدمة: السلسلة ، الطريقة: السلسلة ، البيانات: uint8array) => الوعد <Uint8array> ؛ const sendRequest: rpcimpl = (الخدمة ، الطريقة ، البيانات) => { // بشكل تقليدي في GRPC ، يبدو مسار الطلب // "package.names.servicename/methodname" ، // نحن بناء مثل هذه السلسلة const path = `/$ {service}/$ {method}` ؛ إرجاع وعد جديد ((حل ، رفض) => {// MakeUnaryRequest ينقل النتيجة (والخطأ) باستخدام رد الاتصال // تحويل هذا إلى وعد! (err) {return refect (err) ؛ ، resultcallback) ؛ }) ؛} ؛ const rpc: rpc = {request: sendRequest} ؛
مجد لرعاةنا:
قامت NGROK بتمويل دعم GRPC-Web الأولي لـ TS-Proto.
إذا كنت بحاجة إلى تخصيصات TS-Proto أو دعم الأولوية لشركتك ، فيمكنك Ping Me في عبر البريد الإلكتروني.
يصف هذا القسم كيفية المساهمة مباشرة في TS-Proto ، أي أنه ليس مطلوبًا لتشغيل ts-proto
في protoc
أو باستخدام TypeScript تم إنشاؤه.
متطلبات
عامل ميناء
yarn
npm install -g yarn
يثبت
أفترض الأوامر أدناه أنك قمت بتثبيت Docker . إذا كنت تستخدم OS X ، فقم بتثبيت CoreUtils ، brew install coreutils
.
تحقق من المستودع للحصول على أحدث الكود.
قم بتشغيل yarn install
لتثبيت التبعيات.
قم بتشغيل yarn build:test
لإنشاء ملفات الاختبار.
هذا يدير الأوامر التالية:
proto2ts
يقوم بتشغيل ts-proto
على ملفات integration/**/*.proto
لإنشاء ملفات .ts
.
proto2pbjs
- يولد تطبيق مرجعي باستخدام pbjs
لاختبار التوافق.
تشغيل yarn test
سير العمل
إضافة/تحديث اختبار التكامل لحالة الاستخدام الخاصة بك
يمكنك أيضًا ترك yarn watch
الجري ، ويجب أن "مجرد فعل الشيء الصحيح"
قم بعمل integration/your-new-test/parameters.txt
ts_proto_opt
قم بإنشاء الحد الأدنى integration/your-new-test/your-new-test.proto
مخطط بروتو لإعادة إنتاج حالة الاستخدام الخاصة بك
إما أن تجد اختبار integration/*
قريب بما يكفي من ts_proto_opt
الاستخدام الخاصة بك ، على سبيل المثال ، يحتوي على parameters.txt
إذا تم إنشاء اختبار تكامل جديد:
بعد أي تغييرات على your-new-test.proto
، أو ملف دمج yarn proto2bin
integration/*.proto
أضف/تحديث اختبار وحدة integration/your-new-test/some-test.ts
.
تعديل منطق توليد رمز ts-proto
:
أو yarn proto2ts your-new-test
لإعادة توحيد اختبار محدد
مرة أخرى ، يجب أن تترك yarn watch
الجري "فقط افعل الشيء الصحيح"
تم العثور على أهم منطق في SRC/Main.ts.
بعد أي تغييرات على ملفات src/*.ts
yarn proto2ts
قم بتشغيل yarn test
للتحقق من التغييرات الخاصة بك اجتياز جميع الاختبارات الموجودة
ارتكاب العلاقات العامة وتقديمها
في بعض الأحيان يكون التحقق من التعليمات البرمجية التي تم إنشاؤها مستهجنًا ، ولكن بالنظر إلى الوظيفة الرئيسية لـ TS-Proto هي إنشاء رمز ، ورؤية فرق Codegen في PRS مفيد
قم بتشغيل yarn format
لتنسيق ملفات TypeScript.
تأكد من git add
جميع ملفات *.proto
و *.bin
و *.ts
في integration/your-new-test
اختبار في مشاريعك
يمكنك اختبار تغييرات TS-Proto المحلية في مشاريعك الخاصة عن طريق تشغيل yarn add ts-proto@./path/to/ts-proto
، طالما أنك تقوم yarn build
يدويًا.
protoc protoc
يتضمن المستودع نسخة مقيد من protoc
، والتي تم تكوينها في Docker-corm.yml.
يمكن أن يكون مفيدًا في حال كنت ترغب في استدعاء البرنامج المساعد يدويًا مع إصدار معروف من protoc
.
الاستخدام:
# قم بتضمين الاسم المستعار Protoc في Shell .. aliases.sh# Run Protoc كالمعتاد. يتوفر دليل TS-Proto في/ts-proto.protoc-plugin =/ts-proto/protoc-gen-ts_proto-tres_proto_out =./output -i =./protos ./protoc/*. استخدم الاسم المستعار TS-Protoc الذي يحدد مسار البرنامج المساعد لك. ts-protoc-tts_proto_out =./output -i =./protos ./protoc/*.proto
يجب أن تكون جميع المسارات مسارات نسبية داخل دليل العمل الحالي للمضيف. ../
غير مسموح به
داخل حاوية Docker ، المسار المطلق لجذر المشروع هو /ts-proto
تقوم الحاوية بتركيب دليل العمل الحالي في /host
، وتعيينه كدليل عمل.
بمجرد الحصول على aliases.sh
، يمكنك استخدام أمر protoc
في أي مجلد.
اسم وحدة TS/ES6 هو حزمة Proto
دعم ترميز المدة المستندة إلى السلسلة في fromJSON
/ toJSON
اجعل oneof=unions-value
السلوك الافتراضي في 2.0
ربما تغيير الافتراضي forceLong
في 2.0 ، يجب أن تتخلف عن forceLong=long
اجعل esModuleInterop=true
الافتراضي في 2.0
بشكل افتراضي ، نماذج TS-Proto oneof
الحقول "بشكل قاطع" في الرسالة ، على سبيل المثال رسالة مثل:
Message foo {oneof than_field {string field_a = 1 ؛ سلسلة field_b = 2 ؛ } }
سيقوم بإنشاء نوع Foo
مع حقلين: field_a: string | undefined;
و field_b: string | undefined
.
مع هذا الإخراج ، سيتعين عليك التحقق من كلاهما إذا if object.field_b
if object.field_a
.
بدلاً من ذلك ، نوصي باستخدام خيار oneof=unions-value
، والذي سيغير الإخراج ليكون نوع بيانات جبري/ADT مثل:
واجهة yourmessage { إما ساحة؟: {$ case: "field_a" ؛ القيمة: سلسلة} | {$ case: "field_b" ؛ القيمة: سلسلة} ؛}
نظرًا لأن هذا سيقوم تلقائيًا بفرض واحد فقط من field_a
أو field_b
"يجري تعيينه" في وقت واحد ، لأن القيم يتم تخزينها في حقل eitherField
الذي يمكن أن يكون له قيمة واحدة فقط في وقت واحد.
(لاحظ أن eitherField
هو b/c oneof
في protobuf يعني "في الحقل على الأكثر" ، ولا يعني أن أحد الحقول يجب تعيينه.)
في إصدار TS-Proto الذي لم يتم تحديده حاليًا 2.x ، ستصبح oneof=unions-value
السلوك الافتراضي.
يوجد أيضًا خيار oneof=unions
، والذي يولد اتحادًا حيث يتم تضمين أسماء الحقل في كل خيار:
واجهة yourmessage { إما ساحة؟: {$ case: "field_a" ؛ field_a: string} | {$ case: "field_b" ؛ field_b: string} ؛}
لم يعد الأمر موصى به لأنه قد يكون من الصعب كتابة التعليمات البرمجية والأنواع للتعامل مع خيارات متعددة:
قد تجعل أنواع المساعد التالية من السهل العمل مع الأنواع التي تم إنشاؤها من oneof=unions
، على الرغم من أنها غير مطلوبة عمومًا إذا كنت تستخدم oneof=unions-value
:
/** يستخرج جميع أسماء الحالات من حقل واحد. */اكتب OneOfCases <T> = T يمتد {$ CASE: استنتاج U يمتد String}؟ u: never ؛/** يستخرج اتحاد لجميع أنواع القيمة من حقل واحد*/type OneOfvalues <t> = t يمتد {$ case: invter U تمديد السلسلة ؛ [المفتاح: سلسلة]: غير معروف}؟ t [u]: never ؛/** يستخلص النوع المحدد لحالة واحدة استنادًا إلى اسم الحقل*/type OneOfCase <t القضية $: K ؛ [المفتاح: سلسلة]: غير معروف ؛} ؟ ر : أبدًا ؛/** يستخلص النوع المحدد لنوع القيمة من حقل واحد*/type OneOfValue <t ، k يمتد OneOfCases <t >> = t يمتد { الحالة $: استنتاج U يمتد K ؛ [المفتاح: سلسلة]: غير معروف ؛} ؟ ر [ش] : أبداً؛
للمقارنة ، فإن المعادلات oneof=unions-value
:
/** يستخرج جميع أسماء الحالات من حقل واحد. */اكتب OneOfCases <T> = t ['$ case'] ؛/** يستخلص اتحاد لجميع أنواع القيمة من حقل واحد*/type OneOfvalues <t> = t ['value'] ؛/** يستخلص النوع المحدد لحالة واحدة على أساس اسم الحقل الخاص به */type OneOfcase <t ، k يمتد OneOfCases <t >> = t يمتد { القضية $: K ؛ [المفتاح: سلسلة]: غير معروف ؛} ؟ ر : أبدًا ؛/** يستخلص النوع المحدد لنوع القيمة من حقل واحد*/type OneOfValue <t ، k يمتد OneOfCases <t >> = t يمتد { الحالة $: استنتاج U يمتد K ؛ القيمة: غير معروف ؛} ؟ ر [ش] : أبداً؛
في Protobuf الأساسي (وكذلك ts-proto
) ، لا يتم إرسال القيم التي لا يتم ضبطها أو تساوي القيمة الافتراضية عبر السلك.
على سبيل المثال ، تكون القيمة الافتراضية للرسالة undefined
. الأنواع البدائية تأخذ قيمتها الافتراضية الطبيعية ، على سبيل المثال string
هي ''
، number
0
، إلخ.
اختار ProtoBuf/يفرض هذا السلوك لأنه يتيح التوافق إلى الأمام ، حيث أن الحقول البدائية سيكون لها دائمًا قيمة ، حتى عند حذفها من قبل الوكلاء الذين عفا عليها الزمن.
هذا أمر جيد ، ولكنه يعني أيضًا أن القيم الافتراضية ولا يمكن تمييز القيم في حقول ts-proto
؛ إنها مجرد كيفية عمل Protobuf.
إذا كنت بحاجة إلى حقول بدائية حيث يمكنك اكتشاف مجموعة/إلغاء تعيين ، انظر أنواع الغلاف.
تشفير / فك شفرة
يتبع ts-proto
قواعد protobuf ، ويعيد دائمًا القيم الافتراضية لحقول unsets عند فك تشفير ، مع حذفها من الإخراج عند التسلسل بتنسيق ثنائي.
Syntax = "proto3" ؛ message foo {String Bar = 1 ؛ }
protobufbytes // افترض أن هذا كائن FOO فارغ ، في protobuf binary formatfoo.decode (protobufbytes) ؛ // => {bar: ''}
foo.encode ({bar: ""}) ؛ // => {} ، يكتب كائن FOO فارغ ، بتنسيق Protobuf الثنائي
FromJson / Tojson
ستؤدي قراءة JSON أيضًا إلى تهيئة القيم الافتراضية. نظرًا لأن المرسلين قد يحذفون الحقول غير المستقرة ، أو تعيينها على القيمة الافتراضية ، استخدم fromJSON
لتطبيع الإدخال.
foo.fromjson ({}) ؛ // => {bar: ''} foo.fromjson ({bar: ""}) ؛ // => {bar: ''} foo.fromjson ({bar: "baz"}) ؛ // => {bar: 'baz'}
عند كتابة JSON ، تقوم ts-proto
بتطبيع الرسائل عن طريق حذف الحقول غير المقيدة والحقول التي تم تعيينها على قيمها الافتراضية.
foo.tojson ({}) ؛ // => {} foo.tojson ({bar: undefined}) ؛ // => {} foo.tojson ({bar: ""}) ؛ // => {} - ملاحظة: حذف القيمة الافتراضية ، كما هو متوقع. // => {bar: 'baz'}
يأتي Protobuf مع العديد من تعريفات الرسائل المحددة مسبقًا ، والتي تسمى "أنواع معروفة". يتم تعريف تفسيرهم من خلال مواصفات protobuf ، ومن المتوقع أن تقوم المكتبات بتحويل هذه الرسائل إلى الأنواع الأصلية المقابلة باللغة المستهدفة.
يقوم ts-proto
حاليًا بتحويل هذه الرسائل تلقائيًا إلى أنواعها الأصلية المقابلة.
google.protobuf.boolvalue ⇆ boolean
google.protobuf.bytesvalue ⇆ Uint8Array
google.protobuf.doublevalue ⇆ number
google.protobuf.fieldmask ⇆ string[]
google.protobuf.floatvalue ⇆ number
google.protobuf.int32value ⇆ number
google.protobuf.int64value ⇆ number
google.protobuf.listvalue ⇆ any[]
google.protobuf.uint32value ⇆ number
google.protobuf.uint64value ⇆ number
google.protobuf.stringValue ⇆ string
google.protobuf.value ⇆ any
(أي number | string | boolean | null | array | object
)
google.protobuf.struct ⇆ { [key: string]: any }
أنواع الغلاف هي رسائل تحتوي على حقل بدائي واحد ، ويمكن استيرادها في ملفات .proto
مع import "google/protobuf/wrappers.proto"
.
نظرًا لأن هذه الرسائل ، فإن قيمتها الافتراضية undefined
، مما يتيح لك التمييز بين البدائل غير المستقرة عن قيمها الافتراضية ، عند استخدام أنواع الغلاف. ts-proto
يولد هذه الحقول على أنها <primitive> | undefined
.
على سبيل المثال:
// protobufsyntax = "proto3" ؛ استيراد "Google/protobuf/wrppers.proto" ؛ message examplemessage {Google.Protobuf.StringValue name = 1 ؛ }
// timeScriptInterface Examplemessage { الاسم: سلسلة | غير محدد ؛}
عند ترميز رسالة ، يتم تحويل القيمة البدائية مرة أخرى إلى نوع الغلاف المقابل:
examplemessage.encode ({name: "foo"}) ؛ // => {name: {value: 'foo'}} ، في الثنائي
عند استدعاء Tojson ، لا يتم تحويل القيمة ، لأن أنواع الغلاف منظمة في JSON.
examplemessage.tojson ({name: "foo"}) ؛ // => {name: 'foo'}
لغة Protobuf وأنواعها ليست كافية لتمثيل جميع قيم JSON الممكنة ، لأن JSON قد تحتوي على قيم غير معروفة مسبقًا. لهذا السبب ، يوفر Protobuf عدة أنواع إضافية لتمثيل قيم JSON التعسفية.
وتسمى هذه أنواع الهيكل ، ويمكن استيرادها في ملفات .proto
مع import "google/protobuf/struct.proto"
.
google.protobuf.value ⇆ any
هذا هو النوع الأكثر عمومية ، ويمكن أن يمثل أي قيمة JSON (أي number | string | boolean | null | array | object
).
google.protobuf.listvalue ⇆ any[]
لتمثيل مجموعة JSON
google.protobuf.struct ⇆ { [key: string]: any }
لتمثيل كائن JSON
ts-proto
يتحول تلقائيًا بين أنواع الهياكل هذه وأنواع JSON المقابلة.
مثال:
// protobufsyntax = "proto3" ؛ استيراد "google/protobuf/struct.proto" ؛ message examplemessage {google.protobuf.value hone = 1 ؛ }
// timeScriptInterface Examplemessage { أي شيء: أي | غير محدد ؛}
ترميز قيمة JSON مضمنة في رسالة ، يحولها إلى نوع بنية:
examplemessage.encode ({أي شيء: {name: "hello"}) ؛/* يخرج الهيكل التالي ، مشفر بالتنسيق الثنائي protobuf: {أي شيء: value {structValue = struct {fields = [mapentry {key = "name" ، value = value {stringValue = "Hello"}]}}}}}*/exampplemessage.encode ({أي شيء: true}) ؛/* يخرج الهيكل التالي المشفر في التنسيق الثنائي protobuf: {أي شيء: value {boolvalue = true}} */
إن تمثيل google.protobuf.Timestamp
قابل للتكوين بواسطة علامة useDate
. يتحكم علامة useJsonTimestamp
في الدقة عند useDate
false
protobuf نوع معروف | الافتراضي/ useDate=true | useDate=false | useDate=string | useDate=string-nano |
---|---|---|---|---|
google.protobuf.Timestamp | Date | { seconds: number, nanos: number } | string | string |
عند استخدام useDate=false
و useJsonTimestamp=raw
على أنه { seconds: number, nanos: number }
، ولكن لديه دقة نانو ثانية.
عند استخدام useDate=string-nano
timestamp يتم تمثيله كسلسلة ISO مع دقة النانو ثانية 1970-01-01T14:27:59.987654321Z
ويعتمد على مكتبة المواعيد النانوية للتحويل. ستحتاج إلى تثبيته في مشروعك.
الأرقام افتراضيًا يفترض أنها number
JavaScript عادي.
هذا أمر جيد لأنواع protobuf مثل int32
و float
، ولكن لا يمكن أن تكون أنواع 64 بت مثل int64
ممثلة بنسبة 100 ٪ بنوع number
JavaScript ، لأن int64
يمكن أن يكون لها قيم أكبر/أصغر من number
.
forceLong=number
(في وقت التشغيل) لا يزال استخدام number
لحقول 64 بت ، ثم رمي خطأ إذا كانت قيمة (في وقت التشغيل) أكبر من Number.MAX_SAFE_INTEGER
.
إذا كنت تتوقع استخدام قيم 64 بت / أعلى من قيم MAX_SAFE_INTEGER
، فيمكنك استخدام خيار TS-Proto forceLong
، والذي يستخدم حزمة NPM الطويلة لدعم النطاق الكامل للقيم 64 بت.
خريطة أنواع أرقام البروتوبوف لأنواع JavaScript استنادًا إلى خيار التكوين forceLong
:
أنواع أرقام البروتوبوف | الافتراضي/ forceLong=number | forceLong=long | forceLong=string |
---|---|---|---|
مزدوج | رقم | رقم | رقم |
يطفو | رقم | رقم | رقم |
int32 | رقم | رقم | رقم |
int64 | رقم* | طويل | خيط |
uint32 | رقم | رقم | رقم |
uint64 | رقم* | غير موقعة طويلة | خيط |
Sint32 | رقم | رقم | رقم |
Sint64 | رقم* | طويل | خيط |
ثابت 32 | رقم | رقم | رقم |
ثابت 64 | رقم* | غير موقعة طويلة | خيط |
Sfixed32 | رقم | رقم | رقم |
Sfixed64 | رقم* | طويل | خيط |
حيث (*) يشير إلى أنهم قد يرمون خطأ في وقت التشغيل.
البدائية المطلوبة: استخدم AS-IS ، أي string name = 1
.
البدائية الاختيارية: استخدم أنواع الغلاف ، أي StringValue name = 1
.
الرسائل المطلوبة: غير متوفرة
الرسائل الاختيارية: استخدم AS-IS ، أي SubMessage message = 1
.