Skip to content

Commit 99d073e

Browse files
author
Marc Lipovsky
authored
Merge pull request #57 from marclipovsky/feature/swap-case
Feature/swap case fixes #34
2 parents 2f4034c + 2ce721c commit 99d073e

File tree

7 files changed

+341
-111
lines changed

7 files changed

+341
-111
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,16 @@ jobs:
1919
runs-on: ${{ matrix.os }}
2020
steps:
2121
- name: Checkout
22-
uses: actions/checkout@v2
23-
- name: Setup Node.js
24-
uses: actions/setup-node@v1
22+
uses: actions/checkout@v4
2523
with:
26-
node-version: 18.13.0
24+
ref: ${{ github.ref }}
25+
- name: Setup Node.js
26+
uses: actions/setup-node@v4
2727
- name: Install dependencies
2828
run: npm install
2929
- name: Build package
3030
run: npm run build
3131
- name: Run headless test
32-
uses: GabrielBB/xvfb-action@v1.0
32+
uses: coactions/setup-xvfb@v1
3333
with:
3434
run: npm test

.github/workflows/publish-extension.yml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,33 @@ name: "Publish to Marketplace"
33
on:
44
workflow_run:
55
workflows: ["CI"]
6-
types:
7-
- completed
6+
types: [completed]
7+
branches: [master]
88

99
jobs:
1010
cd:
11-
if: >
12-
${{ github.event.workflow_run.conclusion == 'success' &&
13-
github.event.workflow_run.head_branch == 'master' }}
11+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
1412
runs-on: ubuntu-latest
1513
permissions:
1614
contents: write
1715
steps:
1816
- name: Checkout to branch
1917
uses: actions/checkout@v4
18+
with:
19+
ref: ${{ github.ref }}
2020

2121
- name: Setup node.js
2222
uses: actions/setup-node@v4
23-
with:
24-
node-version: 20
2523

2624
- name: "Bump version"
27-
uses: 'phips28/gh-action-bump-version@master'
25+
uses: "phips28/gh-action-bump-version@master"
2826
env:
2927
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
3028
with:
31-
minor-wording: 'MINOR'
32-
major-wording: 'MAJOR'
33-
patch-wording: 'PATCH,FIX'
34-
rc-wording: 'RELEASE'
29+
minor-wording: "MINOR"
30+
major-wording: "MAJOR"
31+
patch-wording: "PATCH,FIX"
32+
rc-wording: "RELEASE"
3533

3634
- name: Install packages
3735
run: npm ci

content.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,11 @@ abc中文💖
4343
Hello, World!
4444
12345!@#$%
4545
Test123!
46+
'She said, "Hello"'
47+
"My name's Minalike"
48+
"He said, 'It's a trap!'"
49+
'She exclaimed, \"Wow!\"'
50+
"'Double' and 'single' quotes"
51+
No quotes at all
52+
'It's'
53+
"My name's %20 Minalike!"

package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@
194194
"title": "Random Case",
195195
"category": "String Manipulation",
196196
"command": "string-manipulation.randomCase"
197+
},
198+
{
199+
"title": "Swap Quotes",
200+
"category": "String Manipulation",
201+
"command": "string-manipulation.swapQuotes"
197202
}
198203
],
199204
"submenus": [
@@ -329,6 +334,10 @@
329334
{
330335
"command": "string-manipulation.randomCase",
331336
"group": "7_modification"
337+
},
338+
{
339+
"command": "string-manipulation.swapQuotes",
340+
"group": "7_modification"
332341
}
333342
]
334343
}

src/commands.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vscode from "vscode";
22
import * as underscore from "underscore.string";
3+
import { swapQuotes } from "./commands/swap_quotes";
34
const apStyleTitleCase = require("ap-style-title-case");
45
const chicagoStyleTitleCase = require("chicago-capitalize");
56
const slugify = require("@sindresorhus/slugify");
@@ -39,6 +40,14 @@ const randomCase = (input: string): string => {
3940
return result;
4041
};
4142

43+
const snake = (str: string) =>
44+
underscore
45+
.underscored(str)
46+
.replace(/([A-Z])[^A-Z]/g, " $1")
47+
.replace(/[^a-z0-9]+/gi, " ")
48+
.trim()
49+
.replace(/\s/gi, "_");
50+
4251
export type StringFunction = (
4352
str: string,
4453
multiselectData?: MultiSelectData
@@ -53,7 +62,7 @@ const commandNameFunctionMap: { [key: string]: CommandFunction } = {
5362
classify: defaultFunction("classify"),
5463
clean: defaultFunction("clean"),
5564
cleanDiacritics: defaultFunction("cleanDiacritics"),
56-
underscored: defaultFunction("underscored"),
65+
underscored: snake,
5766
dasherize: defaultFunction("dasherize"),
5867
humanize: defaultFunction("humanize"),
5968
reverse: defaultFunction("reverse"),
@@ -64,21 +73,8 @@ const commandNameFunctionMap: { [key: string]: CommandFunction } = {
6473
underscore.camelize(/[a-z]/.test(str) ? str : str.toLowerCase()),
6574
slugify: slugify,
6675
swapCase: defaultFunction("swapCase"),
67-
snake: (str: string) =>
68-
underscore
69-
.underscored(str)
70-
.replace(/([A-Z])[^A-Z]/g, " $1")
71-
.replace(/[^a-z]+/gi, " ")
72-
.trim()
73-
.replace(/\s/gi, "_"),
74-
screamingSnake: (str: string) =>
75-
underscore
76-
.underscored(str)
77-
.replace(/([A-Z])[^A-Z]/g, " $1")
78-
.replace(/[^a-z]+/gi, " ")
79-
.trim()
80-
.replace(/\s/gi, "_")
81-
.toUpperCase(),
76+
snake,
77+
screamingSnake: (str: string) => snake(str).toUpperCase(),
8278
titleizeApStyle: apStyleTitleCase,
8379
titleizeChicagoStyle: chicagoStyleTitleCase,
8480
truncate: (n: number) => defaultFunction("truncate", n),
@@ -101,6 +97,7 @@ const commandNameFunctionMap: { [key: string]: CommandFunction } = {
10197
.map((x) => `\\u${x.charCodeAt(0).toString(16).padStart(4, "0")}`)
10298
.join(""),
10399
randomCase,
100+
swapQuotes,
104101
};
105102

106103
const numberFunctionNames = [

src/commands/swap_quotes.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export const swapQuotes = (str: string): string => {
2+
const singleQuote = "'";
3+
const doubleQuote = '"';
4+
5+
// Check if the string is at least two characters and starts and ends with the same quote
6+
if (str.length < 2) {
7+
return str; // Return as is if not properly quoted
8+
}
9+
10+
const firstChar = str[0];
11+
const lastChar = str[str.length - 1];
12+
13+
if (
14+
(firstChar !== singleQuote && firstChar !== doubleQuote) ||
15+
firstChar !== lastChar
16+
) {
17+
// Not properly quoted, return as is
18+
return str;
19+
}
20+
21+
const originalQuote = firstChar;
22+
const newQuote = originalQuote === singleQuote ? doubleQuote : singleQuote;
23+
let content = str.slice(1, -1);
24+
25+
// Swap inner quotes
26+
content = content.replace(/['"]/g, (match, offset) => {
27+
// Determine if the quote is part of an apostrophe
28+
const prevChar = content[offset - 1];
29+
const nextChar = content[offset + 1];
30+
const isApostrophe =
31+
match === "'" &&
32+
/[a-zA-Z]/.test(prevChar || "") &&
33+
/[a-zA-Z]/.test(nextChar || "");
34+
35+
if (isApostrophe) {
36+
// Handle apostrophe based on the desired output
37+
if (newQuote === singleQuote) {
38+
// Escape apostrophe when outer quote is single quote
39+
return "\\'";
40+
} else {
41+
// Keep apostrophe as is when outer quote is double quote
42+
return match;
43+
}
44+
} else {
45+
// Swap the quote
46+
return match === originalQuote ? newQuote : originalQuote;
47+
}
48+
});
49+
50+
// Return the new string with swapped quotes
51+
return newQuote + content + newQuote;
52+
};

0 commit comments

Comments
 (0)