npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

datex2-ts

v1.0.0

Published

Dev-friendly TypeScript data model for DATEX II v3 (JSON encoding): generated types, discriminated-union friendly model, immutable editing helpers and metadata-driven validation.

Readme

datex2-ts

Thư viện data model TypeScript cho DATEX II v3 (bản mã hoá JSON), viết theo hướng dễ dùng cho dev.

DATEX II là chuẩn châu Âu để trao đổi thông tin giao thông. Bản mã hoá JSON của nó bám sát mô hình UML nên rất chính xác — nhưng viết tay thì cực khổ: hậu tố kỹ thuật G (idG, versionG), enum bị bọc thành { "value": "real" }, và các substitution group luôn lồng sâu thêm một cấp ({ "sitAccident": { … } }).

datex2-ts cung cấp hai cách nhìn cho cùng một model, chuyển đổi qua lại không mất dữ liệu:

| | wire (datex2-ts/wire) | friendly (datex2-ts/friendly) | | --- | --- | --- | | định danh | idG, versionG | id, version | | enum | { value: 'real' } | 'real' | | substitution group | { sitAccident: { … } } | { _type: 'Accident', … } | | dùng khi | đọc/ghi JSON DATEX II | viết code ứng dụng |

Toàn bộ types, enums và metadata runtime đều được sinh tự động từ bộ JSON Schema DATEX II v3.7 chính thức nằm trong schemas/: 19 namespace, 1608 định nghĩa. Không có dependency runtime nào.

Cài đặt

npm install datex2-ts

Bắt đầu nhanh

Viết một situation publication ở dạng friendly, có type-check và gợi ý đầy đủ:

import { create, encodeStrict, serialize } from 'datex2-ts';

const publication = create('PayloadPublicationG', {
  modelBaseVersion: '3',
  version: '3.7',
  _type: 'SituationPublication',
  lang: 'vi',
  publicationTime: new Date().toISOString(),
  publicationCreator: { country: 'vn', nationalIdentifier: 'HCMC' },
  situation: [
    {
      id: '12345',
      headerInformation: { informationStatus: 'real' },
      situationRecord: [
        {
          _type: 'Accident',
          id: '2322',
          version: '1',
          situationRecordCreationTime: '2026-08-20T14:32:00+07:00',
          situationRecordVersionTime: '2026-08-20T14:32:00+07:00',
          probabilityOfOccurrence: 'certain',
          accidentType: ['multipleVehicleAccident'],
          severity: 'high',
          validity: {
            validityStatus: 'active',
            validityTimeSpecification: { overallStartTime: '2026-08-20T14:32:00+07:00' },
          },
          locationReference: {
            _type: 'PointLocation',
            pointByCoordinates: {
              pointCoordinates: { latitude: 10.7769, longitude: 106.7009 },
            },
          },
        },
      ],
    },
  ],
});

// -> JSON DATEX II, ném lỗi nếu không hợp lệ theo model
const wire = encodeStrict('PayloadPublicationG', publication);

// -> document hoàn chỉnh, đã bọc trong envelope `payload`
const json = serialize(publication, 'PayloadPublicationG', { space: 2, validate: true });

PayloadPublicationG là substitution group của mọi publication trong DATEX II, nên cùng một lời gọi đó dựng được ParkingTablePublication, EnergyInfrastructureStatusPublication, VmsPublication… — chỉ cần đổi _type.

Đọc ngược lại:

import { collect, encode, parse } from 'datex2-ts';

const { type, value } = parse(json); // tự nhận diện envelope
value.situation?.[0]?.situationRecord[0]; // -> { _type: 'Accident', id: '2322', … }

// tìm mọi instance của một type ở bất kỳ đâu trong document (dạng wire)
const accidents = collect(encode(type, value), type, 'Accident');

Model dạng friendly

Enum là string thuần

import { AccidentTypeEnum, decode, encode } from 'datex2-ts';

encode('InformationStatusEnumG', 'real');            // { value: 'real' }
decode('InformationStatusEnumG', { value: 'real' }); // 'real'

AccidentTypeEnum.collision; // 'collision' — const object để dùng lúc runtime

DATEX II cho phép profile mở rộng enum. Trường hợp đó vẫn round-trip được, tên kỹ thuật được dọn sạch:

encode('EmissionClassificationEuroEnumG', { value: 'extendedG', extendedValue: 'euro6d' });
// { value: 'extendedG', extendedValueG: 'euro6d' }

Substitution group là discriminated union

import type { SituationRecordG } from 'datex2-ts/friendly';

function moTa(record: SituationRecordG): string {
  switch (record._type) {
    case 'Accident':
      return `${record.accidentType.join(', ')} lúc ${record.situationRecordCreationTime}`;
    case 'ConstructionWorks':
      return `công trường, ${record.validity.validityStatus}`;
    default:
      return record._type;
  }
}

Hỏi model xem một group nhận những thành viên nào:

import { membersOf } from 'datex2-ts';
membersOf('LocationReferenceG');
// ['LocationGroupByList', 'LocationGroupByReference', 'ItineraryByIndexedLocations',
//  'ItineraryByReference', 'LinearLocation', 'SingleRoadLinearLocation',
//  'PointLocation', 'PointLocationForParking', 'LocationByReference', 'AreaLocation']

Input dễ tính

Ngoài dạng friendly, encode() / toWire() còn chấp nhận:

  • tên thuộc tính dạng wire (idG lẫn id), tiện khi dữ liệu đang chuyển đổi dở;
  • một giá trị đơn ở chỗ model cần mảng — sẽ tự bọc thành mảng;
  • object Date ở chỗ cần chuỗi date-time;
  • các thuộc tính model không khai báo: được giữ nguyên để dữ liệu profile / extension không bị mất khi round-trip (truyền { strict: true } nếu muốn bỏ).

Sửa các trường dữ liệu

edit() — an toàn kiểu, bất biến

import { edit } from 'datex2-ts';

const next = edit(publication, (draft) => {
  const record = draft.situation![0]!.situationRecord[0]!;
  if (record._type === 'Accident') {
    record.accidentType = ['multipleVehicleAccident'];
    record.totalNumberOfVehiclesInvolved = 3;
  }
});
// `publication` không bị thay đổi

Path — khi cần truy cập động

Path phân tách bằng dấu chấm, đọc/ghi sâu mà không cần chuỗi ?.. Ghi luôn tạo bản sao mới và tự tạo các cấp cha còn thiếu:

import { getIn, pushIn, select, setIn, updateIn, deleteIn } from 'datex2-ts';

const at = 'situation.0.situationRecord.0';

getIn(publication, `${at}.id`);                                // '2322'
setIn(publication, `${at}.version`, '2');                      // bản sao mới
updateIn(publication, `${at}.version`, (v) => String(+v! + 1));
pushIn(publication, `${at}.accidentType`, 'secondaryAccident');
deleteIn(publication, `${at}.collisionType`);

setIn({}, 'situation.0.situationRecord.0.id', '7');
// { situation: [{ situationRecord: [{ id: '7' }] }] }

select(publication, 'situation.*.situationRecord.*._type'); // ['Accident']

Ngoài ra còn có hasIn, clone, freezeprune (bỏ undefined, null và các container rỗng trước khi serialize).

Kiểm tra hợp lệ

Việc kiểm tra dùng chính metadata đã sinh, nên không cần thư viện JSON Schema nào lúc runtime, và báo lỗi theo đúng ngôn ngữ của model.

import { assertValid, check, isValid, validate } from 'datex2-ts';

validate(wire, 'PayloadPublicationG');    // Issue[] trên dạng wire
check('PayloadPublicationG', friendly);   // Issue[] trên dạng friendly
isValid(wire, 'PayloadPublicationG');
assertValid(wire, 'PayloadPublicationG'); // ném ValidationError

Mỗi Issue gồm { path, code, message, type }, với các mã missingRequired, unknownProperty, wrongType, notAnArray, tooFewItems, tooManyItems, notInEnum, emptyChoice, ambiguousChoice, outOfRange, tooLong, patternMismatch, unknownType.

Nếu muốn dùng validator JSON Schema, schema gốc cũng được đóng gói kèm:

import common from 'datex2-ts/schemas/datex2-v3.7/DATEXII_3_Common.json' with { type: 'json' };

Document và envelope

import { detectRoot, parse, rootTypes, serialize, toDocument } from 'datex2-ts';

rootTypes;                       // { payload: 'PayloadPublicationG' }
detectRoot(doc);                 // { root, type, value } hoặc undefined
parse(jsonOrObject);             // tự nhận diện envelope
parse(fragment, 'Accident');     // chỉ định type cho fragment không có envelope
toDocument(value, type);         // giá trị wire đã bọc envelope
serialize(value, type, { space: 2, validate: true });

Soi model lúc runtime

import { defs, getDef, namespaces, typeNames, typeNamesIn } from 'datex2-ts';

typeNames().length;        // toàn bộ type đã sinh
typeNamesIn('Situation');  // các type thuộc một namespace DATEX II
getDef('Accident');        // { ns, name, kind, props, open, … }

walk(value, type, visitor) duyệt document dạng wire theo chỉ dẫn của model; collect / collectWithPaths được xây trên đó.

Model DATEX II nào đang được đóng gói

Model đi kèm được sinh từ gói model DATEX II phiên bản 3.7 chính thức (https://docs.datex2.eu/downloads/modelv37/): 19 namespace, 1608 định nghĩa, bao gồm Situation, Parking, EnergyInfrastructure, AfirEnergyInfrastructure, Facilities, AfirFacilities, RoadTrafficData, Vms, TrafficRegulation, TrafficManagementPlan, ControlledZone, FaultAndStatus, ReroutingManagementEnhanced, LocationReferencing, UrbanExtensions và các namespace Common.

Các namespace Exchange / CIS của DATEX II (MessageContainer, ExchangeInformation) được publish ở một gói tải riêng, không nằm trong gói model — nên bản này phủ phần payload publication chứ chưa phủ message envelope.

Generator không bị khoá vào bộ schema đó. Trỏ nó sang gói Exchange, sang một phiên bản model cũ hơn, hay sang profile riêng của bạn, mọi thứ sẽ đi theo:

node scripts/generate.mjs schemas/my-profile
npm run typecheck && npm test

Nó hiểu cả hai dialect mà tooling DATEX II sinh ra: draft-04 dùng definitions và draft 2020-12 dùng $defs. Xem thêm schemas/README.md.

Phạm vi

  • Hỗ trợ bản mã hoá JSON của DATEX II v3. XML/XSD nằm ngoài phạm vi.
  • Việc kiểm tra bám theo những gì JSON Schema DATEX II diễn đạt được (cấu trúc, trường bắt buộc, enum, khoảng giá trị, độ dài, pattern, số phần tử). Các quy tắc chỉ mô tả bằng lời trong tiêu chuẩn thì không kiểm tra được.
  • Chỉ import type (datex2-ts/friendly, datex2-ts/wire) thì không tốn gì lúc runtime. Import phần runtime sẽ kéo theo metadata của cả 1608 định nghĩa — khoảng 1 MB chưa minify, bundler sẽ nén lại, và điều này chủ yếu đáng quan tâm khi chạy trên trình duyệt.

Phát triển

npm install
npm run generate    # sinh lại src/generated/ từ schemas/
npm run typecheck
npm test
npm run build
npm run commit      # prompt của commitizen - commit theo Conventional Commits

src/generated/ được commit, và CI sẽ fail nếu nó lệch so với schema. Commit message được kiểm bằng commitlint, nên hãy dùng npm run commit (hoặc tự viết đúng dạng type(scope): subject).

Phát hành

Việc phát hành đi qua staged publishing của npm, tách phần máy làm và phần người duyệt.

Lần publish đầu tiên của một tên package mới. Cả staged publishing lẫn trusted publishing đều không tạo được package chưa tồn tại trên registry — cả hai đều cần bản ghi package có sẵn. Nên bản đầu tiên phải publish thủ công, đúng một lần:

npm login          # tài khoản sở hữu tên package
npm publish        # sẽ hỏi 2FA

Từ bản thứ hai trở đi:

  1. Bump version (npm version <patch|minor|major>) rồi push.

  2. Chạy workflow Publish — qua GitHub Release, hoặc ở Actions -> Publish -> Run workflow. Nó build, kiểm tra, rồi chạy npm stage publish --provenance — bước này không cần 2FA.

  3. Duyệt bản đã stage — đây mới là chỗ cần proof-of-presence:

    npm stage list datex2-ts     # lấy stage id
    npm stage view <stage-id>    # xem thứ sắp lên registry
    npm stage approve <stage-id> # hỏi 2FA rồi publish

    hoặc duyệt trên npmjs.com. npm stage reject <stage-id> để huỷ.

Workflow còn nhận mode: publish để publish thẳng, bỏ qua staging. Đường này cần trusted publishing (cấu hình ở trang settings của package sau lần publish đầu, khi đó không cần token nữa) hoặc một token được phép bypass 2FA — lưu ý npm đang siết loại token này.

Staged publishing cần npm >= 11.15.0 và Node >= 22.14.0, nên workflow cài npm mới trước khi chạy.

Giấy phép

MIT