wrec 0.35.0 → 0.35.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.
- package/package.json +1 -1
- package/scripts/lint.js +59 -1
package/package.json
CHANGED
package/scripts/lint.js
CHANGED
|
@@ -451,6 +451,21 @@ function collectSupportedPropertyNames(classNode) {
|
|
|
451
451
|
return supportedProps;
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
+
// Collects declared TypeScript property types from a component class.
|
|
455
|
+
function collectDeclaredPropertyTypes(classNode) {
|
|
456
|
+
const declaredProps = new Map();
|
|
457
|
+
|
|
458
|
+
for (const member of classNode.members) {
|
|
459
|
+
if (!isDeclarePropertyDeclaration(member)) continue;
|
|
460
|
+
|
|
461
|
+
const propName = getMemberName(member);
|
|
462
|
+
if (!propName || !member.type) continue;
|
|
463
|
+
declaredProps.set(propName, member.type);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return declaredProps;
|
|
467
|
+
}
|
|
468
|
+
|
|
454
469
|
// Validates that useState mappings point at existing component properties.
|
|
455
470
|
function collectUseStateMapErrors(classNode, supportedProps, findings) {
|
|
456
471
|
// Walks the class body looking for useState calls with mapping objects.
|
|
@@ -815,6 +830,7 @@ function formatReport(
|
|
|
815
830
|
findings.duplicateProperties.length > 0 ||
|
|
816
831
|
findings.extraArguments.length > 0 ||
|
|
817
832
|
findings.incompatibleArguments.length > 0 ||
|
|
833
|
+
findings.incompatibleDeclareTypes.length > 0 ||
|
|
818
834
|
findings.invalidCheckedBindings.length > 0 ||
|
|
819
835
|
findings.invalidComputedProperties.length > 0 ||
|
|
820
836
|
findings.invalidDefaultValues.length > 0 ||
|
|
@@ -889,6 +905,13 @@ function formatReport(
|
|
|
889
905
|
});
|
|
890
906
|
}
|
|
891
907
|
|
|
908
|
+
if (findings.incompatibleDeclareTypes.length > 0) {
|
|
909
|
+
lines.push('incompatible declare types:');
|
|
910
|
+
findings.incompatibleDeclareTypes.forEach(message =>
|
|
911
|
+
lines.push(` ${message}`)
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
|
|
892
915
|
if (findings.invalidCheckedBindings.length > 0) {
|
|
893
916
|
lines.push('invalid checked bindings:');
|
|
894
917
|
findings.invalidCheckedBindings.forEach(message =>
|
|
@@ -1166,6 +1189,11 @@ function getPropertyTypeText(checker, sourceFile, expression) {
|
|
|
1166
1189
|
return checker.typeToString(type);
|
|
1167
1190
|
}
|
|
1168
1191
|
|
|
1192
|
+
// Gets the TypeScript type text for a declared property member.
|
|
1193
|
+
function getPropertyTypeTextFromNode(sourceFile, typeNode) {
|
|
1194
|
+
return typeNode.getText(sourceFile).trim();
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1169
1197
|
// Returns an array of string literal values from a property when possible.
|
|
1170
1198
|
function getStringArrayLiteral(property) {
|
|
1171
1199
|
if (!property || !ts.isPropertyAssignment(property)) return undefined;
|
|
@@ -1275,6 +1303,17 @@ function isCallCallee(node) {
|
|
|
1275
1303
|
return ts.isCallExpression(node.parent) && node.parent.expression === node;
|
|
1276
1304
|
}
|
|
1277
1305
|
|
|
1306
|
+
// Returns whether a class member is a declared property declaration.
|
|
1307
|
+
function isDeclarePropertyDeclaration(member) {
|
|
1308
|
+
return (
|
|
1309
|
+
ts.isPropertyDeclaration(member) &&
|
|
1310
|
+
ts.canHaveModifiers(member) &&
|
|
1311
|
+
ts
|
|
1312
|
+
.getModifiers(member)
|
|
1313
|
+
?.some(mod => mod.kind === ts.SyntaxKind.DeclareKeyword)
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1278
1317
|
// Returns whether a reference refers to a getter method.
|
|
1279
1318
|
function isGetterReference(reference) {
|
|
1280
1319
|
return reference.startsWith(GETTER_PREFIX);
|
|
@@ -1362,12 +1401,14 @@ export function lintSource(filePath, sourceText, options = {}) {
|
|
|
1362
1401
|
propertyEntries,
|
|
1363
1402
|
reservedProperties
|
|
1364
1403
|
} = extractProperties(sourceFile, checker, classNode);
|
|
1404
|
+
const declaredPropertyTypes = collectDeclaredPropertyTypes(classNode);
|
|
1365
1405
|
const getterNames = collectGetterNames(classNode);
|
|
1366
1406
|
const allMethods = collectClassMethods(classNode);
|
|
1367
1407
|
const findings = {
|
|
1368
1408
|
duplicateProperties,
|
|
1369
1409
|
extraArguments: [],
|
|
1370
1410
|
incompatibleArguments: [],
|
|
1411
|
+
incompatibleDeclareTypes: [],
|
|
1371
1412
|
invalidCheckedBindings: [],
|
|
1372
1413
|
invalidComputedProperties: [],
|
|
1373
1414
|
invalidDefaultValues: [],
|
|
@@ -1430,6 +1471,8 @@ export function lintSource(filePath, sourceText, options = {}) {
|
|
|
1430
1471
|
|
|
1431
1472
|
validatePropertyConfigs(
|
|
1432
1473
|
checker,
|
|
1474
|
+
sourceFile,
|
|
1475
|
+
declaredPropertyTypes,
|
|
1433
1476
|
supportedProps,
|
|
1434
1477
|
propertyEntries,
|
|
1435
1478
|
getterNames,
|
|
@@ -1473,6 +1516,7 @@ export function lintSource(filePath, sourceText, options = {}) {
|
|
|
1473
1516
|
a.methodName.localeCompare(b.methodName) ||
|
|
1474
1517
|
a.parameterName.localeCompare(b.parameterName)
|
|
1475
1518
|
);
|
|
1519
|
+
findings.incompatibleDeclareTypes.sort();
|
|
1476
1520
|
findings.invalidCheckedBindings.sort();
|
|
1477
1521
|
findings.invalidComputedProperties.sort();
|
|
1478
1522
|
findings.invalidDefaultValues.sort();
|
|
@@ -1865,6 +1909,8 @@ function validateHtmlNesting(node, findings) {
|
|
|
1865
1909
|
// Validates all configured component property metadata entries.
|
|
1866
1910
|
function validatePropertyConfigs(
|
|
1867
1911
|
checker,
|
|
1912
|
+
sourceFile,
|
|
1913
|
+
declaredPropertyTypes,
|
|
1868
1914
|
supportedProps,
|
|
1869
1915
|
propertyEntries,
|
|
1870
1916
|
getterNames,
|
|
@@ -1872,9 +1918,10 @@ function validatePropertyConfigs(
|
|
|
1872
1918
|
findings
|
|
1873
1919
|
) {
|
|
1874
1920
|
for (const {config, propName} of propertyEntries) {
|
|
1921
|
+
const computedProp = getObjectProperty(config, 'computed');
|
|
1922
|
+
const declaredTypeNode = declaredPropertyTypes.get(propName);
|
|
1875
1923
|
const typeProp = getObjectProperty(config, 'type');
|
|
1876
1924
|
const usedByProp = getObjectProperty(config, 'usedBy');
|
|
1877
|
-
const computedProp = getObjectProperty(config, 'computed');
|
|
1878
1925
|
const valueProp = getObjectProperty(config, 'value');
|
|
1879
1926
|
const valuesProp = getObjectProperty(config, 'values');
|
|
1880
1927
|
|
|
@@ -1894,6 +1941,17 @@ function validatePropertyConfigs(
|
|
|
1894
1941
|
`property "${propName}" type must be one of ` +
|
|
1895
1942
|
'Boolean, Number, String, Object, or Array'
|
|
1896
1943
|
);
|
|
1944
|
+
} else if (declaredTypeNode) {
|
|
1945
|
+
const runtimeType = checker.getTypeAtLocation(typeExpression);
|
|
1946
|
+
const declaredType = checker.getTypeFromTypeNode(declaredTypeNode);
|
|
1947
|
+
if (!checker.isTypeAssignableTo(runtimeType, declaredType)) {
|
|
1948
|
+
findings.incompatibleDeclareTypes.push(
|
|
1949
|
+
`property "${propName}" declare type ` +
|
|
1950
|
+
`"${getPropertyTypeTextFromNode(sourceFile, declaredTypeNode)}" ` +
|
|
1951
|
+
`is not compatible with static properties type ` +
|
|
1952
|
+
`"${getPropertyConfigTypeName(typeExpressionKind(typeExpression))}"`
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1897
1955
|
}
|
|
1898
1956
|
|
|
1899
1957
|
if (usedByProp && ts.isPropertyAssignment(usedByProp)) {
|