@firsthandjs/compiler 0.2.0 → 0.4.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.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The build-time half of Firsthand. Nothing here ships to the browser.
4
4
 
5
- **Documentation:** [guide](https://github.com/firsthandjs/firsthand/blob/main/docs/guide/14-building.md) · [API reference](https://github.com/firsthandjs/firsthand/blob/main/docs/reference/compiler.md) · [all docs](https://github.com/firsthandjs/firsthand/blob/main/docs/README.md)
5
+ **Documentation:** [guide](https://github.com/firsthandjs/firsthand/blob/main/docs/guide/16-building.md) · [API reference](https://github.com/firsthandjs/firsthand/blob/main/docs/reference/compiler.md) · [all docs](https://github.com/firsthandjs/firsthand/blob/main/docs/README.md)
6
6
 
7
7
  ```ts
8
8
  // vite.config.ts
package/dist/api.d.ts CHANGED
@@ -7,7 +7,49 @@ export interface TransformOptions extends FirsthandPluginOptions {
7
7
  * source-map hops.
8
8
  */
9
9
  typescript?: boolean;
10
+ /** Produce a source map, so a debugger shows the JSX rather than the output. */
11
+ sourceMaps?: boolean;
10
12
  }
11
- /** Compiles one module. Used by the Vite plugin and by the compiler tests. */
13
+ /**
14
+ * A source map, in the shape every bundler expects one.
15
+ *
16
+ * Spelled out rather than typed as `object`, which is what it was: a bundler
17
+ * plugin's `transform` has to return something assignable to Rollup's
18
+ * `SourceMapInput`, and `object` is not. The mistake type-checks everywhere
19
+ * inside this repository and fails in the first application that puts the
20
+ * plugin into `vite.config.ts` — which is the one place it matters.
21
+ */
22
+ export interface SourceMap {
23
+ version: number;
24
+ mappings: string;
25
+ names: string[];
26
+ sources: string[];
27
+ sourcesContent?: string[];
28
+ sourceRoot?: string;
29
+ file?: string;
30
+ }
31
+ /** A compiled module, and the map back to what was written. */
32
+ export interface Compiled {
33
+ code: string;
34
+ /**
35
+ * A source map, when one was asked for.
36
+ *
37
+ * Without it a debugger shows the compiled output: hoisted templates and
38
+ * calls into the runtime protocol, rather than the JSX someone wrote. That
39
+ * is the difference between a framework you can step through and one you
40
+ * cannot, so the Vite plugin always asks.
41
+ */
42
+ map: SourceMap | null;
43
+ }
44
+ /**
45
+ * Compiles one module, and maps it back.
46
+ *
47
+ * The map is Babel's, which tracks the nodes this transform moves. It is
48
+ * approximate where a template was hoisted out of the markup it came from —
49
+ * there is no original position for a `<template>` that the compiler invented
50
+ * — and exact everywhere a statement survived.
51
+ */
52
+ export declare function compileModule(code: string, options?: TransformOptions): Compiled;
53
+ /** Compiles one module. Used by the compiler's own tests. */
12
54
  export declare function transform(code: string, options?: TransformOptions): string;
13
55
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAW9E"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAKlB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,QAAQ,CAqBpF;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAE9E"}
@@ -128,7 +128,12 @@ function firsthandPlugin(_api, options = {}) {
128
128
  path.replaceWith(compileNode(path, state));
129
129
  },
130
130
  CallExpression(path, state) {
131
- annotateComponent(path, state);
131
+ annotateComponent(path, state, options);
132
+ },
133
+ VariableDeclarator(path, state) {
134
+ if (options.devtools === true) {
135
+ nameCell(path, state);
136
+ }
132
137
  }
133
138
  }
134
139
  };
@@ -157,7 +162,7 @@ function runtime(state, name, source = RUNTIME) {
157
162
  }
158
163
  return t.cloneNode(local);
159
164
  }
160
- function annotateComponent(path, state) {
165
+ function annotateComponent(path, state, options) {
161
166
  const callee = path.node.callee;
162
167
  if (!t.isIdentifier(callee, { name: "component" }) || path.node.arguments.length > 2) {
163
168
  return;
@@ -172,6 +177,9 @@ function annotateComponent(path, state) {
172
177
  }
173
178
  const name = declaredName(path);
174
179
  rewritePropsDestructuring(path, name, state);
180
+ if (options.strictReactivity !== false) {
181
+ checkKeptReads(path.get("arguments.0"), name);
182
+ }
175
183
  path.node.arguments = [
176
184
  setup,
177
185
  path.node.arguments[1] ?? t.identifier("undefined"),
@@ -179,6 +187,94 @@ function annotateComponent(path, state) {
179
187
  t.stringLiteral(name)
180
188
  ];
181
189
  }
190
+ function checkKeptReads(setup, name) {
191
+ const parameter = setup.node.params[0];
192
+ const propsName = t.isIdentifier(parameter) ? parameter.name : null;
193
+ const body = setup.get("body");
194
+ if (!body.isBlockStatement()) {
195
+ return;
196
+ }
197
+ body.traverse({
198
+ Function(nested) {
199
+ nested.skip();
200
+ },
201
+ VariableDeclarator(declarator) {
202
+ const init = declarator.node.init;
203
+ if (init === null || init === void 0 || !readsOnly(init, propsName)) {
204
+ return;
205
+ }
206
+ const target = declarator.node.id;
207
+ const label = t.isIdentifier(target) ? `\`${target.name}\`` : "This value";
208
+ throw declarator.buildCodeFrameError(
209
+ `${name}: ${label} is read once, here, and then kept. A setup runs one time per instance, so this value will not change again.
210
+
211
+ Move the read into the part, handler, effect or computed that should re-read it \u2014 or wrap it in snapshot(() => \u2026) if reading once is what you meant.`
212
+ );
213
+ }
214
+ });
215
+ }
216
+ function readsOnly(node, propsName) {
217
+ let read = false;
218
+ const walk = (current) => {
219
+ if (t.isIdentifier(current) || t.isLiteral(current)) {
220
+ if (t.isTemplateLiteral(current)) {
221
+ return current.expressions.every((part) => walk(part));
222
+ }
223
+ return true;
224
+ }
225
+ if (t.isMemberExpression(current)) {
226
+ const property = current.property;
227
+ if (!current.computed && t.isIdentifier(property, { name: "value" })) {
228
+ read = true;
229
+ }
230
+ if (propsName !== null && t.isIdentifier(current.object, { name: propsName })) {
231
+ read = true;
232
+ }
233
+ return walk(current.object) && (!current.computed || walk(property));
234
+ }
235
+ if (t.isUnaryExpression(current)) {
236
+ return walk(current.argument);
237
+ }
238
+ if (t.isBinaryExpression(current) || t.isLogicalExpression(current)) {
239
+ return walk(current.left) && walk(current.right);
240
+ }
241
+ if (t.isConditionalExpression(current)) {
242
+ return walk(current.test) && walk(current.consequent) && walk(current.alternate);
243
+ }
244
+ return false;
245
+ };
246
+ return walk(node) && read;
247
+ }
248
+ var NAMED = /* @__PURE__ */ new Map([
249
+ ["signal", "signal"],
250
+ ["computed", "computed"],
251
+ ["deepSignal", "signal"]
252
+ ]);
253
+ function nameCell(path, state) {
254
+ const init = path.node.init;
255
+ const target = path.node.id;
256
+ if (!t.isCallExpression(init) || !t.isIdentifier(target) || !t.isIdentifier(init.callee)) {
257
+ return;
258
+ }
259
+ const kind = NAMED.get(init.callee.name);
260
+ if (kind === void 0) {
261
+ return;
262
+ }
263
+ const binding = path.scope.getBinding(init.callee.name);
264
+ if (binding === void 0 || !isFirsthandImport(binding)) {
265
+ return;
266
+ }
267
+ const line = init.loc.start.line;
268
+ const source = state.filename;
269
+ const cut = Math.max(source.lastIndexOf("/"), source.lastIndexOf(String.fromCharCode(92)));
270
+ const where = `${source.slice(cut + 1)}:${String(line)}`;
271
+ const call = t.callExpression(runtime(state, "label"), [
272
+ init,
273
+ t.stringLiteral(kind),
274
+ t.stringLiteral(`${target.name} (${where})`)
275
+ ]);
276
+ path.node.init = call;
277
+ }
182
278
  function isFirsthandImport(binding) {
183
279
  const parent = binding.path.parentPath;
184
280
  if (!parent.isImportDeclaration()) {
@@ -225,7 +321,7 @@ function rewritePropsDestructuring(call, name, state) {
225
321
  for (const entry of references) {
226
322
  for (const reference of entry.paths) {
227
323
  if (entry.access !== propsId) {
228
- reference.replaceWith(t.cloneNode(entry.access));
324
+ reference.replaceWith(located(t.cloneNode(entry.access), reference.node));
229
325
  }
230
326
  }
231
327
  }
@@ -498,7 +594,10 @@ function emitAttribute(attribute, build, self, state, deferred, tag) {
498
594
  build.statements.push(
499
595
  expressionStatement2(
500
596
  t.callExpression(runtime(state, "bind"), [
501
- t.arrowFunctionExpression([], dynamicAttributeCall(name, value, self, state, tag))
597
+ located(
598
+ t.arrowFunctionExpression([], dynamicAttributeCall(name, value, self, state, tag)),
599
+ value
600
+ )
502
601
  ])
503
602
  )
504
603
  );
@@ -682,7 +781,7 @@ function emitChildren(children, build, self, state) {
682
781
  t.cloneNode(self),
683
782
  // A list part is already a thunk that owns its rows; wrapping it would
684
783
  // rebuild the whole list on every evaluation.
685
- entry.kind === "list" ? entry.expression : t.arrowFunctionExpression([], entry.expression)
784
+ entry.kind === "list" ? entry.expression : thunk(entry.expression)
686
785
  ];
687
786
  if (!isLast) {
688
787
  build.html.push("<!>");
@@ -806,23 +905,50 @@ function compileChildren(children, state) {
806
905
  }
807
906
  return result;
808
907
  }
908
+ function thunk(expression) {
909
+ const arrow = t.arrowFunctionExpression([], expression);
910
+ const loc = expression.loc;
911
+ if (loc !== null && loc !== void 0) {
912
+ arrow.loc = { ...loc, end: loc.start };
913
+ expression.loc = null;
914
+ }
915
+ return arrow;
916
+ }
809
917
  function expressionStatement2(expression) {
810
- return t.expressionStatement(expression);
918
+ return located(t.expressionStatement(expression), expression);
919
+ }
920
+ function located(node, source) {
921
+ if (source == null || source.loc == null) {
922
+ return node;
923
+ }
924
+ node.loc = source.loc;
925
+ return node;
811
926
  }
812
927
 
813
928
  // packages/compiler/src/api.ts
814
929
  import { transformSync } from "@babel/core";
815
930
  import jsxSyntax from "@babel/plugin-syntax-jsx";
816
931
  import typescriptSyntax from "@babel/plugin-syntax-typescript";
817
- function transform(code, options = {}) {
932
+ function compileModule(code, options = {}) {
818
933
  const result = transformSync(code, {
819
- ...options.filename === void 0 ? {} : { filename: options.filename },
934
+ ...options.filename === void 0 ? {} : {
935
+ filename: options.filename,
936
+ // The full path, not the basename Babel would default to. A map
937
+ // whose `sources` is `comp.tsx` resolves, relative to a module
938
+ // served at `/src/comp.tsx`, to that very URL — so a debugger ends
939
+ // up with two files under one address, shows both, and puts the
940
+ // breakpoint in the wrong one.
941
+ sourceFileName: options.filename
942
+ },
820
943
  babelrc: false,
821
944
  configFile: false,
822
- sourceMaps: false,
945
+ sourceMaps: options.sourceMaps === true,
823
946
  plugins: buildPlugins(options)
824
947
  });
825
- return result.code;
948
+ return { code: result.code, map: result.map };
949
+ }
950
+ function transform(code, options = {}) {
951
+ return compileModule(code, options).code;
826
952
  }
827
953
  function buildPlugins(options) {
828
954
  const plugins = [];
@@ -830,12 +956,20 @@ function buildPlugins(options) {
830
956
  plugins.push([typescriptSyntax, { isTSX: true }]);
831
957
  }
832
958
  plugins.push(jsxSyntax);
833
- plugins.push([firsthandPlugin, { packageName: options.packageName }]);
959
+ plugins.push([
960
+ firsthandPlugin,
961
+ {
962
+ packageName: options.packageName,
963
+ strictReactivity: options.strictReactivity,
964
+ devtools: options.devtools
965
+ }
966
+ ]);
834
967
  return plugins;
835
968
  }
836
969
 
837
970
  export {
838
971
  stableId,
839
972
  firsthandPlugin,
973
+ compileModule,
840
974
  transform
841
975
  };
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  */
8
8
  export { default as firsthandPlugin } from './transform.js';
9
9
  export type { FirsthandPluginOptions } from './transform.js';
10
- export { transform } from './api.js';
10
+ export { compileModule, transform } from './api.js';
11
+ export type { Compiled, SourceMap, TransformOptions } from './api.js';
11
12
  export { stableId } from './ids.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import {
2
+ compileModule,
2
3
  firsthandPlugin,
3
4
  stableId,
4
5
  transform
5
- } from "./chunk-HHKCDDN2.js";
6
+ } from "./chunk-UYA7HB5G.js";
6
7
  export {
8
+ compileModule,
7
9
  firsthandPlugin,
8
10
  stableId,
9
11
  transform
@@ -27,6 +27,28 @@ declare module '@babel/core' {
27
27
  export interface FirsthandPluginOptions {
28
28
  /** Package name used when hashing stable component ids (ADR-0004). */
29
29
  packageName?: string;
30
+ /**
31
+ * Refuse to compile a value that is read once in a setup and then kept.
32
+ *
33
+ * **On by default.** The rule only sees declarations whose initialiser is
34
+ * nothing but a read, which is the shape that is almost always a mistake;
35
+ * anything containing a call is left alone. `false` turns it off for a
36
+ * codebase that has such a read on purpose and would rather not mark it with
37
+ * `snapshot()` — see `checkKeptReads` (ADR-0019).
38
+ */
39
+ strictReactivity?: boolean;
40
+ /**
41
+ * Name the cells a module creates, for devtools.
42
+ *
43
+ * A runtime cannot see that `const count = signal(0)` is called `count`, and
44
+ * `new Error().stack` reports a position in the *compiled* module — the
45
+ * browser does not apply source maps to `error.stack`, so the line it names
46
+ * is not the line that was written. The compiler knows both, so it says so.
47
+ *
48
+ * Off by default and turned on by the Vite plugin while serving: a
49
+ * production build emits nothing.
50
+ */
51
+ devtools?: boolean;
30
52
  }
31
53
  export default function firsthandPlugin(_api: unknown, options?: FirsthandPluginOptions): PluginObject;
32
54
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAelC,UAAU,cAAc;IACtB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,UAAU;QAClB,SAAS,EAAE,cAAc,CAAC;KAC3B;CACF;AAUD,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAgDd"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAelC,UAAU,cAAc;IACtB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,UAAU;QAClB,SAAS,EAAE,cAAc,CAAC;KAC3B;CACF;AAUD,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAsDd"}
package/dist/vite.d.ts CHANGED
@@ -1,11 +1,15 @@
1
+ import { type SourceMap } from './api.js';
1
2
  import type { FirsthandPluginOptions } from './transform.js';
2
3
  /** Minimal shape of the Vite plugin contract, so the package needs no Vite dependency. */
3
4
  export interface VitePluginLike {
4
5
  name: string;
5
6
  enforce: 'pre';
7
+ configResolved(config: {
8
+ command: string;
9
+ }): void;
6
10
  transform(code: string, id: string): {
7
11
  code: string;
8
- map: null;
12
+ map: SourceMap | null;
9
13
  } | null;
10
14
  }
11
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B,GAAG,cAAc,CAmB9E"}
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACrF;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B,GAAG,cAAc,CA0B9E"}
package/dist/vite.js CHANGED
@@ -1,25 +1,28 @@
1
1
  import {
2
- transform
3
- } from "./chunk-HHKCDDN2.js";
2
+ compileModule
3
+ } from "./chunk-UYA7HB5G.js";
4
4
 
5
5
  // packages/compiler/src/vite.ts
6
6
  function firsthand(options = {}) {
7
+ let serving = false;
7
8
  return {
8
9
  name: "firsthand",
9
10
  enforce: "pre",
11
+ configResolved(config) {
12
+ serving = config.command === "serve";
13
+ },
10
14
  transform(code, id) {
11
15
  const file = id.split("?")[0];
12
16
  if (!file.endsWith(".tsx") && !file.endsWith(".jsx")) {
13
17
  return null;
14
18
  }
15
- return {
16
- code: transform(code, {
17
- filename: file,
18
- typescript: file.endsWith(".tsx"),
19
- ...options
20
- }),
21
- map: null
22
- };
19
+ return compileModule(code, {
20
+ filename: file,
21
+ typescript: file.endsWith(".tsx"),
22
+ devtools: serving,
23
+ sourceMaps: true,
24
+ ...options
25
+ });
23
26
  }
24
27
  };
25
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firsthandjs/compiler",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Build-time TSX transform for Firsthand: static markup into templates, dynamic expressions into DOM parts.",
5
5
  "license": "MIT",
6
6
  "type": "module",