Existing code to spec

👉 Closed beta notice

Tessl framework is in private beta. Join our community to be updated on our future product releases.

Tessl can be used to create specs from existing code using our document tool. This is useful for a number of reasons:

  • Living documentation: Specs become accessible entrypoints for you when approaching unfamiliar code, or for collaborators who need to be onboarded quickly.

  • Low-friction intro to specs: When starting from code you know, you can quickly gain an instinct for what makes a good spec. Does your generated spec accurately reflect the behavior of the module?

  • Test boost: Specs can be prompted to include tests which will run against the original code.

The document tool is invoked with a --code parameter that accepts a code path, like this:

tessl document --code src/cache.js

This will create a spec at cache.spec.md in your specs/ folder. Here's an example:

Descriptive spec for an in-memory cache
# TTL Cache

A time-to-live cache implementation that automatically expires entries after a specified duration. Provides a Map-like interface with automatic cleanup of expired entries.

## Targets

[@describe](../../src/cache.js)

## Capabilities

### Store key-value pairs with automatic expiration

Stores values in the cache with a configurable time-to-live (TTL) duration. When the TTL expires, entries are automatically removed from the cache.

- Setting a key with default TTL stores the value and sets up automatic expiration
- Setting a key with custom TTL overrides the default expiration time
- Setting the same key multiple times replaces the value and resets the TTL
- Expired entries are automatically removed from the cache

### Retrieve cached values

Provides access to stored values while they are still valid (not expired).

- Getting an existing key returns the stored value
- Getting a non-existent key returns undefined
- Getting an expired key returns undefined

### Check key existence

Determines whether a key exists in the cache.

- Checking an existing key returns true
- Checking a non-existent key returns false
- Checking an expired key returns false

### Manual entry removal

Allows explicit removal of cache entries before their TTL expires.

- Deleting an existing key removes it from the cache and returns true
- Deleting a non-existent key returns false
- Deleting a key cancels its expiration timer

### Cache introspection

Provides methods to inspect the current state of the cache.

- Getting cache size returns the number of stored entries
- Getting cache keys returns an iterator of all stored keys
- Getting cache values returns an iterator of all stored values
- Getting cache entries returns an iterator of all key-value pairs

### Complete cache clearing

Removes all entries from the cache and cancels all pending expiration timers.

- Clearing the cache removes all entries
- Clearing the cache cancels all expiration timers
- Clearing a specific key removes only that entry

## API

```javascript { .api }
/**
 * TTL Cache implementation with automatic expiration
 * @class TTLCache
 */
class TTLCache {
  /**
   * Creates a new TTL cache instance
   * @param {number} [defaultTTL=300000] Default time-to-live in milliseconds (5 minutes)
   */
  constructor(defaultTTL = 300000);

  /**
   * Sets a key-value pair in the cache with optional TTL
   * @param {*} key The cache key
   * @param {*} value The value to cache
   * @param {number} [ttl] Time-to-live in milliseconds, defaults to defaultTTL
   * @returns {TTLCache} Returns this cache instance for chaining
   */
  set(key, value, ttl);

  /**
   * Gets a value from the cache
   * @param {*} key The cache key
   * @returns {*} The cached value or undefined if not found or expired
   */
  get(key);

  /**
   * Checks if a key exists in the cache
   * @param {*} key The cache key
   * @returns {boolean} True if the key exists and hasn't expired
   */
  has(key);

  /**
   * Removes a key from the cache
   * @param {*} key The cache key to remove
   * @returns {boolean} True if the key was found and removed
   */
  delete(key);

  /**
   * Clears the cache or a specific key
   * @param {*} [key] If provided, clears only this key; otherwise clears all
   */
  clear(key);

  /**
   * Gets the number of entries in the cache
   * @returns {number} The current cache size
   */
  size();

  /**
   * Gets an iterator of cache keys
   * @returns {Iterator} Iterator of cache keys
   */
  keys();

  /**
   * Gets an iterator of cache values
   * @returns {Iterator} Iterator of cache values
   */
  values();

  /**
   * Gets an iterator of cache entries
   * @returns {Iterator} Iterator of [key, value] pairs
   */
  entries();
}

module.exports = TTLCache;
```

You'll notice that this spec has a @describe tag at the top, instead of @generate. This means that this spec will never generate code as-is, it is purely descriptive.

You may also want to describe the implementation of the code, not just its behavior. To do this, run the document command over your newly produced spec with the --include-impl-details flag:

tessl document --spec specs/cache.spec.md --include-impl-details

This will add implementation details to the spec, loading context from the @describe path. See an example below:

Descriptive spec with implementation details

This looks very similar to our first spec, but this time we see lots of { .impl } blocks. These are specially linked to Tessl's implementation of this spec.

As with most other Tessl tools, document will also accept --context and --prompt parameters, so you can accomplish more complex documentation tasks. For example:

By default specs will not include test links, but you can instruct tessl to include test links by using the prompt. This will make it easy to build tests for code at the same time as building the spec.

For example:

and in the implementation details case:

This will give you a spec that looks like this:

Now, with your descriptive spec, you have curated context you can use to collaborate with other developers, or even to onboard other agents in new sessions.

Last updated