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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@contentful-tools/cli

v0.7.3

Published

A CLI for generating type declarations based on Contentful content types.

Downloads

7

Readme

Contentful Tools CLI

Version License Dependencies Dev Dependencies Dependabot Status oclif

npm install -D @contentful-tools/cli

Read this first: Contentful Store (npm)

This generator CLI pulls a content space definition from Contentful and creates an interface for each content type, using its field validations to create the appropriate TypeScript type. Generated fields are marked optional or required according to the content type definition. The following field types give the corresponding TypeScript types:

  • Boolean ⟹ boolean
  • Date ⟹ string (ISO8601)
  • Integer ⟹ number
  • Number ⟹ number
  • Text (long string) ⟹ string
  • Symbol (short string) ⟹ string
  • Symbol enum (fixed value or values) ⟹ references a generated enum ExampleEnum
  • Symbol enum array ⟹ ExampleEnum[]

The following mappings reference types from @contentful-tools/store, allowing them to be updated with improved definitions, without regeneration:

  • Location ⟹ Location, defined as { lon: number; lat: number }
  • Object ⟹ JSON, defined as { [key: string]: any } | any[]
  • Rich text ⟹ RichText, defined as any

Reference-type fields can be followed to the linked entry or asset — the store lazily evaluates the links using getters, so circular references are no problem.

Entries are flattened for ease-of-use (especially within a GraphQL API) with top-level __typename and __id properties. __id is the Contentful ‘sys’ ID; __typename uses the provided values from the generator config (see below), or otherwise just the API name for the content type (if no mapping is provided).

Example generated interface:

export interface Post extends Entry {
    __typename: 'Post';
    __id: string;
    title: string;
    content: string;
    author: Author;
}

Store class

The generator creates a class with typed methods to get your assets and entries from the store. It must be instantiated with an instance of ContentfulStore, before using any of its methods.

export class ContentStore {
    private readonly store: Store;

    constructor(contentfulStore: Store) {
        this.store = contentfulStore;
    }

    getAsset(__id: string, locale: Locale): Asset | null {
        return this.store.getAsset(__id, locale);
    }

    getAssets(locale: Locale): Asset[] {
        return this.store.getAssets(locale);
    }

    // ...
}

The base locale for your content space, and any additional locales, should be provided in the generator config. Separating the base and extra locales is what allows type-safe access to a field marked as required, without having to make a null check — on the basis that an entry cannot be published if it is missing a value for your space’s default locale.

Note, you should also make sure to call await store.sync() before attempting to use any of the getters (typically before your server starts accepting requests), otherwise you will get no content on first use.

function getPostAuthorAvatar(postId: string): Content.Asset | null {
    const post = contentStore.getPost('123');
    return post ? post.author.avatar : null;
}

Config

Example contentful.json config file (a different name can be specified via the CLI):

{
    // (default = false)
    // Whether to remove everything in the output directory before generation;
    // use at your own risk!
    "clean": true,
    
    // (default = false)
    // If true, the sync command performs an initial sync for this job via the Contentful delivery client, and writes
    // the result to disk as JSON.
    "sync": true,

    // (required)
    // Where to put the generated TypeScript files;
    // created for you using the equivalent of mkdir -p
    "outDir": "./store",
    
    // (required)
    // Contentful space ID.
    "space": "a1b2c3d4",
    
    // (required)
    // Specify at least a base locale; extra may be an empty array.
    "locales": {
        "base": "en",
        "extra": ["de"]
    },
    
    // (optional)
    // If specified, all types will be grouped together in a single namespace file with the given name.
    "namespace": "Content",
    
    // (required)
    // Name of the generated class containing methods to get content entries & assets.
    "storeClass": "ContentStore",

    // (default = false)
    // Whether the locale parameter to the generated methods is optional.
    "localeOptional": true,
    
    // (optional)
    // Array of field IDs, for which getter methods are generated.
    // For example, given ["id"] and a content type "BlogPost", the method "getBlogPostById" is generated.
    "fieldGetters": [
        "id"
    ],
    
    // (optional)
    // Uses the specified field in default getter methods, instead of "__id"
    "idField": "id",

    // (optional)
    // Only generates types and methods for the content types listed in the "contentTypeNameMap". Also generates a
    // whitelist to pass to the ContentfulStore constructor. It is your responsibility to ensure all necessary linked
    // content types are included in your whitelist.
    "whitelist": true,

    // (optional)
    // Mapping from your content type IDs to desired interface names; the generated ContentTypeId
    // enum uses the actual IDs as its string values. If omitted, interfaces will be generated with
    // your content type IDs capitalized (e.g. blogPost ⟹ BlogPost).
    "contentTypeNameMap": {
        "blogPost": "Post",
        // ...
    },
    
    // (optional)
    // Generates a convenient getter method for content types that only have one entry.
    "singletons": [
        "Config"
    ],
    
    // (optional)
    // Useful to override the very generic JSON type for object fields. Path is relative to the generated output;
    // type should be the name of an exported interface or type alias.
    "typeOverrides": {
        "Post": {
            "extra": {
                "path": "./overrides/Post",
                "type": "PostExtra"
            }
        }
    }
}

Prettier

The generator uses the TypeScript compiler API and Prettier internally. If you have a config somewhere that Prettier can find, the generator will use it to format the resulting code.

CLI usage

Generates a type-safe Contentful content delivery client.

USAGE
  $ contentful-generate

OPTIONS
  -c, --config=config            [default: contentful.json] Path to JSON configuration file
  -e, --environment=environment  [default: master] Contentful environment name
  -h, --help                     show CLI help
  -s, --space=space              Contentful space ID
  -t, --token=token              Contentful management API access token
  -v, --version                  show CLI version

DESCRIPTION
  Requires a management API access token, space ID, and environment name. These
  may be specified with the following environment variables:

       CONTENTFUL_MANAGEMENT_ACCESS_TOKEN
       CONTENTFUL_SPACE_ID
       CONTENTFUL_ENVIRONMENT

  These may also be sourced from a .env file, located in the working directory.

Possible improvements

  • Add tests!
  • Produce a useful error message if you try to use the getters without first setting up the store properly
  • Fetch locales, instead of requiring them in the config
  • Document the config with a JSON schema and upload to JSON Schema Store