@shelf/table-of-contents 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import defaults from 'lodash.defaults';
1
+ const DEFAULT_TEMPLATE = '<h<%= level %><%= attrs %>><a href="#<%= anchor %>" name="<%= anchor %>"><wbr /></a><%= header %></h<%= level %>>';
2
2
  export const DEFAULT_SETTINGS = {
3
3
  // DEFAULTS FOR toc.process()
4
4
  //
@@ -15,7 +15,7 @@ export const DEFAULT_SETTINGS = {
15
15
  anchorMin: 2,
16
16
  anchorMax: 6,
17
17
  // Anchorized header template.
18
- header: '<h<%= level %><%= attrs %>><a href="#<%= anchor %>" name="<%= anchor %>"><%= header %></a></h<%= level %>>',
18
+ header: DEFAULT_TEMPLATE,
19
19
  // DEFAULTS FOR toc.toc()
20
20
  //
21
21
  // TOC part templates.
@@ -28,5 +28,5 @@ export const DEFAULT_SETTINGS = {
28
28
  TOC: '<div class="toc"><%= toc %></div>',
29
29
  };
30
30
  export function getSettings(settingsOverride) {
31
- return defaults({}, settingsOverride, DEFAULT_SETTINGS);
31
+ return { ...DEFAULT_SETTINGS, ...settingsOverride };
32
32
  }
@@ -1,9 +1,13 @@
1
- import template from 'lodash.template';
1
+ import { template } from 'lodash-es';
2
2
  import { getSettings } from '../default-settings.js';
3
3
  import { untag } from './untag.js';
4
4
  import { unique } from './unique.js';
5
5
  import { anchor } from './anchor.js';
6
- import { getDataWithoutNestedAnchors } from './getDataWithoutNestedAnchors.js';
6
+ import { decode } from 'entities';
7
+ function normalizeHeaderText(text) {
8
+ // Decode HTML entities, convert NBSP to regular spaces, collapse inner whitespace, and trim.
9
+ return decode(text).replace(/\u00a0/g, ' ').replace(/\s+/g, ' ').trim();
10
+ }
7
11
  // Parse HTML, returning an array of header objects and anchorized HTML.
8
12
  export function anchorize(src, settingsOverride) {
9
13
  // Normalize options and compile template(s).
@@ -19,6 +23,10 @@ export function anchorize(src, settingsOverride) {
19
23
  const tocLevel = level >= settingsOverride.tocMin && level <= settingsOverride.tocMax;
20
24
  // @ts-ignore
21
25
  const anchorLevel = level >= settingsOverride.anchorMin && level <= settingsOverride.anchorMax;
26
+ const untaggedHeader = untag(header);
27
+ const decodedHeader = decode(untaggedHeader).replace(/\u00a0/g, ' ');
28
+ const normalizedText = normalizeHeaderText(untaggedHeader);
29
+ const anchorSource = normalizedText || decodedHeader.trim() || untaggedHeader || 'section';
22
30
  let data;
23
31
  if (tocLevel || anchorLevel) {
24
32
  // This data is passed into the specified "header" template function.
@@ -30,9 +38,9 @@ export function anchorize(src, settingsOverride) {
30
38
  // Header HTML contents.
31
39
  header: header,
32
40
  // Un-tagged header HTML contents.
33
- text: untag(header),
41
+ text: normalizedText,
34
42
  // Unique anchor name for this header.
35
- anchor: unique(names, anchor(header)),
43
+ anchor: unique(names, anchor(anchorSource)),
36
44
  // All HTML (including tags) matched by the "headers" RegExp.
37
45
  all: all,
38
46
  };
@@ -41,7 +49,7 @@ export function anchorize(src, settingsOverride) {
41
49
  headers.push(data);
42
50
  }
43
51
  if (anchorLevel) {
44
- return getDataWithoutNestedAnchors(data, headerTemplate);
52
+ return headerTemplate(data);
45
53
  }
46
54
  return all;
47
55
  });
@@ -1,4 +1,4 @@
1
- import template from 'lodash.template';
1
+ import { template } from 'lodash-es';
2
2
  import { getSettings } from '../default-settings.js';
3
3
  export function toc(headers, settingsOverride) {
4
4
  settingsOverride = getSettings(settingsOverride);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shelf/table-of-contents",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Fork of node-toc to reduce bundle size & rewritten in TypeScript",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -16,60 +16,57 @@
16
16
  "files": [
17
17
  "lib"
18
18
  ],
19
- "scripts": {
20
- "build": "rm -rf lib/ && tsc",
21
- "coverage": "yarn test --coverage",
22
- "lint": "eslint . --ext .js,.ts,.json --fix",
23
- "lint:ci": "eslint . --ext .js,.ts,.json",
24
- "lint:size": "size-limit",
25
- "prepack": "yarn build",
26
- "test": "TZ=UTC jest src",
27
- "test:watch": "TZ=UTC jest src --watch",
28
- "type-check": "tsc --noEmit",
29
- "type-check:watch": "npm run type-check -- --watch"
30
- },
31
- "lint-staged": {
32
- "*.{html,md,yml}": [
33
- "prettier --write"
34
- ],
35
- "*.{js,ts,json}": [
36
- "eslint --fix"
37
- ]
38
- },
39
19
  "prettier": "@shelf/prettier-config",
40
20
  "dependencies": {
41
- "entities": "4.5.0",
42
- "lodash.defaults": "4.2.0",
43
- "lodash.template": "4.5.0",
44
- "slug": "8.2.3"
21
+ "entities": "5.0.0",
22
+ "lodash-es": "4.17.21",
23
+ "slug": "9.1.0"
45
24
  },
46
25
  "devDependencies": {
47
- "@shelf/eslint-config": "3.10.0",
26
+ "@shelf/eslint-config": "3.15.1",
48
27
  "@shelf/prettier-config": "1.0.0",
49
- "@shelf/tsconfig": "0.0.11",
50
- "@size-limit/esbuild-why": "11.0.0",
51
- "@size-limit/preset-small-lib": "11.0.0",
52
- "@swc/core": "1.3.96",
53
- "@swc/jest": "0.2.29",
54
- "@types/jest": "29.5.8",
55
- "@types/lodash.defaults": "4.2.9",
56
- "@types/lodash.template": "4.5.3",
28
+ "@shelf/tsconfig": "0.1.0",
29
+ "@size-limit/esbuild-why": "11.2.0",
30
+ "@size-limit/preset-small-lib": "11.2.0",
31
+ "@swc/core": "1.11.8",
32
+ "@swc/jest": "0.2.37",
33
+ "@types/jest": "29.5.14",
34
+ "@types/lodash-es": "4.17.12",
57
35
  "@types/node": "20.8.9",
58
- "@types/slug": "5.0.7",
59
- "eslint": "8.53.0",
60
- "husky": "8.0.3",
36
+ "@types/slug": "5.0.9",
37
+ "eslint": "8.57.1",
38
+ "husky": "9.1.7",
61
39
  "jest": "29.7.0",
62
40
  "jest-environment-jsdom": "^29.7.0",
63
- "lint-staged": "15.1.0",
64
- "prettier": "3.1.0",
65
- "size-limit": "11.0.0",
41
+ "lint-staged": "15.5.1",
42
+ "prettier": "3.5.3",
43
+ "size-limit": "11.2.0",
66
44
  "ts-jest-resolver": "2.0.1",
67
- "typescript": "5.2.2"
45
+ "typescript": "5.8.3"
68
46
  },
69
47
  "engines": {
70
48
  "node": ">=14"
71
49
  },
72
50
  "publishConfig": {
73
51
  "access": "public"
52
+ },
53
+ "lint-staged": {
54
+ "*.{html,md,yml}": [
55
+ "prettier --write"
56
+ ],
57
+ "*.{js,ts,json}": [
58
+ "eslint --fix"
59
+ ]
60
+ },
61
+ "scripts": {
62
+ "build": "rm -rf lib/ && tsc",
63
+ "coverage": "yarn test --coverage",
64
+ "lint": "eslint . --ext .js,.ts,.json --fix",
65
+ "lint:ci": "eslint . --ext .js,.ts,.json",
66
+ "lint:size": "size-limit",
67
+ "test": "TZ=UTC jest src",
68
+ "test:watch": "TZ=UTC jest src --watch",
69
+ "type-check": "tsc --noEmit",
70
+ "type-check:watch": "npm run type-check -- --watch"
74
71
  }
75
- }
72
+ }
package/.husky/_/husky.sh DELETED
@@ -1,29 +0,0 @@
1
- #!/bin/sh
2
- if [ -z "$husky_skip_init" ]; then
3
- debug () {
4
- [ "$HUSKY_DEBUG" = "1" ] && echo "husky (debug) - $1"
5
- }
6
-
7
- readonly hook_name="$(basename "$0")"
8
- debug "starting $hook_name..."
9
-
10
- if [ "$HUSKY" = "0" ]; then
11
- debug "HUSKY env variable is set to 0, skipping hook"
12
- exit 0
13
- fi
14
-
15
- if [ -f ~/.huskyrc ]; then
16
- debug "sourcing ~/.huskyrc"
17
- . ~/.huskyrc
18
- fi
19
-
20
- export readonly husky_skip_init=1
21
- sh -e "$0" "$@"
22
- exitCode="$?"
23
-
24
- if [ $exitCode != 0 ]; then
25
- echo "husky - $hook_name hook exited with code $exitCode (error)"
26
- fi
27
-
28
- exit $exitCode
29
- fi
@@ -1,3 +0,0 @@
1
- import { type TemplateExecutor } from 'lodash';
2
- import type { Header } from '../types.js';
3
- export declare const getDataWithoutNestedAnchors: (data: Header, headerTemplate: TemplateExecutor) => string;
@@ -1,23 +0,0 @@
1
- const parser = new DOMParser();
2
- const hasAnchorTagsInHeader = (data) => {
3
- const doc = parser.parseFromString(data.all, 'text/html');
4
- // Extract any existing anchor tags from the header variable
5
- const anchorElement = doc.querySelector('a');
6
- return anchorElement?.outerHTML;
7
- };
8
- export const getDataWithoutNestedAnchors = (data, headerTemplate) => {
9
- const results = headerTemplate(data);
10
- if (!hasAnchorTagsInHeader(data)) {
11
- return results;
12
- }
13
- // separately parse the results to get the anchor tag
14
- const doc = parser.parseFromString(data.all, 'text/html');
15
- const anchor = document.createElement('a');
16
- anchor.setAttribute('href', `#${data.anchor}`);
17
- anchor.setAttribute('name', `${data.anchor}`);
18
- anchor.innerHTML = '<wbr>';
19
- const headerNode = doc.querySelector(`h${data.level}`);
20
- headerNode?.prepend(anchor);
21
- const html = doc.body.innerHTML;
22
- return html || results;
23
- };