Files
GDevelop/GDevelop.js/scripts/generate-types.js
D8H 18e8020bf5 Simplify the list of actions/conditions by removing duplicated actions/conditions that are common between objects (#5494)
* Actions, conditions and expressions related to opacity, size (width/height), scale, animations and other common features are now visible only once when you search for them in actions/conditions (instead of being shown once for every type of object supporting them). This reduces the risk of confusion for new or existing users, notably when multiple versions of the same action were returned by the search and was making it difficult to choose the proper one.
* Internally, this works thanks to default, built-in behaviors that are supported by the objects.
2023-08-25 11:11:55 +02:00

391 lines
14 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* This uses the IDL definitions (Bindings.idl),
* to generate types that can be consumed in the IDE codebase.
*
* Bindings.idl is also used by Emscripten
* to generate the JS interface to the WebAssembly compiled C++ code of GDCore/GDJS.
* The parsers and code generation have a few hacks (see postjs.js), so
* we need to also do some hacks/manipulation on the input and some resulting files.
*/
const shell = require('shelljs');
const path = require('path');
const fs = require('fs');
shell.cd(path.join(__dirname, '..'));
const idlTempFolder = fs.mkdtempSync('gdevelopjs-cleaned-bindings-idl');
// Remove some "extended attributes" from the webIDL definitions as they
// are not supported by the webidl2.js parser used by "webidl-tools".
shell.cp('-f', 'Bindings/Bindings.idl', idlTempFolder);
const idlFile = path.join(idlTempFolder, 'Bindings.idl');
shell.sed('-i', /\[Prefix="gdjs::"\]/, '//Removed gdjs prefix', idlFile);
shell.sed(
'-i',
/\[Prefix="gd::InstructionMetadata::"\]/,
'//Removed gd::InstructionMetadata prefix',
idlFile
);
// Don't remove the "types" folder because then Flow
// is not loading the files. This means a removed class must
// have its typing file be removed manually.
// shell.rm('-rf', 'types/');
// Run "webidl-tools flow" that will take care of converting
// the webIDL declarations to Flow classes.
const webidlToolsFlowResult = shell.exec(
`node node_modules/webidl-tools/bin/webidl-tools-flow --out types` +
` --module-name libGDevelop` +
// Prefix all classes by "gd", to easily recognise them
// in the IDE codebase:
` --prefix-interfaces gd` +
// Add "delete" method (see postjs.js) and "ptr"
// (as it's used in the codebase)
` --add-delete-operation` +
` --add-emscripten-ptr-attribute` +
// Transform functions from UpperCamelCase to lowerCamelCase.
` --uncapitalize-operations` +
// Static functions are prefixed
` --static-operation-prefix STATIC_` +
// Functions starting by WRAPPED_, MAP_, FREE_ will be
// stripped of their prefix (see postjs.js):
` --rename "s/WRAPPED_//" --rename "s/MAP_//" --rename "s/FREE_//"` +
// Functions starting by CLONE_ will be renamed to clone
// (see postjs.js and update-bindings.js)
` --rename "s/CLONE_.*/clone/"` +
` ${idlFile}`,
{},
(code, stdout, stderr) => {
fs.unlinkSync(idlFile);
fs.rmdirSync(idlTempFolder);
if (code !== 0 || stdout.length > 1000) {
shell.echo(
'❌ The output of "webidl-tools flow" is suspiciously long or errored. Considering as an error.'
);
shell.echo(
' Is Bindings.idl improperly formatted, or using a syntax not understood by "webidl-tools flow"?'
);
shell.exit(1);
}
fs.writeFileSync(
'types/other-adhoc-types.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
declare type gdSerializable = any;
declare type gdEmscriptenObject = {
ptr: number;
};
`
);
// Fix enums, that are numbers and can be accessed from their enclosing class.
fs.writeFileSync(
'types/eventsfunction_functiontype.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
type EventsFunction_FunctionType = 0 | 1 | 2 | 3 | 4`
);
shell.sed(
'-i',
'declare class gdEventsFunction {',
[
'declare class gdEventsFunction {',
' static Action: 0;',
' static Condition: 1;',
' static Expression: 2;',
' static ExpressionAndCondition: 3;',
' static ActionWithOperator: 4;',
].join('\n'),
'types/gdeventsfunction.js'
);
fs.writeFileSync(
'types/variable_type.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
type Variable_Type = 0 | 1 | 2 | 3 | 4`
);
shell.sed(
'-i',
'declare class gdVariable {',
[
'declare class gdVariable {',
' static String: 0;',
' static Number: 1;',
' static Boolean: 2;',
' static Structure: 3;',
' static Array: 4;',
].join('\n'),
'types/gdvariable.js'
);
fs.writeFileSync(
'types/expressioncompletiondescription_completionkind.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
type ExpressionCompletionDescription_CompletionKind = 0 | 1 | 2 | 3 | 4`
);
shell.sed(
'-i',
'declare class gdExpressionCompletionDescription {',
[
'declare class gdExpressionCompletionDescription {',
' static Object: 0;',
' static Behavior: 1;',
' static Expression: 2;',
' static Variable: 3;',
' static Text: 4;',
].join('\n'),
'types/gdexpressioncompletiondescription.js'
);
fs.writeFileSync(
'types/particleemitterobject_renderertype.js',
`// Automatically generated by GDevelop.js/scripts/generate-types.js
type ParticleEmitterObject_RendererType = 0 | 1 | 2`
);
shell.sed(
'-i',
'declare class gdParticleEmitterObject {',
[
'declare class gdParticleEmitterObject {',
' static Point: 0;',
' static Line: 1;',
' static Quad: 2;',
].join('\n'),
'types/gdparticleemitterobject.js'
);
// Add convenience methods that are manually added (see postjs.js):
shell.sed(
'-i',
'declare class libGDevelop {',
[
'declare class libGDevelop {',
' getPointer(gdEmscriptenObject): number;',
' castObject<T>(gdEmscriptenObject, Class<T>): T;',
' compare(gdEmscriptenObject, gdEmscriptenObject): boolean;',
'',
' getTypeOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string;',
' getTypeOfBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): string;',
' getBehaviorsOfObject(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, searchInGroups: boolean): gdVectorString;',
' isDefaultBehavior(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): boolean;',
' getTypeOfBehaviorInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): string;',
' getBehaviorNamesInObjectOrGroup(globalObjectsContainer: gdObjectsContainer, objectsContainer: gdObjectsContainer, objectName: string, behaviorName: string, searchInGroups: boolean): gdVectorString;',
'',
' removeFromVectorParameterMetadata(gdVectorParameterMetadata, index: number): void;',
' swapInVectorParameterMetadata(gdVectorParameterMetadata, oldIndex: number, newIndex: number): void;',
'',
` asStandardEvent(gdBaseEvent): gdStandardEvent;`,
` asRepeatEvent(gdBaseEvent): gdRepeatEvent;`,
` asWhileEvent(gdBaseEvent): gdWhileEvent;`,
` asForEachEvent(gdBaseEvent): gdForEachEvent;`,
` asForEachChildVariableEvent(gdBaseEvent): gdForEachChildVariableEvent;`,
` asCommentEvent(gdBaseEvent): gdCommentEvent;`,
` asGroupEvent(gdBaseEvent): gdGroupEvent;`,
` asLinkEvent(gdBaseEvent): gdLinkEvent;`,
` asJsCodeEvent(gdBaseEvent): gdJsCodeEvent;`,
` asPlatform(gdPlatform): gdPlatform;`,
'',
` asSpriteConfiguration(gdObjectConfiguration): gdSpriteObject;`,
` asTiledSpriteConfiguration(gdObjectConfiguration): gdTiledSpriteObject;`,
` asPanelSpriteConfiguration(gdObjectConfiguration): gdPanelSpriteObject;`,
` asTextObjectConfiguration(gdObjectConfiguration): gdTextObject;`,
` asShapePainterConfiguration(gdObjectConfiguration): gdShapePainterObject;`,
` asAdMobConfiguration(gdObjectConfiguration): gdAdMobObject;`,
` asTextEntryConfiguration(gdObjectConfiguration): gdTextEntryObject;`,
` asParticleEmitterConfiguration(gdObjectConfiguration): gdParticleEmitterObject;`,
` asObjectJsImplementation(gdObjectConfiguration): gdObjectJsImplementation;`,
` asCustomObjectConfiguration(gdObjectConfiguration): gdCustomObjectConfiguration;`,
` asModel3DConfiguration(gdObjectConfiguration): gdModel3DObjectConfiguration;`,
'',
` asImageResource(gdResource): gdImageResource;`,
'',
].join('\n'),
'types/libgdevelop.js'
);
shell.sed(
'-i',
'declare class gdVectorString {',
'declare class gdVectorString {\n toJSArray(): Array<string>;',
'types/gdvectorstring.js'
);
shell.sed(
'-i',
'declare class gdVectorInt {',
'declare class gdVectorInt {\n toJSArray(): Array<number>;',
'types/gdvectorint.js'
);
shell.sed(
'-i',
'declare class gdSerializer {',
`declare class gdSerializer {
static fromJSObject(object: Object): gdSerializerElement;
static toJSObject(element: gdSerializerElement): any;
`,
'types/gdserializer.js'
);
shell.sed(
'-i',
'declare class gdInstructionsList {',
'declare class gdInstructionsList {\n push_back(gdInstruction): void;',
'types/gdinstructionslist.js'
);
// Add inheritance not expressed in Bindings.idl.
// TODO: these should be expressed in Bindings.idl using "implements".
shell.sed(
'-i',
'declare class gdProject {',
'declare class gdProject extends gdObjectsContainer {',
'types/gdproject.js'
);
shell.sed(
'-i',
'declare class gdLayout {',
'declare class gdLayout extends gdObjectsContainer {',
'types/gdlayout.js'
);
shell.sed(
'-i',
'declare class gdEventsBasedObject {',
'declare class gdEventsBasedObject extends gdObjectsContainer {',
'types/gdeventsbasedobject.js'
);
shell.sed(
'-i',
'declare class gdEventsFunctionsExtension {',
'declare class gdEventsFunctionsExtension extends gdEventsFunctionsContainer {',
'types/gdeventsfunctionsextension.js'
);
shell.sed(
'-i',
'declare class gdObjectJsImplementation {',
'declare class gdObjectJsImplementation extends gdObjectConfiguration {',
'types/gdobjectjsimplementation.js'
);
shell.sed(
'-i',
'declare class gdCustomObjectConfiguration {',
'declare class gdCustomObjectConfiguration extends gdObjectConfiguration {',
'types/gdcustomobjectconfiguration.js'
);
shell.sed(
'-i',
'declare class gdBehaviorJsImplementation {',
'declare class gdBehaviorJsImplementation extends gdBehavior {',
'types/gdbehaviorjsimplementation.js'
);
shell.sed(
'-i',
'declare class gdBehaviorSharedDataJsImplementation {',
'declare class gdBehaviorSharedDataJsImplementation extends gdBehaviorsSharedData {',
'types/gdbehaviorshareddatajsimplementation.js'
);
shell.sed(
'-i',
'declare class gdJsPlatform {',
'declare class gdJsPlatform extends gdPlatform {',
'types/gdjsplatform.js'
);
shell.sed(
'-i',
'declare class gdExpressionValidator {',
'declare class gdExpressionValidator extends gdExpressionParser2NodeWorker {',
'types/gdexpressionvalidator.js'
);
shell.sed(
'-i',
'declare class gdHighestZOrderFinder {',
'declare class gdHighestZOrderFinder extends gdInitialInstanceFunctor {',
'types/gdhighestzorderfinder.js'
);
shell.sed(
'-i',
'declare class gdGroupEvent {',
'declare class gdGroupEvent extends gdBaseEvent {',
'types/gdgroupevent.js'
);
[
'BaseEvent',
'StandardEvent',
'RepeatEvent',
'WhileEvent',
'ForEachEvent',
'CommentEvent',
'GroupEvent',
'LinkEvent',
'JsCodeEvent',
].forEach((eventClassName) => {
shell.sed(
'-i',
`declare class gd${eventClassName} {`,
`declare class gd${eventClassName} extends gdBaseEvent {`,
`types/gd${eventClassName.toLowerCase()}.js`
);
});
// Rename classes from GDJS:
shell.sed(
'-i',
'declare class gdExporter {',
'declare class gdjsExporter {',
'types/gdexporter.js'
);
// Improve typing of resources kind.
shell.sed(
'-i',
/setKind\(kind: string\): void/,
"setKind(kind: 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D'): void",
'types/gdresource.js'
);
shell.sed(
'-i',
/getKind\(\): string/,
"getKind(): 'image' | 'audio' | 'font' | 'video' | 'json' | 'tilemap' | 'tileset' | 'model3D'",
'types/gdresource.js'
);
// Add missing declaration of set_/get_ functions, automatically added by Emscripten
// for attributes:
shell.sed(
'-i',
'x: number;',
'x: number;\n set_x(number): void;\n get_x(): number;',
'types/gdvector2f.js'
);
shell.sed(
'-i',
'y: number;',
'y: number;\n set_y(number): void;\n get_y(): number;',
'types/gdvector2f.js'
);
// Set a few parameters as optionals. No parameter is ever optional when compiled in Emscripten,
// but passing undefined is tolerated for these and it's convenient:
shell.sed(
'-i',
'type: string, description: string, optionalObjectType: string, parameterIsOptional: boolean',
'type: string, description: string, optionalObjectType?: string, parameterIsOptional?: boolean',
'types/gdinstructionmetadata.js'
);
shell.sed(
'-i',
'type: string, description: string, optionalObjectType: string, parameterIsOptional: boolean',
'type: string, description: string, optionalObjectType?: string, parameterIsOptional?: boolean',
'types/gdexpressionmetadata.js'
);
shell.sed(
'-i',
'type: string, description: string, optionalObjectType: string, parameterIsOptional: boolean',
'type: string, description: string, optionalObjectType?: string, parameterIsOptional?: boolean',
'types/gdmultipleinstructionmetadata.js'
);
// Add a notice that the file is auto-generated.
shell.sed(
'-i',
'declare class',
'// Automatically generated by GDevelop.js/scripts/generate-types.js\ndeclare class',
'types/*.js'
);
shell.echo('✅ Properly generated GDevelop.js types.');
}
);