/ Check-in [64a6b822fd]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Sqlite: set dbname on open. Htmlpp: change echo to output.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:64a6b822fd9996f04368c851faa467f2a06bed41
User & Date: pmacdona 2019-12-02 02:02:20
Context
2019-12-03
16:42
Add validate command. Docs check-in: 229a87b69c user: pmacdona tags: trunk
2019-12-02
02:02
Sqlite: set dbname on open. Htmlpp: change echo to output. check-in: 64a6b822fd user: pmacdona tags: trunk
2019-12-01
20:00
Doc check-in: 3075eee92e user: pmacdona tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lib/Htmlpp.jsi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
38
39
40
41
42
43
44
45
46


47
48
49
50
51
52
53
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
199
200
201
202
203
204
205
206


207
208
209
210
211
212
213
#!/usr/bin/env jsish

require('Jsish');

/*
 * Preprocess html, css and js within the webserver. Evaluates javascript between  <? ?> tags (like php).
 * Evaluation occurs within a subinterp to which defines 2 new commands: include(file,...) and echo(str).
 */

var JsiHtmlpp_callback = null;

function Htmlpp(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // Preprocess html evaluating Jsi code between  <? ?> tags (like php).
................................................................................
        //puts('callback: '+iname+' '+cnt);
        Event.update();
    }
    
    if (!JsiHtmlpp_callback)
        JsiHtmlpp_callback = callback;

    function echo(s)    // Append string to output.
    {


        self.rc += s;
    }
    
    function error(s)   // Format an error with file/line number.
    {
        var fn = self.files[self.files.length-1];
        var line = self.data.split('\n').length;
................................................................................
            switch (extn) {
                case '.jsi': 
                    // Preprocess typed function in standard javascript for use within browsers.
                    ispp = true;
                    self.jsifiles.push(fn);
                case '.js': 
                    if (!inline) {
                        echo('<script src="'+tfn+'"></script>\n');
                        continue;
                    }
                    pre += "<script>"+begin;
                    if (!ispp) 
                        pre += File.read(fn);
                    else {
                        if (self.jsifiles.length==1 && self.noCheck) {
................................................................................
                            pre += File.read(self.dir+'/web/jsi.js');
                            if (self.noCheck)
                                pre += '$jsi.conf({disabled:true});\n';
                        }
                        pre += Jspp([fn]);
                    }
                    pre += end + "</script>\n";
                    echo(pre);
                    continue;
                    
                case '.cssi':
                    ispp = true;
                case '.css':
                    self.cssfiles.push(fn);
                    if (!inline) {
                        echo('<link rel="stylesheet" type="text/css" href="'+tfn+'">\n');
                        continue;
                    }
                    pre += "<style>"+begin;
                    if (!ispp)
                        pre += File.read(fn);
                    else {
                        if (!self.cssipp)
                            self.cssipp = Jsi_Csspp();
                        pre += self.cssipp.parse([fn]);
                    }
                    pre += end+"\n</style>\n";
                    if (ispp===false || pre.indexOf('<?')<0) {
                        echo(pre);
                        continue;
                    }
                    x = pre; // .cssi file contains a <? tags so preprocess it.
                    break;
                    
                case '.mdi':
                    self.mdfiles.push(fn);
                    if (!self.mdpp)
                        self.mdpp = Markdown(null);
                    pre += self.mdpp.parse([fn]);
                    echo(pre);
                    continue;
                    break;
                default:
                    notMarked = true;
            }
            if (x===null) {
                x = File.read(fn);
................................................................................
        
        if (!self.intOpts.busyCallback)
            self.intOpts.busyCallback = "JsiHtmlpp_callback";
        if (!self.interp)
            self.interp = new Interp(self.intOpts);
            
        if (!self.interp.alias('echo'))
            self.interp.alias('echo', echo, null);


        if (!self.interp.alias('include'))
            self.interp.alias('include', include, null);

        if (self.noCatch)
            include(files);
        else {
            try {






|







 







|

>
>







 







|







 







|







|












|










|







 







|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/usr/bin/env jsish

require('Jsish');

/*
 * Preprocess html, css and js within the webserver. Evaluates javascript between  <? ?> tags (like php).
 * Evaluation occurs within a subinterp to which defines 2 new commands: include(file,inline) and output(str).
 */

var JsiHtmlpp_callback = null;

function Htmlpp(files:array|string=null, conf:object=undefined):string|object
{
    var options = { // Preprocess html evaluating Jsi code between  <? ?> tags (like php).
................................................................................
        //puts('callback: '+iname+' '+cnt);
        Event.update();
    }
    
    if (!JsiHtmlpp_callback)
        JsiHtmlpp_callback = callback;

    function output(s:string, markdown=false)    // Append string to output.
    {
        if (markdown)
            s = Util.markdown(s).data;
        self.rc += s;
    }
    
    function error(s)   // Format an error with file/line number.
    {
        var fn = self.files[self.files.length-1];
        var line = self.data.split('\n').length;
................................................................................
            switch (extn) {
                case '.jsi': 
                    // Preprocess typed function in standard javascript for use within browsers.
                    ispp = true;
                    self.jsifiles.push(fn);
                case '.js': 
                    if (!inline) {
                        output('<script src="'+tfn+'"></script>\n');
                        continue;
                    }
                    pre += "<script>"+begin;
                    if (!ispp) 
                        pre += File.read(fn);
                    else {
                        if (self.jsifiles.length==1 && self.noCheck) {
................................................................................
                            pre += File.read(self.dir+'/web/jsi.js');
                            if (self.noCheck)
                                pre += '$jsi.conf({disabled:true});\n';
                        }
                        pre += Jspp([fn]);
                    }
                    pre += end + "</script>\n";
                    output(pre);
                    continue;
                    
                case '.cssi':
                    ispp = true;
                case '.css':
                    self.cssfiles.push(fn);
                    if (!inline) {
                        output('<link rel="stylesheet" type="text/css" href="'+tfn+'">\n');
                        continue;
                    }
                    pre += "<style>"+begin;
                    if (!ispp)
                        pre += File.read(fn);
                    else {
                        if (!self.cssipp)
                            self.cssipp = Jsi_Csspp();
                        pre += self.cssipp.parse([fn]);
                    }
                    pre += end+"\n</style>\n";
                    if (ispp===false || pre.indexOf('<?')<0) {
                        output(pre);
                        continue;
                    }
                    x = pre; // .cssi file contains a <? tags so preprocess it.
                    break;
                    
                case '.mdi':
                    self.mdfiles.push(fn);
                    if (!self.mdpp)
                        self.mdpp = Markdown(null);
                    pre += self.mdpp.parse([fn]);
                    output(pre);
                    continue;
                    break;
                default:
                    notMarked = true;
            }
            if (x===null) {
                x = File.read(fn);
................................................................................
        
        if (!self.intOpts.busyCallback)
            self.intOpts.busyCallback = "JsiHtmlpp_callback";
        if (!self.interp)
            self.interp = new Interp(self.intOpts);
            
        if (!self.interp.alias('echo'))
            self.interp.alias('echo', output, null);
        if (!self.interp.alias('output'))
            self.interp.alias('output', output, null);
        if (!self.interp.alias('include'))
            self.interp.alias('include', include, null);

        if (self.noCatch)
            include(files);
        else {
            try {

Changes to lib/Websrv.jsi.

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
        }
        if (!self.rootdir)
            self.rootdir = '.';
        // Provide default values for websocket.
        var wo = self.wsopts = {
            local:self.local,
            debug:self.wsdebug,
            extHandler:true,
            onOpen:WsOpen,
            onClose:WsClose,
            onCloseLast:WsCloseLast,
            onRecv:WsRecv,
            onUpload:WsUpload,
            onFilter:WsFilter,
            port:self.port,







|







360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
        }
        if (!self.rootdir)
            self.rootdir = '.';
        // Provide default values for websocket.
        var wo = self.wsopts = {
            local:self.local,
            debug:self.wsdebug,
            extHandlers:true,
            onOpen:WsOpen,
            onClose:WsClose,
            onCloseLast:WsCloseLast,
            onRecv:WsRecv,
            onUpload:WsUpload,
            onFilter:WsFilter,
            port:self.port,

Changes to lib/web/jsi.js.

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
...
438
439
440
441
442
443
444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
    var h = document.querySelector("head");
    h.appendChild(f);
}

function errHandler(msg, url, lineNumber) {  
    //save error and send to server for example.
    puts('MMM',msg);
    $jsi.htmladd('<p style="color:red">'+msg+'</p>\n');
    //$jsi.htmladd(msg);
    return true;
}


var jsi = {
    unittest:0,
    config:config,
................................................................................
    
    guid: function() { // Return unique UUID.
        if (!jsi.state.uuid)
            jsi.state.uuid = Date.now();
        return '_uuid'+(jsi.state.uuid++).toString(16);
    },
    
    htmladd: function(str) { $jsig('htmladd(str:string)', arguments);
        // Insert html into page.
        var f=document.createElement('div');
        f.innerHTML = str;
        var h = document.querySelector("body");
        h.appendChild(f);
    },

    
    include: function(fns) { $jsig('include(fns:string|array)', arguments);
        // Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.
        if (typeof fns === 'string')
            fns = [fns];
        for (var i in fns) {
            var fn = fns[i];







|
<







 







|






>







236
237
238
239
240
241
242
243

244
245
246
247
248
249
250
...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
    var h = document.querySelector("head");
    h.appendChild(f);
}

function errHandler(msg, url, lineNumber) {  
    //save error and send to server for example.
    puts('MMM',msg);
    $jsi.output('<p style="color:red">'+msg+'</p>\n');

    return true;
}


var jsi = {
    unittest:0,
    config:config,
................................................................................
    
    guid: function() { // Return unique UUID.
        if (!jsi.state.uuid)
            jsi.state.uuid = Date.now();
        return '_uuid'+(jsi.state.uuid++).toString(16);
    },
    
    output: function(str) { $jsig('htmladd(str:string)', arguments);
        // Insert html into page.
        var f=document.createElement('div');
        f.innerHTML = str;
        var h = document.querySelector("body");
        h.appendChild(f);
    },
    htmladd: function(str) { output(str) },
    
    include: function(fns) { $jsig('include(fns:string|array)', arguments);
        // Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.
        if (typeof fns === 'string')
            fns = [fns];
        for (var i in fns) {
            var fn = fns[i];

Changes to md/Builtins.md.

1
2
3
4
5
6
7
8
9
...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
Builtins
========
<div id="sectmenu"></div>
This page provides information and examples for built-in commands.

**Note**: clicking on each section header goes to the auto-generated Reference.

[Channel](Reference.md#Channel)
----
................................................................................

    source('myfile.jsi');
    source(['file1.jsi', 'file2.jsi']);

[WebSocket](Reference.md#WebSocket)
----
The WebSocket extension uses libwebsockets to implement
bidirectional socket communication with a web browser.

When used in conjunction with [Sqlite](Sqlite.md) and [JSON](#JSON),
it is a simple matter to implement browser based applications.


The following creates a minimal client and server using WebSockets.
First the server file ws.js:

    function ws_input(data, id) {
        puts("ws_input: "* + id + *": " + data);

|







 







|

|
|







1
2
3
4
5
6
7
8
9
...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
Builtins
====
<div id="sectmenu"></div>
This page provides information and examples for built-in commands.

**Note**: clicking on each section header goes to the auto-generated Reference.

[Channel](Reference.md#Channel)
----
................................................................................

    source('myfile.jsi');
    source(['file1.jsi', 'file2.jsi']);

[WebSocket](Reference.md#WebSocket)
----
The WebSocket extension uses libwebsockets to implement
bidirectional socket communication with web-browsers.

When used in conjunction with [web](Web.md), [Sqlite](Sqlite.md) and [JSON](#JSON),
it is easy to implement browser based applications.


The following creates a minimal client and server using WebSockets.
First the server file ws.js:

    function ws_input(data, id) {
        puts("ws_input: "* + id + *": " + data);

Changes to md/C-API.md.

1
2
3
4
5
6
7
8
9
C-API
=====
<div id="sectmenu"></div>
Jsi has a sizeable C-API, best documented by the header file [jsi.h](../src/jsi.h).

A portion of which can be used without the interpreter code by C programmers (Jsi-Lite).

CData
----

|







1
2
3
4
5
6
7
8
9
C-API
====
<div id="sectmenu"></div>
Jsi has a sizeable C-API, best documented by the header file [jsi.h](../src/jsi.h).

A portion of which can be used without the interpreter code by C programmers (Jsi-Lite).

CData
----

Changes to md/CData.md.

1
2
3
4
5
6
7
8
9
CData
======
<div id="sectmenu"></div>
The CData interface provides:

- Generation of C-extension modules containing code and data-structs.
- Script-defined C-structs, accessed via the [CData](Reference.md#CData) commands.

**Note**: All examples below that start `"cat XXX <<EOF"` are bash testable with a simple copy+paste. 

|







1
2
3
4
5
6
7
8
9
CData
====
<div id="sectmenu"></div>
The CData interface provides:

- Generation of C-extension modules containing code and data-structs.
- Script-defined C-structs, accessed via the [CData](Reference.md#CData) commands.

**Note**: All examples below that start `"cat XXX <<EOF"` are bash testable with a simple copy+paste. 

Changes to md/DBQuery.md.

1
2
3
4
5
6
7
8
9
Db-Query
========
<div id="sectmenu"></div>
Db-Query uses [CData](CData.md) to define data to exchange data between C-structs and Sqlite.

Supported are **SELECT, INSERT, UPDATE, REPLACE, DELETE** with:

- Automatic data conversions.
- Statement caching.

|







1
2
3
4
5
6
7
8
9
Db-Query
====
<div id="sectmenu"></div>
Db-Query uses [CData](CData.md) to define data to exchange data between C-structs and Sqlite.

Supported are **SELECT, INSERT, UPDATE, REPLACE, DELETE** with:

- Automatic data conversions.
- Statement caching.

Changes to md/Debug.md.

1
2
3
4
5
6
7
8
9
Debug
========

Debuggers
---------
<div id="sectmenu"></div>
There are two debuggers in Jsi.  The command-line one:

    jsish -d myscr.jsi arg1

|







1
2
3
4
5
6
7
8
9
Debug
=====

Debuggers
---------
<div id="sectmenu"></div>
There are two debuggers in Jsi.  The command-line one:

    jsish -d myscr.jsi arg1

Changes to md/Home.md.

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
----

- **Start**: [Download](Download.md), [Building](Download.md#Building), [Using](Download.md#Using), [Embedding](Download.md#Embedding)
- **Docs**: [Builtins](Builtins.md), [Reference](Reference.md), [FAQ](../../../wiki/FAQ), [Index](Docs.md), [License](Misc.md#License), [Language](Misc.md#Language Comparisons), [ECMA](Misc.md#ECMA Compatibilty)
- **Development**: [Types](Types.md), [Strict Mode](Types.md#Strict Mode), [Type Checking](Types.md#Checking), [Debugging](Debug.md), [Errors](Testing.md#Errors), [Logging](Logging.md)
- **Core**: [System](Builtins.md#System), [Info](Builtins.md#Info), [Interp](Interp.md), [Format](Logging.md#format), [File-System](Builtins.md#File), [Events](Builtins.md#Event)
- **Integration**: [Modules](Coding.md#Modules), [Packages](Coding.md#Packages), [Auto-Load](Coding.md#Auto-Load)
- **Web**: [Pre-processors](Builtins.md#WebSocket), [Markup](Reference.md#Util), [JSON](Builtins.md#JSON)
- **Miscellaneous**: [CData](CData.md), [Threads](Interp.md#Thread-Interps), [Signal](Builtins.md#Signal), [Sqlite](Sqlite.md), [MySQL](MySql.md), [Zvfs](Builtins.md#Zvfs), [Socket](Builtins.md#Socket), [WebSocket](Builtins.md#WebSocket)
- **Tools**: [Testing](Testing.md), [Tracing](Coding.md#Execution Trace), [Profiling](Coding.md#Code Profile), [Code-Coverage](Coding.md#Code Coverage)
- **C/C++**: [Jsi-Lite](C-API.md#Jsi-Lite), [C Extension](CData.md), [DString](C-API.md#DString), [CData](CData.md), [Options](C-API.md#Options), [Sqlite-C](DBQuery.md), [JSON-C](C-API.md#JSON)
- **Applications**: [Ledger](Ledger.md), [SqliteUI](Download.md#Apps), [Web Server](Coding.md#Server)

Purpose
----







|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
----

- **Start**: [Download](Download.md), [Building](Download.md#Building), [Using](Download.md#Using), [Embedding](Download.md#Embedding)
- **Docs**: [Builtins](Builtins.md), [Reference](Reference.md), [FAQ](../../../wiki/FAQ), [Index](Docs.md), [License](Misc.md#License), [Language](Misc.md#Language Comparisons), [ECMA](Misc.md#ECMA Compatibilty)
- **Development**: [Types](Types.md), [Strict Mode](Types.md#Strict Mode), [Type Checking](Types.md#Checking), [Debugging](Debug.md), [Errors](Testing.md#Errors), [Logging](Logging.md)
- **Core**: [System](Builtins.md#System), [Info](Builtins.md#Info), [Interp](Interp.md), [Format](Logging.md#format), [File-System](Builtins.md#File), [Events](Builtins.md#Event)
- **Integration**: [Modules](Coding.md#Modules), [Packages](Coding.md#Packages), [Auto-Load](Coding.md#Auto-Load)
- **Web**: [Server](Web.md), [Preprocessing](Web.md), [WebSocket](Builtins.md#WebSocket), [Markup](Reference.md#Util), [JSON](Builtins.md#JSON)
- **Miscellaneous**: [CData](CData.md), [Threads](Interp.md#Thread-Interps), [Signal](Builtins.md#Signal), [Sqlite](Sqlite.md), [MySQL](MySql.md), [Zvfs](Builtins.md#Zvfs), [Socket](Builtins.md#Socket), [WebSocket](Builtins.md#WebSocket)
- **Tools**: [Testing](Testing.md), [Tracing](Coding.md#Execution Trace), [Profiling](Coding.md#Code Profile), [Code-Coverage](Coding.md#Code Coverage)
- **C/C++**: [Jsi-Lite](C-API.md#Jsi-Lite), [C Extension](CData.md), [DString](C-API.md#DString), [CData](CData.md), [Options](C-API.md#Options), [Sqlite-C](DBQuery.md), [JSON-C](C-API.md#JSON)
- **Applications**: [Ledger](Ledger.md), [SqliteUI](Download.md#Apps), [Web Server](Coding.md#Server)

Purpose
----

Changes to md/Web.md.

1


2
3
4
5
6
7


8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72

73
74
75
76
77
78
79
80
81
82
83
84

85
86
87




88
89
90
91
92
93
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
















126

127
128
129
130
131
132

<title>Web</title>



Jsi provides server-side web services built upon the [WebSockets](./js-websocket.md) extension.

Preprocessors
=============
Three pre-processing facilities are provided, depending upon file extension:




Extension | Type       | Description
----------|------------|---------------------------------------------------------------------
.htmli    | HTML       | Evaluate javascript between tags **&lt;?** and **?&gt;**.
.cssi     | CSS        | Preprocess **$defined** symbols.
.jsi      | Javascript | Translate [typed-functions](./functions.wiki) (for use within browsers)




Pre-processors are enabled via **handlers**:

    var ws = new WebSocket({callback:ws_input});
    ws.handler('.htmli', 'Jsi_Htmlpp',  null);
    ws.handler('.jsi',   'Jsi_Jspp', null);
    ws.handler('.cssi',  'Jsi_Csspp',  null);


The specifics are described below.

HTML Preprocessing
------------------
The HTML preprocessor is triggered by the extension <b>.htmli</b>.

It evaluates javascript contained in <b>&lt;?</b> and <b>?&gt;</b> tags.

This code is run in a private subinterp to which two new commands have been added:

    <table border='1' class=cmdstbl>
<tr><th>Command</th> <th>Prototype</th> <th>Description</th> </tr>
<tr><td>echo | echo(str:string) | Output a string |
<tr><td>include | include(files:string|array, debug=false) | Include and evaluate files, recusively. |
</table>

Here is an example:

    <nowiki><pre class=verbatim>
<!DOCTYPE html>    <i><!-- File: main.htmli --></i>
<html>
<b><?</b>
    <b>echo</b>(<i>'&lt;title>My App&lt;/title>'</i>);
    var files = [<i>'head.html'</i>, <i>'body.html'</i>, <i>'dialogs.html'</i>];



    for (var i in files)
        <b>include</b>(files[i]);
<b>?></b>
</html>
</pre></nowiki>

All <b>include</b>-ed files are also similarly processed recursively, regardless of extension.
The only exception are <b>.js .jsi</b> and <b>.css</b>,
whose handling is described below.

Files with the .css/.cssi extensions are wrapped in <b>&lt;style></b> tags
and .js/.jsi are wrapped in <b>&lt;script></b> tags.

When the include <b>debug</b> flag is <i>true</i>, non-html files are not included inline but rather
via link/script tags.  This is used to simplify debugging in the browser, eg.

    <nowiki><pre class=verbatim>
<head>
    <b>include</b>([<i>'main.jsi'</i>, <i>'main.cssi'</i>, <i>'common.cssi'</i>], <b>true</b>);

</head>
</pre></nowiki>

<hr>

<h3 id=csspp>CSS Preprocessing</h3>
The CSS preprocessor is triggered by the <b>.cssi</b> extension, and provides symbolic substitution via defines prefixed with <b>$</b>:

    <nowiki><pre class=verbatim>
<b>$mycolor =</b> { blue }    <i>/* File: styles.cssi */</i>
<b>$mysize =</b> { 14pt }
<b>$mydefn =</b> {
    color:<b>$mycolor</b>;
    font-size:<b>$mysize</b>;
}
  
#mybut1 { color:<b>$mycolor</b>; font-size:<b>$mysize</b>}

.eclass { <b>$mydefn</b>; margin:1px }

<b><?</b>




    <b>echo</b>(<i>'#mylist { color: $mycolor; }\n'</i>);
    <b>include</b>(<i>'common.cssi'</i>);
<b>?></b>
</pre></nowiki>

Note  after <b>$define</b> expansion, <b>&lt;?</b> and <b>?&gt;</b> evaluation is also applied.



<hr>
<h3 id=typepp>Javascript Preprocessing</h3>

The type pre-processor is triggered by the <b>.jsi</b> extension.

It converts typed-[./functions.wiki|function] code into standard web browser javascript, ie.

    <nowiki><pre class=verbatim>
function notifyUser(m:string, n:number=1) {
    alert('NOTICE: '+m+': '+n);
}
</pre></nowiki>

which gets converted to:

    <nowiki><pre class=verbatim>
function notifyUser(m, n) { m=Jsi.ArgCheck(...); n=Jsi.ArgCheck(...);
    alert('NOTICE: '+m+': '+n);
}
</pre></nowiki>


This provides runtime type-checking of function calls.

To debug, we set a breakpoint on warnings which are output
to the console.

The Jsi support functions are included from: <b>/jsi/lib/jsi.js</b>

<hr>
















<h2 id=utilities>Utilities</h2>


The following resources are available to include from <b>/jsi/lib/</b>:

  *  [../lib/web/jsi.js|jsi.js]: Support code for type-checking.
  *  [https://github.com/remy/bind.js|bind.js]: Two way binding between data and elements.
  *  [http://zeptojs.com/|zepto.js]: Lite subset of JQuery.

|
>
>

|


<
<
>
>





|

>

<
<
<
<
<
<
<
<
<
<
|

|
<






|
|
<
<
<



<
|
|
<
<
<
>
>
>
|
|
|
|
<






|

|


<
|
<
>
|
<

<
>
|


<
|
|
|
|
|
|
|
<
>
|

<
>
>
>
>
|
<
|
<

<

>

<
|

|

|

<
|
|
|
<

|

<
|
|
|
<









<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>

|

|
|
<
>
1
2
3
4
5
6
7


8
9
10
11
12
13
14
15
16
17
18










19
20
21

22
23
24
25
26
27
28
29



30
31
32

33
34



35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51
52

53

54
55

56

57
58
59
60

61
62
63
64
65
66
67

68
69
70

71
72
73
74
75

76

77

78
79
80

81
82
83
84
85
86

87
88
89

90
91
92

93
94
95

96
97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
Web
========
<div id="sectmenu"></div>

Jsi provides server-side web services built upon the [WebSockets](Builtins.md#WebSocket) extension.

Preprocessors


----
Pre-processing is determined by file extension:


Extension | Type       | Description
----------|------------|---------------------------------------------------------------------
.htmli    | HTML       | Evaluate javascript between tags **&lt;?** and **?&gt;**.
.cssi     | CSS        | Preprocess **$**define style symbols.
.jsi      | Javascript | Translate [typed-functions](./functions.wiki) (for use within browsers)
.mdi      | Markdown   | Render file contents to markdown











These work as described below.

### HTML Preprocessing

The HTML preprocessor is triggered by the extension <b>.htmli</b>.

It evaluates javascript contained in <b>&lt;?</b> and <b>?&gt;</b> tags.

This code is run in a private subinterp to which two new commands have been added:

    function include(file:array|string, inline=false); // Include and evaluate files.
    function output(str:string, markdown=false); // Append string to output.




Here is an example:


    <!DOCTYPE html>
    <html>



    <?
        output('<title>My App</title>');
        var files = ['head.html','body.html', 'dialogs.html'];
        for (var i in files)
            include(files[i]);
    ?>
    </html>


All <b>include</b>-ed files are also similarly processed recursively, regardless of extension.
The only exception are <b>.js .jsi</b> and <b>.css</b>,
whose handling is described below.

Files with the .css/.cssi extensions are wrapped in <b>&lt;style></b> tags
and *.js/.jsi* are wrapped in **script** tags.

When the include **debug** flag is *true*, non-html files are not included inline but rather
via link/script tags.  This is used to simplify debugging in the browser, eg.


    <head>

        include(['main.jsi', 'main.cssi', 'common.cssi'], true);
    </head>




### CSS Preprocessing
The CSS preprocessor is triggered by the <b>.cssi</b> extension, and provides symbolic substitution via defines prefixed with <b>$</b>:


    $mycolor = { blue }    /* File: styles.cssi */
    $mysize = { 14pt }
    $mydefn = {
        color:$mycolor;
        font-size:$mysize;
    }
      

    #mybut1 { color:$mycolor; font-size:$mysize}
    .eclass { $mydefn; margin:1px }


used like so:

    <?
        include('styles.cssi');
        output('#mylist { color: $mycolor; }\n');

    ?>




Note  after **$define** expansion, <b>&lt;?</b> and <b>?&gt;</b> evaluation is also applied.


### JS Preprocessing

The type pre-processor is triggered by the **.jsi** extension.

It converts [Typed](Types.md) functions into standard web browser javascript, ie.


    function notifyUser(m:string, n:number=1) {
        alert('NOTICE: '+m+': '+n);
    }


is converted to:


    function notifyUser(m, n) { m=Jsi.ArgCheck(...); n=Jsi.ArgCheck(...);
        alert('NOTICE: '+m+': '+n);
    }



This provides runtime type-checking of function calls.

To debug, we set a breakpoint on warnings which are output
to the console.

The Jsi support functions are included from: <b>/jsi/lib/jsi.js</b>


Enabling Preprocessors
----

Pre-processors **handlers** are enabled in WebSocket via:

    var ws = new WebSocket({callback:ws_input, extHandlers:true});
    
or

    var ws = new WebSocket({callback:ws_input});
    ws.handler('.htmli', 'Htmlpp',  null);
    ws.handler('.jsi',   'Jspp', null);
    ws.handler('.cssi',  'Csspp',  null);
    ws.handler('.mdi',   'Markdown',  null);


Utilities
----

The following resources are available to include from **/jsi/lib/**:

|[jsi.js](jsi.js.md)| Support code for type-checking.
|[bind.js](https://github.com/remy/bind.js)| Two way binding between data and elements.

|[mustache](https://github.com/janl/mustache.js)| Web templating.

Changes to md/jsi.js.md.

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17




18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
45
46
47
48
49
50
51
52
53
54
55
56












57
58
59
60
61
62
63
64
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112






113
114
115
116
117
118
119
...
122
123
124
125
126
127
128
129
130
131
jsi.js
====

<div id="sectmenu"></div>
[jsi.js](/file/lib/web/jsi.js) provides [type-checking](Types.md) for
javascript function arguments, eg:

    <script src="/jsi/web/jsi.js"></script>
    <script>
    function bark(s, n) { $jsig('bark(s:string, n:number)', arguments);
       console.log("BARK: "+s+n);

    }
    
    bark('husky',2);
    </script>

Alternatively, signature arguments can be preprocessed ([example](../js-demos/jsig.html)):





    // bark.jsi
    function bark(s:string, n:number) {
       console.log("BARK: "+s);
    }

loaded via **include()**:

    <script src="/jsi/web/jsi.js"></script>
    <script>
        $jsi.include('bark.jsi');
        $jsi.onload(function() {
            bark('abc',0);
            bark(9,0);
................................................................................
    BARK: 9
    jsi.js:23 missing arguments: expected 2 got 1: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 extra arguments: expected 2 got 3: calling bark(s:string, n:number)
    BARK: 9


Or use the **jsish** web server to preprocess **.jsi** files:

    <script src="/jsi/web/jsi.js"></script>
    <script src="bark.js"></script>













$jsi
====
The **$jsi** object contains the following commands:

$(selector:string, top:string=void)
----
Jquery-like querySelectorAll functionality.

................................................................................
----
Save data as filename in browser.

guid()
----
Return unique UUID.

htmladd(str:string)
----
Insert html into page.

    $jsi.htmladd('<b>Hello World</b>');

include(fns:string|array)
----
Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.

onload(f:function)
----
Function to invoke after page is loaded and all **include** processing is complete.







puts(str:string,...)
----
A bind alias for console.log.

schema(obj:object, schm:object=null)
----
Check object/json schema, or generate when schm null/ommited.
................................................................................
----
Set opts in obj and return.

websock(prot='ws')
----
Open new websocket.

Details
====
Aside from **$jsi**, the following are global: **$jsig**, **$**, **puts**.




<
<

<
<
<
<
>
|
<
<
<
<
<
>
>
>
>






|







 







|




>
>
>
>
>
>
>
>
>
>
>
>
|







 







|
<
<
<
<
<
<







>
>
>
>
>
>







 







<
<
<
1
2
3
4


5




6
7





8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
..
98
99
100
101
102
103
104
105






106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
128
129
130
131
132
133
134



jsi.js
====

<div id="sectmenu"></div>







[jsi.js](/file/lib/web/jsi.js) provides provdes global commands: **$**, **$jsig**, **puts**.






Typed Functions
====
Most important is support for [type-checked](Types.md) function arguments
via preprocessing:

    // bark.jsi
    function bark(s:string, n:number) {
       console.log("BARK: "+s);
    }

This is loaded via **include()**:

    <script src="/jsi/web/jsi.js"></script>
    <script>
        $jsi.include('bark.jsi');
        $jsi.onload(function() {
            bark('abc',0);
            bark(9,0);
................................................................................
    BARK: 9
    jsi.js:23 missing arguments: expected 2 got 1: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 extra arguments: expected 2 got 3: calling bark(s:string, n:number)
    BARK: 9


Typically we use the **jsish** web server to preprocess **.jsi** files:

    <script src="/jsi/web/jsi.js"></script>
    <script src="bark.js"></script>

The preprocessor outputs:

    <script src="/jsi/web/jsi.js"></script>
    <script>
    function bark(s, n) { $jsig('bark(s:string, n:number)', arguments);
       console.log("BARK: "+s+n);
    }
    
    bark('husky',2);
    </script>


$jsi methods
====
The **$jsi** object contains the following commands:

$(selector:string, top:string=void)
----
Jquery-like querySelectorAll functionality.

................................................................................
----
Save data as filename in browser.

guid()
----
Return unique UUID.

include(file:string\|array)






----
Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.

onload(f:function)
----
Function to invoke after page is loaded and all **include** processing is complete.

output(str:string)
----
Insert html into page.

    $jsi.output('<b>Hello World</b>');

puts(str:string,...)
----
A bind alias for console.log.

schema(obj:object, schm:object=null)
----
Check object/json schema, or generate when schm null/ommited.
................................................................................
----
Set opts in obj and return.

websock(prot='ws')
----
Open new websocket.




Changes to src/jsiSqlite.c.

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
....
3491
3492
3493
3494
3495
3496
3497

3498
3499
3500
3501
3502
3503
3504
....
3687
3688
3689
3690
3691
3692
3693
3694


3695
3696
3697
3698
3699
3700
3701
    JSI_OPT(BOOL,   Jsi_Db, echo,       .help="LogInfo outputs the string value of every query and eval"),
    JSI_OPT(INT,    Jsi_Db, errCnt,     .help="Count of errors in script callbacks", jsi_IIRO),
    JSI_OPT(INT,    Jsi_Db, errorCode,  .help="Numeric error code returned by the most recent call to sqlite3_exec"),
    JSI_OPT(BOOL,   Jsi_Db, forceInt,   .help="Bind float as int if possible"),
    JSI_OPT(UINT64, Jsi_Db, lastInsertId,.help="The rowid of last insert"),
    JSI_OPT(BOOL,   Jsi_Db, load,       .help="Extensions can be loaded" ),
    JSI_OPT(CUSTOM, Jsi_Db, mutex,      .help="Mutex type to use", jsi_IIOF, .custom=Jsi_Opt_SwitchEnum, .data=mtxStrs),
    JSI_OPT(DSTRING,Jsi_Db, name,       .help="Optional name field"),
    JSI_OPT(BOOL,   Jsi_Db, noConfig,   .help="Disable use of Sqlite.conf to change options after create", jsi_IIOF),
    JSI_OPT(BOOL,   Jsi_Db, noCreate,   .help="Database is must already exist (false)", jsi_IIOF),
    JSI_OPT(FUNC,   Jsi_Db, onAuth,     .help="Function to call for auth", .flags=0, .custom=0, .data=(void*)"db:userobj, code:string, descr1:string, decr2:string, dbname:string, trigname:string"),
    JSI_OPT(FUNC,   Jsi_Db, onBusy,     .help="Function to call when busy", .flags=0, .custom=0, .data=(void*)"db:userobj, tries:number"),
    JSI_OPT(FUNC,   Jsi_Db, onCommit,   .help="Function to call on commit", .flags=0, .custom=0, .data=(void*)"db:userobj"),
    JSI_OPT(FUNC,   Jsi_Db, onNeedCollate,.help="Function to call for collation", .flags=0, .custom=0, .data=(void*)"db:userobj, name:string"),
    JSI_OPT(FUNC,   Jsi_Db, onProfile,  .help="Function to call for profile", .flags=0, .custom=0, .data=(void*)"db:userobj, sql:string, time:number"),
................................................................................

/*    if (jdb->onUnlock && (!ojdb || !ojdb->onUnlock) )
        sqlite3_unlock_notify(jdb->db, dbUnlockNotify, (void*)jdb);
    else
        sqlite3_unlock_notify(jdb->db, 0, 0);
        */
}


static Jsi_RC SqliteConfCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
                         Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Db *jdb, ojdb;
    if (!(jdb = dbGetDbHandle(interp, _this, funcPtr))) return JSI_ERROR;
    Jsi_Value *opts = Jsi_ValueArrayIndex(interp, args, 0);
................................................................................
    db->stmtHash = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
    db->fobj = fobj;
    //dbSys->cnt = Jsi_UserObjCreate(interp, sqliteobject.name /*dbSys*/, fobj, db);
    db->interp = interp;
    db->optPtr = &db->queryOpts;
    db->stmtCache = Jsi_ListNew((Jsi_Interp*)db, 0, dbStmtFreeProc);
    rc = JSI_OK;



    Jsi_JSONParseFmt(interp, &db->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, hdrSrcId:\"%s\", pkgVer:%d}",
        (char *)sqlite3_libversion(), SQLITE_VERSION, SQLITE_VERSION_NUMBER, SQLITE_SOURCE_ID, jsi_DbPkgVersion); 
    dbSetupCallbacks(db, NULL);
    
bail:
    if (rc != JSI_OK) {
        if (db->hasOpts)







|







 







>







 







|
>
>







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
....
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
....
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
    JSI_OPT(BOOL,   Jsi_Db, echo,       .help="LogInfo outputs the string value of every query and eval"),
    JSI_OPT(INT,    Jsi_Db, errCnt,     .help="Count of errors in script callbacks", jsi_IIRO),
    JSI_OPT(INT,    Jsi_Db, errorCode,  .help="Numeric error code returned by the most recent call to sqlite3_exec"),
    JSI_OPT(BOOL,   Jsi_Db, forceInt,   .help="Bind float as int if possible"),
    JSI_OPT(UINT64, Jsi_Db, lastInsertId,.help="The rowid of last insert"),
    JSI_OPT(BOOL,   Jsi_Db, load,       .help="Extensions can be loaded" ),
    JSI_OPT(CUSTOM, Jsi_Db, mutex,      .help="Mutex type to use", jsi_IIOF, .custom=Jsi_Opt_SwitchEnum, .data=mtxStrs),
    JSI_OPT(DSTRING,Jsi_Db, name,       .help="The dbname to use instead of 'main'", jsi_IIOF),
    JSI_OPT(BOOL,   Jsi_Db, noConfig,   .help="Disable use of Sqlite.conf to change options after create", jsi_IIOF),
    JSI_OPT(BOOL,   Jsi_Db, noCreate,   .help="Database is must already exist (false)", jsi_IIOF),
    JSI_OPT(FUNC,   Jsi_Db, onAuth,     .help="Function to call for auth", .flags=0, .custom=0, .data=(void*)"db:userobj, code:string, descr1:string, decr2:string, dbname:string, trigname:string"),
    JSI_OPT(FUNC,   Jsi_Db, onBusy,     .help="Function to call when busy", .flags=0, .custom=0, .data=(void*)"db:userobj, tries:number"),
    JSI_OPT(FUNC,   Jsi_Db, onCommit,   .help="Function to call on commit", .flags=0, .custom=0, .data=(void*)"db:userobj"),
    JSI_OPT(FUNC,   Jsi_Db, onNeedCollate,.help="Function to call for collation", .flags=0, .custom=0, .data=(void*)"db:userobj, name:string"),
    JSI_OPT(FUNC,   Jsi_Db, onProfile,  .help="Function to call for profile", .flags=0, .custom=0, .data=(void*)"db:userobj, sql:string, time:number"),
................................................................................

/*    if (jdb->onUnlock && (!ojdb || !ojdb->onUnlock) )
        sqlite3_unlock_notify(jdb->db, dbUnlockNotify, (void*)jdb);
    else
        sqlite3_unlock_notify(jdb->db, 0, 0);
        */
}


static Jsi_RC SqliteConfCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
                         Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Db *jdb, ojdb;
    if (!(jdb = dbGetDbHandle(interp, _this, funcPtr))) return JSI_ERROR;
    Jsi_Value *opts = Jsi_ValueArrayIndex(interp, args, 0);
................................................................................
    db->stmtHash = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
    db->fobj = fobj;
    //dbSys->cnt = Jsi_UserObjCreate(interp, sqliteobject.name /*dbSys*/, fobj, db);
    db->interp = interp;
    db->optPtr = &db->queryOpts;
    db->stmtCache = Jsi_ListNew((Jsi_Interp*)db, 0, dbStmtFreeProc);
    rc = JSI_OK;
    const char *dbname = Jsi_DSValue(&db->name);
    if (dbname[0])
        sqlite3_db_config(db->db, SQLITE_DBCONFIG_MAINDBNAME, dbname);
    Jsi_JSONParseFmt(interp, &db->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, hdrSrcId:\"%s\", pkgVer:%d}",
        (char *)sqlite3_libversion(), SQLITE_VERSION, SQLITE_VERSION_NUMBER, SQLITE_SOURCE_ID, jsi_DbPkgVersion); 
    dbSetupCallbacks(db, NULL);
    
bail:
    if (rc != JSI_OK) {
        if (db->hasOpts)

Changes to src/jsiWebSocket.c.

2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jspp",     jsi_wsStrValGet(cmdPtr, "jsi"),   1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Htmlpp",   jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Csspp",    jsi_wsStrValGet(cmdPtr, "cssi"),  1);
        //jsi_wsHandlerAdd(interp, cmdPtr, ".mdi",   "Markdeep", jsi_wsStrValGet(cmdPtr, "mdi"),   1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".mdi",   "Markdown",  jsi_wsStrValGet(cmdPtr, "mdi"), 1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion);
#endif







<







2799
2800
2801
2802
2803
2804
2805

2806
2807
2808
2809
2810
2811
2812
        goto bail;
    }
    cmdPtr->handlers = Jsi_HashNew(interp, JSI_KEYS_STRING, jsi_wsfreeHandlers);
    if (cmdPtr->extHandlers) {
        jsi_wsHandlerAdd(interp, cmdPtr, ".jsi",   "Jspp",     jsi_wsStrValGet(cmdPtr, "jsi"),   1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".htmli", "Htmlpp",   jsi_wsStrValGet(cmdPtr, "htmli"), 1);
        jsi_wsHandlerAdd(interp, cmdPtr, ".cssi",  "Csspp",    jsi_wsStrValGet(cmdPtr, "cssi"),  1);

        jsi_wsHandlerAdd(interp, cmdPtr, ".mdi",   "Markdown",  jsi_wsStrValGet(cmdPtr, "mdi"), 1);
    }
    cmdPtr->fobj = fobj;
#ifdef LWS_LIBRARY_VERSION_NUMBER
    Jsi_JSONParseFmt(interp, &cmdPtr->version, "{libVer:\"%s\", hdrVer:\"%s\", hdrNum:%d, pkgVer:%d}",
        (char *)lws_get_library_version(), LWS_LIBRARY_VERSION, LWS_LIBRARY_VERSION_NUMBER, jsi_WsPkgVersion);
#endif