pawajs 1.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/power.js ADDED
@@ -0,0 +1,468 @@
1
+ import { createEffect } from './reactive.js';
2
+ import { render, $state, keepContext,restoreContext} from './index.js';
3
+ import { PawaComment, PawaElement } from './pawaElement.js';
4
+ import { processNode, pawaWayRemover,getComment,getEndComment, safeEval, getEvalValues, setPawaDevError, checkKeywordsExistence } from './utils.js';
5
+ import {normal_Switch} from './normal/Switch.js'
6
+ import {normal_If} from './normal/If.js'
7
+ import {normal_For} from './normal/For.js'
8
+ import {resumer} from './resumer.js'
9
+ import { normal_key } from './normal/Key.js';
10
+ export const If = (el, attr, stateContext,resume=false,notRender,stopResume) => {
11
+ el._checkStatic()
12
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
13
+ return
14
+ }
15
+ el._running = true
16
+ if(!resume){
17
+ const parent = el.parentElement
18
+ const nextSiblings = el.nextElementSibling || null
19
+ const chained=[{
20
+ exp:el.getAttribute('if'),
21
+ condition:'if',
22
+ element:el
23
+ }]
24
+ const chainMap=new Map()
25
+ chainMap.set(el.getAttribute('if'),{condition:'if',element:el})
26
+ const getChained=(nextSibling)=>{
27
+ if (nextSibling !== null) {
28
+ if (nextSibling && nextSibling.getAttribute('else') === '' || nextSibling.getAttribute('else-if')) {
29
+ // console.log(true,'it has',nextSibling.getAttribute('else'))
30
+ if (nextSibling.getAttribute('else-if')) {
31
+ chained.push({
32
+ exp:nextSibling.getAttribute('else-if'),
33
+ condition:'else-if',
34
+ element:nextSibling
35
+ })
36
+ chainMap.set(nextSibling.getAttribute('else-if'),{condition:'else-if',element:nextSibling})
37
+ getChained(nextSibling.nextElementSibling)
38
+ nextSibling.remove()
39
+ }else if (nextSibling.getAttribute('else') === '') {
40
+ chained.push({
41
+ exp:'false',
42
+ condition:'else',
43
+ element:nextSibling
44
+ })
45
+ chainMap.set('else',{condition:'else',element:nextSibling})
46
+ nextSibling.remove()
47
+ }
48
+ }
49
+ }
50
+ }
51
+ getChained(nextSiblings)
52
+ const endComment=document.createComment('end-if')
53
+ el.replaceWith(endComment)
54
+ normal_If(el,attr,stateContext,endComment,chainMap,chained)
55
+ }else{
56
+ stopResume.stop=true
57
+ let comment
58
+ let endComment
59
+ let dataComment
60
+ let id=attr.name.slice(5)
61
+ const children=[]
62
+ const setComment=(c)=>comment=c
63
+ const setEndComment=(c)=>endComment=c
64
+ getComment(el,setComment,id)
65
+ getEndComment(comment,setEndComment,id,children)
66
+ const numberIfChildren=notRender.index + children.length - 1
67
+ notRender.notRender=numberIfChildren
68
+ resumer.resume_if?.(el,attr,stateContext,{comment,endComment,id,children})
69
+
70
+ }
71
+ }
72
+ export const Switch = (el, attr, stateContext,resume=false,notRender,stopResume) => {
73
+ el._checkStatic()
74
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
75
+ return
76
+ }
77
+ el._running = true
78
+ if(!resume){
79
+ el.removeAttribute('switch')
80
+ const parent = el.parentElement
81
+ const nextSiblings = el.nextElementSibling || null
82
+ const chained=[{
83
+ exp:el.getAttribute('case'),
84
+ condition:'case',
85
+ element:el
86
+ }]
87
+ const chainMap=new Map()
88
+ chainMap.set(el.getAttribute('case'),{condition:'case',element:el})
89
+ const getChained=(nextSibling)=>{
90
+ if (nextSibling !== null) {
91
+ if (nextSibling && nextSibling.getAttribute('case') || nextSibling.getAttribute('default') === '') {
92
+ // console.log(true,'it has',nextSibling.getAttribute('else'))
93
+ if (nextSibling.getAttribute('case')) {
94
+ chained.push({
95
+ exp:nextSibling.getAttribute('case'),
96
+ condition:'case',
97
+ element:nextSibling
98
+ })
99
+ chainMap.set(nextSibling.getAttribute('case'),{condition:'case',element:nextSibling})
100
+ getChained(nextSibling.nextElementSibling)
101
+ nextSibling.remove()
102
+ }else if (nextSibling.getAttribute('default') === '') {
103
+ chained.push({
104
+ exp:'false',
105
+ condition:'default',
106
+ element:nextSibling
107
+ })
108
+ chainMap.set('default',{condition:'default',element:nextSibling})
109
+ nextSibling.remove()
110
+ }
111
+ }
112
+ }
113
+ }
114
+ getChained(nextSiblings)
115
+ const endComment=document.createComment('end-switch')
116
+ el.replaceWith(endComment)
117
+ normal_Switch(el,attr,stateContext,endComment,chainMap,chained)
118
+ }else{
119
+ stopResume.stop=true
120
+ let comment
121
+ let endComment
122
+ let dataComment
123
+ let id=attr.name.slice(5)
124
+ const children=[]
125
+ const setComment=(c)=>comment=c
126
+ const setEndComment=(c)=>endComment=c
127
+ getComment(el,setComment,id)
128
+ getEndComment(comment,setEndComment,id,children)
129
+ const numberIfChildren=notRender.index + children.length - 1
130
+ notRender.notRender=numberIfChildren
131
+ resumer.resume_switch?.(el,attr,stateContext,{comment,endComment,id,children})
132
+
133
+ }
134
+ }
135
+
136
+ export const event = (el, attr, stateContext) => {
137
+ el._checkStatic()
138
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
139
+ return
140
+ }
141
+ const splitName = attr.name.split('-')
142
+ const eventType = splitName[1]
143
+ el.removeAttribute(attr.name)
144
+ const context = el._context
145
+ const keys = Object.keys(context);
146
+ const resolvePath = (path, obj) => {
147
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
148
+ };
149
+ const values = keys.map((key) => resolvePath(key, context));
150
+ const func = new Function('e', ...keys, `
151
+ try{
152
+ ${attr.value}
153
+ }catch(error){
154
+ console.error(error.message,error.stack)
155
+ __pawaDev.setError({el:e.target,msg:error.message,stack:error.stack,directives:'on-event'})
156
+ }
157
+ `)
158
+ el.addEventListener(eventType, (e) => {
159
+ try {
160
+ func(e, ...values)
161
+ } catch (error) {
162
+ setPawaDevError({
163
+ message: `Error from on-${eventType} directive ${error.message}`,
164
+ error: error,
165
+ template: el._template
166
+ })
167
+ }
168
+ })
169
+
170
+ }
171
+
172
+ export const mountElement = (el, attr) => {
173
+ if (el._running) {
174
+ return
175
+ }
176
+ try {
177
+ const keys = Object.keys(el._context);
178
+ const resolvePath = (path, obj) => {
179
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
180
+ };
181
+ const values = keys.map((key) => resolvePath(key, el._context));
182
+ const newFunc = new Function(...keys, `${attr.value}`)
183
+ const func = () => {
184
+ newFunc(...values)
185
+ }
186
+
187
+ el._MountFunctions.push(func)
188
+ el.removeAttribute(attr.name)
189
+ } catch (error) {
190
+ setPawaDevError({
191
+ message: `Error from Mount directive ${error.message}`,
192
+ error: error,
193
+ template: el._template
194
+ })
195
+ }
196
+ }
197
+
198
+
199
+
200
+ export const unMountElement = (el, attr) => {
201
+ if (el._running) {
202
+ return
203
+ }
204
+ try {
205
+ const keys = Object.keys(el._context);
206
+ const resolvePath = (path, obj) => {
207
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
208
+ };
209
+ const values = keys.map((key) => resolvePath(key, el._context));
210
+ const func = () => {
211
+ new Function(...keys, `${attr.value}`)(...values)
212
+ }
213
+ el._unMountFunctions.push(func)
214
+ el.removeAttribute(attr.name)
215
+ } catch (error) {
216
+ setPawaDevError({
217
+ message: `Error from UnMount directive ${error.message}`,
218
+ error: error,
219
+ template: el._template
220
+ })
221
+ }
222
+ }
223
+
224
+ export const For = (el, attr, stateContext,resume=false,notRender,stopResume) => {
225
+ el._checkStatic()
226
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
227
+ return
228
+ }
229
+ el._running = true
230
+ if (!resume) {
231
+ const endComment = document.createComment(`end for`)
232
+ el.replaceWith(endComment)
233
+ normal_For(el,attr,stateContext,endComment)
234
+ }else{
235
+ stopResume.stop=true
236
+ let comment
237
+ let endComment
238
+ let dataComment
239
+ let id=attr.value
240
+ const children=[]
241
+ const setComment=(c)=>comment=c
242
+ const setEndComment=(c)=>endComment=c
243
+ getComment(el,setComment,id,'forKey')
244
+ getEndComment(comment,setEndComment,id,children,'isFor')
245
+ const numberIfChildren=notRender.index + children.length - 1
246
+ notRender.notRender=numberIfChildren
247
+ dataComment=comment.nextSibling
248
+ el.removeAttribute(attr.name)
249
+ dataComment.remove()
250
+ resumer.resume_for?.(el,attr,stateContext,{comment,endComment,id,children,dataComment})
251
+ }
252
+
253
+ }
254
+
255
+ export const ref = (el, attr) => {
256
+ el._checkStatic()
257
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
258
+ return
259
+ }
260
+ try {
261
+ const keys = Object.keys(el._context);
262
+ const resolvePath = (path, obj) => {
263
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
264
+ };
265
+
266
+ const values = keys.map((key) => resolvePath(key, el._context))
267
+ const returned=new Function('el', ...keys, `
268
+ try{
269
+ if(Array.isArray(${attr.value}.value)){
270
+ ${attr.value}.value.push(el)
271
+ }else if(typeof ${attr.value} === 'string'){
272
+ return {
273
+ value:el
274
+ }
275
+ }else{
276
+ ${attr.value}.value=el
277
+ }
278
+ }catch(e){
279
+ console.error(e.message,e.error)
280
+ __pawaDev.setError({el:el,msg:e.message,stack:e.stack,directives:'ref'})
281
+ }
282
+ `)(el, ...values)
283
+ el.removeAttribute(attr.name)
284
+ if (returned?.value) {
285
+ const name=attr.name.replace(/^["']|["']$/g, '')
286
+ el._context[name]=returned
287
+ }
288
+ } catch (error) {
289
+ setPawaDevError({
290
+ message: `Error from Ref directive ${error.message}`,
291
+ error: error,
292
+ template: el._template
293
+ })
294
+ }
295
+ }
296
+
297
+
298
+ export const States = (el, attr) => {
299
+
300
+ if (el._running) {
301
+ return
302
+ }
303
+
304
+ const name = attr.name.split('-')[1]
305
+ try {
306
+ const keys = Object.keys(el._context);
307
+ const resolvePath = (path, obj) => {
308
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
309
+ };
310
+ const values = keys.map((key) => resolvePath(key, el._context));
311
+ const val = new Function('$state', ...keys, `
312
+ try{
313
+ return $state(${attr.value})
314
+ }catch(error){
315
+ console.log(error.message,error.stack)
316
+ }
317
+ `)($state, ...values)
318
+ el._context[name] = null
319
+ el._context[name] = val
320
+ el._checkStatic()
321
+ el.removeAttribute(attr.name)
322
+ } catch (error) {
323
+ setPawaDevError({
324
+ message: `Error from State directive ${error.message}`,
325
+ error: error,
326
+ template: el._template
327
+ })
328
+ }
329
+ }
330
+
331
+
332
+ export const documentEvent = (el, attr) => {
333
+ el._checkStatic()
334
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
335
+ return
336
+ }
337
+ if (attr.name.split('-')[2]) {
338
+ return
339
+ }
340
+ const eventName = attr.name.split('-')[1]
341
+ const keys = Object.keys(el._context);
342
+ const resolvePath = (path, obj) => {
343
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
344
+ };
345
+ const func = new Function('e', ...keys, `
346
+ try{
347
+ ${attr.value}
348
+ }catch(error){
349
+ console.error(error.message,error.stack)
350
+ __pawaDev({msg:error.message,stack:error.stack,directives:'out-event'})
351
+ }`)
352
+ const values = keys.map((key) => resolvePath(key, el._context));
353
+ const functions = (e) => {
354
+ try {
355
+
356
+ func(e, ...values)
357
+ } catch (error) {
358
+ setPawaDevError({
359
+ message: `Error from out-${eventName} directive ${error.message}`,
360
+ error: error,
361
+ template: el._template
362
+ })
363
+ }
364
+ }
365
+ el.removeAttribute(attr.name)
366
+ setTimeout(() => {
367
+ document.addEventListener(eventName, functions)
368
+ }, 1000)
369
+
370
+ const unMount = () => document.removeEventListener(eventName, functions);
371
+ el._setUnMount(unMount)
372
+
373
+ }
374
+
375
+ export const exitTransition=(el,attr)=>{
376
+ if (el._running) {
377
+ return
378
+ }
379
+ el._exitAnimation=()=>{
380
+ return new Promise((resolve)=>{
381
+ requestAnimationFrame(()=>{
382
+ const animations =el.getAnimations({subtree:false})
383
+ if (animations.length === 0) {
384
+ resolve()
385
+ return
386
+ }
387
+
388
+ Promise.all(animations.map(a=>a.finished)).then(resolve).catch(resolve)
389
+ })
390
+ })
391
+ }
392
+ el.removeAttribute(attr.name)
393
+ }
394
+ export const After=(el,attr)=>{
395
+ if (el._running) return
396
+ const getTime=attr.name.match(/\[(.*?)\]/)[1]
397
+ const keys = Object.keys(el._context);
398
+ el.removeAttribute(attr.name)
399
+ const resolvePath = (path, obj) => {
400
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
401
+ };
402
+ const func = new Function( ...keys, `
403
+ try{
404
+ ${attr.value}
405
+ }catch(error){
406
+ console.error(error.message,error.stack,'at ${attr.name}')
407
+ __pawaDev({msg:error.message,stack:error.stack,directives:'${attr.name}'})
408
+ }`)
409
+ const values = keys.map((key) => resolvePath(key, el._context));
410
+ const timeout=setTimeout(() => {
411
+ func(...values)
412
+ }, getTime);
413
+ el._setUnMount(()=>{
414
+ clearTimeout(timeout)
415
+ })
416
+ }
417
+ export const Every=(el,attr)=>{
418
+ if (el._running) return
419
+ const getTime=attr.name.match(/\[(.*?)\]/)[1]
420
+ el.removeAttribute(attr.name)
421
+ const keys = Object.keys(el._context);
422
+ const resolvePath = (path, obj) => {
423
+ return path.split('.').reduce((acc, key) => acc?.[key], obj);
424
+ };
425
+ const func = new Function( ...keys, `
426
+ try{
427
+ ${attr.value}
428
+ }catch(error){
429
+ console.error(error.message,error.stack,'at ${attr.name}')
430
+ __pawaDev({msg:error.message,stack:error.stack,directives:'${attr.name}'})
431
+ }`)
432
+ const values = keys.map((key) => resolvePath(key, el._context));
433
+ const timeout=setInterval(() => {
434
+ func(...values)
435
+ }, getTime);
436
+ el._setUnMount(()=>{
437
+ clearInterval(timeout)
438
+ })
439
+ }
440
+ export const Key = (el, attr, stateContext,resume=false,notRender,stopResume) => {
441
+ el._checkStatic()
442
+ if (el._running || checkKeywordsExistence(el._staticContext,attr.value)) {
443
+ return
444
+ }
445
+ el._running = true
446
+ if(!resume){
447
+ el.removeAttribute('key')
448
+ const parent = el.parentElement
449
+ const endComment=document.createComment('end-key')
450
+ el.replaceWith(endComment)
451
+ normal_key(el,attr,stateContext,endComment)
452
+ }else{
453
+ stopResume.stop=true
454
+ let comment
455
+ let endComment
456
+ let dataComment
457
+ let id=attr.name.slice(10)
458
+ const children=[]
459
+ const setComment=(c)=>comment=c
460
+ const setEndComment=(c)=>endComment=c
461
+ getComment(el,setComment,id)
462
+ getEndComment(comment,setEndComment,id,children)
463
+ const numberIfChildren=notRender.index + children.length - 1
464
+ notRender.notRender=numberIfChildren
465
+ resumer?.resume_key?.(el,attr,stateContext,{comment,endComment,id,children})
466
+
467
+ }
468
+ }
package/reactive.js ADDED
@@ -0,0 +1,174 @@
1
+ export let activeEffect = null;
2
+ export const targetMap = new WeakMap();
3
+ export const listeners = new WeakMap();
4
+ export const disconnectedEffects = new Map();
5
+ export const templateCache = new Map()
6
+ export const componentInstances = new Map()
7
+ export const componentMount=new Map()
8
+ let queue = new Set();
9
+ let isFlushing = false;
10
+ let deleteEffect = new Set();
11
+
12
+
13
+
14
+ const scheduled = new Set();
15
+ let rafScheduled = false;
16
+ const FRAME_BUDGET = 16; // milliseconds per frame
17
+ let scheduleInProgress=false
18
+ function scheduleRenderWithTimeBudget() {
19
+ // Avoid scheduling if nothing to run or already scheduled
20
+ if (scheduled.size === 0 || rafScheduled || scheduleInProgress) return;
21
+
22
+ rafScheduled = true;
23
+ scheduleInProgress=true
24
+ requestAnimationFrame(() => {
25
+ const start = performance.now();
26
+ const processed = [];
27
+
28
+ for (const fn of scheduled) {
29
+ const cleanUp = fn();
30
+ if (typeof cleanUp === 'function') cleanUp();
31
+ processed.push(fn);
32
+ if (performance.now() - start > FRAME_BUDGET) {
33
+ break; // Defer remaining to next frame
34
+ }
35
+ }
36
+
37
+ // Cleanup only processed effects
38
+ for (const fn of processed) {
39
+ scheduled.delete(fn);
40
+ }
41
+
42
+ rafScheduled = false;
43
+ // If more effects remain, schedule next frame
44
+ if (scheduled.size > 0) {
45
+ scheduleInProgress=false
46
+ requestAnimationFrame(scheduleRenderWithTimeBudget)
47
+
48
+ }else{
49
+ scheduleInProgress=false
50
+ }
51
+ });
52
+ }
53
+
54
+ export const queueEffect = (effect,depsMap) => {
55
+ if (!queue.has(effect)) queue.add(effect);
56
+ __pawaDev.totalEffect=queue.size
57
+ if (!isFlushing) {
58
+ isFlushing = true;
59
+ Promise.resolve().then(() => {
60
+ const effects = Array.from(queue);
61
+ queue.clear();
62
+ for (const fn of effects) {
63
+ if (!deleteEffect.has(fn._id)) {
64
+ scheduled.add(fn);
65
+ }
66
+ }
67
+ // console.log(scheduleInProgress);
68
+
69
+ if (!scheduleInProgress) {
70
+ scheduleRenderWithTimeBudget();
71
+ } // Trigger the frame-based scheduler
72
+ isFlushing = false;
73
+ });
74
+ }
75
+ };
76
+
77
+ // Add parent tracking to effects
78
+ export const createEffect = (fn, el) => {
79
+ const effect = () => {
80
+ activeEffect = effect;
81
+ effect.el = el;
82
+ effect.parentEl = el?.parentElement; // Track parent for deeper checks
83
+ let cleanUp= fn();
84
+ activeEffect = null;
85
+ if (typeof cleanUp === 'function') {
86
+ return cleanUp
87
+ }
88
+ };
89
+ effect._id=crypto.randomUUID()
90
+ effect._done=false
91
+ effect._dep=null
92
+ let effectQueue = new Set();
93
+ let isBatching = false;
94
+
95
+ function batchEffect() {
96
+ if (isBatching) return;
97
+ isBatching = true;
98
+
99
+ Promise.resolve().then(() => {
100
+ effectQueue.forEach(eff => eff());
101
+ effectQueue.clear();
102
+ isBatching = false;
103
+ });
104
+ }
105
+
106
+ const runEffect = () => {
107
+ effectQueue.add(effect);
108
+ batchEffect();
109
+ };
110
+
111
+ // Run effect initially in batch
112
+ runEffect();
113
+ if (el) {
114
+ const deletes=() => {
115
+ deleteEffect.add(effect._id)
116
+ // console.log(effect._id,'delete');
117
+ // console.log(el,effect._dep);
118
+ }
119
+
120
+ el._terminateEffects.add(deletes)
121
+
122
+ }
123
+ return effect;
124
+ };
125
+
126
+
127
+
128
+ export const track = (target, key) => {
129
+
130
+ if (activeEffect) {
131
+
132
+ let depsMap = targetMap.get(target);
133
+ if (!depsMap) {
134
+ targetMap.set(target, (depsMap = new Map()));
135
+ }
136
+ let dep = depsMap.get(key);
137
+ if (!dep) {
138
+ depsMap.set(key, (dep = new Set()));
139
+ }
140
+ dep.add(activeEffect);
141
+
142
+ }
143
+ };
144
+
145
+ export const stopEffect = (effect, depsMap) => {
146
+ for (const [key, depSet] of depsMap) {
147
+ depSet.delete(effect);
148
+ if (depSet.size === 0) depsMap.delete(key);
149
+ }
150
+ deleteEffect.add(effect._id);
151
+ };
152
+
153
+
154
+ export const trigger = (target, key) => {
155
+ const depsMap = targetMap.get(target);
156
+ if (depsMap) {
157
+ const dep = depsMap.get(key);
158
+ if (dep) {
159
+ // console.log(dep);
160
+
161
+ dep.forEach(effect =>{
162
+
163
+ // console.log(effect._id);
164
+ if (!deleteEffect.has(effect._id)) {
165
+ effect._dep=depsMap
166
+ // console.log(targetMap);
167
+
168
+ queueEffect(effect,depsMap);
169
+ }
170
+ })
171
+
172
+ }
173
+ }
174
+ };
package/resumer.js ADDED
@@ -0,0 +1,21 @@
1
+ export const resumer={
2
+ resume_text:null,
3
+ resume_attribute:null,
4
+ resume_state:null,
5
+ resume_if:null,
6
+ resume_switch:null,
7
+ resume_for:null,
8
+ resume_component:null,
9
+ }
10
+
11
+
12
+ /**
13
+ * @param {resumer} resume
14
+ */
15
+ export const setResumer=(resume)=>{
16
+ for(const [key,value] of Object.entries(resume)){
17
+ if(resumer[key] === null && resumer[key] !== undefined){
18
+ resumer[key]=value
19
+ }
20
+ }
21
+ }
package/server.js ADDED
@@ -0,0 +1,21 @@
1
+ let server=typeof window === "undefined"
2
+
3
+ export const isServer=()=>server
4
+ const serverInstance={
5
+ useInsert:null,
6
+ useInnerContext:null,
7
+ setContext:null,
8
+ useContext:null,
9
+ $state:null,
10
+ accessChild:null,
11
+ useServer:null,
12
+ }
13
+ export const getServerInstance=()=>serverInstance
14
+ export const setServer=(obj={})=>{
15
+ server=true
16
+ for (const [key,value] of Object.entries(obj)) {
17
+ if (serverInstance[key] === null) {
18
+ serverInstance[key]=value
19
+ }
20
+ }
21
+ }