@xsai/stream-object 0.0.28 → 0.0.29

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +38 -10
  2. package/dist/index.js +234 -225
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ Matches any primitive, `void`, `Date`, or `RegExp` value.
28
28
  type BuiltIns = Primitive | void | Date | RegExp;
29
29
 
30
30
  /**
31
- @see PartialDeep
31
+ @see {@link PartialDeep}
32
32
  */
33
33
  type PartialDeepOptions = {
34
34
  /**
@@ -37,6 +37,32 @@ type PartialDeepOptions = {
37
37
  @default false
38
38
  */
39
39
  readonly recurseIntoArrays?: boolean;
40
+
41
+ /**
42
+ Allows `undefined` values in non-tuple arrays.
43
+
44
+ - When set to `true`, elements of non-tuple arrays can be `undefined`.
45
+ - When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
46
+
47
+ @default true
48
+
49
+ @example
50
+ You can prevent `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}` as the second type argument:
51
+
52
+ ```
53
+ import type {PartialDeep} from 'type-fest';
54
+
55
+ type Settings = {
56
+ languages: string[];
57
+ };
58
+
59
+ declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: false}>;
60
+
61
+ partialSettings.languages = [undefined]; // Error
62
+ partialSettings.languages = []; // Ok
63
+ ```
64
+ */
65
+ readonly allowUndefinedInNonTupleArrays?: boolean;
40
66
  };
41
67
 
42
68
  /**
@@ -52,12 +78,12 @@ import type {PartialDeep} from 'type-fest';
52
78
 
53
79
  const settings: Settings = {
54
80
  textEditor: {
55
- fontSize: 14;
56
- fontColor: '#000000';
57
- fontWeight: 400;
58
- }
59
- autocomplete: false;
60
- autosave: true;
81
+ fontSize: 14,
82
+ fontColor: '#000000',
83
+ fontWeight: 400
84
+ },
85
+ autocomplete: false,
86
+ autosave: true
61
87
  };
62
88
 
63
89
  const applySavedSettings = (savedSettings: PartialDeep<Settings>) => {
@@ -72,7 +98,7 @@ By default, this does not affect elements in array and tuple types. You can chan
72
98
  ```
73
99
  import type {PartialDeep} from 'type-fest';
74
100
 
75
- interface Settings {
101
+ type Settings = {
76
102
  languages: string[];
77
103
  }
78
104
 
@@ -81,6 +107,8 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
81
107
  };
82
108
  ```
83
109
 
110
+ @see {@link PartialDeepOptions}
111
+
84
112
  @category Object
85
113
  @category Array
86
114
  @category Set
@@ -101,8 +129,8 @@ type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIn
101
129
  ? Options['recurseIntoArrays'] extends true
102
130
  ? ItemType[] extends T // Test for arrays (non-tuples) specifically
103
131
  ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
104
- ? ReadonlyArray<PartialDeep<ItemType | undefined, Options>>
105
- : Array<PartialDeep<ItemType | undefined, Options>>
132
+ ? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
133
+ : Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
106
134
  : PartialObjectDeep<T, Options> // Tuples behave properly
107
135
  : T // If they don't opt into array testing, just use the original type
108
136
  : PartialObjectDeep<T, Options>
package/dist/index.js CHANGED
@@ -4,226 +4,235 @@ import { streamText } from '@xsai/stream-text';
4
4
 
5
5
  var parse = {};
6
6
 
7
- (function (exports) {
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.parse = void 0;
10
- function parse(s) {
11
- if (s === undefined) {
12
- return undefined;
13
- }
14
- if (s === null) {
15
- return null;
16
- }
17
- if (s === '') {
18
- return '';
19
- }
20
- // remove incomplete escaped characters at the end of the string
21
- s = s.replace(/\\+$/, match => match.length % 2 === 0 ? match : match.slice(0, -1));
22
- try {
23
- return JSON.parse(s);
24
- }
25
- catch (e) {
26
- const [data, reminding] = s.trimLeft()[0] === ':'
27
- ? parseAny(s, e)
28
- : parseAny(s, e, parseStringWithoutQuote);
29
- parse.lastParseReminding = reminding;
30
- if (parse.onExtraToken && reminding.length > 0) {
31
- parse.onExtraToken(s, data, reminding);
32
- }
33
- return data;
34
- }
35
- }
36
- exports.parse = parse;
37
- (function (parse) {
38
- parse.onExtraToken = (text, data, reminding) => {
39
- console.error('parsed json with extra tokens:', {
40
- text,
41
- data,
42
- reminding,
43
- });
44
- };
45
- })(parse = exports.parse || (exports.parse = {}));
46
- function parseAny(s, e, fallback) {
47
- const parser = parsers[s[0]] || fallback;
48
- if (!parser) {
49
- console.error(`no parser registered for ${JSON.stringify(s[0])}:`, { s });
50
- throw e;
51
- }
52
- return parser(s, e);
53
- }
54
- function parseStringCasual(s, e, delimiters) {
55
- if (s[0] === '"') {
56
- return parseString(s);
57
- }
58
- if (s[0] === "'") {
59
- return parseSingleQuoteString(s);
60
- }
61
- return parseStringWithoutQuote(s, e, delimiters);
62
- }
63
- const parsers = {};
64
- function skipSpace(s) {
65
- return s.trimLeft();
66
- }
67
- parsers[' '] = parseSpace;
68
- parsers['\r'] = parseSpace;
69
- parsers['\n'] = parseSpace;
70
- parsers['\t'] = parseSpace;
71
- function parseSpace(s, e) {
72
- s = skipSpace(s);
73
- return parseAny(s, e);
74
- }
75
- parsers['['] = parseArray;
76
- function parseArray(s, e) {
77
- s = s.substr(1); // skip starting '['
78
- const acc = [];
79
- s = skipSpace(s);
80
- for (; s.length > 0;) {
81
- if (s[0] === ']') {
82
- s = s.substr(1); // skip ending ']'
83
- break;
84
- }
85
- const res = parseAny(s, e, (s, e) => parseStringWithoutQuote(s, e, [',', ']']));
86
- acc.push(res[0]);
87
- s = res[1];
88
- s = skipSpace(s);
89
- if (s[0] === ',') {
90
- s = s.substring(1);
91
- s = skipSpace(s);
92
- }
93
- }
94
- return [acc, s];
95
- }
96
- for (const c of '0123456789.-'.slice()) {
97
- parsers[c] = parseNumber;
98
- }
99
- function parseNumber(s) {
100
- for (let i = 0; i < s.length; i++) {
101
- const c = s[i];
102
- if (parsers[c] === parseNumber) {
103
- continue;
104
- }
105
- const num = s.substring(0, i);
106
- s = s.substring(i);
107
- return [numToStr(num), s];
108
- }
109
- return [numToStr(s), ''];
110
- }
111
- function numToStr(s) {
112
- if (s === '-') {
113
- return -0;
114
- }
115
- const num = +s;
116
- if (Number.isNaN(num)) {
117
- return s;
118
- }
119
- return num;
120
- }
121
- parsers['"'] = parseString;
122
- function parseString(s) {
123
- for (let i = 1; i < s.length; i++) {
124
- const c = s[i];
125
- if (c === '\\') {
126
- i++;
127
- continue;
128
- }
129
- if (c === '"') {
130
- const str = fixEscapedCharacters(s.substring(0, i + 1));
131
- s = s.substring(i + 1);
132
- return [JSON.parse(str), s];
133
- }
134
- }
135
- return [JSON.parse(fixEscapedCharacters(s) + '"'), ''];
136
- }
137
- function fixEscapedCharacters(s) {
138
- return s.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
139
- }
140
- parsers["'"] = parseSingleQuoteString;
141
- function parseSingleQuoteString(s) {
142
- for (let i = 1; i < s.length; i++) {
143
- const c = s[i];
144
- if (c === '\\') {
145
- i++;
146
- continue;
147
- }
148
- if (c === "'") {
149
- const str = fixEscapedCharacters(s.substring(0, i + 1));
150
- s = s.substring(i + 1);
151
- return [JSON.parse('"' + str.slice(1, -1) + '"'), s];
152
- }
153
- }
154
- return [JSON.parse('"' + fixEscapedCharacters(s.slice(1)) + '"'), ''];
155
- }
156
- function parseStringWithoutQuote(s, e, delimiters = [' ']) {
157
- const index = Math.min(...delimiters.map(delimiter => {
158
- const index = s.indexOf(delimiter);
159
- return index === -1 ? s.length : index;
160
- }));
161
- const value = s.substring(0, index).trim();
162
- const rest = s.substring(index);
163
- return [value, rest];
164
- }
165
- parsers['{'] = parseObject;
166
- function parseObject(s, e) {
167
- s = s.substr(1); // skip starting '{'
168
- const acc = {};
169
- s = skipSpace(s);
170
- for (; s.length > 0;) {
171
- if (s[0] === '}') {
172
- s = s.substr(1); // skip ending '}'
173
- break;
174
- }
175
- const keyRes = parseStringCasual(s, e, [':', '}']);
176
- const key = keyRes[0];
177
- s = keyRes[1];
178
- s = skipSpace(s);
179
- if (s[0] !== ':') {
180
- acc[key] = undefined;
181
- break;
182
- }
183
- s = s.substr(1); // skip ':'
184
- s = skipSpace(s);
185
- if (s.length === 0) {
186
- acc[key] = undefined;
187
- break;
188
- }
189
- const valueRes = parseAny(s, e);
190
- acc[key] = valueRes[0];
191
- s = valueRes[1];
192
- s = skipSpace(s);
193
- if (s[0] === ',') {
194
- s = s.substr(1);
195
- s = skipSpace(s);
196
- }
197
- }
198
- return [acc, s];
199
- }
200
- parsers['t'] = parseTrue;
201
- function parseTrue(s, e) {
202
- return parseToken(s, `true`, true, e);
203
- }
204
- parsers['f'] = parseFalse;
205
- function parseFalse(s, e) {
206
- return parseToken(s, `false`, false, e);
207
- }
208
- parsers['n'] = parseNull;
209
- function parseNull(s, e) {
210
- return parseToken(s, `null`, null, e);
211
- }
212
- function parseToken(s, tokenStr, tokenVal, e) {
213
- for (let i = tokenStr.length; i >= 1; i--) {
214
- if (s.startsWith(tokenStr.slice(0, i))) {
215
- return [tokenVal, s.slice(i)];
216
- }
217
- }
218
- /* istanbul ignore next */
219
- {
220
- const prefix = JSON.stringify(s.slice(0, tokenStr.length));
221
- console.error(`unknown token starting with ${prefix}:`, { s });
222
- throw e;
223
- }
224
- }
225
-
226
- } (parse));
7
+ var hasRequiredParse;
8
+
9
+ function requireParse () {
10
+ if (hasRequiredParse) return parse;
11
+ hasRequiredParse = 1;
12
+ (function (exports) {
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.parse = undefined;
15
+ function parse(s) {
16
+ if (s === undefined) {
17
+ return undefined;
18
+ }
19
+ if (s === null) {
20
+ return null;
21
+ }
22
+ if (s === '') {
23
+ return '';
24
+ }
25
+ // remove incomplete escaped characters at the end of the string
26
+ s = s.replace(/\\+$/, match => match.length % 2 === 0 ? match : match.slice(0, -1));
27
+ try {
28
+ return JSON.parse(s);
29
+ }
30
+ catch (e) {
31
+ const [data, reminding] = s.trimLeft()[0] === ':'
32
+ ? parseAny(s, e)
33
+ : parseAny(s, e, parseStringWithoutQuote);
34
+ parse.lastParseReminding = reminding;
35
+ if (parse.onExtraToken && reminding.length > 0) {
36
+ parse.onExtraToken(s, data, reminding);
37
+ }
38
+ return data;
39
+ }
40
+ }
41
+ exports.parse = parse;
42
+ (function (parse) {
43
+ parse.onExtraToken = (text, data, reminding) => {
44
+ console.error('parsed json with extra tokens:', {
45
+ text,
46
+ data,
47
+ reminding,
48
+ });
49
+ };
50
+ })(parse = exports.parse || (exports.parse = {}));
51
+ function parseAny(s, e, fallback) {
52
+ const parser = parsers[s[0]] || fallback;
53
+ if (!parser) {
54
+ console.error(`no parser registered for ${JSON.stringify(s[0])}:`, { s });
55
+ throw e;
56
+ }
57
+ return parser(s, e);
58
+ }
59
+ function parseStringCasual(s, e, delimiters) {
60
+ if (s[0] === '"') {
61
+ return parseString(s);
62
+ }
63
+ if (s[0] === "'") {
64
+ return parseSingleQuoteString(s);
65
+ }
66
+ return parseStringWithoutQuote(s, e, delimiters);
67
+ }
68
+ const parsers = {};
69
+ function skipSpace(s) {
70
+ return s.trimLeft();
71
+ }
72
+ parsers[' '] = parseSpace;
73
+ parsers['\r'] = parseSpace;
74
+ parsers['\n'] = parseSpace;
75
+ parsers['\t'] = parseSpace;
76
+ function parseSpace(s, e) {
77
+ s = skipSpace(s);
78
+ return parseAny(s, e);
79
+ }
80
+ parsers['['] = parseArray;
81
+ function parseArray(s, e) {
82
+ s = s.substr(1); // skip starting '['
83
+ const acc = [];
84
+ s = skipSpace(s);
85
+ for (; s.length > 0;) {
86
+ if (s[0] === ']') {
87
+ s = s.substr(1); // skip ending ']'
88
+ break;
89
+ }
90
+ const res = parseAny(s, e, (s, e) => parseStringWithoutQuote(s, e, [',', ']']));
91
+ acc.push(res[0]);
92
+ s = res[1];
93
+ s = skipSpace(s);
94
+ if (s[0] === ',') {
95
+ s = s.substring(1);
96
+ s = skipSpace(s);
97
+ }
98
+ }
99
+ return [acc, s];
100
+ }
101
+ for (const c of '0123456789.-'.slice()) {
102
+ parsers[c] = parseNumber;
103
+ }
104
+ function parseNumber(s) {
105
+ for (let i = 0; i < s.length; i++) {
106
+ const c = s[i];
107
+ if (parsers[c] === parseNumber) {
108
+ continue;
109
+ }
110
+ const num = s.substring(0, i);
111
+ s = s.substring(i);
112
+ return [numToStr(num), s];
113
+ }
114
+ return [numToStr(s), ''];
115
+ }
116
+ function numToStr(s) {
117
+ if (s === '-') {
118
+ return -0;
119
+ }
120
+ const num = +s;
121
+ if (Number.isNaN(num)) {
122
+ return s;
123
+ }
124
+ return num;
125
+ }
126
+ parsers['"'] = parseString;
127
+ function parseString(s) {
128
+ for (let i = 1; i < s.length; i++) {
129
+ const c = s[i];
130
+ if (c === '\\') {
131
+ i++;
132
+ continue;
133
+ }
134
+ if (c === '"') {
135
+ const str = fixEscapedCharacters(s.substring(0, i + 1));
136
+ s = s.substring(i + 1);
137
+ return [JSON.parse(str), s];
138
+ }
139
+ }
140
+ return [JSON.parse(fixEscapedCharacters(s) + '"'), ''];
141
+ }
142
+ function fixEscapedCharacters(s) {
143
+ return s.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
144
+ }
145
+ parsers["'"] = parseSingleQuoteString;
146
+ function parseSingleQuoteString(s) {
147
+ for (let i = 1; i < s.length; i++) {
148
+ const c = s[i];
149
+ if (c === '\\') {
150
+ i++;
151
+ continue;
152
+ }
153
+ if (c === "'") {
154
+ const str = fixEscapedCharacters(s.substring(0, i + 1));
155
+ s = s.substring(i + 1);
156
+ return [JSON.parse('"' + str.slice(1, -1) + '"'), s];
157
+ }
158
+ }
159
+ return [JSON.parse('"' + fixEscapedCharacters(s.slice(1)) + '"'), ''];
160
+ }
161
+ function parseStringWithoutQuote(s, e, delimiters = [' ']) {
162
+ const index = Math.min(...delimiters.map(delimiter => {
163
+ const index = s.indexOf(delimiter);
164
+ return index === -1 ? s.length : index;
165
+ }));
166
+ const value = s.substring(0, index).trim();
167
+ const rest = s.substring(index);
168
+ return [value, rest];
169
+ }
170
+ parsers['{'] = parseObject;
171
+ function parseObject(s, e) {
172
+ s = s.substr(1); // skip starting '{'
173
+ const acc = {};
174
+ s = skipSpace(s);
175
+ for (; s.length > 0;) {
176
+ if (s[0] === '}') {
177
+ s = s.substr(1); // skip ending '}'
178
+ break;
179
+ }
180
+ const keyRes = parseStringCasual(s, e, [':', '}']);
181
+ const key = keyRes[0];
182
+ s = keyRes[1];
183
+ s = skipSpace(s);
184
+ if (s[0] !== ':') {
185
+ acc[key] = undefined;
186
+ break;
187
+ }
188
+ s = s.substr(1); // skip ':'
189
+ s = skipSpace(s);
190
+ if (s.length === 0) {
191
+ acc[key] = undefined;
192
+ break;
193
+ }
194
+ const valueRes = parseAny(s, e);
195
+ acc[key] = valueRes[0];
196
+ s = valueRes[1];
197
+ s = skipSpace(s);
198
+ if (s[0] === ',') {
199
+ s = s.substr(1);
200
+ s = skipSpace(s);
201
+ }
202
+ }
203
+ return [acc, s];
204
+ }
205
+ parsers['t'] = parseTrue;
206
+ function parseTrue(s, e) {
207
+ return parseToken(s, `true`, true, e);
208
+ }
209
+ parsers['f'] = parseFalse;
210
+ function parseFalse(s, e) {
211
+ return parseToken(s, `false`, false, e);
212
+ }
213
+ parsers['n'] = parseNull;
214
+ function parseNull(s, e) {
215
+ return parseToken(s, `null`, null, e);
216
+ }
217
+ function parseToken(s, tokenStr, tokenVal, e) {
218
+ for (let i = tokenStr.length; i >= 1; i--) {
219
+ if (s.startsWith(tokenStr.slice(0, i))) {
220
+ return [tokenVal, s.slice(i)];
221
+ }
222
+ }
223
+ /* istanbul ignore next */
224
+ {
225
+ const prefix = JSON.stringify(s.slice(0, tokenStr.length));
226
+ console.error(`unknown token starting with ${prefix}:`, { s });
227
+ throw e;
228
+ }
229
+ }
230
+
231
+ } (parse));
232
+ return parse;
233
+ }
234
+
235
+ var parseExports = requireParse();
227
236
 
228
237
  const streamObject = async (options) => await streamText({
229
238
  ...options,
@@ -233,15 +242,15 @@ const streamObject = async (options) => await streamText({
233
242
  name: options.schemaName ?? "json_schema",
234
243
  schema: await toJSONSchema(options.schema).then((json) => clean({
235
244
  ...json,
236
- $schema: void 0
245
+ $schema: undefined
237
246
  })),
238
247
  strict: true
239
248
  },
240
249
  type: "json_schema"
241
250
  },
242
- schema: void 0,
243
- schemaDescription: void 0,
244
- schemaName: void 0
251
+ schema: undefined,
252
+ schemaDescription: undefined,
253
+ schemaName: undefined
245
254
  }).then(({ chunkStream, finishReason, textStream: rawTextStream, usage }) => {
246
255
  const [textStream, rawPartialObjectStream] = rawTextStream.tee();
247
256
  let partialObjectData = "";
@@ -250,7 +259,7 @@ const streamObject = async (options) => await streamText({
250
259
  transform: (chunk, controller) => {
251
260
  partialObjectData += chunk;
252
261
  try {
253
- const data = parse.parse(partialObjectData);
262
+ const data = parseExports.parse(partialObjectData);
254
263
  if (JSON.stringify(partialObjectSnapshot) !== JSON.stringify(data)) {
255
264
  partialObjectSnapshot = data;
256
265
  controller.enqueue(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xsai/stream-object",
3
- "version": "0.0.28",
3
+ "version": "0.0.29",
4
4
  "type": "module",
5
5
  "author": "Moeru AI",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "@gcornut/valibot-json-schema": "^0.42.0",
39
39
  "@xsai/providers": "",
40
40
  "best-effort-json-parser": "^1.1.2",
41
- "type-fest": "^4.31.0",
41
+ "type-fest": "^4.32.0",
42
42
  "valibot": "^0.42.1"
43
43
  },
44
44
  "scripts": {