@maiyunnet/kebab 8.2.1 → 8.4.0
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/doc/kebab-rag.md +258 -151
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +6 -0
- package/lib/core.js +24 -0
- package/lib/sql.d.ts +5 -0
- package/lib/sql.js +7 -0
- package/package.json +3 -1
- package/sys/cmd.js +122 -1
- package/sys/ctr.js +10 -0
- package/sys/mod.d.ts +2 -0
- package/sys/mod.js +4 -0
- package/www/example/ctr/test.d.ts +3 -0
- package/www/example/ctr/test.js +81 -0
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '8.
|
|
9
|
+
export const VER = '8.4.0';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/core.d.ts
CHANGED
|
@@ -87,6 +87,12 @@ export declare function purify(text: string): string;
|
|
|
87
87
|
* @param tree 当前树,无需传入
|
|
88
88
|
*/
|
|
89
89
|
export declare function checkType(val: any, type: any, tree?: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* --- 判断一个对象是否符合 JSON Schema ---
|
|
92
|
+
* @param val 对象
|
|
93
|
+
* @param schema JSON Schema
|
|
94
|
+
*/
|
|
95
|
+
export declare function checkSchema(val: any, schema: any): string;
|
|
90
96
|
/**
|
|
91
97
|
* --- 获取 MUID ---
|
|
92
98
|
* @param ctr Ctr 对象
|
package/lib/core.js
CHANGED
|
@@ -8,6 +8,8 @@ import * as http2 from 'http2';
|
|
|
8
8
|
import * as stream from 'stream';
|
|
9
9
|
import * as os from 'os';
|
|
10
10
|
import * as net from 'net';
|
|
11
|
+
import Ajv from 'ajv';
|
|
12
|
+
import addFormats from 'ajv-formats';
|
|
11
13
|
import * as kebab from '#kebab/index.js';
|
|
12
14
|
import * as lTime from '#kebab/lib/time.js';
|
|
13
15
|
import * as lFs from '#kebab/lib/fs.js';
|
|
@@ -18,6 +20,12 @@ import * as lResponse from '#kebab/lib/net/response.js';
|
|
|
18
20
|
import * as sCtr from '#kebab/sys/ctr.js';
|
|
19
21
|
/** --- 全局参数 --- */
|
|
20
22
|
export const globalConfig = {};
|
|
23
|
+
/** --- JSON Schema 校验器 --- */
|
|
24
|
+
const ajv = new Ajv({
|
|
25
|
+
'allErrors': true,
|
|
26
|
+
'strict': false
|
|
27
|
+
});
|
|
28
|
+
addFormats(ajv);
|
|
21
29
|
/**
|
|
22
30
|
* --- 设置 cookie ---
|
|
23
31
|
* @param ctr ctr 实例
|
|
@@ -248,6 +256,22 @@ export function checkType(val, type, tree = 'root') {
|
|
|
248
256
|
}
|
|
249
257
|
return vtype === ttype ? '' : ttype + ':' + tree + ':' + vtype;
|
|
250
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* --- 判断一个对象是否符合 JSON Schema ---
|
|
261
|
+
* @param val 对象
|
|
262
|
+
* @param schema JSON Schema
|
|
263
|
+
*/
|
|
264
|
+
export function checkSchema(val, schema) {
|
|
265
|
+
const validate = ajv.compile(schema);
|
|
266
|
+
if (validate(val)) {
|
|
267
|
+
return '';
|
|
268
|
+
}
|
|
269
|
+
const err = validate.errors?.[0];
|
|
270
|
+
if (!err) {
|
|
271
|
+
return 'schema error';
|
|
272
|
+
}
|
|
273
|
+
return `${lText.logicalOr(err.instancePath, 'root')}${err.message ? ': ' + err.message : ''}`;
|
|
274
|
+
}
|
|
251
275
|
/**
|
|
252
276
|
* --- 获取 MUID ---
|
|
253
277
|
* @param ctr Ctr 对象
|
package/lib/sql.d.ts
CHANGED
|
@@ -265,3 +265,8 @@ export declare function column(field: string): {
|
|
|
265
265
|
'token': string;
|
|
266
266
|
'value': string;
|
|
267
267
|
};
|
|
268
|
+
/**
|
|
269
|
+
* --- 将对象转换为 JSON 字符串并避开类型检查,用于适配 PostgreSQL 的 jsonb 字段 ---
|
|
270
|
+
* @param obj 要转换的 JSON 对象
|
|
271
|
+
*/
|
|
272
|
+
export declare function json(obj: kebab.Json): any;
|
package/lib/sql.js
CHANGED
|
@@ -1134,3 +1134,10 @@ export function column(field) {
|
|
|
1134
1134
|
'value': field
|
|
1135
1135
|
};
|
|
1136
1136
|
}
|
|
1137
|
+
/**
|
|
1138
|
+
* --- 将对象转换为 JSON 字符串并避开类型检查,用于适配 PostgreSQL 的 jsonb 字段 ---
|
|
1139
|
+
* @param obj 要转换的 JSON 对象
|
|
1140
|
+
*/
|
|
1141
|
+
export function json(obj) {
|
|
1142
|
+
return lText.stringifyJson(obj);
|
|
1143
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maiyunnet/kebab",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
"@litert/websocket": "^0.2.8",
|
|
31
31
|
"@types/ssh2": "^1.15.5",
|
|
32
32
|
"@zilliz/milvus2-sdk-node": "^2.6.10",
|
|
33
|
+
"ajv": "^8.18.0",
|
|
34
|
+
"ajv-formats": "^3.0.1",
|
|
33
35
|
"ejs": "^4.0.1",
|
|
34
36
|
"jszip": "^3.10.1",
|
|
35
37
|
"mysql2": "^3.17.2",
|
package/sys/cmd.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Project: Kebab, User: JianSuoQiYue
|
|
3
3
|
* Date: 2020-3-7 23:51:15
|
|
4
|
-
* Last: 2020-3-7 23:51:18, 2022-07-22 14:14:09, 2022-9-27 14:52:19, 2023-5-23 21:42:46, 2024-7-2 15:12:28
|
|
4
|
+
* Last: 2020-3-7 23:51:18, 2022-07-22 14:14:09, 2022-9-27 14:52:19, 2023-5-23 21:42:46, 2024-7-2 15:12:28, 2026-2-23 13:08:11
|
|
5
5
|
*/
|
|
6
6
|
import * as http from 'http';
|
|
7
7
|
import * as lFs from '#kebab/lib/fs.js';
|
|
@@ -10,6 +10,7 @@ import * as lTime from '#kebab/lib/time.js';
|
|
|
10
10
|
import * as lCore from '#kebab/lib/core.js';
|
|
11
11
|
import * as lCrypto from '#kebab/lib/crypto.js';
|
|
12
12
|
import * as kebab from '#kebab/index.js';
|
|
13
|
+
// --- 检查语言包:node ./source/main locale -l ./source/www/example/data/locale/sc -d ./source/www/example ---
|
|
13
14
|
/** --- 解析命令 --- */
|
|
14
15
|
const cmds = process.argv.slice(2);
|
|
15
16
|
/** --- 批量创建目录 --- */
|
|
@@ -222,6 +223,126 @@ async function run() {
|
|
|
222
223
|
}
|
|
223
224
|
}
|
|
224
225
|
lCore.display('DONE');
|
|
226
|
+
// --- 退出进程 ---
|
|
227
|
+
process.exit();
|
|
228
|
+
}
|
|
229
|
+
if (cmds[0] === 'locale') {
|
|
230
|
+
let localePath = '';
|
|
231
|
+
let dirPath = '';
|
|
232
|
+
for (let i = 1; i < cmds.length; i++) {
|
|
233
|
+
if (cmds[i] === '-l' || cmds[i] === '--locale') {
|
|
234
|
+
localePath = cmds[i + 1];
|
|
235
|
+
i++;
|
|
236
|
+
}
|
|
237
|
+
else if (cmds[i] === '-d' || cmds[i] === '--dir') {
|
|
238
|
+
dirPath = cmds[i + 1];
|
|
239
|
+
i++;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (!localePath || !dirPath) {
|
|
243
|
+
process.exit();
|
|
244
|
+
}
|
|
245
|
+
const appLocaleList = [];
|
|
246
|
+
const readDir = async (path) => {
|
|
247
|
+
const dlist = await lFs.readDir(path);
|
|
248
|
+
for (const item of dlist) {
|
|
249
|
+
if (item.name === '.' || item.name === '..') {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (item.isDirectory()) {
|
|
253
|
+
await readDir(path + '/' + item.name);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (!item.name.endsWith('.ejs') &&
|
|
257
|
+
!item.name.endsWith('.ts')) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
// --- ts 文件可能是前端的代码,所以要排除掉前端的 ts 文件 ---
|
|
261
|
+
let content = await lFs.getContent(path + '/' + item.name, 'utf8');
|
|
262
|
+
if (!content) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (item.name.endsWith('.ts')) {
|
|
266
|
+
// --- ts 文件可能是前端的代码,所以要排除掉前端的 ts 文件 ---
|
|
267
|
+
if (content.includes('AbstractPage')) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// --- 移除 TS 多行注释 ---
|
|
271
|
+
content = content.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
272
|
+
// --- 移除 TS 单行注释 ---
|
|
273
|
+
content = content.replace(/(^|[^\:])\/\/.*/g, '$1');
|
|
274
|
+
}
|
|
275
|
+
else if (item.name.endsWith('.ejs')) {
|
|
276
|
+
// --- ejs 文件,只保留 <% %> 内部的内容,因为外部是前端代码 ---
|
|
277
|
+
const matches = content.match(/<%[\s\S]*?%>/g);
|
|
278
|
+
if (!matches) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
content = matches.join('\n');
|
|
282
|
+
// --- 移除多行注释 ---
|
|
283
|
+
content = content.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
284
|
+
// --- 移除单行注释 ---
|
|
285
|
+
content = content.replace(/(^|[^\:])\/\/.*/g, '$1');
|
|
286
|
+
}
|
|
287
|
+
const reg = /(?:\b|_)l\s*\(\s*(['"])(.+?)\1/g;
|
|
288
|
+
let match;
|
|
289
|
+
while (match = reg.exec(content)) {
|
|
290
|
+
const key = match[2];
|
|
291
|
+
if (appLocaleList.includes(key)) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
appLocaleList.push(key);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
/** --- 提取目录 --- */
|
|
299
|
+
const lastSlash = localePath.lastIndexOf('/');
|
|
300
|
+
const dir = lastSlash === -1 ? '.' : localePath.slice(0, lastSlash);
|
|
301
|
+
/** --- 提取前缀,如 'sc' --- */
|
|
302
|
+
const prefix = lastSlash === -1 ? localePath : localePath.slice(lastSlash + 1);
|
|
303
|
+
const localeList = [];
|
|
304
|
+
const getKeys = (o, p = '') => {
|
|
305
|
+
for (const k in o) {
|
|
306
|
+
const nk = p ? p + '.' + k : k;
|
|
307
|
+
if (typeof o[k] === 'object' && o[k] !== null && !Array.isArray(o[k])) {
|
|
308
|
+
getKeys(o[k], nk);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
localeList.push(nk);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
const files = await lFs.readDir(dir);
|
|
316
|
+
let found = false;
|
|
317
|
+
for (const file of files) {
|
|
318
|
+
if (file.isFile() && file.name.startsWith(prefix + '.') && file.name.endsWith('.json')) {
|
|
319
|
+
found = true;
|
|
320
|
+
const content = await lFs.getContent(dir + '/' + file.name, 'utf8');
|
|
321
|
+
if (!content) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const obj = lText.parseJson(content);
|
|
325
|
+
if (typeof obj !== 'object') {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
getKeys(obj);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (!found) {
|
|
332
|
+
lCore.display('Locale files not found: ' + localePath + '.*.json');
|
|
333
|
+
process.exit();
|
|
334
|
+
}
|
|
335
|
+
appLocaleList.length = 0;
|
|
336
|
+
await readDir(dirPath);
|
|
337
|
+
const set1 = new Set(localeList);
|
|
338
|
+
const set2 = new Set(appLocaleList);
|
|
339
|
+
/** --- 只在第一个数组中存在的元素 --- */
|
|
340
|
+
const onlyInFirst = localeList.filter(item => !set2.has(item));
|
|
341
|
+
/** --- 只在第二个数组中存在的元素 --- */
|
|
342
|
+
const onlyInSecond = appLocaleList.filter(item => !set1.has(item));
|
|
343
|
+
lCore.display('More', onlyInFirst);
|
|
344
|
+
lCore.display('Less', onlyInSecond);
|
|
345
|
+
// --- 退出进程 ---
|
|
225
346
|
process.exit();
|
|
226
347
|
}
|
|
227
348
|
// --- 读取配置文件 ---
|
package/sys/ctr.js
CHANGED
|
@@ -311,6 +311,16 @@ export class Ctr {
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
|
+
else if (typeof v === 'object' && v.schema !== undefined) {
|
|
315
|
+
// --- core.checkSchema ---
|
|
316
|
+
if (input[key] !== null) {
|
|
317
|
+
const r = lCore.checkSchema(input[key], v.schema);
|
|
318
|
+
if (r) {
|
|
319
|
+
this._setCheckError(rtn, lastVal, typeof lastVal[1] === 'string' ? `(${r})` : undefined);
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
314
324
|
else {
|
|
315
325
|
/** --- 是否需要返回错误 --- */
|
|
316
326
|
let needReturn = false;
|
package/sys/mod.d.ts
CHANGED
package/sys/mod.js
CHANGED
|
@@ -115,6 +115,10 @@ export default class Mod {
|
|
|
115
115
|
static column(field) {
|
|
116
116
|
return lSql.column(field);
|
|
117
117
|
}
|
|
118
|
+
/** --- 创建 JSON 字符串对象,用于 PGSQL 的 jsonb 字段 --- */
|
|
119
|
+
static json(obj) {
|
|
120
|
+
return lSql.json(obj);
|
|
121
|
+
}
|
|
118
122
|
/**
|
|
119
123
|
* --- 添加一个序列(允许超过 65536 的占位符会被拆分多次执行) ---
|
|
120
124
|
* @param db 数据库对象
|
|
@@ -16,6 +16,8 @@ export default class extends sCtr.Ctr {
|
|
|
16
16
|
ctrXsrf1(): kebab.Json[];
|
|
17
17
|
ctrCheckinput(): string;
|
|
18
18
|
ctrCheckinput1(): Promise<kebab.Json[]>;
|
|
19
|
+
ctrCheckinputSchema(): string;
|
|
20
|
+
ctrCheckinputSchema1(): Promise<kebab.Json[]>;
|
|
19
21
|
ctrLocale(): Promise<kebab.Json[] | string>;
|
|
20
22
|
ctrCachettl(): string;
|
|
21
23
|
ctrHttpcode(): string;
|
|
@@ -41,6 +43,7 @@ export default class extends sCtr.Ctr {
|
|
|
41
43
|
coreConvert62(): string;
|
|
42
44
|
corePurify(): string;
|
|
43
45
|
coreChecktype(): string;
|
|
46
|
+
coreCheckschema(): string;
|
|
44
47
|
coreMuid(): string;
|
|
45
48
|
coreGetlog(): Promise<string>;
|
|
46
49
|
coreLs(): Promise<string>;
|
package/www/example/ctr/test.js
CHANGED
|
@@ -107,6 +107,7 @@ export default class extends sCtr.Ctr {
|
|
|
107
107
|
'<br><br><b>Ctr:</b>',
|
|
108
108
|
`<br><br><a href="${this._config.const.urlBase}test/ctr-xsrf">View "test/ctr-xsrf"</a>`,
|
|
109
109
|
`<br><a href="${this._config.const.urlBase}test/ctr-checkinput">View "test/ctr-checkinput"</a>`,
|
|
110
|
+
`<br><a href="${this._config.const.urlBase}test/ctr-checkinput-schema">View "test/ctr-checkinput-schema"</a>`,
|
|
110
111
|
`<br><a href="${this._config.const.urlBase}test/ctr-locale">View "test/ctr-locale"</a>`,
|
|
111
112
|
`<br><a href="${this._config.const.urlBase}test/ctr-cachettl">View "test/ctr-cachettl"</a>`,
|
|
112
113
|
`<br><a href="${this._config.const.urlBase}test/ctr-httpcode">View "test/ctr-httpcode"</a>`,
|
|
@@ -139,6 +140,7 @@ export default class extends sCtr.Ctr {
|
|
|
139
140
|
`<br><a href="${this._config.const.urlBase}test/core-convert62">View "test/core-convert62"</a>`,
|
|
140
141
|
`<br><a href="${this._config.const.urlBase}test/core-purify">View "test/core-purify"</a>`,
|
|
141
142
|
`<br><a href="${this._config.const.urlBase}test/core-checktype">View "test/core-checktype"</a>`,
|
|
143
|
+
`<br><a href="${this._config.const.urlBase}test/core-checkschema">View "test/core-checkschema"</a>`,
|
|
142
144
|
`<br><a href="${this._config.const.urlBase}test/core-muid">View "test/core-muid"</a>`,
|
|
143
145
|
`<br><a href="${this._config.const.urlBase}test/core-getlog">View "test/core-getlog"</a>`,
|
|
144
146
|
`<br><a href="${this._config.const.urlBase}test/core-ls">View "test/core-ls"</a>`,
|
|
@@ -469,6 +471,60 @@ function postFd() {
|
|
|
469
471
|
}
|
|
470
472
|
return [1, { 'post': this._post }];
|
|
471
473
|
}
|
|
474
|
+
ctrCheckinputSchema() {
|
|
475
|
+
const echo = [
|
|
476
|
+
'<b>Test _checkInput by JSON Schema</b><br><br>',
|
|
477
|
+
];
|
|
478
|
+
const post = [
|
|
479
|
+
{ 'sdata': { 'foo': 1, 'bar': 'abc' } },
|
|
480
|
+
{ 'sdata': { 'foo': '1', 'bar': 'abc' } },
|
|
481
|
+
{ 'sdata': { 'bar': 'abc' } },
|
|
482
|
+
{ 'sdata': { 'foo': 1, 'bar': 'abc', 'baz': 1 } },
|
|
483
|
+
];
|
|
484
|
+
for (const item of post) {
|
|
485
|
+
const str = lText.stringifyJson(item).replace(/"/g, '"');
|
|
486
|
+
echo.push(`<input type="button" value="Post '${str}'" onclick="post('${str}')"><br>`);
|
|
487
|
+
}
|
|
488
|
+
echo.push(`<script>
|
|
489
|
+
function post(p) {
|
|
490
|
+
document.getElementById('result').innerText = 'Waiting...';
|
|
491
|
+
fetch('${this._config.const.urlBase}test/ctr-checkinput-schema1', {
|
|
492
|
+
method: 'POST',
|
|
493
|
+
headers: {
|
|
494
|
+
'content-type': 'application/json'
|
|
495
|
+
},
|
|
496
|
+
body: p
|
|
497
|
+
}).then(function(r) {
|
|
498
|
+
return r.text();
|
|
499
|
+
}).then(function(t) {
|
|
500
|
+
document.getElementById('result').innerText = t;
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
</script>
|
|
504
|
+
<br>Result:<pre id="result">Nothing.</pre>`);
|
|
505
|
+
return echo.join('') + this._getEnd();
|
|
506
|
+
}
|
|
507
|
+
async ctrCheckinputSchema1() {
|
|
508
|
+
if (!await this._handleFormData()) {
|
|
509
|
+
return [0];
|
|
510
|
+
}
|
|
511
|
+
const retur = [];
|
|
512
|
+
if (!this._checkInput(this._post, {
|
|
513
|
+
'sdata': [{
|
|
514
|
+
'schema': {
|
|
515
|
+
'type': 'object',
|
|
516
|
+
'properties': {
|
|
517
|
+
'foo': { 'type': 'integer' },
|
|
518
|
+
'bar': { 'type': 'string' }
|
|
519
|
+
},
|
|
520
|
+
'required': ['foo']
|
|
521
|
+
}
|
|
522
|
+
}, [0, 'The sdata param is incorrect.']],
|
|
523
|
+
}, retur)) {
|
|
524
|
+
return retur;
|
|
525
|
+
}
|
|
526
|
+
return [1, { 'post': this._post }];
|
|
527
|
+
}
|
|
472
528
|
async ctrLocale() {
|
|
473
529
|
const rtn = [];
|
|
474
530
|
if (!this._checkInput(this._get, {
|
|
@@ -1162,6 +1218,31 @@ lCore.checkType(o7, type2): ${lCore.checkType(o7, type2)}<br><br>
|
|
|
1162
1218
|
o8:<pre>${JSON.stringify(o8)}</pre>
|
|
1163
1219
|
lCore.checkType(o8, type1): ${lCore.checkType(o8, type1)}<br>
|
|
1164
1220
|
lCore.checkType(o8, type2): ${lCore.checkType(o8, type2)}
|
|
1221
|
+
<br><br>${this._getEnd()}`;
|
|
1222
|
+
}
|
|
1223
|
+
coreCheckschema() {
|
|
1224
|
+
const schema = {
|
|
1225
|
+
'type': 'object',
|
|
1226
|
+
'properties': {
|
|
1227
|
+
'foo': { 'type': 'integer' },
|
|
1228
|
+
'bar': { 'type': 'string' }
|
|
1229
|
+
},
|
|
1230
|
+
'required': ['foo'],
|
|
1231
|
+
'additionalProperties': false
|
|
1232
|
+
};
|
|
1233
|
+
const o1 = { 'foo': 1, 'bar': 'abc' };
|
|
1234
|
+
const o2 = { 'foo': '1', 'bar': 'abc' };
|
|
1235
|
+
const o3 = { 'bar': 'abc' };
|
|
1236
|
+
const o4 = { 'foo': 1, 'bar': 'abc', 'baz': 1 };
|
|
1237
|
+
return `schema:<pre>${JSON.stringify(schema, null, 2)}</pre>
|
|
1238
|
+
o1:<pre>${JSON.stringify(o1)}</pre>
|
|
1239
|
+
lCore.checkSchema(o1, schema): ${lCore.checkSchema(o1, schema)}<br><br>
|
|
1240
|
+
o2:<pre>${JSON.stringify(o2)}</pre>
|
|
1241
|
+
lCore.checkSchema(o2, schema): ${lCore.checkSchema(o2, schema)}<br><br>
|
|
1242
|
+
o3:<pre>${JSON.stringify(o3)}</pre>
|
|
1243
|
+
lCore.checkSchema(o3, schema): ${lCore.checkSchema(o3, schema)}<br><br>
|
|
1244
|
+
o4:<pre>${JSON.stringify(o4)}</pre>
|
|
1245
|
+
lCore.checkSchema(o4, schema): ${lCore.checkSchema(o4, schema)}
|
|
1165
1246
|
<br><br>${this._getEnd()}`;
|
|
1166
1247
|
}
|
|
1167
1248
|
coreMuid() {
|