DocsAdvanced specs

Advanced specs

As we already mentioned in the push-to-autocomplete-action docs, Fig supports two different kinds of specs, normal specs and diff-versioned specs

Normal specs

Normal specs are one TypeScript file, named as the CLI tool, where the default export is the completion spec object itself. They support importing and exporting both functions and constants and they have all JS features that can be polyfilled for browsers so they are great for fast prototyping and easy spec autogeneration using integrations.

Nevertheless, they are not really good when we have tools that change often or that have multiple major versions in use (like Yarn) and that's why we introduced diff-versioned specs.

Diff-versioned specs

A diff-versioned spec is a folder, instead of a single file, which contains:

  • some x.y.z.ts version files
  • a index.ts file containing an exported function to detect which version of the CLI is installed locally and an exported variable mapping the version files to CLI versions
  • other .ts files manually added related to the spec (e.g. a generators.ts containing the shared generators that stayed the same between multiple majors)

The fig spec is an example of a diff-versioned spec.

Let's dive deeper into how version and index files are composed:

  • index.ts contains:
    • an exported getVersionCommand function which MUST return a string with the semantic version of the CLI (e.g. 1.4.1 and not v1.4.1)
    • an exported variable containing the name of the version files without extension
  • x.y.z.ts version files contain:
    • a default export containing the base spec
    • an exported variable named versions. It is a JS object that has versions as keys and diffs as values.

But what is a diff? Diffs are like normal specs but only contain properties changed between the previous version and the current one. For properties that get removed from one version to another (e.g. an option removed between two versions we add the remove: true to the diff).

How to create a new diff-versioned spec

npx @withfig/autocomplete-tools@latest version init-spec <spec_name> [--cwd <directory_path>]
  • <spec_name> is a required string argument declaring which will be the name of the created spec

  • --cwd <directory_path> is an optional flags that allows to create the diff-versioned spec root folder in a different directory from the current one

Example

To create a diff-versioned spec named "fig" in the autocomplete repo under ~/Documents/autocomplete/src we have to run this command:

npx @withfig/autocomplete-tools@latest version init-spec fig --cwd ~/Documents/autocomplete/src

How to convert a normal spec to a diff-versioned one

NOTE: This section is an extract of the following paragraph reworded to be more understandable

npx @withfig/autocomplete-tools@latest version add-diff <diff_versioned_spec_name> <normal_spec_file_path> <diff_version> [--new-path <directory_path> --use-minor-base]
  • <diff_versioned_spec_name> is a required string argument declaring which will be the name of the converted diff-versioned spec

  • <normal_spec_file_path> is a required argument containing the relative or absolute path to the normal spec to convert

  • <diff_version> is a required argument containing the version of the converted spec

  • --new-path <directory_path> is an optional flag that allows to create the diff-versioned spec in a folder different from the current one

  • --use-minor-base will create a new version file for each new minor version of the tool (this is useful for tools that use the minor to release breaking changes)

IMPORTANT: do not forget to add the function to detect which version of the CLI is installed

Example

To convert fig.ts at version 1.4.1 to a diff-versioned spec we have to run the following in ~/Documents/autocomplete/src:

npx @withfig/autocomplete-tools@latest version add-diff fig path/to/fig.ts 1.4.1

Add a diff to an existing diff-versioned spec

This is basically the same procedure as converting a normal spec to a diff-versioned one, except we introduce a new concept: diffing.

How it works? (this part is quite technical)

  1. We resolve the diff_versioned_spec_name relative to the current directory or to the directory specified in the --cwd option
    • If the previous step did not found a diff-versioned spec we create a new one either in the current working directory or in the directory specified with --new-path
    • If the previous step found a diff-versioned spec and --new-path was specified we copy the found spec to the new path
  2. We resolve the relative or absolute normal_spec_file_path relative to the current directory (the --cwd option won't have effect here!)
  3. We use some magic to get diffs between the existing diff-versioned spec and the normal spec
  4. We add the diffs to the diff-versioned spec resolved in steps 1 and 2
npx @withfig/autocomplete-tools@latest version add-diff <diff_versioned_spec_name> <normal_spec_file_path> <diff_version> [--new-path <directory_path> --cwd <directory_path> --use-minor-base]
  • <diff_versioned_spec_name> is a required string argument declaring which is the name of the existing diff-versioned spec to use as the base for diffing

  • <normal_spec_file_path> is a required argument containing the relative or absolute path to the normal spec to use as the source of changes

  • <diff_version> is a required argument containing the version of the spec contained at normal_spec_file_path

  • --new-path <directory_path> is an optional flag that allows to output the updated diff-versioned spec in a folder different from the current one

  • --cwd <directory_path> is an optional flags that allows to select the directory in which to search for the existing diff-versioned spec to use as base

  • --use-minor-base will create a new version file for each new minor version of the tool (this is useful for tools that use the minor to release breaking changes)

NOTE: in its simplest configuration this command needs to be run in the parent directory of the diff-versioned spec e.g. if the diff versioned spec is "src/fig/" you need to run it from "src"

Example

To add a new version of fig at version 1.4.0 to a diff-versioned spec we have to run the following in ~/Documents/autocomplete/src:

npx @withfig/autocomplete-tools@latest version add-diff fig path/to/fig.ts 1.4.0

Note that the command is the same used to convert a normal spec to a diff-versioned one!

Limitations of the tool handling diff-versioned specs

  • It is difficult to maintain generators so generally after adding a diff or converting a normal spec some hand work needs to be done (however this is generally pretty fast)
  • Once a file version is created at a specific minor, manual edits are required to add a new minor lower than the base one. For example if we created a new diff for 2.0.0.ts at version 2.3.0, then adding 2.1.0 must be done manually