1515 * @import {Nodes, Paragraph} from 'mdast'
1616 */
1717
18+ import { ccount } from 'ccount'
1819import { ok as assert } from 'devlop'
1920import { parseEntities } from 'parse-entities'
2021import { stringifyEntitiesLight } from 'stringify-entities'
@@ -88,6 +89,16 @@ export function directiveFromMarkdown() {
8889 */
8990export function directiveToMarkdown ( options ) {
9091 const settings = options || emptyOptions
92+ if (
93+ settings . quote !== '"' &&
94+ settings . quote !== "'" &&
95+ settings . quote !== null &&
96+ settings . quote !== undefined
97+ ) {
98+ throw new Error (
99+ 'Invalid quote `' + settings . quote + '`, expected `\'` or `"`'
100+ )
101+ }
91102
92103 handleDirective . peek = peekDirective
93104
@@ -181,12 +192,6 @@ export function directiveToMarkdown(options) {
181192 * @returns {string }
182193 */
183194 function attributes ( node , state ) {
184- // If the alternative is less common than `quote`, switch.
185- const appliedQuote = settings . quote || state . options . quote || '"'
186- const subset =
187- node . type === 'textDirective'
188- ? [ appliedQuote ]
189- : [ appliedQuote , '\n' , '\r' ]
190195 const attributes = node . attributes || { }
191196 /** @type {Array<string> } */
192197 const values = [ ]
@@ -208,7 +213,9 @@ export function directiveToMarkdown(options) {
208213 const value = String ( attributes [ key ] )
209214
210215 if ( key === 'id' ) {
211- id = shortcut . test ( value ) ? '#' + value : quoted ( 'id' , value )
216+ id = shortcut . test ( value )
217+ ? '#' + value
218+ : quoted ( 'id' , value , node , state )
212219 } else if ( key === 'class' ) {
213220 const list = value . split ( / [ \t \n \r ] + / g)
214221 /** @type {Array<string> } */
@@ -225,11 +232,11 @@ export function directiveToMarkdown(options) {
225232
226233 classesFull =
227234 classesFullList . length > 0
228- ? quoted ( 'class' , classesFullList . join ( ' ' ) )
235+ ? quoted ( 'class' , classesFullList . join ( ' ' ) , node , state )
229236 : ''
230237 classes = classesList . length > 0 ? '.' + classesList . join ( '.' ) : ''
231238 } else {
232- values . push ( quoted ( key , value ) )
239+ values . push ( quoted ( key , value , node , state ) )
233240 }
234241 }
235242 }
@@ -247,23 +254,39 @@ export function directiveToMarkdown(options) {
247254 }
248255
249256 return values . length > 0 ? '{' + values . join ( ' ' ) + '}' : ''
257+ }
250258
251- /**
252- * @param {string } key
253- * @param {string } value
254- * @returns {string }
255- */
256- function quoted ( key , value ) {
257- return (
258- key +
259- ( value
260- ? '=' +
261- appliedQuote +
262- stringifyEntitiesLight ( value , { subset} ) +
263- appliedQuote
264- : '' )
265- )
266- }
259+ /**
260+ * @param {string } key
261+ * @param {string } value
262+ * @param {Directives } node
263+ * @param {State } state
264+ * @returns {string }
265+ */
266+ function quoted ( key , value , node , state ) {
267+ if ( ! value ) return key
268+
269+ // If the alternative is less common than `quote`, switch.
270+ const preferred = settings . quote || state . options . quote || '"'
271+ const alternative = preferred === '"' ? "'" : '"'
272+ // If the alternative is less common than `quote`, switch.
273+ const appliedQuote =
274+ settings . quoteSmart &&
275+ ccount ( value , preferred ) > ccount ( value , alternative )
276+ ? alternative
277+ : preferred
278+ const subset =
279+ node . type === 'textDirective'
280+ ? [ appliedQuote ]
281+ : [ appliedQuote , '\n' , '\r' ]
282+
283+ return (
284+ key +
285+ ( '=' +
286+ appliedQuote +
287+ stringifyEntitiesLight ( value , { subset} ) +
288+ appliedQuote )
289+ )
267290 }
268291}
269292
0 commit comments