npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

netscape-bookmark-tree

v2.1.1

Published

Parse the NETSCAPE-Bookmark-file-1 format bookmarks exported by the browser and convert them into nested arrays.

Downloads

27

Readme

NETSCAPE-Bookmark-tree

npm

Example 中文

Parse the NETSCAPE-Bookmark-file-1 format bookmarks exported by the browser, convert it into a tree structure, and also convert the tree structure back to bookmarks.


Bookmark file format:

<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
     It will be read and overwritten.
     DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
    ...
</DL><p>

Converted format:

[
    {
        "name": "Bookmarks",
        "index": 0,
        "id": "0",
        "children": [
            {
                "name": "收藏夹栏",
                "index": 0,
                "id": "0_0",
                "pid": "0",
                "children": [
                    {
                        "name": "GitHub",
                        "href": "https://github.com/zmyjs",
                        "icon": "data:image/png;base64,...",
                        "index": 0,
                        "id": "0_0_0",
                        "pid": "0_0"
                    },
                    { "name": "..." }
                ]
            },
            { "name": "..." }
        ]
    }
]

Basic Usage

Node.js

Installation

npm install netscape-bookmark-tree

ESM

// netscape-bookmark-tree/bookmark.js
import { readFileSync } from 'node:fs';
import { parse as bookmarkParse } from 'netscape-bookmark-tree';

const string = readFileSync('bookmarks_2023_5_9.html', 'utf-8');
const bookmarkTree = bookmarkParse(string);

CommonJS

const bookmark = require('netscape-bookmark-tree/bookmark.cjs');

// string: bookmark file string
const bookmarkTree =  bookmark.parse(string);

Browser

The browser requires the file to be prefixed with bookmark.browser.

ESM

<script type="module">
    import * as bookmark from "https://unpkg.com/netscape-bookmark-tree/bookmark.browser.js";

    const res = await fetch('bookmarks_2023_5_9.html');
    const string = await res.text();

    const bookmarkTree =  bookmark.parse(string);
</script>

iife

<script src="https://unpkg.com/netscape-bookmark-tree/bookmark.browser.iife.js"></script>
<script>
    // string: bookmark file string
    const bookmarkTree =  bookmark.parse(string);
</script>

API

import { parse, stringify, defaultOptions } from 'netscape-bookmark-tree';

parse()

/**
 * Convert a bookmark string to a tree structure
 * @param {String} string bookmark file string
 * @param {Object} options default: `defaultOptions.parse`
 * @returns {Array} tree
 */
function parse(string, options) {
    return tree;
}

Parameter

  • string

bookmark file string. Merge multiple bookmarks, and repeating, line breaks, indentation, and other formatting will not affect the interpretation.

If you haven't modified the file, the array returned will contain only one object (the root node). If you interpret multiple bookmark files merged together, the function will return an array with multiple objects.

const bookmark0 = readFileSync('bookmarks_2023_5_5.html', 'utf-8');
const bookmark1 = bookmark0.replace(/\n/g, '');

const tree = bookmark.parse(bookmark0 + bookmark1);
tree.length;
// 2
  • options

The following are all the properties.

const options = {
    /**
    * Iterate over each node and return a new node.
    * This function is not the default value. The default value adds several common properties to the node: `{ id, pid, index }`.
    * @param {Object} node The node interpreted from the bookmark file
    * @param {Object} context The context information of the node
    * @param {Array} context.parentPath The array of parent nodes, for example: `[node.parent.parent, node.parent]`
    * @param {Boolean} context.isLeaf Whether the node is a leaf node. You cannot determine this by checking `node.children`, because when the node is being interpreted, its children have not yet been interpreted.
    * @param {Object} context.index The index of the node in the current array, which may be used to generate a unique ID.
    * @returns {Object} The new node
    */
    each(node, context) {
        return node;
    },
    /**
     * Set the children of the current node
     * The default value for the function is as follows
     * @param {Object} node 
     * @param {Array} children 
     */
    setChildren(node, children) {
        node.children = children;
    }
};

Custom Usage

  • Custom Node Properties
bookmark.parse(string, {
    each(node, context) {
        node.title = node.name;
        return node;
    },
    setChildren(node, children) {
        node.naughtyChild = children;
    }
});
  • Return Different Nodes

For example, if you want each node to be a DOM element, you can still achieve that.

const [li] = bookmark.parse(string, {
    each(node, context) {
        const li = document.createElement('li');

        if (context.isLeaf) {
            const label = document.createElement('a');

            label.textContent = node.name;
            label.href = node.href;

            li.appendChild(label);
        } else {
            const label = document.createElement('label');
            const ul = document.createElement('ul');

            label.textContent = node.name;

            li.appendChild(label);
            li.appendChild(ul);
        }

        // Element
        return li;
    },
    setChildren(li, children) {
        // Adding child nodes to an Element is no longer a simple attribute addition
        children.forEach(function (el) {
            li.children[1].appendChild(el);
        });
    }
});

const ul = document.createElement('ul');
ul.appendChild(li);

document.body.appendChild(ul);

stringify()

/**
 * Convert a bookmark tree to a bookmark string
 * @param {Array} tree
 * @param {Object} options default: `defaultOptions.stringify`
 * @returns {Array} List of bookmark strings
 */
function stringify(tree, options) {
    return files;
}

It should be noted that this function returns an array, not a string. The reason is explained in the parameter description below.

Parameter

  • tree

Bookmark tree, corresponding to the structure returned by parse().

Since parse() supports interpreting multiple bookmark files merged together, the array returned by parse() represents the root of each bookmark tree. Therefore, the return value of stringify() is also an array, and each element of the array is a bookmark file string.

const bookmark0 = readFileSync('bookmarks_2019_5_5.html', 'utf-8');
const bookmark1 = readFileSync('bookmarks_2023_5_9.html', 'utf-8');
// Convert to tree
const tree = bookmark.parse(bookmark0 + bookmark1, {
    each(node, context) {
        // After converting to a tree structure, we usually don't care about the order of properties, but if we need to restore it to a string, we need to include the order of properties.
        node.attributes = context.attributes;
        // For example: { name: 'github', href: 'https://github.com/', attributes:[{name: 'href', value: 'https://github.com/'}] }
        return node;
    }
});
// Restore to string
const files = bookmark.stringify(tree);

files.length === tree.length;
// true
files[0] === bookmark0;
// true
files[1] === bookmark1;
// true

If the bookmark name contains HTML escape sequences such as &amp, the above example may result in files[0] not equaling bookmark0, but this does not affect the use.

  • options

The following are all the properties.

const options = {
    /**
     * Callback function for each node
     * The default value for the function is as follows
     * @param {Array} node Bookmark tree node
     * @param {Array} parentPath The array of parent nodes, for example: `[node.parent.parent, node.parent]`
     * @returns {Object} Return this object: `{ name, attributes, children }`
     * @property {number} name Tag name. Required
     * @property {number} attributes List of attributes, with each element in the array being: `{ name, value }`. Required.
     * @property {number} [children] If children is an array, it will be converted to an `<H3>` tag regardless of whether the array has elements or not. Otherwise, it will be converted to an `<A>` tag. Optional.
     */
    each(node, parentPath) {
        return node;
    },
    // End of Line. The default value is `os.EOL` in the Node.js environment and '\n' in the browser environment.
    eol: '\n'
};

Custom Usage

const tree = bookmark.parse(text, {
    each(node, context) {
        return {
            myName: node.name,
            myAttrs: context.attributes
        };
    },
    setChildren(node, children) {
        node.myChild = children;
    }
});

const files = bookmark.stringify(tree, {
    each(node) {
        return {
            name: node.myName,
            attributes: node.myAttrs,
            children: node.myChild, 
        };
    }
});

files[0] === text;
// true

defaultOptions

Default options.

const defaultOptions = {
    // parse() default options
    parse: {},
    // stringify() default options
    stringify: {}
};

If you want to keep the system default features after customizing the configuration, you can do it like this.

bookmark.parse(string, {
    each(node, context) {
        node.dearFather = lodash.last(context.parentPath);
        return bookmark.defaultOptions.parse(node, context);
    }
});

Test

Node.js

npm test

Browser

npm start

Open this webpage: http://localhost:3000/test/browser

Migrating from v1 to v2

v2 has been refactored and the API is not complicated. It is recommended to read the documentation again.

  • The imported files have changed and need to be distinguished between browser mode and Node.js mode.
  • The entry point has changed, and the module now exports { parse, stringify, defaultOptions }.
  • The options name and split have been removed and replaced with each.
  • The option children has been removed and replaced with setChildren.

License

MIT