lilact 0.29.2 → 0.30.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.
Files changed (44) hide show
  1. package/dist/lilact.development.js +135 -108
  2. package/dist/lilact.development.js.map +3 -3
  3. package/dist/lilact.development.min.js +28 -28
  4. package/dist/lilact.development.min.js.map +3 -3
  5. package/dist/lilact.production.min.js +28 -28
  6. package/docs/assets/hierarchy.js +1 -1
  7. package/docs/assets/navigation.js +1 -1
  8. package/docs/assets/search.js +1 -1
  9. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  10. package/docs/classes/accessories.Suspense.html +7 -7
  11. package/docs/classes/components.Component.html +11 -11
  12. package/docs/classes/components.HTMLComponent.html +11 -11
  13. package/docs/classes/components.RootComponent.html +11 -11
  14. package/docs/functions/components.cloneComponent.html +1 -1
  15. package/docs/functions/components.createComponent.html +1 -1
  16. package/docs/functions/components.createPortal.html +1 -1
  17. package/docs/functions/components.createRoot.html +1 -1
  18. package/docs/functions/components.hotReloadRoot.html +1 -0
  19. package/docs/functions/components.memo.html +1 -1
  20. package/docs/functions/components.render.html +1 -1
  21. package/docs/functions/components.replaceComponentEntity.html +1 -0
  22. package/docs/functions/run.lazy.html +1 -1
  23. package/docs/functions/run.run.html +1 -1
  24. package/docs/functions/run.runScripts.html +1 -1
  25. package/docs/hierarchy.html +1 -1
  26. package/docs/modules/components.html +1 -1
  27. package/docs/static/index.html +1 -1
  28. package/docs/static/lilact.development.js +135 -108
  29. package/docs/static/lilact.development.js.map +3 -3
  30. package/docs/static/lilact.development.min.js +28 -28
  31. package/docs/static/lilact.development.min.js.map +3 -3
  32. package/docs/static/lilact.production.min.js +28 -28
  33. package/docs/variables/components.cloneElement.html +1 -1
  34. package/examples/index.html +1 -1
  35. package/examples/lilact.development.js +135 -108
  36. package/examples/lilact.development.js.map +3 -3
  37. package/examples/lilact.development.min.js +28 -28
  38. package/examples/lilact.development.min.js.map +3 -3
  39. package/examples/lilact.production.min.js +28 -28
  40. package/package.json +1 -1
  41. package/src/components.jsx +128 -40
  42. package/src/jsx.js +7 -32
  43. package/src/lilact.jsx +1 -1
  44. package/src/run.jsx +41 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lilact",
3
- "version": "0.29.2",
3
+ "version": "0.30.0",
4
4
  "description": "A Little React/JSX Runtime Implementation for Browser",
5
5
  "repository": "github:arashkazemi/lilact",
6
6
  "homepage": "https://arashkazemi.github.io/lilact/",
@@ -37,6 +37,53 @@ import { PropTypes } from './proptypes.jsx';
37
37
 
38
38
  const SVG_NS = "http://www.w3.org/2000/svg";
39
39
 
40
+
41
+ function getComponentEntity(entity) {
42
+ return entity?.[MEMOIZED]
43
+ ? entity.component
44
+ : entity;
45
+ }
46
+
47
+ export function replaceComponentEntity(componentCore, nextEntity) {
48
+ if (!componentCore || typeof nextEntity !== "function") {
49
+ return false;
50
+ }
51
+
52
+ const oldEntity = getComponentEntity(componentCore.entity);
53
+ const newEntity = getComponentEntity(nextEntity);
54
+
55
+ if (oldEntity === newEntity) {
56
+ return true;
57
+ }
58
+
59
+ const component = componentCore.component;
60
+
61
+ if (!component) {
62
+ return false;
63
+ }
64
+
65
+ const oldIsClass = isClass(oldEntity);
66
+ const newIsClass = isClass(newEntity);
67
+
68
+ // A function component cannot reuse a class instance, and vice versa.
69
+ if (oldIsClass !== newIsClass) {
70
+ return false;
71
+ }
72
+
73
+ if (newIsClass) {
74
+ // componentCore.state and the component instance are preserved.
75
+ // Only the class implementation changes.
76
+ Object.setPrototypeOf(component, newEntity.prototype);
77
+ } else {
78
+ // The function is invoked with the ComponentCore as `this` by apply().
79
+ component.render = newEntity;
80
+ }
81
+
82
+ componentCore.entity = newEntity;
83
+ return true;
84
+ }
85
+
86
+
40
87
  /*
41
88
  ComponentCache is for internal use. It is the heart of the JSX runtime,
42
89
  it holds child components and detects which one is being rendered or updated.
@@ -54,42 +101,47 @@ class ComponentCache
54
101
  this.owner = owner;
55
102
  }
56
103
 
57
- pick(key, construct_func)
58
- {
59
- let comp;
60
- let buck = this.current_map.get(key);
104
+ pick(key, construct_func, nextEntity) {
105
+ let componentCore;
106
+ let bucket = this.current_map.get(key);
61
107
 
62
- if(buck && buck.length>buck[IDX]) {
63
- comp = buck[buck[IDX]];
64
- buck[IDX]++;
108
+ if (bucket && bucket.length > bucket[IDX]) {
109
+ componentCore = bucket[bucket[IDX]];
110
+ bucket[IDX]++;
65
111
 
66
- buck = this.new_map.get(key);
67
- if(buck!==undefined) {
68
- buck.push( comp );
69
- }
70
- else {
71
- buck = [ comp ];
72
- this.new_map.set(key, buck);
73
- buck[IDX]=0;
112
+ const oldEntity = getComponentEntity(componentCore.entity);
113
+ const newEntity = getComponentEntity(nextEntity);
114
+
115
+ const incompatible =
116
+ typeof oldEntity === "function" &&
117
+ typeof newEntity === "function" &&
118
+ isClass(oldEntity) !== isClass(newEntity);
119
+
120
+ if (incompatible) {
121
+ componentCore = construct_func();
122
+ }
123
+ else if (newEntity) {
124
+ replaceComponentEntity(componentCore, newEntity);
74
125
  }
126
+ } else {
127
+ componentCore = construct_func();
75
128
  }
76
- else {
77
- comp = construct_func();
78
129
 
79
- buck = this.new_map.get(key);
80
- if(buck!==undefined) {
81
- buck.push( comp );
82
- }
83
- else {
84
- buck = [ comp ];
85
- this.new_map.set(key, buck);
86
- buck[IDX]=0;
87
- }
130
+ bucket = this.new_map.get(key);
88
131
 
89
- if(comp[CORE]) comp[CORE].parent ??= this.owner;
132
+ if (bucket) {
133
+ bucket.push(componentCore);
134
+ } else {
135
+ bucket = [componentCore];
136
+ this.new_map.set(key, bucket);
137
+ bucket[IDX] = 0;
90
138
  }
91
139
 
92
- return comp;
140
+ if (componentCore) {
141
+ componentCore.parent ??= this.owner;
142
+ }
143
+
144
+ return componentCore;
93
145
  }
94
146
 
95
147
  commit()
@@ -756,22 +808,36 @@ function constructFunc(core, parent) // returns {text} or component, and not com
756
808
  return comp;
757
809
  }
758
810
 
759
-
760
- function prepareCore(parent, core)
761
- {
811
+ function prepareCore(parent, core) {
762
812
  try {
763
813
  parent.cache ??= new ComponentCache(parent);
764
- core = parent.cache.pick( core[TEXT]===undefined?core?.props?.key:':text:',
765
- ()=>( (core[TEXT]!==undefined || core instanceof ComponentCore) ?
766
- core : constructFunc(core, parent)[CORE] )
767
- );
768
- return core;
769
- }
770
- catch(e) {
771
- if(core?.component?.componentDidCatch) {
814
+
815
+ const isText = core[TEXT] !== undefined;
816
+
817
+ const key = isText
818
+ ? ':text:'
819
+ : core.props?.key;
820
+
821
+ const entity =
822
+ isText || core instanceof ComponentCore
823
+ ? undefined
824
+ : core.entity;
825
+
826
+ return parent.cache.pick(
827
+ key,
828
+ () => (
829
+ isText || core instanceof ComponentCore
830
+ ? core
831
+ : constructFunc(core, parent)[CORE]
832
+ ),
833
+ entity
834
+ );
835
+ } catch (e) {
836
+ if (core?.component?.componentDidCatch) {
772
837
  core.component.componentDidCatch(e);
838
+ } else {
839
+ throw e;
773
840
  }
774
- else throw(e);
775
841
  }
776
842
  }
777
843
 
@@ -1229,6 +1295,28 @@ export function createRoot(element)
1229
1295
  }
1230
1296
  }
1231
1297
 
1298
+
1299
+
1300
+ export function hotReloadRoot(rootCore, nextEntity, props) {
1301
+ if (!rootCore || !rootCore.component) {
1302
+ throw new Error("Invalid Lilact root component.");
1303
+ }
1304
+
1305
+ const replaced = replaceComponentEntity(rootCore, nextEntity);
1306
+
1307
+ if (!replaced) {
1308
+ throw new Error(
1309
+ "Cannot hot-reload the root from a class component to a function component, or vice versa."
1310
+ );
1311
+ }
1312
+
1313
+ rootCore.apply(props === undefined ? rootCore.props : props);
1314
+
1315
+ return rootCore;
1316
+ }
1317
+
1318
+
1319
+
1232
1320
  /**
1233
1321
  * Creates a portal — a way to render children into a DOM node
1234
1322
  * that exists outside the current component hierarchy.
package/src/jsx.js CHANGED
@@ -981,9 +981,6 @@ export function transpileJSX( jsx, {
981
981
  injectTraceLabels = false,
982
982
  discardComments = false,
983
983
  produceCJS = false,
984
- referentiateImports = false,
985
- importsObject = "Lilact.scriptImportsObject", // first letter must be capital so components work as expected
986
- importsObjectVar = "LilactImports", // first letter must be capital so components work as expected
987
984
  logErrors = false,
988
985
 
989
986
  // lilact internal
@@ -1086,41 +1083,26 @@ export function transpileJSX( jsx, {
1086
1083
 
1087
1084
  const codify = (outlen, node, is_attr=false, is_xml=false)=> {
1088
1085
 
1089
- flattened_nodes.push(node);
1090
1086
 
1091
- if(typeof(node)!=='object') {
1092
- if(referentiateImports && typeof(node)==='string') {
1093
- if(meta?.imported_names.has(node)) {
1094
- let j = flattened_nodes.length-2;
1095
- while( (typeof(flattened_nodes[j])==='string' && flattened_nodes[j].trim()==='') ||
1096
- (typeof(flattened_nodes[j])==='object' && flattened_nodes[j].type==='comment') ) j--;
1087
+ flattened_nodes.push(node);
1097
1088
 
1098
- if( typeof(flattened_nodes[j])!=='string' || flattened_nodes[j]!==".") {
1099
- return importsObjectVar+"."+node;
1100
- }
1101
- }
1102
- }
1103
- return node;
1104
- }
1105
- if(node===null) return '';
1089
+ if(typeof(node)!=='object') return node;
1090
+ if(!node) return '';
1106
1091
 
1107
1092
  node.out_index = outlen;
1108
1093
 
1109
- //console.log("CODIFY", node, node.out_index);
1110
-
1111
1094
  if(node.type==='string') return jsx.substring(node.begin, node.end);
1112
- if(node.type==='import') return referentiateImports?'':node.cjs;
1095
+ if(node.type==='import') return node.cjs;
1113
1096
  if(node.type==='export') return node.cjs;
1114
1097
  if(node.type==='regex') return jsx.substring(node.begin, node.end);
1115
1098
  if(node.type==='comment') return (discardComments || is_attr)?'':jsx.substring(node.begin, node.end);
1116
1099
  if(node.type==='directive') return node.value;
1117
1100
 
1118
-
1119
1101
  if(node.type==='parenthesis') {
1120
1102
  let out = "(";
1121
1103
 
1122
1104
  if(node.out) {
1123
- if(produceCJS || referentiateImports) processImportExports(node, jsx, meta);
1105
+ if(produceCJS) processImportExports(node, jsx, meta);
1124
1106
  for(const ch of node.out) {
1125
1107
  out+=codify(outlen+out.length-1, ch);
1126
1108
  }
@@ -1132,7 +1114,7 @@ export function transpileJSX( jsx, {
1132
1114
  let out = "";
1133
1115
 
1134
1116
  if(node.out) {
1135
- if(produceCJS || referentiateImports) processImportExports(node, jsx, meta);
1117
+ if(produceCJS) processImportExports(node, jsx, meta);
1136
1118
  for(const ch of node.out) {
1137
1119
  if(is_xml && ch.type==='comment') continue;
1138
1120
  out+=codify( outlen + out.length - (is_attr?1:0), ch);
@@ -1153,10 +1135,6 @@ export function transpileJSX( jsx, {
1153
1135
 
1154
1136
  if(node.type==='xml') {
1155
1137
 
1156
- if(referentiateImports && meta?.imported_names?.has(node.tag) && node.tag[0]===node.tag[0].toUpperCase()) {
1157
- node.tag=importsObjectVar+"."+node.tag;
1158
- }
1159
-
1160
1138
  if(node.tag.length===0) {
1161
1139
  node.tag = fragment;
1162
1140
  }
@@ -1207,9 +1185,6 @@ export function transpileJSX( jsx, {
1207
1185
  if(injectTraceLabels) {
1208
1186
  out=`/*LILACTBLOCK${++blocksInfo.counter}:0,0:<EXEC>*/try{`
1209
1187
  }
1210
- if(referentiateImports) {
1211
- out+=`const ${importsObjectVar} = ${importsObject};`;
1212
- }
1213
1188
  out+=codify(out.length, json);
1214
1189
 
1215
1190
  if(injectTraceLabels) {
@@ -1225,7 +1200,7 @@ export function transpileJSX( jsx, {
1225
1200
  if(appendSourcemap) {
1226
1201
  out += inline_sm;
1227
1202
  }
1228
- //console.log(out);
1203
+ // console.log(out);
1229
1204
 
1230
1205
  return out;
1231
1206
  }
package/src/lilact.jsx CHANGED
@@ -94,7 +94,7 @@ export {transpileJSX, transpilerConfig} from "./jsx";
94
94
  export const Lilact =
95
95
  {
96
96
 
97
- VERSION: "RC.5",
97
+ VERSION: "RC.6",
98
98
 
99
99
  // Configuration
100
100
 
package/src/run.jsx CHANGED
@@ -172,11 +172,11 @@ function loadModule(path, options = {}) {
172
172
  if (loadAsync) {
173
173
  Lilact[LAZY] = false;
174
174
 
175
- if (module.request) {
176
- return module.request;
177
- }
175
+ if (module.request && !options.forceReload) {
176
+ return module.request;
177
+ }
178
178
 
179
- return loadAsyncResource(path, module);
179
+ return loadAsyncResource(path, module, options);
180
180
  }
181
181
 
182
182
  const resolved = Lilact.resolver?.(path);
@@ -244,58 +244,52 @@ export function require(path)
244
244
  }
245
245
 
246
246
 
247
- function makeImportsObject(mod)
248
- {
249
- mod.importsObject = {};
247
+ function makeImportsObject(mod, options = {}) {
248
+ mod.importsObject = {};
250
249
 
251
- for (const path in mod.meta.imports) {
252
- const imps = mod.meta.imports[path];
250
+ for (const path in mod.meta.imports) {
251
+ const imps = mod.meta.imports[path];
253
252
 
254
- /*
255
- * Do not use require() here. loadModule() resolves and loads the
256
- * dependency, then evaluates it directly through run().
257
- */
258
- const exps = loadModule(path, {
259
- requirer: mod,
260
- });
253
+ const exps = loadModule(path, {
254
+ requirer: mod,
255
+ forceReload: options.forceReload,
256
+ });
261
257
 
262
- for (const i in imps.named_imports) {
263
- if (i === '') continue;
258
+ for (const i in imps.named_imports) {
259
+ if (i === '') continue;
264
260
 
265
- const exportedName = imps.named_imports[i];
261
+ const exportedName = imps.named_imports[i];
266
262
 
267
- if (!Object.prototype.hasOwnProperty.call(exps, exportedName)) {
268
- throw new Error(
269
- `Imported module does not export any "${i}".`
270
- );
271
- }
263
+ if (!Object.prototype.hasOwnProperty.call(exps, exportedName)) {
264
+ throw new Error(
265
+ `Imported module does not export any "${i}".`
266
+ );
267
+ }
272
268
 
273
- mod.importsObject[i] = exps[exportedName];
274
- }
269
+ mod.importsObject[i] = exps[exportedName];
270
+ }
275
271
 
276
- for (const i of imps.import_defaults) {
277
- if (!Object.prototype.hasOwnProperty.call(exps, 'default')) {
278
- throw new Error(
279
- `Imported module does not export a default.`
280
- );
281
- }
272
+ for (const i of imps.import_defaults) {
273
+ if (!Object.prototype.hasOwnProperty.call(exps, 'default')) {
274
+ throw new Error(
275
+ `Imported module does not export a default.`
276
+ );
277
+ }
282
278
 
283
- mod.importsObject[i] = exps.default;
284
- }
279
+ mod.importsObject[i] = exps.default;
280
+ }
285
281
 
286
- for (const i of imps.import_stars) {
287
- mod.importsObject[i] = {...exps};
288
- }
289
- }
282
+ for (const i of imps.import_stars) {
283
+ mod.importsObject[i] = { ...exps };
284
+ }
285
+ }
290
286
  }
291
287
 
292
- // ERROR IS FOUND WHEN run IS CALLED, AND NOT REQUIRE.
293
- // REQUIRE REWRITES MODULE ANYWAY. THAT IS ALSO A PROBLEM.
294
288
 
295
289
  export function run(
296
- jsx,
297
- path = `InlineJSX-${++Lilact.eval_num}`,
298
- {} = {}
290
+ jsx,
291
+ path = `InlineJSX-${++Lilact.eval_num}`,
292
+ options = {}
299
293
  ) {
300
294
  let module = required_scripts[path];
301
295
 
@@ -320,7 +314,6 @@ export function run(
320
314
  module.exports = {};
321
315
  module.loaded = false;
322
316
  module.error = undefined;
323
- module.importsObject = undefined;
324
317
  module.meta = {};
325
318
  }
326
319
 
@@ -334,8 +327,7 @@ export function run(
334
327
  factory: "createComponent",
335
328
  appendSourcemap: true,
336
329
  injectTraceLabels: true,
337
- produceCJS: false,
338
- referentiateImports: true,
330
+ produceCJS: true,
339
331
  blocksInfo: Lilact.blocksInfo,
340
332
  });
341
333
  }
@@ -363,9 +355,6 @@ export function run(
363
355
  globalThis.createComponent = Lilact.createComponent;
364
356
  globalThis.Fragment = Lilact.Fragment;
365
357
 
366
- makeImportsObject(module);
367
-
368
- Lilact.scriptImportsObject = module.importsObject;
369
358
  const result = eval(processed);
370
359
  module.loaded = true;
371
360
 
@@ -383,7 +372,8 @@ function getOrCreateModule(path, options = {}) {
383
372
  return required_scripts[path] || createModule(path, options);
384
373
  }
385
374
 
386
- function loadAsyncResource(path, module) {
375
+ function loadAsyncResource(path, module, options = {})
376
+ {
387
377
  let source;
388
378
 
389
379
  try {
@@ -429,7 +419,7 @@ function loadAsyncResource(path, module) {
429
419
  return undefined;
430
420
  }
431
421
 
432
- return run(module.code, path, {});
422
+ return run(module.code, path, options);
433
423
  })
434
424
  .then(result => result?.default ?? result)
435
425
  .catch(error => {