brighterscript-xml-plugin 0.3.0 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,19 +1,27 @@
1
1
  # brighterscript-xml-plugin
2
+
2
3
  ## BrighterScript plugin for SceneGraph XML completions
3
4
 
4
5
  ### It Does:
6
+
5
7
  - suggest components
6
8
  - suggest component fields
9
+ - validate field values
10
+ - validate field names
11
+ - validate child components
7
12
 
8
13
  ### It Does Not:
9
- - validate field values
14
+
10
15
  - suggest interface elements like `field` and `function`
11
16
 
12
17
  ### Installation
18
+
13
19
  ```
14
20
  npm i brighterscript-xml-plugin
15
21
  ```
22
+
16
23
  `bsconfig.json`
24
+
17
25
  ```
18
26
  {
19
27
  ...
@@ -24,12 +32,13 @@ npm i brighterscript-xml-plugin
24
32
  ```
25
33
 
26
34
  ### Usage
35
+
27
36
  SceneGraph Component completions
28
37
  ![usage gif](./bsc-xml.gif)
29
38
 
30
-
39
+ - validates children components
31
40
  - provides both built-in Roku SceneGraph components and custom project components
32
41
  - provides built-in fields and custom fields
33
42
  - auto suggestions for fields when typing inside an element tag
34
43
  - use completions shortcut to trigger manually
35
- - component completions on `<` do not fill automatically, pretty sure this is something that needs to be configured at the vscode extension level.
44
+ - component completions on `<` do not fill automatically, pretty sure this is something that needs to be configured at the vscode extension level.
@@ -31,7 +31,7 @@ class SGXmlCompletionProvider {
31
31
  let result = [];
32
32
  if (projectComponent) {
33
33
  result.push(...this.getCompletionsFromXmlFile(projectComponent.file));
34
- const extendsName = (_b = (_a = projectComponent.file.ast.component) === null || _a === void 0 ? void 0 : _a.extends) !== null && _b !== void 0 ? _b : 'Node';
34
+ const extendsName = (_b = (_a = projectComponent.file.ast.componentElement) === null || _a === void 0 ? void 0 : _a.extends) !== null && _b !== void 0 ? _b : 'Node';
35
35
  if (extendsName) {
36
36
  result.push(...this.getAllAvailableFields(extendsName));
37
37
  }
@@ -50,7 +50,7 @@ class SGXmlCompletionProvider {
50
50
  }
51
51
  getCompletionsFromXmlFile(xmlFile) {
52
52
  var _a, _b, _c;
53
- return ((_c = (_b = (_a = xmlFile.ast.component) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.fields.map((f) => {
53
+ return ((_c = (_b = (_a = xmlFile.ast.componentElement) === null || _a === void 0 ? void 0 : _a.interfaceElement) === null || _b === void 0 ? void 0 : _b.fields.map((f) => {
54
54
  return {
55
55
  label: f.id,
56
56
  detail: `${f.type}${f.value ? `: ${f.value}` : ''}`,
@@ -90,14 +90,14 @@ class SGXmlCompletionProvider {
90
90
  let result = [];
91
91
  if (component) {
92
92
  result = [
93
- ...((_c = (_b = (_a = component.file.ast.component) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.fields.map((f) => {
93
+ ...((_c = (_b = (_a = component.file.ast.componentElement) === null || _a === void 0 ? void 0 : _a.interfaceElement) === null || _b === void 0 ? void 0 : _b.fields.map((f) => {
94
94
  return {
95
95
  name: f.id,
96
96
  type: f.type,
97
97
  sortText: '0_' + f.id,
98
98
  };
99
99
  })) !== null && _c !== void 0 ? _c : []),
100
- ...this.getAllAvailableFields((_e = (_d = component.file.ast.component) === null || _d === void 0 ? void 0 : _d.extends) !== null && _e !== void 0 ? _e : '').map((f) => {
100
+ ...this.getAllAvailableFields((_e = (_d = component.file.ast.componentElement) === null || _d === void 0 ? void 0 : _d.extends) !== null && _e !== void 0 ? _e : '').map((f) => {
101
101
  return Object.assign(Object.assign({}, f), { sortText: '1_' + f.sortText });
102
102
  }),
103
103
  ];
@@ -7,24 +7,27 @@ exports.SGXmlDiagnostics = {
7
7
  message: `Unknown component: ${componentName}`,
8
8
  severity: brighterscript_1.DiagnosticSeverity.Error,
9
9
  code: 'SG1001',
10
- range: element.tag.range
10
+ location: element.tokens.startTagName.location
11
11
  }),
12
12
  InvalidSystemAttribute: (attributeName, component, attr) => ({
13
13
  message: `Field "${attributeName}" not found on component "${component}"`,
14
14
  severity: brighterscript_1.DiagnosticSeverity.Error,
15
15
  code: 'SG1002',
16
- range: attr.key.range
17
- }),
18
- InvalidAttributeValue: (attributeName, expectedType, attr) => ({
19
- message: `Field value "${attributeName}" does not match type ${expectedType}`,
20
- severity: brighterscript_1.DiagnosticSeverity.Error,
21
- code: 'SG1003',
22
- range: attr.value.range
16
+ location: attr.tokens.key.location
23
17
  }),
18
+ InvalidAttributeValue: (attributeName, expectedType, attr) => {
19
+ var _a;
20
+ return ({
21
+ message: `Field value "${attributeName}" does not match type ${expectedType}`,
22
+ severity: brighterscript_1.DiagnosticSeverity.Error,
23
+ code: 'SG1003',
24
+ location: (_a = attr.tokens.value) === null || _a === void 0 ? void 0 : _a.location
25
+ });
26
+ },
24
27
  AttributeNameCaseMismatch: (attributeName, expectedName, attr) => ({
25
28
  message: `Field "${attributeName}" should match case for "${expectedName}"`,
26
29
  severity: brighterscript_1.DiagnosticSeverity.Warning,
27
30
  code: 'SG2001',
28
- range: attr.key.range
31
+ location: attr.tokens.key.location
29
32
  })
30
33
  };
@@ -13,64 +13,65 @@ class SGXmlValidator {
13
13
  this.program = program;
14
14
  }
15
15
  validateXmlFile(event) {
16
- var _a, _b;
16
+ var _a, _b, _c, _d;
17
17
  const file = event.file;
18
- const diags = (_b = (_a = file === null || file === void 0 ? void 0 : file.ast) === null || _a === void 0 ? void 0 : _a.component) === null || _b === void 0 ? void 0 : _b.children.children.flatMap((child) => {
19
- return this.validateComponent(child).map(diag => {
20
- return Object.assign(Object.assign({}, diag), { file: file });
21
- });
22
- });
23
- event.program.addDiagnostics(diags || []);
18
+ const diags = (_d = (_c = (_b = (_a = file === null || file === void 0 ? void 0 : file.ast) === null || _a === void 0 ? void 0 : _a.componentElement) === null || _b === void 0 ? void 0 : _b.childrenElement) === null || _c === void 0 ? void 0 : _c.elements.flatMap((child) => {
19
+ return this.validateComponent(child);
20
+ })) !== null && _d !== void 0 ? _d : [];
21
+ event.program.diagnostics.register(diags);
24
22
  }
25
23
  validateComponent(element) {
26
24
  const diags = [];
25
+ if (!element.tagName) {
26
+ return diags;
27
+ }
27
28
  if (this.validateComponentExists(element)) {
28
29
  diags.push(...this.validateNodeElement(element));
29
- element.children.forEach((child) => {
30
+ element.elements.forEach((child) => {
30
31
  diags.push(...this.validateComponent(child));
31
32
  });
32
33
  }
33
34
  else {
34
- this.program.logger.error(`Unknown component: ${element.tag.text}`, element);
35
- const diag = SGXmlDiagnostics_1.SGXmlDiagnostics.UnknownComponent(element.tag.text, element);
35
+ this.program.logger.error(`Unknown component: ${element.tagName}`, element);
36
+ const diag = SGXmlDiagnostics_1.SGXmlDiagnostics.UnknownComponent(element.tagName, element);
36
37
  diags.push(diag);
37
38
  }
38
39
  return diags;
39
40
  }
40
41
  validateNodeElement(element) {
41
42
  const diags = [];
42
- const fields = this.findAllFields(element.tag.text);
43
+ const fields = this.findAllFields(element.tagName);
43
44
  element.attributes.forEach((attr) => {
44
45
  const field = fields.find(a => {
45
- return a.id.toLowerCase() === attr.key.text.toLowerCase();
46
+ return a.id.toLowerCase() === attr.key.toLowerCase();
46
47
  });
47
48
  if (!field) {
48
- this.program.logger.error(`Invalid system attribute: ${attr.key.text}`, attr);
49
- diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.InvalidSystemAttribute(attr.key.text, element.tag.text, attr));
49
+ this.program.logger.error(`Invalid system attribute: ${attr.key}`, attr);
50
+ diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.InvalidSystemAttribute(attr.key, element.tagName, attr));
50
51
  return;
51
52
  }
52
- if (field.type && !FieldTypeValidator_1.default.validateFieldType(attr.value.text, field.type)) {
53
- this.program.logger.error(`Invalid value for attribute: ${attr.key.text}`, attr);
54
- diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.InvalidAttributeValue(attr.key.text, field.type, attr));
53
+ if (field.type && !FieldTypeValidator_1.default.validateFieldType(attr.value, field.type)) {
54
+ this.program.logger.error(`Invalid value for attribute: ${attr.key}`, attr);
55
+ diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.InvalidAttributeValue(attr.key, field.type, attr));
55
56
  }
56
- if (field.id !== attr.key.text) {
57
- this.program.logger.warn(`Field "${attr.key.text}" should be "${field.id}"`, attr);
58
- diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.AttributeNameCaseMismatch(attr.key.text, field.id, attr));
57
+ if (field.id !== attr.key) {
58
+ this.program.logger.warn(`Field "${attr.key}" should be "${field.id}"`, attr);
59
+ diags.push(SGXmlDiagnostics_1.SGXmlDiagnostics.AttributeNameCaseMismatch(attr.key, field.id, attr));
59
60
  }
60
61
  });
61
62
  return diags;
62
63
  }
63
64
  validateComponentExists(element) {
64
- let component = this.program.getComponent(element.tag.text) || systemNodes[element.tag.text.toLocaleLowerCase()];
65
+ let component = this.program.getComponent(element.tagName) || systemNodes[element.tagName.toLocaleLowerCase()];
65
66
  return !!component;
66
67
  }
67
68
  findAllFields(name) {
68
- var _a, _b, _c, _d, _e, _f;
69
+ var _a, _b, _c, _d, _e;
69
70
  const fields = [];
70
71
  let component = (_a = this.program.getComponent(name)) === null || _a === void 0 ? void 0 : _a.file;
71
72
  if (component) {
72
- if ((_c = (_b = component.ast.component) === null || _b === void 0 ? void 0 : _b.api) === null || _c === void 0 ? void 0 : _c.fields) {
73
- fields.push(...component.ast.component.api.fields.map(f => {
73
+ if ((_c = (_b = component.ast.componentElement) === null || _b === void 0 ? void 0 : _b.interfaceElement) === null || _c === void 0 ? void 0 : _c.fields) {
74
+ fields.push(...component.ast.componentElement.interfaceElement.fields.map(f => {
74
75
  return {
75
76
  id: f.id,
76
77
  type: f.type,
@@ -78,13 +79,13 @@ class SGXmlValidator {
78
79
  };
79
80
  }) || []);
80
81
  }
81
- if ((_d = component.ast.component) === null || _d === void 0 ? void 0 : _d.extends) {
82
- fields.push(...this.findAllFields((_e = component.ast.component) === null || _e === void 0 ? void 0 : _e.extends));
82
+ if ((_d = component.ast.componentElement) === null || _d === void 0 ? void 0 : _d.extends) {
83
+ fields.push(...this.findAllFields(component.ast.componentElement.extends));
83
84
  }
84
85
  }
85
86
  component = systemNodes[name.toLocaleLowerCase()];
86
87
  if (component) {
87
- fields.push(...((_f = component.fields) === null || _f === void 0 ? void 0 : _f.map(f => {
88
+ fields.push(...((_e = component.fields) === null || _e === void 0 ? void 0 : _e.map(f => {
88
89
  return {
89
90
  id: f.name,
90
91
  type: f.type
package/dist/index.js CHANGED
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.BscXmlPlugin = void 0;
4
7
  const brighterscript_1 = require("brighterscript");
5
8
  const SGXmlCompletionProvider_1 = require("./SGXmlCompletionProvider");
6
9
  const SGXmlValidator_1 = require("./SGXmlValidator");
10
+ const SGParser_1 = __importDefault(require("brighterscript/dist/parser/SGParser"));
11
+ //@ts-ignore
12
+ SGParser_1.default.prototype._mapNode = SGParser_1.default.prototype.mapNode;
13
+ //@ts-ignore
14
+ SGParser_1.default.prototype.mapNode = function (node) {
15
+ if (!node.children.Name) {
16
+ node.children.Name = [];
17
+ }
18
+ //@ts-ignore
19
+ return this._mapNode(node);
20
+ };
7
21
  class BscXmlPlugin {
8
22
  constructor() {
9
23
  this.name = 'bsc-xml-plugin';
@@ -20,13 +34,13 @@ class BscXmlPlugin {
20
34
  }
21
35
  return this.provider;
22
36
  }
23
- beforeProvideCompletions(event) {
37
+ provideCompletions(event) {
38
+ console.log('provideCompletions', event.file.constructor.name);
24
39
  if ((0, brighterscript_1.isXmlFile)(event.file)) {
25
- console.log(event.completions);
26
40
  this.getProvider(event.program).process(event);
27
41
  }
28
42
  }
29
- onFileValidate(event) {
43
+ validateFile(event) {
30
44
  if ((0, brighterscript_1.isXmlFile)(event.file)) {
31
45
  this.getValidator(event).validateXmlFile(event);
32
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brighterscript-xml-plugin",
3
- "version": "0.3.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "BrighterScript plugin for SceneGraph XML completions",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -37,7 +37,7 @@
37
37
  "@types/chai": "^4.3.4",
38
38
  "@types/mocha": "^10.0.1",
39
39
  "@types/node": "^18.15.3",
40
- "brighterscript": "0.65.x",
40
+ "brighterscript": "^1.0.0-alpha.50",
41
41
  "chai": "^4.3.7",
42
42
  "mocha": "^10.2.0",
43
43
  "rimraf": "^5.0.5",
@@ -47,7 +47,7 @@
47
47
  "vscode-languageserver-types": "^3.17.3"
48
48
  },
49
49
  "peerDependencies": {
50
- "brighterscript": ">= 0.65.0 < 1"
50
+ "brighterscript": ">= 1 < 2"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "brighterscript": {
@@ -58,4 +58,4 @@
58
58
  "dist/*.js",
59
59
  "!dist/*.spec.js"
60
60
  ]
61
- }
61
+ }