Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stricter fuzz tests, handle self variable #5

Merged
merged 7 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tsd-ext-type-gen",
"version": "1.0.4",
"version": "1.0.5",
"description": "TypeScript definitions generator that parses script APIs from Defold extensions",
"repository": {
"type": "git",
Expand Down
52 changes: 41 additions & 11 deletions src/xtgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const HEADER = `/** @noSelfInFile */

// Invalid names in TypeScript
const INVALID_NAMES = [
'any',
'boolean',
'break',
'case',
'catch',
Expand All @@ -27,26 +29,36 @@ const INVALID_NAMES = [
'delete',
'do',
'else',
'enum',
'export',
'extends',
'false',
'finally',
'for',
'function',
'if',
'implements',
'import',
'in',
'instanceof',
'interface',
'let',
'new',
'null',
'package',
'private',
'protected',
'public',
'return',
'static',
'super',
'switch',
'this',
'throw',
'true',
'try',
'typeof',
'undefined',
'var',
'void',
'while',
Expand Down Expand Up @@ -291,15 +303,31 @@ function isApiFunc(
}

// Sanitizes name
function getName(name: string) {
let modifiedName = name.replace('...', 'args');
function getName(name: string, isParam: boolean) {
let modifiedName = String(name);

// Check against the reserved keywords in TypeScript
if (INVALID_NAMES.includes(modifiedName)) {
modifiedName = modifiedName + '_';
}
// Sanitize type name, allow alpha-numeric and underscore

if (isParam) {
// Special case: arguments
modifiedName = modifiedName.replace(/^\.\.\.$/, 'args');
// Special case: Lua's `self` variable
modifiedName = modifiedName.replace(/^self$/, 'this');
}

// Sanitize type name: allow only alpha-numeric, underscore, dollar sign
modifiedName = modifiedName.replace(/[^a-zA-Z0-9_$]/g, '_');
if (modifiedName !== name) {

// If the first character is a number, add a dollar sign to start
if (/^\d/.test(modifiedName)) {
modifiedName = '$' + modifiedName;
}

// If we're modifying a function name, not a parameter, give a warning
if (!isParam && modifiedName !== name) {
console.warn(`Modifying invalid name "${name}" to "${modifiedName}"`);
}

Expand Down Expand Up @@ -331,7 +359,7 @@ function getType(
}

function sanitizeForComment(str: string) {
return str.replace(/\*\//g, '');
return str.replace(/\*\//g, '*\\/');
}

// Transforms and sanitizes descriptions
Expand Down Expand Up @@ -397,7 +425,7 @@ function getReturnComments(

function getParamComments(parameters: ScriptApiParameter[], newDesc: string) {
parameters.forEach((param) => {
const name = param.name ? getName(param.name) : '';
const name = param.name ? getName(param.name, true) : '';
if (name) {
newDesc += `\n * @param`;
if (param.type) {
Expand Down Expand Up @@ -453,7 +481,7 @@ function generateTableDefinition(
details: ScriptDetails,
start = false,
): string {
const name = entry.name ? getName(entry.name) : DEFAULT_NAME_IF_BLANK;
const name = entry.name ? getName(entry.name, false) : DEFAULT_NAME_IF_BLANK;
let tableDeclaration = `export namespace ${name} {\n`;
if (start) {
tableDeclaration = details.isLua
Expand Down Expand Up @@ -482,13 +510,15 @@ function generateFunctionDefinition(
return `(${parameters}) => ${returnType}`;
} else {
const comment = getComments(entry);
const name = entry.name ? getName(entry.name) : DEFAULT_NAME_IF_BLANK;
const name = entry.name
? getName(entry.name, false)
: DEFAULT_NAME_IF_BLANK;
return `${comment}export function ${name}(${parameters}): ${returnType};\n`;
}
}

function getParameterDefinition(param: ScriptApiParameter): string {
const name = param.name ? getName(param.name) : DEFAULT_NAME_IF_BLANK;
const name = param.name ? getName(param.name, true) : DEFAULT_NAME_IF_BLANK;
const optional = param.optional ? '?' : '';
let type = getType(param.type, 'param');

Expand Down Expand Up @@ -528,7 +558,7 @@ function getReturnType(

// Function to generate TypeScript definitions for ScriptApiEntry
function generateEntryDefinition(entry: ScriptApiEntry): string {
const name = entry.name ? getName(entry.name) : DEFAULT_NAME_IF_BLANK;
const name = entry.name ? getName(entry.name, false) : DEFAULT_NAME_IF_BLANK;
const varType = isAllUppercase(name) ? 'const' : 'let';
const type = getType(entry.type, 'return');
const comment = getComments(entry);
Expand All @@ -546,7 +576,7 @@ function generateTypeScriptDefinitions(

api.forEach((entry) => {
// Handle nested properties
if (entry.name && entry.name.includes('.')) {
if (typeof entry.name === 'string' && entry.name.includes('.')) {
const namePieces = entry.name.split('.');
const entryNamespace = namePieces[0];
const entryName = namePieces[1];
Expand Down
103 changes: 71 additions & 32 deletions tests/fuzz.script_api
Original file line number Diff line number Diff line change
@@ -1,39 +1,78 @@
- name: "Fuzz!ngExtens!on"
type: "t@ble"
desc: "Extension for Fuzz!ng JavaScript Code"
- name: Fuzz!ngExtens!on
type: t@ble
desc: Extension for Fuzz!ng JavaScript Code
members:
- name: "fuzzC*de"
type: "function"
desc: "Fuzzes the provided JavaScript code."
- name: fuzzC*de
type: function
desc: Fuzzes the provided JavaScript code.
parameters:
- name: "c*de"
type: "str!ng"
desc: "The JavaScript code to be fuzzed. Must be a valid str!ng."
- name: ...
desc: The JavaScript code to be fuzzed.
returns:
- name: "fuzz?dC*de"
type: "s*ring"
desc: "The fuzzed JavaScript code."
- name: fuzz?dC*de
type: s*ring
desc: The fuzzed JavaScript code.
examples:
- desc: "Fuzz!ng a sample JavaScript code"

- name: "/*gen&rate!nval!dInput"
type: "function"
desc: "Generates an !nval!d JavaScript !nput for test!ng."
- desc: Fuzz!ng a sample JavaScript code
- name: /*gen&rate!nval!dInput
type: function
desc: Generates an !nval!d JavaScript !nput for test!ng.
parameters:
- name: "//c*de"
type: "str!ng|n&mber|h@sh"
desc: "Optional JavaScript code to be fuzzed. Must be a valid str!ng."
- name: "t3+st"
type: "s=r!ng"
- name: "f%zz"
type: "str&ng"
desc: "/* */ //"
- name: self
type: any
- name: //c*de
type: str!ng|n&mber|h@sh
desc: Optional JavaScript code to be fuzzed!
- name: t3+st
type: s=r!ng
- name: f%zz
type: str&ng
desc: /* */ //
returns:
- name: "!nval!dInput"
type: "st.r!ng"
desc: "The generated !nval!d JavaScript !nput."
- name: '!nval!dInput'
type: st.r!ng
desc: The generated !nval!d JavaScript !nput.
examples:
- desc: "Generating !nval!d JavaScript input"

- name: "/*C&NST@NT"
type: "f#nct!on"
- desc: Generating !nval!d JavaScript input
- name: /*C&NST@NT
type: f#nct!on
- name: 1invalid
- name: class
- name: const
- name: break
- name: let's_try_this
- name: 123_variable
- name: true
- name: false
- name: function
- name: typeof
- name: undefined
- name: for
- name: in
- name: instanceof
- name: switch
- name: case
- name: try
- name: catch
- name: throw
- name: package
- name: private
- name: protected
- name: public
- name: return
- name: static
- name: super
- name: this
- name: while
- name: with
- name: yield
- name: delete
- name: debugger
- name: else
- name: enum
- name: export
- name: extends
- name: finally
- name: if
- name: implements
- name: import
2 changes: 1 addition & 1 deletion tests/game.project
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
title = Test
; Value from fuzz.script_api as a zip
dependencies#0 = data:application/zip;base64,UEsDBBQACAAIADtMPlgAAAAAAAAAAJ8EAAAPACAAZnV6ei5zY3JpcHRfYXBpVVQNAAcCM7llAzO5ZQIzuWV1eAsAAQT1AQAABBQAAACllNFqgzAUhu/7FMeOeeFovdhdYawg29hg3UX7Aqk5tgGNkhxLJ334JWq7KNoVlitDzjnfn/w/zkCyDBcwfS2rypO7lyOh1F4upxMA+i7sES23Kdo9Rx2bfVMjcglJrqBthA92YOtYiYIgynldn2G2RaUX5hNgdiYlpiEKmgq7WkpSyphEA7arhdnxqIH2CIXKD4Ijd1GxQc3PLQVTBkEXZAcbO0gHq0kZ9e5BC94YYg8ElMMWwV4A+Rw+S012z+DAUsGhGXVRo5BKJYek2AHPPBoRFCgxKqhBjz4AHllWpNhhOu9obWKg65r+jOmk61IY7FD6ihF60lzP4++yKOk2z95Qou3UwCS07S7Ps6Pq8Jgact/sqoNheNXDk/Rt3E77pd4PPN9XYZWy9H+mOnLo8UHTkJqnbqJ+bb+vqmH1/qDhYQBBCGH4d6CGLOoQ5ldCvmvd4qNW3ZKv1nMT3aExolHWj1jkr9ab5WrTj9WdiVX9D/oBUEsHCN+ExiB1AQAAnwQAAFBLAQIUAxQACAAIADtMPljfhMYgdQEAAJ8EAAAPACAAAAAAAAAAAACkgQAAAABmdXp6LnNjcmlwdF9hcGlVVA0ABwIzuWUDM7llAjO5ZXV4CwABBPUBAAAEFAAAAFBLBQYAAAAAAQABAF0AAADSAQAAAAA=
dependencies#0 = data:application/zip;base64,UEsDBBQAAAAIAG+/Q1ieTyB9KAIAAI0HAAAPAAAAZnV6ei5zY3JpcHRfYXBpjZPFluswDIb3F97BGWbcXWYm2s9xbDXxGUfOsVXuw9+4HCUDu+ar9P8iHwuUBTwRH7qjUYLZ+wEBhsTh4wdC0LCs/qFXqYX4qSGoJ2IWYRyKjvOLNPFF9uRf5U1J4q3T0/ACihR8eBJ/C7Hw6VQJbw80zOjMI1JUVGnO6dwqikMQlIMovesZDXrdSFVGJ4uMUvpKn1aG66YnJ/O4dfV/OXA1QU6kMK0R9DLFA3U9tunGwJd61c56S+HAG8xabWcGN/cCA1mUFmqOs+zlvKUI0xiuUR/26UEGuOMlQYI9aRP9Gcsu3Wf0HwEh5gUhUcyT172SKDS9AIJAVUX3W0QA22mOSuKwGXp6qtrnSr6ym+BOvK5J/irkzRn/LGNH0t6636TpSZeHgVosn0fLlvVvj0atBe60Lf70QBycVm3dfVa769vabXM48clNt5XNN6dvXNt97my+f4NZm4yJMvzU3u78+Pvv1Y9/7Lw2UVHisB59bqKo0XWqrAyBIYeBOaUe5HUdWaDdcEV+eEW5Cczq4vKqJ72RqWWvg3yXkY60gaP586jT2Jvr1FkXNXQMgmYCzteBQf4dSKJq6IW+IZWzccjQaGLIQxpZlHvXr6NSqmuZAYPe9CQ1oCNQBJrhbmqNqrPZRbMuSBKPC90S2FCae+vnxgJDhlhnQwOWFabBAgFnaTfLuCc0lg3YLRgZlM4TZwSoA1uzQWkt24VhKzXxuRWAFDifufwHUEsBAj8AFAAAAAgAb79DWJ5PIH0oAgAAjQcAAA8AAAAAAAAAAAAgAAAAAAAAAGZ1enouc2NyaXB0X2FwaVBLBQYAAAAAAQABAD0AAABVAgAAAAA=
; defstring doesn't have a script_api
dependencies#1 = https://github.com/subsoap/defstring/archive/master.zip
; The following deps all have script_api
Expand Down
Loading