gennady 0.2.2 → 0.5.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/README.md +107 -10
- package/cli/cmd/cat.js +26 -0
- package/cli/cmd/commit.js +83 -0
- package/cli/cmd/review.js +58 -0
- package/cli/gennady.js +19 -40
- package/index.js +2 -0
- package/package.json +5 -3
- package/src/ai/ai-core.js +187 -0
- package/src/cat-gen/cat-gen.js +53 -0
- package/src/commit-gen/commit-gen.js +38 -71
- package/src/git/git-core.js +69 -0
- package/src/git/git-diff.js +36 -13
- package/src/prompts/commit/commit-base-prompt.md +38 -0
- package/src/prompts/commit/commit-format-detailed-prompt.md +29 -0
- package/src/prompts/commit/commit-format-oneline-prompt.md +19 -0
- package/src/prompts/commit/commit-translate-prompt.md +15 -0
- package/src/prompts/index.js +10 -0
- package/src/prompts/review/review-base-prompt.md +46 -0
- package/src/review-gen/__fixture__/review-gen-fixture.md +110 -0
- package/src/review-gen/review-gen.js +119 -0
- package/src/review-gen/review-gen.test.js +79 -0
- package/src/review-gen/specs/js/Function.prototype.json +162 -0
- package/src/review-gen/specs/js/Global.json +219 -0
- package/src/review-gen/specs/js/JSON.json +85 -0
- package/src/review-gen/specs/js/Object.json +626 -0
- package/src/review-gen/specs/js/Object.prototype.json +337 -0
- package/src/review-gen/specs/js/Storage.json +97 -0
- package/src/utils/parse-args.js +7 -3
- package/src/utils/style.js +12 -3
- package/src/git/git-cmd.js +0 -32
- package/src/prompts/base-prompt.md +0 -27
- package/src/prompts/format-detailed-prompt.md +0 -16
- package/src/prompts/format-oneline-prompt.md +0 -11
- package/src/prompts/translate-prompt.md +0 -11
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { AiCore } from "../ai/ai-core.js";
|
|
2
|
+
import { prompts } from "../prompts/index.js";
|
|
3
|
+
import { readFileSync, readdirSync } from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
|
|
7
|
+
const LANG_SPECS_DIR = join(
|
|
8
|
+
typeof __dirname !== 'string' ? dirname(fileURLToPath(import.meta.url)) : __dirname,
|
|
9
|
+
'specs',
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export class ReviewGen {
|
|
13
|
+
_langSpecs = {};
|
|
14
|
+
|
|
15
|
+
constructor(init) {
|
|
16
|
+
this.init = {
|
|
17
|
+
basePromptTemplate: prompts.review('base'),
|
|
18
|
+
timeout: 120,
|
|
19
|
+
|
|
20
|
+
...init,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
this.ai = new AiCore({
|
|
24
|
+
logger: this.logger,
|
|
25
|
+
timeout: this.init.timeout,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async generate(
|
|
30
|
+
code,
|
|
31
|
+
langs = [code.includes('.ts') ? 'TypeScript' : 'JavaScript'],
|
|
32
|
+
) {
|
|
33
|
+
const input = this.init.basePromptTemplate
|
|
34
|
+
.replaceAll('{LANGUAGES}', langs.join(', '))
|
|
35
|
+
.replaceAll('\n{EXTRA_RULES}\n', this._getExtraRulesPrompt(langs, code))
|
|
36
|
+
.replaceAll('{INPUT}', code);
|
|
37
|
+
|
|
38
|
+
// console.debug(`<input>${input}</input>`);
|
|
39
|
+
|
|
40
|
+
const output = await this.ai.generate(input);
|
|
41
|
+
|
|
42
|
+
// console.info(`<output>${output}</output>`);
|
|
43
|
+
|
|
44
|
+
return output;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_getExtraRulesPrompt(langs, code) {
|
|
48
|
+
const spec = this._loadSpec(langs);
|
|
49
|
+
|
|
50
|
+
const globals = Object.keys(spec.Global.properties);
|
|
51
|
+
const rGlobals = new RegExp(`\\b(${globals.join('|')})\\b`, 'g');
|
|
52
|
+
const exists = {};
|
|
53
|
+
let prompt = '';
|
|
54
|
+
let matches = null
|
|
55
|
+
|
|
56
|
+
while (matches = rGlobals.exec(code)) {
|
|
57
|
+
const name = matches[0];
|
|
58
|
+
const {exceptions, type} = spec.Global.properties[name];
|
|
59
|
+
|
|
60
|
+
if (!exists[name]) {
|
|
61
|
+
exists[name] = true;
|
|
62
|
+
|
|
63
|
+
if (exceptions?.length) {
|
|
64
|
+
prompt += `## ${name} handling:\n`
|
|
65
|
+
exceptions.forEach(({type, description}) => {
|
|
66
|
+
prompt += `- ${type}: ${description}\n`;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Object.entries(spec[type]?.methods || {}).forEach(([method, {exceptions, hint}]) => {
|
|
72
|
+
if (exceptions.length && code.includes(method)) {
|
|
73
|
+
const key = `${name}.${method}`;
|
|
74
|
+
if (!exists[key] && exceptions.length && hint) {
|
|
75
|
+
exists[key] = true;
|
|
76
|
+
|
|
77
|
+
prompt += `## **${key}** handling:\n`;
|
|
78
|
+
prompt += hint.join('\n');
|
|
79
|
+
|
|
80
|
+
// exceptions.forEach(({type, description}) => {
|
|
81
|
+
// prompt += `- ${type}: ${description}\n`;
|
|
82
|
+
// });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return prompt ? `\n${prompt}\n` : '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
_loadSpec(langs) {
|
|
93
|
+
return langs.reduce((spec, lang) => {
|
|
94
|
+
const specName = lang === 'JavaScript' || lang === 'TypeScript' ? 'js' : lang;
|
|
95
|
+
const specPath = join(LANG_SPECS_DIR, specName);
|
|
96
|
+
|
|
97
|
+
this._langSpecs[specName] = {};
|
|
98
|
+
|
|
99
|
+
for (const entry of readdirSync(specPath)) {
|
|
100
|
+
if (!entry.endsWith('.json')) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const rawJson = readFileSync(join(specPath, entry)).toString();
|
|
105
|
+
const json = JSON.parse(rawJson);
|
|
106
|
+
|
|
107
|
+
Object.assign(this._langSpecs[specName], json);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
...spec,
|
|
112
|
+
...this._langSpecs[specName],
|
|
113
|
+
};
|
|
114
|
+
}, {});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { test, describe } from 'node:test';
|
|
5
|
+
import assert from 'node:assert';
|
|
6
|
+
import { ReviewGen } from './review-gen.js';
|
|
7
|
+
|
|
8
|
+
describe('review', async () => {
|
|
9
|
+
const reviewGen = new ReviewGen();
|
|
10
|
+
const fixtures = getFixture();
|
|
11
|
+
|
|
12
|
+
fixtures.forEach(({ name, diff, expected }) => {
|
|
13
|
+
test(name, async () => {
|
|
14
|
+
const result = (await reviewGen.generate(diff)).trim();
|
|
15
|
+
|
|
16
|
+
if (expected.includes('GOOD')) {
|
|
17
|
+
assert.strictEqual(result.includes('GOOD'), true, `Test '${name}': Expected 'GOOD', got: '${result}'`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!expected || expected.length === 0) {
|
|
22
|
+
assert.fail(`Test '${name}': Invalid or empty 'expected' rules.`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
expected.forEach(ruleString => {
|
|
26
|
+
const suggestion = result.match(/suggestion\n([\s\S]+)/)?.[1] || ''
|
|
27
|
+
const rule = createRule(ruleString);
|
|
28
|
+
const expectationText = rule.isNegation ? 'SHOULD NOT match' : 'SHOULD match';
|
|
29
|
+
const matchResult = rule.regexp.test(suggestion);
|
|
30
|
+
|
|
31
|
+
assert.strictEqual(
|
|
32
|
+
matchResult,
|
|
33
|
+
!rule.isNegation,
|
|
34
|
+
`Test '${name}': Output ${expectationText} ${rule.regexp}.\nOutput: '${suggestion}'`
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function createRule(ruleString) {
|
|
42
|
+
const isNegation = ruleString.startsWith('!');
|
|
43
|
+
const pattern = isNegation ? ruleString.slice(1) : ruleString;
|
|
44
|
+
const regexp = new RegExp(pattern.replace(/^\/|\/$/g, ''));
|
|
45
|
+
return { regexp, isNegation, pattern };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getFixture() {
|
|
49
|
+
const filePath = join(
|
|
50
|
+
typeof __dirname !== 'string' ? dirname(fileURLToPath(import.meta.url)) : __dirname,
|
|
51
|
+
'__fixture__',
|
|
52
|
+
'review-gen-fixture.md',
|
|
53
|
+
);
|
|
54
|
+
const text = readFileSync(filePath).toString();
|
|
55
|
+
const blocks = text.trim().split('\n----\n').filter(Boolean);
|
|
56
|
+
const results = [];
|
|
57
|
+
const regex = /^### (.*?)\s*\n+#### Diff\s*\n+```diff\s*\n(.*?)\n```\s*\n+#### Expected\s*\n+(.*)/si;
|
|
58
|
+
|
|
59
|
+
for (const block of blocks) {
|
|
60
|
+
const match = block.trim().match(regex);
|
|
61
|
+
if (!match) continue;
|
|
62
|
+
|
|
63
|
+
const name = match[1].trim();
|
|
64
|
+
const diff = match[2].trim();
|
|
65
|
+
let expectedText = match[3].trim();
|
|
66
|
+
|
|
67
|
+
if (expectedText.startsWith('```')) {
|
|
68
|
+
const lines = expectedText.split('\n');
|
|
69
|
+
expectedText = lines.length > 1 ? lines.slice(1, -1).join('\n').trim() : '';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const expected = expectedText === 'OK'
|
|
73
|
+
? 'OK'
|
|
74
|
+
: expectedText.split('\n').map(r => r.trim().replace(/-\s*/g, '')).filter(Boolean);
|
|
75
|
+
|
|
76
|
+
results.push({ name, diff, expected });
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Function.prototype": {
|
|
3
|
+
"description": "The prototype object for all Function objects. It is itself a built-in function object but cannot be used as a constructor.",
|
|
4
|
+
"properties": {
|
|
5
|
+
"constructor": {
|
|
6
|
+
"value": "Function",
|
|
7
|
+
"attributes": {
|
|
8
|
+
"writable": true,
|
|
9
|
+
"enumerable": false,
|
|
10
|
+
"configurable": true
|
|
11
|
+
},
|
|
12
|
+
"description": "The constructor function that created the instance object. For Function instances, this is the Function constructor."
|
|
13
|
+
},
|
|
14
|
+
"length": {
|
|
15
|
+
"value": 0,
|
|
16
|
+
"attributes": {
|
|
17
|
+
"writable": false,
|
|
18
|
+
"enumerable": false,
|
|
19
|
+
"configurable": true
|
|
20
|
+
},
|
|
21
|
+
"description": "The number of formal parameters expected by the Function.prototype function itself, which is 0."
|
|
22
|
+
},
|
|
23
|
+
"name": {
|
|
24
|
+
"value": "\"\"",
|
|
25
|
+
"attributes": {
|
|
26
|
+
"writable": false,
|
|
27
|
+
"enumerable": false,
|
|
28
|
+
"configurable": true
|
|
29
|
+
},
|
|
30
|
+
"description": "The name of the Function.prototype function itself, which is the empty string."
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"methods": {
|
|
34
|
+
"apply": {
|
|
35
|
+
"description": "Calls the function with a given `this` value and arguments provided as an array (or an array-like object).",
|
|
36
|
+
"arguments": [
|
|
37
|
+
{
|
|
38
|
+
"name": "thisArg",
|
|
39
|
+
"required": false,
|
|
40
|
+
"description": "The value to be passed as the `this` parameter to the target function. If the function is non-strict, `null` or `undefined` will be replaced with the global object, and primitive values will be boxed."
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "argArray",
|
|
44
|
+
"required": false,
|
|
45
|
+
"description": "An array-like object, specifying the arguments with which the function should be called, or `null` or `undefined` if no arguments are provided."
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"returns": {
|
|
49
|
+
"type": "any",
|
|
50
|
+
"description": "The result of calling the function with the specified `this` value and arguments."
|
|
51
|
+
},
|
|
52
|
+
"exceptions": [
|
|
53
|
+
{
|
|
54
|
+
"type": "TypeError",
|
|
55
|
+
"description": "If the `this` value (the function being called) is not callable."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "TypeError",
|
|
59
|
+
"description": "If `argArray` is provided but cannot be converted to a list (e.g., is not array-like or throws during iteration)."
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"bind": {
|
|
64
|
+
"description": "Creates a new function that, when called, has its `this` keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.",
|
|
65
|
+
"arguments": [
|
|
66
|
+
{
|
|
67
|
+
"name": "thisArg",
|
|
68
|
+
"required": true,
|
|
69
|
+
"description": "The value to be passed as the `this` parameter to the target function when the bound function is called. Ignored if the target function is an arrow function or already bound."
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "args",
|
|
73
|
+
"required": false,
|
|
74
|
+
"variadic": true,
|
|
75
|
+
"description": "Arguments to prepend to arguments provided to the bound function when invoking the target function."
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"returns": {
|
|
79
|
+
"type": "Function",
|
|
80
|
+
"description": "A new bound function object with the specified `this` value and initial arguments."
|
|
81
|
+
},
|
|
82
|
+
"exceptions": [
|
|
83
|
+
{
|
|
84
|
+
"type": "TypeError",
|
|
85
|
+
"description": "If the `this` value (the target function) is not callable."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "TypeError",
|
|
89
|
+
"description": "If reading the 'length' or 'name' property of the target function throws an error (potential UserCodeError)."
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"call": {
|
|
94
|
+
"description": "Calls the function with a given `this` value and arguments provided individually.",
|
|
95
|
+
"arguments": [
|
|
96
|
+
{
|
|
97
|
+
"name": "thisArg",
|
|
98
|
+
"required": false,
|
|
99
|
+
"description": "The value to be passed as the `this` parameter to the target function. If the function is non-strict, `null` or `undefined` will be replaced with the global object, and primitive values will be boxed."
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "args",
|
|
103
|
+
"required": false,
|
|
104
|
+
"variadic": true,
|
|
105
|
+
"description": "Arguments for the function."
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"returns": {
|
|
109
|
+
"type": "any",
|
|
110
|
+
"description": "The result of calling the function with the specified `this` value and arguments."
|
|
111
|
+
},
|
|
112
|
+
"exceptions": [
|
|
113
|
+
{
|
|
114
|
+
"type": "TypeError",
|
|
115
|
+
"description": "If the `this` value (the function being called) is not callable."
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
"toString": {
|
|
120
|
+
"description": "Returns a string representing the source code of the function.",
|
|
121
|
+
"arguments": [],
|
|
122
|
+
"returns": {
|
|
123
|
+
"type": "String",
|
|
124
|
+
"description": "A string containing the source code representation of the function. For built-in functions or bound functions, the format is implementation-defined but should resemble 'function name() { [native code] }'."
|
|
125
|
+
},
|
|
126
|
+
"exceptions": [
|
|
127
|
+
{
|
|
128
|
+
"type": "TypeError",
|
|
129
|
+
"description": "If the `this` value is not a callable Object or if its source text is unavailable and it's not a recognized function type."
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"symbols": {
|
|
135
|
+
"[Symbol.hasInstance]": {
|
|
136
|
+
"description": "Used by the `instanceof` operator. Determines if a constructor function recognizes an object as its instance.",
|
|
137
|
+
"attributes": {
|
|
138
|
+
"writable": false,
|
|
139
|
+
"enumerable": false,
|
|
140
|
+
"configurable": false
|
|
141
|
+
},
|
|
142
|
+
"arguments": [
|
|
143
|
+
{
|
|
144
|
+
"name": "V",
|
|
145
|
+
"required": true,
|
|
146
|
+
"description": "The value to check."
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"returns": {
|
|
150
|
+
"type": "Boolean",
|
|
151
|
+
"description": "`true` if `V` is considered an instance of the function; `false` otherwise. Based on prototype chain checks by default."
|
|
152
|
+
},
|
|
153
|
+
"exceptions": [
|
|
154
|
+
{
|
|
155
|
+
"type": "TypeError",
|
|
156
|
+
"description": "If the `this` value (the function) is not an object, or if checking the prototype chain fails (e.g., accessing prototype throws)."
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Global": {
|
|
3
|
+
"description": "Function Properties of the Global Object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"localStorage": {
|
|
6
|
+
"description": "Provides access to a Storage object for the document's origin, saved across browser sessions. Data has no expiration time (except in private browsing modes).",
|
|
7
|
+
"type": "Storage",
|
|
8
|
+
"readOnly": true,
|
|
9
|
+
"exceptions": [
|
|
10
|
+
{
|
|
11
|
+
"type": "SecurityError",
|
|
12
|
+
"description": "Thrown upon access if the origin is invalid (e.g., file:, data:) or if storage access is disallowed by policy/user settings (e.g., blocking cookies)."
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"sessionStorage": {
|
|
17
|
+
"description": "Provides access to a Storage object for the document's origin, cleared when the page session ends (e.g., when the browser tab is closed).",
|
|
18
|
+
"type": "Storage",
|
|
19
|
+
"readOnly": true,
|
|
20
|
+
"exceptions": [
|
|
21
|
+
{
|
|
22
|
+
"type": "SecurityError",
|
|
23
|
+
"description": "Thrown upon access if the origin is invalid (e.g., file:, data:) or if storage access is disallowed by policy/user settings (e.g., blocking cookies)."
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"JSON": {
|
|
28
|
+
"type": "JSON"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"methods": {
|
|
32
|
+
"isFinite": {
|
|
33
|
+
"description": "Determines whether the passed value is a finite number.",
|
|
34
|
+
"arguments": [
|
|
35
|
+
{
|
|
36
|
+
"name": "number",
|
|
37
|
+
"required": true,
|
|
38
|
+
"description": "The value to be tested for finiteness."
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"returns": {
|
|
42
|
+
"type": "Boolean",
|
|
43
|
+
"description": "`false` if the argument coerces to `NaN`, positive `Infinity`, or negative `Infinity`; otherwise, `true`."
|
|
44
|
+
},
|
|
45
|
+
"exceptions": [
|
|
46
|
+
{
|
|
47
|
+
"type": "TypeError",
|
|
48
|
+
"description": "If the `number` argument cannot be converted to a Number (e.g., it's a Symbol or an object with faulty conversion methods)."
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"isNaN": {
|
|
53
|
+
"description": "Determines whether the passed value is NaN.",
|
|
54
|
+
"arguments": [
|
|
55
|
+
{
|
|
56
|
+
"name": "number",
|
|
57
|
+
"required": true,
|
|
58
|
+
"description": "The value to be tested for NaN."
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"returns": {
|
|
62
|
+
"type": "Boolean",
|
|
63
|
+
"description": "`true` if the given value coerces to `NaN`; otherwise, `false`."
|
|
64
|
+
},
|
|
65
|
+
"exceptions": [
|
|
66
|
+
{
|
|
67
|
+
"type": "TypeError",
|
|
68
|
+
"description": "If the `number` argument cannot be converted to a Number (e.g., it's a Symbol or an object with faulty conversion methods)."
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
"parseFloat": {
|
|
73
|
+
"description": "Parses a string argument and returns a floating-point number.",
|
|
74
|
+
"arguments": [
|
|
75
|
+
{
|
|
76
|
+
"name": "string",
|
|
77
|
+
"required": true,
|
|
78
|
+
"description": "The string to parse."
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"returns": {
|
|
82
|
+
"type": "Number",
|
|
83
|
+
"description": "A floating-point number parsed from the given string. If the first character cannot be converted to a number, `NaN` is returned."
|
|
84
|
+
},
|
|
85
|
+
"exceptions": [
|
|
86
|
+
{
|
|
87
|
+
"type": "TypeError",
|
|
88
|
+
"description": "If the `string` argument cannot be converted to a String (e.g., it's a Symbol or an object with faulty conversion methods)."
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"parseInt": {
|
|
93
|
+
"description": "Parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).",
|
|
94
|
+
"arguments": [
|
|
95
|
+
{
|
|
96
|
+
"name": "string",
|
|
97
|
+
"required": true,
|
|
98
|
+
"description": "The string to parse."
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "radix",
|
|
102
|
+
"required": false,
|
|
103
|
+
"description": "An integer between 2 and 36 that represents the radix (the base in mathematical numeral systems) of the string. If omitted or 0, it is assumed to be 10, except when the number begins with the code unit pairs '0x' or '0X', in which case a radix of 16 is assumed."
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"returns": {
|
|
107
|
+
"type": "Number",
|
|
108
|
+
"description": "An integer parsed from the given string. If the radix is smaller than 2 or bigger than 36, or the first non-whitespace character cannot be converted to a number, `NaN` is returned."
|
|
109
|
+
},
|
|
110
|
+
"exceptions": [
|
|
111
|
+
{
|
|
112
|
+
"type": "TypeError",
|
|
113
|
+
"description": "If the `string` argument cannot be converted to a String."
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "TypeError",
|
|
117
|
+
"description": "If the `radix` argument cannot be converted to a Number (when performing ToInt32)."
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"decodeURI": {
|
|
122
|
+
"description": "Computes a new version of a URI by replacing UTF-8 escape sequences created by encodeURI with the characters they represent. Escape sequences that could not have been introduced by encodeURI are not replaced.",
|
|
123
|
+
"arguments": [
|
|
124
|
+
{
|
|
125
|
+
"name": "encodedURI",
|
|
126
|
+
"required": true,
|
|
127
|
+
"description": "A String representing an encoded URI."
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"returns": {
|
|
131
|
+
"type": "String",
|
|
132
|
+
"description": "A new string representing the decoded URI."
|
|
133
|
+
},
|
|
134
|
+
"exceptions": [
|
|
135
|
+
{
|
|
136
|
+
"type": "TypeError",
|
|
137
|
+
"description": "The `encodedURI` argument cannot be converted to a String."
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "URIError",
|
|
141
|
+
"description": "The `encodedURI` contains a malformed percent-encoded sequence or an invalid UTF-8 sequence."
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"decodeURIComponent": {
|
|
146
|
+
"description": "Computes a new version of a URI component by replacing UTF-8 escape sequences created by encodeURIComponent with the characters they represent.",
|
|
147
|
+
"arguments": [
|
|
148
|
+
{
|
|
149
|
+
"name": "encodedURIComponent",
|
|
150
|
+
"required": true,
|
|
151
|
+
"description": "A String representing an encoded URI component."
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
"returns": {
|
|
155
|
+
"type": "String",
|
|
156
|
+
"description": "A new string representing the decoded URI component."
|
|
157
|
+
},
|
|
158
|
+
"exceptions": [
|
|
159
|
+
{
|
|
160
|
+
"type": "TypeError",
|
|
161
|
+
"description": "The `encodedURIComponent` argument cannot be converted to a String."
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"type": "URIError",
|
|
165
|
+
"description": "The `encodedURIComponent` contains a malformed percent-encoded sequence or an invalid UTF-8 sequence."
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
"encodeURI": {
|
|
170
|
+
"description": "Computes a new version of a URI by replacing instances of certain characters with their UTF-8 escape sequences. Assumes the input is a complete URI, so reserved characters (';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#') are not encoded.",
|
|
171
|
+
"arguments": [
|
|
172
|
+
{
|
|
173
|
+
"name": "uri",
|
|
174
|
+
"required": true,
|
|
175
|
+
"description": "A String representing a complete URI."
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"returns": {
|
|
179
|
+
"type": "String",
|
|
180
|
+
"description": "A new string representing the encoded URI."
|
|
181
|
+
},
|
|
182
|
+
"exceptions": [
|
|
183
|
+
{
|
|
184
|
+
"type": "TypeError",
|
|
185
|
+
"description": "The `uri` argument cannot be converted to a String."
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"type": "URIError",
|
|
189
|
+
"description": "The `uri` contains an unpaired surrogate code point."
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
},
|
|
193
|
+
"encodeURIComponent": {
|
|
194
|
+
"description": "Computes a new version of a URI component by replacing instances of certain characters with their UTF-8 escape sequences. Assumes the input is a component of a URI, so characters reserved in URIs (';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#') are encoded.",
|
|
195
|
+
"arguments": [
|
|
196
|
+
{
|
|
197
|
+
"name": "uriComponent",
|
|
198
|
+
"required": true,
|
|
199
|
+
"description": "A String representing a URI component."
|
|
200
|
+
}
|
|
201
|
+
],
|
|
202
|
+
"returns": {
|
|
203
|
+
"type": "String",
|
|
204
|
+
"description": "A new string representing the encoded URI component."
|
|
205
|
+
},
|
|
206
|
+
"exceptions": [
|
|
207
|
+
{
|
|
208
|
+
"type": "TypeError",
|
|
209
|
+
"description": "The `uriComponent` argument cannot be converted to a String."
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"type": "URIError",
|
|
213
|
+
"description": "The `uriComponent` contains an unpaired surrogate code point."
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"JSON": {
|
|
3
|
+
"description": "The JSON object provides methods to parse JSON strings and convert values to JSON strings.",
|
|
4
|
+
"methods": {
|
|
5
|
+
"parse": {
|
|
6
|
+
"description": "Parses a JSON string, constructing the JavaScript value or object described by the string.",
|
|
7
|
+
"arguments": [
|
|
8
|
+
{
|
|
9
|
+
"name": "text",
|
|
10
|
+
"required": true,
|
|
11
|
+
"description": "A String containing the JSON-formatted text."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "reviver",
|
|
15
|
+
"required": false,
|
|
16
|
+
"description": "A function that can filter and transform the results."
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"returns": {
|
|
20
|
+
"type": "any",
|
|
21
|
+
"description": "The ECMAScript value corresponding to the JSON text (Object, Array, String, Number, Boolean, or null)."
|
|
22
|
+
},
|
|
23
|
+
"exceptions": [
|
|
24
|
+
{
|
|
25
|
+
"type": "SyntaxError",
|
|
26
|
+
"description": "The input string `text` is not valid JSON text."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "TypeError",
|
|
30
|
+
"description": "The `text` argument cannot be converted to a String."
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "UserCodeError",
|
|
34
|
+
"description": "An error was thrown by the `reviver` function."
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"hint": [
|
|
38
|
+
"When you identify an unsafe `JSON.parse` call in the code review, your generated `suggestion` should follow the pattern shown in this reference example: wrap the call in `try...catch`, log the error and then return `null`."
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"stringify": {
|
|
42
|
+
"description": "Converts a JavaScript value to a JSON string, optionally replacing values or including only specified properties.",
|
|
43
|
+
"arguments": [
|
|
44
|
+
{
|
|
45
|
+
"name": "value",
|
|
46
|
+
"required": true,
|
|
47
|
+
"description": "The JavaScript value to convert to a JSON string."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "replacer",
|
|
51
|
+
"required": false,
|
|
52
|
+
"description": "A function that alters the stringification process, or an array of Strings/Numbers used as an inclusion list for properties."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "space",
|
|
56
|
+
"required": false,
|
|
57
|
+
"description": "A String or Number used to insert white space into the output JSON string for readability."
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"returns": {
|
|
61
|
+
"type": "String | undefined",
|
|
62
|
+
"description": "A JSON string representing the given value, or `undefined` if the value (or the value returned by `replacer` or `toJSON`) is `undefined`, a `Function`, or a `Symbol`."
|
|
63
|
+
},
|
|
64
|
+
"exceptions": [
|
|
65
|
+
{
|
|
66
|
+
"type": "TypeError",
|
|
67
|
+
"description": "A cyclic structure was found in the `value`."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"type": "TypeError",
|
|
71
|
+
"description": "Attempted to serialize a BigInt value."
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"type": "UserCodeError",
|
|
75
|
+
"description": "An error was thrown by the `toJSON` method of an object."
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "UserCodeError",
|
|
79
|
+
"description": "An error was thrown by the `replacer` function."
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|