vaderjs 1.3.2 → 1.3.3-5b5a772ebe58

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.
@@ -1,5 +0,0 @@
1
- {
2
- "liveServer.settings.port": 5501,
3
- "js/ts.implicitProjectConfig.checkJs": true,
4
- "js/ts.implicitProjectConfig.experimentalDecorators": true
5
- }
@@ -1,5 +0,0 @@
1
- {
2
- "className":{
3
- "name":"className"
4
- }
5
- }
package/index.js DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * @file index.js
3
- * @description This is the entry point for the library. This file exports all the necessary classes and functions.
4
- * @version 1.1.5
5
- *
6
- */
7
- import Vader, { include} from './vader.js';
8
- // @ts-ignore
9
- import VaderRouter from './vaderRouter.js';
10
-
11
- export { include, VaderRouter };
12
- export default Vader;
package/jsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "allowJs": true,
4
- "checkJs": true,
5
- "target": "es6",
6
- "module": "commonjs",
7
- "alwaysStrict": true
8
-
9
- },
10
- "exclude": [
11
- "node_modules",
12
- "dist"
13
- ],
14
- "include": [
15
- "**/*.js"
16
- ]
17
- }
package/readme.md DELETED
@@ -1,262 +0,0 @@
1
- <p align="center">
2
- <a href="https://vader-js.pages.dev">
3
- <picture>
4
- <source media="(prefers-color-scheme: dark)" srcset="/icon.jpeg">
5
- <img src="logo.png" height="128">
6
- </picture>
7
- <h1 align="center">Vader.js</h1>
8
- </a>
9
- </p>
10
-
11
- # VaderJS: A Reactive Framework for SPAs
12
-
13
- [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/vaderjs.svg?style=flat)](https://www.npmjs.com/package/vaderjs)
14
-
15
- VaderJS is powerful component based reactive library for spa inspired by react.js
16
-
17
-
18
- ## Get Started
19
-
20
- 1. Install VaderJS:
21
-
22
- ```sh
23
- npm install vaderjs
24
- ```
25
-
26
- or
27
-
28
- ```html
29
- <script type="module" src="https://cdn.jsdelivr.net/npm/vaderjs@latest/index.js" ></script>
30
- <script type="module" src="https://unpkg.com/vaderjs@latest/index.js">
31
- ```
32
-
33
- 2. Import components and utilities into your project.
34
-
35
- - Heres an example import map
36
-
37
- ```html
38
- <script type="importmap">
39
- {
40
- "imports":{
41
- "vaderjs":"./dist/vader/index.js",
42
- }
43
- }
44
- </script>
45
- ```
46
-
47
- - Then you can import like this
48
-
49
- ```js
50
- import Vader, { VaderRouter, include } from 'vaderjs'
51
- ```
52
-
53
- 3. Use VaderJS features for routing, state management, auth, and more.
54
-
55
- 4. Create dynamic SPAs with enhanced user experiences.
56
-
57
- 5. Type checking / testing
58
- - Vader has jsdoc annotations built in but also allows ts using the tsconfig
59
-
60
- ```bash
61
- npm run test // validate your code
62
- ```
63
- ## Key Features
64
-
65
- ### Client Fly Rendering
66
-
67
- Vaderjs allows you to render your components & manipulate worker side vs main thread. This allows for faster page speeds and better user experience.
68
-
69
- ```javascript
70
- import Vader from "vaderjs";
71
- class Home extends Vader.Component {
72
- constructor() {
73
- super();
74
- this.cfr = true; // enable client fly rendering - this is optionals
75
- }
76
- render() {
77
- return this.html(`<div>Hello World</div>`);
78
- }
79
- }
80
- ```
81
-
82
- ### Declarative Routing
83
-
84
- ```javascript
85
- import VaderRouter from "../dist/vader/vaderRouter.js";
86
- import { Mycomponent} from "../src/pages/Home.js";
87
-
88
- const app = new VaderRouter('/');
89
-
90
- app.get("/", async (req, res)=>{
91
- res.send('#root', await new Home().render())
92
- })
93
- app.get('/docs/:page/*', async (req, res)=>{
94
- // page and asterisk route use req.params for params and req.params[0] to get the asterisk
95
- // you can get queries from the url using req.query!
96
- })
97
- const middleware = (req, res)=>{
98
- req.time = Date.now()
99
- }
100
- app.use(middleware) // use middlewares
101
-
102
- app.listen(3000, ()=>{
103
- console.log('listening on port 3000')
104
- })
105
-
106
- ```
107
-
108
-
109
- ### State Management
110
-
111
- ```javascript
112
- import Vader from "vaderjs"
113
-
114
- class MyApp extends Vader.Component{
115
- contructor(){
116
- super()
117
-
118
- }
119
-
120
- render(){
121
- const [state, setState] = this.useState('state', 0, ()=>{
122
- // this is a callback that is ran on state change!
123
- })
124
-
125
- let myfunc = this.$Function(function fn(){
126
- setState(state + 1)
127
- })
128
-
129
- this.useEffect(()=>{
130
- // this is a callback that is ran on component mount
131
- }, [])
132
-
133
- return this.html(`
134
- <p>count ${state} </p>
135
- <button onclick="${myfunc}">Change State by 1</button>
136
- `)
137
-
138
- }
139
- }
140
- ```
141
-
142
- ### Signals
143
-
144
- Signals are a way to communicate between components. Signals are similar to events in React.js. Signals are useful for global state management and component communication.
145
-
146
- - This is new as of v1.1.2
147
-
148
- ```javascript
149
-
150
- let count = this.signal('count', 0)
151
-
152
- let increment = this.$Function(function increment(){
153
- count.set(count.get() + 1)
154
- })
155
-
156
- count.subscribe( (detail)=>{
157
- console.log(detail)
158
- }, true) // true means it will run on once
159
-
160
- // call the signal
161
- count.call()
162
-
163
- count.cleanup() // cleans up the signal
164
-
165
- count.get() // returns the signal detail
166
-
167
-
168
-
169
- ```
170
- - Signals also allow you to share state between scopes
171
-
172
- ```javascript
173
- window.addEventListener('signalDispatch', (e)=>{
174
- console.log(e.detail)
175
- })
176
- ````
177
-
178
- ### Function Binding
179
-
180
- ```javascript
181
-
182
- const fn = this.$Function(function fn() {
183
- console.log("Hello World");
184
- });
185
-
186
- return html(`<button onclick="${fn}">Click Me</button>`)
187
- ```
188
-
189
- ### Authentication & Authorization
190
-
191
- ```javascript
192
- const auth = this.useAuth({
193
- rulesets: rules,
194
- user: currentUser
195
- });
196
- if (auth.can('edit')) {
197
- // Display edit button
198
- }
199
- ```
200
-
201
-
202
- ### Simplified Component Creation
203
-
204
- ```javascript
205
- import Vader from 'vaderjs';
206
-
207
- export class App extends Vader.Component{
208
- constructor(){
209
- super('App')
210
- }
211
- render(){
212
- return html`<div>Hello World</div>`
213
- }
214
- }
215
- ```
216
-
217
- ## Include views
218
-
219
- As of v1.1.0 - Vader allows you to include html files as templates
220
-
221
- ```html
222
- // views/app.vjs
223
- <body>
224
- <div>Hello World</div>
225
- <h1>{{title}}</h1>
226
- <slot id="app" />
227
- </body>
228
- ```
229
- ```html
230
- // pages/app.html
231
- <include src="views/app.vjs"/>
232
- <body>
233
- <app tittle="this is a component">
234
- <div> this is apps children! </div>
235
- </app>
236
-
237
- ```
238
-
239
- ```js
240
- // home.js
241
- import Vader from "vaderjs";
242
-
243
- class Home extends Vader.Component {
244
- constructor() {
245
- super();
246
- }
247
- render() {
248
- return this.html(include("pages/app.html"));
249
- }
250
- }
251
-
252
-
253
- ```
254
-
255
-
256
- ## License
257
-
258
- VaderJS is released under the MIT License. See the [LICENSE](https://github.com/Postr-Inc/Vader.js/blob/main/LICENSE) file for details.
259
-
260
- ## Join the Community
261
-
262
- Connect with the VaderJS community on [GitHub](https://github.com/Postr-Inc/Vader.js). Contribute, share feedback, and improve VaderJS for SPA development.
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2016",
4
- "module": "commonjs",
5
- "allowJs": true,
6
- "checkJs": true
7
-
8
- },
9
- "include": [
10
- "**/*.js"
11
- ],
12
- "exclude": [
13
- "node_modules",
14
- "dist",
15
- "website"
16
- ],
17
- "compileOnSave": true,
18
- }
package/vader-min.js DELETED
@@ -1 +0,0 @@
1
- let dom=[],states={},worker=new Worker(new URL("./worker.js",import.meta.url));function markdown(t){let e=t.match(/(#+)(.*)/g);return e&&e.forEach((e=>{if(e.includes("/")||e.includes("<")||e.includes(">"))return;let s=e.split("#").length;t=t.replace(e,`<h${s} class="markdown_heading">${e.replace(/#/g,"")}</h${s}>`)})),t=(t=(t=(t=(t=(t=(t=t.replace(/\*\*(.*?)\*\*/g,((t,e)=>`<b class="markdown_bold">${e}</b>`))).replace(/\*(.*?)\*/g,((t,e)=>`<i class="markdown_italic">${e}</i>`))).replace(/`(.*?)`/g,((t,e)=>`<code>${e}</code>`))).replace(/\[([^\]]+)\]\(([^)]+)\)/g,((t,e,s)=>`<a class="markdown_link" href="${s}">${e}</a>`))).replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((t,e,s)=>`<img class="markdown_image" src="${s}" alt="${e}" />`))).split("\n").map(((t,e,s)=>t.match(/^\s*-\s+(.*?)$/gm)?0!==e&&s[e-1].match(/^\s*-\s+(.*?)$/gm)?e!==s.length-1&&s[e+1].match(/^\s*-\s+(.*?)$/gm)?`<li>${t.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:`<li>${t.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`:`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${t.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:t)).join("\n")).split("\n").map(((t,e,s)=>t.match(/^\s*\d+\.\s+(.*?)$/gm)?0!==e&&s[e-1].match(/^\s*\d+\.\s+(.*?)$/gm)?e!==s.length-1&&s[e+1].match(/^\s*\d+\.\s+(.*?)$/gm)?`<li>${t.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:`<li>${t.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`:`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${t.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:t)).join("\n")}export const useRef=t=>{const e=document.querySelector(`[ref="${t}"]`);return{current:e,update:t=>{const s=(new DOMParser).parseFromString(t,"text/html").body.firstChild;if(e){!s.isEqualNode(e)&&e.parentNode.replaceChild(s,e)}}}};let components=[];export class Component{constructor(){this.states={},this.name=this.constructor.name,this.executedEffects={},this.storedProps={},this.componentMounted=!1,this.hasMounted=!1,this.$_signal_subscribers=[],this.$_signal_subscribers_ran=[],this.effects={},this.$_useStore_subscribers=[],this.init(),this.Componentcontent=null,this.$_signal_dispatch_event=new CustomEvent("SignalDispatch",{detail:{hasUpdated:!1,state:null}}),this.$_signal_dispatch_cleanup_event=new CustomEvent("Signal_Cleanup_Dispatch",{detail:{state:null,lastState:null}}),this.snapshots=[],this.dom=[],this.cfr=!1}adapter(t){}init(){this.registerComponent()}registerComponent(){components.push(this)}setState(t,e){this.states[t]=e,this.updateComponent()}unmount(){this.componentMounted=!1,this.componentWillUnmount(),document.querySelector(`[data-component="${this.name}"]`).remove(),document.querySelector(`[data-component="${this.name}"]`)||(components=components.filter((t=>t.name!==this.name)))}componentUpdate(t,e,s){}componentDidMount(){}componentWillUnmount(){}signal=(t,e)=>{let s=!1,[n,r]=this.useState(t,e,(()=>{if(this.$_signal_subscribers.length>0){for(var t=0;t<this.$_signal_subscribers.length;t++)if(!s){if(this.$_signal_subscribers[t].runonce&&this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[t]))break;return this.$_signal_subscribers[t].function(n),void this.$_signal_subscribers_ran.push(this.$_signal_subscribers[t])}}else this.$_signal_dispatch_event.detail.hasUpdated=!0,this.$_signal_dispatch_event.detail.state=n,window.dispatchEvent(this.$_signal_dispatch_event)}));return this.$_signal_subscribe=(t,e)=>(this.$_signal_subscribers.push({function:t,runonce:e}),t),this.$_signal_cleanup=t=>{this.lastState=n,this.$_signal_subscribers=this.$_signal_subscribers.filter((e=>e.function!==t)),this.$_signal_dispatch_cleanup_event.detail.state=this.states,this.$_signal_dispatch_cleanup_event.detail.lastState=this.lastState,window.dispatchEvent(this.$_signal_dispatch_event)},this.$_signal_dispatch=()=>{for(var t=0;t<this.$_signal_subscribers.length&&(!this.$_signal_subscribers[t].runonce||!this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[t]));t++)this.$_signal_subscribers[t].function(n),this.$_signal_subscribers_ran.push(this.$_signal_subscribers[t])},this.$_signal_get=()=>n,this.$_signal_call=()=>{s=!0,this.$_signal_dispatch()},this.$_signal_set=t=>{r(t)},{subscribe:this.$_signal_subscribe,cleanup:this.$_signal_cleanup,dispatch:this.$_signal_dispatch,call:this.$_signal_call,set:this.$_signal_set,get:this.$_signal_get}};useAuth(t){let e=t.rulesets;if(!e)throw new Error("No rulesets provided");let s=t.user,n={can:t=>{let n=!1;return e.forEach((e=>{e.action===t&&e.condition(s)&&(n=!0)})),n},hasRole:t=>s.role&&s.role.includes(t),canWithRole:(t,e)=>n.can(t)&&n.hasRole(e),assignRule:t=>{e.some((e=>e.action===t.action))||e.push(t)},revokeRule:t=>{e=e.filter((e=>e.action!==t))},canAnyOf:t=>t.some((t=>n.can(t))),canAllOf:t=>t.every((t=>n.can(t))),canGroup:(t,e="any")=>"any"===e?n.canAnyOf(t):n.canAllOf(t)};return n}useReducer(t,e,s){return this.states[t]||(this.states[t]=s),[this.states[t],s=>{this.states[t]=e(this.states[t],s),this.updateComponent()}]}runEffects(){Object.keys(this.effects).forEach((t=>{this.effects[t].forEach((t=>{this.executedEffects[t]||(t(),this.executedEffects[t]=!0)}))}))}useSyncStore(t,e){let[s,n]=this.useState(t,e||localStorage.getItem(`$_vader_${t}`,(e=>{localStorage.setItem(`$_vader_${t}`,JSON.stringify(e)),this.$_useStore_subscribers.forEach((t=>{t(e)}))}))||{});return{getField:t=>s[t],setField:(t,e)=>{const r={...s,[t]:e};n(r)},subscribe:t=>this.$_useStore_subscribers.push(t),clear:t=>{let e=s;delete e[t],n(e)}}}useState(t,e,s=null){return this.states[t]||(this.states[t]=e),[this.states[t],e=>{this.states[t]=e,this.updateComponent(),"function"==typeof s&&s()}]}useRef(t){const e=this.dom[t];return{current:()=>e,update:t=>{const s=(new DOMParser).parseFromString(t,"text/html").body.firstChild;if(e){!s.isEqualNode(e)&&e.parentNode.replaceChild(s,e)}}}}useEffect(t,e){return this.effects[this.name]||(this.effects[this.name]=[]),this.effects[this.name].push(t),e.length>0?e.forEach((t=>{if(t.set)throw new Error("signal found, do not use effect and signals at the same time - signals are more efficient")})):this.hasMounted||(t(),this.hasMounted=!0),{cleanup:()=>{this.effects[this.name]=this.effects[this.name].filter((e=>e!==t))}}}$Function(t){let e=t.name;return e||(e="anonymous"+Math.floor(1e17*Math.random())),window[e]=t,`window.${e}()`}updateComponent(){const t=document.createDocumentFragment();Object.keys(components).forEach((async e=>{const{name:s}=components[e];let n=document.querySelector(`[data-component="${s}"]`),r={name:s,time:(new Date).getTime(),prev_state:this.states,prev_props:this.storedProps,content:n.innerHTML};if(!n)return;const i=await new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","props","render","return `"+await this.render()+"`;")(this.useState,this.useEffect,this.useAuth,this.useReducer,this.useSyncStore,this.signal,this.render);if(i!==n.innerHTML){if(this.snapshots.length>0){this.snapshots[this.snapshots.length-1]!==r&&this.snapshots.push(r)}else this.snapshots.push(r);this.componentUpdate(r.prev_state,r.prev_props,r.content),t.appendChild(document.createRange().createContextualFragment(i)),n.innerHTML="",n.appendChild(t),this.runEffects()}}))}validateClassName(t){return/^[a-zA-Z0-9-_]+$/.test(t)}parseHTML(t){const e=(new DOMParser).parseFromString(t,"text/html");return e.documentElement.querySelectorAll("*").forEach((t=>{if("IMG"===t.nodeName){if(!t.hasAttribute("alt")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${t.outerHTML} missing alt attribute`);if(t.hasAttribute("alt")&&t.getAttribute("alt").length<1&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${t.outerHTML} alt attribute cannot be empty`);if(t.hasAttribute("src")&&!t.getAttribute("src")?.includes("http")||!t.getAttribute("src")?.includes("https")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e")){let e=t.getAttribute("src");t.setAttribute("aria-hidden","true"),t.setAttribute("hidden","true");let s=window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/"+t.getAttribute("src"),n=new Image;n.src=s,n.onerror=()=>{throw t.setAttribute("src",e),new Error(`Image: ${t.outerHTML} not found`)},t.setAttribute("src",s),n.onload=()=>{document.querySelectorAll(`img[src="${s}"]`).forEach((t=>{t.setAttribute("src",s),t.removeAttribute("aria-hidden"),t.removeAttribute("hidden")}))}}}else{if(t.hasAttribute("ref")&&(e[t.getAttribute("ref")]=t),"MARKDOWN"===t.nodeName&&(t.innerHTML=markdown(t.innerHTML.replace(/\\n/g,"\n").trim())),t.hasAttribute("class")){if(!document.documentElement.outerHTML.includes("\x3c!-- #vader-allow_class --\x3e"))throw console.warn("you can disable class errors using, \x3c!-- #vader-allow_class --\x3e"),new Error("class attribute is not allowed, please use className instead")}else t.hasAttribute("className")&&(t.setAttribute("class",t.getAttribute("className")),t.removeAttribute("className"));t.hasAttribute("href")&&t.getAttribute("href").startsWith("/")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")&&t.setAttribute("href",`#/${t.getAttribute("href").replace("/","")}`),!t.hasAttribute("src")||t.getAttribute("src").includes("http")||t.getAttribute("src").includes("https")||document.documentElement.outerHTML.includes("\x3c!-- #vader-disable_relative-paths --\x3e")||t.setAttribute("src",`./public/${t.getAttribute("src")}`)}})),t=e.body.innerHTML,this.Componentcontent=t,t.includes("<div data-component")||(t=`<div data-component="${this.name}">${t}</div>`),markdown(t.replace(/\\n/g,"\n").trim())}html(t,...e){let s=setInterval((()=>{document.querySelector(`[data-component="${this.name}"]`)&&(clearInterval(s),this.componentMounted=!0,document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((t=>{t.hasAttribute("ref")&&(this.dom[t.getAttribute("ref")]=t)})),this.componentDidMount())}),100),n=document.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("data-component-script",this.name);this.dom;if(this.cfr){worker.postMessage({strings:t,args:e,location:window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/",name:this.name});let s=new Promise(((t,e)=>{worker.onmessage=e=>{if(e.data.error)throw new Error(e.data.error);this.dom;let s=e.data.js,n=e.data.template;const r=this.useState.bind(this),i=this.useEffect.bind(this),a=this.useReducer.bind(this),o=this.useAuth.bind(this),c=this.useSyncStore.bind(this),l=this.signal.bind(this),u=this.$Function.bind(this);let h=this.states;const d=this.useRef.bind(this);new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","dom","render","states","useRef",s)(r,i,o,a,c,l,u,this.dom,this.render,this.states,d),t(new Function("useRef","states","return`"+n+"`")(d,h))},worker.onerror=t=>{e(t)}}));return s}{let s="";for(let n=0;n<t.length;n++)s+=t[n],n<e.length&&(s+=e[n]);return s=new Function("useRef",`return \`${s}\``)(useRef),s.trim().startsWith("<body>")||console.warn("You should wrap your html in a body tag, vader may not grab all html!"),this.parseHTML(s)}}async render(t){}}const Vader={Component:Component,useRef:useRef};export const component=()=>new Component;export const rf=(t,e)=>{window[t]=e};let cache={};async function handletemplate(t){let e=(new DOMParser).parseFromString(t,"text/html"),s=e.documentElement.querySelectorAll("*");if(s.length>0)for(var n=0;n<s.length;n++)if("INCLUDE"===s[n].nodeName){if(!s[n].getAttribute("src")||""===s[n].getAttribute("src"))throw new Error("Include tag must have src attribute");let t=s[n].getAttribute("src")?.split("/").pop()?.split(".")[0],r=await include(s[n].getAttribute("src"));r=r.replace(/`/g,"\\`"),cache[s[n].getAttribute("src")]=r,r=new Function(`return \`${r}\`;`)();let i=(new DOMParser).parseFromString(r,"text/html");i.querySelectorAll("include").forEach((t=>{t.remove()})),e.querySelectorAll(t).forEach((t=>{if(t.attributes.length>0)for(var s=0;s<t.attributes.length;s++)i.body.outerHTML=i.body.outerHTML.replaceAll(`{{${t.attributes[s].name}}}`,t.attributes[s].value);if(t.children.length>0&&i.body.querySelector("slot"))for(s=0;s<t.children.length;s++){i.body.querySelectorAll("slot").forEach((e=>{let s=e.getAttribute("id");console.log(s),(t.hasAttribute("key")&&t.getAttribute("key")===s||!t.hasAttribute("key")&&t.nodeName===s)&&(e.outerHTML=`<div>${t.innerHTML}</div>`)}))}e.body.querySelectorAll("include").forEach((t=>{t.remove()})),e.body.outerHTML=e.body.outerHTML.replace(/`/g,"\\`"),e.body.outerHTML=e.body.outerHTML.replace(t.outerHTML,new Function(`return \`${i.body.outerHTML}\`;`)())}))}return e.body.outerHTML=e.body.outerHTML.replace(/`/g,"\\`"),t=new Function(`return \`${e.body.outerHTML}\`;`)()}export const include=async t=>(!t.startsWith("/")||t.includes("/src/")||document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")||(t="/src/"+t),cache[t]?await handletemplate(new Function(`return \`${cache[t]}\`;`)()):fetch(`./${t}`).then((e=>{if(404===e.status)throw new Error(`No file found at ${t}`);return e.text()})).then((async e=>(cache[t]=e,e=await handletemplate(new Function(`return \`${e}\`;`)())))));export default Vader;
package/vaderRouter.js DELETED
@@ -1,231 +0,0 @@
1
-
2
- /**
3
- * @class VaderRouter
4
- * @description - creates an instance of Vader Express Router
5
- *
6
- * @param {String} path
7
- * @param {Function} handler
8
- * @param {object} req request object
9
- * @param {object} res response object
10
- * @returns {Object} Express
11
- *
12
- */
13
- class VaderRouter{
14
- /**
15
- * @constructor
16
- * @param {*} basePath
17
- *
18
- */
19
- constructor(basePath) {
20
- this.routes = [];
21
- this.middlewares = [];
22
- this.errorMiddlewares = [];
23
- this.listeners = [];
24
-
25
- this.basePath = basePath;
26
- }
27
-
28
- /**
29
- * @method get
30
- * @param {String} path
31
- * @param {Function} handler
32
- * @description This method is used to register a get route
33
- * @returns {void}
34
- * @memberof Express
35
- */
36
- get(path, handler) {
37
-
38
- this.routes.push({
39
- path,
40
- handler,
41
- method: 'get',
42
- });
43
- }
44
- /**
45
- * @method use
46
- * @description This method allows you to use middlewares
47
- * @param {Function} middleware
48
- */
49
-
50
- use(/* path, */ middleware) {
51
- this.middlewares.push(middleware);
52
- }
53
-
54
- /**
55
- * @method listen
56
- * @param {*} port - unique id for the listener
57
- * @param {Function} callback - callback function
58
- * @description This method is used to start listening to the routes
59
- * @returns {void}
60
- *
61
- */
62
-
63
- listen(port, callback) {
64
- if(!port){
65
- port = Math.random().toString(36).substring(7);
66
- }
67
- this.listeners.push(port);
68
- callback();
69
- if (this.listeners.length === 1) {
70
- this.handleRoute(window.location.hash);
71
- }else{
72
- this.listeners.pop();
73
- }
74
- if (callback) {
75
- callback();
76
- }
77
- window.onhashchange = () => {
78
- this.handleRoute(window.location.hash);
79
- }
80
- }
81
- /**
82
- * @method extractParams
83
- * @description This method is used to extract parameters from the route path
84
- * @param {*} routePath
85
- * @param {*} hash
86
- * @returns {Object} params
87
- * @memberof Express
88
- */
89
-
90
- extractParams(routePath, hash) {
91
- const routeParts = routePath.split('/');
92
- const hashParts = hash.split('/');
93
- const params = {};
94
- routeParts.forEach((part, index) => {
95
- if (part.startsWith(':')) {
96
- const paramName = part.slice(1);
97
- params[paramName] = hashParts[index];
98
- }else if(part.startsWith('*')){
99
- // remove queries from this par
100
- params[0] = hashParts.slice(index).join('/').split('?')[0];
101
- }
102
- });
103
- return params;
104
- }
105
- extractQueryParams(hash){
106
-
107
- const queryParams = hash.split('?')[1];
108
- if(!queryParams){
109
- return {};
110
- }
111
- const params = {};
112
- queryParams.split('&').forEach((param)=>{
113
- const [key, value] = param.split('=');
114
- params[key] = value;
115
- })
116
- return params;
117
- }
118
-
119
- /**
120
- * @method handleRoute
121
- * @param {String} hash
122
- * @description This method is used to handle the route
123
- */
124
-
125
- handleRoute(hash) {
126
- hash = hash.slice(1);
127
- let status = 200;
128
- let route = this.routes.find((route) => {
129
-
130
- if (route.path === hash) {
131
- return true;
132
- }
133
- const routePathParts = route.path.split('/');
134
- const hashParts = hash.split('/');
135
- if (routePathParts.length !== hashParts.length) {
136
- return false;
137
- }else if(routePathParts[routePathParts.length-1].startsWith('*')){
138
- return true;
139
- }
140
- const params = this.extractParams( route.path, hash);
141
- return Object.keys(params).length > 0;
142
- });
143
-
144
- if (!route) {
145
- route = this.routes.find((route) => {
146
-
147
- if(route.path === '/404'){
148
- return true;
149
- }else{
150
- window.location.hash = this.basePath
151
- }
152
- });
153
-
154
- route ? status = 200 :
155
-
156
- status = 404;
157
- }
158
-
159
-
160
- const queryParams = this.extractQueryParams(hash);
161
- const params = route && route.path ? this.extractParams(route.path, hash) : {};
162
- const req = {
163
- headers: {},
164
- params: params,
165
- query: queryParams,
166
- path: hash,
167
- method: route ? route.method : 'get',
168
- };
169
-
170
- // @ts-ignore
171
- window.$CURRENT_URL = req.path
172
-
173
- // @ts-ignore
174
- window.$FULL_URL = window.location.href.replace('#', '')
175
-
176
- const res = {
177
- status: status,
178
- /**
179
- * @method log
180
- * @param {String} type
181
- * @description This method is used to log the request and response
182
- */
183
- log: (type) => {
184
- if(type === undefined){
185
- console.log(`${req.path} ${req.method} ${res.status} ${req.timestamp}`);
186
- }else{
187
- console.table({
188
- 'Request Path': req.path,
189
- 'Request Method': route.method,
190
- 'Response Status': res.status,
191
- 'Request Timestamp': req.timestamp,
192
- });
193
- }
194
- },
195
- send: (selector, data) => {
196
- if(typeof selector === 'string'){
197
- // @ts-ignore
198
- document.querySelector(selector).innerHTML = data;
199
- }else if(typeof selector === 'number'){
200
- res.status = selector;
201
- }else if(typeof selector === 'object'){
202
- res.status = selector.status;
203
- }
204
- },
205
- json: (selector, data) => {
206
-
207
- if(typeof selector === 'string'){
208
- // @ts-ignore
209
- let obj = document.createElement('object');
210
- // data url
211
- obj.data = URL.createObjectURL(new Blob([JSON.stringify(data)], {type: 'application/json'}));
212
- // @ts-ignore
213
- document.querySelector(selector).appendChild(obj);
214
- }else{
215
- throw new Error('Selector must be a string');
216
- }
217
- },
218
- };
219
- this.middlewares.forEach((middleware) => {
220
- middleware(req, res);
221
- });
222
-
223
- route ? route.handler(req, res) : null;
224
-
225
- }
226
-
227
- }
228
-
229
- export default VaderRouter;
230
-
231
-
package/worker-min.js DELETED
@@ -1 +0,0 @@
1
- onmessage=e=>{let a=Date.now(),l=e.data.strings,s=e.data.args,t="",r=e.data.location.split("/").slice(0,-1).join("/"),c="";for(let e=0;e<l.length;e++)c+=l[e],e<s.length&&(c+=s[e]);let o=c.match(/--([^>]*)--/gs);if(o)for(;o.length;){let e=o.pop();console.log(e),c=c.replace(e,"")}if(c=c.replace(/(#+)(.*)/g,((e,a,l)=>{if(console.log(e),e.includes("<")&&e.includes(">"))return e;{let e=a.length;return`<h ${e} class="markdown_heading">${l}</h${e}>`}})),c=c.replace(/\*\*(.*?)\*\*/g,((e,a)=>`<b class="markdown_bold">${a}</b>`)),c=c.replace(/\*(.*?)\*/g,((e,a)=>`<i class="markdown_italic">${a}</i>`)),c=c.replace(/`(.*?)`/g,((e,a)=>`<code>${a}</code>`)),c=c.replace(/\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<a class="markdown_link" href="${l}">${a}</a>`)),c=c.replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<img class="markdown_image" src="${l}" alt="${a}" />`)),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*-\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*-\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*-\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`):c.replace(e,`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`))})),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*\d+\.\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*\d+\.\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*\d+\.\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`):c.replace(e,`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`))})),c=c.replace(/^\s*-\s+(.*?)$/gm,((e,a)=>`<li class="markdown_list_item">${a}</li>`)),c=c.replace(/^\s*---\s*$/gm,'<hr class="markdown_horizontal" />'),c=c.replace(/^\s*> (.*)$/gm,((e,a)=>`<blockquote class="markdown_blockquote">${a}</blockquote>`)),c=c.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm,((e,a,l)=>{const s=a.split("|").slice(1,-1),t=l.split("|").slice(1,-1);let r='<table class="markdown_table">';return r+='<thead class="markdown_table_head"><tr class="markdown_table_row">',s.forEach((e=>{r+=`<th class="markdown_table_header_cell">${e}</th>`})),r+='</tr></thead><tbody class="markdown_table_body"><tr class="markdown_table_row">',t.forEach((e=>{r+=`<td class="markdown_table_body_cell">${e}</td>`})),r+="</tr></tbody></table>",r})),!c.includes("<body>"))throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${c}`);c=c.replace(/classname/g,"class");let i=c.match(/<img([^>]*)>/g);if(i)for(let a=0;a<i.length;a++){let l=i[a],s=l.match(/src="([^"]*)"/),t=l.match(/alt="([^"]*)"/);if(s)if(s[1].includes("http")||c.includes("\x3c!-- #vader-disable_relative-paths --\x3e")){if(!s[1].includes("http")&&s[1].startsWith(".")&&!c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use absolute paths since relative paths are not disabled in ${e.data.file}. Use relative paths instead. \n\n${s[1]}`)}else c=c.replace(s[1],`${r}/${s[1]}`);if(!t&&!c.includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new Error(`Vader Error: You must include an alt attribute in the image tag \n\n${l} of class ${e.data.name}. `);caches.match(`${r}/${s[1]}`)?console.log("already cached",caches.match(`${r}/${s[1]}`)):caches.open("vader").then((e=>{e.add(`${r}/${s[1]}`),console.log("cached",`${r}/${s[1]}`)})).catch((e=>{console.log(e)}))}let n=c.match(/href="([^"]*)"/g);if(n)for(;n.length;){let a=n.pop();if(a=a.replace('href="',"").replace('"',""),a.includes("http")||c.includes("\x3c!-- #vader-disable_relative-paths --\x3e")){if(!a.includes("http")&&a.startsWith(".")&&!c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use absolute paths since relative paths are not disabled in ${e.data.file}. Use relative paths instead. \n\n${a}`)}else c=c.replace(`href="${a}"`,`href="#${a}"`)}let d=Date.now()-a,h=!1;(r.includes("localhost")||r.includes("127.0.0.1")&&!h)&&(h=!0,c+=`\${console.log('%c${e.data.name} component rendered in ${d}ms','color:#fff;background:#000;padding:5px;border-radius:5px;font-size:12px;font-weight:bold'),""}`);const p=c.split("<script>");p&&p.forEach(((e,a)=>{if(0===a)c=e;else{if(e.includes("// <![CDATA[ <-- For SVG support"))return;let a=e.split("<\/script>")[0];t+=a}}));let $=c.match(/(\$\(.*?\))/gs);if($)for(;$.length;){let e=$.pop();c=c.replace(e,`\${${e.replace("$(","").replace(")","")}}`)}postMessage({template:`<div data-component=${e.data.name}>${c}</div>`,js:t||""})};