dsh-lite-memory 0.15.0 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/anchor.js +55 -13
- package/client.js +60 -23
- package/docs/RELEASE-0.16.0.md +10 -0
- package/index.js +140 -39
- package/package.json +1 -1
- package/state.js +7 -5
- package/store.js +61 -35
- package/test/anchor.test.mjs +90 -0
- package/test/control.test.mjs +19 -0
- package/test/evolution-read.test.mjs +133 -3
- package/test/learning.test.mjs +1 -1
- package/test/recall.test.mjs +14 -0
- package/test/store.test.mjs +87 -19
package/test/store.test.mjs
CHANGED
|
@@ -40,24 +40,31 @@ const rawState = (scope) => fs.readFileSync(path.join(scope.dir, 'state.json'),
|
|
|
40
40
|
const countOf = (scope) => loadIndex(scope).entries.length;
|
|
41
41
|
const suggestionsOf = (scope) => loadIndex(scope).suggestions;
|
|
42
42
|
|
|
43
|
-
test('over-specific body is rejected
|
|
43
|
+
test('over-specific body is stored, not rejected for naming concrete values', () => {
|
|
44
44
|
const scope = fresh('specific');
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
45
|
+
const saved = upsert(scope, {
|
|
46
|
+
title: '自绘菜单',
|
|
47
|
+
summary: '菜单用应用自绘,不用系统原生',
|
|
48
|
+
body: '菜单 z-index: 1100;宽度 min(264px, 100vw - 24px);字号 12px;内边距 10px;圆角 8px。',
|
|
49
|
+
});
|
|
50
|
+
assert.equal(saved.record.title, '自绘菜单');
|
|
51
|
+
assert.ok(saved.record.body.includes('z-index'));
|
|
53
52
|
});
|
|
54
53
|
|
|
55
|
-
test('
|
|
54
|
+
test('a 500-character body is accepted', () => {
|
|
56
55
|
const scope = fresh('toolong');
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
const saved = upsert(scope, { title: '长正文', summary: '长一点也要存下来', body: '记'.repeat(500) });
|
|
57
|
+
assert.equal(saved.record.title, '长正文');
|
|
58
|
+
assert.equal(saved.record.body.length, 500);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('正文正好到 4096 字节可以存,元数据不算进正文上限', () => {
|
|
62
|
+
const scope = fresh('body-cap');
|
|
63
|
+
const body = `${'测'.repeat(1365)}a`;
|
|
64
|
+
const saved = upsert(scope, { title: '正文到顶', summary: '正文刚好到上限', body });
|
|
65
|
+
assert.equal(saved.record.body, body);
|
|
66
|
+
assert.ok(saved.record.bytes > LIMITS.entryBytes);
|
|
67
|
+
assert.throws(() => upsert(scope, { title: '超一点', summary: '正文超一点', body: `${body}a` }), /正文 4097 字节/);
|
|
61
68
|
});
|
|
62
69
|
|
|
63
70
|
test('create then same title merges with full old body kept', () => {
|
|
@@ -146,16 +153,20 @@ test('oversized body is rejected, old data untouched', () => {
|
|
|
146
153
|
assert.equal(loadIndex(scope).entries[0].revision, 1);
|
|
147
154
|
});
|
|
148
155
|
|
|
149
|
-
test('over-long title
|
|
156
|
+
test('over-long title is an error; over-long summary is truncated but the full text is saved', () => {
|
|
150
157
|
const scope = fresh('length');
|
|
151
158
|
assert.throws(() => upsert(scope, { title: 't'.repeat(LIMITS.titleChars + 1), summary: '写得短一点' }), /标题超过/);
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
const long = '长'.repeat(LIMITS.summaryChars + 1);
|
|
160
|
+
const saved = upsert(scope, { title: '长摘要', summary: long });
|
|
161
|
+
assert.equal(saved.record.summary.length, LIMITS.summaryChars);
|
|
162
|
+
assert.equal(readEntry(scope, saved.record.id).body, long);
|
|
163
|
+
assert.equal(saved.draft.fullTextInBody, true);
|
|
164
|
+
assert.equal(saved.draft.summaryShortened, true);
|
|
154
165
|
});
|
|
155
166
|
|
|
156
|
-
test('imperative summary
|
|
167
|
+
test('imperative summary is kept; credentials are still rejected', () => {
|
|
157
168
|
const scope = fresh('validate');
|
|
158
|
-
assert.
|
|
169
|
+
assert.equal(upsert(scope, { title: '回复语言', summary: '请用中文回复' }).record.summary, '请用中文回复');
|
|
159
170
|
assert.throws(() => upsert(scope, { title: '凭据', summary: '一个 token 的值', body: 'token = sk-abcdefghijklmnopqrst' }), /凭据/);
|
|
160
171
|
assert.equal(normalizeDraft({ title: 'a', summary: '名词短语' }).kind, 'note');
|
|
161
172
|
assert.throws(() => normalizeDraft({ title: 'a', summary: '名词短语', kind: 'guess' }), /类型只能是/);
|
|
@@ -816,5 +827,62 @@ test('实验策略版本不认时保持关闭,开关拒绝改动且盘上不
|
|
|
816
827
|
assert.equal(fs.readFileSync(path.join(scope.dir, 'state.json'), 'utf8'), before);
|
|
817
828
|
});
|
|
818
829
|
|
|
830
|
+
test('当前不适用的高相关条目不挤掉后面真能用的条目', () => {
|
|
831
|
+
const scope = fresh('usable-rank');
|
|
832
|
+
for (let index = 0; index < 40; index += 1) {
|
|
833
|
+
upsert(scope, {
|
|
834
|
+
title: `旧规则${index}`,
|
|
835
|
+
summary: `旧规则${index}`,
|
|
836
|
+
body: `口播检查项${index}的正文`,
|
|
837
|
+
applicability: 'unresolved',
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
const usable = upsert(scope, {
|
|
841
|
+
title: '口播检查项可用',
|
|
842
|
+
summary: '口播检查项可用',
|
|
843
|
+
body: '口播检查项的可用正文',
|
|
844
|
+
applicability: 'all_in_scope',
|
|
845
|
+
});
|
|
846
|
+
const usableId = usable.record?.id ?? usable.id;
|
|
847
|
+
const hits = search(scope, '口播检查项', 3);
|
|
848
|
+
assert.equal(hits.some((row) => row.id === usableId), true);
|
|
849
|
+
});
|
|
850
|
+
|
|
819
851
|
for (const dir of dirs) fs.rmSync(dir, { recursive: true, force: true });
|
|
852
|
+
|
|
853
|
+
test('R24 省略正文的更新不覆盖已有正文(按 id 与同名都成立)', () => {
|
|
854
|
+
const scope = fresh('omit-body');
|
|
855
|
+
const first = upsert(scope, { title: '连接池改法', summary: '旧摘要', body: '旧正文:先看连接数。' });
|
|
856
|
+
const id = first.record.id;
|
|
857
|
+
upsert(scope, { id, title: '连接池改法', summary: '新摘要' });
|
|
858
|
+
assert.equal(bodyOf(scope, id), '旧正文:先看连接数。', 'id 更新省略正文时保留原正文');
|
|
859
|
+
upsert(scope, { title: '连接池改法', summary: '再新一点' });
|
|
860
|
+
assert.equal(bodyOf(scope, id), '旧正文:先看连接数。', '同名更新省略正文时保留原正文');
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
test('R25 长摘要改动即使只差第 61 个字符也算改过,全文仍保留', () => {
|
|
864
|
+
const scope = fresh('long-summary-change');
|
|
865
|
+
const head = '摘要主体'.repeat(15);
|
|
866
|
+
const first = upsert(scope, { title: '长摘要规则', summary: `${head}甲` });
|
|
867
|
+
const id = first.record.id;
|
|
868
|
+
assert.equal(first.record.summary.length, LIMITS.summaryChars);
|
|
869
|
+
assert.match(bodyOf(scope, id), /甲$/);
|
|
870
|
+
const again = upsert(scope, { id, title: '长摘要规则', summary: `${head}乙` });
|
|
871
|
+
assert.equal(again.noop, false, '第 61 个字符变化不能当作没改');
|
|
872
|
+
const body = bodyOf(scope, id);
|
|
873
|
+
assert.match(body, /甲/);
|
|
874
|
+
assert.match(body, /乙/, '新的完整摘要也落盘');
|
|
875
|
+
assert.equal(again.record.summary.length, LIMITS.summaryChars);
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
test('R26 显式长正文加短摘要时补上摘要原文,不把两者混成一条', () => {
|
|
879
|
+
const scope = fresh('body-plus-summary');
|
|
880
|
+
const long = '现场记录'.repeat(20);
|
|
881
|
+
const saved = upsert(scope, { title: '带正文的长摘要', summary: long, body: '显式正文:先复现再改。' });
|
|
882
|
+
const body = bodyOf(scope, saved.record.id);
|
|
883
|
+
assert.match(body, /^显式正文:先复现再改。/);
|
|
884
|
+
assert.match(body, /摘要原文:/);
|
|
885
|
+
assert.match(body, /现场记录/);
|
|
886
|
+
});
|
|
887
|
+
|
|
820
888
|
console.log(`store.test.mjs: ${passed} passed`);
|