autopair 1.2.1 → 1.2.2

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.
@@ -0,0 +1,192 @@
1
+ describe('autopair', () => {
2
+ it('wraps selected text in parentheses when "(" is typed', () => {
3
+ cy.visit('/index.html');
4
+
5
+ // Type some text
6
+ cy.get('textarea').type('hello');
7
+
8
+ // Select all text
9
+ cy.get('textarea').then($el => {
10
+ $el[0].selectionStart = 0;
11
+ $el[0].selectionEnd = $el.val().length;
12
+ });
13
+
14
+ // Type "(" to wrap selection
15
+ cy.get('textarea').type('(');
16
+
17
+ // Check result
18
+ cy.get('textarea').should('have.value', '(hello)');
19
+ });
20
+
21
+ it('types through closing character', () => {
22
+ cy.visit('/index.html');
23
+
24
+ // Type a pair
25
+ cy.get('textarea').type('()');
26
+
27
+ // Move cursor between the parentheses
28
+ cy.get('textarea').then($el => {
29
+ $el[0].selectionStart = 1;
30
+ $el[0].selectionEnd = 1;
31
+ });
32
+
33
+ // Type ")" to test typethrough
34
+ cy.get('textarea').type(')');
35
+
36
+ // Value should be unchanged, cursor moves past
37
+ cy.get('textarea').then($el => {
38
+ expect($el.val()).to.eq('()');
39
+ expect($el[0].selectionStart).to.eq(2); // cursor after )
40
+ expect($el[0].selectionEnd).to.eq(2);
41
+ });
42
+ });
43
+
44
+ it('atomically deletes a pair', () => {
45
+ cy.visit('/index.html');
46
+
47
+ // Type a pair
48
+ cy.get('textarea').type('()');
49
+
50
+ // Move cursor between the parentheses
51
+ cy.get('textarea').then($el => {
52
+ $el[0].selectionStart = 1;
53
+ $el[0].selectionEnd = 1;
54
+ });
55
+
56
+ // Press Backspace
57
+ cy.get('textarea').type('{backspace}');
58
+
59
+ // Both characters should be deleted
60
+ cy.get('textarea').should('have.value', '');
61
+ });
62
+
63
+ it('automatically inserts closing parenthesis when "(" is typed', () => {
64
+ cy.visit('/index.html');
65
+
66
+ // Type opening parenthesis
67
+ cy.get('textarea').type('(');
68
+
69
+ // Should insert closing parenthesis and place cursor between
70
+ cy.get('textarea').then($el => {
71
+ expect($el.val()).to.eq('()');
72
+ expect($el[0].selectionStart).to.eq(1);
73
+ expect($el[0].selectionEnd).to.eq(1);
74
+ });
75
+ });
76
+
77
+ it('autopairs before a whitelisted character', () => {
78
+ cy.visit('/index.html');
79
+
80
+ // Type a semicolon
81
+ cy.get('textarea').type(';');
82
+
83
+ // Move cursor before the semicolon
84
+ cy.get('textarea').then($el => {
85
+ $el[0].selectionStart = 0;
86
+ $el[0].selectionEnd = 0;
87
+ });
88
+
89
+ // Type "("
90
+ cy.get('textarea').type('(');
91
+
92
+ // Should autopair
93
+ cy.get('textarea').then($el => {
94
+ expect($el.val()).to.eq('();');
95
+ expect($el[0].selectionStart).to.eq(1);
96
+ });
97
+ });
98
+
99
+ it('does not autopair before a non-whitelisted character', () => {
100
+ cy.visit('/index.html');
101
+
102
+ // Type a period
103
+ cy.get('textarea').type('.');
104
+
105
+ // Move cursor before the period
106
+ cy.get('textarea').then($el => {
107
+ $el[0].selectionStart = 0;
108
+ $el[0].selectionEnd = 0;
109
+ });
110
+
111
+ // Type "("
112
+ cy.get('textarea').type('(');
113
+
114
+ // Should NOT autopair
115
+ cy.get('textarea').then($el => {
116
+ expect($el.val()).to.eq('(.');
117
+ expect($el[0].selectionStart).to.eq(1);
118
+ });
119
+ });
120
+
121
+ it('autopairs multiple opening parentheses correctly', () => {
122
+ cy.visit('/index.html');
123
+
124
+ // Type three opening parentheses
125
+ cy.get('textarea').type('(((');
126
+
127
+ // Should result in three closing parentheses as well
128
+ cy.get('textarea').then($el => {
129
+ expect($el.val()).to.eq('((()))');
130
+ expect($el[0].selectionStart).to.eq(3); // cursor inside the innermost pair
131
+ });
132
+ });
133
+
134
+ it('does not autopair symmetric characters after an existing pair', () => {
135
+ cy.visit('/index.html');
136
+
137
+ // Type a single quote
138
+ cy.get('textarea').type("'");
139
+
140
+ // Should autopair to ''
141
+ cy.get('textarea').then($el => {
142
+ expect($el.val()).to.eq("''");
143
+ expect($el[0].selectionStart).to.eq(1); // cursor inside
144
+ });
145
+
146
+ // Move cursor to the end
147
+ cy.get('textarea').then($el => {
148
+ $el[0].selectionStart = $el.val().length;
149
+ $el[0].selectionEnd = $el.val().length;
150
+ });
151
+
152
+ // Type another single quote
153
+ cy.get('textarea').type("'");
154
+
155
+ // Should NOT autopair again
156
+ cy.get('textarea').then($el => {
157
+ expect($el.val()).to.eq("'''");
158
+ expect($el[0].selectionStart).to.eq(3); // cursor after last '
159
+ });
160
+ });
161
+
162
+ it('handles custom pairing correctly', () => {
163
+ cy.visit('/index.html');
164
+
165
+ // Inject autopair immediately
166
+ cy.document().then(doc => {
167
+ const script = doc.createElement('script');
168
+ script.type = 'module';
169
+ script.textContent = `
170
+ import autopair from './autopair.js';
171
+ autopair(document.querySelector('textarea'), {
172
+ '(': ')',
173
+ '[': ']',
174
+ '{': '}',
175
+ "'": "'",
176
+ '"': '"',
177
+ '<': '>'
178
+ });
179
+ `;
180
+ doc.body.appendChild(script);
181
+ });
182
+
183
+ // Type <
184
+ cy.get('textarea').type('<');
185
+
186
+ // Should autopair to <>
187
+ cy.get('textarea').then($el => {
188
+ expect($el.val()).to.eq('<>');
189
+ expect($el[0].selectionStart).to.eq(1);
190
+ });
191
+ });
192
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "Using fixtures to represent data",
3
+ "email": "hello@cypress.io",
4
+ "body": "Fixtures are a great way to mock data for responses to routes"
5
+ }
@@ -0,0 +1,25 @@
1
+ // ***********************************************
2
+ // This example commands.js shows you how to
3
+ // create various custom commands and overwrite
4
+ // existing commands.
5
+ //
6
+ // For more comprehensive examples of custom
7
+ // commands please read more here:
8
+ // https://on.cypress.io/custom-commands
9
+ // ***********************************************
10
+ //
11
+ //
12
+ // -- This is a parent command --
13
+ // Cypress.Commands.add('login', (email, password) => { ... })
14
+ //
15
+ //
16
+ // -- This is a child command --
17
+ // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18
+ //
19
+ //
20
+ // -- This is a dual command --
21
+ // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22
+ //
23
+ //
24
+ // -- This will overwrite an existing command --
25
+ // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
@@ -0,0 +1,17 @@
1
+ // ***********************************************************
2
+ // This example support/e2e.js is processed and
3
+ // loaded automatically before your test files.
4
+ //
5
+ // This is a great place to put global configuration and
6
+ // behavior that modifies Cypress.
7
+ //
8
+ // You can change the location of this file or turn off
9
+ // automatically serving support files with the
10
+ // 'supportFile' configuration option.
11
+ //
12
+ // You can read more here:
13
+ // https://on.cypress.io/configuration
14
+ // ***********************************************************
15
+
16
+ // Import commands.js using ES2015 syntax:
17
+ import './commands'
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "cypress";
2
+
3
+ export default defineConfig({
4
+ e2e: {
5
+ setupNodeEvents(on, config) {
6
+ // implement node event listeners here
7
+ },
8
+ },
9
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autopair",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Automatically closes parentheses and similar characters.",
5
5
  "main": "src/autopair.js",
6
6
  "author": "Dennis Hackethal <engineering@dennishackethal.com>",
@@ -34,5 +34,11 @@
34
34
  "input",
35
35
  "javascript",
36
36
  "web"
37
- ]
37
+ ],
38
+ "devDependencies": {
39
+ "cypress": "^15.9.0"
40
+ },
41
+ "scripts": {
42
+ "test": "npx cypress run"
43
+ }
38
44
  }
package/src/autopair.js CHANGED
@@ -41,9 +41,6 @@ export default function autopair(textarea, pairs = {
41
41
  const closing = pairs[evt.key];
42
42
  if (!closing) return;
43
43
 
44
- const isWordChar = /[\w]/;
45
- const punctuation = /[;,.})\]]/;
46
-
47
44
  // Wrap selection if present
48
45
  if (start !== end) {
49
46
  evt.preventDefault();
@@ -55,28 +52,15 @@ export default function autopair(textarea, pairs = {
55
52
  return;
56
53
  }
57
54
 
55
+ const nextCharWhitelist = /[\s;})\]]/;
58
56
  const nextChar = value[end] || '';
59
57
  const prevChar = value[start - 1] || '';
60
-
61
58
  const insidePair = closing === nextChar;
62
- const safeNext = !isWordChar.test(nextChar) || punctuation.test(nextChar);
59
+ const safeNext = nextChar === '' || nextCharWhitelist.test(nextChar);
63
60
  const isSymmetric = evt.key === closing;
64
61
 
65
62
  // Autoclose only when allowed
66
- if (
67
- !insidePair &&
68
- (
69
- !safeNext ||
70
- (
71
- isSymmetric &&
72
- start === end &&
73
- (
74
- isWordChar.test(prevChar) || // end of word
75
- prevChar === evt.key // repeated quote
76
- )
77
- )
78
- )
79
- ) {
63
+ if (!insidePair && (!safeNext || (isSymmetric && start === end && prevChar === evt.key))) {
80
64
  return;
81
65
  }
82
66