clj-commons / marginalia Goto Github PK
View Code? Open in Web Editor NEWUltra-lightweight literate programming for clojure inspired by docco
Home Page: https://clj-commons.org/marginalia/
Ultra-lightweight literate programming for clojure inspired by docco
Home Page: https://clj-commons.org/marginalia/
At the moment Marg is compiled to provide a -main entry point, but I think it should act as a pure library only. We should create a whole new project that creates a command-line runnable Marg.
http://jedahu.github.com/story/
This fellow wrote this this litte tool over the last week. Very, very cool. It is similar to marginalia but is language-agnostic (or so I hear). I really like docs it generates, particularly the outline on the left combined with the code outline on the right. Just throwing this out here, since there are a lot of great ideas there that Marginalia could probably benefit from.
Thoughts?
When running from the marginalia jarfile, I get errors for each resource:
Could not locate resources at ./resources/shCore.css
... attempting to fix.
STILL could not locate resources at ./resources/./resources/shCore.css. Giving up!
Setting *resources*
to "" fixes the issue for me.
lein marg blows up if there is a 0.3.1 hiccup jar i libs.
Marg currently processes each file in turn generating the docs in order. However, it would be nice to allow the specification of a documentation header that is always placed at the top of the documentation. This could be a license statement, logo, manifesto, etc. I'm not sure how this would look at the moment, so any suggestions are welcomed.
Marginalia seems to be evaluating macros. This can be problematic.
Docstrings allow code blocks, like
(defn x
"## Code block in docstring
$ verbatim
$ code" [])
This doesn't currently work in comments, such that
;; ## Code block in comment
;; $ verbatim
;; $ code
Source here: https://github.com/jedahu/watcher/blob/master/src/me/panzoo/watcher.clj
Output here: http://jedahu.github.com/watcher/uberdoc.html
No docstrings make it into the margin except the namespace one.
I am using 0.7.0-SNAPSHOT, specifically checkout 0374c22....
The function 'parse-bool' at https://github.com/brehaut/necessary-evil/blob/master/src/necessary_evil/value.clj#L38-41
(defn parse-bool [v] (condp = (.trim (text v))
"0" false
"1" true
"throw exception here"))
is being output in the uberdoc.html with the following as a verbatim code block in the doc column beside an abbreviated piece code:
|
|
When generating the uberdoc for the following test case
(ns test-marg.core)
(defn ^:private private-fn "private docstring" [])
(defn public-fn "docstring" []
(let [x (private-fn)]
(count x)))
I get a
java.lang.RuntimeException: java.lang.IllegalArgumentException: Unable to resolve classname: :private
Even though the doc gets generated, the docstring for the public-fn is not shifted to the left.
The above snipped seems to be the minimal form to get that error, every one of:
makes it go away.
There a small problem with the new parser with multi-methods. When the methods are defined in the same namespace as the defmulti, they are given its docstring.
I tried to run marginalia (via lein marg
), but I noticed that most of my docstrings aren't even recognised. Further inspection showed that nothing after the namespace gets used. Then I downloaded the jar file, and tried to see if there are any errors, but there weren't.
So in the end, I ended up writing a test case.
Assuming we have a project.clj
like the following:
(defproject test "0.0.1-SNAPSHOT"
:description "Marginalia test case"
:dependencies [[clj-time "0.3.0"]]
:dev-dependencies [[lein-marginalia "0.6.0"]]
)
And we have the following in src/test/core.clj
:
(ns test.core
"A docstring for the namespace, this will be on the left."
(:require [clj-time.format :as tf]))
(defn a-function "A description, which should be on the left, but isn't."
[x]
(* x x))
Then running lein marg
will result in an uberdoc that has the a-function
docstring on the right, with the code.
So far, I could reproduce this with (:require [clj-time.format :as tf])
, and (:require [clj-time.coerce :as tc])
(and even without the :as
), but not with - for example - (:require [clojure.contrib.str-utils2 :as s])
.
A suggestion to look for a :marg property in project.clj to specify an ordering of namespaces to render override, e.g.:
:marg [org.foo.z.core org.foo.y.help org.foo.x.util]
would result in namespaces being rendered in the marg doc in that order, instead of in (sort) order as returned by find-clojure-file-paths
see title
Docs say,
"After executing lein deps you can generate your complete source documentation with the command: lein marg"
Yet I get:
$ lein deps # This is a redo, the first pass pulled a bunch of stuff down...
Copying 6 files to /Users/jacobsen/Desktop/clojure/test-marginalia/lib
$ lein marg
That's not a task. Use "lein help" to list all tasks.
$
Perhaps I'm doing something wrong tho...
After all, the defmethod handling isn't correct! I've got a method simply returning a string:
(defmethod compile [::standard AutoIncClause]
[_]
"GENERATED ALWAYS AS IDENTITY")
It get removed by Marginalia, here's the result:
(defmethod compile [::standard AutoIncClause]
[_])
The method really don't have docstring at all, so it's better to leave them alone. The question about how to handle them is still alive!
This error happens when I add :dev-dependencies [[marginalia "0.5.0"]]
to my project: java.lang.Exception: Unable to resolve symbol: with-base-url in this context
More precisely, the error happens when I (:use [hiccup.middleware :only (wrap-base-url)])
in the context of a project that depends on marginalia.
I've been able to reproduce the issue on weavejester/compojure-example
, which is a Hello World project with compojure and hiccup. I have forked his repo to get you a good starting point, and added marginalia to it. Please have a look:
My fork of weavejester/compojure-example
The issue seems to be due to a conflict between two different versions of hiccup. I quickly tried excluding hiccup from marginalia, to no avail:
[marginalia "0.5.0" :exclusions [hiccup.core/with-base-url]]
I'm pretty sure I'm not far from the solution, but I thought you may already know how to handle this.
I have multimethod calls that use :: type keywords, so I can do this:
;; multimethod definition
(ns sandbox.multi)
(def impls (atom {}))
(defmulti foo (fn [arg] (@impls arg)))
(defn set-impl! [arg impl] (swap! impls assoc arg impl))
;; multimethod implementation
(ns sandbox.backend
(:use sandbox.multi))
(defmethod foo ::backend [arg] (println "backend:" arg))
;; binding namespace for multi and backend
(ns sandbox.core
(:require [sandbox.multi :as multi]
[sandbox.backend :as backend])
(:gen-class))
(defn init []
(multi/set-impl! :user ::backend/backend)
(multi/foo :user))
When feeding this code to marginalia, I get a multitude of reader errors "Invalid token: ::backend/backend", which is weird since the reader is able to parse it within the context of the namespace where it is called:
sandbox.core=> (read-string "::backend/backend") :sandbox.backend/backend
Even more disturbing is that using the full namespace notation (:sandbox.backend/backend) unbreaks marginalia, which seems to stem from the fact that the reader accepts arbitrary namespaces for that notation, not for the :: notation:
sandbox.core=> (read-string ":sandbox.foo/bar") :sandbox.foo/bar sandbox.core=> (read-string "::foo/bar") java.lang.RuntimeException: java.lang.Exception: Invalid token: ::foo/bar (NO_SOURCE_FILE:0)
The good news: I got m. to run using "java -jar marginalia-0.5.0-standalone.jar" in the root directory of my Lein project, using the standalone jar-with-dependencies.
Bad news 1: it displayed some errors (though I got my .html file):
macscooter:infwb gw$ ls
README project.clj
classes project.clj~
deleteme.txt src
lib test
marginalia-0.5.0-standalone.jar
macscooter:infwb gw$ java -jar marginalia-0.5.0-standalone.jar
Generating uberdoc for the following source files:
/Users/gw/tech/clojurestuff/cljprojects/infwb/./src/infwb/cards.clj
/Users/gw/tech/clojurestuff/cljprojects/infwb/./src/infwb/core.clj
/Users/gw/tech/clojurestuff/cljprojects/infwb/./src/infwb/infocard.clj
/Users/gw/tech/clojurestuff/cljprojects/infwb/./src/infwb/sedna.clj
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: clojure.lang.LispReader$ReaderException: java.lang.Exception: Unmatched delimiter: )
at clojure.lang.LazySeq.sval(LazySeq.java:47)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:450)
at clojure.core$seq.invoke(core.clj:122)
at clojure.core$apply.invoke(core.clj:540)
at hiccup.core$render_html.invoke(core.clj:107)
FYI, I couldn't find any unmatched parens in my source code; each file compiled OK.
Bad news 2: I couldn't run M. using "lein marg". "lein deps" ran OK, adding hiccup-0.3.0.jar, markdownj-0.3.0-1.0.2b4.jar, and marginalia-0.5.0.jar to my project's lib/dev folder, but when I ran "lein marg", I got the following:
macscooter:infwb gw$ lein marg
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodError: clojure.lang.KeywordLookupSite.<init>(ILclojure/lang/Keyword;)V
at clojure.lang.Compiler.eval(Compiler.java:6212)
at clojure.lang.Compiler.eval(Compiler.java:6191)
at clojure.lang.Compiler.eval(Compiler.java:6168)
at clojure.core$eval.invoke(core.clj:2680)
at clojure.main$eval_opt.invoke(main.clj:231)
at clojure.main$initialize.invoke(main.clj:250)
at clojure.main$null_opt.invoke(main.clj:283)
at clojure.main$main.doInvoke(main.clj:361)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at clojure.lang.Var.invoke(Var.java:405)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.Var.applyTo(Var.java:518)
at clojure.main.main(main.java:37)
Caused by: java.lang.NoSuchMethodError: clojure.lang.KeywordLookupSite.<init>(ILclojure/lang/Keyword;)V
at hiccup.core$not_hint_QMARK_.<clinit>(core.clj:110)
at hiccup.core__init.load(Unknown Source)
at hiccup.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.loadClassForName(RT.java:1817)
at clojure.lang.RT.load(RT.java:399)
at clojure.lang.RT.load(RT.java:381)
at clojure.core$load$fn__4388.invoke(core.clj:5306)
at clojure.core$load.doInvoke(core.clj:5305)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at clojure.core$load_one.invoke(core.clj:5130)
at clojure.core$load_lib.doInvoke(core.clj:5167)
at clojure.lang.RestFn.applyTo(RestFn.java:143)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$load_libs.doInvoke(core.clj:5201)
at clojure.lang.RestFn.applyTo(RestFn.java:138)
at clojure.core$apply.invoke(core.clj:604)
at clojure.core$use.doInvoke(core.clj:5281)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at marginalia.html$loading__4410__auto__.invoke(html.clj:1)
at marginalia.html__init.load(Unknown Source)
at marginalia.html__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.loadClassForName(RT.java:1817)
at clojure.lang.RT.load(RT.java:399)
at clojure.lang.RT.load(RT.java:381)
at clojure.core$load$fn__4388.invoke(core.clj:5306)
at clojure.core$load.doInvoke(core.clj:5305)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at clojure.core$load_one.invoke(core.clj:5130)
at clojure.core$load_lib.doInvoke(core.clj:5167)
at clojure.lang.RestFn.applyTo(RestFn.java:143)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$load_libs.doInvoke(core.clj:5205)
at clojure.lang.RestFn.applyTo(RestFn.java:138)
at clojure.core$apply.invoke(core.clj:604)
at clojure.core$use.doInvoke(core.clj:5281)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at marginalia.core$loading__4410__auto__.invoke(core.clj:34)
at marginalia.core__init.load(Unknown Source)
at marginalia.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.loadClassForName(RT.java:1817)
at clojure.lang.RT.load(RT.java:399)
at clojure.lang.RT.load(RT.java:381)
at clojure.core$load$fn__4388.invoke(core.clj:5306)
at clojure.core$load.doInvoke(core.clj:5305)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at clojure.core$load_one.invoke(core.clj:5130)
at clojure.core$load_lib.doInvoke(core.clj:5167)
at clojure.lang.RestFn.applyTo(RestFn.java:143)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$load_libs.doInvoke(core.clj:5201)
at clojure.lang.RestFn.applyTo(RestFn.java:138)
at clojure.core$apply.invoke(core.clj:602)
at clojure.core$require.doInvoke(core.clj:5270)
at clojure.lang.RestFn.invoke(RestFn.java:409)
at user$eval1.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:6201)
... 12 more
macscooter:infwb gw$
I couldn't discern anything from the error message or from Googling the missing class name.
Thanks for any ideas anyone might have.
My project.clj looks a bit like:
;; Pick up special frobbing
(require 'mine.frob)
(defproject flib
(frob/twiggle)
"Flib at high speed"
...)
And I would love to use marginalia but it chokes on my project.clj! :( Sadness.
The underscores are replaced with spaces in output.
There are a bunch of examples in my Ororo documentation. In hourly-seven-day
, the :hourly forecast
part is actually :hourly_forecast
. This happens everywhere.
Since Clojure 1.3, def
itself allows for inline docstrings just like defn
. Marginalia doesn't parse them yet, it seems.
The first time I've run lein test
it threw:
Could not locate hiccup/core__init.class or hiccup/core.clj on classpath
although Hiccup was in there, now I'm getting:
Unable to resolve var: clojure.test/*test-out* in this context
on http://fogus.me/fun/marginalia/
under marginalia.tasks, the highlighting seems to be wrong. I don't think that "to your" should be highlighted.
This ties marginalia needlessly to lein or cake. It excludes maven, gradle and other build systems.
This will generate proper docs:
(ns foo.bar
"This is a ns docstring"
{:author "Fogus"})
(defprotocol Foo
"This is a proto docstring"
(foo [this]))
This will fail to gen proper docs:
(ns foo.bar
"This is a ns docstring")
(defprotocol Foo
"This is a proto docstring"
(foo [this]))
The problem is that the parser assume that the doc-able thing has some sort of body after the doc, but that is not always the case for ns
.
There are other project fields which would be nice to have parsed. For instance, :description, :license, :mailing-list, :min-lein-version. Some of these fields are nested as well.
At the top of each files in my open source project, there's a copyright and licence notice. Normally I use two semicolon before each lines, in which case it's copied in the docs panel. With only one semicolon it appears in the code panel. Is there a way to hide this notice from Marginalia output? If not I would propose to simple ignore continuous lines of comments using only one semicolon at the top of the file.
So there's got to be a better way to pull docstrings than http://goo.gl/SwHd3.
I'm going to explore using the reader, similar to the way that clojure.repl/source-fn (http://goo.gl/9kANa) works, which then might also be used as the basis of parsing for code-text & docs-text. Unfortunately, my hunch is that comments are just dropped on the floor by LineNumberingPushbackReader, but there might be a way around this.
Thoughts on this or alternative strategies?
The function ->str is being htmlified as ->str
Midje uses => as part of its syntax. Source code like this:
(greater 2 1) => truthy)
... produces this:
(greater 2 1) => truthy)
... which renders as this:
(greater 2 1) => truthy)
I may have presented you with a really annoying special case.
Here's some code that provokes the problem:
(ns basic.core
(:use midje.sweet))
(defn greater [a b]
(>= a b))
(fact
(greater 2 1) => truthy)
Deftypes can have docstrings: http://clojuredocs.org/clojure_contrib/clojure.contrib.types/deftype
But they don't seem to get picked up by marginalia
example: https://gist.github.com/970070
When trying to generate uberdoc for a project that doesn't depend on the monolithic contrib, marginalia fails.
I believe the project.clj should have a :dependency on clojure.contrib (used in core and parser).
In block comments ->
gets replaced with →
(good!), which in turn gets escaped into &arr;
(bad!).
Marginalia 0.5.0, Leiningen 1.4.2 (Java 1.6.0_24), Clojure 1.2.
How to reproduce:
;; something -> something
lein marg
something &rarr; something
Backslashes in docstrings are not output properly and cause the docstring to remain in the code pane.
I've been running off of master for a while now and see no major issues. Has anyone else been using it?
Marg should be able to parse and output docs for a project's tests. This could be via a flag as it's might not be needed by default.
:F
I've finally pinned this down! I'm using marginalia on a cascalog project, which requires that some custom operations be defined like this, with a vector instead of a symbol in the normal symbol position. (This is required for cascalog to allow static arguments as well as dynamic arguments.)
(defbufferop [sparse-vec [length missing-val]]
[tuples]
[[(sparse-vector length missing-val tuples)]])
If I run marginalia on any namespace containing some definition like this, I get this error:
Caused by: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.Symbol
Would be it be possible to catch that exception for cases like this?
Thanks a lot, guys!
Sam
I see there's a some unused code, starting with the global vars at the top of the core namespace. Is this for upcoming features or shall someone clean-up the code? I can volunteer myself to clean-up and add some unit tests.
With 0.5.0-alpha, a source code file shown below causes an exception
Caused by: java.lang.IllegalArgumentException: Duplicate key: false
at clojure.lang.PersistentArrayMap.createWithCheck(PersistentArrayMap.java:70)
at clojure.lang.RT.map(RT.java:1039)
at clojure.lang.LispReader$MapReader.invoke(LispReader.java:1006)
at clojure.lang.LispReader.readDelimitedList(LispReader.java:1051)
at clojure.lang.LispReader$ListReader.invoke(LispReader.java:900)
at clojure.lang.LispReader.read(LispReader.java:145)
... 54 more
my_ns.clj
(ns my-ns)
(def default-config
{;; Comment 1
:str "string"
;; Comment 2
;; comment
:registrations_closed false
:debug false})
I'm trying to run Marginalia over Noir (https://github.com/ibdknox/noir/) and get the following exception once it tries to build the TOC:
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Symbol (NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:5440)
at clojure.lang.Compiler.eval(Compiler.java:5415)
at clojure.lang.Compiler.eval(Compiler.java:5391)
at clojure.core$eval.invoke(core.clj:2382)
at clojure.main$eval_opt.invoke(main.clj:235)
at clojure.main$initialize.invoke(main.clj:254)
at clojure.main$null_opt.invoke(main.clj:279)
at clojure.main$main.doInvoke(main.clj:354)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:369)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:482)
at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Symbol
at clojure.lang.LazySeq.sval(LazySeq.java:47)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.boundedLength(RT.java:1186)
at clojure.lang.RestFn.applyTo(RestFn.java:130)
at clojure.core$apply.invoke(core.clj:540)
at hiccup.core$fn__42.invoke(core.clj:100)
at clojure.lang.MultiFn.invoke(MultiFn.java:163)
at clojure.lang.Var.invoke(Var.java:365)
at marginalia.html$toc_html.invoke(html.clj:178)
at marginalia.html$uberdoc_html.invoke(html.clj:390)
at marginalia.core$uberdoc_BANG_.invoke(core.clj:183)
at marginalia.core$run_marginalia.invoke(core.clj:235)
at user$eval5.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 12 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Symbol
at clojure.lang.LazySeq.sval(LazySeq.java:47)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:450)
at clojure.core$seq.invoke(core.clj:122)
at clojure.core$map$fn__3699.invoke(core.clj:2088)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
... 26 more
Caused by: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Symbol
at clojure.lang.LazySeq.sval(LazySeq.java:47)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:450)
at clojure.core$seq.invoke(core.clj:122)
at clojure.core$map$fn__3699.invoke(core.clj:2088)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
... 31 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Symbol
at clojure.core$find_ns.invoke(core.clj:3180)
at marginalia.parser$extract_common_docstring.invoke(parser.clj:109)
at marginalia.parser$fn__1611.invoke(parser.clj:168)
at clojure.lang.MultiFn.invoke(MultiFn.java:172)
at marginalia.parser$extract_docstring.invoke(parser.clj:174)
at marginalia.parser$arrange_in_sections.invoke(parser.clj:235)
at marginalia.parser$parse.invoke(parser.clj:254)
at marginalia.parser$parse_file.invoke(parser.clj:260)
at marginalia.core$path_to_doc.invoke(core.clj:164)
at clojure.core$map$fn__3699.invoke(core.clj:2096)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
... 36 more
Any thoughts?
"" is missing from `(binding [marginalia.html/resources ""] in marg function at http://fogus.me/fun/marginalia/#leiningen.marg
If a function contains either "<" or ">", the Marginalia layout becomes broken. If an open bracket is used, then the function doesn't have line breaks, printing only on one line. If a closed bracket is used, it breaks the overall layout.
Most telling, if a function contains an open and a closed bracket like "", then the layout is fine. I imagine this is an issue of using HTML-encoded entities instead of actual "<" and ">" in the output.
If I find time I'll try to supply a patch, but it's more likely that someone else is better for the job.
Marg will take wildcard arguments as below:
java -jar marginalia.jar src/trammel/factors.clj src/**/*
And will generate factors.clj
first, followed by the rest, including factors.clj
again. We should filter out duplicate filenames before generating the docs.
With the latest fix for the parser, it now has been improved to handle top-level versus nested comments. For the moment, it leaves them untouched. I wonder if we could make Marginalia do something clever with them, any suggestions?
Can you elaborate a little on your to-do items, as listed in the README?
* paragraph anchors
* options for non-uber-docs
* Maven generation support
* POM parsing
If I have some spare time this month, I'd like to work on some of these. I'd just want to make sure I was producing something like the results you desire.
I noticed that if I have code that is really long, the page will try to render all of the code and thus make the docs side (on the left) really narrow. It's pretty hideous. It looks like docco keeps the left side fixed. As a result, code may walk off of the screen on the right, but I think that is a more appropriate thing to do in this case.
Thoughts?
This should be fully parsed by Marg:
(defprotocol Foo
"This is a protocol docstring. It should be
presented on the LHS doc view"
(bar [this]
"This is a protocol signature docstring. It too
should be on the LHS doc view")
(baz [this]
[this that]
"This is another proto docstring following
>1 argument signatures. It too should be on
the LHS doc view"))
In order to clearly identify the project in the generated content, please add the project name to the page title.
The generated page has a fixed title of "Marginalia Output" at the moment.
The meta "description" could also be set to the project description.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.