diff --git a/README.md b/README.md index 8b23173..a9488f3 100644 --- a/README.md +++ b/README.md @@ -139,9 +139,9 @@ There are two cases, described here, where it does more than replace the TypeScr ### ASI (automatic semicolon insertion) -To guard against [ASI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#automatic_semicolon_insertion) issues in the output, `ts-blank-space` will add `;` to the end of type-only statements. +To guard against [ASI](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#automatic_semicolon_insertion) issues in the output, `ts-blank-space` will add `;` to the end of type-only statements, and when removing a leading type annotation could introduce an ASI hazard. -Example input: +#### Example one - type-only statement ```typescript @@ -159,6 +159,26 @@ statementWithNoSemiColon ("not calling above statement"); ``` +#### Example two - computed class fields/methods + + +```typescript +class C { + field = 1/* no ; */ + public ["computed field not accessing above"] = 2 +} +``` + +becomes: + + +```javascript +class C { + field = 1/* no ; */ + ; ["computed field not accessing above"] = 2 +} +``` + ### Arrow function type annotations that introduce a new line If the type annotations around an arrow function's parameters introduce a new line then only replacing them with blank space can be incorrect. Therefore, in addition to removing the type annotation, the `(` or `)` surrounding the function parameters may also be moved. diff --git a/package-lock.json b/package-lock.json index da0e49e..272e6c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ts-blank-space", - "version": "0.4.1", + "version": "0.4.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ts-blank-space", - "version": "0.4.1", + "version": "0.4.3", "license": "Apache-2.0", "dependencies": { "typescript": "5.1.6 - 5.6.x" diff --git a/package.json b/package.json index c8ac604..fb0cffc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ts-blank-space", "description": "A small, fast, pure JavaScript type-stripper that uses the official TypeScript parser.", - "version": "0.4.2", + "version": "0.4.3", "license": "Apache-2.0", "homepage": "https://bloomberg.github.io/ts-blank-space", "contributors": [ diff --git a/src/index.ts b/src/index.ts index f1a65b8..7a13408 100644 --- a/src/index.ts +++ b/src/index.ts @@ -228,7 +228,7 @@ function visitClassLike(node: ts.ClassLikeDeclaration): VisitResult { blankStatement(node); return VISIT_BLANKED; } - visitModifiers(node.modifiers); + visitModifiers(node.modifiers, /* addSemi:*/ false); } // ... @@ -280,12 +280,17 @@ function isRemovedModifier(kind: ts.SyntaxKind): kind is (typeof classElementMod return classElementModifiersToRemove.has(kind as never); } -function visitModifiers(modifiers: ArrayLike): void { +function visitModifiers(modifiers: ArrayLike, addSemi: boolean): void { for (let i = 0; i < modifiers.length; i++) { const modifier = modifiers[i]; const kind = modifier.kind; if (isRemovedModifier(kind)) { - blankExact(modifier); + if (addSemi && i === 0) { + str.blankButStartWithSemi(modifier.getStart(ast), modifier.end); + addSemi = false; + } else { + blankExact(modifier); + } continue; } else if (kind === SK.Decorator) { visitor(modifier); @@ -328,7 +333,7 @@ function visitPropertyDeclaration(node: ts.PropertyDeclaration): VisitResult { blankStatement(node); return VISIT_BLANKED; } - visitModifiers(node.modifiers); + visitModifiers(node.modifiers, /* addSemi */ node.name.kind === SK.ComputedPropertyName); } node.exclamationToken && blankExact(node.exclamationToken); node.questionToken && blankExact(node.questionToken); @@ -394,12 +399,13 @@ function visitFunctionLikeDeclaration(node: ts.FunctionLikeDeclaration, kind: ts return VISIT_BLANKED; } + const nodeName = node.name; if (node.modifiers) { - visitModifiers(node.modifiers); + visitModifiers(node.modifiers, /* addSemi */ !!nodeName && nodeName.kind === SK.ComputedPropertyName); } - if (node.name) { - visitor(node.name); + if (nodeName) { + visitor(nodeName); } let moveOpenParen = false; diff --git a/tests/fixture/cases/asi.ts b/tests/fixture/cases/asi.ts index b60823e..663db75 100644 --- a/tests/fixture/cases/asi.ts +++ b/tests/fixture/cases/asi.ts @@ -78,4 +78,16 @@ class ASI { ((() => { 1/*trailing*/})(), 1) + 1 as number/*trailing*/ (1); } + g = 2/*missing ; */ + public ["computed-field"] = 1 +// ;^^^^^ + h = 3/*missing ; */ + public ["computed-method"]() {} +// ;^^^^^ +} + +class NoASI { + f = 1/*missing ; */ + static readonly ["computed-field"] = 1 +// ^^^^^^^^ } diff --git a/tests/fixture/output/asi.js b/tests/fixture/output/asi.js index 142c319..932b677 100644 --- a/tests/fixture/output/asi.js +++ b/tests/fixture/output/asi.js @@ -78,4 +78,16 @@ class ASI { ((() => { 1/*trailing*/})(), 1) + 1; /*trailing*/ (1); } + g = 2/*missing ; */ + ; ["computed-field"] = 1 +// ;^^^^^ + h = 3/*missing ; */ + ; ["computed-method"]() {} +// ;^^^^^ +} + +class NoASI { + f = 1/*missing ; */ + static ["computed-field"] = 1 +// ^^^^^^^^ }