@wcstack/lint 1.27.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -23,6 +23,8 @@ npx wcs-validate --errors-only src/**/*.html
23
23
 
24
24
  `.manifest.json` で終わるファイルは sidecar manifest として、それ以外は `data-wcs` バインディングを含む HTML として検査されます。
25
25
 
26
+ `<wcs-state src="...">` で参照される外部 state(`.json` / `.js` / `.ts`)は HTML ファイルからの相対パスで解決され、パス検証の対象になります。URL・絶対パスは読み込まず、読めないファイルはスキップされ、解決できないパスは warning のままです。なお外部 state が**解決できた**ページには通常の検証面が全て適用されるため、error severity の検出(例: 配列でない値への `for:`)が「これまでパス未解決で沈黙していたビルド」を新たに落とすことがあります。
27
+
26
28
  ```
27
29
  wcs-validate [--attr=data-wcs] [--state-tag=wcs-state] [--lang=ja|en] [--errors-only] <file> [<file> ...]
28
30
  ```
package/README.md CHANGED
@@ -23,6 +23,8 @@ npx wcs-validate --errors-only src/**/*.html
23
23
 
24
24
  Files ending in `.manifest.json` are validated as sidecar manifests; everything else is validated as HTML with `data-wcs` bindings.
25
25
 
26
+ External state referenced via `<wcs-state src="...">` (`.json` / `.js` / `.ts`) is resolved relative to the HTML file and included in path validation. URLs and absolute paths are never read, unreadable files are skipped, and unresolved paths stay warnings. Note that once external state *does* resolve, the full validation surface applies to those pages — error-severity findings (e.g. `for:` bound to a non-array) can fail a build that was previously silent because the paths could not be checked.
27
+
26
28
  ```
27
29
  wcs-validate [--attr=data-wcs] [--state-tag=wcs-state] [--lang=ja|en] [--errors-only] <file> [<file> ...]
28
30
  ```
package/dist/cli.cjs CHANGED
@@ -21,12 +21,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/cli.ts
22
22
  var cli_exports = {};
23
23
  __export(cli_exports, {
24
+ createFileReader: () => createFileReader,
24
25
  main: () => main,
25
26
  parseArgs: () => parseArgs,
26
27
  resolveCliLocale: () => resolveCliLocale
27
28
  });
28
29
  module.exports = __toCommonJS(cli_exports);
29
30
  var import_node_fs = require("node:fs");
31
+ var import_node_path = require("node:path");
30
32
 
31
33
  // src/core/offsetToPosition.ts
32
34
  function createPositionMapper(text) {
@@ -190,9 +192,24 @@ var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
190
192
  "for"
191
193
  ]);
192
194
  var MAX_WILDCARD_DEPTH = 128;
195
+ var MODIFIER_PREVENT = "prevent";
196
+ var MODIFIER_STOP = "stop";
197
+ var MODIFIER_READONLY = "ro";
198
+ var MODIFIER_FLAGS = Object.freeze([
199
+ MODIFIER_PREVENT,
200
+ MODIFIER_STOP,
201
+ MODIFIER_READONLY
202
+ ]);
203
+ var MODIFIER_KEY_INIT = "init";
204
+ var MODIFIER_KEY_SYNC = "sync";
205
+ var MODIFIER_KEYS = Object.freeze([
206
+ MODIFIER_KEY_INIT,
207
+ MODIFIER_KEY_SYNC
208
+ ]);
209
+ var INDEX_PARAM_PREFIX = "$";
193
210
  var tmpIndexByIndexName = {};
194
211
  for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
195
- tmpIndexByIndexName[`$${i + 1}`] = i;
212
+ tmpIndexByIndexName[`${INDEX_PARAM_PREFIX}${i + 1}`] = i;
196
213
  }
197
214
  Object.freeze(tmpIndexByIndexName);
198
215
 
@@ -1104,10 +1121,10 @@ function getMessages(locale) {
1104
1121
 
1105
1122
  // src/service/bindingValidator.ts
1106
1123
  var filterMap = new Map(BUILTIN_FILTERS.map((f) => [f.name, f]));
1107
- function validateBindings(html, attrName, stateTagName = "wcs-state", locale) {
1124
+ function validateBindings(html, attrName, stateTagName = "wcs-state", locale, fileReader) {
1108
1125
  const diagnostics = [];
1109
1126
  const msgs = getMessages(locale);
1110
- const statePaths = getStatePathsFromHtml(html, stateTagName);
1127
+ const statePaths = getStatePathsFromHtml(html, stateTagName, fileReader);
1111
1128
  const pathsByState = /* @__PURE__ */ new Map();
1112
1129
  for (const p of statePaths) {
1113
1130
  const list = pathsByState.get(p.stateName) ?? [];
@@ -1898,10 +1915,10 @@ function isInsideTag(html, offset, tagName) {
1898
1915
  }
1899
1916
 
1900
1917
  // src/service/templateSyntaxValidator.ts
1901
- function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale) {
1918
+ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale, fileReader) {
1902
1919
  const diagnostics = [];
1903
1920
  const msgs = getMessages(locale);
1904
- const allPaths = getStatePathsFromHtml(html, stateTagName);
1921
+ const allPaths = getStatePathsFromHtml(html, stateTagName, fileReader);
1905
1922
  if (allPaths.length === 0) return diagnostics;
1906
1923
  const defaultPaths = allPaths.filter((p) => p.stateName === "default");
1907
1924
  const pathSet = new Set(defaultPaths.map((p) => p.path));
@@ -2015,6 +2032,7 @@ function isValidTemplatePath(path, pathSet, scopedPaths) {
2015
2032
  var BUILTIN_TAGS = {
2016
2033
  "wcs-accelerometer": {
2017
2034
  "package": "accelerometer",
2035
+ "observedAttributes": [],
2018
2036
  "inputs": {
2019
2037
  "frequency": null
2020
2038
  },
@@ -2032,6 +2050,7 @@ var BUILTIN_TAGS = {
2032
2050
  },
2033
2051
  "wcs-ambient-light-sensor": {
2034
2052
  "package": "ambient-light-sensor",
2053
+ "observedAttributes": [],
2035
2054
  "inputs": {
2036
2055
  "frequency": null
2037
2056
  },
@@ -2045,8 +2064,240 @@ var BUILTIN_TAGS = {
2045
2064
  "stop"
2046
2065
  ]
2047
2066
  },
2067
+ "wcs-audio": {
2068
+ "package": "audio",
2069
+ "observedAttributes": [
2070
+ "volume",
2071
+ "limiter",
2072
+ "resume-on-gesture"
2073
+ ],
2074
+ "inputs": {
2075
+ "volume": "volume",
2076
+ "limiter": "limiter",
2077
+ "resumeOnGesture": "resume-on-gesture"
2078
+ },
2079
+ "properties": [
2080
+ "state",
2081
+ "running",
2082
+ "suspended",
2083
+ "unsupported",
2084
+ "voices",
2085
+ "noteOn",
2086
+ "noteOff",
2087
+ "warnings",
2088
+ "error",
2089
+ "errorInfo"
2090
+ ],
2091
+ "commands": [
2092
+ "resume",
2093
+ "suspend",
2094
+ "noteOn",
2095
+ "noteOff",
2096
+ "allNotesOff"
2097
+ ]
2098
+ },
2099
+ "wcs-voice": {
2100
+ "package": "audio",
2101
+ "observedAttributes": [
2102
+ "poly"
2103
+ ],
2104
+ "inputs": {},
2105
+ "properties": [],
2106
+ "commands": []
2107
+ },
2108
+ "wcs-osc": {
2109
+ "package": "audio",
2110
+ "observedAttributes": [
2111
+ "frequency",
2112
+ "detune",
2113
+ "type",
2114
+ "glide",
2115
+ "transpose",
2116
+ "id",
2117
+ "out",
2118
+ "param",
2119
+ "note",
2120
+ "master",
2121
+ "poly"
2122
+ ],
2123
+ "inputs": {
2124
+ "frequency": "frequency",
2125
+ "detune": "detune",
2126
+ "type": "type",
2127
+ "glide": "glide",
2128
+ "transpose": "transpose"
2129
+ },
2130
+ "properties": [],
2131
+ "commands": []
2132
+ },
2133
+ "wcs-noise": {
2134
+ "package": "audio",
2135
+ "observedAttributes": [
2136
+ "id",
2137
+ "out",
2138
+ "param",
2139
+ "note",
2140
+ "master",
2141
+ "poly"
2142
+ ],
2143
+ "inputs": {},
2144
+ "properties": [],
2145
+ "commands": []
2146
+ },
2147
+ "wcs-biquad": {
2148
+ "package": "audio",
2149
+ "observedAttributes": [
2150
+ "frequency",
2151
+ "q",
2152
+ "gain",
2153
+ "detune",
2154
+ "type",
2155
+ "id",
2156
+ "out",
2157
+ "param",
2158
+ "note",
2159
+ "master",
2160
+ "poly"
2161
+ ],
2162
+ "inputs": {
2163
+ "frequency": "frequency",
2164
+ "q": "q",
2165
+ "gain": "gain",
2166
+ "detune": "detune",
2167
+ "type": "type"
2168
+ },
2169
+ "properties": [],
2170
+ "commands": []
2171
+ },
2172
+ "wcs-gain": {
2173
+ "package": "audio",
2174
+ "observedAttributes": [
2175
+ "gain",
2176
+ "id",
2177
+ "out",
2178
+ "param",
2179
+ "note",
2180
+ "master",
2181
+ "poly"
2182
+ ],
2183
+ "inputs": {
2184
+ "gain": "gain"
2185
+ },
2186
+ "properties": [],
2187
+ "commands": []
2188
+ },
2189
+ "wcs-delay": {
2190
+ "package": "audio",
2191
+ "observedAttributes": [
2192
+ "time",
2193
+ "feedback",
2194
+ "mix",
2195
+ "id",
2196
+ "out",
2197
+ "param",
2198
+ "note",
2199
+ "master",
2200
+ "poly"
2201
+ ],
2202
+ "inputs": {
2203
+ "time": "time",
2204
+ "feedback": "feedback",
2205
+ "mix": "mix"
2206
+ },
2207
+ "properties": [],
2208
+ "commands": []
2209
+ },
2210
+ "wcs-shaper": {
2211
+ "package": "audio",
2212
+ "observedAttributes": [
2213
+ "amount",
2214
+ "id",
2215
+ "out",
2216
+ "param",
2217
+ "note",
2218
+ "master",
2219
+ "poly"
2220
+ ],
2221
+ "inputs": {
2222
+ "amount": "amount"
2223
+ },
2224
+ "properties": [],
2225
+ "commands": []
2226
+ },
2227
+ "wcs-env": {
2228
+ "package": "audio",
2229
+ "observedAttributes": [
2230
+ "attack",
2231
+ "decay",
2232
+ "sustain",
2233
+ "release",
2234
+ "depth",
2235
+ "id",
2236
+ "out",
2237
+ "param",
2238
+ "note",
2239
+ "master",
2240
+ "poly"
2241
+ ],
2242
+ "inputs": {
2243
+ "attack": "attack",
2244
+ "decay": "decay",
2245
+ "sustain": "sustain",
2246
+ "release": "release",
2247
+ "depth": "depth"
2248
+ },
2249
+ "properties": [],
2250
+ "commands": []
2251
+ },
2252
+ "wcs-lfo": {
2253
+ "package": "audio",
2254
+ "observedAttributes": [
2255
+ "rate",
2256
+ "depth",
2257
+ "type",
2258
+ "id",
2259
+ "out",
2260
+ "param",
2261
+ "note",
2262
+ "master",
2263
+ "poly"
2264
+ ],
2265
+ "inputs": {
2266
+ "rate": "rate",
2267
+ "depth": "depth",
2268
+ "type": "type"
2269
+ },
2270
+ "properties": [],
2271
+ "commands": []
2272
+ },
2273
+ "wcs-analyser": {
2274
+ "package": "audio",
2275
+ "observedAttributes": [
2276
+ "fft",
2277
+ "smoothing",
2278
+ "id",
2279
+ "out",
2280
+ "param",
2281
+ "note",
2282
+ "master",
2283
+ "poly"
2284
+ ],
2285
+ "inputs": {
2286
+ "fft": "fft",
2287
+ "smoothing": "smoothing"
2288
+ },
2289
+ "properties": [
2290
+ "frame"
2291
+ ],
2292
+ "commands": [
2293
+ "sample"
2294
+ ]
2295
+ },
2048
2296
  "wcs-broadcast": {
2049
2297
  "package": "broadcast",
2298
+ "observedAttributes": [
2299
+ "name"
2300
+ ],
2050
2301
  "inputs": {
2051
2302
  "name": "name",
2052
2303
  "manual": "manual"
@@ -2064,6 +2315,13 @@ var BUILTIN_TAGS = {
2064
2315
  },
2065
2316
  "wcs-camera": {
2066
2317
  "package": "camera",
2318
+ "observedAttributes": [
2319
+ "facing-mode",
2320
+ "device-id",
2321
+ "audio",
2322
+ "width",
2323
+ "height"
2324
+ ],
2067
2325
  "inputs": {
2068
2326
  "audio": "audio",
2069
2327
  "facingMode": "facing-mode",
@@ -2092,6 +2350,7 @@ var BUILTIN_TAGS = {
2092
2350
  },
2093
2351
  "wcs-recorder": {
2094
2352
  "package": "camera",
2353
+ "observedAttributes": [],
2095
2354
  "inputs": {
2096
2355
  "mimeType": "mime-type",
2097
2356
  "timeslice": "timeslice",
@@ -2120,6 +2379,7 @@ var BUILTIN_TAGS = {
2120
2379
  },
2121
2380
  "wcs-clipboard": {
2122
2381
  "package": "clipboard",
2382
+ "observedAttributes": [],
2123
2383
  "inputs": {
2124
2384
  "monitor": "monitor"
2125
2385
  },
@@ -2147,6 +2407,7 @@ var BUILTIN_TAGS = {
2147
2407
  },
2148
2408
  "wcs-contacts": {
2149
2409
  "package": "contacts",
2410
+ "observedAttributes": [],
2150
2411
  "inputs": {},
2151
2412
  "properties": [
2152
2413
  "value",
@@ -2161,6 +2422,7 @@ var BUILTIN_TAGS = {
2161
2422
  },
2162
2423
  "wcs-credential": {
2163
2424
  "package": "credential",
2425
+ "observedAttributes": [],
2164
2426
  "inputs": {},
2165
2427
  "properties": [
2166
2428
  "value",
@@ -2176,6 +2438,7 @@ var BUILTIN_TAGS = {
2176
2438
  },
2177
2439
  "wcs-debounce": {
2178
2440
  "package": "debounce",
2441
+ "observedAttributes": [],
2179
2442
  "inputs": {
2180
2443
  "source": null,
2181
2444
  "wait": "wait",
@@ -2196,6 +2459,7 @@ var BUILTIN_TAGS = {
2196
2459
  },
2197
2460
  "wcs-throttle": {
2198
2461
  "package": "debounce",
2462
+ "observedAttributes": [],
2199
2463
  "inputs": {
2200
2464
  "source": null,
2201
2465
  "wait": "wait",
@@ -2216,6 +2480,7 @@ var BUILTIN_TAGS = {
2216
2480
  },
2217
2481
  "wcs-defined": {
2218
2482
  "package": "defined",
2483
+ "observedAttributes": [],
2219
2484
  "inputs": {
2220
2485
  "tags": "tags",
2221
2486
  "mode": "mode",
@@ -2233,6 +2498,7 @@ var BUILTIN_TAGS = {
2233
2498
  },
2234
2499
  "wcs-eyedropper": {
2235
2500
  "package": "eyedropper",
2501
+ "observedAttributes": [],
2236
2502
  "inputs": {},
2237
2503
  "properties": [
2238
2504
  "value",
@@ -2248,6 +2514,9 @@ var BUILTIN_TAGS = {
2248
2514
  },
2249
2515
  "wcs-fetch": {
2250
2516
  "package": "fetch",
2517
+ "observedAttributes": [
2518
+ "url"
2519
+ ],
2251
2520
  "inputs": {
2252
2521
  "url": null,
2253
2522
  "method": null,
@@ -2273,24 +2542,36 @@ var BUILTIN_TAGS = {
2273
2542
  },
2274
2543
  "wcs-fetch-header": {
2275
2544
  "package": "fetch",
2545
+ "observedAttributes": [],
2276
2546
  "inputs": {},
2277
2547
  "properties": [],
2278
2548
  "commands": []
2279
2549
  },
2280
2550
  "wcs-fetch-body": {
2281
2551
  "package": "fetch",
2552
+ "observedAttributes": [],
2282
2553
  "inputs": {},
2283
2554
  "properties": [],
2284
2555
  "commands": []
2285
2556
  },
2286
2557
  "wcs-infinite-scroll": {
2287
2558
  "package": "fetch",
2559
+ "observedAttributes": [
2560
+ "target",
2561
+ "root",
2562
+ "root-margin",
2563
+ "threshold",
2564
+ "disabled"
2565
+ ],
2288
2566
  "inputs": {},
2289
2567
  "properties": [],
2290
2568
  "commands": []
2291
2569
  },
2292
2570
  "wcs-fullscreen": {
2293
2571
  "package": "fullscreen",
2572
+ "observedAttributes": [
2573
+ "target"
2574
+ ],
2294
2575
  "inputs": {
2295
2576
  "target": "target"
2296
2577
  },
@@ -2306,6 +2587,7 @@ var BUILTIN_TAGS = {
2306
2587
  },
2307
2588
  "wcs-geo": {
2308
2589
  "package": "geolocation",
2590
+ "observedAttributes": [],
2309
2591
  "inputs": {
2310
2592
  "highAccuracy": "high-accuracy",
2311
2593
  "timeout": "timeout",
@@ -2336,6 +2618,7 @@ var BUILTIN_TAGS = {
2336
2618
  },
2337
2619
  "wcs-gyroscope": {
2338
2620
  "package": "gyroscope",
2621
+ "observedAttributes": [],
2339
2622
  "inputs": {
2340
2623
  "frequency": null
2341
2624
  },
@@ -2353,6 +2636,7 @@ var BUILTIN_TAGS = {
2353
2636
  },
2354
2637
  "wcs-idle": {
2355
2638
  "package": "idle",
2639
+ "observedAttributes": [],
2356
2640
  "inputs": {
2357
2641
  "threshold": "threshold"
2358
2642
  },
@@ -2371,6 +2655,12 @@ var BUILTIN_TAGS = {
2371
2655
  },
2372
2656
  "wcs-intersect": {
2373
2657
  "package": "intersection",
2658
+ "observedAttributes": [
2659
+ "target",
2660
+ "root",
2661
+ "root-margin",
2662
+ "threshold"
2663
+ ],
2374
2664
  "inputs": {
2375
2665
  "target": "target",
2376
2666
  "root": "root",
@@ -2398,6 +2688,7 @@ var BUILTIN_TAGS = {
2398
2688
  },
2399
2689
  "wcs-magnetometer": {
2400
2690
  "package": "magnetometer",
2691
+ "observedAttributes": [],
2401
2692
  "inputs": {
2402
2693
  "frequency": null
2403
2694
  },
@@ -2413,8 +2704,46 @@ var BUILTIN_TAGS = {
2413
2704
  "stop"
2414
2705
  ]
2415
2706
  },
2707
+ "wcs-midi": {
2708
+ "package": "midi",
2709
+ "observedAttributes": [
2710
+ "input",
2711
+ "output",
2712
+ "channel"
2713
+ ],
2714
+ "inputs": {
2715
+ "input": "input",
2716
+ "output": "output",
2717
+ "channel": "channel",
2718
+ "sysex": "sysex",
2719
+ "auto": "auto"
2720
+ },
2721
+ "properties": [
2722
+ "message",
2723
+ "type",
2724
+ "channel",
2725
+ "note",
2726
+ "velocity",
2727
+ "control",
2728
+ "value",
2729
+ "devices",
2730
+ "connected",
2731
+ "permission",
2732
+ "granted",
2733
+ "denied",
2734
+ "unsupported",
2735
+ "error",
2736
+ "errorInfo"
2737
+ ],
2738
+ "commands": [
2739
+ "request",
2740
+ "close",
2741
+ "send"
2742
+ ]
2743
+ },
2416
2744
  "wcs-network": {
2417
2745
  "package": "network",
2746
+ "observedAttributes": [],
2418
2747
  "inputs": {},
2419
2748
  "properties": [
2420
2749
  "effectiveType",
@@ -2427,6 +2756,7 @@ var BUILTIN_TAGS = {
2427
2756
  },
2428
2757
  "wcs-notify": {
2429
2758
  "package": "notification",
2759
+ "observedAttributes": [],
2430
2760
  "inputs": {
2431
2761
  "notice": null,
2432
2762
  "mode": "mode",
@@ -2462,6 +2792,7 @@ var BUILTIN_TAGS = {
2462
2792
  },
2463
2793
  "wcs-permission": {
2464
2794
  "package": "permission",
2795
+ "observedAttributes": [],
2465
2796
  "inputs": {
2466
2797
  "name": "name",
2467
2798
  "userVisibleOnly": "user-visible-only",
@@ -2478,6 +2809,9 @@ var BUILTIN_TAGS = {
2478
2809
  },
2479
2810
  "wcs-pip": {
2480
2811
  "package": "picture-in-picture",
2812
+ "observedAttributes": [
2813
+ "target"
2814
+ ],
2481
2815
  "inputs": {
2482
2816
  "target": "target"
2483
2817
  },
@@ -2493,6 +2827,9 @@ var BUILTIN_TAGS = {
2493
2827
  },
2494
2828
  "wcs-pointer-lock": {
2495
2829
  "package": "pointer-lock",
2830
+ "observedAttributes": [
2831
+ "target"
2832
+ ],
2496
2833
  "inputs": {
2497
2834
  "target": "target"
2498
2835
  },
@@ -2508,6 +2845,7 @@ var BUILTIN_TAGS = {
2508
2845
  },
2509
2846
  "wcs-raf": {
2510
2847
  "package": "raf",
2848
+ "observedAttributes": [],
2511
2849
  "inputs": {
2512
2850
  "once": "once",
2513
2851
  "repeat": "repeat",
@@ -2532,6 +2870,11 @@ var BUILTIN_TAGS = {
2532
2870
  },
2533
2871
  "wcs-resize": {
2534
2872
  "package": "resize",
2873
+ "observedAttributes": [
2874
+ "target",
2875
+ "box",
2876
+ "round"
2877
+ ],
2535
2878
  "inputs": {
2536
2879
  "target": "target",
2537
2880
  "box": "box",
@@ -2555,6 +2898,7 @@ var BUILTIN_TAGS = {
2555
2898
  },
2556
2899
  "wcs-screen-orientation": {
2557
2900
  "package": "screen-orientation",
2901
+ "observedAttributes": [],
2558
2902
  "inputs": {},
2559
2903
  "properties": [
2560
2904
  "type",
@@ -2571,6 +2915,7 @@ var BUILTIN_TAGS = {
2571
2915
  },
2572
2916
  "wcs-share": {
2573
2917
  "package": "share",
2918
+ "observedAttributes": [],
2574
2919
  "inputs": {},
2575
2920
  "properties": [
2576
2921
  "value",
@@ -2585,6 +2930,7 @@ var BUILTIN_TAGS = {
2585
2930
  },
2586
2931
  "wcs-speak": {
2587
2932
  "package": "speech",
2933
+ "observedAttributes": [],
2588
2934
  "inputs": {
2589
2935
  "say": null,
2590
2936
  "rate": "rate",
@@ -2614,6 +2960,7 @@ var BUILTIN_TAGS = {
2614
2960
  },
2615
2961
  "wcs-listen": {
2616
2962
  "package": "speech",
2963
+ "observedAttributes": [],
2617
2964
  "inputs": {
2618
2965
  "lang": "lang",
2619
2966
  "continuous": "continuous",
@@ -2641,6 +2988,9 @@ var BUILTIN_TAGS = {
2641
2988
  },
2642
2989
  "wcs-sse": {
2643
2990
  "package": "sse",
2991
+ "observedAttributes": [
2992
+ "url"
2993
+ ],
2644
2994
  "inputs": {
2645
2995
  "url": "url",
2646
2996
  "withCredentials": "with-credentials",
@@ -2665,6 +3015,10 @@ var BUILTIN_TAGS = {
2665
3015
  },
2666
3016
  "wcs-storage": {
2667
3017
  "package": "storage",
3018
+ "observedAttributes": [
3019
+ "key",
3020
+ "type"
3021
+ ],
2668
3022
  "inputs": {
2669
3023
  "key": null,
2670
3024
  "type": null,
@@ -2687,6 +3041,7 @@ var BUILTIN_TAGS = {
2687
3041
  },
2688
3042
  "wcs-tilt": {
2689
3043
  "package": "tilt",
3044
+ "observedAttributes": [],
2690
3045
  "inputs": {},
2691
3046
  "properties": [
2692
3047
  "alpha",
@@ -2705,6 +3060,9 @@ var BUILTIN_TAGS = {
2705
3060
  },
2706
3061
  "wcs-timer": {
2707
3062
  "package": "timer",
3063
+ "observedAttributes": [
3064
+ "interval"
3065
+ ],
2708
3066
  "inputs": {
2709
3067
  "interval": "interval",
2710
3068
  "once": "once",
@@ -2729,6 +3087,9 @@ var BUILTIN_TAGS = {
2729
3087
  },
2730
3088
  "wcs-upload": {
2731
3089
  "package": "upload",
3090
+ "observedAttributes": [
3091
+ "url"
3092
+ ],
2732
3093
  "inputs": {
2733
3094
  "url": null,
2734
3095
  "method": null,
@@ -2757,6 +3118,10 @@ var BUILTIN_TAGS = {
2757
3118
  },
2758
3119
  "wcs-wakelock": {
2759
3120
  "package": "wakelock",
3121
+ "observedAttributes": [
3122
+ "active",
3123
+ "type"
3124
+ ],
2760
3125
  "inputs": {
2761
3126
  "active": "active",
2762
3127
  "type": "type",
@@ -2774,6 +3139,9 @@ var BUILTIN_TAGS = {
2774
3139
  },
2775
3140
  "wcs-ws": {
2776
3141
  "package": "websocket",
3142
+ "observedAttributes": [
3143
+ "url"
3144
+ ],
2777
3145
  "inputs": {
2778
3146
  "url": "url",
2779
3147
  "protocols": "protocols",
@@ -2803,6 +3171,9 @@ var BUILTIN_TAGS = {
2803
3171
  },
2804
3172
  "wcs-worker": {
2805
3173
  "package": "worker",
3174
+ "observedAttributes": [
3175
+ "src"
3176
+ ],
2806
3177
  "inputs": {
2807
3178
  "src": "src",
2808
3179
  "type": "type",
@@ -2844,13 +3215,13 @@ var DOM_COMMON_PROPERTIES = /* @__PURE__ */ new Set([
2844
3215
  ]);
2845
3216
  var STRUCTURAL_DIRECTIVES2 = /* @__PURE__ */ new Set(["for", "if", "elseif", "else"]);
2846
3217
  var EMPTYISH_SEEDS = /* @__PURE__ */ new Set(["''", '""', "``", "null", "[]", "{}"]);
2847
- function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale) {
3218
+ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale, fileReader) {
2848
3219
  const diagnostics = [];
2849
3220
  const msgs = getMessages(locale);
2850
3221
  const occurrences = findBuiltinTagOccurrences(html);
2851
3222
  if (occurrences.length === 0) return diagnostics;
2852
3223
  let statePaths = null;
2853
- const getPaths = () => statePaths ??= getStatePathsFromHtml(html, stateTagName);
3224
+ const getPaths = () => statePaths ??= getStatePathsFromHtml(html, stateTagName, fileReader);
2854
3225
  for (const occ of occurrences) {
2855
3226
  const contract = BUILTIN_TAGS[occ.tagName];
2856
3227
  if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
@@ -3202,10 +3573,11 @@ function validateDocument(text, options = {}) {
3202
3573
  const bindAttribute = options.bindAttribute ?? "data-wcs";
3203
3574
  const stateTagName = options.stateTagName ?? "wcs-state";
3204
3575
  const locale = options.locale;
3576
+ const fileReader = options.fileReader;
3205
3577
  const out = [];
3206
- out.push(...validateBindings(text, bindAttribute, stateTagName, locale));
3207
- out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale));
3208
- out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale));
3578
+ out.push(...validateBindings(text, bindAttribute, stateTagName, locale, fileReader));
3579
+ out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale, fileReader));
3580
+ out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale, fileReader));
3209
3581
  out.push(...validateDocumentEnv(text, locale));
3210
3582
  out.push(...validateArrayMutations(text, stateTagName, locale));
3211
3583
  out.push(...validateWatchDeclarations(text, stateTagName, locale));
@@ -3792,7 +4164,8 @@ function runValidation(inputs, options = {}) {
3792
4164
  const diagnosticsBySource = /* @__PURE__ */ new Map();
3793
4165
  for (const input of inputs) {
3794
4166
  if (input.kind === "html") {
3795
- diagnosticsBySource.set(input.source, validateDocument(input.text, options));
4167
+ const docOptions = input.fileReader !== void 0 ? { ...options, fileReader: input.fileReader } : options;
4168
+ diagnosticsBySource.set(input.source, validateDocument(input.text, docOptions));
3796
4169
  }
3797
4170
  }
3798
4171
  const manifestInputs = inputs.filter((i) => i.kind === "manifest");
@@ -3836,6 +4209,29 @@ function runValidation(inputs, options = {}) {
3836
4209
  function classify(path) {
3837
4210
  return path.endsWith(".manifest.json") ? "manifest" : "html";
3838
4211
  }
4212
+ function createFileReader(htmlPath, read = (p) => (0, import_node_fs.readFileSync)(p, "utf8")) {
4213
+ const base = (0, import_node_path.dirname)(htmlPath);
4214
+ const cache = /* @__PURE__ */ new Map();
4215
+ return (relativePath) => {
4216
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(relativePath) || relativePath.startsWith("/")) {
4217
+ return void 0;
4218
+ }
4219
+ if (cache.has(relativePath)) {
4220
+ return cache.get(relativePath);
4221
+ }
4222
+ let content;
4223
+ try {
4224
+ content = read((0, import_node_path.resolve)(base, relativePath));
4225
+ if (content.charCodeAt(0) === 65279) {
4226
+ content = content.slice(1);
4227
+ }
4228
+ } catch {
4229
+ content = void 0;
4230
+ }
4231
+ cache.set(relativePath, content);
4232
+ return content;
4233
+ };
4234
+ }
3839
4235
  function parseArgs(argv) {
3840
4236
  const options = {};
3841
4237
  const files = [];
@@ -3875,7 +4271,8 @@ function main(argv) {
3875
4271
  `);
3876
4272
  return 2;
3877
4273
  }
3878
- inputs.push({ source: path, text, kind: classify(path) });
4274
+ const kind = classify(path);
4275
+ inputs.push({ source: path, text, kind, fileReader: kind === "html" ? createFileReader(path) : void 0 });
3879
4276
  }
3880
4277
  const result = runValidation(inputs, { ...options, locale });
3881
4278
  for (const line of result.lines) {
@@ -3893,6 +4290,7 @@ if (typeof require !== "undefined" && typeof module !== "undefined" && require.m
3893
4290
  }
3894
4291
  // Annotate the CommonJS export names for ESM import in node:
3895
4292
  0 && (module.exports = {
4293
+ createFileReader,
3896
4294
  main,
3897
4295
  parseArgs,
3898
4296
  resolveCliLocale
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/lint",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "Static-contract validator CLI (wcs-validate) for wcstack data-wcs bindings and wcstack.manifest.json sidecars. Thin npm wrapper around the wcstack-intellisense validator core.",
5
5
  "type": "module",
6
6
  "bin": {