8000 In JSDoc comments, doctrine can't parse arrow functions · Issue #256 · mhkeller/layercake · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

In JSDoc comments, doctrine can't parse arrow functions #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community. 8000

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
rgieseke opened this issue Mar 14, 2025 · 10 comments · Fixed by #257
Closed

In JSDoc comments, doctrine can't parse arrow functions #256

rgieseke opened this issue Mar 14, 2025 · 10 comments · Fixed by #257

Comments

@rgieseke
Copy link
Contributor
rgieseke commented Mar 14, 2025

I started looking into Svelte 5 conversion (#255) of components and noted that doctrine can't handle arrow functions (the previously used Function works).

/** @type {(d: any) => string} [format=d => d] - A function that passes the current tick value and expects a nicely formatted value in return. */
  export let format = d => d;

For example on https://layercake.graphics/components/AxisX.svelte the properties are currently not displayed completely, everything after format is missing.

Image

These might be alternatives:

https://github.com/syavorsky/comment-parser
https://github.com/jsdoctypeparser/jsdoctypeparser

I look into that while I look into the Svelte 5 conversion.

@mhkeller
Copy link
Owner

Ah how frustrating! Thanks for finding these alternatives.

Also, these JSDoc comments need a completely different format with Svelte 5 also and I haven't seen examples of how people are doing that. I did this one but it's very verbose

/** @type {{
    data: any[],
    fields: {name: string, type: string}[]
  }} */
let props = $props();
const { data, fields } = props;

@rgieseke
Copy link
Contributor Author

I didn't find any examples of JSDoc-umented Svelte 5 components either.

The following seems to work, too:

/**
 * @typedef {Object} Props
 * @property {boolean} [tickMarks=false] - Show a vertical mark for each tick.
 * @property {boolean} [gridlines=true] - Show gridlines extending into the chart area.
 * @property {Number} [tickMarkLength=6] - The length of the tick mark.
 * @property {boolean} [baseline=false] - Show a solid line at the bottom.
 * @property {boolean} [snapLabels=false] - Instead of centering the text labels on the first and the last items, align them to the edges of the chart
 * @property {(d: any) => string} [format=d => d] - A function that passes the current tick value and expects a nicely formatted value in return.
 * @property {Number|Array<any>|Function|undefined} [ticks] - If this is a number, it passes that along to the [d3Scale.ticks](https://github.com/d3/d3-scale) function. If this is an array, hardcodes the ticks to those values. If it's a function, passes along the default tick values and expects an array of tick values in return. If nothing, it uses the default ticks supplied by the D3 function.
 * @property {Number} [tickGutter=0] - The amount of whitespace between the start of the tick and the chart drawing area (the yRange min).
 * @property {Number} [dx=0] - Any optional value passed to the `dx` attribute on the text label.
 * @property {Number} [dy=12] - Any optional value passed to the `dy` attribute on the text label.
 */

/** @type {Props} */
let {
	tickMarks = false,
	gridlines = true,
	tickMarkLength = 6,
	baseline = false,
	snapLabels = false,
	format = (d) => d,
	ticks = undefined,
	tickGutter = 0,
	dx = 0,
	dy = 12
} = $props();

I also experimented with inlined JSDoc comments, but these wouldn't display in VSCode etc.

let {
  /** @type {boolean} [tickMarks=false] - Show a vertical mark for each tick.*/ tickMarks = false,
} = $props();

Would be nicer to have code and documentation closer together, but the above using typedef worked without many changes with the current Layer Cake documentation system.

@mhkeller
Copy link
Owner

Looks good! Just came across this, which suggests the same typedef approach: https://stackoverflow.com/questions/78225355/svelte-5-how-to-write-jsdoc-for-props

@rgieseke
Copy link
Contributor Author

Spotted another issue (probably also caused by me adding more type annotations 😄):

On https://layercake.graphics/components/AxisRadial.svelte it should only use @type for the property table, not @param 'total' from a function defined in the component.

Image

Just noting this here so I don't forget to check that this is also fixed in the future.

@rgieseke
Copy link
Contributor Author

Looks good! Just came across this, which suggests the same typedef approach: https://stackoverflow.com/questions/78225355/svelte-5-how-to-write-jsdoc-for-props

FWIW, the typedef/props style is also what's used by svelte-migrate, unfortunately it can't (yet) handle the comment style used in Layer Cake

Example test output from svelte-migrate:
https://github.com/sveltejs/svelte/blob/74917ae7039e512d6bf26b2b04f433eea7da8cd3/packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte

@rgieseke
Copy link
Contributor Author

FWIW, the typedef/props style is also what's used by svelte-migrate, unfortunately it can't (yet) handle the comment style used in Layer Cake

I created an issue in Svelte for that:

sveltejs/svelte#15530

@rgieseke
Copy link
Contributor Author
rgieseke commented Mar 20, 2025

Would you mind if Layer Cake's type definition lost the default value declaration in square brackets during the conversion?
E.g.

/** @type {number} [default_value=1] - A property with default value */
export let default_value = 1;

would become

/**
 * @typedef {Object} Props
 * @property {number} [default_value] -  A property with default value
 */

/** @type {Props} */
let { default_value=1 } = $props()

I started looking into fixing the Svelte migrate scripts to handle Layer Cake style type declarations and it might be easier to add that without the default value declaration in the JSDoc comment (at least from my current understanding of the migrate script).

I think it's possible to still generate the Layer Cake docs somehow without having the default value in square brackets and it would remove the duplication as well.

@rgieseke
Copy link
Contributor Author

My fix is in Svelte 5.24.0, so it's now possible to convert (cleanly formatted) Layer Cake components to the Svelte 5 syntax. The default value declaration is lost. It would be possible to add this to Svelte, too, but it's a bit tricky due to the way this is handled in svelte-migrate.

In VS Code for example, the default values can't be seen, but it might be an option to just add them to the comment.
In the Layer Cake documentation tables I can parse them from the declarations and write them to the table.

Before:
Image

After svelte-migrate:
Image

@mhkeller
Copy link
Owner

Wow thanks for doing that PR! The approach of adding the default value into the comment seems like a good one. And then, if I'm following correctly, the idea is the table would extract them from the comment?

@rgieseke
Copy link
Contributor Author

For the Layer Cake documentation tables it's possible to extract it from the block, something like the following seemed to work, parse the typedef and then extract the default values from the declaration and combine them into one object to go into the html table.

const jsdocPropertyMatches = fromMain.matchAll(/(@property [^\n]*)/gm);
const propertiesDefaultValues = fromMain.match(/let\s+\{([\s\S]*?)\} = \$props/m);
let defaultValues = {};
if (propertiesDefaultValues) {
	defaultValues = propertiesDefaultValues[1]
		.split(',')
		.map(i => i.trim())
		.filter(i => i !== 'children')
		.reduce((acc, item) => {
			const [key, value] = item.split(' = ');
			console.log(key, value);
			acc[key] = value;
			return acc;
		}, {});
}

const jsdocParsed = [...jsdocPropertyMatches].map(match => {
	const [, jsdocComment] = match;
	let parsed = parseJsdoc(jsdocComment);
	if (parsed && parsed['name'] in defaultValues)
		parsed['defaultValue'] = defaultValues[parsed['name']];
	return parsed;
}).filter(i => i !== null);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants
0