From a4f9babd484ad67b34e4d9c653f42158eceaef58 Mon Sep 17 00:00:00 2001 From: Eduardo Cuducos Date: Mon, 24 Aug 2020 18:18:33 -0400 Subject: [PATCH 1/3] [refactor][xs] Enhance remove empty lines function --- src/text.js | 18 ++++++++++++++---- test/fixtures/data-resource.md | 28 ---------------------------- test/text.test.js | 2 +- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/src/text.js b/src/text.js index cf70a0b..a009180 100644 --- a/src/text.js +++ b/src/text.js @@ -1,8 +1,18 @@ function removeExtraEmptyLines(text) { - let cleaned = text.trim(); - cleaned = cleaned.replace(/\n{3,}/gm, "\n\n"); // remove extra empty lines - cleaned += "\n"; // add new line at end of string - return cleaned; + const lines = text.split("\n"); + const cleaned = []; + + for (let idx = 0; idx < lines.length; idx++) { + let line = lines[idx].trim(); + let previous = cleaned[cleaned.length - 1] || ""; + + if (line == "" && previous == "") { + continue; // skip duplicate empty lines + } + cleaned.push(line); + } + + return cleaned.join("\n").trim() + "\n"; } export { removeExtraEmptyLines }; diff --git a/test/fixtures/data-resource.md b/test/fixtures/data-resource.md index b85e8a8..bc0dce6 100644 --- a/test/fixtures/data-resource.md +++ b/test/fixtures/data-resource.md @@ -15,11 +15,8 @@ Every Package and Resource descriptor has a profile. The default profile, if non ### Examples - `{"profile":"tabular-data-package"}` - - `{"profile":"http://example.com/my-profiles-json-schema.json"}` - - ## Name @@ -32,8 +29,6 @@ This is ideally a url-usable and human-readable name. Name `SHOULD` be invariant ### Example - `{"name":"my-nice-name"}` - - ## Path @@ -44,14 +39,10 @@ The dereferenced value of each referenced data source in `path` `MUST` be commen ### Examples - `{"path":["file.csv","file2.csv"]}` - - `{"path":["http://example.com/file.csv","http://example.com/file2.csv"]}` - - `{"path":"http://example.com/file.csv"}` - - ## Data @@ -72,8 +63,6 @@ A human-readable title. ### Example - `{"title":"My Package Title"}` - - ## Description @@ -84,8 +73,6 @@ A text description. Markdown is encouraged. ### Example - `{"description":"# My Package description\nAll about my package."}` - - ## Home Page @@ -96,8 +83,6 @@ The home on the web that is related to this data package. ### Example - `{"homepage":"http://example.com/"}` - - ## Sources @@ -108,8 +93,6 @@ The raw sources for this resource. ### Example - `{"sources":[{"title":"World Bank and OECD","path":"http://data.worldbank.org/indicator/NY.GDP.MKTP.CD"}]}` - - ## Licenses @@ -122,8 +105,6 @@ This property is not legally binding and does not guarantee that the package is ### Example - `{"licenses":[{"name":"odc-pddl-1.0","path":"http://opendatacommons.org/licenses/pddl/","title":"Open Data Commons Public Domain Dedication and License v1.0"}]}` - - ## Format @@ -136,8 +117,6 @@ The file format of this resource. ### Example - `{"format":"xls"}` - - ## Media Type @@ -148,8 +127,6 @@ The media type of this resource. Can be any valid media type listed with [IANA]( ### Example - `{"mediatype":"text/csv"}` - - ## Encoding @@ -160,8 +137,6 @@ The file encoding of this resource. ### Example - `{"encoding":"utf-8"}` - - ## Bytes @@ -172,8 +147,6 @@ The size of this resource in bytes. ### Example - `{"bytes":2082}` - - ## Hash @@ -184,6 +157,5 @@ The MD5 hash of this resource. Indicate other hashing algorithms with the {algor ### Examples - `{"hash":"d25c9c77f588f5dc32059d2da1136c02"}` - - `{"hash":"SHA256:5262f12512590031bbcc9a430452bfd75c2791ad6771320bb4b5728bfb78c4d0"}` diff --git a/test/text.test.js b/test/text.test.js index a539975..5393682 100644 --- a/test/text.test.js +++ b/test/text.test.js @@ -4,6 +4,6 @@ import { removeExtraEmptyLines } from "../src/text.js"; test("Can clean up extra empty lines from a string", (t) => { const expect = "0\n\n1\n\n2\n\n3\n4\n"; - const result = removeExtraEmptyLines("0\n\n\n\n1\n\n\n2\n\n3\n4"); + const result = removeExtraEmptyLines("0\n\n \n\n1\n\n\n2\n\n3\n4"); t.is(result, expect); }); From 5661af4365d1be3ac82c289ea0500f1538291ccf Mon Sep 17 00:00:00 2001 From: Eduardo Cuducos Date: Mon, 24 Aug 2020 18:19:16 -0400 Subject: [PATCH 2/3] [refactor][xs] Creates a macro/function to render an instance This allow us to call the template for a given property recursively, enabling us to imrpove towards nested fields. --- src/render.js | 10 ++++++---- src/template.md | 31 ------------------------------- src/templates/base.md | 12 ++++++++++++ src/templates/macros.md | 28 ++++++++++++++++++++++++++++ test/fixtures/data-resource.html | 22 +++++++++++----------- test/fixtures/data-resource.md | 22 +++++++++++----------- test/render.test.js | 8 ++++---- 7 files changed, 72 insertions(+), 61 deletions(-) delete mode 100644 src/template.md create mode 100644 src/templates/base.md create mode 100644 src/templates/macros.md diff --git a/src/render.js b/src/render.js index 65a62e3..ed86628 100644 --- a/src/render.js +++ b/src/render.js @@ -1,4 +1,4 @@ -import { dirname } from "path"; +import path from "path"; import { fileURLToPath } from "url"; import nunjucks from "nunjucks"; @@ -7,13 +7,15 @@ import showdown from "showdown"; import { removeExtraEmptyLines } from "./text.js"; // load converters & template engines -const srcDir = dirname(fileURLToPath(import.meta.url)); +const srcDir = path.dirname(fileURLToPath(import.meta.url)); +const templateDir = path.join(srcDir, "templates"); const sd = new showdown.Converter(); -const env = new nunjucks.Environment(new nunjucks.FileSystemLoader(srcDir)); +const loader = new nunjucks.FileSystemLoader(templateDir); +const env = new nunjucks.Environment(loader); env.addFilter("parseJson", JSON.parse); /// basic convertion functions -const toMarkDown = (schema) => env.render("template.md", schema); +const toMarkDown = (schema) => env.render("base.md", schema); const toHtml = (schema) => sd.makeHtml(toMarkDown(schema)); // helpers for the engine function below diff --git a/src/template.md b/src/template.md deleted file mode 100644 index 0a2c82f..0000000 --- a/src/template.md +++ /dev/null @@ -1,31 +0,0 @@ -# {{ title }} - -**(`{{ type }}`)** - -{{ description|safe }} - -{% for _, property in properties %} - -## {{ property.title }} - -{% if property.type %}**(`{{ property.type }}`)** {% endif %}{% if property.default %}Defaults to _{{ property.default }}_.{% endif %} - -{% if property.description %} -{{ property.description }} -{% endif %} - -{% if property.context %} -{{ property.context|safe }} -{% endif %} - -{% if property.examples %} - -### Example{% if property.examples.length > 1 %}s{% endif %} - -{% for example in property.examples %} - -- `{{ example|parseJson|dump|safe }}` - {% endfor %} - {% endif %} - -{% endfor %} diff --git a/src/templates/base.md b/src/templates/base.md new file mode 100644 index 0000000..a710d5d --- /dev/null +++ b/src/templates/base.md @@ -0,0 +1,12 @@ +{% import "macros.md" as macros %} +# {{ title }} + +**(`{{ type }}`)** + +{{ description|safe }} + +{% for _, property in properties %} + +{{ macros.instance(property, title=2) }} + +{% endfor %} diff --git a/src/templates/macros.md b/src/templates/macros.md new file mode 100644 index 0000000..856fe56 --- /dev/null +++ b/src/templates/macros.md @@ -0,0 +1,28 @@ +{% macro instance(property, level=2) %} + +{{ "#".repeat(level) }} {{ property.title }} + +{% if property.type %}**(`{{ property.type }}`)**{% endif %}{% if property.default %} Defaults to _{{ property.default }}_.{% endif %} + +{% if property.description %} +{{ property.description }} +{% endif %} + +{% if property.context %} +{{ property.context|safe }} +{% endif %} + +{% if property.examples %} +{% if property.examples.length > 1 %} + {% set example_section_title = "Examples" %} +{% else %} + {% set example_section_title = "Example" %} +{% endif %} +{{ "#".repeat(level + 1) }} {{ example_section_title }} + +{% for example in property.examples %} +- `{{ example|parseJson|dump|safe }}` +{% endfor %} + +{% endif %} +{% endmacro %} diff --git a/test/fixtures/data-resource.html b/test/fixtures/data-resource.html index e2b3b86..e522184 100644 --- a/test/fixtures/data-resource.html +++ b/test/fixtures/data-resource.html @@ -11,7 +11,7 @@

Examples

  • {"profile":"http://example.com/my-profiles-json-schema.json"}

  • Name

    -

    (string)

    +

    (string)

    An identifier string. Lower case characters with ., _, - and / are allowed.

    This is ideally a url-usable and human-readable name. Name SHOULD be invariant, meaning it SHOULD NOT change when its parent descriptor is updated.

    Example

    @@ -30,38 +30,38 @@

    Examples

    Data

    Inline data for this resource.

    Schema

    -

    (object)

    +

    (object)

    A schema for this resource.

    Title

    -

    (string)

    +

    (string)

    A human-readable title.

    Example

    Description

    -

    (string)

    +

    (string)

    A text description. Markdown is encouraged.

    Example

    Home Page

    -

    (string)

    +

    (string)

    The home on the web that is related to this data package.

    Example

    Sources

    -

    (array)

    +

    (array)

    The raw sources for this resource.

    Example

    Licenses

    -

    (array)

    +

    (array)

    The license(s) under which the resource is published.

    This property is not legally binding and does not guarantee that the package is licensed under the terms defined herein.

    Example

    @@ -69,7 +69,7 @@

    Example

  • {"licenses":[{"name":"odc-pddl-1.0","path":"http://opendatacommons.org/licenses/pddl/","title":"Open Data Commons Public Domain Dedication and License v1.0"}]}
  • Format

    -

    (string)

    +

    (string)

    The file format of this resource.

    csv, xls, json are examples of common formats.

    Example

    @@ -77,7 +77,7 @@

    Example

  • {"format":"xls"}
  • Media Type

    -

    (string)

    +

    (string)

    The media type of this resource. Can be any valid media type listed with IANA.

    Example

    Bytes

    -

    (integer)

    +

    (integer)

    The size of this resource in bytes.

    Example

    Hash

    -

    (string)

    +

    (string)

    The MD5 hash of this resource. Indicate other hashing algorithms with the {algorithm}:{hash} format.

    Examples