@effectweb/compiler 0.2.2 → 0.3.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 TeleVecha contributors
3
+ Copyright (c) 2026 EffectWeb contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -19,4 +19,32 @@ See [EffectWeb](https://github.com/DerpyCrabs/EffectWeb) for authoring and devel
19
19
 
20
20
  For editor and CI diagnostics, add `@effectweb/compiler/oxlint` to Oxlint's `jsPlugins` and enable `effectweb/valid-view` as an error. The optional `effectweb/whole-model-dependency` rule reports coarse dependencies. Both use the compiler's Rust analysis; no second purity implementation is maintained. `diagnose` exposes the same structured view diagnostics for other tooling. Invalid syntax still throws and is handled by the host parser.
21
21
 
22
- The Vite plugin enables plain-data snapshot freezing during development and disables it for production builds. This catches accidental mutation without changing object identity or introducing proxies. See the authoring guide for the readonly type contract, opaque values, and explicit test configuration.
22
+ The runtime freezes published plain objects and arrays in every build without changing their identity or introducing proxies. Opaque mutable resources retain their own lifecycle. The Vite plugin adds source-dependency instrumentation during development; production builds omit that metadata.
23
+
24
+ Diagnostics include `code`, `category`, `severity`, source `file`/`line`/`column` (one-based UTF-16 columns), and an actionable `remedy`:
25
+
26
+ | Code | Category | Meaning and remedy |
27
+ | ------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28
+ | EW1000 | correctness | Lint could not parse/analyze the file; fix syntax or the native compiler installation. |
29
+ | EW1001 | correctness | Invalid view syntax or impure render work; the message identifies the supported form or command boundary. |
30
+ | EW1002 | correctness | A known raw object array is rendered with `.map`; use `entities(items)`, a declared `collection(identity).from(items)`, or explicit positional `sequence(items)`. |
31
+ | EW2001 | unprovable-dependency | A mutable capture is outside snapshot dependencies; pass immutable data through the model. Compilation rejects this. |
32
+ | EW2002 | unprovable-dependency | A query declares a custom `key`; remove it. Every request argument already participates in cache identity. This is a compilation error. |
33
+ | EW3001 | performance | A helper depends on the entire model; optionally pass the individual fields it uses. |
34
+
35
+ `effectweb/valid-view` reports compilation errors; `effectweb/whole-model-dependency` is optional performance advice. `effectweb/query-key` reports rejected custom query keys in `.ts` and `.tsx`. Configure these rules as follows:
36
+
37
+ ```json
38
+ {
39
+ "jsPlugins": ["@effectweb/compiler/oxlint"],
40
+ "rules": {
41
+ "effectweb/valid-view": "error",
42
+ "effectweb/query-key": "error",
43
+ "effectweb/whole-model-dependency": "warn"
44
+ }
45
+ }
46
+ ```
47
+
48
+ Identity checks use conservative same-file evidence: object array literals, typed variables or parameters, explicit `view<Model>`, local non-generic aliases/interfaces, `Array`/`ReadonlyArray`/`readonly` annotations, and common `filter`/`slice` operations. They do not run a TypeScript project checker, resolve imported types, or infer domain keys. Unknown types remain subject to runtime identity checks. Collections validate identities when constructed or shared, including unchanged-array paths; duplicate errors report both zero-based positions.
49
+
50
+ Query checks recognize imported `query` (including aliases and `effectweb/query`) and reject literal definitions containing `key`. TypeScript and the runtime also reject custom keys, including definitions assembled outside the compiler's static analysis. Pass all request data as arguments and supply services through the Effect environment.
package/dist/compile.d.ts CHANGED
@@ -4,6 +4,9 @@ export interface Diagnostic {
4
4
  readonly column: number;
5
5
  readonly message: string;
6
6
  readonly severity: 'error' | 'warning';
7
+ readonly code: string;
8
+ readonly category: 'correctness' | 'unprovable-dependency' | 'performance';
9
+ readonly remedy: string;
7
10
  }
8
11
  export interface CompilerOptions {
9
12
  /** The module exporting view and slot. Defaults to effectweb. */
@@ -17,7 +20,6 @@ export interface CompilerResult {
17
20
  readonly map: string | null;
18
21
  readonly diagnostics: readonly Diagnostic[];
19
22
  }
20
- /** JSX analysis and lowering run in Rust/Oxc; this boundary only transports options and results. */
21
23
  export declare function compile(source: string, filename: string, options?: CompilerOptions): CompilerResult;
22
24
  /** Run the same view analysis as compilation, collecting one error per invalid view. */
23
25
  export declare function diagnose(source: string, filename: string, options?: Omit<CompilerOptions, 'onDiagnostic'>): readonly Diagnostic[];
package/dist/compile.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { compile as nativeCompile } from '../native.cjs';
2
- /** JSX analysis and lowering run in Rust/Oxc; this boundary only transports options and results. */
3
2
  export function compile(source, filename, options = {}) {
4
3
  const { onDiagnostic, ...nativeOptions } = { importSource: 'effectweb', ...options };
5
4
  const result = JSON.parse(nativeCompile(source, filename, JSON.stringify(nativeOptions)));
package/dist/oxlint.d.ts CHANGED
@@ -54,6 +54,23 @@ declare const _default: {
54
54
  Program(): void;
55
55
  };
56
56
  };
57
+ 'query-key': {
58
+ meta: {
59
+ type: "problem" | "suggestion";
60
+ schema: {
61
+ type: string;
62
+ properties: {
63
+ importSource: {
64
+ type: string;
65
+ };
66
+ };
67
+ additionalProperties: boolean;
68
+ }[];
69
+ };
70
+ create(context: Context): {
71
+ Program(): void;
72
+ };
73
+ };
57
74
  };
58
75
  };
59
76
  export default _default;
package/dist/oxlint.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { diagnose } from './compile.js';
2
2
  const results = new WeakMap();
3
- function rule(severity) {
3
+ function rule(category) {
4
4
  return {
5
5
  meta: {
6
- type: severity === 'error' ? 'problem' : 'suggestion',
6
+ type: category !== 'performance' ? 'problem' : 'suggestion',
7
7
  schema: [
8
8
  {
9
9
  type: 'object',
@@ -15,7 +15,7 @@ function rule(severity) {
15
15
  create(context) {
16
16
  return {
17
17
  Program() {
18
- if (!context.filename.endsWith('.tsx'))
18
+ if (!/\.tsx?$/u.test(context.filename) || context.filename.endsWith('.d.ts'))
19
19
  return;
20
20
  const importSource = context.options[0]?.importSource ?? 'effectweb';
21
21
  let cached = results.get(context.sourceCode);
@@ -37,6 +37,9 @@ function rule(severity) {
37
37
  line: 1,
38
38
  column: 1,
39
39
  severity: 'error',
40
+ code: 'EW1000',
41
+ category: 'correctness',
42
+ remedy: 'Fix the parser error or install the native compiler binary for this platform.',
40
43
  message: error instanceof Error ? error.message : String(error),
41
44
  },
42
45
  ];
@@ -44,11 +47,16 @@ function rule(severity) {
44
47
  cached.diagnostics.set(key, diagnostics);
45
48
  }
46
49
  for (const diagnostic of diagnostics) {
47
- if (diagnostic.severity !== severity)
50
+ const selected = category === 'unprovable-dependency'
51
+ ? diagnostic.code === 'EW2002' || diagnostic.code === 'EW1000'
52
+ : category === 'errors'
53
+ ? diagnostic.severity === 'error'
54
+ : diagnostic.category === category;
55
+ if (!selected)
48
56
  continue;
49
57
  context.report({
50
58
  loc: { line: diagnostic.line, column: diagnostic.column - 1 },
51
- message: diagnostic.message,
59
+ message: `[${diagnostic.code}] ${diagnostic.message}`,
52
60
  });
53
61
  }
54
62
  },
@@ -58,5 +66,9 @@ function rule(severity) {
58
66
  }
59
67
  export default {
60
68
  meta: { name: 'effectweb' },
61
- rules: { 'valid-view': rule('error'), 'whole-model-dependency': rule('warning') },
69
+ rules: {
70
+ 'valid-view': rule('errors'),
71
+ 'whole-model-dependency': rule('performance'),
72
+ 'query-key': rule('unprovable-dependency'),
73
+ },
62
74
  };
package/dist/vite.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Plugin } from 'vite';
2
2
  import { type CompilerOptions } from './compile.js';
3
- /** Rust/Oxc lowers snapshot JSX before Vite's TypeScript pass. */
4
3
  export declare function effectweb(options?: CompilerOptions): Plugin;
5
4
  export default effectweb;
package/dist/vite.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { compile } from './compile.js';
2
- /** Rust/Oxc lowers snapshot JSX before Vite's TypeScript pass. */
3
2
  export function effectweb(options = {}) {
4
3
  let development = false;
5
4
  return {
@@ -16,13 +15,13 @@ export function effectweb(options = {}) {
16
15
  enforce: 'pre',
17
16
  transform(code, id) {
18
17
  const filename = id.split('?')[0];
19
- if (!filename?.endsWith('.tsx'))
18
+ if (!filename || !/\.tsx?$/u.test(filename) || filename.endsWith('.d.ts'))
20
19
  return;
21
20
  const result = compile(code, filename, {
22
21
  ...options,
23
22
  development,
24
23
  onDiagnostic: options.onDiagnostic ??
25
- ((diagnostic) => this.warn(`${diagnostic.file}:${diagnostic.line}:${diagnostic.column} ${diagnostic.message}`)),
24
+ ((diagnostic) => this.warn(`${diagnostic.file}:${diagnostic.line}:${diagnostic.column} [${diagnostic.code}] ${diagnostic.message}`)),
26
25
  });
27
26
  return { code: result.code, map: result.map };
28
27
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effectweb/compiler",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Native Oxc compiler and Vite plugin for effectweb",
5
5
  "homepage": "https://github.com/DerpyCrabs/EffectWeb",
6
6
  "bugs": {
@@ -46,11 +46,11 @@
46
46
  }
47
47
  },
48
48
  "optionalDependencies": {
49
- "@effectweb/compiler-darwin-arm64": "0.2.2",
50
- "@effectweb/compiler-darwin-x64": "0.2.2",
51
- "@effectweb/compiler-linux-arm64-gnu": "0.2.2",
52
- "@effectweb/compiler-linux-x64-gnu": "0.2.2",
53
- "@effectweb/compiler-win32-x64-msvc": "0.2.2"
49
+ "@effectweb/compiler-darwin-arm64": "0.3.0",
50
+ "@effectweb/compiler-darwin-x64": "0.3.0",
51
+ "@effectweb/compiler-linux-arm64-gnu": "0.3.0",
52
+ "@effectweb/compiler-linux-x64-gnu": "0.3.0",
53
+ "@effectweb/compiler-win32-x64-msvc": "0.3.0"
54
54
  },
55
55
  "engines": {
56
56
  "node": ">=22.14"