@samitouri / QOSami-HFS / commits / 72ada4b7

fix: faulty multiline comments

Massimo Melina committed Mar 28, 2024 at 21:06 UTC 72ada4b74eb3895a155580908532f72296cf8652
1 file changed +25 -14
src/comments.ts
+25 -14
@@ -2,7 +2,7 @@ import { defineConfig } from './config'
2 import { dirname, join } from 'path'
3 import { basename } from './cross'
4 import { parseFile, parseFileCache } from './util-files'
5 -import { writeFile } from 'fs/promises'
5 +import { createWriteStream } from 'fs'
6 import { singleWorkerFromBatchWorker } from './misc'
7 import _ from 'lodash'
8 import iconv from 'iconv-lite'
@@ -28,11 +28,16 @@ export const setCommentFor = singleWorkerFromBatchWorker(async (jobs: [path: str
28 comments.set(file, comment)
29 }
30 // encode comments in descript.ion format
31 - let txt = ''
32 - comments.forEach((c, f) =>
33 - txt += (f.includes(' ') ? `"${f}"` : f) + ' ' + (c.includes('\n') ? c.replaceAll('\n', '\\n') + MULTILINE_SUFFIX : c) + '\n')
34 - const buffer = iconv.encode(txt, descriptIonEncoding.get())
35 - await writeFile(join(folder, DESCRIPT_ION), buffer)
31 + const ws = createWriteStream(join(folder, DESCRIPT_ION))
32 + comments.forEach((comment, filename) => {
33 + const multiline = comment.includes('\n')
34 + const line = (filename.includes(' ') ? `"${filename}"` : filename)
35 + + ' ' + (multiline ? comment.replaceAll('\n', '\\n') : comment)
36 + ws.write( iconv.encode(line, descriptIonEncoding.get()) )
37 + if (multiline)
38 + ws.write(MULTILINE_SUFFIX, 'binary')
39 + ws.write('\n')
40 + })
41 }))
42 })
43
@@ -40,19 +45,25 @@ export function areCommentsEnabled() {
45 return descriptIon.get()
46 }
47
43 -const MULTILINE_SUFFIX = '\x04\xc2'
48 +const MULTILINE_SUFFIX = Buffer.from([4, 0xC2])
49 function readDescription(path: string) {
45 - return parseFile(join(path, DESCRIPT_ION), raw =>
46 - // decoding could also be done with native TextDecoder.decode, but we need iconv for the encoding anyway
47 - new Map(iconv.decode(raw, descriptIonEncoding.get()).split('\n').map(line => {
50 + // decoding could also be done with native TextDecoder.decode, but we need iconv for the encoding anyway
51 + return parseFile(join(path, DESCRIPT_ION), raw => {
52 + // for simplicity we "remove" the sequence MULTILINE_SUFFIX before iconv.decode messes it up
53 + for (let i=0; i<raw.length; i++)
54 + if (raw[i] === MULTILINE_SUFFIX[0] && raw[i+1] === MULTILINE_SUFFIX[1] && [undefined,13,10].includes(raw[i+2]))
55 + raw[i] = raw[i+1] = 10
56 + const decoded = iconv.decode(raw, descriptIonEncoding.get())
57 + const ret = new Map(decoded.split('\n').map(line => {
58 const quoted = line[0] === '"' ? 1 : 0
59 const i = quoted ? line.indexOf('"', 2) + 1 : line.indexOf(' ')
60 const fn = line.slice(quoted, i - quoted)
51 - let comment = line.slice(i + 1)
52 - if (comment.endsWith(MULTILINE_SUFFIX))
53 - comment = comment.slice(0, -2).replaceAll('\\n', '\n')
61 + const comment = line.slice(i + 1).replaceAll('\\n', '\n')
62 return [fn, comment]
55 - })))
63 + }))
64 + ret.delete('')
65 + return ret
66 + })
67 }
68
69 descriptIonEncoding.sub(() => { // invalidate cache at encoding change