Skip to content

Commit 3d30487

Browse files
authored
Asserter#generateTypeChecks: Handle @typedef's for ObjectPattern + more unit tests + nice names for potential warning (#175)
* Add unit test: test/typechecking/simple-ObjectPattern-typedef-input.mjs * Asserter#generateTypeChecks: Handle @typedef's for ObjectPattern + more unit tests + nice names for potential warning * Fix lint * Fix unit tests by using fancy/nice JSDoc `@param` name
1 parent 951e28f commit 3d30487

7 files changed

+116
-37
lines changed

src-transpiler/Asserter.js

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ class Asserter extends Stringifier {
443443
// ${JSON.stringify(jsdoc)}\n${parent}\n${spaces}*/\n`;
444444
for (let name in params) {
445445
const type = params[name];
446+
// Copy name for warnings, `name` may become `arguments[${paramIndex}]`.
447+
const nameFancy = name;
446448
const hasParam = this.nodeHasParamName(node, name);
447449
if (!hasParam) {
448450
let testNode = node;
@@ -480,47 +482,53 @@ class Asserter extends Stringifier {
480482
}
481483
const t = JSON.stringify(type.elementType, null, 2).replaceAll('\n', '\n' + spaces);
482484
if (templates) {
483-
out += `${spaces}if (!inspectTypeWithTemplates(${element.name}, ${t}, '${loc}', '${name}', rtiTemplates)) {\n`;
485+
out += `${spaces}if (!inspectTypeWithTemplates(${element.name}, ${t}, '${loc}', '${nameFancy}', rtiTemplates)) {\n`;
484486
} else {
485-
out += `${spaces}if (!inspectType(${element.name}, ${t}, '${loc}', '${name}')) {\n`;
487+
out += `${spaces}if (!inspectType(${element.name}, ${t}, '${loc}', '${nameFancy}')) {\n`;
486488
}
487489
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
488490
}
489491
continue;
490-
} else if (param.left.type === 'ObjectPattern' && type.type === 'object') {
491-
// Add a type assertion for each property of the ObjectPattern
492-
for (const property of param.left.properties) {
493-
if (property.key.type !== 'Identifier') {
494-
this.warn('ObjectPattern> Only Identifier case handled right now');
495-
continue;
496-
}
497-
const keyName = property.key.name;
498-
if (type.type !== 'object' || !type.properties) {
499-
this.warn(
500-
"missing subtype information in JSDoc> in type",
501-
JSON.stringify(type, null, 2),
502-
"for ObjectPattern:", this.toSource(property).trim()
503-
);
504-
continue;
505-
}
506-
const subType = type.properties[keyName];
507-
if (!subType) {
508-
this.warn("missing subtype information in JSDoc");
509-
continue;
492+
} else if (param.left.type === 'ObjectPattern') {
493+
if (type.type === 'object') {
494+
// Add a type assertion for each property of the ObjectPattern
495+
for (const property of param.left.properties) {
496+
if (property.key.type !== 'Identifier') {
497+
this.warn('ObjectPattern> Only Identifier case handled right now');
498+
continue;
499+
}
500+
const keyName = property.key.name;
501+
if (type.type !== 'object' || !type.properties) {
502+
this.warn(
503+
"missing subtype information in JSDoc> in type",
504+
JSON.stringify(type, null, 2),
505+
"for ObjectPattern:", this.toSource(property).trim()
506+
);
507+
continue;
508+
}
509+
const subType = type.properties[keyName];
510+
if (!subType) {
511+
this.warn("missing subtype information in JSDoc");
512+
continue;
513+
}
514+
const t = JSON.stringify(subType, null, 2).replaceAll('\n', '\n' + spaces);
515+
if (templates) {
516+
out += `${spaces}if (!inspectTypeWithTemplates(${keyName}, ${t}, '${loc}', '${nameFancy}', rtiTemplates)) {\n`;
517+
} else {
518+
out += `${spaces}if (!inspectType(${keyName}, ${t}, '${loc}', '${nameFancy}')) {\n`;
519+
}
520+
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
510521
}
511-
const t = JSON.stringify(subType, null, 2).replaceAll('\n', '\n' + spaces);
512-
if (templates) {
513-
out += `${spaces}if (!inspectTypeWithTemplates(${keyName}, ${t}, '${loc}', '${name}', rtiTemplates)) {\n`;
514-
} else {
515-
out += `${spaces}if (!inspectType(${keyName}, ${t}, '${loc}', '${name}')) {\n`;
516-
}
517-
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
522+
continue;
523+
} else if (typeof type === 'string') {
524+
// The case when we have an ObjectPattern with a @typedef
525+
name = `arguments[${paramIndex}]`;
518526
}
527+
} else {
528+
this.warn(`generateTypeChecks> ${loc}> todo implement`,
529+
`AssignmentPattern for parameter ${name}`);
519530
continue;
520531
}
521-
this.warn(`generateTypeChecks> ${loc}> todo implement`,
522-
`AssignmentPattern for parameter ${name}`);
523-
continue;
524532
}
525533
} else {
526534
const loc = this.getName(node);
@@ -552,9 +560,9 @@ class Asserter extends Stringifier {
552560
first = false;
553561
}
554562
if (templates) {
555-
out += `${spaces}if (${prevCheck}!inspectTypeWithTemplates(${name}, ${t}, '${loc}', '${name}', rtiTemplates)) {\n`;
563+
out += `${spaces}if (${prevCheck}!inspectTypeWithTemplates(${name}, ${t}, '${loc}', '${nameFancy}', rtiTemplates)) {\n`;
556564
} else {
557-
out += `${spaces}if (${prevCheck}!inspectType(${name}, ${t}, '${loc}', '${name}')) {\n`;
565+
out += `${spaces}if (${prevCheck}!inspectType(${name}, ${t}, '${loc}', '${nameFancy}')) {\n`;
558566
}
559567
out += `${spaces} youCanAddABreakpointHere();\n${spaces}}\n`;
560568
}

test/typechecking.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@
115115
"input": "./test/typechecking/simple-ObjectPattern-input.mjs",
116116
"output": "./test/typechecking/simple-ObjectPattern-output.mjs"
117117
},
118+
{
119+
"input": "./test/typechecking/simple-ObjectPattern-typedef-input.mjs",
120+
"output": "./test/typechecking/simple-ObjectPattern-typedef-output.mjs"
121+
},
118122
{
119123
"input": "./test/typechecking/template-types-1-input.mjs",
120124
"output": "./test/typechecking/template-types-1-output.mjs"

test/typechecking/functions-output.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function fetchSomething(url, {
3737
"optional": true
3838
}
3939
}
40-
}, 'fetchSomething', 'arguments[1]')) {
40+
}, 'fetchSomething', 'options')) {
4141
youCanAddABreakpointHere();
4242
}
4343
function inner() {}

test/typechecking/simple-ArrayPattern-output.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function center_to_corners_format([centerX, centerY, width, height]) {
99
"type": "array",
1010
"elementType": "number",
1111
"optional": false
12-
}, 'center_to_corners_format', 'arguments[0]')) {
12+
}, 'center_to_corners_format', 'arr')) {
1313
youCanAddABreakpointHere();
1414
}
1515
return [

test/typechecking/simple-ObjectPattern-output.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function fetchSomething(url, {
3737
"optional": true
3838
}
3939
}
40-
}, 'fetchSomething', 'arguments[1]')) {
40+
}, 'fetchSomething', 'options')) {
4141
youCanAddABreakpointHere();
4242
}
4343
console.log('fetchSomething>', {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class Tokenizer {
2+
/**
3+
* Loads a pre-trained tokenizer from the given `pretrained_model_name_or_path`.
4+
*
5+
* @param {string} pretrained_model_name_or_path The path to the pre-trained tokenizer.
6+
* @param {PretrainedTokenizerOptions} options Additional options for loading the tokenizer.
7+
*
8+
* @throws {Error} Throws an error if the tokenizer.json or tokenizer_config.json files are not found in the `pretrained_model_name_or_path`.
9+
* @returns {Promise<PreTrainedTokenizer>} A new instance of the `PreTrainedTokenizer` class.
10+
*/
11+
static async from_pretrained(pretrained_model_name_or_path, {
12+
progress_callback = null,
13+
config = null,
14+
cache_dir = null,
15+
local_files_only = false,
16+
revision = 'main',
17+
legacy = null,
18+
} = {}) {
19+
const info = await loadTokenizer(pretrained_model_name_or_path, {
20+
progress_callback,
21+
config,
22+
cache_dir,
23+
local_files_only,
24+
revision,
25+
legacy,
26+
});
27+
// @ts-ignore
28+
return new this(...info);
29+
}
30+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class Tokenizer {
2+
/**
3+
* Loads a pre-trained tokenizer from the given `pretrained_model_name_or_path`.
4+
*
5+
* @param {string} pretrained_model_name_or_path The path to the pre-trained tokenizer.
6+
* @param {PretrainedTokenizerOptions} options Additional options for loading the tokenizer.
7+
*
8+
* @throws {Error} Throws an error if the tokenizer.json or tokenizer_config.json files are not found in the `pretrained_model_name_or_path`.
9+
* @returns {Promise<PreTrainedTokenizer>} A new instance of the `PreTrainedTokenizer` class.
10+
*/
11+
static async from_pretrained(pretrained_model_name_or_path, {
12+
progress_callback = null,
13+
config = null,
14+
cache_dir = null,
15+
local_files_only = false,
16+
revision = 'main',
17+
legacy = null,
18+
} = {}) {
19+
if (!inspectType(pretrained_model_name_or_path, "string", 'Tokenizer#from_pretrained', 'pretrained_model_name_or_path')) {
20+
youCanAddABreakpointHere();
21+
}
22+
if (!inspectType(arguments[1], "PretrainedTokenizerOptions", 'Tokenizer#from_pretrained', 'options')) {
23+
youCanAddABreakpointHere();
24+
}
25+
const info = await loadTokenizer(pretrained_model_name_or_path, {
26+
progress_callback,
27+
config,
28+
cache_dir,
29+
local_files_only,
30+
revision,
31+
legacy,
32+
});
33+
// @ts-ignore
34+
return new this(...info);
35+
}
36+
}
37+
registerClass(Tokenizer);

0 commit comments

Comments
 (0)