From c68da1aad9145c6ab5a2f61419c44af85c3f3156 Mon Sep 17 00:00:00 2001 From: William Killerud Date: Tue, 12 Mar 2024 18:40:40 +0100 Subject: [PATCH] feat: add sync version of the parse function The built-in resolvers are all sync, so the async nature isn't really needed. Any custom resolvers you might pass to parseSync must also be sync (not return a Promise). --- src/sassdoc-parser.test.ts | 197 ++++++++++++++++++++++++++++++++++++- src/sassdoc-parser.ts | 46 +++++++++ 2 files changed, 242 insertions(+), 1 deletion(-) diff --git a/src/sassdoc-parser.test.ts b/src/sassdoc-parser.test.ts index 3bb06e4..6e17442 100644 --- a/src/sassdoc-parser.test.ts +++ b/src/sassdoc-parser.test.ts @@ -1,5 +1,5 @@ import { test, expect } from "vitest"; -import { parse } from "./sassdoc-parser.js"; +import { parse, parseSync } from "./sassdoc-parser.js"; test("parses a decked out function", async () => { const result = await parse(/* scss */ ` @@ -469,3 +469,198 @@ $secondary-color: #000000; expect(result[1].name).toEqual("wants-to-be-the-primary-color"); expect(result[1].context.name).toEqual("secondary-color"); }); + +test("parseSync works", () => { + const result = parseSync(/* scss */ ` + /// Example trying to max out the number of annotations so we don't need so many test cases + /// @param {Number} $value - Value to add unit to + /// @param {String} $unit - String representation of the unit + /// @return {Number} - $value expressed in $unit + /// @deprecated Prefer other-item + /// @alias other-item + /// @see yet-another-item + /// @author Just Testing + /// @group helpers + /// @since 1.0.0 + /// @example Add unit + /// to-length($number, "%") + @function to-length($value, $unit) { + $units: ( + "px": 1px, + "rem": 1rem, + "%": 1%, + "em": 1em, + ); + + @if not index(map-keys($units), $unit) { + $_: log("Invalid unit #{$unit}."); + } + + @return $value * map.get($units, $unit); + } + + /// Other item + @function other-item($value) { + @return $value; + } + + /// Yet another item + @function yet-another-item($value) { + @return $value; + } + `); + + expect(result).toMatchInlineSnapshot(` + [ + { + "access": "public", + "alias": "other-item", + "author": [ + "Just Testing", + ], + "commentRange": { + "end": 13, + "start": 2, + }, + "context": { + "code": " + $units: ( + "px": 1px, + "rem": 1rem, + "%": 1%, + "em": 1em, + ); + + @if not index(map-keys($units), $unit) { + $_: log("Invalid unit #{$unit}."); + } + + @return $value * map.get($units, $unit); + ", + "line": { + "end": 27, + "start": 14, + }, + "name": "to-length", + "type": "function", + }, + "deprecated": "Prefer other-item", + "description": "Example trying to max out the number of annotations so we don't need so many test cases + ", + "example": [ + { + "code": "to-length($number, "%")", + "description": "unit", + "type": "Add", + }, + ], + "group": [ + "helpers", + ], + "name": "to-length", + "parameter": [ + { + "description": "Value to add unit to", + "name": "value", + "type": "Number", + }, + { + "description": "String representation of the unit", + "name": "unit", + "type": "String", + }, + ], + "require": [], + "return": { + "description": "$value expressed in $unit", + "type": "Number", + }, + "see": [ + { + "access": "public", + "commentRange": { + "end": 34, + "start": 34, + }, + "context": { + "code": " + @return $value; + ", + "line": { + "end": 37, + "start": 35, + }, + "name": "yet-another-item", + "type": "function", + }, + "description": "Yet another item + ", + "group": [ + "undefined", + ], + "name": "yet-another-item", + "require": [], + }, + ], + "since": [ + { + "version": "1.0.0", + }, + ], + }, + { + "access": "public", + "aliased": [ + "to-length", + ], + "commentRange": { + "end": 29, + "start": 29, + }, + "context": { + "code": " + @return $value; + ", + "line": { + "end": 32, + "start": 30, + }, + "name": "other-item", + "type": "function", + }, + "description": "Other item + ", + "group": [ + "undefined", + ], + "name": "other-item", + "require": [], + }, + { + "access": "public", + "commentRange": { + "end": 34, + "start": 34, + }, + "context": { + "code": " + @return $value; + ", + "line": { + "end": 37, + "start": 35, + }, + "name": "yet-another-item", + "type": "function", + }, + "description": "Yet another item + ", + "group": [ + "undefined", + ], + "name": "yet-another-item", + "require": [], + }, + ] + `); +}); diff --git a/src/sassdoc-parser.ts b/src/sassdoc-parser.ts index 2684668..1d522b6 100644 --- a/src/sassdoc-parser.ts +++ b/src/sassdoc-parser.ts @@ -49,6 +49,35 @@ class Parser { return Promise.all(promises).then(() => data); } + + parseStringSync(code: string, id?: string): ParseResult[] { + let data = this.scssParser.parse( + removeReduntantWhitespace(code), + id, + ) as Array; + data = sorter(data); + + data = data.map((d) => { + if (!d.name) { + // Give everything a default name from context + d.name = d.context.name; + } + return d; + }); + + Object.keys(this.annotations.list).forEach((key: string) => { + const annotation = this.annotations.list[key as BuiltInAnnotationNames]; + + if (annotation.resolve) { + const result = annotation.resolve(data); + if (typeof result !== "undefined") { + throw new Error("Tried to resolve an async annotation in parseSync"); + } + } + }); + + return data; + } } export type ParseOptions = { @@ -72,3 +101,20 @@ export async function parse( const parser = new Parser(options?.parserConfig); return await parser.parseString(code, options?.id); } + +/** + * Try to parse any SassDoc in the SCSS input + * + * @example + * parse(` + * /// Main color + * $stardew: #ffffff; + * `); + */ +export function parseSync( + code: string, + options?: ParseOptions, +): Array { + const parser = new Parser(options?.parserConfig); + return parser.parseStringSync(code, options?.id); +}