Nunjucks Powers Mozilla

    commonform-html

    6.0.0 • Public • Published

    commonform-html

    render Common Forms in HTML

    const html = require('commonform-html')

    Call the exported function with a Common Form, receive a string of HTML:

    const assert = require('assert')
    
    assert.deepStrictEqual(
      html({ content: ['Just a test'] }),
      '<div class="article"><p>Just a test</p></div>'
    )
    
    assert.deepStrictEqual(
      html({
        content: [
          {
            heading: 'A',
            form: { content: ['This is A'] }
          },
          {
            heading: 'B',
            form: { content: ['This is B'] }
          }
        ]
      }),
      [
        '<div class="article">',
        '<div class="section">',
        '<h1>A</h1>',
        '<p>This is A</p>',
        '</div>',
        '<div class="section">',
        '<h1>B</h1>',
        '<p>This is B</p>',
        '</div>',
        '</div>'
      ]
        .join('')
    )

    You can also pass an Array of fill-in-the-blank values:

    assert.deepStrictEqual(
      html(
        {
          content: [
            { blank: '' },
            { form: { content: ['Another ', { blank: '' }] } }
          ]
        },
        [
          { blank: ['content', 0], value: 'Joe' },
          { blank: ['content', 1, 'form', 'content', 1], value: 'Bob' }
        ]
      ),
      (
        '<div class="article">' +
          '<p><span class="blank">Joe</span></p>' +
          '<div class="section">' +
            '<p>Another <span class="blank">Bob</span></p>' +
          '</div>' +
        '</div>'
      )
    )

    A final argument of { html5: true } specifies HTML5 output:

    assert.deepStrictEqual(
      html({ content: ['Just a test'] }, [], { html5: true }),
      '<article><p>Just a test</p></article>'
    )
    
    assert.deepStrictEqual(
      html(
        {
          content: [
            'First text defines a ',
            { definition: 'Term' },
            {
              heading: 'A',
              form: { content: ['This is A'] }
            },
            'Middle text uses a ',
            { use: 'Term' },
            {
              heading: 'B',
              form: { content: ['This is B'] }
            },
            'Last text references ',
            { reference: 'Elsewhere' }
          ]
        },
        [],
        { html5: true }
      ),
      [
        '<article>', // not <div class="article">
        '<p>',
        'First text defines a ',
        '<dfn>Term</dfn>', // not <span class="definition">
        '</p>',
        '<section>', // not <div class="section">
        '<h1>A</h1>',
        '<p>This is A</p>',
        '</section>',
        '<p>',
        'Middle text uses a ',
        '<span class="term">Term</span>',
        '</p>',
        '<section>',
        '<h1>B</h1>',
        '<p>This is B</p>',
        '</section>',
        '<p>',
        'Last text references ',
        '<span class="reference">Elsewhere</span>',
        '</p>',
        '</article>'
      ]
        .join('')
    )

    The option { lists: true } renders any series of forms without headings as an ordered list:

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'First-Level Heading',
              form: {
                content: [
                  'Here comes a list.',
                  { form: { content: ['Apple'] } },
                  { form: { content: ['Orange'] } },
                  'And another one!',
                  {
                    form: {
                      content: [
                        'Red',
                        { form: { content: ['Red-Orange'] } },
                        { form: { content: ['Red-Yellow'] } }
                      ]
                    }
                  },
                  { form: { content: ['Purple'] } },
                  {
                    form: {
                      content: [
                        { form: { content: ['More'] } },
                        { form: { content: ['Even More'] } }
                      ]
                    }
                  },
                  'Last text!'
                ]
              }
            }
          ]
        },
        [],
        { html5: true, lists: true }
      ),
      [
        '<article>',
        '<section>',
        '<h1>First-Level Heading</h1>',
        '<p>Here comes a list.</p>',
        '<ol>',
        '<li><p>Apple</p></li>',
        '<li><p>Orange</p></li>',
        '</ol>',
        '<p>And another one!</p>',
        '<ol>',
        '<li>',
        '<p>Red</p>',
        '<ol>',
        '<li><p>Red-Orange</p></li>',
        '<li><p>Red-Yellow</p></li>',
        '</ol>',
        '</li>',
        '<li><p>Purple</p></li>',
        '<li>',
        '<ol>',
        '<li><p>More</p></li>',
        '<li><p>Even More</p></li>',
        '</ol>',
        '</li>',
        '</ol>',
        '<p>Last text!</p>',
        '</section>',
        '</article>'
      ]
        .join('')
    )

    The option { ids: true } renders headings and references with IDs:

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'First Heading',
              form: {
                content: [
                  'first heading content'
                ]
              }
            },
            {
              heading: 'Second Heading',
              form: {
                content: [
                  'reference to ',
                  { reference: 'First Heading' }
                ]
              }
            }
          ]
        },
        [],
        { html5: true, ids: true }
      ),
      [
        '<article>',
        '<section>',
        '<h1 id="first-heading">First Heading</h1>',
        '<p>first heading content</p>',
        '</section>',
        '<section>',
        '<h1 id="second-heading">Second Heading</h1>',
        '<p>reference to <a class="reference" href="#first-heading">First Heading</a></p>',
        '</section>',
        '</article>'
      ]
        .join('')
    )

    You can also set a title, version, or both:

    assert.deepStrictEqual(
      html(
        { content: ['Hello, ', { blank: '' }] },
        [{ blank: ['content', 1], value: 'Joe' }],
        { title: 'Welcome' }
      ),
      [
        '<div class="article">',
        '<h1>Welcome</h1>',
        '<p>',
        'Hello, <span class="blank">Joe</span>',
        '</p>',
        '</div>'
      ]
        .join('')
    )
    
    assert.deepStrictEqual(
      html(
        { content: ['Hello, ', { blank: '' }] },
        [{ blank: ['content', 1], value: 'Joe' }],
        { title: 'Welcome', version: '1.0.0' }
      ),
      [
        '<div class="article">',
        '<h1>Welcome</h1>',
        '<p class="version">1.0.0</p>',
        '<p>',
        'Hello, <span class="blank">Joe</span>',
        '</p>',
        '</div>'
      ]
        .join('')
    )

    Set options.hash to print the form hash at the top:

    assert.deepStrictEqual(
      html(
        { content: ['Hello, ', { blank: '' }] },
        [{ blank: ['content', 1], value: 'Joe' }],
        { title: 'Welcome', version: '1.0.0', hash: true }
      ),
      [
        '<div class="article">',
        '<h1>Welcome</h1>',
        '<p class="version">1.0.0</p>',
        '<p class="hash"><code>' +
          'd36c54da27de611b3a9ce7d08638bbd2' +
          '00cf5f3bb41d59320d04bba02ca48f85' +
          '</code></p>',
        '<p>',
        'Hello, <span class="blank">Joe</span>',
        '</p>',
        '</div>'
      ]
        .join('')
    )

    The option { classNames: ["test"] } adds custom class names to the root element.

    assert.deepStrictEqual(
      html(
        { content: ['Hello, Joe.'] },
        [],
        { classNames: ['test'] }
      ),
      [
        '<div class="article test">',
        '<p>',
        'Hello, Joe.',
        '</p>',
        '</div>'
      ]
        .join('')
    )
    
    assert.deepStrictEqual(
      html(
        { content: ['Hello, Joe.'] },
        [],
        { html5: true, classNames: ['test'] }
      ),
      [
        '<article class="test">',
        '<p>',
        'Hello, Joe.',
        '</p>',
        '</article>'
      ]
        .join('')
    )

    The option { depth: n } demotes all headings by n levels. For example, { depth: 1 } demotes <h1>s to <h2>s, and so on.

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'A',
              form: { content: ['This is A'] }
            },
            {
              heading: 'B',
              form: { content: ['This is B'] }
            }
          ]
        },
        [],
        { depth: 2 }
      ),
      [
        '<div class="article">',
        '<div class="section">',
        '<h3>A</h3>',
        '<p>This is A</p>',
        '</div>',
        '<div class="section">',
        '<h3>B</h3>',
        '<p>This is B</p>',
        '</div>',
        '</div>'
      ]
        .join('')
    )

    Set options.smartify to replace ASCII punctuation with Unicode punctuation:

    assert.deepStrictEqual(
      html(
        { content: [{ use: 'Purchaser' }, "'s address is ", { blank: '' }] },
        //                                  ^ straight
        [],
        { smartify: true }
      ),
      [
        '<div class="article">',
        '<p>',
        '<span class="term">Purchaser</span>’s ',
        //                                  ^ curly
        'address is ',
        '<span class="blank">[•]</span>',
        '</p>',
        '</div>'
      ]
        .join('')
    )

    The option { annotations: [] } renders annotations in context.

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'A',
              form: { content: ['This is A'] }
            },
            {
              heading: 'B',
              form: { content: ['This is B'] }
            },
            {
              heading: 'C',
              form: {
                content: [
                  { form: { content: ['1'] } },
                  { form: { content: ['2'] } },
                  { form: { content: ['3'] } }
                ]
              }
            }
          ]
        },
        [],
        {
          lists: true,
          annotations: [
            {
              path: ['content', 0, 'form', 'content', 0],
              level: 'info',
              message: 'Annotation to A.'
            },
            {
              path: ['content', 1, 'form', 'content', 0],
              level: 'error',
              message: 'Annotation to B.'
            },
            {
              path: ['content', 2, 'form', 'content', 1, 'form', 'content', 0],
              level: 'error',
              message: 'Annotation to 2.'
            }
          ]
        }
      ),
      [
        '<div class="article">',
        '<div class="section">',
        '<h1>A</h1>',
        '<div class="annotation info"><p>Annotation to A.</p></div>',
        '<p>This is A</p>',
        '</div>',
        '<div class="section">',
        '<h1>B</h1>',
        '<div class="annotation error"><p>Annotation to B.</p></div>',
        '<p>This is B</p>',
        '</div>',
        '<div class="section">',
        '<h1>C</h1>',
        '<ol>',
        '<li><p>1</p></li>',
        '<li>',
        '<div class="annotation error"><p>Annotation to 2.</p></div>',
        '<p>2</p>',
        '</li>',
        '<li><p>3</p></li>',
        '</ol>',
        '</div>',
        '</div>'
      ]
        .join('')
    )

    With { html5: true }, annotations render as <aside>s.

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'A',
              form: { content: ['This is A'] }
            },
            {
              heading: 'B',
              form: { content: ['This is B'] }
            },
            {
              heading: 'C',
              form: {
                content: [
                  { form: { content: ['1'] } },
                  { form: { content: ['2'] } },
                  { form: { content: ['3'] } }
                ]
              }
            }
          ]
        },
        [],
        {
          html5: true,
          lists: true,
          annotations: [
            {
              path: ['content', 0, 'form', 'content', 0],
              level: 'info',
              message: 'Annotation to A.'
            },
            {
              path: ['content', 1, 'form', 'content', 0],
              level: 'error',
              message: 'Annotation to B.'
            },
            {
              path: ['content', 2, 'form', 'content', 1, 'form', 'content', 0],
              level: 'error',
              message: 'Annotation to 2.'
            }
          ]
        }
      ),
      [
        '<article>',
        '<section>',
        '<h1>A</h1>',
        '<aside class="annotation info"><p>Annotation to A.</p></aside>',
        '<p>This is A</p>',
        '</section>',
        '<section>',
        '<h1>B</h1>',
        '<aside class="annotation error"><p>Annotation to B.</p></aside>',
        '<p>This is B</p>',
        '</section>',
        '<section>',
        '<h1>C</h1>',
        '<ol>',
        '<li><p>1</p></li>',
        '<li>',
        '<aside class="annotation error"><p>Annotation to 2.</p></aside>',
        '<p>2</p>',
        '</li>',
        '<li><p>3</p></li>',
        '</ol>',
        '</section>',
        '</article>'
      ]
        .join('')
    )

    Annotations to the root of the form appear just within the root element:

    const lint = require('commonform-lint')
    const form = { content: ['See ', { reference: 'Nonexistent' }] }
    const annotations = lint(form)
    assert.deepStrictEqual(
      html(form, [], {
        html5: true,
        lists: true,
        annotations: annotations
      }),
      [
        '<article>',
        '<aside class="annotation error">',
        '<p>The heading &quot;Nonexistent&quot; is referenced, but not used.</p>',
        '</aside>',
        '<p>See <span class="reference">Nonexistent</span></p>',
        '</article>'
      ]
        .join('')
    )

    Supports components:

    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              heading: 'License Grant',
              component: 'https://commonform.org/kemitchell/apache-style-license-grant',
              version: '1.0.0',
              substitutions: {
                terms: {
                  Licensor: 'Vendor',
                  Licensee: 'Customer',
                  Program: 'Software'
                },
                headings: {
                  'Express Warranties': 'Guarantees'
                },
                blanks: {
                  1: 'United States'
                }
              }
            }
          ]
        },
        [],
        {
          html5: true,
          lists: true,
          ids: true
        }
      ),
      [
        '<article>',
        '<section class="component">',
        '<h1 id="license-grant">License Grant</h1>',
        '<p>',
        'Incorporate ',
        '<a href="https://commonform.org/kemitchell/apache-style-license-grant/1.0.0">',
        'https://commonform.org/kemitchell/apache-style-license-grant/1.0.0',
        '</a>',
        ' substituting:',
        '</p>',
        '<ul>',
        '<li>the term <span class="term">Customer</span> for the term <span class="term">Licensee</span></li>',
        '<li>the term <span class="term">Vendor</span> for the term <span class="term">Licensor</span></li>',
        '<li>the term <span class="term">Software</span> for the term <span class="term">Program</span></li>',
        '<li>references to <a class="reference" href="#guarantees">Guarantees</a> for references to <span class="reference">Express Warranties</span></li>',
        '<li>"United States" for the first blank</li>',
        '</ul>',
        '</section>',
        '</article>'
      ]
        .join('')
    )
    
    assert.deepStrictEqual(
      html(
        {
          content: [
            {
              component: 'https://commonform.org/kemitchell/apache-style-license-grant',
              version: '1.0.0',
              substitutions: {
                terms: {
                  Licensor: 'Vendor',
                  Licensee: 'Customer',
                  Program: 'Software'
                },
                headings: {
                  'Express Warranties': 'Guarantees'
                },
                blanks: {
                  1: 'United States'
                }
              }
            }
          ]
        },
        [],
        {
          html5: true,
          lists: true,
          ids: true
        }
      ),
      [
        '<article>',
        '<ol>',
        '<li class="component">',
        '<p>',
        'Incorporate ',
        '<a href="https://commonform.org/kemitchell/apache-style-license-grant/1.0.0">',
        'https://commonform.org/kemitchell/apache-style-license-grant/1.0.0',
        '</a>',
        ' substituting:',
        '</p>',
        '<ul>',
        '<li>the term <span class="term">Customer</span> for the term <span class="term">Licensee</span></li>',
        '<li>the term <span class="term">Vendor</span> for the term <span class="term">Licensor</span></li>',
        '<li>the term <span class="term">Software</span> for the term <span class="term">Program</span></li>',
        '<li>references to <a class="reference" href="#guarantees">Guarantees</a> for references to <span class="reference">Express Warranties</span></li>',
        '<li>"United States" for the first blank</li>',
        '</ul>',
        '</li>',
        '</ol>',
        '</article>'
      ]
        .join('')
    )

    If you pass a form with resolved components labeled with appropriate metadata, you can specify one of three styles for rendering them specially:

    const formWithLoaded = {
      content: [
        {
          form: {
            content: [
              'Except under ', { reference: 'Warranties' },
              ', the ', { use: 'Vendor' },
              ' disclaimers all warranties to the ', { use: 'Customer' },
              ' related to the ', { use: 'Software' }, '.'
            ]
          },
          reference: {
            component: 'https://example.com/toy-disclaimer',
            version: '1.0.0',
            substitutions: {
              terms: {
                Seller: 'Vendor',
                Buyer: 'Customer',
                Product: 'Software'
              },
              headings: {
                Warranties: 'Quality Assurances'
              },
              blanks: {}
            }
          },
          component: {
            publisher: 'Example Publisher',
            name: 'Toy Disclaimer',
            version: '1.0.0'
          }
        }
      ]
    }
    
    assert.deepStrictEqual(
      html(formWithLoaded, [], {
        html5: true,
        lists: true,
        loadedComponentStyle: 'both' // reference and copy
      }),
      [
        '<article>',
        '<ol>',
        '<li class="component">',
        '<p>',
        'Incorporate ',
        '<a href="https://example.com/toy-disclaimer/1.0.0">Example Publisher Toy Disclaimer Version 1.0.0</a>',
        ' substituting:',
        '</p>',
        '<ul>',
        '<li>the term <span class="term">Customer</span> for the term <span class="term">Buyer</span></li>',
        '<li>the term <span class="term">Software</span> for the term <span class="term">Product</span></li>',
        '<li>the term <span class="term">Vendor</span> for the term <span class="term">Seller</span></li>',
        '<li>references to <span class="reference">Quality Assurances</span> for references to <span class="reference">Warranties</span></li>',
        '</ul>',
        '<p>Quoting for convenience, with any conflicts resolved in favor of the standard:</p>',
        '<blockquote>',
        '<p>',
        'Except under <span class="reference">Warranties</span>, ',
        'the <span class="term">Vendor</span> ',
        'disclaimers all warranties to the <span class="term">Customer</span> ',
        'related to the <span class="term">Software</span>.',
        '</p>',
        '</blockquote>',
        '</li>',
        '</ol>',
        '</article>'
      ]
        .join('')
    )
    
    assert.deepStrictEqual(
      html(formWithLoaded, [], {
        html5: true,
        lists: true,
        loadedComponentStyle: 'both',
        quoteComponentText: 'For reference:' // custom text between
      }),
      [
        '<article>',
        '<ol>',
        '<li class="component">',
        '<p>',
        'Incorporate ',
        '<a href="https://example.com/toy-disclaimer/1.0.0">Example Publisher Toy Disclaimer Version 1.0.0</a>',
        ' substituting:',
        '</p>',
        '<ul>',
        '<li>the term <span class="term">Customer</span> for the term <span class="term">Buyer</span></li>',
        '<li>the term <span class="term">Software</span> for the term <span class="term">Product</span></li>',
        '<li>the term <span class="term">Vendor</span> for the term <span class="term">Seller</span></li>',
        '<li>references to <span class="reference">Quality Assurances</span> for references to <span class="reference">Warranties</span></li>',
        '</ul>',
        '<p>',
        'For reference:', // here
        '</p>',
        '<blockquote>',
        '<p>',
        'Except under <span class="reference">Warranties</span>, ',
        'the <span class="term">Vendor</span> ',
        'disclaimers all warranties to the <span class="term">Customer</span> ',
        'related to the <span class="term">Software</span>.',
        '</p>',
        '</blockquote>',
        '</li>',
        '</ol>',
        '</article>'
      ]
        .join('')
    )
    assert.deepStrictEqual(
      html(formWithLoaded, [], {
        html5: true,
        lists: true,
        incorporateComponentText: 'Include',
        loadedComponentStyle: 'reference' // just reference
      }),
      [
        '<article>',
        '<ol>',
        '<li class="component">',
        '<p>',
        'Include ',
        '<a href="https://example.com/toy-disclaimer/1.0.0">Example Publisher Toy Disclaimer Version 1.0.0</a>',
        ' substituting:',
        '</p>',
        '<ul>',
        '<li>the term <span class="term">Customer</span> for the term <span class="term">Buyer</span></li>',
        '<li>the term <span class="term">Software</span> for the term <span class="term">Product</span></li>',
        '<li>the term <span class="term">Vendor</span> for the term <span class="term">Seller</span></li>',
        '<li>references to <span class="reference">Quality Assurances</span> for references to <span class="reference">Warranties</span></li>',
        '</ul>',
        '</li>',
        '</ol>',
        '</article>'
      ]
        .join('')
    )
    
    assert.deepStrictEqual(
      html(formWithLoaded, [], {
        html5: true,
        lists: true,
        loadedComponentStyle: 'copy'
      }),
      [
        '<article>',
        '<ol>',
        '<li class="component">',
        '<p>',
        'Except under <span class="reference">Warranties</span>, ',
        'the <span class="term">Vendor</span> ',
        'disclaimers all warranties to the <span class="term">Customer</span> ',
        'related to the <span class="term">Software</span>.',
        '</p>',
        '</li>',
        '</ol>',
        '</article>'
      ]
        .join('')
    )

    Keywords

    none

    Install

    npm i commonform-html

    DownloadsWeekly Downloads

    4

    Version

    6.0.0

    License

    BlueOak-1.0.0

    Unpacked Size

    38 kB

    Total Files

    5

    Last publish

    Collaborators

    • kemitchell