đī¸ Sketch
Templating, made portable
Templating is awesome. While it is mostly used for websites, it can be a powerful tool for developers as it can allow us to automate some repetitive tasks like setting up projects which share the same basic structure.
There are very powerful templating engines, which however require a library to work with them, which makes them not exactly portable.
And there are pieces of software like ansible
, which provide better portability and great templating capabilities but still require a significant amount of setup, which makes them slightly overkill for simpler tasks like generating a few files and directories.
This is why I made sketch
.
sketch
is portable enough so that the most basic setups require zero configuration whatsoever, but can also sustain more complex setups like extensible, multi-format configuration files with overrides available via cli flags in most cases.
It makes it very easy to define a template for a file or for an entire project, and set it all up with just a single command.
And there's more: by leveraging the Tera rendering engine, you can take advantage of its built-in filters and functions which can allow you to populate your templates not only with static values but with dynamically calculated ones, such as the current time of the day, a manipulated string, an env variable, or the result of an arithmetic calculation.
Every setup that used to require several repetitive steps can now be executed in just a single command.
And speaking of commands, you can use sketch
to render the output to stdout (so that it can be piped to other commands), or even to execute it as a shell command directly, which expands its utility for even more creative and flexible use cases.
Typescript Project Generation
sketch
was initially conceived as a typescript-centric tool, because I needed a way to manage the chaotic nature of typescript projects in a structured, orderly and easily reproducible way, that would also give me enough flexibility to be able to customize how each project piece is defined and generated.
It contains special commands and tools to generate new typescript projects and packages, such as the ability to define reusable, extensible package.json
and tsconfig
presets, as well as commonly used configuration files such as those belonging to oxlint
or vitest
.
Documentation
You can find the full documentation in the dedicated website.
Command-Line Help for sketch
This document contains the help content for the sketch
command-line program.
Command Overview:
sketch
â´sketch ts
â´sketch ts monorepo
â´sketch ts package
â´sketch init
â´sketch new
â´sketch render
â´sketch render-preset
â´sketch exec
â´
sketch
đī¸ Templating made portable. A tool to generate files, project structures or shell commands via custom templates
Usage: sketch [OPTIONS] <COMMAND>
Subcommands:
ts
â Launches typescript-specific commandsinit
â Creates a new git repo with a gitignore file. Optionally, it sets up the git remote and the pre-commit confignew
â Generates a new config file with some optional initial values defined via the cli flagsrender
â Renders a single template to a file or to stdoutrender-preset
â Renders a templating preset defined in the configuration fileexec
â Renders a template and launches it as a command
Options:
-c
,--config <FILE>
â Sets a custom config file--ignore-config-file
â Ignores any config files, uses cli instructions only--shell <SHELL>
â The shell to use for commands [default:cmd.exe
on windows andsh
elsewhere]--debug
â Activates debugging mode--root-dir <DIR>
â The base path for the generated files [default: "."]--templates-dir <DIR>
â The path to the templates directory, starting from the cwd (when set via cli) or from the config file (when defined in one of them)--no-overwrite
â Does not overwrite existing files--dry-run
â Aborts before writing any content to disk-s
,--set <KEY=VALUE>
â Set a variable (as key=value) to use in templates. Overrides global and local variables
sketch ts
Launches typescript-specific commands
Usage: sketch ts [OPTIONS] <COMMAND>
Subcommands:
monorepo
â Generates a new typescript monorepopackage
â Generates a new typescript package
Options:
-
--package-manager <NAME>
â The package manager being used. [default: pnpm]Possible values:
pnpm
,npm
,deno
,bun
,yarn
-
--no-default-deps
â Does not add default dependencies to newpackage.json
files (typescript and oxlint, plus vitest if enabled) -
--version-range <KIND>
â The kind of version ranges to use for dependencies that are fetched automatically. [default: minor]Possible values:
patch
,minor
,exact
-
--catalog
â Uses the pnpm catalog for default dependencies -
--no-convert-latest
â Does not convert dependencies marked aslatest
to a version range
sketch ts monorepo
Generates a new typescript monorepo
Usage: sketch ts monorepo [OPTIONS]
Options:
-n
,--name <NAME>
â The name of the root package [default: "root"]-t
,--ts-config <output=PATH,id=ID>
â One or many tsconfig files for the root package. If unset, defaults are used-p
,--package-json <ID>
â The id of the package.json preset to use for the root package--no-oxlint
â Does not generate an oxlint config at the root-i
,--install
â Install the dependencies at the root after creation
sketch ts package
Generates a new typescript package
Usage: sketch ts package [OPTIONS] [DIR]
Arguments:
<DIR>
â The new package's directory, starting from theroot_dir
. Defaults to the name of the package
Options:
-p
,--preset <PRESET>
â The package preset to use--update-root-tsconfig
â Whether the tsconfig file at the workspace root should receive a reference to the new package--no-vitest
â Does not set up vitest for this package--oxlint
â Sets up an oxlint config file for this package-i
,--install
â Installs the dependencies with the chosen package manager--app
â Marks the package as an application (only relevant for default tsconfigs)--library
â Marks the package as a library (only relevant for default tsconfigs)-n
,--name <NAME>
â The name of the new package. Ifdir
is set, it defaults to the last segment of it-t
,--ts-config <output=PATH,id=ID>
â One or many tsconfig files for this package. If unset, defaults are used--package-json <ID>
â The id of the package.json preset to use for this package
sketch init
Creates a new git repo with a gitignore file. Optionally, it sets up the git remote and the pre-commit config
Usage: sketch init [OPTIONS]
Options:
--no-pre-commit
â Does not generate a pre-commit config--remote <REMOTE>
â The link to the git remote to use
sketch new
Generates a new config file with some optional initial values defined via the cli flags
Usage: sketch new [OUTPUT]
Arguments:
<OUTPUT>
â The output file [default: sketch.yaml]
sketch render
Renders a single template to a file or to stdout
Usage: sketch render [OPTIONS] <OUTPUT_PATH|--stdout>
Arguments:
<OUTPUT_PATH>
â The output file (relative from the cwd)
Options:
--stdout
â Output the result to stdout-f
,--file <FILE>
â The path to the template file, from the cwd-i
,--id <ID>
â The id of the template to use-c
,--content <CONTENT>
â The literal definition for the template
sketch render-preset
Renders a templating preset defined in the configuration file
Usage: sketch render-preset <ID>
Arguments:
<ID>
â The id of the preset
sketch exec
Renders a template and launches it as a command
Usage: sketch exec [OPTIONS] [CMD]
Arguments:
<CMD>
â The literal definition for the command's template
Options:
-f
,--file <FILE>
â The path to the command's template file-t
,--template <TEMPLATE>
â The id of the template to use
This document was generated automatically by
clap-markdown
.
Configuration
Sketch supports yaml
, json
and toml
formats for its configuration file.
The configuration file can be manually specified with the -c
or --config
flag. If none is provided, the cli will automatically look for a file named sketch.{yaml, json, toml}
in the cwd. If none is found, then it will look in the XDG_CONFIG_HOME
directory. If no config is found there, it will use default values.
You can also use the --ignore-config-file
flag to temporarily ignore configuration files and only use cli-set values.
Top Level Configuration
These are the defaults for the top level configuration values:
# yaml-language-server: $schema=../schemas/latest.json
# The root path for the generated files.
# All output paths will start from this directory.
root_dir: .
# Enables debugging mode
debug: false
# Extends other configuration files
extends: []
# Settings for the .gitignore file generated via the `init` command.
# This can be:
# - A list of directives (to add to the defaults)
# - A literal string (to replace defaults)
gitignore: []
# Variables for templates
vars: {}
# Do not overwrite existing files
no_overwrite: false
# The pre-commit settings, used for the .pre-commit-config file
# generated with the `init` command.
# Can be:
# - A boolean, to use defaults or disable it altogether
# - A list of repos to populate the config with
# The default setting includes just the gitleaks repo.
pre_commit: true
# The shell to use for the `exec` command. Defaults to `cmd.exe` on windows and `sh` elsewhere.
shell: null
# A map of template definitions.
templates: {}
# A map of templating presets.
templating_presets: {}
# The relative path from the config file (or from the cwd, if set via the cli flag)
# to the directory containing templates.
templates_dir: null
# The configuration for typescript-related commands.
typescript: null
Generating Config Files
You can use the sketch new
command to generate a new configuration file in the desired output file and format.
The default is sketch.yaml
, but any name is supported as long as the format is either json
, toml
or yaml
, and the configuration file is specified with the -c
or --config
flag.
If extra arguments are provided, the generated config will populated with the values of these arguments.
So if we run sketch --templates-dir "/path/to/templates"
, templates_dir
will be set to that path in the generated config.
â ī¸ Since the default
sketch.yaml
file is always automatically detected, if there is such a file in the cwd and you want to create a new config with certain values, you need to use--ignore-config-file
to ignore the config file's values.
Command:
sketch --templates-dir tests/templates --shell zsh --set hello="there" --set general="kenobi" new tests/output/generated_configs/with_extras.yaml
Output:
shell: zsh
root_dir: tests/output
templates_dir: tests/templates
no_overwrite: false
pre_commit: true
templates: {}
templating_presets: {}
vars:
hello: there
general: kenobi
Repo Setup
You can also use the init
command to create a new git repo. This command will:
- Create a new git repo in the specified
root_dir
. - If a
--remote
is provided, it will also add that remote as the origin/main for the repo. - Unless
pre-commit
is disabled, it will generate a new .pre-commit-config.yaml file in the root, with the repos specified in the config file (if there are any, otherwise it will just add the gitleaks repo). It will then runpre-commit install
to install the given hooks.
Lsp Integration
In order to ensure the best development experience, it is highly recommended to set up your IDE to load the json schema for Sketch's configuration file.
This will provide type-safety, autocompletion and additional documentation when writing config files.
Every time a new version is released, the json schema for the configuration file will be updated in the github repo. Each version will have its own distinct schema file, and the latest.json
file will track the schema for the latest version.
You can then use this schema with the yaml
, toml
or json
language servers to get autocompletion, type information and documentation for each element of the config file.
This can be done by configuring the specific LSP in your editor, or simply by using a special comment at the top of your file that links to the config's json schema.
Examples
Yaml:
# yaml-language-server: $schema=https://github.com/Rick-Phoenix/sketch/blob/main/schemas/latest.json
Json:
{
"$schema": "https://github.com/Rick-Phoenix/sketch/blob/main/schemas/latest.json"
}
Toml:
#:schema https://github.com/Rick-Phoenix/sketch/blob/main/schemas/latest.json
Extensible Configurations
Configuration files can extend one another by using the extends
field:
extends: ["other_config.yaml"]
Where the path being used can be either an absolute path or a relative path starting from the original config file.
The merging strategy works as follows:
- For conflicting values, such as opposite booleans, the previous value will be overridden.
- For non-conflicting values such as maps (for example, the global template vars map), the values will be merged.
Templating
Sketch uses the Tera templating engine to render custom templates. Every template, whether it's defined in a file, in the config file, or inlined, can take advantage of all of Tera's functionalities, like using filters, functions, defining and using macros, performing operations and importing other templates.
Special variables
Sketch provides some special variables prefixed with to get access to some commonly used information. All of the following variables are available in templates, prefixed with sketch_
(i.e. sketch_os
and so on).
cwd
tmp_dir
(obtained with env::temp_dir)home
(obtained with env::home_dir)os
(env OS)user
(env USER)hostname
(env HOSTNAME)arch
(env HOSTTYPE)xdg_config
(env XDG_CONFIG_HOME)xdg_data
(env XDG_DATA_HOME)xdg_state
(env XDG_STATE_HOME)xdg_cache
(env XDG_CACHE_HOME)
Filters and functions
All of the builtin filters and functions for Tera are available.
On top of that, Sketch adds a uuid
function that can be used to generate a v4 UUID.
Global and Local Context
Variables are evaluated based on the locality of their context. Variables set via cli with the --set
flag have the highest priority, followed by variables defined in a local context (the context
field in a template preset) and by global variables defined in the config file.
â ī¸ Variables defined with the
--set
flag must be formatted in valid json. This means that, for example, strings must be wrapped in escaped quotes.
Rendering Templates
Templates can be defined in files or directly within a command. The variables can also be defined in the config file or as part of a command.
# This will be the starting path for the templates' output paths
root_dir = "../output/custom_templates"
vars = { my_var = 15 }
# We can define templates directly in the config file
templates = { lit_template = "my_var: {{ my_var }}" }
# Or as files inside a directory
templates_dir = "../templates"
We can then render them singularly, or in groups.
âšī¸ Single templates can be rendered to stdout with the --stdout flag.
Rendering A Single Template
Using A File
If templates_dir
is set, all the files in templates_dir
can be referenced with their ID, which is the relative path to them from templates_dir
.
So if we have this directory structure in our templates_dir
:
.
âââ abc.j2
âââ subdir
âââ nested.j2
We can render the contents of nested.j2
by running
sketch render --id subdir/nested.j2 from_template_file.yaml
However, we can also render content from any file, by using the -f
flag. In this case, the relative paths will be resolved from the cwd.
Example:
sketch render -f tests/custom_templates/single_file.j2 from_single_file.yaml
From A Config Definition
Templates can be defined inside the configuration file:
templates = { lit_template = "my_var: {{ my_var }}" }
sketch render --id lit_template from_config_template.yaml
From Literal Definition
...or directly as part of the command:
sketch --set location="Isengard" render --content "they're taking the hobbits to {{ location }}!" from_literal.txt
Rendering Presets
Templates can also be defined in groups, which can be rendered all at once starting from the same root_dir
.
This is how groups are defined:
# A group of templates that will be rendered together
templating_presets.test = [
# Full path to the template file from `templates_dir`
{ template = "subdir/nested.j2", output = "new_dir/nested.yaml" },
# Only using the global variables
{ template = "lit_template", output = "with_global_var.yaml" },
# Using a local override
{ template = "lit_template", output = "with_override.yaml", context = { my_var = 20 } },
# Defining a literal template
{ template = { name = "literal_inlined", content = "my_var: {{ my_var }}" }, output = "literal_inlined.yaml" },
]
When we run the command
sketch render-preset test
These templates will be rendered together, so that the output of the specified root_dir
will look like this:
.
âââ literal_inlined.yaml
âââ new_dir
â  âââ nested.yaml
âââ with_global_var.yaml
âââ with_override.yaml
Executing Templates
With the sketch exec
command, you can render a template and then execute it as a shell command.
To do this, you can use a regular file, a template with an id (either defined in the config file or inside the templates_dir
), or even one defined within the command itself.
From Template
Let's say that we have a file named cmd_template.j2
inside our templates_dir
, and it looks like this:
echo "{{ category }} engine... {{ category }}... argh!" > output_from_templates_dir.txt
âšī¸ You do not have to use
.j2
as an extension for the template files. Any extension can be used.
We can refer to it by its id:
sketch --set category="gp2" exec -t cmd_template.j2
This will create a file containing
gp2 engine... gp2... argh!
From File
We can also use a file that is not inside templates_dir
by using the -f
flag and providing the path to said file. Relative paths will be resolved starting from the cwd.
So let's say that we have this template file:
echo "all the time you have to leave the {{ something }}!" > output_from_file.txt
We launch the command like this:
sketch --set something="space" exec -f tests/commands_tests/cmd_from_file.j2
To create a file containing:
all the time you have to leave the space!
From Literal Template
Templates can also be defined directly as part of the command.
sketch --set general="kenobi" exec 'echo "hello there!\ngeneral {{ general }}." > command_output.txt'
This creates a file containing:
hello there!
general kenobi.
Typescript Projects
Sketch can be used to quickly generate Typescript monorepos and packages, and uses modular and extensible presets to define some reusable elements that can be shared among different kinds of typical TS projects.
These are the top level configuration settings for Typescript projects, with their default values:
# yaml-language-server: $schema=../../schemas/latest.json
typescript:
# Convert `latest` to a version range for dependencies
no_convert_latest_to_range: false
# Use this kind of version range when converting from `latest`
version_range: patch
# Do not add default dependencies to new `package.json` files (typescript and oxlint, plus vitest if enabled)
no_default_deps: false
# Use the pnpm catalog for default dependencies
catalog: false
package_manager: pnpm
# Configuration for the generated pnpm-workspace.yaml file
pnpm_config:
# All dirs listed here will be created automatically
packages: ["packages/*"]
# A map containing extensible package.json presets
package_json_presets: {}
# A map containing extensible package presets
package_presets: {}
# A map containing extensible tsconfig presets
tsconfig_presets: {}
# A map of contributors and maintainers, which can be referred to
# in package.json presets with their ID
people: {}
# The configuration for the root package
# (only relevant when creating a monorepo)
root_package: null
Monorepo Generation
Once we have our settings (or not, if we want to use defaults), we can run
sketch ts monorepo
to create our new Typescript monorepo.
For example, if we use this config:
typescript:
root_package:
name: workspace
package_json:
license: Apache-2.0
devDependencies:
husky: latest
# The tsconfig files to generate at the root.
# If left empty, defaults will be used.
ts_config:
- output: tsconfig.options.json
config:
compilerOptions:
verbatimModuleSyntax: true
strict: true
- output: tsconfig.json
config:
files: []
# Literal oxlint configuration to generate at the root
# of the workspace.
# Can be set to `true` to use defaults.
oxlint: |
{
"plugins": ["unicorn", "typescript", "oxc"]
}
And the package.json file of the root package will be like this:
{
"name": "workspace",
"private": true,
"version": "0.1.0",
"type": "module",
"license": "Apache-2.0",
"packageManager": "pnpm",
"scripts": {},
"devDependencies": {
"husky": "^9.1.7",
"oxlint": "^1.16.0",
"typescript": "^5.9.2"
},
"dependencies": {}
}
You can also use the generate_templates
field to automatically generate a certain file structure when the monorepo is generated.
Let's say, for example, that every time that you create a new monorepo, you always want to create a docker
directory with a basic dev.dockerfile
inside of it, so that you can quickly create a dev environment using docker.
For the root package, you would do so like this:
generate_templates:
- output: docker/dev.dockerfile
template:
name: dev_dockerfile
content: |
FROM node:23-alpine
COPY . .
EXPOSE {{ docker_dev_port }}
CMD ["npm", "run", "dev"]
vars:
docker_dev_port: 5173
So the final tree structure of the output directory will look like this:
.
âââ .oxlintrc.json
âââ docker
â  âââ dev.dockerfile
âââ package.json
âââ packages
âââ pnpm-workspace.yaml
âââ tsconfig.json
âââ tsconfig.options.json
âšī¸ You can use the
-i
flag to install dependencies for the root package after creating the new monorepo.
Generating A Package
You can use the command sketch ts package
to generate a new Typescript package.
For setting up the root package in a monorepo, go look in the dedicated section.
This is an example of a package-related configuration:
typescript:
package_presets:
frontend:
# The name of the package. If this is unset and `dir` is set,
# it will use the last segment from it.
name: "@myproject/frontend"
# The package.json config for this package. Can be a preset id
# or a literal configuration.
package_json:
devDependencies:
tailwindcss: "^4.0.0"
# The directory for this package, starting from the `root_dir`
dir: packages/frontend
# The kind of package to generate. Only relevant if you use
# default tsconfigs.
kind: library
# Can be set to true (for a default config), a literal config
# or to false (which is the default setting) for no oxlint config.
oxlint: false
# Create a vitest setup.
# Can be set to true to use defaults (which are as below).
vitest:
# Where the config file should be generated, starting from
# the root of the package.
# It defaults to the value of `tests_dir`
out_dir: null
# The directory to use for tests
tests_dir: tests
# The directory containing the setup files for tests.
# (starting from tests_dir)
setup_dir: setup
# Can use a list of plugins which will be set up in the config file
plugins: []
After setting things up, you can run
sketch ts package --preset frontend
To generate the new package.
Template rendering
You can use the generate_templates
field to specify a list of templates that should also be generated whenever a package preset is being generated.
Let's say for example that in a type of package, you always need a schemas
directory, where you import some common schemas from a shared package and define new ones.
You can use this feature to generate a file inside src/schemas/index.ts
automatically like this:
# Inside the package preset configuration
generate_templates:
- output: src/schemas/index.ts
# This can be a template defined in the config file
# or file path inside templates_dir
template: schemas
templates:
schemas: |
import z from "zod";
import { sharedSchemas } from "{{ schemas_package }}";
vars:
schemas_package: "@myproject/schemas"
So the final tree structure of the output directory will look like this:
.
âââ .oxlintrc.json
âââ package.json
âââ src
â  âââ index.ts
â  âââ schemas
â  âââ index.ts
âââ tests
â  âââ setup
â  â  âââ tests_setup.ts
â  âââ vitest.config.ts
âââ tsconfig.dev.json
âââ tsconfig.json
âââ tsconfig.src.json
âšī¸ You can also use the
-i
flag to automatically install the dependencies with your selected package manager whenever a new package is created.
TsConfig Presets
The configuration file can contain a variety of presets that can be used for generating Tsconfig files.
These presets contain all of the fields of a normal tsconfig.json
file, with the addition of an extra field called extend-presets
, which allows you to extend a basic preset from another one.
âšī¸ You can omit the ts_config field entirely, and the defaults will be used.
Example
Let's start with some basic starting point here:
Here we define two typical tsconfig settings to use for the packages in our workspace.
The app
preset will not emit any .d.ts or .js files, whereas the library
preset, which can be used for internal packages, will have emitDeclarationOnly
set to true
.
typescript:
tsconfig_presets:
app:
compilerOptions:
noEmit: true
include:
- src
lib:
compilerOptions:
emitDeclarationOnly: true
Now let's say that we want to create another preset which starts from the app
preset but adds the tests
directory to include
:
testing:
extend_presets: ["app"]
# The two lists will be merged and deduped
include: ["tests"]
Now we will set up a package that will generate 2 tsconfig files.
- A basic tsconfig.json file, which we will define literally, and it will have just the
files
field set to an empty array. - One which will use the lib preset and extend it with an extra feature of our choice, and that will apply only to the files inside src. We will generate this in
tsconfig.src.json
. - A separate config that will take care of typechecking the files inside the
tests
directory, without emitting files. We will create this insidetsconfig.dev.json
.
package_presets:
tsconfig-example:
dir: packages/tsconfig-example
name: "@examples/tsconfig"
# Tsconfig can also be not defined at all,
# and the default presets will be used.
ts_config:
- output: tsconfig.json
# Literal definition
config:
files: []
- output: tsconfig.dev.json
# Only specifying the preset id here
config: testing
- output: tsconfig.src.json
config:
# Literal definition that extends a preset
extend_presets: ["lib"]
compilerOptions:
verbatimModuleSyntax: true
After running the command
sketch ts package --preset tsconfig-example
We get the following files:
tsconfig.json
{
"files": []
}
tsconfig.src.json
{
"compilerOptions": {
"emitDeclarationOnly": true,
"verbatimModuleSyntax": true
}
}
âī¸ Note how the two configs have been merged!
tsconfig.dev.json
{
"include": [
"src",
"tests"
],
"compilerOptions": {
"noEmit": true
}
}
Package.json Presets
You can use the config file to store some package.json
presets that you can easily reuse among different projects or packages with similar characteristics, like scripts or dependencies.
Just like tsconfigs and global configurations, package.json
presets can also extend one another.
Example
typescript:
package_json_presets:
# The base from which all the packages from a specific project will start
base:
author:
name: Bruce Wayne
email: i-may-or-may-not-be-batman@gotham.com
license: Apache-2.0
bugs:
url: joker.com
# Another preset defining some common dependencies and scripts
frontend:
extends: ["base"]
scripts:
build: vite build
dev: vite dev
devDependencies:
# By default, these will be converted into version ranges
# starting from the actual latest version for them
tailwindcss: latest
svelte: latest
vite: latest
# This will inherit the settings from `base` and `frontend`
svelte_frontend:
extends: ["frontend"]
# But it can also override values selectively
license: MIT
package_presets:
svelte_frontend:
package_json: svelte_frontend
dir: packages/svelte_frontend
After we run
sketch ts package --preset svelte_frontend
We get this output in the package.json file:
âšī¸ Typescript and Oxlint are always added by default (along with Vitest for non-root packages), unless
no_default_deps
is set totrue
.
{
"name": "svelte_frontend",
"private": true,
"version": "0.1.0",
"type": "module",
"license": "MIT",
"packageManager": "pnpm",
"scripts": {
"build": "vite build",
"dev": "vite dev"
},
"bugs": {
"url": "joker.com"
},
"author": {
"name": "Bruce Wayne",
"email": "i-may-or-may-not-be-batman@gotham.com"
},
"devDependencies": {
"oxlint": "^1.16.0",
"svelte": "^5.39.2",
"tailwindcss": "^4.1.13",
"typescript": "^5.9.2",
"vite": "^7.1.6",
"vitest": "^3.2.4"
},
"dependencies": {}
}
Handling Dependencies
Converting latest
to a range
By default, all latest
versions will be converted to a version range (which can be specified in the config) that starts from the actual latest version for that package.
This means that you can easily use your presets and ensure that they're always going to be updated, without using latest
, which is not very good practice.
â ī¸ Sketch uses the npm api to fetch the latest version for any given package. Depending on how many requests are made in a given timeframe, you might be rate limited by the api.
typescript:
# Default
no_convert_latest_to_range: false
# Default
version_range: patch
Adding dependencies to the catalog
If you set up your package manager to be pnpm
(which is the default) and set catalog
to true
, whenever you try to generate a new package that has dependencies marked with catalog:
(either the default catalog or a named one), each package that is not present in the target catalog inside pnpm-workspace.yaml
will be added automatically to it.
Example
Let's say that we are starting with a basic pnpm-workspace.yaml
file, and we generate a package that has catalog
dependencies, which are currently absent from their target catalogs:
typescript:
catalog: true
package_presets:
with_catalog:
name: with_catalog
dir: packages/with_catalog
package_json:
devDependencies:
# Named catalog
svelte: catalog:svelte
# Default catalog
hono: "catalog:"
After running
sketch ts package --preset with_catalog
We can see that the pnpm-workspace.yaml file has been updated with the new named catalog and dependencies:
packages:
- 'packages/*'
catalogs:
"svelte":
"svelte": ^5.39.2
catalog:
"hono": ^4.9.8
"oxlint": ^1.16.0
"typescript": ^5.9.2
"vitest": ^3.2.4
Maintainers Information
When working with a team on a monorepo that is made of several individual packages, it's very common that the same people have to be added to the author
, contributors
and maintainers
fields in the package.json
files for these packages.
To make this job easier and faster, you can use the people
field in the typescript config to store information about the contributors that are referred in multiple places, and then you can simply refer them by their ID.
Example
typescript:
people:
bruce:
name: Bruce Wayne
email: bruce@gotham.com
url: brucewayne.com
package_json_presets:
people-example:
author: bruce # Using the id from the store
maintainers:
# Literal definition
- name: Clark Kent
url: clarkkent.com
email: clark-kent@dailyplanet.com
- bruce
contributors:
- bruce
# Since package.json presets are extensible,
# you can use the above as a base for other package.json files,
# if the author or contributors are always the same
some-other-project:
extends:
- people-example
scripts:
say-hi: echo hi!
package_presets:
people-example:
dir: packages/people-example
package_json: people-example
After we run
sketch ts package --preset people-example
We get this package.json
file in the root of the new package:
{
"name": "people-example",
"private": true,
"version": "0.1.0",
"type": "module",
"packageManager": "pnpm",
"scripts": {},
"contributors": [
{
"name": "Bruce Wayne",
"email": "bruce@gotham.com",
"url": "brucewayne.com"
}
],
"maintainers": [
{
"name": "Bruce Wayne",
"email": "bruce@gotham.com",
"url": "brucewayne.com"
},
{
"name": "Clark Kent",
"email": "clark-kent@dailyplanet.com",
"url": "clarkkent.com"
}
],
"devDependencies": {
"oxlint": "^1.16.0",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
},
"dependencies": {}
}