Skip to content

Usage rules

Usage rules enforce that code uses the right building blocks, reach for your design-system Input, not a raw <input>; call a service, not fetch. This is the one place Shapelint looks inside function bodies and JSX.

Two rule options, both taking a list of UsageBan:

  • disallowElements: ban JSX elements/components.
  • disallowCalls: ban function calls.
ts
{
  name: 'ui-primitive',
  files: 'components/ui/**/*.tsx',
  disallowElements: [
    { name: 'input', useInstead: 'the Input component', except: ['components/ui/Input.tsx'] },
  ],
  disallowCalls: [
    { name: 'fetch',   useInstead: 'a service in @/services' },
    { name: 'axios.*', useInstead: 'a service in @/services' },
  ],
}

The UsageBan shape

FieldDescription
nameThe element tag or call callee to ban. * is a wildcard segment: axios.*, use*Query.
useInsteadThe replacement, shown verbatim in the diagnostic.
withinOnly ban inside this lexical JSX ancestor (e.g. 'Form'). Omit for anywhere.
exceptFile globs exempt from this ban, e.g. the primitive's own file may use the raw element.

Element identity

  • A lowercase name (input, div) matches the raw HTML tag.
  • A capitalized name (Input) matches that component by identifier.

Context-sensitivity (within)

ts
disallowElements: [{ name: 'Input', useInstead: 'InputField', within: 'Form' }];

Input is allowed everywhere except lexically inside a <Form>…</Form>.

Lexical only. within sees JSX ancestors in the same file. If a <Form> renders a child component that itself renders an Input, Shapelint cannot see across that component boundary, no static tool can. This is a deliberate limit, not a bug.

Self-exclusion (except)

The component that provides the primitive legitimately uses the raw element:

ts
{ name: 'input', useInstead: 'the Input component', except: ['components/ui/Input.tsx'] }

Without except, Input.tsx would flag its own <input>.

Banning backend & utility calls

disallowCalls applies across any tier of the stack to enforce logging, caching, configuration, or I/O abstractions:

ts
// Ban direct synchronous I/O or raw environment access in domain services
{
  name: 'domain-service',
  files: 'domain/services/**/*.ts',
  disallowCalls: [
    { name: 'fs.readFileSync', useInstead: 'the FileStorageService repository' },
    { name: 'console.log',     useInstead: 'this.logger.info' },
    { name: 'process.env.*',   useInstead: 'the AppConfig service' },
  ],
}

Diagnostic codes

  • ARCH_DISALLOWED_ELEMENT
  • ARCH_DISALLOWED_CALL

Released under the MIT License.