on_the_money 0.7.0 → 0.7.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.1] — 2026-07-19
8
+
9
+ Port feedback, same day: the first downstream migrations onto the 0.7.0 batteries surfaced three regressions. Issues #132–#135, #137; PRs #138–#142.
10
+
11
+ ### Fixed
12
+
13
+ - **`otm/no-raw-websocket` flags only the browser global.** Scope-resolved: an imported or locally declared `WebSocket` (a Node `ws`-package client) passes — the hand-rolled-lifecycle slop vector the rule targets doesn't exist there. (#132)
14
+ - **`.ejs` joins otm-lint's markup universe** for cross-file rules (reveal spans, slots, actions); per-file rules stay `.html`-only so template syntax never trips HTML-004. HTML-107's css→span direction is silent when zero reveal spans were found anywhere — an empty universe is blindness, not dead wiring. Kills 46 false errors on server-templated projects. (#133)
15
+ - **src-first entry — the core singleton unforked.** `exports "."` (and `main`/`module`) resolve to `src/core/index.js`, the same graph every battery subpath imports; previously `.` pointed at the dist bundle, so importing the entry plus any battery loaded two `The` singletons and `boot()` configured one while batteries read the other. The redundant `./src` alias is gone; `dist/` demotes to a CDN/script-tag artifact. Reverses the 0.2.0 dist-entry decision — deliberately, no legacy. (#134)
16
+ - Test-runner IPC flake (`Unable to deserialize cloned data`) starved at the source: the CLI's console chatter is mocked in its tests. (#30 lineage)
17
+
18
+ ### Changed
19
+
20
+ - Blog example modernized to 0.7.0 idioms: `$.cloneEach` + `data-bind` replace the manual clone loop and per-clone `setAttribute`. (#135)
21
+
7
22
  ## [0.7.0] — 2026-07-19
8
23
 
9
24
  The boundary release. OTM's mandate extends to the browser side of live data — batteries for the platform's gaps, contracts instead of server code, and the lint stack grown into a drift wall — under a ratified constitution: a battery ships only if it wraps a platform *absence*, rides an existing standard or published machine-readable convention, lands with lint + doctest on day one, lives in a subpath the core never pays for, and carries an explicit NOT-list. Issues #84, #86–#89, #115–#120; PRs #121–#131.
package/README.md CHANGED
@@ -766,7 +766,7 @@ npx otm-lint --check ./src
766
766
  | **HTML-106** *(warn)* | A globally written state key nothing consumes | The deletion test as lint: no CSS attribute selector, `[data-text]` slot, `"data-key"` JS string literal (e.g. MutationObserver `attributeFilter`), or `the("key")` read touches it — dead state or a missing CSS rule. Warn-level: reported, never fails the run. |
767
767
  | **HTML-107** | A `data-K-key="V"` reveal span with no `[data-K="V"]` state-CSS rule, or a CSS `[data-K-key="V"]` reference with no span | Either half missing means the message silently never shows (or the rule is dead wiring). Add the missing half or delete the orphan; `data-otm-dynamic` opts a span out of the span→CSS direction. |
768
768
 
769
- `otm-lint` walks `.html`, `.js`, `.css`, and locale `.json` files. HTML files get the per-file rules above (template content included); `.js` files contribute `$.clone` references, `the()` write/read keys, and `data-action` selectors; `.css` files contribute attribute-selector consumption for HTML-106; locale dicts get loaded per HTML file's `<meta name="i18n">` for HTML-102/103. Default excludes: `node_modules`, `dist`, `.git`, dotdirs. Exit code is nonzero when error-level violations are found.
769
+ `otm-lint` walks `.html`, `.ejs` (cross-file rules only — per-file rules stay `.html`), `.js`, `.css`, and locale `.json` files. HTML files get the per-file rules above (template content included); `.js` files contribute `$.clone` references, `the()` write/read keys, and `data-action` selectors; `.css` files contribute attribute-selector consumption for HTML-106; locale dicts get loaded per HTML file's `<meta name="i18n">` for HTML-102/103. Default excludes: `node_modules`, `dist`, `.git`, dotdirs. Exit code is nonzero when error-level violations are found.
770
770
 
771
771
  ### Lint-rule scope
772
772
 
@@ -849,9 +849,11 @@ src/
849
849
  test/
850
850
  └── integration.test.js # cross-module integration suite
851
851
  dist/
852
- └── on_the_money.min.js # built ESM bundle (esbuild)
852
+ └── on_the_money.min.js # CDN/script-tag artifact only — npm resolves "." to src
853
853
  ```
854
854
 
855
+ **One module graph.** The npm entry (`.`) and every battery subpath resolve into the same `src/` graph, so `The`'s statics (`dictionary`, `locale`, `prefix`, `persistKeys`) are one singleton everywhere. `dist/on_the_money.min.js` exists solely for `<script type="module">` hotlinking — importing it *alongside* npm subpaths would fork the core, which is exactly the bug this arrangement removes.
856
+
855
857
  Unit tests are co-located with source: `src/core/On.test.js`, etc.
856
858
 
857
859
  ## Commands
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "on_the_money",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Opinionated, attribute-driven, standards-oriented modern framework. Native browser APIs only. See README.md for the authoring context.",
5
5
  "type": "module",
6
- "main": "dist/on_the_money.min.js",
7
- "module": "dist/on_the_money.min.js",
6
+ "main": "src/core/index.js",
7
+ "module": "src/core/index.js",
8
8
  "bin": {
9
9
  "otm-lint": "./src/linter/main.js"
10
10
  },
11
11
  "exports": {
12
- ".": "./dist/on_the_money.min.js",
13
- "./src": "./src/core/index.js",
12
+ ".": "./src/core/index.js",
14
13
  "./live": "./src/live/index.js",
15
14
  "./clipboard": "./src/clipboard/index.js",
16
15
  "./test": "./src/test/index.js",
@@ -293,9 +293,14 @@ const noRawWebsocket = {
293
293
  create(context) {
294
294
  return {
295
295
  NewExpression(node) {
296
- if (node.callee?.name === "WebSocket") {
297
- context.report({ node, messageId: "useLive" });
298
- }
296
+ if (node.callee?.name !== "WebSocket") return;
297
+ // Only the browser GLOBAL is banned. An imported or locally
298
+ // declared WebSocket (a Node ws-package client) resolves to a
299
+ // definition and is outside live()'s reach — let it pass.
300
+ const scope = context.sourceCode.getScope(node);
301
+ const ref = scope.references.find((r) => r.identifier === node.callee);
302
+ if (ref?.resolved?.defs.length) return;
303
+ context.report({ node, messageId: "useLive" });
299
304
  },
300
305
  };
301
306
  },
@@ -437,7 +437,10 @@ export default class Linter {
437
437
  );
438
438
  }
439
439
 
440
- for (const ref of spanRefs) {
440
+ // An empty span universe is evidence of blindness (markup living in
441
+ // templates the scan can't see), not of dead wiring — the css→span
442
+ // direction only fires when at least one reveal span was found.
443
+ for (const ref of spanPairs.size > 0 ? spanRefs : []) {
441
444
  if (spanPairs.has(`${ref.group} ${ref.value}`)) continue;
442
445
  Linter.#addViolation(
443
446
  violations,
package/src/linter/cli.js CHANGED
@@ -62,8 +62,19 @@ export default class Cli {
62
62
  }
63
63
 
64
64
  static async scan(dir) {
65
- const allFiles = await Cli.getFiles(dir, [".html", ".js", ".json", ".css"]);
66
- const htmlPaths = allFiles.filter((f) => f.endsWith(".html"));
65
+ const allFiles = await Cli.getFiles(dir, [
66
+ ".html",
67
+ ".ejs",
68
+ ".js",
69
+ ".json",
70
+ ".css",
71
+ ]);
72
+ // .ejs joins the markup universe for cross-file rules (reveal spans,
73
+ // slots, actions); per-file rules stay .html-only — Linter.check
74
+ // skips non-.html, so template syntax never false-positives HTML-004.
75
+ const htmlPaths = allFiles.filter(
76
+ (f) => f.endsWith(".html") || f.endsWith(".ejs"),
77
+ );
67
78
  const jsPaths = allFiles.filter((f) => f.endsWith(".js"));
68
79
  const cssPaths = allFiles.filter((f) => f.endsWith(".css"));
69
80
  let totalViolations = 0;