diff --git a/package-lock.json b/package-lock.json index 7ac4b8e..87f2658 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@babel/core": "^7.13.1", "@babel/eslint-parser": "^7.13.4", "@babel/plugin-syntax-class-properties": "^7.12.13", + "@types/node": "^14.14.31", "eslint": "^7.20.0", "nyc": "^15.1.0", "open": "^7.4.2", @@ -547,6 +548,12 @@ "node": ">=8" } }, + "node_modules/@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", + "dev": true + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -3382,6 +3389,12 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@types/node": { + "version": "14.14.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz", + "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==", + "dev": true + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", diff --git a/package.json b/package.json index 687ceb7..47f9b34 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@babel/core": "^7.13.1", "@babel/eslint-parser": "^7.13.4", "@babel/plugin-syntax-class-properties": "^7.12.13", + "@types/node": "^14.14.31", "eslint": "^7.20.0", "nyc": "^15.1.0", "open": "^7.4.2", diff --git a/path.js b/path.js index f862f87..a2fe01e 100644 --- a/path.js +++ b/path.js @@ -1,13 +1,31 @@ +// @ts-check + 'use strict'; +/** A path is a story label optionally with a variable number of ids. + * The label may be a dotted string containing sub-labels within each dotted level. + * Any ids count nodes within the grammar subtree under label. + * + * @typedef {[string, ...number[]]} Path + */ + exports.start = start; +/** Creates the Path where all stories start from. + * + * @returns {Path} + */ function start() { return ['start']; } exports.toName = pathToName; +/** Converts a path to a dotted string like "lab.el.1.2.3" + * + * @param {Path} path + * @returns {string} + */ function pathToName(path) { var name = path[0]; var i; @@ -23,24 +41,39 @@ function pathToName(path) { exports.next = nextPath; +/** Constructs a sibling path, incrementing the last id from the given path. + * If the given path is label-only, simply returns the given path unchanged. + * + * @param {Path} path + * @returns {Path} + */ function nextPath(path) { - path = path.slice(); - path[path.length - 1]++; + const [label, ...ids] = path; + if (ids.length > 0) { + ids[ids.length-1]++; + return [label, ...ids]; + } return path; } exports.firstChild = firstChildPath; +/** Constructs a child path by appending a 1 id to a copy of the given path. + * + * @param {string|Path} path + * @returns {Path} -- a copy of path with an added 1 id + */ function firstChildPath(path) { - path = path.slice(); - path.push(1); - return path; + return typeof path === 'string' ? [path, 1] : [...path, 1]; } exports.zerothChild = zerothChildPath; +/** Constructs a child path by appending a 0 id to a copy of the given path. + * + * @param {string|Path} path + * @returns {Path} -- a copy of path with an added 0 id + */ function zerothChildPath(path) { - path = path.slice(); - path.push(0); - return path; + return typeof path === 'string' ? [path, 0] : [...path, 0]; } diff --git a/tsconfig.json b/tsconfig.json index a70df0d..8b6b014 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,8 @@ "noEmit": true, "module": "CommonJS", - "target": "es2020" + "target": "es2020", + + "strict": true } }