Package: dnjs
dnjsdnjsis a pure subset ofJavaScriptthat wants to replace (across many host languages):overly limiting/baroqueconfiguration languagesmucky string basedhtml/xmltemplatingIt is powerful yet familiar, and the reduced syntax makes it easy to implement (the reference implementation inPythontook a couple of days to write) and easy to reason about. Currently the state is very alpha - see theTODOat the end.╔══════════════════════════════╗
║ ╔═══════════════╗            ║
║ ║ ╔══════╗      ║            ║
║ ║ ║ JSON ║ dnjs ║ JavaScript ║
║ ║ ╚══════╝      ║            ║
║ ╚═══════════════╝            ║
╚══════════════════════════════╝Installing the reference interpreterpipinstalldnjs
dnjs--helpExamplesSome of these examples reference other files inthe examples folder.For configuration:import{environments}from"./global.dn.js"// names of the services to deployconstserviceNames=["signup","account"]constmakeService=(environment,serviceName)=>({name:serviceName,ip:environment===environments.PROD?"189.34.0.4":"127.0.0.1"})exportdefault(environment)=>serviceNames.map((v,i)=>makeService(environment,v))Let's use the reference implementation written inPythonto run these (this also has aPythonAPI documented below):dnjsexamples/configuration.dn.jsexamples/environment.json|jqGives us:[{"name":"signup","ip":"127.0.0.1"},{"name":"account","ip":"127.0.0.1"}]Forhtmltemplatingdnjsprescribes functions for makinghtml, that handily are a subset ofmithril(this makes it possible to write powerful, reusable cross-languagehtmlcomponents).Given the filecommentsPage.dn.js:importmfrom"mithril"import{page}from"./basePage.dn.js"constcommentList=(comments)=>m("ul",comments.map((comment,i)=>m("li",`Comment${i}says:${comment.text}`)))exportdefault(comments)=>page(commentList(comments))Then in a python webserver we can render the file ashtml:fromdnjsimportrender@app.route("/some-route"):defsome_route():...returnrender("commentsPage.dn.js",comments)And the endpoint will return:<html><head><scriptsrc="someScript.js"></script></head><body><ul><li>Comment 0 says: hiya!</li><li>Comment 1 says: oioi</li></ul></body></html>Or we can use the same components on the frontend withmithril:importpagefrom"../commentsPage.dn.js"...m.mount(document.body,page)Or we can render thehtmlon the command line similar to before:dnjsexamples/commentsPage.dn.jsexamples/comments.json--htmlNote, that without the--htmlflag, we still make the followingJSON, the conversion tohtmlis a post-processing stage:{"tag":"html","attrs":{"className":""},"children":[{"tag":"head","attrs":{...ForcsstemplatingUsing--csswill post-process eg:exportdefault{".bold":{"font-weight":"bold"},".red":{"color":"red"},}to:.bold{font-weight:bold;}.red{color:red;}As ajqreplacementJSON='[{foo: 1, bar: "one"}, {foo: 2, bar: "two"}]'echo$JSON|dnjs--p'a=>a.map(b=>[b.bar, b.foo])'[["one",1],["two",2]]csvecho$JSON|dnjs--p'a=>a.map(b=>[b.bar, b.foo])'--csv"one",1
"two",2csv, rawecho$JSON|dnjs--p'a=>a.map(b=>[b.bar, b.foo])'--csv--rawone,1
two,2jsonl(Whilednjsis implemented in python, this is very slow).JSON='{foo: 1, bar: "one"}\n{foo: 2, bar: "two"}'echo$JSON|whilereadl;doecho$l|dnjs--p'a=>a.bar'--raw;doneone
twoFlatteningRemember, you can flatten arrays with:.reduce((a,b)=>[...a,...b],[])How exactly doesdnjsextendJSON?Rememberdnjsis arestrictionofJavaScript, the aim is not to implement all of it, any more thanJSONis.Here are all the extensions toJSON:Comments with//.Optional trailing commas.Unquoted keys in objects.import { c } from "./b.dn.js",import b from "./b.dn.js". Non-local imports are simply ignored (so as to allow importingmas anything).export default a,export const b = c.dicts andlists can be splatted with rest syntax:{...a}/[...a].Functions can be defined withconst f = (a, b) => csyntax. Brackets are not required for one argument, functions are called with the number of arguments provided.Ternary expressions,onlyin the forma === b ? c : d. Equality should be implemented howeverJavaScriptdoes.Map, filter, reduce, map over dict, dict from entries, in the forma.map((v, i) => b),a.filter((v, i) => b),a.reduce((x, y) => [...x, ...y], []),Object.entries(a).map(([k, v], i) => b),Object.fromEntries(a).Hyperscript, somewhat compatible withmithril-m("sometag#some-id.some-class.other-class", {"href": "foo.js", "class": ["another-class"]}, children), this evaluates todicts like{"tag": "sometag", "attrs": {"id": "some-id", className: "some-class other-class another-class", "href": "foo.js", "children": children}.m.trust(a)to not escape html.Multiline templates in the form`foo ${a}`,dedent(`foo ${a}`).dedentshould work the same asthis npm package.Lists have.length,.includes(a)attributes.NameOriginally the name stood for DOM Notation JavaScript.PythonAPIThese functions returnJSON-able data:fromdnjsimportget_default_export,get_named_exportget_default_export(path)get_named_export(path,name)This function returns html as astr:fromdnjsimportrenderrender(path,*values)The types used throughoutdnjsare fairly simpledataclasss , there's not much funny stuff going on in the code - check it out!DevelopmentInstall dev requirements with:pipinstall-rrequirements-dev.txtRun tests with:pytestPin requirements with:pip-compile-q;catrequirements.inrequirements-dev.in|pip-compile-q--output-file=requirements-dev.txt-Rebuild and publish (after upversioning) with:# up version setup.pyrmdist/*;pythonsetup.pysdistbdist_wheel;twineuploaddist/*JSJavascript validation library to follow - seeTODOsection below.Run tests with:npminstall
npmtestTODOUse on something real to iron out bugs.Spec out weird behaviour + make the same as js:numbers===Nicer docs:Write up why we don't need filters like | to_human.Consideronclick,onkeydown,on...functions... and how we want to handle them / attach them on reaching the browser in a isomophic setup.Decide what else should be added:Common string functions like upper case, replace etc?parseIntetc..Standalone (inc/rust/go? withPythonbindings) to JSON program.Write JS library that simply wraps mithril render and has adnjs.isValid(path)function that uses the grammar (doing this may involve removing somelark-specific bits in the grammar.Typescript support?Consider what preventsdnjsfrom becoming a data interchange format - eg. infinite recursion.--safemode? Specify PATHs that it's permitted to import from.Allow importing JSON using Experimental JSON modules](https://nodejs.org/api/esm.html#esm_experimental_json_modules).Remove accidental non-js compatability - eg. template grammar is a bit wacky.