@oicl-lit/analyzer 0.14.1

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.
Files changed (115) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +76 -0
  3. package/index.d.ts +10 -0
  4. package/index.d.ts.map +1 -0
  5. package/index.js +10 -0
  6. package/index.js.map +1 -0
  7. package/lib/analyzer.d.ts +47 -0
  8. package/lib/analyzer.d.ts.map +1 -0
  9. package/lib/analyzer.js +90 -0
  10. package/lib/analyzer.js.map +1 -0
  11. package/lib/custom-elements/custom-elements.d.ts +33 -0
  12. package/lib/custom-elements/custom-elements.d.ts.map +1 -0
  13. package/lib/custom-elements/custom-elements.js +124 -0
  14. package/lib/custom-elements/custom-elements.js.map +1 -0
  15. package/lib/custom-elements/events.d.ts +19 -0
  16. package/lib/custom-elements/events.d.ts.map +1 -0
  17. package/lib/custom-elements/events.js +25 -0
  18. package/lib/custom-elements/events.js.map +1 -0
  19. package/lib/diagnostic-code.d.ts +21 -0
  20. package/lib/diagnostic-code.d.ts.map +1 -0
  21. package/lib/diagnostic-code.js +20 -0
  22. package/lib/diagnostic-code.js.map +1 -0
  23. package/lib/errors.d.ts +24 -0
  24. package/lib/errors.d.ts.map +1 -0
  25. package/lib/errors.js +17 -0
  26. package/lib/errors.js.map +1 -0
  27. package/lib/javascript/classes.d.ts +50 -0
  28. package/lib/javascript/classes.d.ts.map +1 -0
  29. package/lib/javascript/classes.js +307 -0
  30. package/lib/javascript/classes.js.map +1 -0
  31. package/lib/javascript/functions.d.ts +31 -0
  32. package/lib/javascript/functions.d.ts.map +1 -0
  33. package/lib/javascript/functions.js +144 -0
  34. package/lib/javascript/functions.js.map +1 -0
  35. package/lib/javascript/jsdoc.d.ts +67 -0
  36. package/lib/javascript/jsdoc.d.ts.map +1 -0
  37. package/lib/javascript/jsdoc.js +244 -0
  38. package/lib/javascript/jsdoc.js.map +1 -0
  39. package/lib/javascript/mixins.d.ts +45 -0
  40. package/lib/javascript/mixins.d.ts.map +1 -0
  41. package/lib/javascript/mixins.js +147 -0
  42. package/lib/javascript/mixins.js.map +1 -0
  43. package/lib/javascript/modules.d.ts +42 -0
  44. package/lib/javascript/modules.d.ts.map +1 -0
  45. package/lib/javascript/modules.js +277 -0
  46. package/lib/javascript/modules.js.map +1 -0
  47. package/lib/javascript/packages.d.ts +18 -0
  48. package/lib/javascript/packages.d.ts.map +1 -0
  49. package/lib/javascript/packages.js +53 -0
  50. package/lib/javascript/packages.js.map +1 -0
  51. package/lib/javascript/variables.d.ts +29 -0
  52. package/lib/javascript/variables.d.ts.map +1 -0
  53. package/lib/javascript/variables.js +143 -0
  54. package/lib/javascript/variables.js.map +1 -0
  55. package/lib/lit/decorators.d.ts +36 -0
  56. package/lib/lit/decorators.d.ts.map +1 -0
  57. package/lib/lit/decorators.js +32 -0
  58. package/lib/lit/decorators.js.map +1 -0
  59. package/lib/lit/lit-element.d.ts +39 -0
  60. package/lib/lit/lit-element.d.ts.map +1 -0
  61. package/lib/lit/lit-element.js +96 -0
  62. package/lib/lit/lit-element.js.map +1 -0
  63. package/lib/lit/modules.d.ts +28 -0
  64. package/lib/lit/modules.d.ts.map +1 -0
  65. package/lib/lit/modules.js +62 -0
  66. package/lib/lit/modules.js.map +1 -0
  67. package/lib/lit/properties.d.ts +43 -0
  68. package/lib/lit/properties.d.ts.map +1 -0
  69. package/lib/lit/properties.js +268 -0
  70. package/lib/lit/properties.js.map +1 -0
  71. package/lib/lit/template.d.ts +110 -0
  72. package/lib/lit/template.d.ts.map +1 -0
  73. package/lib/lit/template.js +412 -0
  74. package/lib/lit/template.js.map +1 -0
  75. package/lib/lit-element/decorators.d.ts +11 -0
  76. package/lib/lit-element/decorators.d.ts.map +1 -0
  77. package/lib/lit-element/decorators.js +11 -0
  78. package/lib/lit-element/decorators.js.map +1 -0
  79. package/lib/lit-element/lit-element.d.ts +11 -0
  80. package/lib/lit-element/lit-element.d.ts.map +1 -0
  81. package/lib/lit-element/lit-element.js +11 -0
  82. package/lib/lit-element/lit-element.js.map +1 -0
  83. package/lib/lit-element/properties.d.ts +11 -0
  84. package/lib/lit-element/properties.d.ts.map +1 -0
  85. package/lib/lit-element/properties.js +11 -0
  86. package/lib/lit-element/properties.js.map +1 -0
  87. package/lib/model.d.ts +506 -0
  88. package/lib/model.d.ts.map +1 -0
  89. package/lib/model.js +392 -0
  90. package/lib/model.js.map +1 -0
  91. package/lib/package-analyzer.d.ts +25 -0
  92. package/lib/package-analyzer.d.ts.map +1 -0
  93. package/lib/package-analyzer.js +81 -0
  94. package/lib/package-analyzer.js.map +1 -0
  95. package/lib/paths.d.ts +24 -0
  96. package/lib/paths.d.ts.map +1 -0
  97. package/lib/paths.js +35 -0
  98. package/lib/paths.js.map +1 -0
  99. package/lib/references.d.ts +107 -0
  100. package/lib/references.d.ts.map +1 -0
  101. package/lib/references.js +345 -0
  102. package/lib/references.js.map +1 -0
  103. package/lib/types.d.ts +25 -0
  104. package/lib/types.d.ts.map +1 -0
  105. package/lib/types.js +257 -0
  106. package/lib/types.js.map +1 -0
  107. package/lib/utils.d.ts +22 -0
  108. package/lib/utils.d.ts.map +1 -0
  109. package/lib/utils.js +51 -0
  110. package/lib/utils.js.map +1 -0
  111. package/package-analyzer.d.ts +8 -0
  112. package/package-analyzer.d.ts.map +1 -0
  113. package/package-analyzer.js +8 -0
  114. package/package-analyzer.js.map +1 -0
  115. package/package.json +109 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/lib/lit/decorators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC;AAiBnC,eAAO,MAAM,wBAAwB,GACnC,IAAI,UAAU,EACd,WAAW,EAAE,CAAC,SAAS,KACtB,SAAS,IAAI,sBACyC,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,EAAE,CAAC,SAAS;IAC1D,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,cAAc,CAAC;CACxC;AAED,eAAO,MAAM,oBAAoB,GAC/B,IAAI,UAAU,EACd,aAAa,EAAE,CAAC,mBAAmB,kCAIgC,CAAC;AAQtE;;;GAGG;AACH,UAAU,iBAAkB,SAAQ,EAAE,CAAC,SAAS;IAC9C,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,cAAc,CAAC;CACxC;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,UAAU,EACd,WAAW,iBAAiB,2CAO7B,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Returns true if the decorator site is a simple called decorator factory of
8
+ * the form `@decoratorName()`.
9
+ *
10
+ * TODO (justinfagnani): change to looking up decorators by known declarations.
11
+ */
12
+ const isNamedDecoratorFactory = (ts, decorator, name) => ts.isCallExpression(decorator.expression) &&
13
+ ts.isIdentifier(decorator.expression.expression) &&
14
+ decorator.expression.expression.text === name;
15
+ export const isCustomElementDecorator = (ts, decorator) => isNamedDecoratorFactory(ts, decorator, 'customElement');
16
+ export const getPropertyDecorator = (ts, declaration) => ts
17
+ .getDecorators(declaration)
18
+ ?.find((d) => isPropertyDecorator(ts, d));
19
+ const isPropertyDecorator = (ts, decorator) => isNamedDecoratorFactory(ts, decorator, 'property');
20
+ /**
21
+ * Gets the property options object from a `@property()` decorator callsite.
22
+ *
23
+ * Only works with an object literal passed as the first argument.
24
+ */
25
+ export const getPropertyOptions = (ts, decorator) => {
26
+ const options = decorator.expression.arguments[0];
27
+ if (options !== undefined && ts.isObjectLiteralExpression(options)) {
28
+ return options;
29
+ }
30
+ return undefined;
31
+ };
32
+ //# sourceMappingURL=decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/lib/lit/decorators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;;GAKG;AACH,MAAM,uBAAuB,GAAG,CAC9B,EAAc,EACd,SAAuB,EACvB,IAAY,EACyB,EAAE,CACvC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,UAAU,CAAC;IACzC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC;IAChD,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,KAAK,IAAI,CAAC;AAEhD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,EAAc,EACd,SAAuB,EACc,EAAE,CACvC,uBAAuB,CAAC,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;AAU1D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,EAAc,EACd,WAAmC,EACnC,EAAE,CACF,EAAE;KACC,aAAa,CAAC,WAAW,CAAC;IAC3B,EAAE,IAAI,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AAEtE,MAAM,mBAAmB,GAAG,CAC1B,EAAc,EACd,SAAuB,EACS,EAAE,CAClC,uBAAuB,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AAUrD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,EAAc,EACd,SAA4B,EAC5B,EAAE;IACF,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,SAAS,IAAI,EAAE,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE,CAAC;QACnE,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * @fileoverview\n *\n * Utilities for analyzing ReactiveElement decorators.\n */\n\nimport type ts from 'typescript';\n\nexport type TypeScript = typeof ts;\n\n/**\n * Returns true if the decorator site is a simple called decorator factory of\n * the form `@decoratorName()`.\n *\n * TODO (justinfagnani): change to looking up decorators by known declarations.\n */\nconst isNamedDecoratorFactory = (\n ts: TypeScript,\n decorator: ts.Decorator,\n name: string\n): decorator is CustomElementDecorator =>\n ts.isCallExpression(decorator.expression) &&\n ts.isIdentifier(decorator.expression.expression) &&\n decorator.expression.expression.text === name;\n\nexport const isCustomElementDecorator = (\n ts: TypeScript,\n decorator: ts.Decorator\n): decorator is CustomElementDecorator =>\n isNamedDecoratorFactory(ts, decorator, 'customElement');\n\n/**\n * A narrower type for ts.Decorator that represents the shape of an analyzable\n * `@customElement('x')` callsite.\n */\nexport interface CustomElementDecorator extends ts.Decorator {\n readonly expression: ts.CallExpression;\n}\n\nexport const getPropertyDecorator = (\n ts: TypeScript,\n declaration: ts.PropertyDeclaration\n) =>\n ts\n .getDecorators(declaration)\n ?.find((d): d is PropertyDecorator => isPropertyDecorator(ts, d));\n\nconst isPropertyDecorator = (\n ts: TypeScript,\n decorator: ts.Decorator\n): decorator is PropertyDecorator =>\n isNamedDecoratorFactory(ts, decorator, 'property');\n\n/**\n * A narrower type for ts.Decorator that represents the shape of an analyzable\n * `@customElement('x')` callsite.\n */\ninterface PropertyDecorator extends ts.Decorator {\n readonly expression: ts.CallExpression;\n}\n\n/**\n * Gets the property options object from a `@property()` decorator callsite.\n *\n * Only works with an object literal passed as the first argument.\n */\nexport const getPropertyOptions = (\n ts: TypeScript,\n decorator: PropertyDecorator\n) => {\n const options = decorator.expression.arguments[0];\n if (options !== undefined && ts.isObjectLiteralExpression(options)) {\n return options;\n }\n return undefined;\n};\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * @fileoverview
8
+ *
9
+ * Utilities for analyzing LitElement (and ReactiveElement) declarations.
10
+ */
11
+ import type ts from 'typescript';
12
+ import { LitElementDeclaration, AnalyzerInterface } from '../model.js';
13
+ export type TypeScript = typeof ts;
14
+ /**
15
+ * Gets an analyzer LitElementDeclaration object from a ts.ClassDeclaration
16
+ * (branded as LitClassDeclaration).
17
+ */
18
+ export declare const getLitElementDeclaration: (declaration: LitClassDeclaration, analyzer: AnalyzerInterface, isMixinClass?: boolean) => LitElementDeclaration;
19
+ /**
20
+ * This type identifies a ClassDeclaration as one that inherits from LitElement.
21
+ *
22
+ * It lets isLitElement function as a type predicate that returns whether or
23
+ * not its argument is a LitElement such that when it returns false TypeScript
24
+ * doesn't infer that the argument is not a ClassDeclaration.
25
+ */
26
+ export type LitClassDeclaration = ts.ClassDeclaration & {
27
+ __litBrand: never;
28
+ };
29
+ /**
30
+ * Returns true if `node` is a ClassLikeDeclaration that extends LitElement.
31
+ */
32
+ export declare const isLitElementSubclass: (node: ts.Node, analyzer: AnalyzerInterface) => node is LitClassDeclaration;
33
+ /**
34
+ * Returns the tagname associated with a LitClassDeclaration
35
+ * @param declaration
36
+ * @returns
37
+ */
38
+ export declare const getTagName: (declaration: LitClassDeclaration, analyzer: AnalyzerInterface) => string | undefined;
39
+ //# sourceMappingURL=lit-element.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lit-element.d.ts","sourceRoot":"","sources":["../../src/lib/lit/lit-element.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,EAAC,qBAAqB,EAAE,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAYrE,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,aAAa,mBAAmB,EAChC,UAAU,iBAAiB,EAC3B,eAAe,OAAO,KACrB,qBAWF,CAAC;AAkDF;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,EAAE,CAAC,gBAAgB,GAAG;IACtD,UAAU,EAAE,KAAK,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,MAAM,EAAE,CAAC,IAAI,EACb,UAAU,iBAAiB,KAC1B,IAAI,IAAI,mBAeV,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,aAAa,mBAAmB,EAChC,UAAU,iBAAiB,uBAkB5B,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ import { getClassMembers, getHeritage } from '../javascript/classes.js';
7
+ import { LitElementDeclaration } from '../model.js';
8
+ import { isCustomElementDecorator, } from './decorators.js';
9
+ import { getProperties } from './properties.js';
10
+ import { getJSDocData, getTagName as getCustomElementTagName, } from '../custom-elements/custom-elements.js';
11
+ import { getBaseTypes } from '../utils.js';
12
+ /**
13
+ * Gets an analyzer LitElementDeclaration object from a ts.ClassDeclaration
14
+ * (branded as LitClassDeclaration).
15
+ */
16
+ export const getLitElementDeclaration = (declaration, analyzer, isMixinClass) => {
17
+ return new LitElementDeclaration({
18
+ tagname: getTagName(declaration, analyzer),
19
+ // TODO(kschaaf): support anonymous class expressions when assigned to a const
20
+ name: declaration.name?.text ?? '',
21
+ node: declaration,
22
+ reactiveProperties: getProperties(declaration, analyzer),
23
+ ...getJSDocData(declaration, analyzer),
24
+ getHeritage: () => getHeritage(declaration, analyzer, isMixinClass),
25
+ ...getClassMembers(declaration, analyzer),
26
+ });
27
+ };
28
+ /**
29
+ * Returns true if this type represents the actual LitElement class.
30
+ */
31
+ const _isLitElementClassDeclaration = (t, analyzer) => {
32
+ // TODO: should we memoize this for performance?
33
+ const declarations = t.getSymbol()?.getDeclarations();
34
+ if (declarations?.length !== 1) {
35
+ return false;
36
+ }
37
+ const node = declarations[0];
38
+ return (_isLitElement(analyzer.typescript, node) ||
39
+ isLitElementSubclass(node, analyzer));
40
+ };
41
+ /**
42
+ * Returns true if the given declaration is THE LitElement declaration.
43
+ *
44
+ * TODO(kschaaf): consider a less brittle method of detecting canonical
45
+ * LitElement
46
+ */
47
+ const _isLitElement = (ts, node) => {
48
+ return (_isLitElementModule(node.getSourceFile()) &&
49
+ ts.isClassDeclaration(node) &&
50
+ node.name?.text === 'LitElement');
51
+ };
52
+ /**
53
+ * Returns true if the given source file is THE lit-element source file.
54
+ */
55
+ const _isLitElementModule = (file) => {
56
+ return (file.fileName.endsWith('/node_modules/lit-element/lit-element.d.ts') ||
57
+ file.fileName.endsWith('/node_modules/lit-element/development/lit-element.d.ts') ||
58
+ // Handle case of running analyzer in symlinked monorepo
59
+ file.fileName.endsWith('/packages/lit-element/lit-element.d.ts') ||
60
+ file.fileName.endsWith('/packages/lit-element/development/lit-element.d.ts'));
61
+ };
62
+ /**
63
+ * Returns true if `node` is a ClassLikeDeclaration that extends LitElement.
64
+ */
65
+ export const isLitElementSubclass = (node, analyzer) => {
66
+ if (!analyzer.typescript.isClassLike(node)) {
67
+ return false;
68
+ }
69
+ const checker = analyzer.program.getTypeChecker();
70
+ const type = checker.getTypeAtLocation(node);
71
+ const baseTypes = getBaseTypes(type);
72
+ return baseTypes.some((t) =>
73
+ // Mixins will cause the base types to be an intersection that
74
+ // includes `LitElement`
75
+ t.isIntersection()
76
+ ? t.types.some((t) => _isLitElementClassDeclaration(t, analyzer))
77
+ : _isLitElementClassDeclaration(t, analyzer));
78
+ };
79
+ /**
80
+ * Returns the tagname associated with a LitClassDeclaration
81
+ * @param declaration
82
+ * @returns
83
+ */
84
+ export const getTagName = (declaration, analyzer) => {
85
+ const customElementDecorator = analyzer.typescript
86
+ .getDecorators(declaration)
87
+ ?.find((d) => isCustomElementDecorator(analyzer.typescript, d));
88
+ if (customElementDecorator !== undefined &&
89
+ customElementDecorator.expression.arguments.length === 1 &&
90
+ analyzer.typescript.isStringLiteral(customElementDecorator.expression.arguments[0])) {
91
+ // Get tag from decorator: `@customElement('x-foo')`
92
+ return customElementDecorator.expression.arguments[0].text;
93
+ }
94
+ return getCustomElementTagName(declaration, analyzer);
95
+ };
96
+ //# sourceMappingURL=lit-element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lit-element.js","sourceRoot":"","sources":["../../src/lib/lit/lit-element.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EAAC,eAAe,EAAE,WAAW,EAAC,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAC,qBAAqB,EAAoB,MAAM,aAAa,CAAC;AACrE,OAAO,EAEL,wBAAwB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,UAAU,IAAI,uBAAuB,GACtC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAIzC;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,WAAgC,EAChC,QAA2B,EAC3B,YAAsB,EACC,EAAE;IACzB,OAAO,IAAI,qBAAqB,CAAC;QAC/B,OAAO,EAAE,UAAU,CAAC,WAAW,EAAE,QAAQ,CAAC;QAC1C,8EAA8E;QAC9E,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE;QAClC,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC;QACxD,GAAG,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC;QACtC,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC;QACnE,GAAG,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC;KAC1C,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,6BAA6B,GAAG,CACpC,CAAc,EACd,QAA2B,EAC3B,EAAE;IACF,gDAAgD;IAChD,MAAM,YAAY,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,eAAe,EAAE,CAAC;IACtD,IAAI,YAAY,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC7B,OAAO,CACL,aAAa,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;QACxC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,CACrC,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,aAAa,GAAG,CAAC,EAAc,EAAE,IAAoB,EAAE,EAAE;IAC7D,OAAO,CACL,mBAAmB,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACzC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,YAAY,CACjC,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG,CAAC,IAAmB,EAAE,EAAE;IAClD,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CACpB,wDAAwD,CACzD;QACD,wDAAwD;QACxD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QAChE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,oDAAoD,CAAC,CAC7E,CAAC;AACJ,CAAC,CAAC;AAaF;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAAa,EACb,QAA2B,EACE,EAAE;IAC/B,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAErC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;IAC1B,8DAA8D;IAC9D,wBAAwB;IACxB,CAAC,CAAC,cAAc,EAAE;QAChB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACjE,CAAC,CAAC,6BAA6B,CAAC,CAAC,EAAE,QAAQ,CAAC,CAC/C,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,WAAgC,EAChC,QAA2B,EAC3B,EAAE;IACF,MAAM,sBAAsB,GAAG,QAAQ,CAAC,UAAU;SAC/C,aAAa,CAAC,WAAW,CAAC;QAC3B,EAAE,IAAI,CAAC,CAAC,CAAC,EAA+B,EAAE,CACxC,wBAAwB,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CACjD,CAAC;IACJ,IACE,sBAAsB,KAAK,SAAS;QACpC,sBAAsB,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QACxD,QAAQ,CAAC,UAAU,CAAC,eAAe,CACjC,sBAAsB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAC/C,EACD,CAAC;QACD,oDAAoD;QACpD,OAAO,sBAAsB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IACD,OAAO,uBAAuB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2022 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * @fileoverview\n *\n * Utilities for analyzing LitElement (and ReactiveElement) declarations.\n */\n\nimport type ts from 'typescript';\nimport {getClassMembers, getHeritage} from '../javascript/classes.js';\nimport {LitElementDeclaration, AnalyzerInterface} from '../model.js';\nimport {\n CustomElementDecorator,\n isCustomElementDecorator,\n} from './decorators.js';\nimport {getProperties} from './properties.js';\nimport {\n getJSDocData,\n getTagName as getCustomElementTagName,\n} from '../custom-elements/custom-elements.js';\nimport {getBaseTypes} from '../utils.js';\n\nexport type TypeScript = typeof ts;\n\n/**\n * Gets an analyzer LitElementDeclaration object from a ts.ClassDeclaration\n * (branded as LitClassDeclaration).\n */\nexport const getLitElementDeclaration = (\n declaration: LitClassDeclaration,\n analyzer: AnalyzerInterface,\n isMixinClass?: boolean\n): LitElementDeclaration => {\n return new LitElementDeclaration({\n tagname: getTagName(declaration, analyzer),\n // TODO(kschaaf): support anonymous class expressions when assigned to a const\n name: declaration.name?.text ?? '',\n node: declaration,\n reactiveProperties: getProperties(declaration, analyzer),\n ...getJSDocData(declaration, analyzer),\n getHeritage: () => getHeritage(declaration, analyzer, isMixinClass),\n ...getClassMembers(declaration, analyzer),\n });\n};\n\n/**\n * Returns true if this type represents the actual LitElement class.\n */\nconst _isLitElementClassDeclaration = (\n t: ts.BaseType,\n analyzer: AnalyzerInterface\n) => {\n // TODO: should we memoize this for performance?\n const declarations = t.getSymbol()?.getDeclarations();\n if (declarations?.length !== 1) {\n return false;\n }\n const node = declarations[0];\n return (\n _isLitElement(analyzer.typescript, node) ||\n isLitElementSubclass(node, analyzer)\n );\n};\n\n/**\n * Returns true if the given declaration is THE LitElement declaration.\n *\n * TODO(kschaaf): consider a less brittle method of detecting canonical\n * LitElement\n */\nconst _isLitElement = (ts: TypeScript, node: ts.Declaration) => {\n return (\n _isLitElementModule(node.getSourceFile()) &&\n ts.isClassDeclaration(node) &&\n node.name?.text === 'LitElement'\n );\n};\n\n/**\n * Returns true if the given source file is THE lit-element source file.\n */\nconst _isLitElementModule = (file: ts.SourceFile) => {\n return (\n file.fileName.endsWith('/node_modules/lit-element/lit-element.d.ts') ||\n file.fileName.endsWith(\n '/node_modules/lit-element/development/lit-element.d.ts'\n ) ||\n // Handle case of running analyzer in symlinked monorepo\n file.fileName.endsWith('/packages/lit-element/lit-element.d.ts') ||\n file.fileName.endsWith('/packages/lit-element/development/lit-element.d.ts')\n );\n};\n\n/**\n * This type identifies a ClassDeclaration as one that inherits from LitElement.\n *\n * It lets isLitElement function as a type predicate that returns whether or\n * not its argument is a LitElement such that when it returns false TypeScript\n * doesn't infer that the argument is not a ClassDeclaration.\n */\nexport type LitClassDeclaration = ts.ClassDeclaration & {\n __litBrand: never;\n};\n\n/**\n * Returns true if `node` is a ClassLikeDeclaration that extends LitElement.\n */\nexport const isLitElementSubclass = (\n node: ts.Node,\n analyzer: AnalyzerInterface\n): node is LitClassDeclaration => {\n if (!analyzer.typescript.isClassLike(node)) {\n return false;\n }\n const checker = analyzer.program.getTypeChecker();\n const type = checker.getTypeAtLocation(node);\n const baseTypes = getBaseTypes(type);\n\n return baseTypes.some((t) =>\n // Mixins will cause the base types to be an intersection that\n // includes `LitElement`\n t.isIntersection()\n ? t.types.some((t) => _isLitElementClassDeclaration(t, analyzer))\n : _isLitElementClassDeclaration(t, analyzer)\n );\n};\n\n/**\n * Returns the tagname associated with a LitClassDeclaration\n * @param declaration\n * @returns\n */\nexport const getTagName = (\n declaration: LitClassDeclaration,\n analyzer: AnalyzerInterface\n) => {\n const customElementDecorator = analyzer.typescript\n .getDecorators(declaration)\n ?.find((d): d is CustomElementDecorator =>\n isCustomElementDecorator(analyzer.typescript, d)\n );\n if (\n customElementDecorator !== undefined &&\n customElementDecorator.expression.arguments.length === 1 &&\n analyzer.typescript.isStringLiteral(\n customElementDecorator.expression.arguments[0]\n )\n ) {\n // Get tag from decorator: `@customElement('x-foo')`\n return customElementDecorator.expression.arguments[0].text;\n }\n return getCustomElementTagName(declaration, analyzer);\n};\n"]}
@@ -0,0 +1,28 @@
1
+ import type ts from 'typescript';
2
+ type TypeScript = typeof ts;
3
+ /**
4
+ * Returns true if this node is an import declaration for a module known to
5
+ * export the Lit html template tag.
6
+ */
7
+ export declare const isLitHtmlImportDeclaration: (node: ts.Node, ts: TypeScript) => node is ts.ImportDeclaration;
8
+ /**
9
+ * Returns true if the specifier is known to export the Lit html template tag.
10
+ *
11
+ * This can be used in a heuristic to determine if a template is a lit-html
12
+ * template.
13
+ */
14
+ export declare const isKnownLitHtmlModuleSpecifier: (specifier: string) => boolean;
15
+ /**
16
+ * Resolve a common pattern of using the `html` identifier of a lit namespace
17
+ * import.
18
+ *
19
+ * E.g.:
20
+ *
21
+ * ```ts
22
+ * import * as identifier from 'lit';
23
+ * identifier.html`<p>I am compiled!</p>`;
24
+ * ```
25
+ */
26
+ export declare const isResolvedPropertyAccessExpressionLitHtmlNamespace: (node: ts.PropertyAccessExpression, ts: TypeScript, checker: ts.TypeChecker) => boolean;
27
+ export {};
28
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/lib/lit/modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,KAAK,UAAU,GAAG,OAAO,EAAE,CAAC;AAE5B;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,MAAM,EAAE,CAAC,IAAI,EACb,IAAI,UAAU,KACb,IAAI,IAAI,EAAE,CAAC,iBASb,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GAAI,WAAW,MAAM,KAAG,OAMjE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kDAAkD,GAC7D,MAAM,EAAE,CAAC,wBAAwB,EACjC,IAAI,UAAU,EACd,SAAS,EAAE,CAAC,WAAW,KACtB,OAyBF,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Returns true if this node is an import declaration for a module known to
3
+ * export the Lit html template tag.
4
+ */
5
+ export const isLitHtmlImportDeclaration = (node, ts) => {
6
+ if (!ts.isImportDeclaration(node)) {
7
+ return false;
8
+ }
9
+ const specifier = node.moduleSpecifier;
10
+ if (!ts.isStringLiteral(specifier)) {
11
+ return false;
12
+ }
13
+ return isKnownLitHtmlModuleSpecifier(specifier.text);
14
+ };
15
+ /**
16
+ * Returns true if the specifier is known to export the Lit html template tag.
17
+ *
18
+ * This can be used in a heuristic to determine if a template is a lit-html
19
+ * template.
20
+ */
21
+ export const isKnownLitHtmlModuleSpecifier = (specifier) => {
22
+ return (specifier === 'lit' ||
23
+ specifier === 'lit-html' ||
24
+ specifier === 'lit-element');
25
+ };
26
+ /**
27
+ * Resolve a common pattern of using the `html` identifier of a lit namespace
28
+ * import.
29
+ *
30
+ * E.g.:
31
+ *
32
+ * ```ts
33
+ * import * as identifier from 'lit';
34
+ * identifier.html`<p>I am compiled!</p>`;
35
+ * ```
36
+ */
37
+ export const isResolvedPropertyAccessExpressionLitHtmlNamespace = (node, ts, checker) => {
38
+ // Ensure propertyAccessExpression ends with `.html`.
39
+ if (ts.isIdentifier(node.name) && node.name.text !== 'html') {
40
+ return false;
41
+ }
42
+ // Expect a namespace preceding `html`, `<namespace>.html`.
43
+ if (!ts.isIdentifier(node.expression)) {
44
+ return false;
45
+ }
46
+ // Resolve the namespace if it has been aliased.
47
+ const symbol = checker.getSymbolAtLocation(node.expression);
48
+ if (!symbol) {
49
+ return false;
50
+ }
51
+ const namespaceImport = symbol.declarations?.[0];
52
+ if (!namespaceImport || !ts.isNamespaceImport(namespaceImport)) {
53
+ return false;
54
+ }
55
+ const importDeclaration = namespaceImport.parent.parent;
56
+ const specifier = importDeclaration.moduleSpecifier;
57
+ if (!ts.isStringLiteral(specifier)) {
58
+ return false;
59
+ }
60
+ return isKnownLitHtmlModuleSpecifier(specifier.text);
61
+ };
62
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.js","sourceRoot":"","sources":["../../src/lib/lit/modules.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,IAAa,EACb,EAAc,EACgB,EAAE;IAChC,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,6BAA6B,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAAW,EAAE;IAC1E,OAAO,CACL,SAAS,KAAK,KAAK;QACnB,SAAS,KAAK,UAAU;QACxB,SAAS,KAAK,aAAa,CAC5B,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kDAAkD,GAAG,CAChE,IAAiC,EACjC,EAAc,EACd,OAAuB,EACd,EAAE;IACX,qDAAqD;IACrD,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,2DAA2D;IAC3D,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gDAAgD;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,eAAe,IAAI,CAAC,EAAE,CAAC,iBAAiB,CAAC,eAAe,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,iBAAiB,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC;IACxD,MAAM,SAAS,GAAG,iBAAiB,CAAC,eAAe,CAAC;IACpD,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,6BAA6B,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC","sourcesContent":["import type ts from 'typescript';\n\ntype TypeScript = typeof ts;\n\n/**\n * Returns true if this node is an import declaration for a module known to\n * export the Lit html template tag.\n */\nexport const isLitHtmlImportDeclaration = (\n node: ts.Node,\n ts: TypeScript\n): node is ts.ImportDeclaration => {\n if (!ts.isImportDeclaration(node)) {\n return false;\n }\n const specifier = node.moduleSpecifier;\n if (!ts.isStringLiteral(specifier)) {\n return false;\n }\n return isKnownLitHtmlModuleSpecifier(specifier.text);\n};\n\n/**\n * Returns true if the specifier is known to export the Lit html template tag.\n *\n * This can be used in a heuristic to determine if a template is a lit-html\n * template.\n */\nexport const isKnownLitHtmlModuleSpecifier = (specifier: string): boolean => {\n return (\n specifier === 'lit' ||\n specifier === 'lit-html' ||\n specifier === 'lit-element'\n );\n};\n\n/**\n * Resolve a common pattern of using the `html` identifier of a lit namespace\n * import.\n *\n * E.g.:\n *\n * ```ts\n * import * as identifier from 'lit';\n * identifier.html`<p>I am compiled!</p>`;\n * ```\n */\nexport const isResolvedPropertyAccessExpressionLitHtmlNamespace = (\n node: ts.PropertyAccessExpression,\n ts: TypeScript,\n checker: ts.TypeChecker\n): boolean => {\n // Ensure propertyAccessExpression ends with `.html`.\n if (ts.isIdentifier(node.name) && node.name.text !== 'html') {\n return false;\n }\n // Expect a namespace preceding `html`, `<namespace>.html`.\n if (!ts.isIdentifier(node.expression)) {\n return false;\n }\n\n // Resolve the namespace if it has been aliased.\n const symbol = checker.getSymbolAtLocation(node.expression);\n if (!symbol) {\n return false;\n }\n const namespaceImport = symbol.declarations?.[0];\n if (!namespaceImport || !ts.isNamespaceImport(namespaceImport)) {\n return false;\n }\n const importDeclaration = namespaceImport.parent.parent;\n const specifier = importDeclaration.moduleSpecifier;\n if (!ts.isStringLiteral(specifier)) {\n return false;\n }\n return isKnownLitHtmlModuleSpecifier(specifier.text);\n};\n"]}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * @fileoverview
8
+ *
9
+ * Utilities for analyzing reactive property declarations
10
+ */
11
+ import type ts from 'typescript';
12
+ import { LitClassDeclaration } from './lit-element.js';
13
+ import { ReactiveProperty, AnalyzerInterface } from '../model.js';
14
+ export type TypeScript = typeof ts;
15
+ export declare const getProperties: (classDeclaration: LitClassDeclaration, analyzer: AnalyzerInterface) => Map<string, ReactiveProperty>;
16
+ /**
17
+ * Gets the `attribute` property of a property options object as a string.
18
+ *
19
+ * The attribute value returned is the value that is used at runtime by
20
+ * ReactiveElement, not the raw option. If the attribute property option is
21
+ * not given or is `true`, the lower-cased property name is used. If the
22
+ * attribute property option is `false`, `undefined` is returned.
23
+ */
24
+ export declare const getPropertyAttribute: (ts: TypeScript, optionsNode: ts.ObjectLiteralExpression | undefined, propertyName: string) => string | undefined;
25
+ /**
26
+ * Gets the `type` property of a property options object as a string.
27
+ *
28
+ * Note: A string is returned as a convenience so we don't have to compare
29
+ * the type value against a known set of TS references for String, Number, etc.
30
+ *
31
+ * If a non-default converter is used, the types might not mean the same thing,
32
+ * but we might not be able to realistically support custom converters.
33
+ */
34
+ export declare const getPropertyType: (ts: TypeScript, obj: ts.ObjectLiteralExpression | undefined) => string | undefined;
35
+ /**
36
+ * Gets the `reflect` property of a property options object as a boolean.
37
+ */
38
+ export declare const getPropertyReflect: (ts: TypeScript, obj: ts.ObjectLiteralExpression | undefined) => boolean;
39
+ /**
40
+ * Gets the `converter` property of a property options object.
41
+ */
42
+ export declare const getPropertyConverter: (ts: TypeScript, obj: ts.ObjectLiteralExpression | undefined) => ts.PropertyAssignment | undefined;
43
+ //# sourceMappingURL=properties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../../src/lib/lit/properties.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAC,mBAAmB,EAAC,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAC,gBAAgB,EAAE,iBAAiB,EAAC,MAAM,aAAa,CAAC;AAOhE,MAAM,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC;AAEnC,eAAO,MAAM,aAAa,GACxB,kBAAkB,mBAAmB,EACrC,UAAU,iBAAiB,kCA0E5B,CAAC;AAyJF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAC/B,IAAI,UAAU,EACd,aAAa,EAAE,CAAC,uBAAuB,GAAG,SAAS,EACnD,cAAc,MAAM,uBAwBrB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,UAAU,EACd,KAAK,EAAE,CAAC,uBAAuB,GAAG,SAAS,uBAU5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,UAAU,EACd,KAAK,EAAE,CAAC,uBAAuB,GAAG,SAAS,YAU5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,IAAI,UAAU,EACd,KAAK,EAAE,CAAC,uBAAuB,GAAG,SAAS,sCAM5C,CAAC"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ import { getTypeForNode } from '../types.js';
7
+ import { getPropertyDecorator, getPropertyOptions } from './decorators.js';
8
+ import { hasStaticModifier } from '../utils.js';
9
+ import { DiagnosticCode } from '../diagnostic-code.js';
10
+ import { createDiagnostic } from '../errors.js';
11
+ export const getProperties = (classDeclaration, analyzer) => {
12
+ const { typescript: ts } = analyzer;
13
+ const reactiveProperties = new Map();
14
+ const undecoratedProperties = new Map();
15
+ // Filter down to just the property and getter declarations
16
+ const propertyDeclarations = classDeclaration.members.filter((m) => ts.isPropertyDeclaration(m) || ts.isGetAccessorDeclaration(m));
17
+ let staticProperties;
18
+ for (const prop of propertyDeclarations) {
19
+ if (!ts.isIdentifier(prop.name) && !ts.isPrivateIdentifier(prop.name)) {
20
+ analyzer.addDiagnostic(createDiagnostic({
21
+ typescript: ts,
22
+ node: prop,
23
+ message: '@lit-labs/analyzer only supports analyzing class properties ' +
24
+ 'named with plain identifiers, or private class fields. This ' +
25
+ 'property was ignored: ' +
26
+ prop.name.getText(),
27
+ category: ts.DiagnosticCategory.Warning,
28
+ code: DiagnosticCode.UNSUPPORTED,
29
+ }));
30
+ continue;
31
+ }
32
+ const name = prop.name.text;
33
+ const propertyDecorator = getPropertyDecorator(ts, prop);
34
+ if (propertyDecorator !== undefined) {
35
+ // Decorated property; get property options from the decorator and add
36
+ // them to the reactiveProperties map
37
+ const options = getPropertyOptions(ts, propertyDecorator);
38
+ reactiveProperties.set(name, {
39
+ name,
40
+ node: prop,
41
+ optionsNode: options,
42
+ type: getTypeForNode(prop, analyzer),
43
+ attribute: getPropertyAttribute(ts, options, name),
44
+ typeOption: getPropertyType(ts, options),
45
+ reflect: getPropertyReflect(ts, options),
46
+ converter: getPropertyConverter(ts, options),
47
+ });
48
+ }
49
+ else if (name === 'properties' && hasStaticModifier(ts, prop)) {
50
+ // This field has the static properties block (initializer or getter).
51
+ // Note we will process this after the loop so that the
52
+ // `undecoratedProperties` map is complete before processing the static
53
+ // properties block.
54
+ staticProperties = prop;
55
+ }
56
+ else if (!hasStaticModifier(ts, prop)) {
57
+ // Store the declaration node for any undecorated properties. In a TS
58
+ // program that happens to use a static properties block along with
59
+ // the `declare` keyword to type the field, we can use this node to
60
+ // get/infer the TS type of the field from
61
+ undecoratedProperties.set(name, prop);
62
+ }
63
+ }
64
+ // Handle static properties block (initializer or getter).
65
+ if (staticProperties !== undefined) {
66
+ addPropertiesFromStaticBlock(classDeclaration, staticProperties, undecoratedProperties, reactiveProperties, analyzer);
67
+ }
68
+ return reactiveProperties;
69
+ };
70
+ /**
71
+ * Given a static properties declaration (field or getter), add property
72
+ * options to the provided `reactiveProperties` map.
73
+ */
74
+ const addPropertiesFromStaticBlock = (classDeclaration, properties, undecoratedProperties, reactiveProperties, analyzer) => {
75
+ const { typescript: ts } = analyzer;
76
+ // Add any constructor initializers to the undecorated properties node map
77
+ // from which we can infer types from. This is the primary path that JS source
78
+ // can get their inferred types (in TS, types will come from the undecorated
79
+ // fields passed in, since you need to declare the field to assign it in the
80
+ // constructor).
81
+ addConstructorInitializers(ts, classDeclaration, undecoratedProperties);
82
+ // Find the object literal from the initializer or getter return value
83
+ const object = getStaticPropertiesObjectLiteral(properties, analyzer);
84
+ if (object === undefined) {
85
+ return;
86
+ }
87
+ // Loop over each key/value in the object and add them to the map
88
+ for (const prop of object.properties) {
89
+ if (ts.isPropertyAssignment(prop) &&
90
+ ts.isIdentifier(prop.name) &&
91
+ ts.isObjectLiteralExpression(prop.initializer)) {
92
+ const name = prop.name.text;
93
+ const options = prop.initializer;
94
+ const nodeForType = undecoratedProperties.get(name);
95
+ reactiveProperties.set(name, {
96
+ name,
97
+ node: prop,
98
+ optionsNode: options,
99
+ type: nodeForType !== undefined
100
+ ? getTypeForNode(nodeForType, analyzer)
101
+ : undefined,
102
+ attribute: getPropertyAttribute(ts, options, name),
103
+ typeOption: getPropertyType(ts, options),
104
+ reflect: getPropertyReflect(ts, options),
105
+ converter: getPropertyConverter(ts, options),
106
+ });
107
+ }
108
+ else {
109
+ analyzer.addDiagnostic(createDiagnostic({
110
+ typescript: ts,
111
+ node: prop,
112
+ message: 'Unsupported static properties entry. Expected a string identifier key and object literal value.',
113
+ code: DiagnosticCode.UNSUPPORTED,
114
+ category: ts.DiagnosticCategory.Warning,
115
+ }));
116
+ }
117
+ }
118
+ };
119
+ /**
120
+ * Find the object literal for a static properties block.
121
+ *
122
+ * If a ts.PropertyDeclaration, it will look like:
123
+ *
124
+ * static properties = { ... };
125
+ *
126
+ * If a ts.GetAccessorDeclaration, it will look like:
127
+ *
128
+ * static get properties() {
129
+ * return {... }
130
+ * }
131
+ */
132
+ const getStaticPropertiesObjectLiteral = (properties, analyzer) => {
133
+ const { typescript: ts } = analyzer;
134
+ let object = undefined;
135
+ if (ts.isPropertyDeclaration(properties) &&
136
+ properties.initializer !== undefined &&
137
+ ts.isObjectLiteralExpression(properties.initializer)) {
138
+ // `properties` has a static initializer; get the object from there
139
+ object = properties.initializer;
140
+ }
141
+ else if (ts.isGetAccessorDeclaration(properties)) {
142
+ // Object was in a static getter: find the object in the return value
143
+ const statements = properties.body?.statements;
144
+ const statement = statements?.[statements.length - 1];
145
+ if (statement !== undefined &&
146
+ ts.isReturnStatement(statement) &&
147
+ statement.expression !== undefined &&
148
+ ts.isObjectLiteralExpression(statement.expression)) {
149
+ object = statement.expression;
150
+ }
151
+ }
152
+ if (object === undefined) {
153
+ analyzer.addDiagnostic(createDiagnostic({
154
+ typescript: ts,
155
+ node: properties,
156
+ message: `Unsupported static properties format. Expected an object literal assigned in a static initializer or returned from a static getter.`,
157
+ code: DiagnosticCode.UNSUPPORTED,
158
+ category: ts.DiagnosticCategory.Warning,
159
+ }));
160
+ }
161
+ return object;
162
+ };
163
+ /**
164
+ * Adds any field initializers in the given class's constructor to the provided
165
+ * map. This will be used for inferring the type of fields in JS programs.
166
+ */
167
+ const addConstructorInitializers = (ts, classDeclaration, undecoratedProperties) => {
168
+ const ctor = classDeclaration.forEachChild((node) => ts.isConstructorDeclaration(node) ? node : undefined);
169
+ if (ctor !== undefined) {
170
+ ctor.body?.statements.forEach((stmt) => {
171
+ // Look for initializers in the form of `this.foo = xxxx`
172
+ if (ts.isExpressionStatement(stmt) &&
173
+ ts.isBinaryExpression(stmt.expression) &&
174
+ ts.isPropertyAccessExpression(stmt.expression.left) &&
175
+ stmt.expression.left.expression.kind === ts.SyntaxKind.ThisKeyword &&
176
+ ts.isIdentifier(stmt.expression.left.name) &&
177
+ !undecoratedProperties.has(stmt.expression.left.name.text)) {
178
+ // Add the initializer expression to the map
179
+ undecoratedProperties.set(
180
+ // Property name
181
+ stmt.expression.left.name.text,
182
+ // Expression from which we can infer a type
183
+ stmt.expression.right);
184
+ }
185
+ });
186
+ }
187
+ };
188
+ /**
189
+ * Gets the `attribute` property of a property options object as a string.
190
+ *
191
+ * The attribute value returned is the value that is used at runtime by
192
+ * ReactiveElement, not the raw option. If the attribute property option is
193
+ * not given or is `true`, the lower-cased property name is used. If the
194
+ * attribute property option is `false`, `undefined` is returned.
195
+ */
196
+ export const getPropertyAttribute = (ts, optionsNode, propertyName) => {
197
+ if (optionsNode === undefined) {
198
+ return propertyName.toLowerCase();
199
+ }
200
+ const attributeProperty = getObjectProperty(ts, optionsNode, 'attribute');
201
+ if (attributeProperty === undefined) {
202
+ return propertyName.toLowerCase();
203
+ }
204
+ const { initializer } = attributeProperty;
205
+ if (ts.isStringLiteral(initializer)) {
206
+ return initializer.text;
207
+ }
208
+ if (initializer.kind === ts.SyntaxKind.FalseKeyword) {
209
+ return undefined;
210
+ }
211
+ if (initializer.kind === ts.SyntaxKind.TrueKeyword ||
212
+ (ts.isIdentifier(initializer) && initializer.text === 'undefined') ||
213
+ initializer.kind === ts.SyntaxKind.UndefinedKeyword) {
214
+ return propertyName.toLowerCase();
215
+ }
216
+ return undefined;
217
+ };
218
+ /**
219
+ * Gets the `type` property of a property options object as a string.
220
+ *
221
+ * Note: A string is returned as a convenience so we don't have to compare
222
+ * the type value against a known set of TS references for String, Number, etc.
223
+ *
224
+ * If a non-default converter is used, the types might not mean the same thing,
225
+ * but we might not be able to realistically support custom converters.
226
+ */
227
+ export const getPropertyType = (ts, obj) => {
228
+ if (obj === undefined) {
229
+ return undefined;
230
+ }
231
+ const typeProperty = getObjectProperty(ts, obj, 'type');
232
+ if (typeProperty !== undefined && ts.isIdentifier(typeProperty.initializer)) {
233
+ return typeProperty.initializer.text;
234
+ }
235
+ return undefined;
236
+ };
237
+ /**
238
+ * Gets the `reflect` property of a property options object as a boolean.
239
+ */
240
+ export const getPropertyReflect = (ts, obj) => {
241
+ if (obj === undefined) {
242
+ return false;
243
+ }
244
+ const reflectProperty = getObjectProperty(ts, obj, 'reflect');
245
+ if (reflectProperty === undefined) {
246
+ return false;
247
+ }
248
+ return reflectProperty.initializer.kind === ts.SyntaxKind.TrueKeyword;
249
+ };
250
+ /**
251
+ * Gets the `converter` property of a property options object.
252
+ */
253
+ export const getPropertyConverter = (ts, obj) => {
254
+ if (obj === undefined) {
255
+ return undefined;
256
+ }
257
+ return getObjectProperty(ts, obj, 'converter');
258
+ };
259
+ /**
260
+ * Gets a named property from an object literal expression.
261
+ *
262
+ * Only returns a value for `{k: v}` property assignments. Does not work for
263
+ * shorthand properties (`{k}`), methods, or accessors.
264
+ */
265
+ const getObjectProperty = (ts, obj, name) => obj.properties.find((p) => ts.isPropertyAssignment(p) &&
266
+ ts.isIdentifier(p.name) &&
267
+ p.name.text === name);
268
+ //# sourceMappingURL=properties.js.map