ripple 0.2.74 → 0.2.76

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.
Files changed (23) hide show
  1. package/package.json +8 -1
  2. package/src/compiler/index.js +29 -12
  3. package/src/compiler/phases/3-transform/{index.js → client/index.js} +17 -19
  4. package/src/compiler/phases/3-transform/server/index.js +95 -0
  5. package/src/runtime/internal/client/for.js +3 -4
  6. package/src/runtime/internal/server/index.js +40 -0
  7. package/src/server/index.js +1 -0
  8. package/tests/{array.test.ripple → client/array.test.ripple} +1 -1
  9. package/types/server.d.ts +0 -0
  10. /package/tests/{__snapshots__ → client/__snapshots__}/basic.test.ripple.snap +0 -0
  11. /package/tests/{__snapshots__ → client/__snapshots__}/composite.test.ripple.snap +0 -0
  12. /package/tests/{__snapshots__ → client/__snapshots__}/for.test.ripple.snap +0 -0
  13. /package/tests/{accessors-props.test.ripple → client/accessors-props.test.ripple} +0 -0
  14. /package/tests/{basic.test.ripple → client/basic.test.ripple} +0 -0
  15. /package/tests/{boundaries.test.ripple → client/boundaries.test.ripple} +0 -0
  16. /package/tests/{compiler.test.ripple → client/compiler.test.ripple} +0 -0
  17. /package/tests/{composite.test.ripple → client/composite.test.ripple} +0 -0
  18. /package/tests/{context.test.ripple → client/context.test.ripple} +0 -0
  19. /package/tests/{for.test.ripple → client/for.test.ripple} +0 -0
  20. /package/tests/{map.test.ripple → client/map.test.ripple} +0 -0
  21. /package/tests/{ref.test.ripple → client/ref.test.ripple} +0 -0
  22. /package/tests/{set.test.ripple → client/set.test.ripple} +0 -0
  23. /package/tests/{svg.test.ripple → client/svg.test.ripple} +0 -0
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.2.74",
6
+ "version": "0.2.76",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index.js",
9
9
  "main": "src/runtime/index.js",
@@ -29,6 +29,10 @@
29
29
  "default": "./src/runtime/index.js"
30
30
  },
31
31
  "./package.json": "./package.json",
32
+ "./server": {
33
+ "types": "./types/server.d.ts",
34
+ "default": "./src/server/index.js"
35
+ },
32
36
  "./compiler": {
33
37
  "types": "./types/index.d.ts",
34
38
  "require": "./compiler/index.js",
@@ -42,6 +46,9 @@
42
46
  "./internal/client": {
43
47
  "default": "./src/runtime/internal/client/index.js"
44
48
  },
49
+ "./internal/server": {
50
+ "default": "./src/runtime/internal/server/index.js"
51
+ },
45
52
  "./jsx-runtime": {
46
53
  "types": "./src/jsx-runtime.d.ts",
47
54
  "import": "./src/jsx-runtime.js",
@@ -1,25 +1,42 @@
1
+ /** @import { RawSourceMap } from 'source-map' */
2
+ /** @import { Program } from 'estree' */
3
+ /** @import { ParseError } from './phases/1-parse/index.js' */
4
+
1
5
  import { parse as parse_module } from './phases/1-parse/index.js';
2
6
  import { analyze } from './phases/2-analyze/index.js';
3
- import { transform } from './phases/3-transform/index.js';
7
+ import { transform_client } from './phases/3-transform/client/index.js';
8
+ import { transform_server } from './phases/3-transform/server/index.js';
4
9
  import { convert_source_map_to_mappings } from './phases/3-transform/segments.js';
5
10
 
11
+ /**
12
+ * @param {string} source
13
+ * @returns {{ ast: Program, errors: ParseError[] }}
14
+ */
6
15
  export function parse(source) {
7
- return parse_module(source);
16
+ return parse_module(source);
8
17
  }
9
18
 
10
- export function compile(source, filename) {
11
- const ast = parse_module(source);
12
- const analysis = analyze(ast, filename);
13
- const result = transform(filename, source, analysis, false);
19
+ /**
20
+ * @param {string} source
21
+ * @param {string} filename
22
+ * @param {{ environment?: 'client' | 'server' }} options
23
+ * @returns {{ js: { code: string, map: RawSourceMap }, css: { code: string, map: RawSourceMap } | null }}
24
+ */
25
+ export function compile(source, filename, options = {}) {
26
+ const ast = parse_module(source);
27
+ const analysis = analyze(ast, filename);
28
+ const result = options.environment === 'server'
29
+ ? transform_server(filename, source, analysis)
30
+ : transform_client(filename, source, analysis, false);
14
31
 
15
- return result;
32
+ return result;
16
33
  }
17
34
 
18
35
  export function compile_to_volar_mappings(source, filename) {
19
- // Parse and transform to get the esrap sourcemap
20
- const ast = parse_module(source);
21
- const analysis = analyze(ast, filename);
22
- const transformed = transform(filename, source, analysis, true);
36
+ // Parse and transform to get the esrap sourcemap
37
+ const ast = parse_module(source);
38
+ const analysis = analyze(ast, filename);
39
+ const transformed = transform_client(filename, source, analysis, true);
23
40
 
24
- return convert_source_map_to_mappings(transformed.js.map, source, transformed.js.code);
41
+ return convert_source_map_to_mappings(transformed.js.map, source, transformed.js.code);
25
42
  }
@@ -2,15 +2,15 @@ import { walk } from 'zimmerframe';
2
2
  import path from 'node:path';
3
3
  import { print } from 'esrap';
4
4
  import tsx from 'esrap/languages/tsx';
5
- import * as b from '../../../utils/builders.js';
5
+ import * as b from '../../../../utils/builders.js';
6
6
  import {
7
7
  IS_CONTROLLED,
8
8
  IS_INDEXED,
9
9
  TEMPLATE_FRAGMENT,
10
10
  TEMPLATE_SVG_NAMESPACE,
11
11
  TEMPLATE_MATHML_NAMESPACE,
12
- } from '../../../constants.js';
13
- import { sanitize_template_string } from '../../../utils/sanitize_template_string.js';
12
+ } from '../../../../constants.js';
13
+ import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
14
14
  import {
15
15
  build_hoisted_params,
16
16
  is_inside_component,
@@ -27,11 +27,11 @@ import {
27
27
  is_element_dom_element,
28
28
  is_top_level_await,
29
29
  is_ripple_track_call,
30
- } from '../../utils.js';
30
+ } from '../../../utils.js';
31
31
  import is_reference from 'is-reference';
32
- import { object } from '../../../utils/ast.js';
33
- import { render_stylesheets } from './stylesheet.js';
34
- import { is_event_attribute, is_passive_event } from '../../../utils/events.js';
32
+ import { object } from '../../../../utils/ast.js';
33
+ import { render_stylesheets } from '../stylesheet.js';
34
+ import { is_event_attribute, is_passive_event } from '../../../../utils/events.js';
35
35
 
36
36
  function add_ripple_internal_import(context) {
37
37
  if (!context.state.to_ts) {
@@ -65,7 +65,11 @@ function visit_function(node, context) {
65
65
  });
66
66
  }
67
67
 
68
- let body = context.visit(node.body, state);
68
+ let body = context.visit(node.body, {
69
+ ...state,
70
+ // we are new context so tracking no longer applies
71
+ metadata: { ...state.metadata, tracked: false },
72
+ });
69
73
 
70
74
  if (metadata?.tracked === true) {
71
75
  const new_body = [];
@@ -1663,7 +1667,7 @@ function transform_body(body, { visit, state }) {
1663
1667
  return [...body_state.setup, ...body_state.init, ...body_state.final];
1664
1668
  }
1665
1669
 
1666
- export function transform(filename, source, analysis, to_ts) {
1670
+ export function transform_client(filename, source, analysis, to_ts) {
1667
1671
  const state = {
1668
1672
  imports: new Set(),
1669
1673
  events: new Set(),
@@ -1700,16 +1704,10 @@ export function transform(filename, source, analysis, to_ts) {
1700
1704
  );
1701
1705
  }
1702
1706
 
1703
- const js = print(
1704
- program,
1705
- tsx({
1706
- comments: analysis.ast.comments || [],
1707
- }),
1708
- {
1709
- sourceMapContent: source,
1710
- sourceMapSource: path.basename(filename),
1711
- },
1712
- );
1707
+ const js = print(program, tsx(), {
1708
+ sourceMapContent: source,
1709
+ sourceMapSource: path.basename(filename),
1710
+ });
1713
1711
 
1714
1712
  const css = render_stylesheets(state.stylesheets);
1715
1713
 
@@ -0,0 +1,95 @@
1
+ import * as b from '../../../../utils/builders.js';
2
+ import { walk } from 'zimmerframe';
3
+ import ts from 'esrap/languages/ts';
4
+ import path from 'node:path';
5
+ import { print } from 'esrap';
6
+
7
+ function add_ripple_internal_import(context) {
8
+ if (!context.state.to_ts) {
9
+ if (!context.state.imports.has(`import * as _$_ from 'ripple/internal/server'`)) {
10
+ context.state.imports.add(`import * as _$_ from 'ripple/internal/server'`);
11
+ }
12
+ }
13
+ }
14
+
15
+ function transform_body(body, { visit, state }) {
16
+ const body_state = {
17
+ ...state,
18
+ init: [],
19
+ metadata: state.metadata,
20
+ };
21
+
22
+ return body_state.init;
23
+ }
24
+
25
+ const visitors = {
26
+ _: function set_scope(node, { next, state }) {
27
+ const scope = state.scopes.get(node);
28
+
29
+ if (scope && scope !== state.scope) {
30
+ return next({ ...state, scope });
31
+ } else {
32
+ return next();
33
+ }
34
+ },
35
+
36
+ Component(node, context) {
37
+ add_ripple_internal_import(context);
38
+
39
+ const metadata = { await: false };
40
+ const body_statements = [
41
+ b.stmt(b.call('_$_.push_component')),
42
+ ...transform_body(node.body, {
43
+ ...context,
44
+ state: { ...context.state, component: node, metadata },
45
+ }),
46
+ b.stmt(b.call('_$_.pop_component')),
47
+ ];
48
+
49
+ if (node.css !== null && node.css) {
50
+ context.state.stylesheets.push(node.css);
51
+ }
52
+
53
+ return b.function(
54
+ node.id,
55
+ node.params.length > 0 ? [b.id('__output'), node.params[0]] : [b.id('__output')],
56
+ b.block([
57
+ ...(metadata.await
58
+ ? [b.stmt(b.call('_$_.async', b.thunk(b.block(body_statements), true)))]
59
+ : body_statements),
60
+ ]),
61
+ );
62
+ },
63
+ };
64
+
65
+ export function transform_server(filename, source, analysis) {
66
+ const state = {
67
+ imports: new Set(),
68
+ init: null,
69
+ scope: analysis.scope,
70
+ scopes: analysis.scopes,
71
+ stylesheets: [],
72
+ };
73
+
74
+ const program = /** @type {ESTree.Program} */ (
75
+ walk(analysis.ast, { ...state, namespace: 'html' }, visitors)
76
+ );
77
+
78
+ for (const import_node of state.imports) {
79
+ program.body.unshift(b.stmt(b.id(import_node)));
80
+ }
81
+
82
+ const js = print(program, ts(), {
83
+ sourceMapContent: source,
84
+ sourceMapSource: path.basename(filename),
85
+ });
86
+
87
+ // TODO: extract css
88
+ const css = '';
89
+
90
+ return {
91
+ ast: program,
92
+ js,
93
+ css,
94
+ };
95
+ }
@@ -210,10 +210,9 @@ function reconcile(anchor, block, b, render_fn, is_controlled, is_indexed) {
210
210
  sources[j - b_start] = i + 1;
211
211
  if (fast_path_removal) {
212
212
  fast_path_removal = false;
213
- // while (a_start < i) {
214
- // debugger
215
- // destroy_block(a_blocks[a_start++]);
216
- // }
213
+ while (a_start < i) {
214
+ destroy_block(a_blocks[a_start++]);
215
+ }
217
216
  }
218
217
  if (pos > j) {
219
218
  moved = true;
@@ -0,0 +1,40 @@
1
+
2
+ class Output {
3
+ head = '';
4
+ body = '';
5
+ #parent = null;
6
+
7
+ constructor(parent) {
8
+ this.#parent = parent;
9
+ }
10
+
11
+ push(str) {
12
+ this.body += str;
13
+ }
14
+ }
15
+
16
+ export async function renderToString(component) {
17
+ const output = new Output(null);
18
+
19
+ if (component.async) {
20
+ await component(output, {});
21
+ } else {
22
+ component(output, {});
23
+ }
24
+
25
+ const { head, body } = output;
26
+
27
+ return { head, body };
28
+ }
29
+
30
+ export function push_component() {
31
+ debugger;
32
+ }
33
+
34
+ export function pop_component() {
35
+ debugger;
36
+ }
37
+
38
+ export async function async(fn) {
39
+ // TODO
40
+ }
@@ -0,0 +1 @@
1
+ export { renderToString } from '../runtime/internal/server/index.js';
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
2
  import { mount, flushSync, effect, untrack, TrackedArray, track } from 'ripple';
3
- import { MAX_ARRAY_LENGTH } from '../src/runtime/internal/client/constants.js';
3
+ import { MAX_ARRAY_LENGTH } from '../../src/runtime/internal/client/constants.js';
4
4
 
5
5
  describe('TrackedArray', () => {
6
6
  let container;
File without changes