fix(输入法): 修复光标间隙并扩大26键及明确大小写切换

这个提交包含在:
sydxky 于 2026-11-14 19:37:32 +08:00 提交
1 父节点 b95e7caae7
当前提交 100757f684
35 个文件已更改
+675 -243

没有与搜索条件相匹配的文件

@@ -0,0 +1,54 @@
import fs from 'node:fs'
import path from 'node:path'
import {fileURLToPath} from 'node:url'
import assert from 'node:assert/strict'
import {syncInput,checkInput,watchInput} from '../scripts/install.mjs'
const parent=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'../.glyphix-work')
fs.mkdirSync(parent,{recursive:true})
const scratch=fs.mkdtempSync(path.join(parent,'sync-test-')),source=path.join(scratch,'source'),host=path.join(scratch,'host')
function write(root,name,body){const file=path.join(root,name);fs.mkdirSync(path.dirname(file),{recursive:true});fs.writeFileSync(file,body)}
function fixture(root){
write(root,'src/manifest.json',JSON.stringify({versionName:'fixture',router:{pages:{}}}))
for(const name of ['keyboard/index.ux','components/CrabInput/index.ux','assets/ime-icons/icon.png',...['engine','theme','lifecycle'].map(n=>'common/ime-'+n+'.js')])write(root,'src/'+name,'first')
write(root,'src/assets/ime-dict/meta.json',JSON.stringify({shards:['2222']}));write(root,'src/assets/ime-dict/2222.json','{}')
for(const name of ['crabKeyboard','jieba','remix-icon'])write(root,'third_party/'+name+'/LICENSE','MIT')
write(root,'LICENSE','MIT');write(root,'NOTICE.md','third party notices')
}
let stop
try{
fixture(source);write(host,'src/manifest.json',JSON.stringify({router:{pages:{}}}));write(host,'src/assets/host-data.txt','preserve')
write(host,'src/assets/ime-dict/meta.json',JSON.stringify({shards:['1111']}));write(host,'src/assets/ime-dict/1111.json','old format')
const first=syncInput(host,source);assert.equal(first.copied,13);assert.equal(first.removed,1);checkInput(host,source)
const timestamp=fs.statSync(path.join(host,'src/components/CrabInput/index.ux')).mtimeMs
assert.equal(syncInput(host,source).copied,0);assert.equal(fs.statSync(path.join(host,'src/components/CrabInput/index.ux')).mtimeMs,timestamp)
write(host,'src/common/ime-theme.js','stale');assert.throws(()=>checkInput(host,source),/differs/);assert.equal(syncInput(host,source).copied,1)
write(source,'src/common/ime-engine.js','second');assert.throws(()=>checkInput(host,source),/changed/)
write(host,'input-component.json',JSON.stringify({schema:1,integration:'component'}));syncInput(host,source)
assert.ok(!JSON.parse(fs.readFileSync(path.join(host,'src/manifest.json'),'utf8')).router.pages.keyboard)
assert.ok(!fs.existsSync(path.join(host,'src/keyboard/index.ux')))
write(source,'src/keyboard/index.ux','unused compatibility route update');checkInput(host,source)
const events=[];stop=watchInput(host,source,event=>events.push(event))
const initial=events.length
write(source,'src/components/CrabInput/index.ux','component update')
write(source,'src/common/ime-theme.js','theme update')
write(source,'src/assets/ime-icons/new-icon.png','new icon')
write(source,'src/common/ime-layout.js','new related module')
write(source,'src/assets/ime-dict/meta.json',JSON.stringify({shards:['3333'],association_shards:['a0f'],completion_shards:['c01']}));write(source,'src/assets/ime-dict/3333.json','{"changed":true}');write(source,'src/assets/ime-dict/a0f.json','{}');write(source,'src/assets/ime-dict/c01.json','{}')
const deadline=Date.now()+8000
while(Date.now()<deadline){await new Promise(resolve=>setTimeout(resolve,50));try{checkInput(host,source);break}catch{}}
const current=checkInput(host,source)
assert.ok(fs.existsSync(path.join(host,'src/assets/ime-dict/a0f.json'))&&fs.existsSync(path.join(host,'src/assets/ime-dict/c01.json')),'prediction shards synchronize')
assert.notEqual(current.sourceHash,first.sourceHash);assert.ok(events.length>initial)
assert.equal(fs.readFileSync(path.join(host,'src/common/ime-layout.js'),'utf8'),'new related module')
assert.ok(!fs.existsSync(path.join(host,'src/assets/ime-dict/2222.json')))
assert.equal(fs.readFileSync(path.join(host,'src/assets/host-data.txt'),'utf8'),'preserve')
const receipt=JSON.parse(fs.readFileSync(path.join(host,'src/assets/crab-input-source.json'),'utf8'))
receipt.files['../outside']={};write(host,'src/assets/crab-input-source.json',JSON.stringify(receipt))
assert.throws(()=>syncInput(host,source),/Invalid managed/)
assert.ok(!fs.existsSync(path.join(host,'src/assets/crab-input-source.json')),'failed sync invalidates receipt')
console.log(JSON.stringify({suite:'input-sync',status:'passed',watchEvents:events.length,checks:['incremental','tamper rejection','source drift rejection','watch component engine theme icon dictionary update','obsolete shard removal','host isolation','invalid receipt rejection']}))
}finally{
if(stop)stop()
if(!scratch.startsWith(parent+path.sep+'sync-test-'))throw Error('Unexpected test directory')
fs.rmSync(scratch,{recursive:true,force:true})
}