mapstronaut

A full-featured JavaScript object mapper

Mapstronaut Banner

Mapstronaut is a lightweight and flexible JavaScript/TypeScript library for transforming objects. It simplifies complex object manipulation by defining mapping rules, letting you focus on the data, not the boilerplate code.

npm version MIT License Tests 302/302 Coverage 99%

Why Mapstronaut?

  • Declarative Approach: Define your mapping structure as an array of rules. It's easy to read, understand, and maintain.
  • Advanced Data Selection: Uses JSONPath to precisely select source properties, even from complex nested objects and arrays. Uses dot-prop to select target properties.
  • Automapping: Can automatically map properties with matching names and types, saving you from defining obvious mappings.
  • High-Performance Async: Supports parallel asynchronous mapping, offering a significant performance boost for I/O-heavy transformations.

Developer's note: I used Typescript for a long time before having to switch to Java a few years ago. I love using the popular object mapper Mapstruct and was inspired by it for Mapstronaut.

Installation

npm i mapstronaut

Usage

All examples will use the following space mission data:

const spaceMissionData = {
  mission: {
    id: "artemis-3",
    name: "Artemis III",
    status: "planned",
    launch: {
      date: "2027-07-15T14:30:00Z",
      site: "Kennedy Space Center",
    },
  },
  crew: [
    { id: "cmdr-001", name: "Sarah Chen", role: "commander", experience: 2840 },
    {
      id: "plt-002",
      name: "Marcus Rodriguez",
      role: "pilot",
      experience: 1650,
    },
  ],
  spacecraft: {
    name: "Orion",
    modules: ["crew", "service"],
    fuel: { type: "liquid", amount: 95.5 },
  },
};

Basic Mapping

const structure = [
  ["mission.name", "missionTitle"],
  ["mission.launch.date", "scheduledDate"],
  ["crew[0].name", "commander"],
  ["spacecraft.fuel.amount", "spacecraft.fuelLevel"],
];

const mapper = new Mapper(structure);
const result = mapper.map(spaceMissionData);

// Result:
// {
//   missionTitle: "Artemis III",
//   scheduledDate: "2027-07-15T14:30:00Z",
//   commander: "Sarah Chen"
//   spacecraft: {
//     fuelLevel: 95.5
//   }
// }

Transforming and Filtering

Apply transformations and conditional logic during mapping:

const structure = [
  {
    source: "mission.launch.date",
    target: "launchYear",
    transform: (date) => new Date(date).getFullYear(),
  },
  {
    source: "crew",
    target: "activeCrew",
    filter: (crew, source) => source.mission.status === "in-progress",
  },
  {
    source: "spacecraft.fuel.amount",
    target: "fuelStatus",
    transform: (amount) => (amount > 90 ? "ready" : "needs-refuel"),
  },
];

const mapper = new Mapper(structure);
const result = mapper.map(spaceMissionData);

// Result:
// {
//   launchYear: 2027,
//   fuelStatus: "ready"
// }
// // activeCrew is filtered out

Asynchronous Mapping

// Simulate external API calls
const fetchWeatherData = (site) =>
  new Promise((resolve) =>
    setTimeout(() => resolve({ temp: 22, conditions: "clear" }), 100),
  );

const fetchCrewCertification = (crewId) =>
  new Promise((resolve) =>
    setTimeout(() => resolve({ certified: true, expires: "2027-01-01" }), 150),
  );

const structure = [
  ["mission.name", "title"],
  {
    source: "mission.launch.site",
    target: "weather",
    transform: async (site) => await fetchWeatherData(site),
  },
  {
    source: "crew[0].id",
    target: "commanderStatus",
    transform: async (id) => await fetchCrewCertification(id),
  },
];

const mapper = new AsyncMapper(structure, { parallelRun: true });
const result = await mapper.map(spaceMissionData);

// Result:
// {
//   title: "Artemis III",
//   weather: { temp: 22, conditions: 'clear' },
//   commanderStatus: { certified: true, expires: '2027-01-01' }
// }

Documentation

What's New in Version 2.0.0?

  • Using dot-prop for better target properties selection
  • Improved automapping with deep merging of object and arrays
  • Added maximum number of parallel jobs option in async mapping
  • Improved and tested documentation to help you get the most out of the library

Contributions

Contributions are welcome! If you have a feature request, bug report, or want to improve the code, please feel free to open an issue or submit a pull request.

Licence

This project is licensed under the MIT License.

Built by Jonathan Prevost.