@openrewrite/rewrite 8.62.4 → 8.62.6

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 (110) hide show
  1. package/dist/java/tree.d.ts +12 -6
  2. package/dist/java/tree.d.ts.map +1 -1
  3. package/dist/java/tree.js +12 -5
  4. package/dist/java/tree.js.map +1 -1
  5. package/dist/java/type.d.ts +2 -0
  6. package/dist/java/type.d.ts.map +1 -1
  7. package/dist/java/type.js +12 -0
  8. package/dist/java/type.js.map +1 -1
  9. package/dist/java/visitor.d.ts +8 -0
  10. package/dist/java/visitor.d.ts.map +1 -1
  11. package/dist/java/visitor.js +23 -1
  12. package/dist/java/visitor.js.map +1 -1
  13. package/dist/javascript/index.d.ts +3 -0
  14. package/dist/javascript/index.d.ts.map +1 -1
  15. package/dist/javascript/index.js +3 -0
  16. package/dist/javascript/index.js.map +1 -1
  17. package/dist/javascript/method-matcher.d.ts +16 -0
  18. package/dist/javascript/method-matcher.d.ts.map +1 -0
  19. package/dist/javascript/method-matcher.js +222 -0
  20. package/dist/javascript/method-matcher.js.map +1 -0
  21. package/dist/javascript/parser.js +1 -1
  22. package/dist/javascript/parser.js.map +1 -1
  23. package/dist/javascript/preconditions.d.ts +6 -0
  24. package/dist/javascript/preconditions.d.ts.map +1 -0
  25. package/dist/javascript/preconditions.js +58 -0
  26. package/dist/javascript/preconditions.js.map +1 -0
  27. package/dist/javascript/remove-import.d.ts +56 -0
  28. package/dist/javascript/remove-import.d.ts.map +1 -0
  29. package/dist/javascript/remove-import.js +715 -0
  30. package/dist/javascript/remove-import.js.map +1 -0
  31. package/dist/javascript/rpc.js +2 -2
  32. package/dist/javascript/rpc.js.map +1 -1
  33. package/dist/javascript/search/index.d.ts +3 -0
  34. package/dist/javascript/search/index.d.ts.map +1 -0
  35. package/dist/javascript/search/index.js +19 -0
  36. package/dist/javascript/search/index.js.map +1 -0
  37. package/dist/javascript/search/uses-method.d.ts +8 -0
  38. package/dist/javascript/search/uses-method.d.ts.map +1 -0
  39. package/dist/javascript/search/uses-method.js +35 -0
  40. package/dist/javascript/search/uses-method.js.map +1 -0
  41. package/dist/javascript/search/uses-type.d.ts +8 -0
  42. package/dist/javascript/search/uses-type.d.ts.map +1 -0
  43. package/dist/javascript/search/uses-type.js +71 -0
  44. package/dist/javascript/search/uses-type.js.map +1 -0
  45. package/dist/javascript/templating.d.ts +1 -1
  46. package/dist/javascript/templating.d.ts.map +1 -1
  47. package/dist/javascript/templating.js +1 -1
  48. package/dist/javascript/templating.js.map +1 -1
  49. package/dist/javascript/tree.d.ts +3 -3
  50. package/dist/javascript/tree.d.ts.map +1 -1
  51. package/dist/javascript/tree.js +28 -0
  52. package/dist/javascript/tree.js.map +1 -1
  53. package/dist/javascript/type-mapping.d.ts +4 -0
  54. package/dist/javascript/type-mapping.d.ts.map +1 -1
  55. package/dist/javascript/type-mapping.js +92 -46
  56. package/dist/javascript/type-mapping.js.map +1 -1
  57. package/dist/javascript/visitor.js +1 -1
  58. package/dist/javascript/visitor.js.map +1 -1
  59. package/dist/print.d.ts +1 -0
  60. package/dist/print.d.ts.map +1 -1
  61. package/dist/print.js +6 -0
  62. package/dist/print.js.map +1 -1
  63. package/dist/rpc/rewrite-rpc.d.ts +1 -1
  64. package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
  65. package/dist/rpc/rewrite-rpc.js +0 -3
  66. package/dist/rpc/rewrite-rpc.js.map +1 -1
  67. package/dist/search/index.d.ts +2 -0
  68. package/dist/search/index.d.ts.map +1 -0
  69. package/dist/search/index.js +18 -0
  70. package/dist/search/index.js.map +1 -0
  71. package/dist/search/is-source-file.d.ts +8 -0
  72. package/dist/search/is-source-file.d.ts.map +1 -0
  73. package/dist/search/is-source-file.js +70 -0
  74. package/dist/search/is-source-file.js.map +1 -0
  75. package/dist/test/rewrite-test.d.ts.map +1 -1
  76. package/dist/test/rewrite-test.js +3 -0
  77. package/dist/test/rewrite-test.js.map +1 -1
  78. package/dist/util.d.ts +1 -0
  79. package/dist/util.d.ts.map +1 -1
  80. package/dist/util.js +13 -0
  81. package/dist/util.js.map +1 -1
  82. package/dist/version.txt +1 -1
  83. package/dist/visitor.d.ts +1 -1
  84. package/dist/visitor.d.ts.map +1 -1
  85. package/dist/visitor.js +3 -2
  86. package/dist/visitor.js.map +1 -1
  87. package/package.json +3 -1
  88. package/src/java/tree.ts +19 -11
  89. package/src/java/type.ts +14 -0
  90. package/src/java/visitor.ts +28 -8
  91. package/src/javascript/index.ts +4 -0
  92. package/src/javascript/method-matcher.ts +250 -0
  93. package/src/javascript/parser.ts +1 -1
  94. package/src/javascript/preconditions.ts +40 -0
  95. package/src/javascript/remove-import.ts +780 -0
  96. package/src/javascript/rpc.ts +2 -2
  97. package/src/javascript/search/index.ts +2 -0
  98. package/src/javascript/search/uses-method.ts +21 -0
  99. package/src/javascript/search/uses-type.ts +27 -0
  100. package/src/javascript/templating.ts +4 -3
  101. package/src/javascript/tree.ts +47 -3
  102. package/src/javascript/type-mapping.ts +113 -50
  103. package/src/javascript/visitor.ts +125 -125
  104. package/src/print.ts +9 -3
  105. package/src/rpc/rewrite-rpc.ts +1 -4
  106. package/src/search/index.ts +1 -0
  107. package/src/search/is-source-file.ts +26 -0
  108. package/src/test/rewrite-test.ts +4 -1
  109. package/src/util.ts +19 -4
  110. package/src/visitor.ts +3 -3
@@ -105,7 +105,7 @@ class JavaScriptSender extends JavaScriptVisitor<RpcSendQueue> {
105
105
  await q.getAndSend(functionCall, m => m.function, f => this.visitRightPadded(f, q));
106
106
  await q.getAndSend(functionCall, m => m.typeParameters, params => this.visitContainer(params, q));
107
107
  await q.getAndSend(functionCall, m => m.arguments, args => this.visitContainer(args, q));
108
- await q.getAndSend(functionCall, m => asRef(m.functionType), type => this.visitType(type, q));
108
+ await q.getAndSend(functionCall, m => asRef(m.methodType), type => this.visitType(type, q));
109
109
  return functionCall;
110
110
  }
111
111
 
@@ -643,7 +643,7 @@ class JavaScriptReceiver extends JavaScriptVisitor<RpcReceiveQueue> {
643
643
  draft.function = await q.receive(functionCall.function, select => this.visitRightPadded(select, q));
644
644
  draft.typeParameters = await q.receive(functionCall.typeParameters, typeParams => this.visitContainer(typeParams, q));
645
645
  draft.arguments = await q.receive(functionCall.arguments, args => this.visitContainer(args, q));
646
- draft.functionType = await q.receive(functionCall.functionType, type => this.visitType(type, q) as unknown as Type.Method);
646
+ draft.methodType = await q.receive(functionCall.methodType, type => this.visitType(type, q) as unknown as Type.Method);
647
647
 
648
648
  return finishDraft(draft);
649
649
  }
@@ -0,0 +1,2 @@
1
+ export * from './uses-method';
2
+ export * from './uses-type';
@@ -0,0 +1,21 @@
1
+ import {Expression, J, JavaVisitor} from "../../java";
2
+ import {ExecutionContext} from "../../execution";
3
+ import {MethodMatcher} from "../method-matcher";
4
+ import {JS} from "../tree";
5
+ import {foundSearchResult} from "../../markers";
6
+
7
+ export class UsesMethod extends JavaVisitor<ExecutionContext> {
8
+ private readonly matcher;
9
+
10
+ constructor(pattern: string) {
11
+ super();
12
+ this.matcher = new MethodMatcher(pattern);
13
+ }
14
+
15
+ protected async visitExpression(expression: Expression, p: ExecutionContext): Promise<J | undefined> {
16
+ if (JS.isMethodCall(expression) && this.matcher.matches(expression.methodType)) {
17
+ return foundSearchResult(expression);
18
+ }
19
+ return super.visitExpression(expression, p);
20
+ }
21
+ }
@@ -0,0 +1,27 @@
1
+ import {J, JavaVisitor, Type} from "../../java";
2
+ import {ExecutionContext} from "../../execution";
3
+ import * as picomatch from "picomatch";
4
+ import {foundSearchResult} from "../../markers";
5
+
6
+ export class UsesType extends JavaVisitor<ExecutionContext> {
7
+ private readonly matcher: picomatch.Matcher;
8
+
9
+ constructor(typePattern: string) {
10
+ super();
11
+ // Create a picomatch matcher for the pattern
12
+ this.matcher = picomatch.default ? picomatch.default(typePattern) : (picomatch as any)(typePattern);
13
+ }
14
+
15
+ protected async preVisit(tree: J, _: ExecutionContext): Promise<J | undefined> {
16
+ if (J.hasType(tree)) {
17
+ const type = tree.type;
18
+ if (Type.isFullyQualified(type)) {
19
+ const fullyQualifiedName = Type.FullyQualified.getFullyQualifiedName(type);
20
+ if (this.matcher(fullyQualifiedName)) {
21
+ return foundSearchResult(tree);
22
+ }
23
+ }
24
+ }
25
+ return tree;
26
+ }
27
+ }
@@ -92,7 +92,8 @@ export class Pattern {
92
92
  export class MatchResult implements Pick<Map<string, J>, "get"> {
93
93
  constructor(
94
94
  private readonly bindings: Map<string, J> = new Map()
95
- ) {}
95
+ ) {
96
+ }
96
97
 
97
98
  get(capture: Capture | string): J | undefined {
98
99
  const name = typeof capture === "string" ? capture : capture.name;
@@ -577,7 +578,7 @@ class TemplateApplier {
577
578
  * @returns A Promise resolving to the modified AST
578
579
  */
579
580
  async apply(): Promise<J | undefined> {
580
- const {tree, loc, mode} = this.coordinates;
581
+ const {loc} = this.coordinates;
581
582
 
582
583
  // Apply the template based on the location and mode
583
584
  switch (loc || 'EXPRESSION_PREFIX') {
@@ -771,7 +772,7 @@ class RewriteRuleImpl implements RewriteRule {
771
772
  * after: template`${"left"} === ${"right"}`
772
773
  * }));
773
774
  */
774
- export function rewrite<T extends J>(
775
+ export function rewrite(
775
776
  builderFn: () => RewriteConfig
776
777
  ): RewriteRule {
777
778
  const config = builderFn();
@@ -17,7 +17,20 @@
17
17
  */
18
18
 
19
19
  import {SourceFile} from "../tree";
20
- import {Expression, J, NameTree, Statement, Type, TypedTree, TypeTree, VariableDeclarator,} from "../java";
20
+ import {
21
+ Expression,
22
+ J,
23
+ JavaVisitor,
24
+ MethodCall,
25
+ NameTree,
26
+ Statement,
27
+ Type,
28
+ TypedTree,
29
+ TypeTree,
30
+ VariableDeclarator,
31
+ registerJavaExtensionKinds
32
+ } from "../java";
33
+ import {JavaScriptVisitor} from "./visitor";
21
34
 
22
35
  export interface JS extends J {
23
36
  }
@@ -94,6 +107,10 @@ export namespace JS {
94
107
  WithStatement: "org.openrewrite.javascript.tree.JS$WithStatement",
95
108
  } as const;
96
109
 
110
+ export function isMethodCall(e?: Expression): e is MethodCall {
111
+ return J.isMethodCall(e) || e?.kind === JS.Kind.FunctionCall;
112
+ }
113
+
97
114
  /**
98
115
  * Represents the root of a JavaScript AST (compilation unit).
99
116
  * @example // file.js as AST root
@@ -650,12 +667,11 @@ export namespace JS {
650
667
  * @example data["key"](5, 0, 4)
651
668
  * @example (() => { return 3 + 5 })()
652
669
  */
653
- export interface FunctionCall extends JS, Expression {
670
+ export interface FunctionCall extends JS, MethodCall {
654
671
  readonly kind: typeof Kind.FunctionCall;
655
672
  readonly function?: J.RightPadded<Expression>;
656
673
  readonly typeParameters?: J.Container<Expression>;
657
674
  readonly arguments: J.Container<Expression>;
658
- readonly functionType?: Type.Method;
659
675
  }
660
676
 
661
677
  /**
@@ -901,6 +917,34 @@ export namespace JSX {
901
917
 
902
918
  const KindValues = new Set(Object.values(JS.Kind));
903
919
 
920
+ function javascriptVisitorAdapter<P>(visitor: JavaVisitor<P>): JavaVisitor<P> {
921
+ const adaptedVisitor = new JavaScriptVisitor<P>();
922
+
923
+ // Walk up the prototype chain of the visitor to get all overridden methods
924
+ let proto = Object.getPrototypeOf(visitor);
925
+ while (proto && proto !== JavaVisitor.prototype) {
926
+ Object.getOwnPropertyNames(proto).forEach(name => {
927
+ const descriptor = Object.getOwnPropertyDescriptor(proto, name);
928
+ if (descriptor && typeof descriptor.value === 'function' && name !== 'constructor') {
929
+ // Copy the method, binding it to jsVisitor
930
+ (adaptedVisitor as any)[name] = descriptor.value.bind(adaptedVisitor);
931
+ }
932
+ });
933
+ proto = Object.getPrototypeOf(proto);
934
+ }
935
+
936
+ // Also copy any instance properties
937
+ Object.keys(visitor).forEach(key => {
938
+ if (!(key in adaptedVisitor)) {
939
+ (adaptedVisitor as any)[key] = (visitor as any)[key];
940
+ }
941
+ });
942
+
943
+ return adaptedVisitor;
944
+ }
945
+
946
+ registerJavaExtensionKinds(Object.values(JS.Kind), javascriptVisitorAdapter);
947
+
904
948
  export function isJavaScript(tree: any): tree is JS {
905
949
  return KindValues.has(tree["kind"]);
906
950
  }
@@ -22,13 +22,6 @@ class NonDraftableType {
22
22
  [immerable] = false;
23
23
  }
24
24
 
25
- const builtInTypes = new Set([
26
- 'Array', 'Object', 'Function', 'String', 'Number', 'Boolean',
27
- 'Date', 'RegExp', 'Error', 'Promise', 'Map', 'Set', 'WeakMap',
28
- 'WeakSet', 'Symbol', 'BigInt', 'HTMLElement', 'Document',
29
- 'Window', 'Console', 'JSON', 'Math', 'Reflect', 'Proxy'
30
- ]);
31
-
32
25
  export class JavaScriptTypeMapping {
33
26
  private readonly typeCache: Map<string | number, Type> = new Map();
34
27
  private readonly regExpSymbol: ts.Symbol | undefined;
@@ -121,7 +114,7 @@ export class JavaScriptTypeMapping {
121
114
 
122
115
  primitiveType(node: ts.Node): Type.Primitive {
123
116
  const type = this.type(node);
124
- if (Type.isClass(type) && type.fullyQualifiedName === 'lib.RegExp') {
117
+ if (Type.isClass(type) && type.fullyQualifiedName === 'RegExp') {
125
118
  return Type.Primitive.String;
126
119
  }
127
120
  return Type.isPrimitive(type) ? type : Type.Primitive.None;
@@ -139,7 +132,47 @@ export class JavaScriptTypeMapping {
139
132
  return undefined;
140
133
  }
141
134
 
135
+ /**
136
+ * Helper to create a Type.Method object from common parameters
137
+ */
138
+ private createMethodType(
139
+ signature: ts.Signature,
140
+ node: ts.Node,
141
+ declaringType: Type.FullyQualified,
142
+ name: string,
143
+ declaredFormalTypeNames: string[] = []
144
+ ): Type.Method {
145
+ const returnType = signature.getReturnType();
146
+ const parameters = signature.getParameters();
147
+ const parameterTypes: Type[] = [];
148
+ const parameterNames: string[] = [];
149
+
150
+ for (const param of parameters) {
151
+ parameterNames.push(param.getName());
152
+ const paramType = this.checker.getTypeOfSymbolAtLocation(param, node);
153
+ parameterTypes.push(this.getType(paramType));
154
+ }
155
+
156
+ // Create the Type.Method object
157
+ return Object.assign(new NonDraftableType(), {
158
+ kind: Type.Kind.Method,
159
+ declaringType: declaringType,
160
+ name: name,
161
+ returnType: this.getType(returnType),
162
+ parameterNames: parameterNames,
163
+ parameterTypes: parameterTypes,
164
+ thrownExceptions: [], // JavaScript doesn't have checked exceptions
165
+ annotations: [],
166
+ defaultValue: undefined,
167
+ declaredFormalTypeNames: declaredFormalTypeNames,
168
+ toJSON: function () {
169
+ return Type.signature(this);
170
+ }
171
+ }) as Type.Method;
172
+ }
173
+
142
174
  methodType(node: ts.Node): Type.Method | undefined {
175
+
143
176
  let signature: ts.Signature | undefined;
144
177
  let methodName: string;
145
178
  let declaringType: Type.FullyQualified;
@@ -153,7 +186,68 @@ export class JavaScriptTypeMapping {
153
186
  return undefined;
154
187
  }
155
188
 
156
- const symbol = this.checker.getSymbolAtLocation(node.expression);
189
+ let symbol = this.checker.getSymbolAtLocation(node.expression);
190
+
191
+
192
+ if (!symbol && ts.isPropertyAccessExpression(node.expression)) {
193
+ // For property access expressions where we couldn't get a symbol,
194
+ // try to get the symbol from the signature's declaration
195
+ const declaration = signature?.getDeclaration();
196
+ if (declaration) {
197
+ symbol = this.checker.getSymbolAtLocation(declaration);
198
+ }
199
+
200
+ // If still no symbol but we have a signature, we can proceed with limited info
201
+ if (!symbol && signature) {
202
+ // For cases like util.isArray where the module is 'any' type
203
+ // We'll construct a basic method type from the signature
204
+ methodName = node.expression.name.getText();
205
+
206
+ // When there's no symbol but we have a signature, we need to work harder
207
+ // to find the declaring type. This happens with CommonJS require() calls
208
+ // where the module is typed as 'any' but methods still have signatures
209
+
210
+ // Try to trace back through the AST to find the require() call
211
+ let inferredDeclaringType: Type.FullyQualified | undefined;
212
+ const objExpr = node.expression.expression;
213
+
214
+ if (ts.isIdentifier(objExpr)) {
215
+ // Look for the variable declaration that assigns the require() result
216
+ const objSymbol = this.checker.getSymbolAtLocation(objExpr);
217
+
218
+ if (objSymbol && objSymbol.valueDeclaration) {
219
+ const valueDecl = objSymbol.valueDeclaration;
220
+ if (ts.isVariableDeclaration(valueDecl) && valueDecl.initializer) {
221
+ // Check if it's a require() call
222
+ if (ts.isCallExpression(valueDecl.initializer)) {
223
+ const callExpr = valueDecl.initializer;
224
+ if (ts.isIdentifier(callExpr.expression) &&
225
+ callExpr.expression.getText() === 'require' &&
226
+ callExpr.arguments.length > 0) {
227
+ // Extract the module name from require('module-name')
228
+ const moduleArg = callExpr.arguments[0];
229
+ if (ts.isStringLiteral(moduleArg)) {
230
+ const moduleName = moduleArg.text;
231
+
232
+ inferredDeclaringType = {
233
+ kind: Type.Kind.Class,
234
+ fullyQualifiedName: moduleName
235
+ } as Type.FullyQualified;
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ // Use the inferred type or fall back to unknown
244
+ declaringType = inferredDeclaringType || Type.unknownType as Type.FullyQualified;
245
+
246
+ // Create the method type using the helper
247
+ return this.createMethodType(signature, node, declaringType, methodName);
248
+ }
249
+ }
250
+
157
251
  if (!symbol) {
158
252
  return undefined;
159
253
  }
@@ -201,12 +295,12 @@ export class JavaScriptTypeMapping {
201
295
  if ((mappedType as any).keyword === 'String') {
202
296
  declaringType = {
203
297
  kind: Type.Kind.Class,
204
- fullyQualifiedName: 'lib.String'
298
+ fullyQualifiedName: 'String'
205
299
  } as Type.FullyQualified;
206
300
  } else if ((mappedType as any).keyword === 'Number') {
207
301
  declaringType = {
208
302
  kind: Type.Kind.Class,
209
- fullyQualifiedName: 'lib.Number'
303
+ fullyQualifiedName: 'Number'
210
304
  } as Type.FullyQualified;
211
305
  } else {
212
306
  // Fallback for other types
@@ -220,17 +314,17 @@ export class JavaScriptTypeMapping {
220
314
 
221
315
  // For string methods like 'hello'.split(), ensure we have a proper declaring type for primitives
222
316
  if (!isImport && declaringType === Type.unknownType) {
223
- // If the expression type is a primitive string, use lib.String as declaring type
317
+ // If the expression type is a primitive string, use String as declaring type
224
318
  const typeString = this.checker.typeToString(exprType);
225
319
  if (typeString === 'string' || exprType.flags & ts.TypeFlags.String || exprType.flags & ts.TypeFlags.StringLiteral) {
226
320
  declaringType = {
227
321
  kind: Type.Kind.Class,
228
- fullyQualifiedName: 'lib.String'
322
+ fullyQualifiedName: 'string'
229
323
  } as Type.FullyQualified;
230
324
  } else if (typeString === 'number' || exprType.flags & ts.TypeFlags.Number || exprType.flags & ts.TypeFlags.NumberLiteral) {
231
325
  declaringType = {
232
326
  kind: Type.Kind.Class,
233
- fullyQualifiedName: 'lib.Number'
327
+ fullyQualifiedName: 'number'
234
328
  } as Type.FullyQualified;
235
329
  } else {
236
330
  // Fallback for other primitive types or unknown
@@ -383,34 +477,8 @@ export class JavaScriptTypeMapping {
383
477
  return undefined;
384
478
  }
385
479
 
386
- // Common logic for all method types
387
- const returnType = signature.getReturnType();
388
- const parameters = signature.getParameters();
389
- const parameterTypes: Type[] = [];
390
- const parameterNames: string[] = [];
391
-
392
- for (const param of parameters) {
393
- parameterNames.push(param.getName());
394
- const paramType = this.checker.getTypeOfSymbolAtLocation(param, node);
395
- parameterTypes.push(this.getType(paramType));
396
- }
397
-
398
- // Create the Type.Method object
399
- return Object.assign(new NonDraftableType(), {
400
- kind: Type.Kind.Method,
401
- declaringType: declaringType,
402
- name: methodName,
403
- returnType: this.getType(returnType),
404
- parameterNames: parameterNames,
405
- parameterTypes: parameterTypes,
406
- thrownExceptions: [], // JavaScript doesn't have checked exceptions
407
- annotations: [],
408
- defaultValue: undefined,
409
- declaredFormalTypeNames: declaredFormalTypeNames,
410
- toJSON: function () {
411
- return Type.signature(this);
412
- }
413
- }) as Type.Method;
480
+ // Create the method type using the helper
481
+ return this.createMethodType(signature, node, declaringType, methodName, declaredFormalTypeNames);
414
482
  }
415
483
 
416
484
 
@@ -507,14 +575,9 @@ export class JavaScriptTypeMapping {
507
575
  }
508
576
  }
509
577
 
510
- // If it's just a simple name without dots, check if it's a built-in type
511
- if (!cleanedName.includes('.')) {
512
- if (builtInTypes.has(cleanedName)) {
513
- return `lib.${cleanedName}`;
514
- }
515
- }
516
-
517
- return cleanedName;
578
+ return cleanedName.endsWith('Constructor') ?
579
+ cleanedName.substring(0, cleanedName.length - 'Constructor'.length) :
580
+ cleanedName;
518
581
  }
519
582
 
520
583