Skip to content

Commit

Permalink
Merge f6ed454 into 311eb32
Browse files Browse the repository at this point in the history
  • Loading branch information
markwpearce committed Jun 6, 2024
2 parents 311eb32 + f6ed454 commit 7f82797
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 22 deletions.
65 changes: 55 additions & 10 deletions scripts/scrape-roku-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -553,19 +553,30 @@ class Runner {

private getNodeFields(manager: TokenManager) {
const result = [] as SceneGraphNodeField[];
const tables = manager.getAllTablesByHeaders(['field', 'type', 'default', 'access permission', 'description']);
const tables = [
...manager.getAllTablesByHeaders(['field', 'type', 'default', 'access permission', 'description']),
...manager.getAllTablesByHeaders(['field', 'type', 'description'], null, null, (headingToken) => {
return (headingToken as marked.Tokens.Heading)?.text?.toLowerCase() === 'fields';
})
];
for (const table of tables) {
const rows = manager.tableToObjects(table);
const descriptionIndex = table.header.findIndex(header => header.text.toLowerCase() === 'description');
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
let description = table.rows[i][4].text;
let description = table.rows[i][descriptionIndex].text;
//the turndown plugin doesn't convert inner html tables, so turn that into markdown too
description = turndownService.turndown(description);

if (!row.field) {
continue;
}

result.push({
name: this.sanitizeMarkdownSymbol(row.field),
type: this.sanitizeMarkdownSymbol(row.type, { allowSquareBrackets: true, allowSpaces: true }),
default: this.sanitizeMarkdownSymbol(row.default, { allowSquareBrackets: true, allowSpaces: true }),
accessPermission: this.sanitizeMarkdownSymbol(row['access permission'], { allowSpaces: true }),
default: (row.default !== undefined) ? this.sanitizeMarkdownSymbol(row.default, { allowSquareBrackets: true, allowSpaces: true }) : null,
accessPermission: row['access permission'] ? this.sanitizeMarkdownSymbol(row['access permission'], { allowSpaces: true }) : 'READ_WRITE',
//grab all the markdown from the 4th column (description)
description: description
});
Expand Down Expand Up @@ -1227,6 +1238,30 @@ class Runner {
}],
returnType: 'Void'
}]
},
ifsocketasync: {
methods: [{

description: 'Returns the message port (if any) currently associated with the object',
name: 'GetMessagePort',
params: [],
returnDescription: 'The message port.',
returnType: 'Object'

}, {
description: 'Sets the roMessagePort to be used to receive events.',
name: 'SetMessagePort',
params: [
{
default: null,
description: 'The port to be used to receive events.',
isRequired: true,
name: 'port',
type: 'Object'
}
],
returnType: 'Void'
}]
}
}
});
Expand Down Expand Up @@ -1552,7 +1587,7 @@ class TokenManager {
/**
* Scan the tokens and find the first the top-level table based on the header names
*/
public getTableByHeaders(searchHeaders: string[], startAt?: Token, endTokenMatcher?: EndTokenMatcher): TableEnhanced {
public getTableByHeaders(searchHeaders: string[], startAt?: Token, endTokenMatcher?: TokenMatcher): TableEnhanced {
let startIndex = this.tokens.indexOf(startAt);
startIndex = startIndex > -1 ? startIndex : 0;

Expand All @@ -1576,13 +1611,22 @@ class TokenManager {
/**
* Scan the tokens and find the all top-level tables based on the header names
*/
public getAllTablesByHeaders(searchHeaders: string[], startAt?: Token, endTokenMatcher?: EndTokenMatcher): TableEnhanced[] {
public getAllTablesByHeaders(searchHeaders: string[], startAt?: Token, endTokenMatcher?: TokenMatcher, headingMatcher?: TokenMatcher): TableEnhanced[] {
let startIndex = this.tokens.indexOf(startAt);
startIndex = startIndex > -1 ? startIndex : 0;
const tables = [];
let lastHeading: Token;
for (let i = startIndex + 1; i < this.tokens.length; i++) {
const token = this.tokens[i];
if (token.type === 'heading') {
lastHeading = token;
}
if (token?.type === 'table') {
if (headingMatcher) {
if (!headingMatcher(lastHeading)) {
continue;
}
}
const headers = token?.header?.map(x => x.text.toLowerCase());
if (
headers.every(x => searchHeaders.includes(x)) &&
Expand Down Expand Up @@ -1683,7 +1727,7 @@ class TokenManager {
/**
* Get all text found between the start token and the matched end token
*/
public getTokensBetween(startToken: Token, endTokenMatcher: EndTokenMatcher) {
public getTokensBetween(startToken: Token, endTokenMatcher: TokenMatcher) {
let startIndex = this.tokens.indexOf(startToken);
startIndex = startIndex > -1 ? startIndex : 0;

Expand All @@ -1704,14 +1748,14 @@ class TokenManager {
/**
* Get join all markdown between the specified items
*/
public getMarkdown(startToken: Token, endTokenMatcher: EndTokenMatcher) {
public getMarkdown(startToken: Token, endTokenMatcher: TokenMatcher) {
return this.getTokensBetween(startToken, endTokenMatcher).map(x => x.raw).join('')?.trim() || undefined;
}

/**
* Find any `available since` text between the specified items
*/
public getAvailableSince(startToken: Token, endTokenMatcher: EndTokenMatcher) {
public getAvailableSince(startToken: Token, endTokenMatcher: TokenMatcher) {
const markdown = this.getMarkdown(startToken, endTokenMatcher);
const match = /available\s+since\s?(?:roku\s*os\s*)?([\d\.]+)/i.exec(markdown);
if (match) {
Expand Down Expand Up @@ -1758,7 +1802,8 @@ class TokenManager {
}
}

type EndTokenMatcher = (t: Token) => boolean | undefined;
type TokenMatcher = (t: Token) => boolean | undefined;


interface TableEnhanced extends marked.Tokens.Table {
tokens: {
Expand Down
31 changes: 31 additions & 0 deletions src/Program.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2874,6 +2874,37 @@ describe('Program', () => {
expectZeroDiagnostics(program);
});


it('includes non-standard fields tables', () => {
const table = program.globalScope.symbolTable;
const opts = { flags: SymbolTypeFlag.runtime };
const multiLabel = table.getSymbolType('roSGNodeMultiStyleLabel', { flags: SymbolTypeFlag.typetime });
expectTypeToBe(multiLabel, ComponentType);
expectTypeToBe(multiLabel.getMemberType('drawingStyles', opts), AssociativeArrayType);
});

it('includes overrides from scrapper', () => {
const table = program.globalScope.symbolTable;
const opts = { flags: SymbolTypeFlag.runtime };
const regionType = table.getSymbolType('roRegion', { flags: SymbolTypeFlag.typetime });
expectTypeToBe(regionType, InterfaceType);

const ifDraw2DType = regionType.getMemberType('ifDraw2D', opts) as InterfaceType;
expectTypeToBe(ifDraw2DType, InterfaceType);
expect(ifDraw2DType.name).to.eq('ifDraw2D');
expectTypeToBe(ifDraw2DType.getMemberType('getWidth', opts), TypedFunctionType);
expectTypeToBe(regionType.getMemberType('getWidth', opts), TypedFunctionType);

const streamSocketType = table.getSymbolType('roStreamSocket', { flags: SymbolTypeFlag.typetime });
expectTypeToBe(streamSocketType, InterfaceType);

const socketAsyncType = streamSocketType.getMemberType('ifSocketAsync', opts) as InterfaceType;
expectTypeToBe(socketAsyncType, InterfaceType);
expect(socketAsyncType.name).to.eq('ifSocketAsync');
expectTypeToBe(socketAsyncType.getMemberType('setMessagePort', opts), TypedFunctionType);
expectTypeToBe(streamSocketType.getMemberType('setMessagePort', opts), TypedFunctionType);
});

});

describe('manifest', () => {
Expand Down
44 changes: 33 additions & 11 deletions src/roku-types/data.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generatedDate": "2024-06-04T14:49:50.193Z",
"generatedDate": "2024-06-06T14:10:20.575Z",
"nodes": {
"animation": {
"description": "Extends [**AnimationBase**](https://developer.roku.com/docs/references/scenegraph/abstract-nodes/animationbase.md\n\nThe Animation node class provides animations of renderable nodes, by applying interpolator functions to the values in specified renderable node fields. For an animation to take effect, an Animation node definition must include a child field interpolator node ([FloatFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/floatfieldinterpolator.md\"FloatFieldInterpolator\"), [Vector2DFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/vector2dfieldinterpolator.md\"Vector2DFieldInterpolator\"), [ColorFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/colorfieldinterpolator.md\"ColorFieldInterpolator\")) definition for each renderable node field that is animated.\n\nThe Animation node class provides a simple linear interpolator function, where the animation takes place smoothly and simply from beginning to end. The Animation node class also provides several more complex interpolator functions to allow custom animation effects. For example, you can move a graphic image around the screen at differing speeds and curved trajectories at different times in the animation by specifying the appropriate function in the easeFunction field (quadratic and exponential are two examples of functions that can be specified). The interpolator functions are divided into two parts: the beginning of the animation (ease-in), and the end of the animation (ease-out). You can apply a specified interpolator function to either or both ease-in and ease-out, or specify no function for either or both (which is the linear function). You can also change the portion of the animation that is ease-in and ease-out to arbitrary fractional values for a quadratic interpolator function applied to both ease-in and ease-out.",
Expand Down Expand Up @@ -433,13 +433,6 @@
"url": "https://developer.roku.com/docs/references/scenegraph/node.md"
},
"fields": [
{
"accessPermission": "",
"default": "",
"description": "",
"name": "",
"type": ""
},
{
"accessPermission": "READ_ONLY",
"default": "",
Expand Down Expand Up @@ -3664,7 +3657,15 @@
"name": "LabelBase",
"url": "https://developer.roku.com/docs/references/scenegraph/label-nodes/label-base.md"
},
"fields": [],
"fields": [
{
"accessPermission": "READ_WRITE",
"default": null,
"description": "Defines the size, URI, and color of a font style. This field may contain one or more font styles.",
"name": "drawingStyles",
"type": "associative array of associative arrays"
}
],
"interfaces": [],
"name": "MultiStyleLabel",
"url": "https://developer.roku.com/docs/references/scenegraph/label-nodes/multi-style-label.md"
Expand Down Expand Up @@ -5041,7 +5042,7 @@
"type": "assocarray"
},
{
"accessPermission": "",
"accessPermission": "READ_WRITE",
"default": "invalid",
"description": "Setting this field to a node extended from a \\*\\*Dialog\\*\\* node causes the dialog to be displayed",
"name": "dialog",
Expand Down Expand Up @@ -15881,6 +15882,13 @@
"params": [],
"returnType": "Integer"
},
{
"description": "Returns the message port (if any) currently associated with the object",
"name": "GetMessagePort",
"params": [],
"returnDescription": "The message port.",
"returnType": "Object"
},
{
"description": "Checks whether underlying select determines non-blocking read of OOB data is possible.",
"name": "IsException",
Expand Down Expand Up @@ -15943,6 +15951,20 @@
}
],
"returnType": "Void"
},
{
"description": "Sets the roMessagePort to be used to receive events.",
"name": "SetMessagePort",
"params": [
{
"default": null,
"description": "The port to be used to receive events.",
"isRequired": true,
"name": "port",
"type": "Object"
}
],
"returnType": "Void"
}
],
"name": "ifSocketAsync",
Expand Down Expand Up @@ -19366,4 +19388,4 @@
"url": "https://developer.roku.com/docs/references/brightscript/events/rovideoplayerevent.md"
}
}
}
}
6 changes: 5 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,11 @@ export class Util {
} else if (typeDescriptorLower === 'assocarray' ||
typeDescriptorLower === 'associative array' ||
typeDescriptorLower === 'associativearray' ||
typeDescriptorLower === 'roassociativearray') {
typeDescriptorLower === 'roassociativearray' ||
typeDescriptorLower.startsWith('associative array of') ||
typeDescriptorLower.startsWith('associativearray of') ||
typeDescriptorLower.startsWith('roassociativearray of')
) {
return new AssociativeArrayType();
} else if (typeDescriptorLower === 'node') {
return ComponentType.instance;
Expand Down

0 comments on commit 7f82797

Please sign in to comment.