├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── completions ├── apis.json ├── components.json └── navigator.json ├── demo.gif ├── lib ├── autocomplete.js ├── helper │ ├── collect.js │ └── units.js ├── modules │ ├── api.js │ └── component.js └── provider.js ├── package.json └── src ├── autocomplete.js ├── helper ├── collect.js └── units.js ├── modules ├── api.js └── component.js └── provider.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | atom-file-watchers-config.json 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 - First Release 2 | * Every feature added 3 | * Every bug fixed 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # atom-react-native-autocomplete (The project stop maintenance) 2 | 3 | React-Native autocompletion for Atom text editor! Only supports the suffix for `.js` and `.jsx` files. 4 | 5 | ## Install 6 | Using `apm`: 7 | 8 | ``` 9 | apm install atom-react-native-autocomplete 10 | ``` 11 | 12 | Or search for `atom-react-native-autocomplete` in Atom settings view.
13 | 14 | Potentially wait for further installs (just `apm install language-javascript-jsx` if its not there already).
15 | 16 | ## Options 17 | - #### prefix 18 | AutoComplete feature the string parsing rules 19 | 20 | *Default:* `React` 21 | 22 |
23 | ![demo](http://7oxfk1.com1.z0.glb.clouddn.com/atom-react-native-autocomplete-demo.gif) 24 | -------------------------------------------------------------------------------- /completions/apis.json: -------------------------------------------------------------------------------- 1 | { 2 | "React": [ 3 | { 4 | "text": "ActionSheetIOS", 5 | "type": "class", 6 | "rightLabelHTML": "react-native" 7 | }, 8 | { 9 | "text": "Alert", 10 | "type": "class", 11 | "rightLabelHTML": "react-native" 12 | }, 13 | { 14 | "text": "AlertIOS", 15 | "type": "class", 16 | "rightLabelHTML": "react-native" 17 | }, 18 | { 19 | "text": "Animated", 20 | "type": "class", 21 | "rightLabelHTML": "react-native" 22 | }, 23 | { 24 | "text": "AppRegistry", 25 | "type": "class", 26 | "rightLabelHTML": "react-native" 27 | }, 28 | { 29 | "text": "AppState", 30 | "type": "class", 31 | "rightLabelHTML": "react-native" 32 | }, 33 | { 34 | "text": "AppStateIOS", 35 | "type": "class", 36 | "rightLabelHTML": "react-native" 37 | }, 38 | { 39 | "text": "AsyncStorage", 40 | "type": "class", 41 | "rightLabelHTML": "react-native" 42 | }, 43 | { 44 | "text": "BackAndroid", 45 | "type": "class", 46 | "rightLabelHTML": "react-native" 47 | }, 48 | { 49 | "text": "CameraRoll", 50 | "type": "class", 51 | "rightLabelHTML": "react-native" 52 | }, 53 | { 54 | "text": "Clipboard", 55 | "type": "class", 56 | "rightLabelHTML": "react-native" 57 | }, 58 | { 59 | "text": "DatePickerAndroid", 60 | "type": "class", 61 | "rightLabelHTML": "react-native" 62 | }, 63 | { 64 | "text": "Dimensions", 65 | "type": "class", 66 | "rightLabelHTML": "react-native" 67 | }, 68 | { 69 | "text": "IntentAndroid", 70 | "type": "class", 71 | "rightLabelHTML": "react-native" 72 | }, 73 | { 74 | "text": "InteractionManager", 75 | "type": "class", 76 | "rightLabelHTML": "react-native" 77 | }, 78 | { 79 | "text": "LayoutAnimation", 80 | "type": "class", 81 | "rightLabelHTML": "react-native" 82 | }, 83 | { 84 | "text": "Linking", 85 | "type": "class", 86 | "rightLabelHTML": "react-native" 87 | }, 88 | { 89 | "text": "LinkingIOS", 90 | "type": "class", 91 | "rightLabelHTML": "react-native" 92 | }, 93 | { 94 | "text": "NativeMethodsMixin", 95 | "type": "class", 96 | "rightLabelHTML": "react-native" 97 | }, 98 | { 99 | "text": "NetInfo", 100 | "type": "class", 101 | "rightLabelHTML": "react-native" 102 | }, 103 | { 104 | "text": "PanResponder", 105 | "type": "class", 106 | "rightLabelHTML": "react-native" 107 | }, 108 | { 109 | "text": "PixelRatio", 110 | "type": "class", 111 | "rightLabelHTML": "react-native" 112 | }, 113 | { 114 | "text": "Platform", 115 | "type": "property", 116 | "rightLabelHTML": "react-native" 117 | }, 118 | { 119 | "text": "PushNotificationIOS", 120 | "type": "class", 121 | "rightLabelHTML": "react-native" 122 | }, 123 | { 124 | "text": "StatusBarIOS", 125 | "type": "class", 126 | "rightLabelHTML": "react-native" 127 | }, 128 | { 129 | "text": "StyleSheet", 130 | "type": "class", 131 | "rightLabelHTML": "react-native" 132 | }, 133 | { 134 | "text": "TimePickerAndroid", 135 | "type": "class", 136 | "rightLabelHTML": "react-native" 137 | }, 138 | { 139 | "text": "ToastAndroid", 140 | "type": "class", 141 | "rightLabelHTML": "react-native" 142 | }, 143 | { 144 | "text": "Vibration", 145 | "type": "class", 146 | "rightLabelHTML": "react-native" 147 | }, 148 | { 149 | "text": "VibrationIOS", 150 | "type": "class", 151 | "rightLabelHTML": "react-native" 152 | } 153 | ], 154 | "Platform": [ 155 | { 156 | "text": "OS", 157 | "type": "property" 158 | }, 159 | { 160 | "text": "Version", 161 | "type": "property" 162 | } 163 | ], 164 | "Dimensions": [ 165 | { 166 | "name": "get", 167 | "snippet": "get(${1:dim})", 168 | "type": "method", 169 | "description": "Initial dimensions are set before runApplication is called so they shouldbe avai", 170 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/dimensions.html#get" 171 | }, 172 | { 173 | "name": "set", 174 | "snippet": "set(${1:dims})", 175 | "type": "method", 176 | "description": "This should only be called from native code by sending thedidUpdateDimensions ev", 177 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/dimensions.html#set" 178 | } 179 | ], 180 | "BackAndroid": [ 181 | { 182 | "name": "addEventListener", 183 | "snippet": "addEventListener(${1:eventName}, ${2:handler})", 184 | "type": "method", 185 | "description": " ", 186 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/backandroid.html#addeventlistener" 187 | }, 188 | { 189 | "name": "exitApp", 190 | "snippet": "exitApp()", 191 | "type": "method", 192 | "description": " ", 193 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/backandroid.html#exitapp" 194 | }, 195 | { 196 | "name": "removeEventListener", 197 | "snippet": "removeEventListener(${1:eventName}, ${2:handler})", 198 | "type": "method", 199 | "description": " ", 200 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/backandroid.html#removeeventlistener" 201 | } 202 | ], 203 | "CameraRoll": [ 204 | { 205 | "name": "getPhotos", 206 | "snippet": "getPhotos(${1:params})", 207 | "type": "method", 208 | "description": "Returns a Promise with photo identifier objects from the local cameraroll of the", 209 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/cameraroll.html#getphotos" 210 | }, 211 | { 212 | "name": "saveImageWithTag", 213 | "snippet": "saveImageWithTag(${1:tag})", 214 | "type": "method", 215 | "description": "Saves the image to the camera roll / gallery.", 216 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/cameraroll.html#saveimagewithtag" 217 | } 218 | ], 219 | "VibrationIOS": [ 220 | { 221 | "name": "vibrate", 222 | "snippet": "vibrate()", 223 | "type": "method", 224 | "description": "@deprecated", 225 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/vibrationios.html#vibrate" 226 | } 227 | ], 228 | "Vibration": [ 229 | { 230 | "name": "cancel", 231 | "snippet": "cancel()", 232 | "type": "method", 233 | "description": "Stop vibration", 234 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/vibration.html#cancel" 235 | }, 236 | { 237 | "name": "vibrate", 238 | "snippet": "vibrate(${1:pattern}, ${2:repeat})", 239 | "type": "method", 240 | "description": " ", 241 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/vibration.html#vibrate" 242 | } 243 | ], 244 | "TimePickerAndroid": [ 245 | { 246 | "name": "dismissedAction", 247 | "snippet": "dismissedAction()", 248 | "type": "method", 249 | "description": "The dialog has been dismissed.", 250 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/timepickerandroid.html#dismissedaction" 251 | }, 252 | { 253 | "name": "open", 254 | "snippet": "open(${1:options})", 255 | "type": "method", 256 | "description": "Opens the standard Android time picker dialog.", 257 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/timepickerandroid.html#open" 258 | }, 259 | { 260 | "name": "timeSetAction", 261 | "snippet": "timeSetAction()", 262 | "type": "method", 263 | "description": "A time has been selected.", 264 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/timepickerandroid.html#timesetaction" 265 | } 266 | ], 267 | "AsyncStorage": [ 268 | { 269 | "name": "clear", 270 | "snippet": "clear(${1:callback?})", 271 | "type": "method", 272 | "description": "Erases all AsyncStorage for all clients, libraries, etc. You probablydon't", 273 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#clear" 274 | }, 275 | { 276 | "name": "flushGetRequests", 277 | "snippet": "flushGetRequests()", 278 | "type": "method", 279 | "description": "Flushes any pending requests using a single multiget", 280 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#flushgetrequests" 281 | }, 282 | { 283 | "name": "getAllKeys", 284 | "snippet": "getAllKeys(${1:callback?})", 285 | "type": "method", 286 | "description": "Gets all keys known to the app, for all callers, libraries, etc. Returns a Promi", 287 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#getallkeys" 288 | }, 289 | { 290 | "name": "getItem", 291 | "snippet": "getItem(${1:key}, ${2:callback?})", 292 | "type": "method", 293 | "description": "Fetches key and passes the result to callback, along with an Error ifthere is an", 294 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#getitem" 295 | }, 296 | { 297 | "name": "mergeItem", 298 | "snippet": "mergeItem(${1:key}, ${2:value}, ${3:callback?})", 299 | "type": "method", 300 | "description": "Merges existing value with input value, assuming they are stringified json.Retur", 301 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#mergeitem" 302 | }, 303 | { 304 | "name": "multiGet", 305 | "snippet": "multiGet(${1:keys}, ${2:callback?})", 306 | "type": "method", 307 | "description": "multiGet invokes callback with an array of key-value pair arrays thatmatches the", 308 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#multiget" 309 | }, 310 | { 311 | "name": "multiMerge", 312 | "snippet": "multiMerge(${1:keyValuePairs}, ${2:callback?})", 313 | "type": "method", 314 | "description": "Merges existing values with input values, assuming they are stringifiedjson. Ret", 315 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#multimerge" 316 | }, 317 | { 318 | "name": "multiRemove", 319 | "snippet": "multiRemove(${1:keys}, ${2:callback?})", 320 | "type": "method", 321 | "description": "Delete all the keys in the keys array. Returns a Promise object.", 322 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#multiremove" 323 | }, 324 | { 325 | "name": "multiSet", 326 | "snippet": "multiSet(${1:keyValuePairs}, ${2:callback?})", 327 | "type": "method", 328 | "description": "multiSet and multiMerge take arrays of key-value array pairs that matchthe outpu", 329 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#multiset" 330 | }, 331 | { 332 | "name": "removeItem", 333 | "snippet": "removeItem(${1:key}, ${2:callback?})", 334 | "type": "method", 335 | "description": "Returns a Promise object.", 336 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#removeitem" 337 | }, 338 | { 339 | "name": "setItem", 340 | "snippet": "setItem(${1:key}, ${2:value}, ${3:callback?})", 341 | "type": "method", 342 | "description": "Sets value for key and calls callback on completion, along with anError if there", 343 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/asyncstorage.html#setitem" 344 | } 345 | ], 346 | "Linking": [ 347 | { 348 | "name": "addEventListener", 349 | "snippet": "addEventListener(${1:type}, ${2:handler})", 350 | "type": "method", 351 | "description": "Add a handler to Linking changes by listening to the url event typeand providing", 352 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linking.html#addeventlistener" 353 | }, 354 | { 355 | "name": "canOpenURL", 356 | "snippet": "canOpenURL(${1:url})", 357 | "type": "method", 358 | "description": "Determine whether or not an installed app can handle a given URL.", 359 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linking.html#canopenurl" 360 | }, 361 | { 362 | "name": "getInitialURL", 363 | "snippet": "getInitialURL()", 364 | "type": "method", 365 | "description": "If the app launch was triggered by an app link with,it will give the link url, o", 366 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linking.html#getinitialurl" 367 | }, 368 | { 369 | "name": "openURL", 370 | "snippet": "openURL(${1:url})", 371 | "type": "method", 372 | "description": "Try to open the given url with any of the installed apps.", 373 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linking.html#openurl" 374 | }, 375 | { 376 | "name": "removeEventListener", 377 | "snippet": "removeEventListener(${1:type}, ${2:handler})", 378 | "type": "method", 379 | "description": "Remove a handler by passing the url event type and the handler", 380 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linking.html#removeeventlistener" 381 | } 382 | ], 383 | "Clipboard": [ 384 | { 385 | "name": "getString", 386 | "snippet": "getString()", 387 | "type": "method", 388 | "description": "Get content of string type, this method returns a Promise, so you can use follow", 389 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/clipboard.html#getstring" 390 | }, 391 | { 392 | "name": "setString", 393 | "snippet": "setString(${1:content})", 394 | "type": "method", 395 | "description": "Set content of string type. You can use following code to set clipboard content", 396 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/clipboard.html#setstring" 397 | } 398 | ], 399 | "NativeMethodsMixin": [ 400 | { 401 | "name": "blur", 402 | "snippet": "blur()", 403 | "type": "method", 404 | "description": "Removes focus from an input or view. This is the opposite of focus().", 405 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/nativemethodsmixin.html#blur" 406 | }, 407 | { 408 | "name": "focus", 409 | "snippet": "focus()", 410 | "type": "method", 411 | "description": "Requests focus for the given input or view. The exact behavior triggeredwill dep", 412 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/nativemethodsmixin.html#focus" 413 | }, 414 | { 415 | "name": "measure", 416 | "snippet": "measure(${1:callback})", 417 | "type": "method", 418 | "description": "Determines the location on screen, width, and height of the given view andreturn", 419 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/nativemethodsmixin.html#measure" 420 | }, 421 | { 422 | "name": "measureInWindow", 423 | "snippet": "measureInWindow(${1:callback})", 424 | "type": "method", 425 | "description": "Determines the location of the given view in the window and returns thevalues vi", 426 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/nativemethodsmixin.html#measureinwindow" 427 | }, 428 | { 429 | "name": "measureLayout", 430 | "snippet": "measureLayout(${1:relativeToNativeNode}, ${2:onSuccess}, ${3:onFail})", 431 | "type": "method", 432 | "description": "Like measure(), but measures the view relative an ancestor,specified as relative", 433 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/nativemethodsmixin.html#measurelayout" 434 | } 435 | ], 436 | "Alert": [ 437 | { 438 | "name": "alert", 439 | "snippet": "alert(${1:title}, ${2:message?}, ${3:buttons?}, ${4:type?})", 440 | "type": "method", 441 | "description": " ", 442 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/alert.html#alert" 443 | } 444 | ], 445 | "AlertIOS": [ 446 | { 447 | "name": "alert", 448 | "snippet": "alert(${1:title}, ${2:message?}, ${3:callbackOrButtons?}, ${4:type?})", 449 | "type": "method", 450 | "description": "Creates a popup to alert the user. SeeAlert.", 451 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/alertios.html#alert" 452 | }, 453 | { 454 | "name": "prompt", 455 | "snippet": "prompt(${1:title}, ${2:message?}, ${3:callbackOrButtons?}, ${4:type?}, ${5:defaultValue?})", 456 | "type": "method", 457 | "description": "Prompt the user to enter some text.", 458 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/alertios.html#prompt" 459 | } 460 | ], 461 | "StatusBarIOS": [ 462 | { 463 | "name": "setHidden", 464 | "snippet": "setHidden(${1:hidden}, ${2:animation?})", 465 | "type": "method", 466 | "description": " ", 467 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/statusbarios.html#sethidden" 468 | }, 469 | { 470 | "name": "setNetworkActivityIndicatorVisible", 471 | "snippet": "setNetworkActivityIndicatorVisible(${1:visible})", 472 | "type": "method", 473 | "description": " ", 474 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/statusbarios.html#setnetworkactivityindicatorvisible" 475 | }, 476 | { 477 | "name": "setStyle", 478 | "snippet": "setStyle(${1:style}, ${2:animated?})", 479 | "type": "method", 480 | "description": " ", 481 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/statusbarios.html#setstyle" 482 | } 483 | ], 484 | "ToastAndroid": [ 485 | { 486 | "name": "LONG", 487 | "text": "LONG", 488 | "type": "property", 489 | "description": " ", 490 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/toastandroid.html#long" 491 | }, 492 | { 493 | "name": "SHORT", 494 | "text": "SHORT", 495 | "type": "property", 496 | "description": " ", 497 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/toastandroid.html#short" 498 | }, 499 | { 500 | "name": "show", 501 | "snippet": "show(${1:message}, ${2:duration})", 502 | "type": "method", 503 | "description": " ", 504 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/toastandroid.html#show" 505 | } 506 | ], 507 | "StyleSheet": [ 508 | { 509 | "name": "create", 510 | "snippet": "create(${1:obj})", 511 | "type": "method", 512 | "description": "Creates a StyleSheet style reference from the given object.", 513 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/stylesheet.html#create" 514 | }, 515 | { 516 | "name": "flatten", 517 | "text": "flatten", 518 | "type": "property", 519 | "description": "Flattens an array of style objects, into one aggregated style object.Alternative", 520 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/stylesheet.html#flatten" 521 | }, 522 | { 523 | "name": "hairlineWidth", 524 | "text": "hairlineWidth", 525 | "type": "property", 526 | "description": "This is defined as the width of a thin line on the platform. It can beused as th", 527 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/stylesheet.html#hairlinewidth" 528 | } 529 | ], 530 | "LayoutAnimation": [ 531 | { 532 | "name": "configChecker", 533 | "text": "configChecker", 534 | "type": "property", 535 | "description": " ", 536 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#configchecker" 537 | }, 538 | { 539 | "name": "configureNext", 540 | "snippet": "configureNext(${1:config}, ${2:onAnimationDidEnd?})", 541 | "type": "method", 542 | "description": "Schedules an animation to happen on the next layout.", 543 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#configurenext" 544 | }, 545 | { 546 | "name": "create", 547 | "snippet": "create(${1:duration}, ${2:type}, ${3:creationProp})", 548 | "type": "method", 549 | "description": "Helper for creating a config for configureNext.", 550 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#create" 551 | }, 552 | { 553 | "name": "easeInEaseOut", 554 | "text": "easeInEaseOut", 555 | "type": "property", 556 | "description": " ", 557 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#easeineaseout" 558 | }, 559 | { 560 | "name": "linear", 561 | "text": "linear", 562 | "type": "property", 563 | "description": " ", 564 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#linear" 565 | }, 566 | { 567 | "name": "Presets", 568 | "text": "Presets", 569 | "type": "property", 570 | "description": " ", 571 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#presets" 572 | }, 573 | { 574 | "name": "Properties", 575 | "text": "Properties", 576 | "type": "property", 577 | "description": " ", 578 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#properties" 579 | }, 580 | { 581 | "name": "spring", 582 | "text": "spring", 583 | "type": "property", 584 | "description": " ", 585 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#spring" 586 | }, 587 | { 588 | "name": "Types", 589 | "text": "Types", 590 | "type": "property", 591 | "description": " ", 592 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/layoutanimation.html#types" 593 | } 594 | ], 595 | "AppStateIOS": [ 596 | { 597 | "name": "addEventListener", 598 | "snippet": "addEventListener(${1:type}, ${2:handler})", 599 | "type": "method", 600 | "description": "Add a handler to AppState changes by listening to the change event typeand provi", 601 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstateios.html#addeventlistener" 602 | }, 603 | { 604 | "name": "currentState", 605 | "text": "currentState", 606 | "type": "property", 607 | "description": "// TODO: getCurrentAppState callback seems to be called at a really late stage//", 608 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstateios.html#currentstate" 609 | }, 610 | { 611 | "name": "removeEventListener", 612 | "snippet": "removeEventListener(${1:type}, ${2:handler})", 613 | "type": "method", 614 | "description": "Remove a handler by passing the change event type and the handler", 615 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstateios.html#removeeventlistener" 616 | } 617 | ], 618 | "LinkingIOS": [ 619 | { 620 | "name": "addEventListener", 621 | "snippet": "addEventListener(${1:type}, ${2:handler})", 622 | "type": "method", 623 | "description": "Add a handler to LinkingIOS changes by listening to the url event typeand provid", 624 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linkingios.html#addeventlistener" 625 | }, 626 | { 627 | "name": "canOpenURL", 628 | "snippet": "canOpenURL(${1:url}, ${2:callback})", 629 | "type": "method", 630 | "description": "Determine whether or not an installed app can handle a given URL.The callback fu", 631 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linkingios.html#canopenurl" 632 | }, 633 | { 634 | "name": "openURL", 635 | "snippet": "openURL(${1:url})", 636 | "type": "method", 637 | "description": "Try to open the given url with any of the installed apps.", 638 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linkingios.html#openurl" 639 | }, 640 | { 641 | "name": "popInitialURL", 642 | "snippet": "popInitialURL()", 643 | "type": "method", 644 | "description": "If the app launch was triggered by an app link, it will pop the link url,otherwi", 645 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linkingios.html#popinitialurl" 646 | }, 647 | { 648 | "name": "removeEventListener", 649 | "snippet": "removeEventListener(${1:type}, ${2:handler})", 650 | "type": "method", 651 | "description": "Remove a handler by passing the url event type and the handler", 652 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/linkingios.html#removeeventlistener" 653 | } 654 | ], 655 | "PixelRatio": [ 656 | { 657 | "name": "get", 658 | "snippet": "get()", 659 | "type": "method", 660 | "description": "Returns the device pixel density. Some examples:", 661 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pixelratio.html#get" 662 | }, 663 | { 664 | "name": "getFontScale", 665 | "snippet": "getFontScale()", 666 | "type": "method", 667 | "description": "Returns the scaling factor for font sizes. This is the ratio that is used to cal", 668 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pixelratio.html#getfontscale" 669 | }, 670 | { 671 | "name": "getPixelSizeForLayoutSize", 672 | "snippet": "getPixelSizeForLayoutSize(${1:layoutSize})", 673 | "type": "method", 674 | "description": "Converts a layout size (dp) to pixel size (px).", 675 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pixelratio.html#getpixelsizeforlayoutsize" 676 | }, 677 | { 678 | "name": "roundToNearestPixel", 679 | "snippet": "roundToNearestPixel(${1:layoutSize})", 680 | "type": "method", 681 | "description": "Rounds a layout size (dp) to the nearest layout size that corresponds toan integ", 682 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pixelratio.html#roundtonearestpixel" 683 | }, 684 | { 685 | "name": "startDetecting", 686 | "snippet": "startDetecting()", 687 | "type": "method", 688 | "description": "// No-op for iOS, but used on the web. Should not be documented.", 689 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pixelratio.html#startdetecting" 690 | } 691 | ], 692 | "InteractionManager": [ 693 | { 694 | "name": "addListener", 695 | "text": "addListener", 696 | "type": "property", 697 | "description": " ", 698 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#addlistener" 699 | }, 700 | { 701 | "name": "clearInteractionHandle", 702 | "snippet": "clearInteractionHandle(${1:handle})", 703 | "type": "method", 704 | "description": "Notify manager that an interaction has completed.", 705 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#clearinteractionhandle" 706 | }, 707 | { 708 | "name": "createInteractionHandle", 709 | "snippet": "createInteractionHandle()", 710 | "type": "method", 711 | "description": "Notify manager that an interaction has started.", 712 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#createinteractionhandle" 713 | }, 714 | { 715 | "name": "Events", 716 | "text": "Events", 717 | "type": "property", 718 | "description": " ", 719 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#events" 720 | }, 721 | { 722 | "name": "runAfterInteractions", 723 | "snippet": "runAfterInteractions(${1:task})", 724 | "type": "method", 725 | "description": "Schedule a function to run after all interactions have completed.", 726 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#runafterinteractions" 727 | }, 728 | { 729 | "name": "setDeadline", 730 | "snippet": "setDeadline(${1:deadline})", 731 | "type": "method", 732 | "description": "A positive number will use setTimeout to schedule any tasks after theeventLoopRu", 733 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/interactionmanager.html#setdeadline" 734 | } 735 | ], 736 | "AppRegistry": [ 737 | { 738 | "name": "getAppKeys", 739 | "snippet": "getAppKeys()", 740 | "type": "method", 741 | "description": " ", 742 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#getappkeys" 743 | }, 744 | { 745 | "name": "registerComponent", 746 | "snippet": "registerComponent(${1:appKey}, ${2:getComponentFunc})", 747 | "type": "method", 748 | "description": " ", 749 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#registercomponent" 750 | }, 751 | { 752 | "name": "registerConfig", 753 | "snippet": "registerConfig(${1:config})", 754 | "type": "method", 755 | "description": " ", 756 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#registerconfig" 757 | }, 758 | { 759 | "name": "registerRunnable", 760 | "snippet": "registerRunnable(${1:appKey}, ${2:func})", 761 | "type": "method", 762 | "description": " ", 763 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#registerrunnable" 764 | }, 765 | { 766 | "name": "runApplication", 767 | "snippet": "runApplication(${1:appKey}, ${2:appParameters})", 768 | "type": "method", 769 | "description": " ", 770 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#runapplication" 771 | }, 772 | { 773 | "name": "unmountApplicationComponentAtRootTag", 774 | "snippet": "unmountApplicationComponentAtRootTag(${1:rootTag})", 775 | "type": "method", 776 | "description": " ", 777 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appregistry.html#unmountapplicationcomponentatroottag" 778 | } 779 | ], 780 | "IntentAndroid": [ 781 | { 782 | "name": "canOpenURL", 783 | "snippet": "canOpenURL(${1:url}, ${2:callback})", 784 | "type": "method", 785 | "description": "Determine whether or not an installed app can handle a given URL.", 786 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/intentandroid.html#canopenurl" 787 | }, 788 | { 789 | "name": "getInitialURL", 790 | "snippet": "getInitialURL(${1:callback})", 791 | "type": "method", 792 | "description": "If the app launch was triggered by an app link with {@code Intent.ACTION_VIEW},i", 793 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/intentandroid.html#getinitialurl" 794 | }, 795 | { 796 | "name": "openURL", 797 | "snippet": "openURL(${1:url})", 798 | "type": "method", 799 | "description": "Starts a corresponding external activity for the given URL.", 800 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/intentandroid.html#openurl" 801 | } 802 | ], 803 | "AppState": [ 804 | { 805 | "name": "addEventListener", 806 | "snippet": "addEventListener(${1:type}, ${2:handler})", 807 | "type": "method", 808 | "description": "Add a handler to AppState changes by listening to the change event typeand provi", 809 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstate.html#addeventlistener" 810 | }, 811 | { 812 | "name": "currentState", 813 | "text": "currentState", 814 | "type": "property", 815 | "description": " ", 816 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstate.html#currentstate" 817 | }, 818 | { 819 | "name": "removeEventListener", 820 | "snippet": "removeEventListener(${1:type}, ${2:handler})", 821 | "type": "method", 822 | "description": "Remove a handler by passing the change event type and the handler", 823 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/appstate.html#removeeventlistener" 824 | } 825 | ], 826 | "DatePickerAndroid": [ 827 | { 828 | "name": "dateSetAction", 829 | "snippet": "dateSetAction()", 830 | "type": "method", 831 | "description": "A date has been selected.", 832 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/datepickerandroid.html#datesetaction" 833 | }, 834 | { 835 | "name": "dismissedAction", 836 | "snippet": "dismissedAction()", 837 | "type": "method", 838 | "description": "The dialog has been dismissed.", 839 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/datepickerandroid.html#dismissedaction" 840 | }, 841 | { 842 | "name": "open", 843 | "snippet": "open(${1:options})", 844 | "type": "method", 845 | "description": "Opens the standard Android date picker dialog.", 846 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/datepickerandroid.html#open" 847 | } 848 | ], 849 | "Animated": [ 850 | { 851 | "name": "add", 852 | "snippet": "add(${1:a}, ${2:b})", 853 | "type": "method", 854 | "description": "Creates a new Animated value composed from two Animated values addedtogether.", 855 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#add" 856 | }, 857 | { 858 | "name": "createAnimatedComponent", 859 | "snippet": "createAnimatedComponent(${1:Component})", 860 | "type": "method", 861 | "description": "Make any React component Animatable. Used to create Animated.View, etc.", 862 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#createanimatedcomponent" 863 | }, 864 | { 865 | "name": "decay", 866 | "snippet": "decay(${1:value}, ${2:config})", 867 | "type": "method", 868 | "description": "Animates a value from an initial velocity to zero based on a decaycoefficient.", 869 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#decay" 870 | }, 871 | { 872 | "name": "delay", 873 | "snippet": "delay(${1:time})", 874 | "type": "method", 875 | "description": "Starts an animation after the given delay.", 876 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#delay" 877 | }, 878 | { 879 | "name": "event", 880 | "snippet": "event(${1:argMapping}, ${2:config?})", 881 | "type": "method", 882 | "description": " Takes an array of mappings and extracts values from each arg accordingly, then ", 883 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#event" 884 | }, 885 | { 886 | "name": "modulo", 887 | "snippet": "modulo(${1:a}, ${2:modulus})", 888 | "type": "method", 889 | "description": "Creates a new Animated value that is the (non-negative) modulo of theprovided An", 890 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#modulo" 891 | }, 892 | { 893 | "name": "multiply", 894 | "snippet": "multiply(${1:a}, ${2:b})", 895 | "type": "method", 896 | "description": "Creates a new Animated value composed from two Animated values multipliedtogethe", 897 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#multiply" 898 | }, 899 | { 900 | "name": "parallel", 901 | "snippet": "parallel(${1:animations}, ${2:config?})", 902 | "type": "method", 903 | "description": "Starts an array of animations all at the same time. By default, if oneof the an", 904 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#parallel" 905 | }, 906 | { 907 | "name": "sequence", 908 | "snippet": "sequence(${1:animations})", 909 | "type": "method", 910 | "description": "Starts an array of animations in order, waiting for each to completebefore start", 911 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#sequence" 912 | }, 913 | { 914 | "name": "spring", 915 | "snippet": "spring(${1:value}, ${2:config})", 916 | "type": "method", 917 | "description": "Spring animation based on Rebound and Origami. Tracks velocity state tocreate f", 918 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#spring" 919 | }, 920 | { 921 | "name": "stagger", 922 | "snippet": "stagger(${1:time}, ${2:animations})", 923 | "type": "method", 924 | "description": "Array of animations may run in parallel (overlap), but are started insequence wi", 925 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#stagger" 926 | }, 927 | { 928 | "name": "timing", 929 | "snippet": "timing(${1:value}, ${2:config})", 930 | "type": "method", 931 | "description": "Animates a value along a timed easing curve. The Easing module has tonsof pre-d", 932 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#timing" 933 | }, 934 | { 935 | "name": "Value", 936 | "text": "Value()", 937 | "type": "class", 938 | "description": "Standard value class for driving animations. Typically initialized withnew Anim", 939 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#value" 940 | }, 941 | { 942 | "name": "ValueXY", 943 | "text": "ValueXY()", 944 | "type": "class", 945 | "description": "2D value class for driving 2D animations, such as pan gestures.", 946 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/animated.html#valuexy" 947 | } 948 | ], 949 | "ActionSheetIOS": [ 950 | { 951 | "name": "showActionSheetWithOptions", 952 | "snippet": "showActionSheetWithOptions(${1:options}, ${2:callback})", 953 | "type": "method", 954 | "description": "Display an iOS action sheet. The options object must contain one or moreof:", 955 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/actionsheetios.html#showactionsheetwithoptions" 956 | }, 957 | { 958 | "name": "showShareActionSheetWithOptions", 959 | "snippet": "showShareActionSheetWithOptions(${1:options}, ${2:failureCallback}, ${3:successCallback})", 960 | "type": "method", 961 | "description": "Display the iOS share sheet. The options object should containone or both of:", 962 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/actionsheetios.html#showshareactionsheetwithoptions" 963 | } 964 | ], 965 | "PushNotificationIOS": [ 966 | { 967 | "name": "abandonPermissions", 968 | "snippet": "abandonPermissions()", 969 | "type": "method", 970 | "description": "Unregister for all remote notifications received via Apple Push Notification ser", 971 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#abandonpermissions" 972 | }, 973 | { 974 | "name": "addEventListener", 975 | "snippet": "addEventListener(${1:type}, ${2:handler})", 976 | "type": "method", 977 | "description": "Attaches a listener to remote or local notification events while the app is runn", 978 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#addeventlistener" 979 | }, 980 | { 981 | "name": "cancelAllLocalNotifications", 982 | "snippet": "cancelAllLocalNotifications()", 983 | "type": "method", 984 | "description": "Cancels all scheduled localNotifications", 985 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#cancelalllocalnotifications" 986 | }, 987 | { 988 | "name": "cancelLocalNotifications", 989 | "snippet": "cancelLocalNotifications(${1:userInfo})", 990 | "type": "method", 991 | "description": "Cancel local notifications.", 992 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#cancellocalnotifications" 993 | }, 994 | { 995 | "name": "checkPermissions", 996 | "snippet": "checkPermissions(${1:callback})", 997 | "type": "method", 998 | "description": "See what push permissions are currently enabled. callback will beinvoked with a ", 999 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#checkpermissions" 1000 | }, 1001 | { 1002 | "name": "constructor", 1003 | "snippet": "constructor(${1:nativeNotif})", 1004 | "type": "method", 1005 | "description": "You will never need to instantiate PushNotificationIOS yourself.Listening to the", 1006 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#constructor" 1007 | }, 1008 | { 1009 | "name": "getAlert", 1010 | "snippet": "getAlert()", 1011 | "type": "method", 1012 | "description": "Gets the notification's main message from the aps object", 1013 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getalert" 1014 | }, 1015 | { 1016 | "name": "getApplicationIconBadgeNumber", 1017 | "snippet": "getApplicationIconBadgeNumber(${1:callback})", 1018 | "type": "method", 1019 | "description": "Gets the current badge number for the app icon on the home screen", 1020 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getapplicationiconbadgenumber" 1021 | }, 1022 | { 1023 | "name": "getBadgeCount", 1024 | "snippet": "getBadgeCount()", 1025 | "type": "method", 1026 | "description": "Gets the badge count number from the aps object", 1027 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getbadgecount" 1028 | }, 1029 | { 1030 | "name": "getData", 1031 | "snippet": "getData()", 1032 | "type": "method", 1033 | "description": "Gets the data object on the notif", 1034 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getdata" 1035 | }, 1036 | { 1037 | "name": "getMessage", 1038 | "snippet": "getMessage()", 1039 | "type": "method", 1040 | "description": "An alias for getAlert to get the notification's main message string", 1041 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getmessage" 1042 | }, 1043 | { 1044 | "name": "getSound", 1045 | "snippet": "getSound()", 1046 | "type": "method", 1047 | "description": "Gets the sound string from the aps object", 1048 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#getsound" 1049 | }, 1050 | { 1051 | "name": "popInitialNotification", 1052 | "snippet": "popInitialNotification()", 1053 | "type": "method", 1054 | "description": "An initial notification will be available if the app was cold-launchedfrom a not", 1055 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#popinitialnotification" 1056 | }, 1057 | { 1058 | "name": "presentLocalNotification", 1059 | "snippet": "presentLocalNotification(${1:details})", 1060 | "type": "method", 1061 | "description": "Schedules the localNotification for immediate presentation.", 1062 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#presentlocalnotification" 1063 | }, 1064 | { 1065 | "name": "removeEventListener", 1066 | "snippet": "removeEventListener(${1:type}, ${2:handler})", 1067 | "type": "method", 1068 | "description": "Removes the event listener. Do this in componentWillUnmount to preventmemory lea", 1069 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#removeeventlistener" 1070 | }, 1071 | { 1072 | "name": "requestPermissions", 1073 | "snippet": "requestPermissions(${1:permissions?})", 1074 | "type": "method", 1075 | "description": "Requests notification permissions from iOS, prompting the user'sdialog box.", 1076 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#requestpermissions" 1077 | }, 1078 | { 1079 | "name": "scheduleLocalNotification", 1080 | "snippet": "scheduleLocalNotification(${1:details})", 1081 | "type": "method", 1082 | "description": "Schedules the localNotification for future presentation.", 1083 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#schedulelocalnotification" 1084 | }, 1085 | { 1086 | "name": "setApplicationIconBadgeNumber", 1087 | "snippet": "setApplicationIconBadgeNumber(${1:number})", 1088 | "type": "method", 1089 | "description": "Sets the badge number for the app icon on the home screen", 1090 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/pushnotificationios.html#setapplicationiconbadgenumber" 1091 | } 1092 | ], 1093 | "NetInfo": [ 1094 | { 1095 | "name": "addEventListener", 1096 | "snippet": "addEventListener(${1:eventName}, ${2:handler})", 1097 | "type": "method", 1098 | "description": "Invokes the listener whenever network status changes.The listener receives one o", 1099 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/netinfo.html#addeventlistener" 1100 | }, 1101 | { 1102 | "name": "fetch", 1103 | "snippet": "fetch()", 1104 | "type": "method", 1105 | "description": "Returns a promise that resolves with one of the connectivity types listedabove.", 1106 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/netinfo.html#fetch" 1107 | }, 1108 | { 1109 | "name": "isConnected", 1110 | "text": "isConnected", 1111 | "type": "property", 1112 | "description": "An object with the same methods as above but the listener receives aboolean whic", 1113 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/netinfo.html#isconnected" 1114 | }, 1115 | { 1116 | "name": "isConnectionExpensive", 1117 | "snippet": "isConnectionExpensive()", 1118 | "type": "method", 1119 | "description": " ", 1120 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/netinfo.html#isconnectionexpensive" 1121 | }, 1122 | { 1123 | "name": "removeEventListener", 1124 | "snippet": "removeEventListener(${1:eventName}, ${2:handler})", 1125 | "type": "method", 1126 | "description": "Removes the listener for network status changes.", 1127 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/netinfo.html#removeeventlistener" 1128 | } 1129 | ], 1130 | "PanResponder": [ 1131 | { 1132 | "name": "create", 1133 | "snippet": "create(${1:config})", 1134 | "type": "method", 1135 | "description": "@param {object} config Enhanced versions of all of the responder callbacksthat p", 1136 | "descriptionMoreURL": "http://facebook.github.io/react-native/docs/panresponder.html#create" 1137 | } 1138 | ] 1139 | } -------------------------------------------------------------------------------- /completions/navigator.json: -------------------------------------------------------------------------------- 1 | { 2 | "geolocation": [{ 3 | "name": "getCurrentPosition", 4 | "snippet": "getCurrentPosition(geo_success: Function, geo_error?: Function, geo_options?: GeoOptions)", 5 | "type": "method", 6 | "rightLabelHTML": "react-native" 7 | }, { 8 | "name": "watchPosition", 9 | "snippet": "watchPosition(success: Function, error?: Function, options?: GeoOptions)", 10 | "type": "method", 11 | "rightLabelHTML": "react-native" 12 | }, { 13 | "name": "clearWatch", 14 | "snippet": "clearWatch(watchID: number)", 15 | "type": "method", 16 | "rightLabelHTML": "react-native" 17 | }, { 18 | "name": "stopObserving", 19 | "snippet": "stopObserving()", 20 | "type": "method", 21 | "rightLabelHTML": "react-native" 22 | }] 23 | } 24 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/94cstyles/atom-react-native-autocomplete/6374f2626344faf9a561e9e0f598a16bca219e89/demo.gif -------------------------------------------------------------------------------- /lib/autocomplete.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _provider = require('./provider'); 8 | 9 | var _provider2 = _interopRequireDefault(_provider); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var packageName = 'atom-react-native-autocomplete'; 14 | 15 | var autocomplete = { 16 | config: { 17 | prefix: { 18 | title: 'Prefix parsing rules', 19 | description: 'AutoComplete feature the string parsing rules', 20 | type: 'string', 21 | "default": 'React', 22 | order: 10 23 | } 24 | }, 25 | activate: function activate(state) { 26 | //监听配置变化 27 | atom.config.observe(packageName + '.prefix', _provider2.default.setPrefix); 28 | 29 | //安装依赖插件 30 | require('atom-package-deps').install('atom-react-native-autocomplete'); 31 | }, 32 | deactivate: function deactivate() {}, 33 | serialize: function serialize() {}, 34 | getProvider: function getProvider() { 35 | return _provider2.default; 36 | } 37 | }; 38 | 39 | exports.default = autocomplete; 40 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/helper/collect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _path = require("path"); 4 | 5 | var _path2 = _interopRequireDefault(_path); 6 | 7 | var _fs = require("fs"); 8 | 9 | var _fs2 = _interopRequireDefault(_fs); 10 | 11 | var _cheerio = require("cheerio"); 12 | 13 | var _cheerio2 = _interopRequireDefault(_cheerio); 14 | 15 | var _request = require("request"); 16 | 17 | var _request2 = _interopRequireDefault(_request); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | var docsURL = 'http://facebook.github.io/react-native/docs/getting-started.html'; 22 | var separateTags = ['ActivityIndicatorIOS', 'DatePickerIOS', 'Image', 'ListView', 'MapView', 'Navigator', 'NavigatorIOS', 'ProgressBarAndroid', 'ProgressViewIOS', 'SegmentedControlIOS', 'SliderIOS', 'TextInput', 'ToolbarAndroid', 'WebView']; 23 | 24 | /** 25 | * 从官网抓取apis和components文档 26 | * 最后输出至: ProjectDir/completions/[apis.json,components.json] 27 | */ 28 | var collect = { 29 | API: { 30 | "React": [{ 31 | "text": "Platform", 32 | "type": "property", 33 | "rightLabelHTML": "react-native" 34 | }], 35 | "Platform": [{ 36 | "text": "OS", 37 | "type": "property" 38 | }, { 39 | "text": "Version", 40 | "type": "property" 41 | }] 42 | }, 43 | COMPONENT: { 44 | "tags": { 45 | "queue": [], 46 | "completions": [] 47 | }, 48 | "attributes": {}, 49 | "values": {}, 50 | "extend": {} 51 | }, 52 | CLASS: {}, 53 | cache: { 54 | API: {}, 55 | COMPONENT: {}, 56 | CLASS: {} 57 | }, 58 | indent: 2, 59 | alphabetical: function alphabetical(arr) { 60 | function _alphabetical(a, b) { 61 | var A = a.toLowerCase(); 62 | var B = b.toLowerCase(); 63 | if (A < B) { 64 | return -1; 65 | } else if (A > B) { 66 | return 1; 67 | } else { 68 | return 0; 69 | } 70 | }; 71 | arr.sort(function (a, b) { 72 | if (typeof a === 'string') { 73 | return _alphabetical(a, b); 74 | } else { 75 | return _alphabetical(a.snippet || a.text, b.snippet || b.text); 76 | } 77 | }); 78 | return arr; 79 | }, 80 | extend: function extend(arrOne, arrTwo) { 81 | var arr = [].concat(arrOne, arrTwo), 82 | keyMap = {}; 83 | 84 | for (var i = arr.length - 1; i >= 0; i--) { 85 | if (keyMap[arr[i].snippet]) { 86 | arr.splice(i, 1); 87 | } else { 88 | keyMap[arr[i].snippet] = true; 89 | } 90 | } 91 | 92 | return arr; 93 | }, 94 | 95 | clone: function clone(obj) { 96 | var newObj = null; 97 | if (typeof obj.length === 'number') { 98 | newObj = []; 99 | var _iteratorNormalCompletion = true; 100 | var _didIteratorError = false; 101 | var _iteratorError = undefined; 102 | 103 | try { 104 | for (var _iterator = obj[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 105 | var val = _step.value; 106 | 107 | newObj.push(val); 108 | } 109 | } catch (err) { 110 | _didIteratorError = true; 111 | _iteratorError = err; 112 | } finally { 113 | try { 114 | if (!_iteratorNormalCompletion && _iterator.return) { 115 | _iterator.return(); 116 | } 117 | } finally { 118 | if (_didIteratorError) { 119 | throw _iteratorError; 120 | } 121 | } 122 | } 123 | } else { 124 | newObj = {}; 125 | for (var key in obj) { 126 | if (!key.match(/(name|value)/)) { 127 | newObj[key] = obj[key]; 128 | } 129 | } 130 | newObj.rightLabelHTML = 'react-native'; 131 | } 132 | return newObj; 133 | }, 134 | createDir: function createDir(dir) { 135 | var dirNames = dir.split(_path2.default.spe), 136 | dirPath = ''; 137 | 138 | for (var i = 0; i < dirNames.length; i++) { 139 | dirPath = _path2.default.resolve(dirPath, dirNames[i]); 140 | if (!_fs2.default.existsSync(dirPath)) { 141 | _fs2.default.mkdirSync(dirPath); //创建目录 142 | } 143 | } 144 | }, 145 | getOutputPath: function getOutputPath(type) { 146 | var filePath = _path2.default.resolve(__dirname, '../../completions/' + type + '.json'); 147 | this.createDir(_path2.default.parse(filePath).dir); 148 | return filePath; 149 | }, 150 | setExtendAttribute: function setExtendAttribute() { 151 | if (this.COMPONENT.extend) { 152 | for (var key in this.COMPONENT.extend) { 153 | var _iteratorNormalCompletion2 = true; 154 | var _didIteratorError2 = false; 155 | var _iteratorError2 = undefined; 156 | 157 | try { 158 | for (var _iterator2 = this.COMPONENT.extend[key][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 159 | var extendKey = _step2.value; 160 | 161 | if (this.COMPONENT.attributes[extendKey]) { 162 | this.COMPONENT.attributes[key] = this.alphabetical(this.extend(this.COMPONENT.attributes[key], this.COMPONENT.attributes[extendKey])); 163 | this.COMPONENT.extend[key].splice(this.COMPONENT.extend[key].indexOf(extendKey), 1); 164 | } 165 | } 166 | } catch (err) { 167 | _didIteratorError2 = true; 168 | _iteratorError2 = err; 169 | } finally { 170 | try { 171 | if (!_iteratorNormalCompletion2 && _iterator2.return) { 172 | _iterator2.return(); 173 | } 174 | } finally { 175 | if (_didIteratorError2) { 176 | throw _iteratorError2; 177 | } 178 | } 179 | } 180 | 181 | if (this.COMPONENT.extend[key].length === 0) { 182 | delete this.COMPONENT.extend[key]; 183 | } 184 | } 185 | } 186 | }, 187 | getAPIS: function getAPIS(content) { 188 | this.API.React.push(this.clone(content.attribute)); 189 | this.API[content.attribute.name] = this.alphabetical(this.clone(content.completions)); 190 | 191 | //排序 192 | this.alphabetical(this.API.React); 193 | return this.API; 194 | }, 195 | getCOMPONENTS: function getCOMPONENTS(content) { 196 | var _this = this; 197 | 198 | this.COMPONENT.tags.queue.push(content.attribute.name); 199 | this.COMPONENT.tags.completions.push(this.clone(content.attribute)); 200 | this.COMPONENT.attributes[content.attribute.name] = []; 201 | this.COMPONENT.extend[content.attribute.name] = content.extend; 202 | 203 | content.completions.forEach(function (obj) { 204 | if (typeof obj.value !== 'undefined') { 205 | if (_this.COMPONENT.values[obj.name] && obj.value.length <= _this.COMPONENT.values[obj.name].length) { 206 | //解决value重复 取值最多的项 207 | return false; 208 | } 209 | _this.COMPONENT.values[obj.name] = _this.alphabetical(obj.value); 210 | } 211 | _this.COMPONENT.attributes[content.attribute.name].push(_this.clone(obj)); 212 | }); 213 | this.setExtendAttribute(); 214 | 215 | //排序 216 | this.alphabetical(this.COMPONENT.tags.queue); 217 | this.alphabetical(this.COMPONENT.tags.completions); 218 | return this.COMPONENT; 219 | }, 220 | outputFile: function outputFile(type, content) { 221 | if (!content) return; 222 | content = typeof content.length === 'number' ? content : [content]; 223 | 224 | for (var i = 0; i < content.length; i++) { 225 | var filePath = this.getOutputPath(type); 226 | content[i] = this['get' + type.toUpperCase()](content[i]); 227 | _fs2.default.writeFile(filePath, JSON.stringify(content[i], null, this.indent), function (err) { 228 | console.log('更新文件: ' + type + '.json'); 229 | }); 230 | } 231 | }, 232 | parseMethod: function parseMethod(node, url, key) { 233 | var name = node.find('> .propTitle').html().match(/static <\/span>([\s\S]*)/); 234 | 235 | if (name) { 236 | name = name[1].trim(); 237 | } else { 238 | name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)/); 239 | if (name) { 240 | name = name[2].trim(); 241 | } else { 242 | console.log('读取method失败:\n' + url + '\n' + node.find('> .propTitle').html()); 243 | return null; 244 | } 245 | } 246 | var param = node.find('.propTitle > .propType'), 247 | snippet = '('; 248 | 249 | param = param.eq(param.length - 1).html().trim().replace('(', '').replace(')', '').split(','); 250 | if (param && param[0].trim() !== '') { 251 | param.forEach(function (text, index) { 252 | snippet += (index !== 0 ? ', ' : '') + '${' + (index + 1) + ':' + text.split(':')[0].replace(/\n/g, '').trim() + '}'; 253 | }); 254 | } 255 | 256 | return { 257 | "name": name, 258 | "snippet": name + snippet + ')', 259 | "type": "method", 260 | "description": this.getDescription(node), 261 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name) 262 | }; 263 | }, 264 | parsePropertie: function parsePropertie(node, url, key) { 265 | var name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)/); 266 | if (name) { 267 | name = name[2].trim(); 268 | return { 269 | "name": name, 270 | "text": key === 'Animated' && !!name.match(/^(Value|ValueXY)$/) ? name + '()' : name, 271 | "type": key === 'Animated' && !!name.match(/^(Value|ValueXY)$/) ? "class" : "property", 272 | "description": this.getDescription(node), 273 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name) 274 | }; 275 | } else { 276 | console.log('读取propertie失败:\n' + url + '\n' + node.find('> .propTitle').html()); 277 | return null; 278 | } 279 | }, 280 | parseProp: function parseProp(node, url, key) { 281 | if (node.parent().attr('class') !== 'props') return null; 282 | var extendKey = node.find('> .propTitle').html().match(/([\s\S]*)<\/a>/); 283 | if (extendKey === null) { 284 | var name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)([\s\S]*)<\/span>/); 285 | name = name ? name : node.find('> .propTitle').html().match(/<\/a>([\s\S]*)([\s\S]*)<\/span>([\s\S]*)/)) { 290 | name = name[2].match(/([\s\S]*)<\/span>([\s\S]*)/); 291 | mobile = name[1] + ':'; 292 | name = name[2].trim(); 293 | } else { 294 | name = name[2].trim(); 295 | } 296 | var obj = { 297 | "name": name, 298 | "displayText": name, 299 | "snippet": name + '=' + (/^enum|string/.test(type) && !this.enumException(name) ? '"$1"' : '{$1}'), 300 | "type": "attribute", 301 | "description": this.getDescription(node), 302 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name), 303 | "leftLabelHTML": mobile + (type.match(/(function|bool|style|string|number)/) ? type : 'object') 304 | }; 305 | if (type.indexOf('enum') !== -1) { 306 | obj.leftLabelHTML = mobile + 'enum'; 307 | obj.value = type.match(/enum\(([\s\S]*)\)/)[1].replace(/'/g, '').replace(/"/g, '').replace(/\s/g, '').split(','); 308 | } else if (type.match(/View#style/)) { 309 | obj.leftLabelHTML = mobile + 'style'; 310 | } else if (type.match(/^(\{|\[)/)) { 311 | obj.leftLabelHTML = mobile + 'object'; 312 | } 313 | return obj; 314 | } else { 315 | return extendKey[2].split(' ')[0]; 316 | } 317 | }, 318 | getDescriptionMoreURL: function getDescriptionMoreURL(url, name) { 319 | return url.replace(/#([\s\S]*)/g, '') + '#' + name.toLowerCase(); 320 | }, 321 | getDescription: function getDescription(node) { 322 | var description = node.find('> .propTitle').eq(0).next().find('> p').eq(0).html(); 323 | description = description ? description.replace(/<\/?[^>]*>/g, '').replace(/\n/g, '').replace(/\r/g, '') : ' '; 324 | description = description && description.length > 80 ? description.substring(0, 80) : description; 325 | return description; 326 | }, 327 | getCompletionObj: function getCompletionObj(type, name) { 328 | var completion = { 329 | "attribute": { 330 | "name": name 331 | }, 332 | "completions": [] 333 | }; 334 | if (type === 'apis') { 335 | completion.attribute.text = name; 336 | completion.attribute.type = 'class'; 337 | } else { 338 | completion.attribute.displayText = name; 339 | completion.attribute.snippet = name + (separateTags.indexOf(name) !== -1 ? '$1/>' : '$1>\n'); 340 | completion.attribute.type = 'tag'; 341 | completion.extend = []; 342 | } 343 | return completion; 344 | }, 345 | getClass: function getClass(type, name, url, $) { 346 | var completion = this.getCompletionObj(type, name), 347 | titles = $('.inner-content > div > span > h3, .inner-content > div > h3'); 348 | 349 | for (var i = 0; i < titles.length; i++) { 350 | var title = titles.eq(i).html().match(/<\/a>/); 351 | if (title && (title = title[1]).match(/(methods|properties|props)/)) { 352 | var props = titles.eq(i).next().find(' > .prop'); 353 | for (var j = 0; j < props.length; j++) { 354 | var obj = null; 355 | if (title === 'methods') { 356 | obj = this.parseMethod(props.eq(j), url, name); 357 | } else if (title === 'properties') { 358 | obj = this.parsePropertie(props.eq(j), url, name); 359 | } else if (title === 'props') { 360 | obj = this.parseProp(props.eq(j), url, name); 361 | } 362 | if (typeof obj === 'string') { 363 | completion.extend.push(obj); 364 | if (obj === 'ScrollView') { 365 | completion.extend.push('View'); 366 | } 367 | } else if (obj) { 368 | completion.completions.push(obj); 369 | } 370 | } 371 | } 372 | } 373 | return completion; 374 | }, 375 | getSubClass: function getSubClass(type, name, url, $) { 376 | if (type === 'apis') { 377 | var classNodes = $('.inner-content h2'), 378 | completionList = []; 379 | for (var i = 0; i < classNodes.length; i++) { 380 | var className = classNodes.eq(i).html().match(/<\/a>class([\s\S]*)([a-zA-Z][-a-zA-Z]*|$)/; 22 | var tagPattern = /<(([a-zA-Z][-a-zA-Z]*)|TabBarIOS.Item)(?:\s|$)/; //TabBarIOS.Item是特殊的标签 23 | 24 | var COMPONENT = { 25 | getTagNameCompletions: function getTagNameCompletions() { 26 | var _completions = []; 27 | _components2.default.tags.completions.forEach(function (obj) { 28 | _completions.push(_units2.default.clone(obj)); 29 | }); 30 | return _completions; 31 | }, 32 | getAttributeNameCompletions: function getAttributeNameCompletions(editor, bufferPosition) { 33 | var _completions = [], 34 | tag = this.getPreviousTag(editor, bufferPosition); 35 | 36 | if (_components2.default.attributes[tag]) { 37 | _components2.default.attributes[tag].forEach(function (obj) { 38 | _completions.push(_units2.default.clone(obj)); 39 | }); 40 | } 41 | 42 | return _completions; 43 | }, 44 | getAttributeValueCompletions: function getAttributeValueCompletions(line) { 45 | var _completions = [], 46 | attribute = this.getPreviousAttribute(line); 47 | 48 | if (_components2.default.values[attribute]) { 49 | _components2.default.values[attribute].forEach(function (text) { 50 | _completions.push({ 51 | "text": text, 52 | "type": "value" 53 | }); 54 | }); 55 | } 56 | return _completions; 57 | }, 58 | getPreviousTag: function getPreviousTag(editor, bufferPosition) { 59 | var ref; 60 | var row = bufferPosition.row; 61 | 62 | while (row >= 0) { 63 | ref = tagPattern.exec(editor.lineTextForBufferRow(row)); 64 | if (ref) { 65 | return ref[1]; 66 | } 67 | row--; 68 | } 69 | return null; 70 | }, 71 | getPreviousAttribute: function getPreviousAttribute(line) { 72 | var ref, ref1; 73 | var quoteIndex = line.length - 1; 74 | 75 | while (line[quoteIndex] && !((ref = line[quoteIndex]) === '"' || ref === "'")) { 76 | quoteIndex--; 77 | } 78 | line = line.substring(0, quoteIndex); 79 | return (ref1 = attributePattern.exec(line)) != null ? ref1[1] : null; 80 | }, 81 | isAttributeValue: function isAttributeValue(scopes) { 82 | return this.hasTagScope(scopes) && this.hasAttributeValueScope(scopes) && !this.hasAttributeContentScope(scopes); 83 | }, 84 | isAttribute: function isAttribute(prefix, scopes) { 85 | if (!trailingWhitespace.test(prefix) && !attributeInput.test(prefix)) { 86 | return false; 87 | } 88 | return (this.hasTagScope(scopes) || this.hasAttributeScope(scopes)) && !this.hasAttributeContentScope(scopes); 89 | }, 90 | isTag: function isTag(scopes, line) { 91 | var segment = line.split(' ').pop(); 92 | 93 | return tagInput.test(segment) && !tagNotInput.test(segment) && !this.hasScopeDescriptor(scopes, ['string.quoted.double.jsx', 'string.quoted.single.jsx', 'string.quoted.double.js', 'string.quoted.single.js']) && !this.hasAttributeContentScope(scopes); 94 | }, 95 | hasTagScope: function hasTagScope(scopes) { 96 | return this.hasScopeDescriptor(scopes, ['meta.scope.tag.block', 'meta.tag.block.begin.jsx', 'meta.tag.block.end.jsx', 'entity.name.tag.jsx', 'tag.open.js', 'punctuation.definition.tag.begin.js', 'punctuation.definition.tag.end.js']) && !this.hasScopeDescriptor(scopes, ['invalid.illegal.tag.end.jsx', 'tag.closed.js']); 97 | }, 98 | hasAttributeScope: function hasAttributeScope(scopes) { 99 | return this.hasScopeDescriptor(scopes, ['entity.other.attribute-name.jsx', 'punctuation.separator.key-value.attribute.jsx']); 100 | }, 101 | hasAttributeValueScope: function hasAttributeValueScope(scopes) { 102 | return this.hasScopeDescriptor(scopes, ['string.quoted.double.jsx', 'string.quoted.single.jsx', 'string.quoted.double.js', 'string.quoted.single.js']) && this.hasScopeDescriptor(scopes, ['meta.scope.inner', 'punctuation.definition.string.begin.jsx', 'punctuation.definition.string.end.jsx', 'punctuation.definition.string.begin.js', 'punctuation.definition.string.end.js']); 103 | }, 104 | hasAttributeContentScope: function hasAttributeContentScope(scopes) { 105 | return this.hasScopeDescriptor(scopes, ['punctuation.section.embedded.begin.jsx', 'punctuation.section.embedded.end.jsx', 'punctuation.definition.brace.curly.begin.js', 'punctuation.definition.brace.curly.end.js', 'meta.brace.curly.js', 'meta.embedded.expression.jsx', /meta.embedded.expression.(\S*).jsx/]); 106 | }, 107 | hasScopeDescriptor: function hasScopeDescriptor(fromScopes, toScopes) { 108 | var _iteratorNormalCompletion = true; 109 | var _didIteratorError = false; 110 | var _iteratorError = undefined; 111 | 112 | try { 113 | for (var _iterator = toScopes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 114 | var scope = _step.value; 115 | 116 | if (typeof scope === 'string') { 117 | if (fromScopes.indexOf(scope) !== -1) { 118 | return true; 119 | } 120 | } else { 121 | var pass = false; 122 | var _iteratorNormalCompletion2 = true; 123 | var _didIteratorError2 = false; 124 | var _iteratorError2 = undefined; 125 | 126 | try { 127 | for (var _iterator2 = fromScopes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 128 | var text = _step2.value; 129 | 130 | if (scope.test(text)) { 131 | pass = true; 132 | } 133 | } 134 | } catch (err) { 135 | _didIteratorError2 = true; 136 | _iteratorError2 = err; 137 | } finally { 138 | try { 139 | if (!_iteratorNormalCompletion2 && _iterator2.return) { 140 | _iterator2.return(); 141 | } 142 | } finally { 143 | if (_didIteratorError2) { 144 | throw _iteratorError2; 145 | } 146 | } 147 | } 148 | 149 | if (pass) return true; 150 | } 151 | } 152 | } catch (err) { 153 | _didIteratorError = true; 154 | _iteratorError = err; 155 | } finally { 156 | try { 157 | if (!_iteratorNormalCompletion && _iterator.return) { 158 | _iterator.return(); 159 | } 160 | } finally { 161 | if (_didIteratorError) { 162 | throw _iteratorError; 163 | } 164 | } 165 | } 166 | 167 | return false; 168 | } 169 | }; 170 | 171 | exports.default = COMPONENT; 172 | module.exports = exports['default']; -------------------------------------------------------------------------------- /lib/provider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _api = require("./modules/api.js"); 8 | 9 | var _api2 = _interopRequireDefault(_api); 10 | 11 | var _component = require("./modules/component.js"); 12 | 13 | var _component2 = _interopRequireDefault(_component); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var provider = { 18 | selector: '.source.js, .source.jsx', 19 | filterSuggestions: true, 20 | getSuggestions: function getSuggestions(request) { 21 | var prefix = request.prefix, 22 | bufferPosition = request.bufferPosition, 23 | editor = request.editor, 24 | scopes = request.scopeDescriptor.getScopesArray(), 25 | line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]); 26 | 27 | return new Promise(function (resolve) { 28 | var suggestion = null; 29 | 30 | if (_component2.default.isAttributeValue(scopes)) { 31 | suggestion = _component2.default.getAttributeValueCompletions(line); 32 | } else if (_component2.default.isTag(scopes, line)) { 33 | suggestion = _component2.default.getTagNameCompletions(); 34 | } else if (_component2.default.isAttribute(prefix, scopes)) { 35 | suggestion = _component2.default.getAttributeNameCompletions(editor, bufferPosition); 36 | } else { 37 | suggestion = _api2.default.getCompletions(line); 38 | } 39 | resolve(suggestion); 40 | }); 41 | }, 42 | onDidInsertSuggestion: function onDidInsertSuggestion(request) { 43 | if (request.suggestion.rightLabelHTML === 'react-native' && request.suggestion.type === 'attribute') { 44 | setTimeout(function () { 45 | atom.commands.dispatch(atom.views.getView(request.editor), 'autocomplete-plus:activate', { 46 | activatedManually: false 47 | }); 48 | }, 1); 49 | } 50 | }, 51 | setPrefix: function setPrefix(prefix) { 52 | _api2.default.setMatchRule(prefix); 53 | } 54 | }; 55 | 56 | exports.default = provider; 57 | module.exports = exports['default']; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-react-native-autocomplete", 3 | "main": "./lib/autocomplete", 4 | "version": "0.0.27", 5 | "description": "React-Native autocompletion for Atom text editor! ", 6 | "keywords": [ 7 | "react-native", 8 | "autocomplete" 9 | ], 10 | "repository": "https://github.com/TOP-Chao/atom-react-native-autocomplete", 11 | "license": "MIT", 12 | "engines": { 13 | "atom": ">=1.0.0 <2.0.0" 14 | }, 15 | "dependencies": { 16 | "atom-package-deps": "^4.0.1" 17 | }, 18 | "devDependencies": { 19 | "babel-plugin-add-module-exports": "^0.1.2", 20 | "babel-preset-es2015": "^6.3.13", 21 | "cheerio": "^0.19.0", 22 | "request": "^2.67.0" 23 | }, 24 | "providedServices": { 25 | "autocomplete.provider": { 26 | "versions": { 27 | "2.0.0": "getProvider" 28 | } 29 | } 30 | }, 31 | "scripts": { 32 | "prepublish": "babel -d lib/ src/ --presets es2015 --plugins add-module-exports" 33 | }, 34 | "package-deps": [ 35 | "language-javascript-jsx" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/autocomplete.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import provider from "./provider"; 4 | 5 | const packageName = 'atom-react-native-autocomplete'; 6 | 7 | const autocomplete = { 8 | config: { 9 | prefix: { 10 | title: 'Prefix parsing rules', 11 | description: 'AutoComplete feature the string parsing rules', 12 | type: 'string', 13 | "default": 'React', 14 | order: 10 15 | } 16 | }, 17 | activate: function(state) { 18 | //监听配置变化 19 | atom.config.observe(packageName + '.prefix', provider.setPrefix); 20 | 21 | //安装依赖插件 22 | require('atom-package-deps').install('atom-react-native-autocomplete'); 23 | }, 24 | deactivate: function() {}, 25 | serialize: function() {}, 26 | getProvider: function() { 27 | return provider; 28 | } 29 | }; 30 | 31 | export default autocomplete; 32 | -------------------------------------------------------------------------------- /src/helper/collect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import path from "path"; 4 | import fs from "fs"; 5 | import cheerio from "cheerio"; 6 | import request from "request"; 7 | 8 | const docsURL = 'http://facebook.github.io/react-native/docs/getting-started.html'; 9 | const separateTags = ['ActivityIndicatorIOS', 'DatePickerIOS', 'Image', 'ListView', 'MapView', 'Navigator', 'NavigatorIOS', 'ProgressBarAndroid', 'ProgressViewIOS', 'SegmentedControlIOS', 'SliderIOS', 'TextInput', 'ToolbarAndroid', 'WebView']; 10 | 11 | /** 12 | * 从官网抓取apis和components文档 13 | * 最后输出至: ProjectDir/completions/[apis.json,components.json] 14 | */ 15 | var collect = { 16 | API: { 17 | "React": [{ 18 | "text": "Platform", 19 | "type": "property", 20 | "rightLabelHTML": "react-native" 21 | }], 22 | "Platform": [{ 23 | "text": "OS", 24 | "type": "property" 25 | }, { 26 | "text": "Version", 27 | "type": "property" 28 | }] 29 | }, 30 | COMPONENT: { 31 | "tags": { 32 | "queue": [], 33 | "completions": [] 34 | }, 35 | "attributes": {}, 36 | "values": {}, 37 | "extend": {} 38 | }, 39 | CLASS: { 40 | 41 | }, 42 | cache: { 43 | API: {}, 44 | COMPONENT: {}, 45 | CLASS: {} 46 | }, 47 | indent: 2, 48 | alphabetical(arr) { 49 | function _alphabetical(a, b) { 50 | var A = a.toLowerCase(); 51 | var B = b.toLowerCase(); 52 | if (A < B) { 53 | return -1; 54 | } else if (A > B) { 55 | return 1; 56 | } else { 57 | return 0; 58 | } 59 | }; 60 | arr.sort(function(a, b) { 61 | if (typeof(a) === 'string') { 62 | return _alphabetical(a, b); 63 | } else { 64 | return _alphabetical(a.snippet || a.text, b.snippet || b.text); 65 | } 66 | }); 67 | return arr; 68 | }, 69 | extend(arrOne, arrTwo) { 70 | let arr = [].concat(arrOne, arrTwo), 71 | keyMap = {}; 72 | 73 | for (let i = arr.length - 1; i >= 0; i--) { 74 | if (keyMap[arr[i].snippet]) { 75 | arr.splice(i, 1); 76 | } else { 77 | keyMap[arr[i].snippet] = true; 78 | } 79 | } 80 | 81 | return arr; 82 | }, 83 | clone: function(obj) { 84 | var newObj = null; 85 | if (typeof(obj.length) === 'number') { 86 | newObj = []; 87 | for (let val of obj) { 88 | newObj.push(val); 89 | } 90 | } else { 91 | newObj = {}; 92 | for (let key in obj) { 93 | if (!key.match(/(name|value)/)) { 94 | newObj[key] = obj[key]; 95 | } 96 | } 97 | newObj.rightLabelHTML = 'react-native'; 98 | } 99 | return newObj; 100 | }, 101 | createDir: function(dir) { 102 | let dirNames = dir.split(path.spe), 103 | dirPath = ''; 104 | 105 | for (let i = 0; i < dirNames.length; i++) { 106 | dirPath = path.resolve(dirPath, dirNames[i]); 107 | if (!fs.existsSync(dirPath)) { 108 | fs.mkdirSync(dirPath); //创建目录 109 | } 110 | } 111 | }, 112 | getOutputPath: function(type) { 113 | let filePath = path.resolve(__dirname, '../../completions/' + type + '.json'); 114 | this.createDir(path.parse(filePath).dir); 115 | return filePath; 116 | }, 117 | setExtendAttribute: function() { 118 | if (this.COMPONENT.extend) { 119 | for (let key in this.COMPONENT.extend) { 120 | for (let extendKey of this.COMPONENT.extend[key]) { 121 | if (this.COMPONENT.attributes[extendKey]) { 122 | this.COMPONENT.attributes[key] = this.alphabetical(this.extend(this.COMPONENT.attributes[key], this.COMPONENT.attributes[extendKey])); 123 | this.COMPONENT.extend[key].splice(this.COMPONENT.extend[key].indexOf(extendKey), 1); 124 | } 125 | } 126 | if (this.COMPONENT.extend[key].length === 0) { 127 | delete this.COMPONENT.extend[key]; 128 | } 129 | } 130 | } 131 | }, 132 | getAPIS: function(content) { 133 | this.API.React.push(this.clone(content.attribute)); 134 | this.API[content.attribute.name] = this.alphabetical(this.clone(content.completions)) 135 | 136 | //排序 137 | this.alphabetical(this.API.React); 138 | return this.API; 139 | }, 140 | getCOMPONENTS: function(content) { 141 | this.COMPONENT.tags.queue.push(content.attribute.name); 142 | this.COMPONENT.tags.completions.push(this.clone(content.attribute)); 143 | this.COMPONENT.attributes[content.attribute.name] = []; 144 | this.COMPONENT.extend[content.attribute.name] = content.extend; 145 | 146 | content.completions.forEach((obj) => { 147 | if (typeof(obj.value) !== 'undefined') { 148 | if (this.COMPONENT.values[obj.name] && obj.value.length <= this.COMPONENT.values[obj.name].length) { 149 | //解决value重复 取值最多的项 150 | return false; 151 | } 152 | this.COMPONENT.values[obj.name] = this.alphabetical(obj.value); 153 | } 154 | this.COMPONENT.attributes[content.attribute.name].push(this.clone(obj)); 155 | }); 156 | this.setExtendAttribute(); 157 | 158 | //排序 159 | this.alphabetical(this.COMPONENT.tags.queue); 160 | this.alphabetical(this.COMPONENT.tags.completions); 161 | return this.COMPONENT; 162 | }, 163 | outputFile: function(type, content) { 164 | if (!content) return; 165 | content = typeof(content.length) === 'number' ? content : [content]; 166 | 167 | for (let i = 0; i < content.length; i++) { 168 | let filePath = this.getOutputPath(type); 169 | content[i] = this['get' + type.toUpperCase()](content[i]); 170 | fs.writeFile(filePath, JSON.stringify(content[i], null, this.indent), (err) => { 171 | console.log('更新文件: ' + type + '.json'); 172 | }); 173 | } 174 | }, 175 | parseMethod: function(node, url, key) { 176 | var name = node.find('> .propTitle').html().match(/static <\/span>([\s\S]*)/); 177 | 178 | if (name) { 179 | name = name[1].trim(); 180 | } else { 181 | name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)/); 182 | if (name) { 183 | name = name[2].trim(); 184 | } else { 185 | console.log('读取method失败:\n' + url + '\n' + node.find('> .propTitle').html()); 186 | return null; 187 | } 188 | } 189 | let param = node.find('.propTitle > .propType'), 190 | snippet = '('; 191 | 192 | param = param.eq(param.length - 1).html().trim().replace('(', '').replace(')', '').split(','); 193 | if (param && param[0].trim() !== '') { 194 | param.forEach((text, index) => { 195 | snippet += (index !== 0 ? ', ' : '') + '${' + (index + 1) + ':' + text.split(':')[0].replace(/\n/g, '').trim() + '}'; 196 | }); 197 | } 198 | 199 | return { 200 | "name": name, 201 | "snippet": name + snippet + ')', 202 | "type": "method", 203 | "description": this.getDescription(node), 204 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name) 205 | } 206 | }, 207 | parsePropertie: function(node, url, key) { 208 | var name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)/); 209 | if (name) { 210 | name = name[2].trim(); 211 | return { 212 | "name": name, 213 | "text": key === 'Animated' && !!name.match(/^(Value|ValueXY)$/) ? name + '()' : name, 214 | "type": key === 'Animated' && !!name.match(/^(Value|ValueXY)$/) ? "class" : "property", 215 | "description": this.getDescription(node), 216 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name) 217 | } 218 | } else { 219 | console.log('读取propertie失败:\n' + url + '\n' + node.find('> .propTitle').html()); 220 | return null; 221 | } 222 | }, 223 | parseProp: function(node, url, key) { 224 | if (node.parent().attr('class') !== 'props') return null; 225 | var extendKey = node.find('> .propTitle').html().match(/([\s\S]*)<\/a>/); 226 | if (extendKey === null) { 227 | var name = node.find('> .propTitle').html().match(/<\/a>([\s\S]*)([\s\S]*)<\/span>/); 228 | name = name ? name : node.find('> .propTitle').html().match(/<\/a>([\s\S]*)([\s\S]*)<\/span>([\s\S]*)/)) { 233 | name = name[2].match(/([\s\S]*)<\/span>([\s\S]*)/); 234 | mobile = name[1] + ':'; 235 | name = name[2].trim(); 236 | } else { 237 | name = name[2].trim(); 238 | } 239 | let obj = { 240 | "name": name, 241 | "displayText": name, 242 | "snippet": name + '=' + (/^enum|string/.test(type) && !this.enumException(name) ? '"$1"' : '{$1}'), 243 | "type": "attribute", 244 | "description": this.getDescription(node), 245 | "descriptionMoreURL": this.getDescriptionMoreURL(url, name), 246 | "leftLabelHTML": mobile + (type.match(/(function|bool|style|string|number)/) ? type : 'object') 247 | }; 248 | if (type.indexOf('enum') !== -1) { 249 | obj.leftLabelHTML = mobile + 'enum'; 250 | obj.value = type.match(/enum\(([\s\S]*)\)/)[1].replace(/'/g, '').replace(/"/g, '').replace(/\s/g, '').split(','); 251 | } else if (type.match(/View#style/)) { 252 | obj.leftLabelHTML = mobile + 'style'; 253 | } else if (type.match(/^(\{|\[)/)) { 254 | obj.leftLabelHTML = mobile + 'object'; 255 | } 256 | return obj; 257 | } else { 258 | return extendKey[2].split(' ')[0]; 259 | } 260 | }, 261 | getDescriptionMoreURL: function(url, name) { 262 | return url.replace(/#([\s\S]*)/g, '') + '#' + name.toLowerCase(); 263 | }, 264 | getDescription: function(node) { 265 | let description = node.find('> .propTitle').eq(0).next().find('> p').eq(0).html(); 266 | description = description ? description.replace(/<\/?[^>]*>/g, '').replace(/\n/g, '').replace(/\r/g, '') : ' '; 267 | description = description && description.length > 80 ? description.substring(0, 80) : description; 268 | return description; 269 | }, 270 | getCompletionObj: function(type, name) { 271 | let completion = { 272 | "attribute": { 273 | "name": name 274 | }, 275 | "completions": [] 276 | }; 277 | if (type === 'apis') { 278 | completion.attribute.text = name; 279 | completion.attribute.type = 'class'; 280 | } else { 281 | completion.attribute.displayText = name; 282 | completion.attribute.snippet = name + (separateTags.indexOf(name) !== -1 ? '$1/>' : '$1>\n'); 283 | completion.attribute.type = 'tag'; 284 | completion.extend = []; 285 | } 286 | return completion; 287 | }, 288 | getClass: function(type, name, url, $) { 289 | let completion = this.getCompletionObj(type, name), 290 | titles = $('.inner-content > div > span > h3, .inner-content > div > h3'); 291 | 292 | for (let i = 0; i < titles.length; i++) { 293 | let title = titles.eq(i).html().match(/<\/a>/); 294 | if (title && ((title = title[1]).match(/(methods|properties|props)/))) { 295 | let props = titles.eq(i).next().find(' > .prop'); 296 | for (let j = 0; j < props.length; j++) { 297 | let obj = null; 298 | if (title === 'methods') { 299 | obj = this.parseMethod(props.eq(j), url, name); 300 | } else if (title === 'properties') { 301 | obj = this.parsePropertie(props.eq(j), url, name); 302 | } else if (title === 'props') { 303 | obj = this.parseProp(props.eq(j), url, name); 304 | } 305 | if (typeof(obj) === 'string') { 306 | completion.extend.push(obj) 307 | if (obj === 'ScrollView') { 308 | completion.extend.push('View'); 309 | } 310 | } else if (obj) { 311 | completion.completions.push(obj); 312 | } 313 | } 314 | } 315 | } 316 | return completion; 317 | }, 318 | getSubClass: function(type, name, url, $) { 319 | if (type === 'apis') { 320 | let classNodes = $('.inner-content h2'), 321 | completionList = []; 322 | for (let i = 0; i < classNodes.length; i++) { 323 | let className = classNodes.eq(i).html().match(/<\/a>class([\s\S]*) { 343 | if (error) return console.log(error + '\n' + url + '\n'); 344 | let $ = cheerio.load(body); 345 | this.outputFile(type, this.getClass(type, name, url, $)); 346 | // this.outputFile(type, this.getSubClass(type, name, url, $)); 347 | }); 348 | }, 349 | find: function() { 350 | request(docsURL, (error, response, body) => { 351 | if (error) return console.log(error + '\n' + '起始错误。'); 352 | let $ = cheerio.load(body), 353 | menuNode = $('.nav-docs .nav-docs-section'); 354 | 355 | for (let i = 0; i < menuNode.length; i++) { 356 | let title = menuNode.eq(i).find('h3').html().trim(); 357 | if (title.match(/apis|components/gi)) { 358 | let subMenuNode = menuNode.eq(i).find('ul a'); 359 | for (let j = 0; j < subMenuNode.length; j++) { 360 | this.reloadPage(title, subMenuNode.eq(j).html(), 'http://facebook.github.io/react-native/' + subMenuNode.eq(j).attr('href')); 361 | } 362 | } 363 | } 364 | }); 365 | }, 366 | enumException: function(name) { 367 | return /minuteInterval/.test(name); 368 | } 369 | }; 370 | collect.find(); 371 | // export default collect; 372 | -------------------------------------------------------------------------------- /src/helper/units.js: -------------------------------------------------------------------------------- 1 | var units = { 2 | clone: function(obj) { 3 | var newObj = {}; 4 | for (let key in obj) { 5 | newObj[key] = obj[key]; 6 | } 7 | newObj.rightLabelHTML = 'react-native'; 8 | return newObj; 9 | } 10 | }; 11 | 12 | export default units; 13 | -------------------------------------------------------------------------------- /src/modules/api.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import units from "../helper/units.js"; 3 | import completions from "../../completions/apis.json"; 4 | 5 | var propertyPrefix = 'React', 6 | propertyPrefixPattern = /(?:^|\[|\(|,|=|:|\s)\s*((React|navigator.geolocation).(?:[a-zA-Z]+\.?){0,2})$/; 7 | 8 | var API = { 9 | getCompletions: function(line) { 10 | var ref, ref1; 11 | let _completions = [], 12 | match = (ref = propertyPrefixPattern.exec(line)) !== null ? ref[1] : null; 13 | 14 | if (!match) { 15 | return _completions; 16 | } 17 | 18 | let segments = match.split('.'), 19 | propertyCompletions = (ref1 = completions[segments[segments.length - 2]]) != null ? ref1 : []; 20 | 21 | if (segments[0] == propertyPrefix) { 22 | if (segments.length == 2) propertyCompletions = completions.React; 23 | for (let i = 0, len = propertyCompletions.length; i < len; i++) { 24 | _completions.push(units.clone(propertyCompletions[i])); 25 | } 26 | } else if (segments[0] === 'navigator') { 27 | return require('../../completions/navigator.json').geolocation; 28 | } 29 | 30 | return _completions; 31 | }, 32 | setMatchRule: function(prefix) { 33 | propertyPrefix = prefix; 34 | propertyPrefixPattern = new RegExp('(?:^|\\[|\\(|,|=|:|\\s)\\s*((' + prefix + '|navigator.geolocation).(?:[a-zA-Z]+\\.?){0,2})$'); 35 | } 36 | }; 37 | 38 | export default API; 39 | -------------------------------------------------------------------------------- /src/modules/component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import units from "../helper/units.js"; 3 | import completions from "../../completions/components.json"; 4 | 5 | const trailingWhitespace = /\s$/; 6 | const attributeInput = /^([a-zA-Z][-a-zA-Z]*)$/; 7 | const attributePattern = /\s+([a-zA-Z][-a-zA-Z]*)\s*=\s*$/; 8 | const tagInput = /^<([a-zA-Z][-a-zA-Z]*|$)/; 9 | const tagNotInput = />([a-zA-Z][-a-zA-Z]*|$)/; 10 | const tagPattern = /<(([a-zA-Z][-a-zA-Z]*)|TabBarIOS.Item)(?:\s|$)/; //TabBarIOS.Item是特殊的标签 11 | 12 | var COMPONENT = { 13 | getTagNameCompletions: function() { 14 | let _completions = []; 15 | completions.tags.completions.forEach((obj) => { 16 | _completions.push(units.clone(obj)); 17 | }); 18 | return _completions; 19 | }, 20 | getAttributeNameCompletions: function(editor, bufferPosition) { 21 | let _completions = [], 22 | tag = this.getPreviousTag(editor, bufferPosition); 23 | 24 | if (completions.attributes[tag]) { 25 | completions.attributes[tag].forEach((obj) => { 26 | _completions.push(units.clone(obj)); 27 | }); 28 | } 29 | 30 | return _completions; 31 | }, 32 | getAttributeValueCompletions: function(line) { 33 | let _completions = [], 34 | attribute = this.getPreviousAttribute(line); 35 | 36 | if (completions.values[attribute]) { 37 | completions.values[attribute].forEach((text) => { 38 | _completions.push({ 39 | "text": text, 40 | "type": "value" 41 | }) 42 | }); 43 | } 44 | return _completions; 45 | }, 46 | getPreviousTag: function(editor, bufferPosition) { 47 | var ref; 48 | let row = bufferPosition.row; 49 | 50 | while (row >= 0) { 51 | ref = tagPattern.exec(editor.lineTextForBufferRow(row)); 52 | if (ref) { 53 | return ref[1] 54 | } 55 | row--; 56 | } 57 | return null; 58 | }, 59 | getPreviousAttribute: function(line) { 60 | var ref, ref1; 61 | let quoteIndex = line.length - 1; 62 | 63 | while (line[quoteIndex] && !((ref = line[quoteIndex]) === '"' || ref === "'")) { 64 | quoteIndex--; 65 | } 66 | line = line.substring(0, quoteIndex); 67 | return (ref1 = attributePattern.exec(line)) != null ? ref1[1] : null; 68 | }, 69 | isAttributeValue: function(scopes) { 70 | return this.hasTagScope(scopes) && this.hasAttributeValueScope(scopes) && !this.hasAttributeContentScope(scopes); 71 | }, 72 | isAttribute: function(prefix, scopes) { 73 | if (!trailingWhitespace.test(prefix) && !attributeInput.test(prefix)) { 74 | return false; 75 | } 76 | return (this.hasTagScope(scopes) || this.hasAttributeScope(scopes)) && !this.hasAttributeContentScope(scopes); 77 | }, 78 | isTag: function(scopes, line) { 79 | let segment = line.split(' ').pop(); 80 | 81 | return tagInput.test(segment) && !tagNotInput.test(segment) && !this.hasScopeDescriptor(scopes, [ 82 | 'string.quoted.double.jsx', 83 | 'string.quoted.single.jsx', 84 | 'string.quoted.double.js', 85 | 'string.quoted.single.js' 86 | ]) && !this.hasAttributeContentScope(scopes); 87 | }, 88 | hasTagScope: function(scopes) { 89 | return this.hasScopeDescriptor(scopes, [ 90 | 'meta.scope.tag.block', 91 | 'meta.tag.block.begin.jsx', 92 | 'meta.tag.block.end.jsx', 93 | 'entity.name.tag.jsx', 94 | 'tag.open.js', 95 | 'punctuation.definition.tag.begin.js', 96 | 'punctuation.definition.tag.end.js' 97 | ]) && !this.hasScopeDescriptor(scopes, [ 98 | 'invalid.illegal.tag.end.jsx', 99 | 'tag.closed.js' 100 | ]); 101 | }, 102 | hasAttributeScope: function(scopes) { 103 | return this.hasScopeDescriptor(scopes, [ 104 | 'entity.other.attribute-name.jsx', 105 | 'punctuation.separator.key-value.attribute.jsx' 106 | ]); 107 | }, 108 | hasAttributeValueScope: function(scopes) { 109 | return this.hasScopeDescriptor(scopes, [ 110 | 'string.quoted.double.jsx', 111 | 'string.quoted.single.jsx', 112 | 'string.quoted.double.js', 113 | 'string.quoted.single.js' 114 | ]) && this.hasScopeDescriptor(scopes, [ 115 | 'meta.scope.inner', 116 | 'punctuation.definition.string.begin.jsx', 117 | 'punctuation.definition.string.end.jsx', 118 | 'punctuation.definition.string.begin.js', 119 | 'punctuation.definition.string.end.js' 120 | ]); 121 | }, 122 | hasAttributeContentScope: function(scopes) { 123 | return this.hasScopeDescriptor(scopes, [ 124 | 'punctuation.section.embedded.begin.jsx', 125 | 'punctuation.section.embedded.end.jsx', 126 | 'punctuation.definition.brace.curly.begin.js', 127 | 'punctuation.definition.brace.curly.end.js', 128 | 'meta.brace.curly.js', 129 | 'meta.embedded.expression.jsx', 130 | /meta.embedded.expression.(\S*).jsx/ 131 | ]); 132 | }, 133 | hasScopeDescriptor: function(fromScopes, toScopes) { 134 | for (let scope of toScopes) { 135 | if (typeof(scope) === 'string') { 136 | if (fromScopes.indexOf(scope) !== -1) { 137 | return true; 138 | } 139 | } else { 140 | let pass = false 141 | for (let text of fromScopes) { 142 | if (scope.test(text)) { 143 | pass = true; 144 | } 145 | } 146 | if (pass) return true; 147 | } 148 | } 149 | return false; 150 | } 151 | }; 152 | 153 | export default COMPONENT; 154 | -------------------------------------------------------------------------------- /src/provider.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import API from "./modules/api.js"; 3 | import COMPONENT from "./modules/component.js"; 4 | 5 | const provider = { 6 | selector: '.source.js, .source.jsx', 7 | filterSuggestions: true, 8 | getSuggestions: function(request) { 9 | var prefix = request.prefix, 10 | bufferPosition = request.bufferPosition, 11 | editor = request.editor, 12 | scopes = request.scopeDescriptor.getScopesArray(), 13 | line = editor.getTextInRange([ 14 | [bufferPosition.row, 0], bufferPosition 15 | ]); 16 | 17 | return new Promise(function(resolve) { 18 | var suggestion = null; 19 | 20 | if (COMPONENT.isAttributeValue(scopes)) { 21 | suggestion = COMPONENT.getAttributeValueCompletions(line); 22 | } else if (COMPONENT.isTag(scopes, line)) { 23 | suggestion = COMPONENT.getTagNameCompletions(); 24 | } else if (COMPONENT.isAttribute(prefix, scopes)) { 25 | suggestion = COMPONENT.getAttributeNameCompletions(editor, bufferPosition); 26 | } else { 27 | suggestion = API.getCompletions(line); 28 | } 29 | resolve(suggestion); 30 | }); 31 | }, 32 | onDidInsertSuggestion: function(request) { 33 | if (request.suggestion.rightLabelHTML === 'react-native' && request.suggestion.type === 'attribute') { 34 | setTimeout(function() { 35 | atom.commands.dispatch(atom.views.getView(request.editor), 'autocomplete-plus:activate', { 36 | activatedManually: false 37 | }); 38 | }, 1); 39 | } 40 | }, 41 | setPrefix: function(prefix) { 42 | API.setMatchRule(prefix); 43 | } 44 | }; 45 | 46 | export default provider; 47 | --------------------------------------------------------------------------------