العمل مع YAML في TypeScript: تحليل، توليد، والتحقق من صحة البيانات
\n\nYAML (YAML Ain't Markup Language) — أحد أشهر تنسيقات تسلسل البيانات، المستخدمة بنشاط في ملفات التكوين، DevOps (Docker، Kubernetes، Ansible)، وخطوط أنابيب CI/CD. في نظام TypeScript البيئي، تُستخدم مكتبة js-yaml للعمل مع YAML، والتي توفر دعمًا كاملاً لمواصفات YAML 1.2، بما في ذلك الهياكل المعقدة والعلامات وأنواع البيانات المخصصة.
التثبيت والإعداد
\n\nللبدء، قم بتثبيت المكتبة وأنواعها عبر npm:
\n\nnpm install js-yaml\nnpm install --save-dev @types/js-yaml\n\nبعد التثبيت، يمكنك استيراد المكتبة إلى مشروع TypeScript الخاص بك:
\n\nimport * as yaml from 'js-yaml';\nimport * as fs from 'fs';\n\nتحليل YAML في TypeScript
\n\nالوظيفة الرئيسية لقراءة YAML هي yaml.load()، والتي تحول سلسلة YAML إلى كائن JavaScript/TypeScript. لنلق نظرة على مثال مع ملف تكوين:
// config.yaml\n// server:\n// port: 3000\n// host: "localhost"\n// database:\n// url: "mongodb://localhost:27017/mydb"\n// poolSize: 10\n// features:\n// - logging\n// - authentication\n\ninterface Config {\n server: {\n port: number;\n host: string;\n };\n database: {\n url: string;\n poolSize: number;\n };\n features: string[];\n}\n\nconst yamlContent = fs.readFileSync('config.yaml', 'utf8');\nconst config = yaml.load(yamlContent) as Config;\n\nconsole.log(config.server.port); // 3000\nconsole.log(config.features); // ['logging', 'authentication']\n\nللتحليل الآمن (بدون تنفيذ كود)، استخدم yaml.load() — فهو أكثر أمانًا من yaml.eval()، الذي قد ينفذ كود JavaScript عشوائي.
توليد YAML من كائنات TypeScript
\n\nالعملية العكسية — تحويل كائن TypeScript إلى سلسلة YAML — تتم بواسطة الدالة yaml.dump(). هذا مفيد لإنشاء ملفات التكوين بشكل ديناميكي:
interface DeploymentConfig {\n apiVersion: string;\n kind: string;\n metadata: { name: string; labels?: Record<string, string> };\n spec: { replicas: number; selector: Record<string, string> };\n}\n\nconst deployment: DeploymentConfig = {\n apiVersion: 'apps/v1',\n kind: 'Deployment',\n metadata: {\n name: 'my-app',\n labels: { app: 'my-app', tier: 'backend' }\n },\n spec: {\n replicas: 3,\n selector: { matchLabels: { app: 'my-app' } }\n }\n};\n\nconst yamlString = yaml.dump(deployment, {\n indent: 2,\n lineWidth: 120,\n noRefs: true,\n sortKeys: true\n});\n\nconsole.log(yamlString);\n// apiVersion: apps/v1\n// kind: Deployment\n// metadata:\n// labels:\n// app: my-app\n// tier: backend\n// name: my-app\n// spec:\n// replicas: 3\n// selector:\n// matchLabels:\n// app: my-app\n\nالعمل مع الأنواع المخصصة
\n\nتدعم مكتبة js-yaml المخططات وأنواع البيانات المخصصة. هذا مفيد بشكل خاص عند العمل مع التواريخ، التعبيرات العادية، أو الكائنات الخاصة:
import * as yaml from 'js-yaml';\n\n// إنشاء نوع مخصص للتواريخ\nconst DateType = new yaml.Type('!date', {\n kind: 'scalar',\n resolve: (data: string) => !isNaN(Date.parse(data)),\n construct: (data: string) => new Date(data),\n instanceOf: Date,\n represent: (date: Date) => date.toISOString()\n});\n\n// إنشاء مخطط يدعم الأنواع القياسية والمخصصة\nconst schema = yaml.DEFAULT_SCHEMA.extend([DateType]);\n\nconst yamlWithDates = `\nevent: !date 2024-12-25T10:00:00Z\ntitle: "ندوة عيد الميلاد"\n`;\n\nconst parsed = yaml.load(yamlWithDates, { schema });\nconsole.log(parsed.event instanceof Date); // true\nconsole.log(parsed.event.toLocaleDateString('ar-SA')); // 25/12/2024\n\n