@effectweb/compiler 0.1.1 → 0.2.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/README.md CHANGED
@@ -4,15 +4,19 @@ Native Rust/Oxc compiler for EffectWeb snapshot JSX.
4
4
 
5
5
  ```ts
6
6
  import { defineConfig } from 'vite';
7
- import { snapshotCompiler } from '@effectweb/compiler/vite';
7
+ import { effectweb } from '@effectweb/compiler/vite';
8
8
 
9
- export default defineConfig({ plugins: [snapshotCompiler()] });
9
+ export default defineConfig({ plugins: [effectweb()] });
10
10
  ```
11
11
 
12
12
  Install `effectweb` and its required Effect version in the application. Set TypeScript `jsx` to `preserve` and `jsxImportSource` to `effectweb`.
13
13
 
14
- For direct compilation, import `compileSnapshot` from `@effectweb/compiler`; the result contains generated code, a source map, and diagnostics. The Vite plugin reports diagnostics and enables development instrumentation during serve.
14
+ For direct compilation, import `compile` from `@effectweb/compiler`; the result contains generated code, a source map, and diagnostics. The Vite plugin reports diagnostics and enables development instrumentation during serve.
15
15
 
16
16
  Requires Node.js 22.14+. Optional packages provide binaries for glibc Linux x64/arm64, macOS x64/arm64, and Windows x64. Keep optional dependencies enabled. Installation does not compile Rust. Framework contributors build from source using Rust 1.96+.
17
17
 
18
18
  See [EffectWeb](https://github.com/DerpyCrabs/EffectWeb) for authoring and development instructions.
19
+
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
+
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.
@@ -0,0 +1,23 @@
1
+ export interface Diagnostic {
2
+ readonly file: string;
3
+ readonly line: number;
4
+ readonly column: number;
5
+ readonly message: string;
6
+ readonly severity: 'error' | 'warning';
7
+ }
8
+ export interface CompilerOptions {
9
+ /** The module exporting view and slot. Defaults to effectweb. */
10
+ importSource?: string;
11
+ runtimeModule?: string;
12
+ development?: boolean;
13
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
14
+ }
15
+ export interface CompilerResult {
16
+ readonly code: string;
17
+ readonly map: string | null;
18
+ readonly diagnostics: readonly Diagnostic[];
19
+ }
20
+ /** JSX analysis and lowering run in Rust/Oxc; this boundary only transports options and results. */
21
+ export declare function compile(source: string, filename: string, options?: CompilerOptions): CompilerResult;
22
+ /** Run the same view analysis as compilation, collecting one error per invalid view. */
23
+ export declare function diagnose(source: string, filename: string, options?: Omit<CompilerOptions, 'onDiagnostic'>): readonly Diagnostic[];
@@ -0,0 +1,18 @@
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
+ export function compile(source, filename, options = {}) {
4
+ const { onDiagnostic, ...nativeOptions } = { importSource: 'effectweb', ...options };
5
+ const result = JSON.parse(nativeCompile(source, filename, JSON.stringify(nativeOptions)));
6
+ for (const diagnostic of result.diagnostics)
7
+ onDiagnostic?.(diagnostic);
8
+ return result;
9
+ }
10
+ /** Run the same view analysis as compilation, collecting one error per invalid view. */
11
+ export function diagnose(source, filename, options = {}) {
12
+ return JSON.parse(nativeCompile(source, filename, JSON.stringify({
13
+ importSource: 'effectweb',
14
+ ...options,
15
+ development: true,
16
+ diagnosticsOnly: true,
17
+ }))).diagnostics;
18
+ }
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { compileSnapshot, type SnapshotCompilerOptions, type SnapshotCompilerResult, type SnapshotDiagnostic, } from './snapshotJsx.js';
1
+ export { compile, diagnose, type CompilerOptions, type CompilerResult, type Diagnostic, } from './compile.js';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { compileSnapshot, } from './snapshotJsx.js';
1
+ export { compile, diagnose, } from './compile.js';
@@ -0,0 +1,59 @@
1
+ type Source = {
2
+ text: string;
3
+ };
4
+ type Context = {
5
+ filename: string;
6
+ sourceCode: Source;
7
+ options: readonly {
8
+ importSource?: string;
9
+ }[];
10
+ report: (diagnostic: {
11
+ loc: {
12
+ line: number;
13
+ column: number;
14
+ };
15
+ message: string;
16
+ }) => void;
17
+ };
18
+ declare const _default: {
19
+ meta: {
20
+ name: string;
21
+ };
22
+ rules: {
23
+ 'valid-view': {
24
+ meta: {
25
+ type: "problem" | "suggestion";
26
+ schema: {
27
+ type: string;
28
+ properties: {
29
+ importSource: {
30
+ type: string;
31
+ };
32
+ };
33
+ additionalProperties: boolean;
34
+ }[];
35
+ };
36
+ create(context: Context): {
37
+ Program(): void;
38
+ };
39
+ };
40
+ 'whole-model-dependency': {
41
+ meta: {
42
+ type: "problem" | "suggestion";
43
+ schema: {
44
+ type: string;
45
+ properties: {
46
+ importSource: {
47
+ type: string;
48
+ };
49
+ };
50
+ additionalProperties: boolean;
51
+ }[];
52
+ };
53
+ create(context: Context): {
54
+ Program(): void;
55
+ };
56
+ };
57
+ };
58
+ };
59
+ export default _default;
package/dist/oxlint.js ADDED
@@ -0,0 +1,62 @@
1
+ import { diagnose } from './compile.js';
2
+ const results = new WeakMap();
3
+ function rule(severity) {
4
+ return {
5
+ meta: {
6
+ type: severity === 'error' ? 'problem' : 'suggestion',
7
+ schema: [
8
+ {
9
+ type: 'object',
10
+ properties: { importSource: { type: 'string' } },
11
+ additionalProperties: false,
12
+ },
13
+ ],
14
+ },
15
+ create(context) {
16
+ return {
17
+ Program() {
18
+ if (!context.filename.endsWith('.tsx'))
19
+ return;
20
+ const importSource = context.options[0]?.importSource ?? 'effectweb';
21
+ let cached = results.get(context.sourceCode);
22
+ if (!cached || cached.text !== context.sourceCode.text) {
23
+ cached = { text: context.sourceCode.text, diagnostics: new Map() };
24
+ results.set(context.sourceCode, cached);
25
+ }
26
+ const key = `${context.filename}\0${importSource}`;
27
+ let diagnostics = cached.diagnostics.get(key);
28
+ if (!diagnostics) {
29
+ try {
30
+ diagnostics = diagnose(context.sourceCode.text, context.filename, { importSource });
31
+ }
32
+ catch (error) {
33
+ // Parser failures and unavailable native binaries must not silently pass lint.
34
+ diagnostics = [
35
+ {
36
+ file: context.filename,
37
+ line: 1,
38
+ column: 1,
39
+ severity: 'error',
40
+ message: error instanceof Error ? error.message : String(error),
41
+ },
42
+ ];
43
+ }
44
+ cached.diagnostics.set(key, diagnostics);
45
+ }
46
+ for (const diagnostic of diagnostics) {
47
+ if (diagnostic.severity !== severity)
48
+ continue;
49
+ context.report({
50
+ loc: { line: diagnostic.line, column: diagnostic.column - 1 },
51
+ message: diagnostic.message,
52
+ });
53
+ }
54
+ },
55
+ };
56
+ },
57
+ };
58
+ }
59
+ export default {
60
+ meta: { name: 'effectweb' },
61
+ rules: { 'valid-view': rule('error'), 'whole-model-dependency': rule('warning') },
62
+ };
package/dist/vite.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Plugin } from 'vite';
2
- import { type SnapshotCompilerOptions } from './snapshotJsx.js';
2
+ import { type CompilerOptions } from './compile.js';
3
3
  /** Rust/Oxc lowers snapshot JSX before Vite's TypeScript pass. */
4
- export declare function snapshotCompiler(options?: SnapshotCompilerOptions): Plugin;
4
+ export declare function effectweb(options?: CompilerOptions): Plugin;
5
+ export default effectweb;
package/dist/vite.js CHANGED
@@ -1,10 +1,13 @@
1
- import { compileSnapshot } from './snapshotJsx.js';
1
+ import { compile } from './compile.js';
2
2
  /** Rust/Oxc lowers snapshot JSX before Vite's TypeScript pass. */
3
- export function snapshotCompiler(options = {}) {
3
+ export function effectweb(options = {}) {
4
4
  let development = false;
5
5
  return {
6
- config() {
7
- return { resolve: { dedupe: ['effect'] } };
6
+ config(_config, environment) {
7
+ return {
8
+ define: { __EFFECTWEB_DEV__: JSON.stringify(environment.command === 'serve') },
9
+ resolve: { dedupe: ['effect'] },
10
+ };
8
11
  },
9
12
  configResolved(config) {
10
13
  development = config.command === 'serve';
@@ -15,7 +18,7 @@ export function snapshotCompiler(options = {}) {
15
18
  const filename = id.split('?')[0];
16
19
  if (!filename?.endsWith('.tsx'))
17
20
  return;
18
- const result = compileSnapshot(code, filename, {
21
+ const result = compile(code, filename, {
19
22
  ...options,
20
23
  development,
21
24
  onDiagnostic: options.onDiagnostic ??
@@ -25,3 +28,4 @@ export function snapshotCompiler(options = {}) {
25
28
  },
26
29
  };
27
30
  }
31
+ export default effectweb;
package/native.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  const { existsSync } = require('node:fs');
2
2
  const { join } = require('node:path');
3
3
  const { name } = require('./package.json');
4
- const local = join(__dirname, 'native', 'snapshot-compiler.node');
4
+ const local = join(__dirname, 'native', 'effectweb-compiler.node');
5
5
  let suffix;
6
6
  if (existsSync(local)) suffix = 'local';
7
7
  else if (process.platform === 'linux') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effectweb/compiler",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Native Oxc compiler and Vite plugin for effectweb",
5
5
  "homepage": "https://github.com/DerpyCrabs/EffectWeb",
6
6
  "bugs": {
@@ -28,6 +28,10 @@
28
28
  "./vite": {
29
29
  "types": "./dist/vite.d.ts",
30
30
  "import": "./dist/vite.js"
31
+ },
32
+ "./oxlint": {
33
+ "types": "./dist/oxlint.d.ts",
34
+ "import": "./dist/oxlint.js"
31
35
  }
32
36
  },
33
37
  "publishConfig": {
@@ -42,11 +46,11 @@
42
46
  }
43
47
  },
44
48
  "optionalDependencies": {
45
- "@effectweb/compiler-darwin-arm64": "0.1.1",
46
- "@effectweb/compiler-darwin-x64": "0.1.1",
47
- "@effectweb/compiler-linux-arm64-gnu": "0.1.1",
48
- "@effectweb/compiler-linux-x64-gnu": "0.1.1",
49
- "@effectweb/compiler-win32-x64-msvc": "0.1.1"
49
+ "@effectweb/compiler-darwin-arm64": "0.2.1",
50
+ "@effectweb/compiler-darwin-x64": "0.2.1",
51
+ "@effectweb/compiler-linux-arm64-gnu": "0.2.1",
52
+ "@effectweb/compiler-linux-x64-gnu": "0.2.1",
53
+ "@effectweb/compiler-win32-x64-msvc": "0.2.1"
50
54
  },
51
55
  "engines": {
52
56
  "node": ">=22.14"
@@ -1,20 +0,0 @@
1
- export interface SnapshotDiagnostic {
2
- readonly file: string;
3
- readonly line: number;
4
- readonly column: number;
5
- readonly message: string;
6
- }
7
- export interface SnapshotCompilerOptions {
8
- /** An additional public module exporting view; relative imports ending in /mvu also work. */
9
- importSource?: string;
10
- runtimeModule?: string;
11
- development?: boolean;
12
- onDiagnostic?: (diagnostic: SnapshotDiagnostic) => void;
13
- }
14
- export interface SnapshotCompilerResult {
15
- readonly code: string;
16
- readonly map: string | null;
17
- readonly diagnostics: readonly SnapshotDiagnostic[];
18
- }
19
- /** JSX analysis and lowering run in Rust/Oxc; this boundary only transports options and results. */
20
- export declare function compileSnapshot(source: string, filename: string, options?: SnapshotCompilerOptions): SnapshotCompilerResult;
@@ -1,9 +0,0 @@
1
- import { compile } from '../native.cjs';
2
- /** JSX analysis and lowering run in Rust/Oxc; this boundary only transports options and results. */
3
- export function compileSnapshot(source, filename, options = {}) {
4
- const { onDiagnostic, ...nativeOptions } = { importSource: 'effectweb', ...options };
5
- const result = JSON.parse(compile(source, filename, JSON.stringify(nativeOptions)));
6
- for (const diagnostic of result.diagnostics)
7
- onDiagnostic?.(diagnostic);
8
- return result;
9
- }