-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Fix TypeScript typing for filterColor shader hook #8644
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
base: dev-2.0
Are you sure you want to change the base?
Changes from all commits
a5f85a7
ea3b6b4
9de7f94
fdf4b55
ce9ef51
36f70e2
c42ef81
c809894
51a03f0
ca4c1a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -175,4 +175,3 @@ export function applyPatches() { | |
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,10 +26,18 @@ const constantsLookup = new Set(); | |
| const typedefs = {}; | ||
| const mutableProperties = new Set(['disableFriendlyErrors']); // Properties that should be mutable, not constants | ||
| allRawData.forEach(entry => { | ||
| if (entry.kind === 'constant' || entry.kind === 'typedef') { | ||
| if (entry.kind === 'constant') { | ||
| constantsLookup.add(entry.name); | ||
| if (entry.kind === 'typedef') { | ||
| typedefs[entry.name] = entry.type; | ||
| } | ||
|
|
||
| // Collect object typedefs so constants referencing them can resolve to proper types | ||
| if (entry.kind === 'typedef') { | ||
| if ( | ||
| entry.properties && | ||
| entry.properties.length > 0 && | ||
| !entry.properties.every(p => p.name === entry.name) | ||
| ) { | ||
| typedefs[entry.name] = entry; | ||
| } | ||
| } | ||
| }); | ||
|
|
@@ -201,6 +209,16 @@ function convertTypeToTypeScript(typeNode, options = {}) { | |
| throw new Error(`convertTypeToTypeScript expects an object, got: ${typeof typeNode} - ${JSON.stringify(typeNode)}`); | ||
| } | ||
|
|
||
| if (typeNode.properties && typeNode.properties.length > 0) { | ||
| const props = typeNode.properties.map(prop => { | ||
| const propType = convertTypeToTypeScript(prop.type, options); | ||
| const optional = prop.optional ? '?' : ''; | ||
| return `${prop.name}${optional}: ${propType}`; | ||
| }); | ||
|
|
||
| return `{ ${props.join('; ')} }`; | ||
| } | ||
|
|
||
| const { currentClass = null, isInsideNamespace = false, inGlobalMode = false, isConstantDef = false } = options; | ||
|
|
||
| switch (typeNode.type) { | ||
|
|
@@ -242,19 +260,18 @@ function convertTypeToTypeScript(typeNode, options = {}) { | |
| } | ||
| } | ||
|
|
||
| // Check if this is a p5 constant - use typeof since they're defined as values | ||
| // If p5 constant: use its typedef when defining it, else reference it as a value via `typeof` | ||
| if (constantsLookup.has(typeName)) { | ||
| if (inGlobalMode) { | ||
| return `typeof P5.${typeName}`; | ||
| } else if (typedefs[typeName]) { | ||
| if (isConstantDef) { | ||
| return convertTypeToTypeScript(typedefs[typeName], options); | ||
| } else { | ||
| return `typeof p5.${typeName}` | ||
| } | ||
| } else { | ||
| return `Symbol`; | ||
| if (isConstantDef && typedefs[typeName]) { | ||
| return convertTypeToTypeScript(typedefs[typeName], options); | ||
| } | ||
| return inGlobalMode | ||
| ? `typeof P5.${typeName}` | ||
| : `typeof ${typeName}`; | ||
| } | ||
|
|
||
| if (typedefs[typeName]) { | ||
| return typeName; | ||
| } | ||
|
|
||
| return typeName; | ||
|
|
@@ -368,6 +385,11 @@ const typescriptStrategy = { | |
|
|
||
| const processed = processData(rawData, typescriptStrategy); | ||
|
|
||
| // Augment constantsLookup with processed constants | ||
| Object.keys(processed.consts).forEach(name => { | ||
| constantsLookup.add(name); | ||
| }); | ||
|
|
||
| function normalizeIdentifier(name) { | ||
| return ( | ||
| '0123456789'.includes(name[0]) || | ||
|
|
@@ -595,6 +617,22 @@ function generateClassDeclaration(classData) { | |
| function generateTypeDefinitions() { | ||
| let output = '// This file is auto-generated from JSDoc documentation\n\n'; | ||
|
|
||
| const strandsMethods = processStrandsFunctions(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why this was moved up here from below?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had moved it earlier because it was being used too late in the generation flow and wasn’t available in time, which was causing some errors. But after the recent changes I made, I don't think it's needed to initialise it at the start of the function |
||
|
|
||
| Object.entries(typedefs).forEach(([name, entry]) => { | ||
| if (entry.properties && entry.properties.length > 0) { | ||
| const props = entry.properties.map(prop => { | ||
| const propType = prop.type ? convertTypeToTypeScript(prop.type) : 'any'; | ||
| const optional = prop.optional ? '?' : ''; | ||
| return ` ${prop.name}${optional}: ${propType}`; | ||
| }); | ||
| output += `type ${name} = {\n${props.join(';\n')};\n};\n\n`; | ||
| } else { | ||
| const tsType = convertTypeToTypeScript(entry.type || entry); | ||
| output += `type ${name} = ${tsType};\n\n`; | ||
| } | ||
| }); | ||
|
|
||
| // First, define all constants at the top level with their actual values | ||
| const seenConstants = new Set(); | ||
| const p5Constants = processed.classitems.filter(item => { | ||
|
|
@@ -606,6 +644,9 @@ function generateTypeDefinitions() { | |
| if (seenConstants.has(item.name)) { | ||
| return false; | ||
| } | ||
| if (item.name in typedefs) { | ||
| return false; | ||
| } | ||
| seenConstants.add(item.name); | ||
| return true; | ||
| } | ||
|
|
@@ -618,12 +659,26 @@ function generateTypeDefinitions() { | |
| output += formatJSDocComment(constant.description, 0) + '\n'; | ||
| output += ' */\n'; | ||
| } | ||
| const type = convertTypeToTypeScript(constant.type, { isInsideNamespace: false, isConstantDef: true }); | ||
| let type; | ||
| // Avoid invalid self-referential types like `typeof FOO` | ||
| if ( | ||
| constant.type?.type === 'NameExpression' && | ||
| constant.type.name === constant.name | ||
| ) { | ||
| // Self-referential constant → fallback | ||
| type = 'number'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is not sufficient yet. When I run declare const P2D: number;
declare const __P2D: typeof P2D;Previously, it looked like this: declare const P2D: 'p2d';
declare const __P2D: typeof P2D;I think a next step should be not just to get the tests to pass -- first, I would
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah sure, I'll try comparing the diffs and try to find out what corrections need to be made to get the original structure + filterColorHook type |
||
| } else { | ||
| type = convertTypeToTypeScript(constant.type, { | ||
| isInsideNamespace: false, | ||
| isConstantDef: true | ||
| }); | ||
| } | ||
| const isMutable = mutableProperties.has(constant.name); | ||
| const declaration = isMutable ? 'declare let' : 'declare const'; | ||
| output += `${declaration} ${constant.name}: ${type};\n\n`; | ||
| // Duplicate with a private identifier so we can re-export in the namespace later | ||
| output += `${declaration} __${constant.name}: typeof ${constant.name};\n\n`; | ||
|
|
||
| }); | ||
|
|
||
| // Generate main p5 class | ||
|
|
@@ -645,7 +700,6 @@ function generateTypeDefinitions() { | |
| }); | ||
|
|
||
| // Add strands functions to p5 instance | ||
| const strandsMethods = processStrandsFunctions(); | ||
| strandsMethods.forEach(method => { | ||
| output += generateMethodDeclaration(method, p5Options); | ||
| }); | ||
|
|
@@ -667,9 +721,16 @@ function generateTypeDefinitions() { | |
|
|
||
| output += '\n'; | ||
|
|
||
|
|
||
| p5Constants.forEach(constant => { | ||
| output += `${mutableProperties.has(constant.name) ? 'let' : 'const'} ${constant.name}: typeof __${constant.name};\n`; | ||
| const isTypedefTyped = | ||
| constant.type?.type === 'NameExpression' && | ||
| constant.type?.name in typedefs; | ||
|
|
||
| if (isTypedefTyped) { | ||
| output += `${mutableProperties.has(constant.name) ? 'let' : 'const'} ${constant.name}: ${constant.type.name};\n`; | ||
| } else { | ||
| output += `${mutableProperties.has(constant.name) ? 'let' : 'const'} ${constant.name}: typeof __${constant.name};\n`; | ||
| } | ||
| }); | ||
|
|
||
| output += '\n'; | ||
|
|
@@ -820,4 +881,4 @@ console.log('TypeScript definitions generated successfully!'); | |
|
|
||
| // Apply patches | ||
| console.log('Applying TypeScript patches...'); | ||
| applyPatches(); | ||
| applyPatches(); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these be
: voidtoo or is there a reason for them to be: undefined?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I tried using
void, the generatedp5.d.tsended up showinganyinstead. I tried using different ways to define a function but it still kept showingany. So I've defined it asundefinedwhich showed up correctly while generatingp5.js.d.ts