-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add missing Engine API properties (#12)
- Loading branch information
1 parent
0963605
commit 6a975c8
Showing
2 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { readFileSync } from 'fs'; | ||
import { resolve } from 'path'; | ||
|
||
// eslint-disable-next-line import/no-unresolved | ||
import { ArrayType, Converter, DeclarationReflection, IntrinsicType, ReflectionFlag, ReflectionKind, ReferenceType, UnionType } from 'typedoc'; | ||
|
||
/** | ||
* Extract property types from JSDoc in a .js file. | ||
* | ||
* @param {string} filePath - The path to the .js file. | ||
* @returns {Map<string, string>} A map of property names to types. | ||
*/ | ||
function getProperties(filePath) { | ||
const data = readFileSync(resolve(process.cwd(), filePath), 'utf-8'); | ||
const docBlocks = data.match(/\/\*\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g); | ||
const properties = new Map(); | ||
|
||
if (docBlocks) { | ||
docBlocks.forEach((block) => { | ||
const propertyLines = block.match(/@property\s*\{[^}]+\}\s*[^*]*/g); | ||
|
||
if (propertyLines) { | ||
propertyLines.forEach((line) => { | ||
const match = line.match(/@property\s*\{([^}]+)\}\s*(\w+)/); | ||
|
||
if (match) { | ||
let type = match[1].trim(); | ||
const name = match[2].trim(); | ||
|
||
// Simplify complex import types. | ||
type = type.replace(/import\(['"]([^'"]+)['"]\)\.(\w+)/g, (_, p1, p2) => p2); | ||
|
||
properties.set(name, type); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
return properties; | ||
} | ||
|
||
/** | ||
* This Typedoc plugin adds missing PlayCanvas API symbols to the Typedoc reflection graph. The | ||
* symbols are missing because they are generated by `Object.defineProperty` in the PlayCanvas | ||
* sourcebase. The TypeScript compiler is unable to detect them, either in the code or in the | ||
* JSDoc comments (specified via \@property tags). | ||
* | ||
* @param {import('typedoc').Application} app - The Typedoc application. | ||
*/ | ||
function load(app) { | ||
const classes = new Map([ | ||
['ButtonComponent', './submodules/engine/src/framework/components/button/component.js'], | ||
['CollisionComponent', './submodules/engine/src/framework/components/collision/component.js'], | ||
['ElementComponent', './submodules/engine/src/framework/components/element/component.js'], | ||
['LightComponent', './submodules/engine/src/framework/components/light/component.js'], | ||
['ParticleSystemComponent', './submodules/engine/src/framework/components/particle-system/component.js'], | ||
['ScrollbarComponent', './submodules/engine/src/framework/components/scrollbar/component.js'], | ||
['ScrollViewComponent', './submodules/engine/src/framework/components/scroll-view/component.js'], | ||
['StandardMaterial', './submodules/engine/src/scene/materials/standard-material.js'] | ||
]); | ||
|
||
app.converter.on(Converter.EVENT_RESOLVE_BEGIN, (/** @type {import('typedoc').Context} */ context) => { | ||
const getReference = (type) => { | ||
const reflection = context.project.children[0].children.find(child => child.name === type && child.kind === ReflectionKind.Class); | ||
if (!reflection) { | ||
console.error(`Unable to find class ${type}`); | ||
} | ||
return reflection; | ||
}; | ||
|
||
classes.forEach((filePath, className) => { | ||
const reflection = getReference(className); | ||
|
||
/** | ||
* Returns the reference type matching the specified class name. | ||
* | ||
* @param {string} type - The class name. | ||
* @returns {ReferenceType} The reference type. | ||
*/ | ||
const getReferenceType = (type) => { | ||
const reference = getReference(type); | ||
return reference ? new ReferenceType(type, reference, context.project) : undefined; | ||
}; | ||
|
||
/** | ||
* Returns the Typedoc type matching the specified JSDoc type. This can include a union type (|). | ||
* | ||
* @param {string} type - The JSDoc type string. | ||
* @returns {import('typedoc').Type} The Typedoc type. | ||
*/ | ||
const getType = (type) => { | ||
if (type.includes('|')) { | ||
const types = type.split('|'); | ||
return new UnionType(types.map(type => getType(type))); | ||
} | ||
|
||
switch (type) { | ||
case 'null': | ||
return new IntrinsicType('null'); | ||
case 'boolean': | ||
return new IntrinsicType('boolean'); | ||
case 'number': | ||
return new IntrinsicType('number'); | ||
case 'number[]': | ||
return new ArrayType(new IntrinsicType('number')); | ||
case 'string': | ||
return new IntrinsicType('string'); | ||
default: | ||
return getReferenceType(type); | ||
} | ||
}; | ||
|
||
const properties = getProperties(filePath); | ||
|
||
// Get just the @property definitions from the class' JSDoc block | ||
const blockTags = reflection.comment.blockTags.filter(blockTag => blockTag.tag === '@property'); | ||
|
||
// Convert all @property tags on StandardMaterial to actual child properties of StandardMaterial | ||
for (const blockTag of blockTags) { | ||
const newProperty = new DeclarationReflection(blockTag.name, ReflectionKind.Property, reflection); | ||
|
||
const type = properties.get(blockTag.name); | ||
|
||
newProperty.type = getType(type); | ||
|
||
// Mark the new property as public | ||
newProperty.setFlag(ReflectionFlag.Public, true); | ||
|
||
// Add the new property to the class | ||
if (!reflection.children) { | ||
reflection.children = []; | ||
} | ||
reflection.children.push(newProperty); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
export { load }; |