ts-gem-plugin 0.0.9 → 0.0.12

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 (2) hide show
  1. package/dist/index.js +215 -68
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -27,6 +27,26 @@ var import_typescript_template_language_service_decorator = require("@mantou/typ
27
27
 
28
28
  // ../gem/lib/utils.js
29
29
  var { assign, fromEntries, entries, keys } = Object;
30
+ function queueMicrotask(cb) {
31
+ Promise.resolve().then(cb);
32
+ }
33
+ var microtaskSet = /* @__PURE__ */ new Set();
34
+ function addMicrotask(func, method = queueMicrotask) {
35
+ if (microtaskSet.has(func))
36
+ return;
37
+ method(() => {
38
+ microtaskSet.delete(func);
39
+ func();
40
+ });
41
+ microtaskSet.add(func);
42
+ }
43
+ function createUpdater(initState, fn) {
44
+ const state = fn;
45
+ delete state.name;
46
+ delete state.length;
47
+ assign(state, initState);
48
+ return state;
49
+ }
30
50
  var LinkedList = class extends EventTarget {
31
51
  #map = /* @__PURE__ */ new Map();
32
52
  #firstItem;
@@ -101,6 +121,10 @@ var LinkedList = class extends EventTarget {
101
121
  }
102
122
  return deleteItem;
103
123
  }
124
+ clear() {
125
+ this.#map.clear();
126
+ this.#firstItem = this.#lastItem = void 0;
127
+ }
104
128
  /** 获取头部元素,会从链表删除 */
105
129
  get() {
106
130
  const firstItem = this.#firstItem;
@@ -117,8 +141,25 @@ function kebabToCamelCase(str) {
117
141
  return str.replace(/-(.)/g, (_substr, $1) => $1.toUpperCase());
118
142
  }
119
143
 
144
+ // ../gem/lib/store.js
145
+ var _StoreListenerMap = /* @__PURE__ */ new WeakMap();
146
+ function createStore(originStore) {
147
+ const store = createUpdater(originStore, (value) => {
148
+ Object.assign(store, value);
149
+ _StoreListenerMap.get(store)?.forEach((func) => addMicrotask(func));
150
+ });
151
+ _StoreListenerMap.set(store, /* @__PURE__ */ new Set());
152
+ return store;
153
+ }
154
+ function connect(store, func) {
155
+ const listeners = _StoreListenerMap.get(store);
156
+ listeners?.add(func);
157
+ return () => listeners?.delete(func);
158
+ }
159
+
120
160
  // src/configuration.ts
121
161
  var defaultConfiguration = {
162
+ strict: false,
122
163
  emmet: {},
123
164
  elementDefineRules: {
124
165
  "Duoyun*Element": "dy-*",
@@ -140,26 +181,27 @@ var Rules = class {
140
181
  }
141
182
  }
142
183
  };
184
+ var configurationStore = createStore({});
185
+ function onConfigurationUpdate(fn) {
186
+ return connect(configurationStore, fn);
187
+ }
143
188
  var Configuration = class {
144
- #emmet = defaultConfiguration.emmet;
145
- #elementDefineRules = new Rules(defaultConfiguration.elementDefineRules);
146
- update(config) {
147
- this.#emmet = config.emmet || defaultConfiguration.emmet;
148
- this.#elementDefineRules = new Rules({
189
+ strict = defaultConfiguration.strict;
190
+ emmet = defaultConfiguration.emmet;
191
+ elementDefineRules = new Rules(defaultConfiguration.elementDefineRules);
192
+ update({ update, ...config }) {
193
+ Object.assign(this, defaultConfiguration, config);
194
+ this.elementDefineRules = new Rules({
149
195
  ...defaultConfiguration.elementDefineRules,
150
196
  ...config.elementDefineRules
151
197
  });
152
- }
153
- get emmet() {
154
- return this.#emmet;
155
- }
156
- get elementDefineRules() {
157
- return this.#elementDefineRules;
198
+ configurationStore();
158
199
  }
159
200
  };
160
201
 
161
202
  // src/constants.ts
162
203
  var NAME = "gem-plugin";
204
+ var HTML_SUBSTITUTION_CHAR = "_";
163
205
  var Decorators = {
164
206
  Attr: "attribute",
165
207
  NumAttr: "numattribute",
@@ -168,6 +210,7 @@ var Decorators = {
168
210
  Emitter: "emitter",
169
211
  GlobalEmitter: "globalemitter",
170
212
  AdoptedStyle: "adoptedStyle",
213
+ Shadow: "shadow",
171
214
  CustomElement: "customElement",
172
215
  Part: "part",
173
216
  Slot: "slot"
@@ -279,6 +322,11 @@ var Cache = class {
279
322
  this.#addedLinked.add(value);
280
323
  return value;
281
324
  }
325
+ clear() {
326
+ this.#map.clear();
327
+ this.#reverseMap.clear();
328
+ this.#addedLinked.clear();
329
+ }
282
330
  };
283
331
 
284
332
  // src/cache.ts
@@ -293,6 +341,9 @@ var LRUCache = class {
293
341
  get(context, position, init) {
294
342
  return this.#bucket.get(this.#genKey(context, position), init);
295
343
  }
344
+ clear() {
345
+ this.#bucket.clear?.();
346
+ }
296
347
  };
297
348
 
298
349
  // src/data-provider.ts
@@ -318,6 +369,16 @@ function forEachNode(roots, fn) {
318
369
  list.push(..."getChildren" in currentNode ? currentNode.getChildren() : currentNode.children);
319
370
  }
320
371
  }
372
+ function hasDecorator(typescript, node, decorates) {
373
+ return node.modifiers?.some(
374
+ (modifier) => typescript.isDecorator(modifier) && typescript.isIdentifier(modifier.expression) && (!decorates || decorates.includes(modifier.expression.text))
375
+ );
376
+ }
377
+ function hasCallDecorator(typescript, node, decorates) {
378
+ return node.modifiers?.some(
379
+ (modifier) => typescript.isDecorator(modifier) && typescript.isCallExpression(modifier.expression) && (!decorates || decorates.includes(modifier.expression.expression.getText()))
380
+ );
381
+ }
321
382
  function getTemplateNode(typescript, node) {
322
383
  if (typescript.isTaggedTemplateExpression(node)) return node.template;
323
384
  if (typescript.isTemplateExpression(node)) return node;
@@ -469,7 +530,7 @@ var HTMLDataProvider = class {
469
530
  const declaration = e.getDeclarations()?.at(0);
470
531
  const prop = declaration && ts.isPropertyDeclaration(declaration);
471
532
  if (!prop) return;
472
- const hasPropDecorator = declaration.modifiers?.some((m) => ts.isDecorator(m) && ts.isIdentifier(m.expression));
533
+ const hasPropDecorator = hasDecorator(ts, declaration);
473
534
  if (!hasPropDecorator && !isDep) return;
474
535
  const type = declaration.type && typeChecker.getTypeFromTypeNode(declaration.type);
475
536
  const typeText = declaration.type?.getText();
@@ -644,7 +705,7 @@ var Context = class {
644
705
  const vHtml = this.htmlLanguageService.parseHTMLDocument(vDoc);
645
706
  const tagNodeMap = new NodeMap();
646
707
  const classIdNodeMap = new NodeMap();
647
- vHtml.roots.forEach(function process2(e, index, arr) {
708
+ vHtml.roots.forEach(function process(e, index, arr) {
648
709
  e.prev = arr[index - 1];
649
710
  e.next = arr[index + 1];
650
711
  e.tag && tagNodeMap.add(e.tag, e);
@@ -667,7 +728,7 @@ var Context = class {
667
728
  });
668
729
  });
669
730
  }
670
- e.children.forEach(process2);
731
+ e.children.forEach(process);
671
732
  });
672
733
  return { vDoc, vHtml, tagNodeMap, classIdNodeMap };
673
734
  });
@@ -801,7 +862,7 @@ function createVirtualDocument(languageId, content) {
801
862
  return import_vscode_html_languageservice2.TextDocument.create(`embedded://document.${languageId}`, languageId, 1, content);
802
863
  }
803
864
  function getSubstitution(templateString, start, end) {
804
- return templateString.slice(start, end).replaceAll(/[^\n]/g, "_");
865
+ return templateString.slice(start, end).replaceAll(/[^\n]/g, HTML_SUBSTITUTION_CHAR);
805
866
  }
806
867
  function isValidCSSTemplate(typescript, node, callName) {
807
868
  switch (node.kind) {
@@ -1067,6 +1128,7 @@ var CSSLanguageService = class {
1067
1128
  #ctx;
1068
1129
  constructor(ctx) {
1069
1130
  this.#ctx = ctx;
1131
+ onConfigurationUpdate(() => this.#diagnosticsCache.clear());
1070
1132
  }
1071
1133
  #normalize(context, position) {
1072
1134
  const parent = context.node.parent;
@@ -1117,20 +1179,40 @@ var CSSLanguageService = class {
1117
1179
  #getSyntacticDiagnostics(context) {
1118
1180
  const { text, offset } = this.#normalize(context, { line: 0, character: 0 });
1119
1181
  const { vDoc, vCss } = this.#ctx.getCssDoc(text);
1182
+ const result = [];
1120
1183
  const oDiagnostics = this.#ctx.cssLanguageService.doValidation(vDoc, vCss);
1121
1184
  const file = this.#ctx.getProgram().getSourceFile(context.fileName);
1122
- return oDiagnostics.map(({ message, range }) => {
1185
+ const baseDiagnostic = { code: 0, file, source: NAME, category: context.typescript.DiagnosticCategory.Warning };
1186
+ if (this.#ctx.config.strict) {
1187
+ const scopeSelectors = /* @__PURE__ */ new Set([":host", ":scope", "&"]);
1188
+ vCss.getChildren().forEach((rule) => {
1189
+ if (rule.type !== import_vscode_css_languageservice2.NodeType.Ruleset) return;
1190
+ const [selectors, declarations] = rule.getChildren();
1191
+ const isScopeSelector = selectors?.getChildren().every((s) => scopeSelectors.has(s.getText()));
1192
+ if (!isScopeSelector) return;
1193
+ declarations.getChildren().forEach((decl) => {
1194
+ const [property] = decl.getChildren();
1195
+ if (property?.getText() === "display") {
1196
+ result.push({
1197
+ ...baseDiagnostic,
1198
+ start: property.offset,
1199
+ length: property.length,
1200
+ messageText: `Do not set 'display' directly in '${selectors.getText()}', which will cause the 'hidden' attribute to be unavailable`
1201
+ });
1202
+ }
1203
+ });
1204
+ });
1205
+ }
1206
+ oDiagnostics.forEach(({ message, range }) => {
1123
1207
  const start = context.toOffset(range.start);
1124
- return {
1125
- category: context.typescript.DiagnosticCategory.Warning,
1126
- code: 0,
1127
- file,
1208
+ result.push({
1209
+ ...baseDiagnostic,
1128
1210
  start: range.start.line === 0 ? start - offset : start,
1129
1211
  length: context.toOffset(range.end) - start,
1130
- messageText: message,
1131
- source: NAME
1132
- };
1212
+ messageText: message
1213
+ });
1133
1214
  });
1215
+ return result;
1134
1216
  }
1135
1217
  getSyntacticDiagnostics(context) {
1136
1218
  this.#ctx.initElements();
@@ -1345,36 +1427,44 @@ var HTMLLanguageService = class {
1345
1427
  }
1346
1428
  #getHtmlSemanticDiagnostics(context) {
1347
1429
  const offset = context.node.getStart() + 1;
1430
+ const templateTag = context.node.parent.tag?.getText();
1348
1431
  const { vHtml } = this.#ctx.getHtmlDoc(context.text);
1349
1432
  const program = this.#ctx.getProgram();
1350
1433
  const file = program.getSourceFile(context.fileName);
1351
1434
  const typeChecker = program.getTypeChecker();
1352
1435
  const diagnostics = [];
1436
+ const baseDiagnostic = { file, source: NAME };
1353
1437
  forEachNode(vHtml.roots, (node) => {
1354
1438
  if (!node.tag) return;
1355
1439
  const customElementTagDecl = this.#ctx.elements.get(node.tag);
1356
1440
  const builtInElementTagDecl = this.#ctx.builtInElements.get(node.tag);
1441
+ const baseTagDiagnostic = { ...baseDiagnostic, start: node.start + 1, length: node.tag.length };
1442
+ if (this.#ctx.config.strict && templateTag !== "raw" && node.tag === "style") {
1443
+ diagnostics.push({
1444
+ ...baseTagDiagnostic,
1445
+ category: context.typescript.DiagnosticCategory.Warning,
1446
+ code: 106 /* NoStyleTag */,
1447
+ messageText: `Use 'adoptedStyle' or 'createDecoratorTheme' instead of the style tag`
1448
+ });
1449
+ }
1357
1450
  if (isCustomElementTag(node.tag) && !customElementTagDecl) {
1358
1451
  diagnostics.push({
1452
+ ...baseTagDiagnostic,
1359
1453
  category: context.typescript.DiagnosticCategory.Warning,
1360
1454
  code: 101 /* UnknownTag */,
1361
- file,
1362
- start: node.start + 1,
1363
- length: node.tag.length,
1364
- messageText: `Unknown element tag '${node.tag}'`,
1365
- source: NAME
1455
+ messageText: `Unknown element tag '${node.tag}'`
1366
1456
  });
1367
1457
  }
1368
1458
  const tagDeclaration = customElementTagDecl || builtInElementTagDecl;
1369
1459
  if (!tagDeclaration) return;
1460
+ const classType = typeChecker.getTypeAtLocation(tagDeclaration);
1461
+ const isSVG = builtInElementTagDecl?.name.getText().startsWith("SVG");
1370
1462
  if (tagDeclaration.name && isDeprecate(typeChecker.getSymbolAtLocation(tagDeclaration.name))) {
1371
- [node.start + 1, node.endTagStart && node.endTagStart + 2].forEach((tagStart) => {
1372
- tagStart && diagnostics.push({
1373
- category: context.typescript.DiagnosticCategory.Suggestion,
1374
- file,
1463
+ [node.start + 1, node.endTagStart && node.endTagStart + 2].filter(isNotNullish).forEach((tagStart) => {
1464
+ diagnostics.push({
1465
+ ...baseTagDiagnostic,
1375
1466
  start: tagStart,
1376
- length: node.tag.length,
1377
- source: NAME,
1467
+ category: context.typescript.DiagnosticCategory.Suggestion,
1378
1468
  code: 105 /* Deprecated */,
1379
1469
  messageText: `Deprecated tag '${node.tag}'`,
1380
1470
  reportsDeprecated: "true"
@@ -1382,30 +1472,45 @@ var HTMLLanguageService = class {
1382
1472
  });
1383
1473
  }
1384
1474
  for (const [attributeName, { value, start, end }] of node.attributesMap) {
1385
- if (attributeName.startsWith("_")) continue;
1386
- const hasValueSpan = value?.startsWith("_");
1475
+ if (attributeName.startsWith(HTML_SUBSTITUTION_CHAR)) continue;
1476
+ const hasValueSpan = value?.startsWith(HTML_SUBSTITUTION_CHAR);
1387
1477
  const attrInfo = getAttrName(attributeName);
1388
- const propType = getPropType(typeChecker, tagDeclaration, !customElementTagDecl, attrInfo, () => {
1478
+ const propName = getPropName(attrInfo, !!builtInElementTagDecl);
1479
+ const propType = getPropType(typeChecker, classType, propName, attrInfo.decorate === "@");
1480
+ const attrBaseDiagnostic = { ...baseDiagnostic, start, length: end - start };
1481
+ if (isDeprecate(classType.getProperty(propName))) {
1389
1482
  diagnostics.push({
1483
+ ...attrBaseDiagnostic,
1390
1484
  category: context.typescript.DiagnosticCategory.Suggestion,
1391
- file,
1392
- start,
1393
- length: end - start,
1394
- source: NAME,
1395
1485
  code: 105 /* Deprecated */,
1396
1486
  messageText: `Deprecated prop '${attrInfo.attr}'`,
1397
1487
  reportsDeprecated: "true"
1398
1488
  });
1399
- });
1489
+ }
1400
1490
  const diagnostic = {
1491
+ ...attrBaseDiagnostic,
1401
1492
  category: context.typescript.DiagnosticCategory.Warning,
1402
- file,
1403
- start,
1404
- length: end - start,
1405
- source: NAME,
1406
1493
  code: 103 /* PropTypeError */,
1407
1494
  messageText: !propType ? `'${attributeName}' type error` : `'${attributeName}' not satisfied '${typeChecker.typeToString(propType)}'`
1408
1495
  };
1496
+ if (templateTag === "raw") {
1497
+ if (attrInfo.decorate) {
1498
+ diagnostics.push({
1499
+ ...diagnostic,
1500
+ code: 104 /* PropSyntaxError */,
1501
+ messageText: `Raw HTML templates only support attributes`
1502
+ });
1503
+ continue;
1504
+ }
1505
+ if (hasValueSpan) {
1506
+ diagnostics.push({
1507
+ ...diagnostic,
1508
+ code: 104 /* PropSyntaxError */,
1509
+ messageText: `Please wrap the raw html template attribute value with "" to avoid parsing errors when the value is an empty string`
1510
+ });
1511
+ continue;
1512
+ }
1513
+ }
1409
1514
  if ((attributeName === "v-else-if" || attributeName === "v-else") && !node.prev?.attributesMap.has("v-if") && !node.prev?.attributesMap.has("v-else-if")) {
1410
1515
  diagnostics.push({
1411
1516
  ...diagnostic,
@@ -1427,7 +1532,10 @@ var HTMLLanguageService = class {
1427
1532
  }
1428
1533
  continue;
1429
1534
  }
1430
- if (attrInfo.decorate === "" && attributeName !== camelToKebabCase(attrInfo.attr)) {
1535
+ if (
1536
+ // SVG 大小写敏感
1537
+ !isSVG && attrInfo.decorate === "" && attributeName !== camelToKebabCase(attrInfo.attr)
1538
+ ) {
1431
1539
  diagnostics.push({
1432
1540
  ...diagnostic,
1433
1541
  code: 2552 /* AttrFormatError */,
@@ -1436,8 +1544,10 @@ var HTMLLanguageService = class {
1436
1544
  continue;
1437
1545
  }
1438
1546
  if (!propType) {
1439
- if (attrInfo.decorate !== "@" && // SVG 元素有很多 css 属性,所以不检查
1440
- !builtInElementTagDecl?.name.getText().startsWith("SVG")) {
1547
+ if (
1548
+ // SVG 元素有很多 css 属性,所以不检查
1549
+ !isSVG && attrInfo.decorate !== "@"
1550
+ ) {
1441
1551
  diagnostics.push({
1442
1552
  ...diagnostic,
1443
1553
  code: 102 /* UnknownProp */,
@@ -1489,7 +1599,11 @@ var HTMLLanguageService = class {
1489
1599
  }
1490
1600
  continue;
1491
1601
  default: {
1492
- const nullablePropType = getUnionType(typeChecker, [propType, typeChecker.getNullType()]);
1602
+ const nullablePropType = getUnionType(typeChecker, [
1603
+ propType,
1604
+ typeChecker.getNullType(),
1605
+ typeChecker.getUndefinedType()
1606
+ ]);
1493
1607
  if (!typeChecker.isTypeAssignableTo(spanType, nullablePropType) && (!typeChecker.isTypeAssignableTo(propType, typeChecker.getStringType()) || !typeChecker.isTypeAssignableTo(spanType, typeChecker.getStringType()))) {
1494
1608
  diagnostics.push(diagnostic);
1495
1609
  }
@@ -1680,12 +1794,16 @@ var globalEnumeratedBooleanAttr = /* @__PURE__ */ new Map([
1680
1794
  ["spellcheck", []],
1681
1795
  ["contenteditable", ["plaintext-only"]]
1682
1796
  ]);
1683
- function getPropType(typeChecker, tagClassDeclaration, isBuiltInTag, attrInfo, reportDeprecate) {
1684
- const classType = typeChecker.getTypeAtLocation(tagClassDeclaration);
1797
+ function getPropName(attrInfo, isNativeTag) {
1685
1798
  if (attrInfo.attr.startsWith("data-")) {
1799
+ return attrInfo.attr;
1800
+ }
1801
+ return globalAttrPropMap.get(attrInfo.attr) || (isNativeTag ? buildInElementNoGlobalAttrPropMap.get(attrInfo.attr) || kebabToCamelCase(attrInfo.attr) : kebabToCamelCase(attrInfo.attr));
1802
+ }
1803
+ function getPropType(typeChecker, classType, propName, isEvent) {
1804
+ if (propName.startsWith("data-")) {
1686
1805
  return typeChecker.getStringType();
1687
1806
  }
1688
- const propName = globalAttrPropMap.get(attrInfo.attr) || (isBuiltInTag ? buildInElementNoGlobalAttrPropMap.get(attrInfo.attr) || kebabToCamelCase(attrInfo.attr) : kebabToCamelCase(attrInfo.attr));
1689
1807
  switch (propName) {
1690
1808
  case "class":
1691
1809
  case "style":
@@ -1718,9 +1836,7 @@ function getPropType(typeChecker, tagClassDeclaration, isBuiltInTag, attrInfo, r
1718
1836
  typeChecker.getUndefinedType()
1719
1837
  ]);
1720
1838
  default: {
1721
- const isEvent = attrInfo.decorate === "@";
1722
1839
  const propSymbol = classType.getProperty(propName);
1723
- if (isDeprecate(propSymbol)) reportDeprecate();
1724
1840
  const propType = propSymbol && typeChecker.getTypeOfSymbol(propSymbol);
1725
1841
  if (!isEvent) return propType;
1726
1842
  const eventHandleType = getEmitterHandleType(typeChecker, classType, propType);
@@ -1805,19 +1921,45 @@ function decorateLanguageService(ctx, languageService) {
1805
1921
  ts.forEachChild(file, (node) => {
1806
1922
  const tag = ctx.getTagFromNode(node);
1807
1923
  if (tag && ts.isClassDeclaration(node)) {
1924
+ if (node.name && !node.name.text.endsWith("Element")) {
1925
+ result.push({
1926
+ file,
1927
+ start: node.name.getStart(),
1928
+ length: node.name.getEnd() - node.name.getStart(),
1929
+ category: ctx.config.strict ? ts.DiagnosticCategory.Warning : ts.DiagnosticCategory.Suggestion,
1930
+ code: 108 /* SuggestionClassName */,
1931
+ messageText: "Element definition class suggests the suffix to use `Element`"
1932
+ });
1933
+ }
1934
+ const isShadowDom = hasCallDecorator(ts, node, [Decorators.Shadow]);
1808
1935
  node.members.forEach((member) => {
1936
+ const memberStart = member.getStart();
1937
+ const baseMemberDiagnostic = { file, start: memberStart, length: member.getEnd() - memberStart };
1938
+ if (ctx.config.strict && member.name && ts.isIdentifier(member.name) && member.name.text.length > 3 && member.name.text === member.name.text.toLowerCase() && member.name.text.startsWith("on")) {
1939
+ result.push({
1940
+ ...baseMemberDiagnostic,
1941
+ category: ts.DiagnosticCategory.Warning,
1942
+ code: 110 /* SuggestionPropName */,
1943
+ messageText: "Consider changing the name, it looks too much like the html event handler"
1944
+ });
1945
+ }
1809
1946
  if (!ts.isPropertyDeclaration(member) || !member.modifiers) return;
1810
- const shouldIsStatic = member.modifiers.some(
1811
- (modifier) => ts.isDecorator(modifier) && ts.isIdentifier(modifier.expression) && [Decorators.Slot, Decorators.Part].includes(modifier.expression.text)
1812
- );
1813
- if (shouldIsStatic && member.modifiers.every((e) => e.kind !== ts.SyntaxKind.StaticKeyword)) {
1947
+ if (hasDecorator(ts, member, [Decorators.Prop]) && !member.questionToken && !member.initializer) {
1814
1948
  result.push({
1815
- file,
1816
- start: member.getStart(),
1817
- length: member.getEnd() - member.getStart(),
1949
+ ...baseMemberDiagnostic,
1950
+ category: ctx.config.strict ? ts.DiagnosticCategory.Warning : ts.DiagnosticCategory.Suggestion,
1951
+ code: 109 /* SuggestionPropOptional */,
1952
+ messageText: "Custom element property should be optional"
1953
+ });
1954
+ }
1955
+ if (!hasDecorator(ts, member, [Decorators.Slot, Decorators.Part])) return;
1956
+ const missStaticKeyword = member.modifiers.every((e) => e.kind !== ts.SyntaxKind.StaticKeyword);
1957
+ if (missStaticKeyword || !isShadowDom) {
1958
+ result.push({
1959
+ ...baseMemberDiagnostic,
1818
1960
  category: ts.DiagnosticCategory.Warning,
1819
- code: 2552 /* DecoratorSyntaxError */,
1820
- messageText: "Use static field for `@part` and `@slot`"
1961
+ code: 107 /* DecoratorSyntaxError */,
1962
+ messageText: missStaticKeyword ? "Use static field for `@part` and `@slot`" : "Not available on light dom `@part` and `@slot`"
1821
1963
  });
1822
1964
  }
1823
1965
  });
@@ -1826,10 +1968,15 @@ function decorateLanguageService(ctx, languageService) {
1826
1968
  return result.filter(({ start, reportsUnnecessary, category }) => {
1827
1969
  if (!reportsUnnecessary || category !== ts.DiagnosticCategory.Suggestion) return true;
1828
1970
  const node = getAstNodeAtPosition(ts, file, start);
1829
- if (!node || !ts.isPrivateIdentifier(node)) return true;
1830
- const declaration = node.parent;
1831
- if (!ts.isMethodDeclaration(declaration) && !ts.isPropertyDeclaration(declaration)) return true;
1832
- return !declaration.modifiers?.some((e) => e?.kind === ts.SyntaxKind.Decorator);
1971
+ const declaration = node?.parent;
1972
+ if (!declaration) return true;
1973
+ if (ts.isClassDeclaration(declaration)) {
1974
+ return !hasCallDecorator(ts, declaration, [Decorators.CustomElement]);
1975
+ }
1976
+ if (ts.isMethodDeclaration(declaration) || ts.isPropertyDeclaration(declaration)) {
1977
+ return !declaration.modifiers?.some((e) => e?.kind === ts.SyntaxKind.Decorator);
1978
+ }
1979
+ return true;
1833
1980
  });
1834
1981
  };
1835
1982
  languageService.findReferences = (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-gem-plugin",
3
- "version": "0.0.9",
3
+ "version": "0.0.12",
4
4
  "description": "Typescript language service plugin for Gem",
5
5
  "keywords": [
6
6
  "gem",
@@ -14,17 +14,17 @@
14
14
  "prepublishOnly": "pnpm run build"
15
15
  },
16
16
  "dependencies": {
17
- "@mantou/gem": "^2.2.1",
17
+ "@mantou/gem": "^2.2.4",
18
18
  "@mantou/typescript-template-language-service-decorator": "^2.3.6",
19
19
  "@mantou/vscode-css-languageservice": "^6.3.6",
20
20
  "@mantou/vscode-emmet-helper": "^2.9.3",
21
21
  "@mantou/vscode-html-languageservice": "^5.3.6",
22
- "duoyun-ui": "^2.2.1",
22
+ "duoyun-ui": "^2.2.3",
23
23
  "vscode-languageserver-textdocument": "^1.0.12",
24
24
  "vscode-languageserver-types": "^3.17.5"
25
25
  },
26
26
  "devDependencies": {
27
- "@gemjs/config": "^2.1.1",
27
+ "@gemjs/config": "^2.1.3",
28
28
  "typescript": "^5.6.2"
29
29
  },
30
30
  "author": "mantou132",