diff --git a/package-lock.json b/package-lock.json index e6b44406..6538d09e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,6 @@ "d3-time-format": "^4.1.0", "degit": "^2.8.4", "do-not-zip": "^1.0.0", - "doctrine": "^3.0.0", "emoji-regex": "^10.3.0", "golden-fleece": "^1.0.9", "highlight.js": "^11.9.0", @@ -1818,19 +1817,6 @@ "dev": true, "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -1938,16 +1924,6 @@ "dev": true, "license": "MIT" }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/file-source": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/file-source/-/file-source-0.6.1.tgz", diff --git a/package.json b/package.json index 6848022a..107d2d82 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "d3-time-format": "^4.1.0", "degit": "^2.8.4", "do-not-zip": "^1.0.0", - "doctrine": "^3.0.0", "emoji-regex": "^10.3.0", "golden-fleece": "^1.0.9", "highlight.js": "^11.9.0", diff --git a/src/_components/Area.svelte b/src/_components/Area.svelte index 9c499f5b..40e046d2 100644 --- a/src/_components/Area.svelte +++ b/src/_components/Area.svelte @@ -7,7 +7,7 @@ const { data, xGet, yGet, xScale, yScale, extents } = getContext('LayerCake'); - /** @type {String} [fill='#ab00d610'] The shape's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ + /** @type {String} [fill='#ab00d610'] - The shape's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ export let fill = '#ab00d610'; $: path = diff --git a/src/_components/AxisX.percent-range.html.svelte b/src/_components/AxisX.percent-range.html.svelte index efd2294e..386e00ae 100644 --- a/src/_components/AxisX.percent-range.html.svelte +++ b/src/_components/AxisX.percent-range.html.svelte @@ -18,7 +18,7 @@ /** @type {Number} [tickMarkLength=6] - The length of the tick mark. */ export let tickMarkLength = 6; - /** @type {boolean} [baseline=false] – Show a solid line at the bottom. */ + /** @type {boolean} [baseline=false] - Show a solid line at the bottom. */ export let baseline = false; /** @type {boolean} [snapLabels=false] - Instead of centering the text labels on the first and the last items, align them to the edges of the chart. */ @@ -42,7 +42,7 @@ /** @type {String} units - Whether this component should use percentage or pixel values. If `percentRange={true}` it defaults to `'%'`. Options: `'%'` or `'px'`. */ export let units = $percentRange === true ? '%' : 'px'; - $: tickLen = tickMarks === true ? tickMarkLength ?? 6 : 0; + $: tickLen = tickMarks === true ? (tickMarkLength ?? 6) : 0; $: isBandwidth = typeof $xScale.bandwidth === 'function'; diff --git a/src/_components/AxisX.svelte b/src/_components/AxisX.svelte index da7bb3cc..119e4e9a 100644 --- a/src/_components/AxisX.svelte +++ b/src/_components/AxisX.svelte @@ -16,7 +16,7 @@ /** @type {Number} [tickMarkLength=6] - The length of the tick mark. */ export let tickMarkLength = 6; - /** @type {boolean} [baseline=false] – Show a solid line at the bottom. */ + /** @type {boolean} [baseline=false] - Show a solid line at the bottom. */ export let baseline = false; /** @type {boolean} [snapLabels=false] - Instead of centering the text labels on the first and the last items, align them to the edges of the chart. */ @@ -51,7 +51,7 @@ return 'middle'; } - $: tickLen = tickMarks === true ? tickMarkLength ?? 6 : 0; + $: tickLen = tickMarks === true ? (tickMarkLength ?? 6) : 0; $: isBandwidth = typeof $xScale.bandwidth === 'function'; diff --git a/src/_components/AxisXTop.percent-range.html.svelte b/src/_components/AxisXTop.percent-range.html.svelte index 01c00fc5..b2498af7 100644 --- a/src/_components/AxisXTop.percent-range.html.svelte +++ b/src/_components/AxisXTop.percent-range.html.svelte @@ -18,7 +18,7 @@ /** @type {Number} [tickMarkLength=6] - The length of the tick mark. */ export let tickMarkLength = 6; - /** @type {boolean} [baseline=false] – Show a solid line at the bottom. */ + /** @type {boolean} [baseline=false] - Show a solid line at the bottom. */ export let baseline = false; /** @type {boolean} [snapLabels=false] - Instead of centering the text labels on the first and the last items, align them to the edges of the chart. */ @@ -42,7 +42,7 @@ /** @type {String} units - Whether this component should use percentage or pixel values. If `percentRange={true}` it defaults to `'%'`. Options: `'%'` or `'px'`. */ export let units = $percentRange === true ? '%' : 'px'; - $: tickLen = tickMarks === true ? tickMarkLength ?? 6 : 0; + $: tickLen = tickMarks === true ? (tickMarkLength ?? 6) : 0; $: isBandwidth = typeof $xScale.bandwidth === 'function'; diff --git a/src/_components/AxisXTop.svelte b/src/_components/AxisXTop.svelte index 42095dfd..c0da01d8 100644 --- a/src/_components/AxisXTop.svelte +++ b/src/_components/AxisXTop.svelte @@ -16,7 +16,7 @@ /** @type {Number} [tickMarkLength=6] - The length of the tick mark. */ export let tickMarkLength = 6; - /** @type {boolean} [baseline=false] – Show a solid line at the bottom. */ + /** @type {boolean} [baseline=false] - Show a solid line at the bottom. */ export let baseline = false; /** @type {boolean} [snapLabels=false] - Instead of centering the text labels on the first and the last items, align them to the edges of the chart. */ @@ -51,7 +51,7 @@ return 'middle'; } - $: tickLen = tickMarks === true ? tickMarkLength ?? 6 : 0; + $: tickLen = tickMarks === true ? (tickMarkLength ?? 6) : 0; $: isBandwidth = typeof $xScale.bandwidth === 'function'; diff --git a/src/_components/AxisY.percent-range.html.svelte b/src/_components/AxisY.percent-range.html.svelte index abab2f24..33927193 100644 --- a/src/_components/AxisY.percent-range.html.svelte +++ b/src/_components/AxisY.percent-range.html.svelte @@ -66,8 +66,8 @@ $: tickLen = tickMarks === true ? labelPosition === 'above' - ? tickMarkLength ?? widestTickLen - : tickMarkLength ?? 6 + ? (tickMarkLength ?? widestTickLen) + : (tickMarkLength ?? 6) : 0; $: widestTickLen = Math.max( diff --git a/src/_components/AxisY.svelte b/src/_components/AxisY.svelte index e3773c3a..696751ee 100644 --- a/src/_components/AxisY.svelte +++ b/src/_components/AxisY.svelte @@ -61,8 +61,8 @@ $: tickLen = tickMarks === true ? labelPosition === 'above' - ? tickMarkLength ?? widestTickLen - : tickMarkLength ?? 6 + ? (tickMarkLength ?? widestTickLen) + : (tickMarkLength ?? 6) : 0; $: widestTickLen = Math.max( diff --git a/src/_components/AxisYRight.percent-range.html.svelte b/src/_components/AxisYRight.percent-range.html.svelte index 367f37ff..3ec044ef 100644 --- a/src/_components/AxisYRight.percent-range.html.svelte +++ b/src/_components/AxisYRight.percent-range.html.svelte @@ -66,8 +66,8 @@ $: tickLen = tickMarks === true ? labelPosition === 'above' - ? tickMarkLength ?? widestTickLen - : tickMarkLength ?? 6 + ? (tickMarkLength ?? widestTickLen) + : (tickMarkLength ?? 6) : 0; $: widestTickLen = Math.max( diff --git a/src/_components/AxisYRight.svelte b/src/_components/AxisYRight.svelte index 6e6694e2..bf479892 100644 --- a/src/_components/AxisYRight.svelte +++ b/src/_components/AxisYRight.svelte @@ -61,8 +61,8 @@ $: tickLen = tickMarks === true ? labelPosition === 'above' - ? tickMarkLength ?? widestTickLen - : tickMarkLength ?? 6 + ? (tickMarkLength ?? widestTickLen) + : (tickMarkLength ?? 6) : 0; $: widestTickLen = Math.max( diff --git a/src/_components/Beeswarm.html.svelte b/src/_components/Beeswarm.html.svelte index 86276cae..999c461c 100644 --- a/src/_components/Beeswarm.html.svelte +++ b/src/_components/Beeswarm.html.svelte @@ -19,7 +19,7 @@ /** @type {Number} [spacing=1.5] - Spacing, in pixels, between each circle. */ export let spacing = 1.5; - /** @type {Function} [getTitle] — An accessor function to get the field on the data element to display as a hover label. Mostly useful for debugging, needs better styling for production. */ + /** @type {Function|undefined} [getTitle] - An accessor function to get the field on the data element to display as a hover label. Mostly useful for debugging, needs better styling for production. */ export let getTitle = undefined; $: circles = dodge($data, { rds: r * 2 + spacing + strokeWidth, x: $xGet }); diff --git a/src/_components/Beeswarm.svelte b/src/_components/Beeswarm.svelte index 2f5f6091..5083c9b9 100644 --- a/src/_components/Beeswarm.svelte +++ b/src/_components/Beeswarm.svelte @@ -19,7 +19,7 @@ /** @type {Number} [spacing=1.5] - Whitespace padding between each circle, in pixels */ export let spacing = 1.5; - /** @type {Function|undefined} [getTitle] — An accessor function to get the field on the data element to display as a hover label using a `` tag. */ + /** @type {Function|undefined} [getTitle] - An accessor function to get the field on the data element to display as a hover label using a `<title>` tag. */ export let getTitle = undefined; $: circles = dodge($data, { rds: r * 2 + spacing + strokeWidth, x: $xGet }); diff --git a/src/_components/BeeswarmForce.html.svelte b/src/_components/BeeswarmForce.html.svelte index 206c1bdb..8c4f891b 100644 --- a/src/_components/BeeswarmForce.html.svelte +++ b/src/_components/BeeswarmForce.html.svelte @@ -25,7 +25,7 @@ /** @type {Number} [yStrength=0.075] - The value passed into the `.strength` method on `forceY`, which is used as the `'y'` property on the simulation. See [the documentation](https://github.com/d3/d3-force#y_strength) for more. */ export let yStrength = 0.075; - /** @type {Function|undefined} [getTitle] — An accessor function to get the field on the data element to display as a hover label. Mostly useful for debugging, needs better styling for production. */ + /** @type {Function|undefined} [getTitle] - An accessor function to get the field on the data element to display as a hover label. Mostly useful for debugging, needs better styling for production. */ export let getTitle = undefined; $: simulation = forceSimulation(nodes) diff --git a/src/_components/BeeswarmForce.svelte b/src/_components/BeeswarmForce.svelte index 7e5ac18c..87b0ec61 100644 --- a/src/_components/BeeswarmForce.svelte +++ b/src/_components/BeeswarmForce.svelte @@ -25,7 +25,7 @@ /** @type {Number} [yStrength=0.075] - The value passed into the `.strength` method on `forceY`. See [the documentation](https://github.com/d3/d3-force#y_strength). */ export let yStrength = 0.075; - /** @type {Function|undefined} [getTitle] — An accessor function to get the field on the data element to display as a hover label using a `<title>` tag. */ + /** @type {Function|undefined} [getTitle] - An accessor function to get the field on the data element to display as a hover label using a `<title>` tag. */ export let getTitle = undefined; $: simulation = forceSimulation(nodes) diff --git a/src/_components/CirclePackForce.svelte b/src/_components/CirclePackForce.svelte index 811f6156..966fb177 100644 --- a/src/_components/CirclePackForce.svelte +++ b/src/_components/CirclePackForce.svelte @@ -14,7 +14,7 @@ /** @type {Number} [xStrength=0.1] - The value passed into the `.strength` method on `forceX`, which is used as the `'x'` property on the simulation. See [the documentation](https://github.com/d3/d3-force#x_strength) for more. */ export let xStrength = 0.1; - /** @type {String|undefined} [nodeColor] Set a color manually otherwise it will default to the `zScale`. */ + /** @type {String|undefined} [nodeColor] - Set a color manually otherwise it will default to the `zScale`. */ export let nodeColor = undefined; /** @type {String} [nodeStroke='#fff'] - The circle's stroke color. */ diff --git a/src/_components/Labels.html.svelte b/src/_components/Labels.html.svelte index 772bd1aa..80e57680 100644 --- a/src/_components/Labels.html.svelte +++ b/src/_components/Labels.html.svelte @@ -10,7 +10,7 @@ /** @type {Array<Object>} labels - An array of objects that contain a field containing text label and data fields. */ export let labels; - /** @type {Function} getLabelName= - An accessor function to return the label field on your objects in the `labels` array. */ + /** @type {Function} getLabelName - An accessor function to return the label field on your objects in the `labels` array. */ export let getLabelName; /** @type {Function} [formatLabelName=d => d] - An optional formatting function. */ diff --git a/src/_components/MapPoints.svelte b/src/_components/MapPoints.svelte index b45c1902..ec75d94a 100644 --- a/src/_components/MapPoints.svelte +++ b/src/_components/MapPoints.svelte @@ -3,7 +3,6 @@ Generates canvas dots onto a map using [d3-geo](https://github.com/d3/d3-geo). --> <script> - /** @type {Function} projection - A D3 projection function. Pass this in as an uncalled function, e.g. `projection={geoAlbersUsa}`. */ import { getContext } from 'svelte'; const { data, width, height } = getContext('LayerCake'); @@ -11,6 +10,7 @@ /* -------------------------------------------- * Require a D3 projection function */ + /** @type {Function} projection - A D3 projection function. Pass this in as an uncalled function, e.g. `projection={geoAlbersUsa}`. */ export let projection; /** @type {Number} [r=3.5] - The point's radius. */ diff --git a/src/_components/QuadTree.html.svelte b/src/_components/QuadTree.html.svelte index 0fb97542..01325803 100644 --- a/src/_components/QuadTree.html.svelte +++ b/src/_components/QuadTree.html.svelte @@ -14,16 +14,16 @@ let found = {}; let e = {}; - /** @type {String} [x='x'] – The dimension to search across when moving the mouse left and right. */ + /** @type {String} [x='x'] - The dimension to search across when moving the mouse left and right. */ export let x = 'x'; - /** @type {String} [y='y'] – The dimension to search across when moving the mouse up and down. */ + /** @type {String} [y='y'] - The dimension to search across when moving the mouse up and down. */ export let y = 'y'; - /** @type {Number|undefined} [searchRadius] – The number of pixels to search around the mouse's location. This is the third argument passed to [`quadtree.find`](https://github.com/d3/d3-quadtree#quadtree_find) and by default a value of `undefined` means an unlimited range. */ + /** @type {Number|undefined} [searchRadius] - The number of pixels to search around the mouse's location. This is the third argument passed to [`quadtree.find`](https://github.com/d3/d3-quadtree#quadtree_find) and by default a value of `undefined` means an unlimited range. */ export let searchRadius = undefined; - /** @type {Array<Object>|undefined} [dataset] – The dataset to work off of—defaults to $data if left unset. You can pass override the default here in here in case you don't want to use the main data or it's in a strange format. */ + /** @type {Array<Object>|undefined} [dataset] - The dataset to work off of—defaults to $data if left unset. You can pass override the default here in here in case you don't want to use the main data or it's in a strange format. */ export let dataset = undefined; $: xGetter = x === 'x' ? $xGet : $yGet; diff --git a/src/_components/Radar.svelte b/src/_components/Radar.svelte index d7d09379..7e7d7d8e 100644 --- a/src/_components/Radar.svelte +++ b/src/_components/Radar.svelte @@ -8,28 +8,28 @@ const { data, width, height, xGet, config } = getContext('LayerCake'); - /** @type {String} [fill='#f0c'] The radar's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ + /** @type {String} [fill='#f0c'] - The radar's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ export let fill = '#f0c'; - /** @type {String} [stroke='#f0c'] The radar's stroke color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ + /** @type {String} [stroke='#f0c'] - The radar's stroke color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ export let stroke = '#f0c'; - /** @type {Number} [stroke=2] The radar's stroke color. */ + /** @type {Number} [stroke=2] - The radar's stroke color. */ export let strokeWidth = 2; - /** @type {Number} [fillOpacity=0.5] The radar's fill opacity. */ + /** @type {Number} [fillOpacity=0.5] - The radar's fill opacity. */ export let fillOpacity = 0.5; - /** @type {Number} [r=4.5] Each circle's radius. */ + /** @type {Number} [r=4.5] - Each circle's radius. */ export let r = 4.5; - /** @type {String} [circleFill="#f0c"] Each circle's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ + /** @type {String} [circleFill="#f0c"] - Each circle's fill color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ export let circleFill = '#f0c'; - /** @type {String} [circleStroke="#fff"] Each circle's stroke color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ + /** @type {String} [circleStroke="#fff"] - Each circle's stroke color. This is technically optional because it comes with a default value but you'll likely want to replace it with your own color. */ export let circleStroke = '#fff'; - /** @type {Number} [circleStrokeWidth=1] Each circle's stroke width. */ + /** @type {Number} [circleStrokeWidth=1] - Each circle's stroke width. */ export let circleStrokeWidth = 1; $: angleSlice = (Math.PI * 2) / $config.x.length; diff --git a/src/_components/Scatter.svg.svelte b/src/_components/Scatter.svg.svelte index 1a874378..cf97421d 100644 --- a/src/_components/Scatter.svg.svelte +++ b/src/_components/Scatter.svg.svelte @@ -7,16 +7,16 @@ const { data, xGet, yGet, xScale, yScale } = getContext('LayerCake'); - /** @type {Number} [r=5] – The circle's radius. */ + /** @type {Number} [r=5] - The circle's radius. */ export let r = 5; - /** @type {String} [fill='#0cf'] – The circle's fill color. */ + /** @type {String} [fill='#0cf'] - The circle's fill color. */ export let fill = '#0cf'; - /** @type {String} [stroke='#000'] – The circle's stroke color. */ + /** @type {String} [stroke='#000'] - The circle's stroke color. */ export let stroke = '#000'; - /** @type {Number} [strokeWidth=0] – The circle's stroke width. */ + /** @type {Number} [strokeWidth=0] - The circle's stroke width. */ export let strokeWidth = 0; </script> diff --git a/src/_components/Voronoi.svelte b/src/_components/Voronoi.svelte index 51009a92..ec8a6e82 100644 --- a/src/_components/Voronoi.svelte +++ b/src/_components/Voronoi.svelte @@ -9,7 +9,7 @@ const { data, xGet, yGet, width, height } = getContext('LayerCake'); - /** @type {String|undefined} [stroke] – An optional stroke color, which is likely only useful for testing to make sure the shapes drew correctly. */ + /** @type {String|undefined} [stroke] - An optional stroke color, which is likely only useful for testing to make sure the shapes drew correctly. */ export let stroke = undefined; let dispatcher = createEventDispatcher(); diff --git a/src/lib/helpers/parseJsdoc.js b/src/lib/helpers/parseJsdoc.js new file mode 100644 index 00000000..a378658c --- /dev/null +++ b/src/lib/helpers/parseJsdoc.js @@ -0,0 +1,40 @@ +/** * @param {string} annotation */ +export default function parseJsdoc(annotation) { + // Splits a JSDoc definition into its parts. + // @type {boolean} foor - Required variable `foo`. + // @type {number} [bar=1] - Optional variable `bar` with default value 1. + const regex = /@(type|property)\s\{(.+?)\}\s+(\w+|\[.*?\]) - (.+)/; + + const match = annotation.match(regex); + + if (!match) return null; + + const [, kind, type, nameAndDefaultValue, description] = match; + + let name = ''; + let required = true; + let defaultValue = null; + + // Optional parameters are enclosed in square brackets. + // A default value is given after `=`, otherwise it's just the name. + if (nameAndDefaultValue.startsWith('[') && nameAndDefaultValue.endsWith(']')) { + if (nameAndDefaultValue.includes('=')) { + const regexNameDefaultValue = /\[(\w+)=(.+)\]/; + [, name, defaultValue] = nameAndDefaultValue.match(regexNameDefaultValue); + } else { + name = nameAndDefaultValue.slice(1, -1); + } + required = false; + } else { + name = nameAndDefaultValue; + } + + return { + kind, + type, + name, + required, + defaultValue, + description + }; +} diff --git a/src/routes/components/[slug].json/+server.js b/src/routes/components/[slug].json/+server.js index 4208a3fc..12c354ac 100644 --- a/src/routes/components/[slug].json/+server.js +++ b/src/routes/components/[slug].json/+server.js @@ -1,7 +1,7 @@ import { error, json } from '@sveltejs/kit'; import { readFileSync, existsSync } from 'fs'; import { readdirFilterSync } from 'indian-ocean'; -import doctrine from 'doctrine'; +import parseJsdoc from '$lib/helpers/parseJsdoc.js'; function cleanMain(str) { const cleaned = str @@ -75,33 +75,22 @@ export async function GET({ params }) { }; }); - const componentDescription = doctrine.parse( - fromMain.split('<script>')[0].replace('<!--', '').replace('-->', '') - ).tags[0].description; - - const jsdocTop = fromMain - .replace('<script>', '') - .split('</script>')[0] - .match(/\/\*\*.*/gm); - - let jsdocString = ''; - - if (jsdocTop !== null) { - jsdocString = jsdocTop - .join('\n') - .replaceAll('@type', '@param') - .replaceAll('/**', '') - .replaceAll('*/', '') - .trim(); - } - - const jsdocParsed = doctrine.parse(jsdocString, { unwrap: true, sloppy: true }); + const componentDescription = fromMain + .split('<script>')[0] + .replace('<!--', '') + .replace('-->', '') + .split('@component')[1]; + const jsdocPropertyMatches = fromMain.matchAll(/(@type [^\n]*) \*\/[\s]+export/gm); + const jsdocParsed = [...jsdocPropertyMatches].map(match => { + const [, jsdocComment] = match; + return parseJsdoc(jsdocComment); + }); const response = { main, dek, usedIn, - hasjsDoctable: jsdocString !== jsdocTop, + hasjsDoctable: jsdocParsed.length > 0, jsdocParsed, componentDescription, modules diff --git a/src/routes/components/[slug]/+page.svelte b/src/routes/components/[slug]/+page.svelte index f4c7689e..ac8aef9f 100644 --- a/src/routes/components/[slug]/+page.svelte +++ b/src/routes/components/[slug]/+page.svelte @@ -46,21 +46,13 @@ $: component = lookup.get(slug); function printTypes(type) { - const joinEls = els => els.map(d => `\`${d.name}\``).join(' | '); - if (type.name) { - return `\`${type.name}\``; - } - if (type.type.elements) { - return `(${joinEls(type.type.elements)})`; - } - if (type.expression) { - if (type.expression.name) { - return `\`${type.expression.name}\``; - } - if (type.expression.elements) { - return `(${joinEls(type.expression.elements)})`; - } - } + if (type.includes('|')) { + const escaped = type + .split('|') + .map(d => `\`${d}\``) + .join(' | '); + return `(${escaped})`; + } else return `\`${type}\``; } function printDefault(def) { @@ -68,8 +60,8 @@ return `\`${def}\``; } - function printRequired(type) { - const str = type.type !== 'OptionalType' ? 'yes' : 'no'; + function printRequired(required) { + const str = required ? 'yes' : 'no'; return `<center>${str}</center>`; } @@ -80,15 +72,15 @@ let jsdocTable = ''; if (content.hasjsDoctable === true) { - jsdocTableBody = `${content.jsdocParsed.tags + jsdocTableBody = `${content.jsdocParsed .map( d => - `**${d.name}** ${printTypes(d.type)}|${printDefault(d.default)}|${printRequired( - d.type + `**${d.name}** ${printTypes(d.type)}|${printDefault(d.defaultValue)}|${printRequired( + d.required )}|${d.description?.replace(/^(-|–|—)/g, '').trim()}` ) .join('\n')}`; - jsdocTable = content.jsdocParsed.tags.length ? `${jsdocTableHeader}\n${jsdocTableBody}` : ''; + jsdocTable = content.jsdocParsed.length ? `${jsdocTableHeader}\n${jsdocTableBody}` : ''; } function copyToClipboard() { diff --git a/test/parseJsdoc.test.js b/test/parseJsdoc.test.js new file mode 100644 index 00000000..bc672677 --- /dev/null +++ b/test/parseJsdoc.test.js @@ -0,0 +1,74 @@ +/* globals describe it */ +import * as assert from 'assert'; +import fn from '../src/lib/helpers/parseJsdoc.js'; + +const name = 'parseJsdoc'; + +const tests = [ + { + input: `@type {String} [stroke='#ccc'] - The shape's stroke color.`, + expected: { + kind: 'type', + type: 'String', + name: 'stroke', + required: false, + defaultValue: "'#ccc'", + description: `The shape's stroke color.` + } + }, + { + input: `@property {Number} min - The brush's min value. Useful to bind to.`, + expected: { + kind: 'property', + type: 'Number', + name: 'min', + required: true, + defaultValue: null, + description: `The brush's min value. Useful to bind to.` + } + }, + { + input: `@type {(d: any) => string} [format=d => d] - A function that passes the current tick value and expects a nicely formatted value in return.`, + expected: { + kind: 'type', + type: `(d: any) => string`, + name: 'format', + required: false, + defaultValue: `d => d`, + description: `A function that passes the current tick value and expects a nicely formatted value in return.` + } + }, + { + input: `@type {Number|Array<any>|Function|undefined} [ticks] - If this is a number, it passes that along to D3.`, + expected: { + kind: 'type', + type: `Number|Array<any>|Function|undefined`, + name: 'ticks', + required: false, + defaultValue: null, + description: `If this is a number, it passes that along to D3.` + } + }, + { + input: `@type {Function} [sortBy=(a, b) => b.value - a.value] - The order in which circle's are drawn. Sorting on the \`depth\` key is also a popular choice.`, + expected: { + kind: 'type', + type: 'Function', + name: 'sortBy', + required: false, + defaultValue: `(a, b) => b.value - a.value`, + description: `The order in which circle's are drawn. Sorting on the \`depth\` key is also a popular choice.` + } + } +]; + +describe(name, () => { + tests.forEach(test => { + describe(`${name}("${test.input}")`, () => { + const actual = fn(test.input); + it(`should equal ${JSON.stringify(test.expected)}`, () => { + assert.deepStrictEqual(actual, test.expected); + }); + }); + }); +});