Official language support for Jacaré .jcr files — syntax highlighting, compile diagnostics, Mesh hover, snippets, file icons, and editor ergonomics for the Jacaré reactive UI framework.
Publisher: heberalmeida
Extension ID: heberalmeida.jacare
Author: Heber Almeida
Marketplace: https://marketplace.visualstudio.com/items?itemName=heberalmeida.jacare
Live Lab: https://jacarejs.github.io/core/lab/
Features
| Feature | Description |
|---|---|
| Syntax highlighting | JavaScript module body, view / style / contract blocks, directives, HTML, and bindings |
| TypeScript | // @jacare-ts turns the script region into source.ts; sibling *.jcr.ts uses full TypeScript mode |
| Jacaré scope themes | Optional dark/light themes that color @jacare-ts, #if/#for, <view>/<contract>, and mesh addresses |
| Pulse Mesh | Highlight ${@bag/key} / ${@route/key} / ${@search/key}; hover shows bag / key / resolve expr; Go to Definition jumps to the bag (not for reserved route / search); snippets for bags, links, and route/search sugar |
| Compile diagnostics | On open/edit/save, compile() errors appear in the Problems panel (click to jump to the line) |
| Template directives | #if, #elif, #else, #end, #case, #when, #for (and @if / @each aliases) · jacare-when |
| Template contracts | Colored export <contract> tags plus props / pulses / slots / emits / forwards / links (from / mode) |
| Snippets | Component scaffold, screen/nav, a11y field, Mesh/@route, jacare-when, focus grip, islands, signals, control flow |
| Component tags | PascalCase components such as <Field /> and <Card> |
| Bindings | bind-value, on-click, @click, :prop, class-active / class:active, style---pct / style:pct, ${expr} — prefer bare calls over ${() => …} when no local is captured |
| Scoped CSS | style tagged templates and export <style> highlighted as CSS |
| File icons | Jacaré logo for .jcr files in the Explorer |
| Editor helpers | Auto-closing brackets, quotes, and template literals |
| Lab command | Jacaré: Open Lab Lesson for Symbol — opens the matching Lab lesson (or a picker) |
Installation
Visual Studio Marketplace
- Open the Extensions panel (
Cmd+Shift+X/Ctrl+Shift+X) - Search for Jacaré
- Install Jacaré by heberalmeida
Or install from the command line:
code --install-extension heberalmeida.jacare
From source (monorepo)
cd packages/vscode-jacare
yarn install
yarn build
yarn package
code --install-extension jacare-0.0.23.vsix --force
Development mode
- Open the
packages/vscode-jacarefolder in VS Code - Run Run Extension from the Debug panel (F5)
- A new Extension Development Host window opens with the extension loaded
Snippets
In a .jcr file, type a prefix and accept the suggestion (Tab / Enter). Snippets use the jacare language id.
| Prefix | Aliases | Inserts |
|---|---|---|
jcr-bag |
createBag |
Pulse Bag factory + ripple (lazy publish) |
jcr-bag-read |
— | ${cart.count()} — Mesh Port via import |
jcr-mesh |
jcr-at, @bag |
${@cart/count} — address sugar via getBag |
jcr-route |
@route |
${@route/id} — active nav param via getRouteParam |
jcr-search |
@search |
${@search/q} — active search via getRouteSearch |
jcr-mesh-click |
@bag-click |
on-click=${@cart/clear} |
jcr-links |
contract-links |
Contract links + view alias (no bag import) |
jcr-import |
import-jacare |
import { … } including createBag / getBag / getRouteParam / ripple |
jcr-island |
mountIsland |
mountIsland from @jacare/core/island + dispose |
jcr-component |
jacare-component |
Full scaffold: export <contract> + <view> + <style> |
jcr-contract |
export-contract |
Contract with props, pulses, slots, and emits |
jcr-props |
contract-props |
Minimal contract (required + model props) |
jcr-view |
export-view |
export <view>…</view> |
jcr-style |
export-style |
export <style>…</style> |
jcr-signal |
signal |
const name = signal(…) |
jcr-pulse |
pulse |
const name = pulse(…) |
jcr-computed |
computed |
const name = computed(() => …) |
jcr-derive |
derive |
const name = derive(() => …) |
jcr-text |
jcr-expr |
${count()} — prefer bare (no redundant arrow) |
jcr-text-arrow |
jcr-expr-arrow |
${() => label(item.id)} — when capturing a #for local |
jcr-class |
class-active |
class-active=${open()} |
jcr-class-colon |
class: |
class:active=${open()} — colon alias |
jcr-style-var |
style--- |
style---pct=${pct()} |
jcr-style-colon |
style: |
style:pct=${pct()} — colon alias |
jcr-screen |
jacare-screen |
Nav screen page scaffold (data-jacare-focus) |
jcr-field-a11y |
a11y-field |
Label + input + role="alert" error |
jcr-if |
#if |
#if / #end |
jcr-when |
jacare-when |
<p jacare-when=${cond}>…</p> — same IR as single #if |
jcr-focus |
data-jacare-focus |
data-jacare-focus tabindex="-1" |
jcr-go-focus |
nav.go.focus |
await nav.go('/x', { focus: true }) |
jcr-ifelse |
#ifelse |
#if / #else / #end |
jcr-case |
#case |
#case / #when / #else / #end |
jcr-for |
#for |
#for items() as item (item.id) / #end |
jcr-bind |
bind-value |
bind-value=${signal} |
jcr-click |
on-click |
on-click=${handler} |
jcr-click-arrow |
— | on-click=${() => remove(item.id)} |
jcr-emit |
emit |
emit('change') |
jcr-slot |
slot |
<slot name="…" /> |
jcr-use |
component-tag |
<Component :prop=${value}>…</Component> |
jcr-debug |
debug |
<debug copy label="…">${value}</debug> |
Navigation snippets (.js / .ts)
| Prefix | Aliases | Inserts |
|---|---|---|
jcr-nav-lazy |
lazy-screen |
Lazy createNav screen entry |
jcr-nav-screen |
screen-entry |
Eager screen() entry + import |
jcr-create-nav |
createNav |
Full createNav + createRoute scaffold |
Pair jcr-screen in the .jcr page with jcr-nav-lazy in nav.js.
Lab command
Command Palette → Jacaré: Open Lab Lesson for Symbol
- Cursor on a known symbol (
pulse,#if,createNav,bind-value, …) → opens that Lab lesson - Otherwise → QuickPick of all lessons
Live Lab: https://jacarejs.github.io/core/lab/
Template expression style
Both forms are reactive. Prefer the bare call when nothing from a #for (or other local) needs capturing:
${cart.count()}
${t('home.lead')}
class-on=${open()}
Use an arrow when the expression must close over a loop item or handler argument:
#for items() as item (item.id)
<span>${() => label(item.id)}</span>
<button on-click=${() => remove(item.id)}>×</button>
#end
jacare check warns on redundant nullary arrows (--strict-style to fail CI). See syntax — Template bindings.
Snippet examples
Component scaffold (jcr-component):
export <contract>
props: {
label: { type: 'string', required: true }
}
emits: ['change']
</contract>
export <view>
<div class="component">
</div>
</view>
export <style>
.component {
}
</style>
Contract (jcr-contract):
export <contract>
props: {
label: { type: 'string', required: true }
}
pulses: {
count: 'number'
}
slots: ['default', 'actions']
emits: ['change']
</contract>
Pulse bag (jcr-bag) / Mesh sugar (jcr-mesh) / Contract links (jcr-links):
export const cart = createBag('cart', () => { /* … */ })
export <view>
<span>${@cart/count}</span>
</view>
Island host (jcr-island):
import { mountIsland } from '@jacare/core/island'
import Widget from './Widget.jcr'
const dispose = mountIsland('#slot', Widget, {
props: { start: 0 },
shadow: true,
})
Control flow (jcr-if, jcr-for):
#if show()
<p>Visible</p>
#else
<p>Hidden</p>
#end
#for items() as item (item.id)
<li>${item.label}</li>
#end
Tab through placeholders to fill names, types, and handlers.
Language support
File extension
| Extension | Language ID | Aliases |
|---|---|---|
.jcr |
jacare |
Jacaré, jacare, jcr |
Jacaré files are plain JavaScript modules. The extension highlights both the script and embedded templates.
Highlighted syntax
JavaScript module
Tagged template
import { signal, view } from '@jacare/core'
const count = signal(0)
function increment() {
count.update((n) => n + 1)
}
export default view`
<div class="counter">
<p>${count}</p>
<button on-click=${increment}>+1</button>
</div>
`
View block (HTML-style alternative)
import { signal } from '@jacare/core'
const count = signal(0)
function increment() {
count.update((n) => n + 1)
}
export <view>
<div class="counter">
<p>${count}</p>
<button on-click=${increment}>+1</button>
</div>
</view>
Template contracts
Declare the component surface with export <contract>. The compiler checks parents with jacare check (and Vite transform) — no runtime PropTypes. Use bind-value for model: true props; :value is rejected.
export <contract>
props: { label: 'string' }
pulses: { count: 'number' }
slots: ['default', 'actions']
emits: ['inc']
</contract>
export <view>
<p>${label}: ${count}</p>
<slot name="actions" />
<button on-click=${() => emit('inc')}>+</button>
</view>
Parent usage (validated at check time):
<Counter :label=${'Score'} :count=${score} on-inc=${() => score.update((n) => n + 1)}>
<button slot="actions">Reset</button>
</Counter>
| Contract field | Meaning |
|---|---|
props |
Accepted props ('string' or { type, required, default, model }) |
pulses |
Props expected to be pulses/signals |
slots |
Slot names (default → children) |
emits |
Events via emit('name') — parent listens with on-name |
links |
Mesh aliases { alias: { from: 'bag.key', mode: 'read'|'write'|'mirror' } } |
See the API — Template contracts and Pulse bags sections for the full reference.
Pulse Mesh (shared state)
Jacaré-native shared pulses — highlight and snippets for bags, contract links, and ${@bag/key} address sugar.
import { createBag, pulse, ripple } from '@jacare/core'
export const cart = createBag('cart', () => {
const count = pulse(0)
return { count, bump: () => ripple(() => count.update((n) => n + 1)) }
})
export <view>
<span>${cart.count}</span>
<span>${@cart/count}</span>
<button type="button" on-click=${@cart/bump}>+</button>
</view>
export <contract>
links: {
count: { from: 'cart.count', mode: 'read' }
}
</contract>
export <view>
<span>${count}</span>
</view>
Template directives
view`
#if show()
<p>Visible</p>
#else
<p>Hidden</p>
#end
#for items() as item (item.id)
<li>${item.label}</li>
#end
`
Components and slots
view`
<Card :title=${title}>
<p>Slot content</p>
</Card>
`
Scoped styles
export <style>
.card { padding: 1rem; }
.title { font-weight: bold; }
</style>
Scope names (for theme authors)
| Scope | Used for |
|---|---|
source.jacare |
Root language scope |
keyword.control.directive.jacare-ts |
// @jacare-ts pragma (green in Jacaré scope themes) |
meta.embedded.block.typescript.jacare |
Script region when the file starts with // @jacare-ts |
keyword.control.jacare |
#if, #for, #end, @each, etc. |
entity.name.tag.jacare |
view, style, and contract block tags |
entity.name.tag.jacare.contract |
<contract> / </contract> specifically |
keyword.other.contract.jacare |
Contract fields: props, pulses, slots, emits, forwards, links, from, mode |
variable.other.mesh-address.jacare |
Mesh / route address sugar ${@bag/key} · ${@route/id} |
entity.name.type.tag.jacare |
PascalCase components |
entity.name.tag |
HTML elements (div, slot, button, view, style, …) |
entity.other.attribute-name |
bind-*, on-*, class-*, jacare-*, data-jacare-*, :prop |
meta.embedded.expression.jacare |
${expression} inside templates |
meta.contract.jacare |
Entire export <contract>…</contract> block |
source.css |
Content inside style blocks |
TypeScript coloring
| File / marker | Highlighting |
|---|---|
Foo.jcr (default) |
Script as JavaScript |
Foo.jcr starting with // @jacare-ts |
Script as TypeScript (source.ts) · pragma in Jacaré green |
Foo.jcr.ts sibling |
Full TypeScript language mode + Jacaré file icon |
Optional color themes (Preferences: Color Theme):
- Jacaré scopes (dark) — accent for
@jacare-ts, directives, tags, mesh - Jacaré scopes (light) — same scopes for light UI
Snippets: jcr-ts (pragma scaffold) · jcr-ts-sibling in .jcr.ts files.
File icons
The extension contributes the Jacaré Icons file icon theme and sets it as the default when installed.
| File type | Icon |
|---|---|
.jcr |
Jacaré logo |
.jcr.ts |
Jacaré logo (typed sibling) |
| Other files | Minimal generic file/folder icons |
If icons do not appear:
- Open Command Palette (
Cmd+Shift+P/Ctrl+Shift+P) - Run Preferences: File Icon Theme
- Select Jacaré Icons
- Run Developer: Reload Window
Configuration
The extension works out of the box. No settings are required.
To use another file icon theme while keeping syntax highlighting, pick any theme in Preferences: File Icon Theme. Language highlighting for .jcr files remains active.
Recommended workspace settings
Optional settings.json for Jacaré projects:
{
"files.associations": {
"*.jcr": "jacare"
},
"editor.quickSuggestions": {
"strings": true
}
}
What this extension does not include
| Not included | Alternative |
|---|---|
| IntelliSense / autocomplete | Use snippets (jcr-*) plus TypeScript with jacare.d.ts in your project |
| Formatting | Format the JavaScript parts with your Prettier/ESLint setup |
Cross-file contract / Mesh links check |
Use jacare check from @jacare/cli for workspace-wide validation |
Related documentation
- Jacaré repository
- API reference — template contracts · Pulse bags / Mesh
- Jacaré Lab — interactive demos including Pulse bags
- Main README
- Syntax guide
- Live demos — Todo · Showcase · Scale BMI · Lab
- Compiler docs
License
MIT © Heber Almeida