diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ef44688 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.gitignore b/.gitignore index 43e05fb..cca36be 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.vscode/launch.json b/.vscode/launch.json index 7bc18a4..44a86ab 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -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}" - ] - } - ] -} \ No newline at end of file + "configurations": [ + { + "name": "Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ] + } + ] +} diff --git a/.vscodeignore b/.vscodeignore index f369b5e..9214eaf 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0c2f5..436db92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 `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 `Change` event exists): Angular `[(prop)]`, Svelte `bind:prop`. +- **Ready-made layout examples** (`ns--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/`, 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 \ No newline at end of file +- Initial public release — NativeScript UI snippets for Angular (`html`) in VS Code. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b1acef5 --- /dev/null +++ b/CLAUDE.md @@ -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//*.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--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-` — the bare tag (e.g. `ns-button` → ``; React/Svelte lowercase the first letter → `` | Plain tag | -| property (prop) | `ns-button-prop` | `nsbutpr` | with *props | + All properties | -| complete (comp) | `ns-button-comp` | `nsbu-c` | with *props, *events, *docs | + All properties, events and API docs | -| layout snippets | `ns-dock-layout-snippet-2` | `nsdocnip2` | see below | Sample snippets from [site docs]. | -| gestures | `ns-tap` | `nstap` | `(tap)=""` | Gesture Snippets | -| setting icon | `ns-icon-stop` | `nsicost` | `14` | [Setting Icon] snippets | +Every component and layout ships in three variants. Here's the same `Switch`, three ways — exactly what lands in your editor: + +### 1. Bare — `ns-switch` + +```html + +``` + +### 2. Property — `ns-switch-prop` + +Every property becomes a Tab-stop. Two-way-bindable props use the flavor's binding syntax: + +```html + +``` + +### 3. Complete — `ns-switch-comp` + +Properties **and** events, plus an inline doc comment listing each one — and a reminder of how many inherited `View` properties the element also accepts: + +```html + + + +``` + +> Bigger elements scale the same way — `ns-button-prop` lays out every one of `Button`'s properties and `ns-text-field-prop` every property of `TextField`, each as a numbered Tab-stop you can fill or skip. + +### The same prefix, every flavor + +`ns-button` adapts to whichever file you're in — PascalCase tags for Angular/Core/Vue, camelCase for React/Svelte, and the right event syntax for each: + +```html + + + + + -``` +Eight gesture bindings, one prefix each — adapted to the flavor's event syntax: -#### Property output +| Prefix | Angular | Core | Vue | React | Svelte | +|---|---|---|---|---|---| +| `ns-tap` | `(tap)=""` | `tap=""` | `@tap=""` | `onTap={}` | `on:tap={}` | -``` html - -``` +…plus `ns-doubleTap`, `ns-longPress`, `ns-swipe`, `ns-pan`, `ns-pinch`, `ns-rotation`, and `ns-touch`. -#### Complete output +### iOS system icons (Angular + Core) -``` html - - +```html + ``` -## Demo +24 icons in all (`ns-icon-done`, `ns-icon-search`, `ns-icon-trash`, …) — see [reference.md][reference] for the complete list. -**HTML snippet `ns-text-field` in action; _default_, _property_ (prop) and _complete_ (comp) syntax demo.** +## Snippets -![nativescript-angular-html-snippet-demo](images/playback.gif "Nativescript: Angular HTML Snippets demo") +This extension contributes **805 snippets** across **five NativeScript flavors**, generated from `@nativescript/core` v9.0.20. See **[reference.md](reference.md)** for the full prefix tables. -## Snippets +| Flavor | Language id(s) | Snippets | +|---|---|---| +| Angular | `html` | 182 | +| Core (XML) | `xml` | 179 | +| Vue | `vue` | 149 | +| React | `typescriptreact`, `javascriptreact` | 143 | +| Svelte | `svelte` | 152 | -For complete references examples and demo, [see here][snippet-reference]. - -### User Interface > Layouts - -* ns-absolute-layout -* ns-dock-layout -* ns-grid-layout -* ns-stack-layout -* ns-wrap-layout -* ns-flexbox-layout - -### User Interface > Components - -* ns-actionbar -* ns-actionbarextension -* ns-actionitem -* ns-navigationbutton -* ns-activityindicator -* ns-button -* ns-datepicker -* ns-formattedstring -* ns-htmlview -* ns-image -* ns-label -* ns-listpicker -* ns-listview -* ns-progress -* ns-scroll-view -* ns-search-bar -* ns-segmented-bar -* ns-segmented-bar-item -* ns-slider -* ns-switch -* ns-bottom-navigation -* ns-tab-strip -* ns-tab-strip-item -* ns-tab-content-item -* ns-tabs -* ns-tab-view -* ns-tab-view-item -* ns-text-field -* ns-text-view -* ns-time-picker -* ns-web-view +> Vue and Svelte snippets require the **Vue (Volar)** and **Svelte** language extensions respectively — without them VS Code has no `vue`/`svelte` language to attach to, and the snippets stay dormant until installed. -### Gestures +### Variants + +| Prefix | Expands to | +|---|---| +| `ns-` | the bare element | +| `ns--prop` | element + its primary properties as tab-stops | +| `ns--comp` | properties + events + a documented property/event table | +| `ns--snippet-N` | *(layouts only)* a complete ready-made example layout | -| Snippet | Output | -|----------------|------------------| -| `ns-tap` | `(tap)=""` | -| `ns-doubleTap` | `(doubleTap)=""` | -| `ns-longPress` | `(longPress)=""` | -| `ns-swipe` | `(swipe)=""` | -| `ns-pan` | `(pan)=""` | -| `ns-pinch` | `(pinch)=""` | -| `ns-rotation` | `(rotation)=""` | -| `ns-touch` | `(touch)=""` | - -### Setting Icons - -| Snippet | Output | -|------------------|--------| -|`ns-icon-action` | `9` | -|`ns-icon-undo` | `21` | - -#### List - -| ICON | VALUE | ICON | VALUE | -|---------------|-------|-------------|-------| -| Done | 0 | Search | 12 | -| Cancel | 1 | Refresh | 13 | -| Edit | 2 | Stop | 14 | -| Save | 3 | Camera | 15 | -| Add | 4 | Trash | 16 | -| FlexibleSpace | 5 | Play | 17 | -| FixedSpace | 6 | Pause | 18 | -| Compose | 7 | Rewind | 19 | -| Reply | 8 | FastForward | 20 | -| Action | 9 | Undo | 21 | -| Organize | 10 | Redo | 22 | -| Bookmarks | 11 | PageCurl | 23 | - -Reference: https://docs.nativescript.org/angular/ui/action-bar#setting-icons +Most prefixes work in every flavor; a few are flavor-specific: `ActionBarExtension` (Angular only), `NavigationButton` (not in React), `Repeater` (not in Vue and React), `RootLayout` (not in React), `SplitView` (Angular/Core only). +### The same prefix per flavor +| Flavor | Language id(s) | per-flavor syntax *(illustrative — tag case + property + event)* | +|---|---|---| +| Angular | `html` | `