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

soia-cc-gen

v1.1.15

Published

[![npm](https://img.shields.io/npm/v/soia-cc-gen)](https://www.npmjs.com/package/soia-cc-gen) [![build](https://github.com/gepheum/soia-cc-gen/workflows/Build/badge.svg)](https://github.com/gepheum/soia-cc-gen/actions)

Downloads

52

Readme

npm build

Soia's C++ Code Generator

Official plugin for generating C++ code from .soia files.

Targets C++17 and higher.

Installation

From your project's root directory, run npm i --save-dev soia-cc-gen.

In your soia.yml file, add the following snippet under generators:

  - mod: soia-cc-gen
    config:
      writeGoogleTestHeaders: true

The npm run soiac command will now generate C++ code within the soiagen directory.

For more information, see this C++ project example.

C++ generated code guide

The examples below are for the code generated from this .soia file.

Referring to generated symbols

Every generated symbol lives in a namespace called soiagen_${path}, where ${path} is the path to the .soia file relative from the root of the soia source directory, with the ".soia" extension removed, and slashes replaced with underscores.

#include "soiagen/user.h"

using ::soiagen_user::User;
using ::soiagen_user::UserRegistry;

Constructing structs

// You can construct a struct like this:
User john;
john.user_id = 42;
john.name = "John Doe";

// Or you can use the designated initialized syntax:
User jane = {
    // Keep fields in alphabetical order
    .name = "Jane Doe",
    .pets = {{
                  .name = "Fluffy",
                  .picture = "cat",
              },
              {
                  .name = "Rex",
                  .picture = "dog",
              }},
    .subscription_status = soiagen::kPremium,
    .user_id = 43,
};

// ${StructName}::whole forces you to initialize all the fields of the struct.
// You will get a compile-time error if you miss one.
User lyla = User::whole{
    .name = "Lyla Doe",
    .pets =
        {
            User::Pet::whole{
                .height_in_meters = 0.05f,
                .name = "Tiny",
                .picture = "🐁",
            },
        },
    .quote = "This is Lyla's world, you just live in it",
    .subscription_status = soiagen::kFree,
    .user_id = 44,
};

Constructing enums


// Use soiagen::${kFieldName} for constant variants.
User::SubscriptionStatus john_status = soiagen::kFree;
User::SubscriptionStatus jane_status = soiagen::kPremium;

// Compilation error: MONDAY is not a field of the SubscriptionStatus enum.
// User::SubscriptionStatus sara_status = soiagen::kMonday;

// Use soiagen::wrap_${field_name} for data variants.
User::SubscriptionStatus jade_status =
    soiagen::wrap_trial_start_time(absl::FromUnixMillis(1743682787000));

// The ${kFieldName} and wrap_${field_name} symbols are also defined in the
// generated class.
User::SubscriptionStatus lara_status = User::SubscriptionStatus::kFree;

Conditions on enums

if (john_status == soiagen::kFree) {
  std::cout << "John, would you like to upgrade to premium?\n";
}

// Call is_${field_name}() to check if the enum holds a data variant.
if (jade_status.is_trial_start_time()) {
  // as_${field_name}() returns the value held by the enum
  const absl::Time trial_start_time = jade_status.as_trial_start_time();
  std::cout << "Jade's trial started on " << trial_start_time << "\n";
}

// One way to do an exhaustive switch on an enum.
switch (lara_status.kind()) {
  case User::SubscriptionStatus::kind_type::kConstUnknown:
    // UNKNOWN is the default value for an uninitialized SubscriptionStatus.
    // ...
    break;
  case User::SubscriptionStatus::kind_type::kConstFree:
    // ...
    break;
  case User::SubscriptionStatus::kind_type::kConstPremium:
    // ...
    break;
  case User::SubscriptionStatus::kind_type::kValTrialStartTime: {
    const absl::Time& trial_start_time = lara_status.as_trial_start_time();
    std::cout << "Lara's trial started on " << trial_start_time << "\n";
  }
}

// Another way to do an exhaustive switch using the visitor pattern.
struct Visitor {
  void operator()(soiagen::k_unknown) const {
    std::cout << "Lara's subscription status is UNKNOWN\n";
  }
  void operator()(soiagen::k_free) const {
    std::cout << "Lara's subscription status is FREE\n";
  }
  void operator()(soiagen::k_premium) const {
    std::cout << "Lara's subscription status is PREMIUM\n";
  }
  void operator()(
      User::SubscriptionStatus::wrap_trial_start_time_type& w) const {
    const absl::Time& trial_start_time = w.value;
    std::cout << "Lara's trial started on " << trial_start_time << "\n";
  }
};
lara_status.visit(Visitor());

Serialization

Use ToDenseJson, ToReadableJson or ToBytes to serialize a soia value.

// Serialize a soia value to JSON with ToDenseJson or ToReadableJson.
std::cout << soia::ToDenseJson(john) << "\n";
// [42,"John Doe"]

std::cout << soia::ToReadableJson(john) << "\n";
// {
//   "user_id": 42,
//   "name": "John Doe"
// }

// The dense flavor is the flavor you should pick if you intend to
// deserialize the value in the future. Soia allows fields to be renamed, and
// because fields names are not part of the dense JSON, renaming a field does
// not prevent you from deserializing the value.
// You should pick the readable flavor mostly for debugging purposes.

// The binary format is not human readable, but it is a bit more compact than
// JSON, and serialization/deserialization can be a bit faster.
// Only use it when this small performance gain is likely to matter, which
// should be rare.
std::cout << soia::ToBytes(john).as_string() << "\n";
// soia�+Jane Doe����Fluffy�cat��Rex�dog

Deserialization

Use Parse to deserialize a soia value from JSON or binary format.

absl::StatusOr<User> maybe_john = soia::Parse<User>(soia::ToDenseJson(john));
assert(maybe_john.ok() && *maybe_john == john);

Keyed arrays

A keyed_items<T, get_key> is a container that stores items of type T and allows for fast lookups by key using a hash table.

UserRegistry user_registry;
soia::keyed_items<User, soiagen::get_user_id<>>& users = user_registry.users;
users.push_back(john);
users.push_back(jane);
users.push_back(lyla);

assert(users.size() == 3);
assert(users[0] == john);

const User* maybe_jane = users.find_or_null(43);
assert(maybe_jane != nullptr && *maybe_jane == jane);

assert(users.find_or_default(44).name == "Lyla Doe");
assert(users.find_or_default(45).name == "");

Equality and hashing

Soia structs and enums are equality comparable and hashable.

absl::flat_hash_set<User> user_set;
user_set.insert(john);
user_set.insert(jane);
user_set.insert(jane);
user_set.insert(lyla);

assert(user_set.size() == 3);

Constants

const User& tarzan = soiagen_user::k_tarzan();
assert(tarzan.name == "Tarzan");

Soia services

Starting a soia service on an HTTP server

Full example here.

Sending RPCs to a soia service

Full example here.

Dynamic reflection

using ::soia::reflection::GetTypeDescriptor;
using ::soia::reflection::TypeDescriptor;

// A TypeDescriptor describes a soia type. It contains the definition of all
// the structs and enums referenced from the type.
const TypeDescriptor& user_descriptor = GetTypeDescriptor<User>();

// TypeDescriptor can be serialized/deserialized to/from JSON.

absl::StatusOr<TypeDescriptor> reserialized_type_descriptor =
    TypeDescriptor::FromJson(user_descriptor.AsJson());
assert(reserialized_type_descriptor.ok());

Static reflection

Static reflection allows you to inspect and modify values of generated soia types in a typesafe maneer.

See string_capitalizer.h.

User tarzan_copy = soiagen_user::k_tarzan();
// CapitalizeStrings recursively capitalizes all the strings found within a
// soia value.
CapitalizeStrings(tarzan_copy);

std::cout << tarzan_copy << "\n";
// {
//   .user_id: 123,
//   .name: "TARZAN",
//   .quote: "AAAAAAAAAAYAAAAAAAAAAYAAAAAAAAAA",
//   .pets: {
//     {
//       .name: "CHEETA",
//       .height_in_meters: 1.67,
//       .picture: "🐒",
//     },
//   },
//   .subscription_status: ::soiagen::wrap_trial_start_time(absl::FromUnixMillis(1743592409000 /* 2025-04-02T11:13:29+00:00 */)),
// }

// ...

Writing unit tests with GoogleTest

Full example here.

Struct matchers

const User john = {
    .name = "John Doe",
    .pets =
        {
            {.height_in_meters = 1.67, .name = "Cheeta", .picture = "🐒"},
        },
    .quote = "Life is like a box of chocolates.",
    .user_id = 42,
};

EXPECT_THAT(john, (StructIs<User>{
                      // Only the specified fields are tested
                      .pets = testing::ElementsAre(StructIs<User::Pet>{
                          .height_in_meters = testing::FloatNear(1.7, 0.1),
                      }),
                      .quote = testing::StartsWith("Life is"),
                      .user_id = 42,
                  }));

Enum matchers

User::SubscriptionStatus john_status = soiagen::kFree;

EXPECT_THAT(john_status, testing::Eq(soiagen::kFree));

User::SubscriptionStatus jade_status =
    soiagen::wrap_trial_start_time(absl::FromUnixMillis(1743682787000));

EXPECT_THAT(jade_status, IsTrialStartTime());
EXPECT_THAT(jade_status, IsTrialStartTime(testing::Gt(absl::UnixEpoch())));