Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5a8e454
chore: enforce LF and update ignore rules
ElecTreeFrying Jun 20, 2026
03ecc18
chore: refresh icon and demo media
ElecTreeFrying Jun 20, 2026
14c29d8
docs: add snippets/ generator-contract notes
ElecTreeFrying Jun 20, 2026
0f941f0
add: Angular (HTML) component, layout, gesture & icon snippets
ElecTreeFrying Jun 20, 2026
fff2c00
add: Core (XML) component, layout, gesture & icon snippets
ElecTreeFrying Jun 20, 2026
698f3f8
add: Vue component, layout & gesture snippets
ElecTreeFrying Jun 20, 2026
08a907c
add: React (tsx/jsx) component, layout & gesture snippets
ElecTreeFrying Jun 20, 2026
7d70459
add: Svelte component, layout & gesture snippets
ElecTreeFrying Jun 20, 2026
1f0f5d1
add: wire multi-flavor manifest
ElecTreeFrying Jun 20, 2026
1a87051
chore: remove legacy Angular-only snippets
ElecTreeFrying Jun 20, 2026
052f5ba
chore: regenerate reference.md
ElecTreeFrying Jun 20, 2026
b757e11
docs: rewrite README for multi-flavor
ElecTreeFrying Jun 20, 2026
9efde00
docs: add SPEC.md
ElecTreeFrying Jun 20, 2026
5eb7f11
docs: add SUPPORT.md
ElecTreeFrying Jun 20, 2026
389a037
docs: add project CLAUDE.md
ElecTreeFrying Jun 20, 2026
750926a
docs: add v1.0.0 changelog entry
ElecTreeFrying Jun 20, 2026
658b4ea
fix: correct LICENSE copyright (encoding + year)
ElecTreeFrying Jun 20, 2026
474c2a4
test: scaffold qa/ harness
ElecTreeFrying Jun 20, 2026
86235b7
test: add qa/checklists
ElecTreeFrying Jun 20, 2026
438a0df
test: add qa/workspace fixtures
ElecTreeFrying Jun 20, 2026
f72426b
test: add qa/demo-workspace sandbox
ElecTreeFrying Jun 20, 2026
ab800db
chore: exclude dev tooling from the .vsix, update EDH launch
ElecTreeFrying Jun 20, 2026
72af72c
chore: align package-lock version with package.json (0.1.4)
ElecTreeFrying Jun 20, 2026
0ed1e17
docs: polish historical changelog entries (v0.1.0–v0.1.4)
ElecTreeFrying Jun 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Enforce LF for all text files — prevents the CRLF spurious-diff problem
# (editors re-saving as CRLF previously produced huge phantom diffs across the snippet JSON)
* text=auto eol=lf

# Binary assets
*.png binary
*.gif binary
*.vsix binary
*.mov binary
12 changes: 10 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
snippets/cson
.vscode-test/
*.vsix
node_modules/
.DS_Store
# .claude/ is local-only — not committed
.claude/

# tools/ is local-only (the snippet generator) — not committed
tools/

# demo-video masters — converted to .gif for the README; kept local, not committed (see .vscodeignore)
images/*.mov
23 changes: 11 additions & 12 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}
23 changes: 22 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

# dev-only: keep the published .vsix lean (ship package.json + snippets/ + README/CHANGELOG/LICENSE + images/icon.png)
node_modules/**
tools/**
qa/**
.gitattributes
package-lock.json
reference.md
SPEC.md
SUPPORT.md
CLAUDE.md
# per-directory dev docs beside the shipped snippet JSON (the bare CLAUDE.md above only matches root)
snippets/**/CLAUDE.md
snippets/**/README.md
.claude/**

# Keep demo media out of the .vsix: README uses relative image paths that vsce auto-rewrites to GitHub raw URLs at publish, so bundling these large gifs is unnecessary; .mov are convert-to-gif masters
images/playback.gif
images/demo-variants.gif
images/demo-flavors.gif
images/demo-variants.mov
images/demo-flavors.mov
50 changes: 39 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,67 @@
# Change Log

## v1.0.0 (2026-6-28)

### Added

- **Multiplatform support** — snippets now cover **five NativeScript flavors**: Angular (`html`), Core (`xml`), Vue (`vue`), React (`typescriptreact`/`javascriptreact`), and Svelte (`svelte`). 805 snippets total.
- **Code generator** (`tools/`, run with `npm run generate`) — snippet content is derived from `@nativescript/core` v9 TypeScript types, walking inheritance for each component's full property set. It reads both `@nsProperty`/`@nsEvent` annotations **and** `Property`/`CssProperty` registrations (which carry most real markup props), and folds in the implementation `<Name>Base` classes that the public `.d.ts` flattens away. README and `reference.md` tables are generated too, so they can no longer drift.
- **Two-way binding** in `-prop`/`-comp` for two-way-capable props (where a `<prop>Change` event exists): Angular `[(prop)]`, Svelte `bind:prop`.
- **Ready-made layout examples** (`ns-<layout>-snippet-N`) carried forward from the original pack and rendered for every flavor.
- `NavigationButton` (Angular/Core/Vue/Svelte) and `ActionBarExtension` (Angular) restored; `Repeater` (legacy `@nsView` list component) added.
- `LiquidGlass` and `LiquidGlassContainer` — iOS Liquid Glass effect containers (driven by the inherited `iosGlassEffect` View property), for all five flavors.
- Enum-typed properties now expand to value hints, e.g. `iosIndicatorViewStyle="${2:(medium|large)}"`.
- `.gitattributes` enforcing LF (fixes the recurring CRLF spurious-diff problem); snippet validator (`npm run validate`).

### Changes

- Rebuilt every snippet against current NativeScript (v9.0.20) — a three-major-version leap across more than six years, from the v6.4.0 the original pack was authored against.
- `-prop`/`-comp` variants now use sequential tab-stops + a final `$0` (fixes the mirrored-tab-stop bug) and document the inherited `View` properties.
- Corrected event names derived from the static member (e.g. `blur`, not `blurEvent`; `isLoadingChange`, not `isLoading`).
- Accurate property attribution: component-specific CSS props (`placeholderColor`, `tintColor`, tab/segmented colors, …) are scoped to their component instead of listed as universal `View` props; read-only status getters (e.g. `Image.isLoading`) are excluded.
- Cleaner enum hints: drop noise CSS-wide keywords (`initial`/`inherit`/`unset`/`revert`), expand string-literal aliases/enums, resolve trivial aliases to primitives, and cap oversized unions. `-prop` uses two-way binding (Angular `[(x)]`, Svelte `bind:x`); `-comp` shows every property + event explicitly.
- `Source:` URLs verified against the current docs (`/api/class/<Tag>`, gestures → `/guide/gestures`, icons → `/ui/action-bar`).
- Broadened extension display name/description to all flavors; fixed `anuglar` keyword typo.

### Removed

- The whole modern tab-navigation family — `Tabs`, `BottomNavigation`, `TabStrip`, `TabStripItem`, `TabContentItem` — verified absent from `@nativescript/core` v9.0.20 (0 class declarations); it ships in a separate plugin now. Planned for a future plugin-aware release.
- `SplitView` is emitted only for Angular/Core (it is not registered in the Vue/React/Svelte element registries).

## v0.1.4 (2020-7-25)

### Changes

- updated README
- Updated the README.

## v0.1.3 (2020-3-21)

### Changes

- updated README
- Updated the README.

## v0.1.2 (2020-3-18)

### Added

- more demos and exampls in reference .md
- updated README
- removed snippet in keywords and added html
- More demos and examples in `reference.md`.
- HTML language scoping; dropped the redundant `snippet` marketplace keyword.

### Changes

- remove typos in CHANGELOG
- Updated the README.
- Corrected typos in the changelog.

## v0.1.1 (2020-3-18)

### Fixes

- vsce publish error: icon not found
- fixed some CHANGELOG.md typos
- version name
- Fixed a `vsce publish` failure caused by a missing icon.
- Corrected the version metadata in `package.json`.
- Corrected typos in the changelog.

## v0.1.0 (2020-3-17)

- Initial release
### Added

- version name
- Initial public release — NativeScript UI snippets for Angular (`html`) in VS Code.
103 changes: 103 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commit conventions

Do NOT append a `Co-Authored-By: Claude …` trailer (or any other AI attribution) to commit messages. Write commits as if authored solely by the user. Style is loose conventional-commits (`fix:`, `chore:`, `add:`) plus bare version-number commits (e.g. `0.2.0`) that mark a release alongside the `CHANGELOG.md` entry. Don't bake `version` bumps into your work — `vsce publish` owns versioning.

## What this is

A **generated, multi-flavor VS Code snippets extension** for NativeScript. It ships **no runtime/activation code** (no `extension.ts`, no `main`, no `activationEvents`) — the published artifact is `package.json` + the snippet JSON under `snippets/`. But it is **not** hand-authored: every snippet is derived from `@nativescript/core` v9 TypeScript types by a build-time generator under `tools/`. There is a build step (the generator) even though there is no runtime. The `tools/` generator is **local-only (gitignored)** — not committed or distributed, so a fresh clone has the shipped `snippets/` + docs but not the build tooling.

The same `ns-*` prefixes are contributed to five flavors, each scoped to its language(s) via `contributes.snippets`:

| Flavor | Language id(s) | Icons? |
|---|---|---|
| Angular | `html` | yes |
| Core | `xml` | yes |
| Vue | `vue` | no |
| React | `typescriptreact`, `javascriptreact` | no |
| Svelte | `svelte` | no |

## Commands

```bash
npm run generate # full pipeline: extract → render → gen-docs → validate → check-coverage
npm run validate # structural integrity checks on the generated snippet JSON only
npm run check # fidelity: generated snippets vs the model (every prop/event, counts, no orphans)
```

- **Test interactively:** press `F5` (`.vscode/launch.json` → "Extension") to open an Extension Development Host, then type a prefix in a file of the matching language and confirm the expansion.
- **Package / publish:** `npx @vscode/vsce package` (produces a gitignored `.vsix`) / `npx @vscode/vsce publish` (publisher `ElecTreeFrying`; needs a PAT). `vsce` is invoked directly — not wrapped in an npm script.

## Architecture — the generation pipeline

One neutral model, four stages plus a fidelity gate, data flowing left to right:

```
@nativescript/core .d.ts
│ tools/extract.js (TypeScript compiler API; @nsView/@nsProperty/@nsEvent + Property/CssProperty
│ registrations; walks the extends/Base chain for each element's full prop set)
tools/ns-model.json (neutral model: coreVersion, components[] {tag, kind, base, desc, props, events,
│ inheritedPropCount, inheritedEventCount}, viewCommon)
│ tools/render.js (one model → five flavor renderers; variants bare / -prop / -comp; gestures;
│ icons for Angular+Core; per-flavor element registries; two-way-binding shapes)
snippets/<flavor>/*.json + tools/render-manifest.json (per-flavor counts; gitignored)
│ tools/gen-docs.js (model + manifest → docs)
reference.md + README.md "## Snippets" section
│ tools/validate.js (gate: valid JSON, unique prefixes, $0 in -prop/-comp, no repeated tab-stops,
│ Source: URL present) — exit 1 on any failure
│ tools/check-coverage.js (fidelity gate: snippets vs ns-model.json + extra-components.json —
▼ every prop/event, two-way shape, inherited counts, no orphans) — exit 1
```

**Source of truth:** the `@nativescript/core` types (for components/layouts), plus hand-authored data with no type representation — the `GESTURES`/`ICONS` tables in `render.js` (8 gestures, 24 iOS icons), `tools/layout-examples.json` (the ready-made `ns-<layout>-snippet-N` demos), and `tools/extra-components.json` (real non-`@nsView` elements like `NavigationButton`/`ActionBarExtension`; also read by `gen-docs.js`). The shipped `snippets/**/*.json` are **build artifacts**, not source.

## The generator contract (read before touching docs or snippets)

These are silently overwritten on the next `npm run generate`:

- **`snippets/**/*.json`** — regenerated wholesale by `render.js`. Hand-editing a snippet is futile. To change a snippet, edit the generator or its curated data, then regenerate.
- **`reference.md`** — regenerated wholesale by `gen-docs.js`. Never hand-edit; the file header says so.
- **README `## Snippets` section** — `gen-docs.js` rewrites everything between the `## Snippets` heading and the **next `## ` heading** in place. When editing the README, keep that heading and ensure a following `## ` heading exists, and treat the block between them as generator-owned.

The rest of the README, plus `SPEC.md`, `SUPPORT.md`, `CLAUDE.md`, `CHANGELOG.md`, and `LICENSE.md`, are hand-maintained.

## Prefix & variant grammar

All prefixes start with `ns-`. Per element:

- `ns-<name>` — the bare tag (e.g. `ns-button` → `<Button></Button>`; React/Svelte lowercase the first letter → `<button>`).
- `ns-<name>-prop` — every primary property as a `${n:hint}` tab-stop; enum types expand to `(a|b|c)` hints; two-way-capable props use the flavor's binding (Angular `[(x)]`, Svelte `bind:x`).
- `ns-<name>-comp` — properties + events + a trailing doc comment listing each, and a count of inherited `View` props/events.
- `ns-<layout>-snippet-N` — *(layouts only)* complete ready-made example layouts.
- `ns-<gesture>` — a gesture binding fragment (8 gestures).
- `ns-icon-<name>` — *(Angular + Core only)* the numeric `ios.systemIcon` value for an `ActionItem` (24 icons).

Per-flavor transforms live in the `FLAVORS` table in `render.js` (tag case, prop/event syntax, comment delimiters, which flavors get icons). A few elements are intentionally absent from some flavors' element registries (e.g. `SplitView` Angular/Core only) — that's why per-flavor snippet counts differ.

## Gotchas

- **Line endings:** `.gitattributes` enforces LF. Snippet JSON is LF, 2-space indent — preserve it; a CRLF re-save produces huge phantom diffs.
- **`tools/render-manifest.json` is generated and gitignored** — `gen-docs.js` reads it, so run `render.js` before `gen-docs.js` (the `generate` script already orders them).
- **`validate.js` gates the pipeline** (exit 1) — it's the last step of `generate` and also runnable alone via `npm run validate`.
- **Event names come from the static `<event>Event` member**, not the unreliable `@nsEvent` tag value (e.g. `blur`, not `blurEvent`).
- **`svelte-start-tag` dual-scoping (don't "clean up"):** `package.json` contributes `snippets/svelte/gestures.json` to **two** languages — `svelte` *and* `svelte-start-tag`. The Svelte grammar scopes the inside of an element's opening tag as a separate `svelte-start-tag` language, so without the second mapping the gesture snippets (`ns-tap` → `on:tap={…}`) only appear *between* elements, never inside `<button …>`. The duplicate-looking line is load-bearing — leave it. Vue has no equivalent in-tag language to target, so this is Svelte-only; the Vue limitation is documented in `SUPPORT.md` instead.

## Manual QA harness — `qa/`

There are no *automated* tests (see below), but `qa/` holds a **manual QA harness** for verifying the shipped snippets in the Extension Development Host (press `F5`). It is dev-only — excluded from the published `.vsix` via `.vscodeignore` (`qa/**`). Layout:

- **`qa/checklists/`** — one `[ ]` checklist per flavor (`angular`/`core`/`vue`/`react`/`svelte`) plus `general.md` (cross-flavor: prefix grammar, variant model, tab-stop semantics, **language scoping**). Run `general.md` first; per-flavor checklists test only that flavor's delta (tag case, event/two-way syntax, icons, excluded elements).
- **`qa/workspace/`** — fixture files to open as a folder in the EDH; one subdir per checklist (`general/` + the five flavors), each holding near-empty scratch files to type prefixes into. **Checklist ↔ workspace is 1:1; the checklist is the source of truth** — if a checklist references a fixture, that file must exist.
- **`qa/demo-workspace/`** — a standalone NativeScript flavor sandbox (one component per flavor, same flavor layout as `workspace/`; nothing to install — snippets are declarative) for trying snippets in context. Referenced by no checklist; the sync rules don't apply to it.

Each of `qa/`, `qa/checklists/`, `qa/workspace/`, and every `qa/workspace/<flavor>/` has its own `README.md` (human guide) + `CLAUDE.md` (edit/sync rules). When a checklist changes, propagate per `qa/CLAUDE.md`.

## What's intentionally absent

No `extension.ts`, no bundler, no test framework, no `@types/vscode` — it's a declarative snippets extension at ship time. The only "build" is the doc/snippet generator, which is a dev-time concern excluded from the published `.vsix` via `.vscodeignore`. Correctness is guarded by two deterministic gates — `tools/validate.js` (structural) and `tools/check-coverage.js` (fidelity: the generated snippets faithfully reflect the model) — plus the `qa/` manual checklists (behavioral, in the EDH).
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2020 John James G. Ermita¤o
Copyright (c) 2020-2026 John James G. Ermitaño

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
Expand Down
Loading