check-utf8.js 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. const fs = require('fs')
  2. const path = require('path')
  3. function walk(dir, out = []) {
  4. for (const name of fs.readdirSync(dir)) {
  5. const p = path.join(dir, name)
  6. const st = fs.statSync(p)
  7. if (st.isDirectory()) walk(p, out)
  8. else if (/\.(vue|js|scss)$/.test(name)) out.push(p)
  9. }
  10. return out
  11. }
  12. const root = path.join(__dirname, '../src/views/lobster')
  13. for (const file of walk(root)) {
  14. const buf = fs.readFileSync(file)
  15. let invalid = 0
  16. for (let i = 0; i < buf.length; i++) {
  17. const b = buf[i]
  18. if (b <= 0x7f) continue
  19. if (b >= 0xc2 && b <= 0xdf) {
  20. if (i + 1 >= buf.length || buf[i + 1] < 0x80 || buf[i + 1] > 0xbf) invalid++
  21. else i++
  22. } else if (b >= 0xe0 && b <= 0xef) {
  23. if (i + 2 >= buf.length || buf[i + 1] < 0x80 || buf[i + 1] > 0xbf || buf[i + 2] < 0x80 || buf[i + 2] > 0xbf) invalid++
  24. else i += 2
  25. } else if (b >= 0xf0 && b <= 0xf4) {
  26. if (i + 3 >= buf.length) invalid++
  27. else i += 3
  28. } else if (b >= 0x80 && b <= 0xbf) {
  29. invalid++
  30. } else {
  31. invalid++
  32. }
  33. }
  34. const text = buf.toString('utf8')
  35. const repl = (text.match(/\uFFFD/g) || []).length
  36. const mojibake = /[\u0080-\u00ff]{3,}/.test(text) && /label=/.test(text)
  37. if (invalid || repl || mojibake) {
  38. console.log(path.relative(root, file), { invalid, repl, mojibake })
  39. }
  40. }