Why a checkerなぜ検査器なのか
In wcstack the HTML and the state meet only through path strings. That is what keeps them independent — and it means a typo in a path is not a syntax error the browser could catch. The checker reads both sides and compares them: every path in data-wcs and {{ }} against the keys and getters of your state, every filter against the built-in list, every array call in your methods against the update rule.
wcstackでは、HTMLとstateはパスの文字列だけで結ばれています。だから両者は互いに独立していられるのですが、それはパスの打ち間違いがブラウザに見つけられる構文エラーにならない、ということでもあります。検査器は両側を読んで突き合わせます。data-wcsと{{ }}のすべてのパスをstateのキーやgetterと、すべてのフィルタを組み込みの一覧と、メソッド内の配列の呼び出しを更新の規則と照らし合わせます。
Run it実行する
You need Node.js. In the folder of your index.html from step 6, run:
Node.jsが必要です。ステップ6のindex.htmlがあるフォルダで、次を実行します。
$ npx @wcstack/lint index.html 0 error(s), 0 warning(s), 0 info
No configuration and no install step: npx fetches the checker and runs it. A few options are worth knowing:
設定もインストールの手順もいりません。npxが検査器を取ってきて実行します。知っておくと便利なオプションがいくつかあります。
| Optionオプション | What it does働き |
|---|---|
--lang=ja | Messages in Japanese (--lang=en for English).メッセージを日本語にする(英語は--lang=en)。 |
--errors-only | Print only errors — handy in a fix-and-rerun loop.エラーだけを表示する。直しては実行し直すループで便利。 |
--strict | Exit with 1 on warnings too. Without it, the exit code is 1 only when there is an error.警告でも終了コードを1にする。付けなければ、終了コードが1になるのはエラーがあるときだけ。 |
Each finding has a severity. An error is something the page cannot run with; a warning is almost certainly a mistake; an info is a suggestion.
指摘にはそれぞれ重さがあります。errorはページがそのままでは動かないもの、warningはほぼ確実に間違いであるもの、infoは提案です。
Break it on purposeわざと壊してみる
The fastest way to trust a checker is to watch it catch something. Make each change below in your step-6 page, reload the page to see what the browser does, run the checker, then undo the change. The line numbers are those of the step-6 file.
検査器を信頼するいちばんの近道は、何かを見つけるところを見ることです。ステップ6のページに下の変更を1つずつ加え、再読み込みしてブラウザの様子を見て、検査器を実行し、変更を元に戻します。行番号はステップ6のファイルのものです。
1. A typo in a path1. パスの打ち間違い
Change {{ .name }} in the product card to {{ .nmae }}. The page still loads, but every card loses its title — the only trace is a warning in the browser console. The checker points at the line:
商品カードの{{ .name }}を{{ .nmae }}に変えます。ページは読み込まれますが、すべてのカードから商品名が消え、手がかりはブラウザのコンソールの警告だけです。検査器はその行を指します。
$ npx @wcstack/lint index.html index.html:97:18 warning wcs/binding-path-missing Path ".nmae" does not exist in the state definition (expanded: products.*.nmae) 0 error(s), 1 warning(s), 0 info
2. A filter that doesn't exist2. 存在しないフィルタ
Change {{ .price|toFixed(2) }} in the card to {{ .price|currency }}. This time nothing on the page binds: the state stops at startup with [wcs/filter-unknown] filter not found: currency in the console. The checker:
カードの{{ .price|toFixed(2) }}を{{ .price|currency }}に変えます。今度はページの何もバインドされません。stateは起動の時点で止まり、コンソールに[wcs/filter-unknown] filter not found: currencyが出ます。検査器の結果は次のとおりです。
$ npx @wcstack/lint index.html index.html:99:39 error wcs/filter-unknown Filter "currency" is not a built-in filter 1 error(s), 0 warning(s), 0 info
The 47 built-in filters are listed on the state page.
47個の組み込みフィルタはstateのページに一覧があります。
3. push instead of a new array3. 新しい配列の代わりにpush
In addToCart, change this.cart = this.cart.concat( to this.cart.push(. In the browser, “Add to cart” now does nothing the first time you add a product. The checker reports an error, and three warnings after it:
addToCartのthis.cart = this.cart.concat(をthis.cart.push(に変えます。ブラウザでは、商品を初めて入れるときの「Add to cart」が何も起こさなくなります。検査器はエラーを1つと、それに続く警告を3つ出します。
$ npx @wcstack/lint index.html index.html:59:11 error wcs/array-mutation Destructive array method "push" does not trigger a reactive update (re-assigning the same reference does not reflect added/removed elements either). Use a non-destructive method with reassignment (e.g. this.cart = this.cart.concat(item)). index.html:117:40 warning wcs/binding-path-missing Path ".name" does not exist in the state definition (expanded: cart.*.name) index.html:120:98 warning wcs/binding-path-missing Path ".quantity" does not exist in the state definition (expanded: cart.*.quantity) index.html:121:24 warning wcs/binding-path-missing Path ".quantity" does not exist in the state definition (expanded: cart.*.quantity) 1 error(s), 3 warning(s), 0 info
Fix the error first: the warnings come from the same line. cart starts as an empty array, and the checker learned what a cart line looks like — name, quantity, … — from the object you passed to concat. Without that assignment it no longer knows the shape of a line. Put the concat back and all four go away.
先にエラーを直します。警告は同じ行から来ています。cartは空の配列から始まるので、検査器はカートの行の形(name、quantityなど)を、concatに渡したオブジェクトから知っていました。その代入が無くなると、行の形が分からなくなります。concatに戻せば、4つとも消えます。
The codes are the ones the browser console uses: wcs/binding-path-missing and wcs/filter-unknown above appeared in both places. A message you see at runtime can be found again, statically, with the checker.
コードはブラウザのコンソールと同じものです。上のwcs/binding-path-missingとwcs/filter-unknownは、どちらにも現れました。実行時に見たメッセージは、検査器で静的に見つけ直せます。
In your editor and your agentエディタとAIエージェントで
In VS Code, the wcstack-intellisense extension shows the same diagnostics as you type, completes paths and filters inside data-wcs, and gives the inline state script TypeScript's completion and hover.
VS Codeでは、拡張機能wcstack-intellisenseが、同じ診断を入力中に表示し、data-wcsの中でパスとフィルタを補完し、インラインのstateスクリプトにTypeScriptの補完とホバーを付けます。
If an AI coding agent writes your pages, have it run npx @wcstack/lint --errors-only index.html after each edit and fix until it exits with 0. It doesn't have to get the syntax right the first time; it has to converge.
AIのコーディングエージェントにページを書かせるなら、編集のたびにnpx @wcstack/lint --errors-only index.htmlを実行させ、終了コードが0になるまで直させます。最初から構文を正しく書けなくてもかまいません。収束すればよいのです。
Part 1 completePart 1 完了
You built a shop with a catalog, a cart, totals and search, in one HTML file and one script tag. Along the way:
HTMLファイル1つとscriptタグ1つで、商品一覧・カート・合計・検索のあるショップを作りました。その途中で学んだこと:
<wcs-state>holds one state tree;data-wcs="property: path|filter"and{{ }}wire it to any DOM property.for:,if:andelse:on<template>; inside a row,.nameis “this row's name”.- Handlers receive
(event, index). An update is an assignment to a path; lists change by assigning a new array. - Derived values are getters — on a path with
*for every row, with$getAllfor a column — and recompute only what changed. value:andradio:bind inputs both ways.npx @wcstack/lintchecks the paths, filters and array updates before the browser runs them.
<wcs-state>がstateの木を1本持ち、data-wcs="プロパティ: パス|フィルタ"と{{ }}がそれをどのDOMプロパティにもつなぐ。<template>のfor:・if:・else:。行の中の.nameは「この行のname」。- ハンドラは
(event, index)を受け取る。更新とはパスへの代入で、リストは新しい配列を代入して変える。 - 導かれる値はgetterに書く。
*を含むパスなら全行に、$getAllなら列全体に。変わったところだけが計算し直される。 value:とradio:は入力を両方向にバインドする。npx @wcstack/lintは、ブラウザが実行する前にパス・フィルタ・配列の更新を検査する。
Coming nextこの先
Part 2 — Connect to the outside loads the catalog from a JSON file with <wcs-fetch> and keeps the cart across reloads with <wcs-storage>: tags and a few getters, no fetch() or localStorage in your code. Part 3 — Grow into an app adds product pages with <wcs-router>, splits the page into components, tests it with @wcstack/testing, and publishes it with pinned versions; it is in preparation.
Part 2 外の世界とつなぐでは、<wcs-fetch>でJSONファイルから商品一覧を読み込み、<wcs-storage>で再読み込みしてもカートを残します。加えるのはタグといくつかのgetterで、コードにfetch()やlocalStorageは出てきません。Part 3 アプリに育てるでは、<wcs-router>で商品ページを加え、ページを部品に分け、@wcstack/testingでテストし、バージョンを固定して公開します。こちらは準備中です。