Skip to content

v2.0.0

Choose a tag to compare

@stamat stamat released this 28 Aug 10:12
· 3 commits to master since this release

npm install shortcodes.js pulled down a demo page, its Quill and Prism
wiring, a Sass build and — in 1.0.1 — an entire copy of book-of-spells, docs
and webfonts included. The package had no files field, and npm publishes
whatever is lying in the tree. The library was the smallest part of what you
got. The demo now lives in site/, the build in dist/, and the tarball
carries those two and nothing else: 10 files where 1.0.1 had 33. The library
itself ran only as that built IIFE: two variables were never declared, and
strict mode — every ES module — turned them into a ReferenceError on the
first shortcode that bound anything. Under that, the sorting ate content: a
sentence that mentioned a tag, a paragraph with a link in it.

Added

  • A descriptor is checked at register(). A key that is not one, or one
    from the old per-element api — extract_fn, bind_fn, extract_attr —
    extract: 'attr', bind_extracted: 'before', a count that is neither a
    number nor 'many', a repeater with no item_anchor: each gets a console
    line with the path and what it should be. A descriptor carried over from a
    single-file copy of the 2016–2023 years used to register fine and render
    nothing. Nothing throws; the descriptor is used as given.

Changed

  • main is dist/shortcodes.js. Resolution through main follows it, so
    bundlers and a bare unpkg.com/shortcodes.js are unaffected. A URL that
    spelled out the old root path — unpkg.com/shortcodes.js/shortcodes.js — is
    not.

  • The package is "type": "module". The source has always been ESM inside
    .js files, which is why the tests could only run through the esm shim,
    and that shim stopped working on current Node. require('shortcodes.js') now
    throws ERR_REQUIRE_ESM. main is a browser IIFE that assigns
    window.Shortcodes, so there was never anything to destructure off it.

  • book-of-spells is ^2.8.0, and attribute values arrive typed.
    parseAttributes returns 3 where it returned "3", false where it
    returned "false", and decodes HTML entities on the way, so
    background-image="…?a=1&b=2" reaches a parser with a real &. A
    custom attribute_parsers entry that assumed a string has to say so now.

  • @glidejs/glide is a devDependency. The library never imported it — only
    the demo page does. Installing shortcodes.js no longer drags Glide along.

  • A paragraph is a tag only when the tag is all it says. The tag was found
    anywhere in an element's text, so <p>My favourite is [hero] by far</p> was
    removed and a hero opened in its place. The sentence is content now; a tag
    stands on a line of its own.

  • A closing tag that closes nothing stays on the page. [/hero] after a
    [text] opened a second hero. It now closes the open shortcode, or stays
    put as content where the author sees it.

  • A wrapper is unwrapped only when the element is all it holds. Each key
    was searched for inside a paragraph, so <p>Read the <a>docs</a> first</p>
    reached the a entry as the link alone and the sentence was gone. It stays
    a paragraph now and goes to rest; <p><a>docs</a></p> is still the
    link, and a line break beside it does not count. Keys are tried in
    descriptor order as before, so <p><a><img></a></p> is still the image
    under a descriptor that lists img first.

  • In a repeater, count caps a key per item, not across items. count: 1
    on a title gave the first slide one and sent every later title to text. Each
    item now takes one element per key, and a repeat — a second image — starts
    the next item, as a subtag does.

  • A subtag after content starts a new item, and may name several classes.
    The first subtag only ever named the item already open, whatever it held.
    { red big } threw InvalidCharacterError on its way into the class list;
    it now sets both classes.

  • placement_class_prefix works. The option was read into the engine and
    never handed to the shortcode, so placement="left" always looked for
    .shortcode-landing-left. It now looks for .<prefix>-left. A site that
    passed the option and built its landings on the default prefix has to rename
    them, or drop the option.

  • shopify_full_size option, on by default. The _600x600 size Shopify's
    editor puts on an inserted image has always been stripped from the src
    bound to a template, unconditionally. It is an option now; false keeps the
    size the author picked.

Fixed

  • An attribute whose value types to 0 or false reaches its parser. The
    gate tested the value for truthiness, which was correct only while every
    value was a string. Under typed values, placement="0" and open="false"
    fell through to the class list and their parsers never ran. null is
    parseAttributes' mark for a valueless attribute, and that is what the gate
    tests now.

  • detachElement is imported from the package root. It was reached through
    book-of-spells/src/dom.mjs, a deep path into another package's internals
    that would break the day book-of-spells declares an exports map. It has
    been exported from the root since 1.0.4.

  • The published main bundle is built from the current source. It had been
    committed two commits behind src/, so the bundle was missing isEmpty and
    anyone using the package through main got older code than anyone using
    module.

  • The module entry runs. Two variables were never declared, which the
    built IIFE let slide as globals and strict mode did not: the first shortcode
    with a bind_extracted threw ReferenceError: finalDestination is not defined, and any repeater ReferenceError: res is not defined. A bundler
    resolves module first, so a bundled shortcodes.js could not render a
    thing. A test now runs the demo page through the source.

  • Relative imports name their .js. The source imported ./lib/parsers
    without an extension, which a bundler resolves and a browser or Node does
    not — a <script type="module"> importing it failed with
    ERR_MODULE_NOT_FOUND.

  • An object in extract works. Both the { name, extract_fn } and the
    { name: 'style', properties } forms threw ReferenceError: hasOwnProperties is not defined; past that, the style form compared the
    wrong thing and never returned a style.

  • parse_extracted given as a function is called. It was looked up under
    the wrong name and threw TypeError: props.parse is not a function.

  • An element entry without extract renders. It threw TypeError: Cannot read properties of undefined (reading 'length') while the content was
    collected. The entry is collected and binds nothing.

  • An element past its key's count is reported. A second image under a
    hero that takes one was left where it stood and nothing said so — a missing
    picture with no trace. It is still left in place, and the console now says
    which shortcode was full and which element stayed behind.

  • A missing template names its selector. TypeError: Cannot read properties of null (reading 'cloneNode') is now shortcodes.js: no template matches "section.nope".

  • placement="content" and a repeater work without a template. The
    anchor element was handed to querySelectorAll and threw SyntaxError; a
    repeater with no outer template threw ReferenceError: descriptor is not defined.

  • A top-level inline tag lands in rest, not in a key it is a substring
    of.
    Buckets were matched by tag name as a substring of the key, so a bare
    <i> counted as img and <b> as blockquote, and hit the cut-off when
    that key was full. Keys are selectors and are matched as such.

  • clear() removes the anchors of the class you configured. It removed
    .self-anchor whatever self_anchor_class said, so a custom class left one
    anchor behind per reinitialize.

  • Content comes back when a callback throws. execute() hides the source
    while it works and showed it again only on the way out the front door; a
    throwing pre or callback left the page blank.

  • A landing nothing matches is reported. placement="nowhere", an anchor
    the page lacks, an element anchor the template lacks or an item_anchor
    matching nothing rendered into the void without a word. The console now
    names the shortcode and the selector.

  • An attribute the source lacks is not written. bind_extracted: ['href', 'target'] on a link without a target wrote target="undefined", which
    opens a new tab — a window by that name. The attribute is skipped.

  • The first shortcode's anchor carries its -sc-0 class. The counter
    class was skipped for 0, so the first anchor on a page was
    self-anchor shortcode-hero and every later one had its number.

  • A src with a quote or a parenthesis in it still becomes a background.
    url(…) was built unquoted, so a ) ended it early and the style was
    dropped. It is quoted and escaped now, in the background-image attribute
    and in the style binder alike.

Full Changelog: v.1.0.1...v2.0.0