├── .editorconfig ├── formatters ├── .cfformat.json ├── cfml_format.sublime-settings └── ortus-java-style.xml ├── guides ├── coldfusion.md ├── css-sass.md ├── database.md ├── do-this-not-this-table.md ├── javascript.md └── security.md ├── linters ├── .cflintrc ├── .cflintrc-handlers ├── .editorconfig ├── .eslintrc.json ├── .jsbeautifyrc ├── .jshintrc └── .sass-lint.yml ├── readme.md └── resources ├── ortus-spaceman.jpg ├── sublime-format-settings.png └── vscode-beautify-settings.png /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = false 10 | indent_style = tab 11 | indent_size = 4 12 | tab_width = 4 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{md,markdown}] 19 | trim_trailing_whitespace = false 20 | insert_final_newline = false -------------------------------------------------------------------------------- /formatters/.cfformat.json: -------------------------------------------------------------------------------- 1 | { 2 | "array.empty_padding": false, 3 | "array.padding": true, 4 | "array.multiline.min_length": 50, 5 | "array.multiline.element_count": 2, 6 | "array.multiline.leading_comma.padding": true, 7 | "array.multiline.leading_comma": false, 8 | "alignment.consecutive.assignments": true, 9 | "alignment.consecutive.properties": true, 10 | "alignment.consecutive.params": true, 11 | "alignment.doc_comments" : true, 12 | "brackets.padding": true, 13 | "comment.asterisks": "align", 14 | "binary_operators.padding": true, 15 | "for_loop_semicolons.padding": true, 16 | "function_call.empty_padding": false, 17 | "function_call.padding": true, 18 | "function_call.multiline.leading_comma.padding": true, 19 | "function_call.casing.builtin": "cfdocs", 20 | "function_call.casing.userdefined": "camel", 21 | "function_call.multiline.element_count": 3, 22 | "function_call.multiline.leading_comma": false, 23 | "function_call.multiline.min_length": 50, 24 | "function_declaration.padding": true, 25 | "function_declaration.empty_padding": false, 26 | "function_declaration.multiline.leading_comma": false, 27 | "function_declaration.multiline.leading_comma.padding": true, 28 | "function_declaration.multiline.element_count": 3, 29 | "function_declaration.multiline.min_length": 50, 30 | "function_declaration.group_to_block_spacing": "compact", 31 | "function_anonymous.empty_padding": false, 32 | "function_anonymous.group_to_block_spacing": "compact", 33 | "function_anonymous.multiline.element_count": 3, 34 | "function_anonymous.multiline.leading_comma": false, 35 | "function_anonymous.multiline.leading_comma.padding": true, 36 | "function_anonymous.multiline.min_length": 50, 37 | "function_anonymous.padding": true, 38 | "indent_size": 4, 39 | "keywords.block_to_keyword_spacing": "spaced", 40 | "keywords.group_to_block_spacing": "spaced", 41 | "keywords.padding_inside_group": true, 42 | "keywords.spacing_to_block": "spaced", 43 | "keywords.spacing_to_group": true, 44 | "keywords.empty_group_spacing": false, 45 | "max_columns": 115, 46 | "metadata.multiline.element_count": 3, 47 | "metadata.multiline.min_length": 50, 48 | "method_call.chain.multiline" : 3, 49 | "newline":"\n", 50 | "property.multiline.element_count": 3, 51 | "property.multiline.min_length": 30, 52 | "parentheses.padding": true, 53 | "strings.quote": "double", 54 | "strings.attributes.quote": "double", 55 | "struct.separator": " : ", 56 | "struct.padding": true, 57 | "struct.empty_padding": false, 58 | "struct.multiline.leading_comma": false, 59 | "struct.multiline.leading_comma.padding": true, 60 | "struct.multiline.element_count": 2, 61 | "struct.multiline.min_length": 60, 62 | "tab_indent": true 63 | } 64 | -------------------------------------------------------------------------------- /formatters/cfml_format.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | // default commands to run when calling cfml_format 3 | "default_commands": ["keywords", "blocks", "delimited_scopes", "method_chains", "normalize_strings", "normalize_builtin_functions"], 4 | "singleline_max_col": 180, 5 | "brackets": { 6 | "padding": "spaced", // "spaced|compact" 7 | "padding_strip_newlines": true 8 | }, 9 | "parentheses": { 10 | "padding": "spaced", // "spaced|compact" 11 | "padding_strip_newlines": false 12 | }, 13 | "keywords": { 14 | "block_to_keyword_spacing": "spaced", // "newline|spaced|compact" - only applies to `else`, `else if`, `while`, `catch` 15 | "to_keyword_spacing": null, // "newline|emptyline" - applies to anything other than a comment 16 | "spacing_to_group": "compact", // "spaced|compact" - eg: `if (condition)` vs `if(condition)` 17 | "spacing_to_block": "compact", // "newline|spaced|compact" 18 | "empty_group_spacing": "compact", // "spaced|compact" 19 | "padding_inside_group": "spaced", // "spaced|compact" 20 | "padding_strip_newlines": false, // never ignored, truthy value - set `padding_inside_group` to null to avoid formatting 21 | "group_to_block_spacing": "compact" // "newline|spaced|compact" 22 | }, 23 | "blocks": { 24 | "empty_spacing": "newline", // "spaced|compact|newline|emptyline" 25 | "start_spacing": null, // "newline|emptyline" 26 | "end_spacing": "newline", // "newline|emptyline" 27 | "after_block_spacing": null // "newline|emptyline" 28 | }, 29 | "array": { 30 | "empty_spacing": "spaced", // "spaced|compact" 31 | "padding_inside": "spaced", // "spaced|compact" 32 | "after_comma_spacing": "spaced", // "spaced|compact" 33 | "multiline": { 34 | "element_count": 4, // always split onto multiple lines, if there are at least this many elements 35 | "leading_comma": false 36 | } 37 | }, 38 | "struct": { 39 | "empty_spacing": "compact", // "spaced|compact" 40 | "padding_inside": "spaced", // "spaced|compact" 41 | "key_value_colon": "spaced", // "spaced|compact" 42 | "key_value_equals": "spaced", // "spaced|compact" 43 | "after_comma_spacing": "spaced", // "spaced|compact" 44 | "multiline": { 45 | "element_count": 4, // always split onto multiple lines, if there are at least this many elements 46 | "leading_comma": false 47 | } 48 | }, 49 | "function_declaration": { 50 | "empty_spacing": "spaced", // "spaced|compact" 51 | "padding_inside": "spaced", // "spaced|compact" 52 | "after_comma_spacing": "spaced", // "spaced|compact" 53 | "spacing_to_group": "compact", // "spaced|compact" - e.g. `function name()` vs `function name ()` 54 | "group_to_block_spacing": "compact", // "newline|spaced|compact" 55 | "multiline": { 56 | "element_count": 5, // always split onto multiple lines, if there are at least this many elements 57 | "leading_comma": false 58 | } 59 | }, 60 | "function_call": { 61 | "empty_spacing": "compact", // "spaced|compact" 62 | "padding_inside": "spaced", // "spaced|compact" 63 | "after_comma_spacing": "spaced", // "spaced|compact" 64 | "multiline": { 65 | "element_count": 4, // always split onto multiple lines, if there are at least this many elements 66 | "leading_comma": false, 67 | "break_after_first_element": false // break after first element and align other elements to it 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /formatters/ortus-java-style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /guides/coldfusion.md: -------------------------------------------------------------------------------- 1 | # Ortus ColdFusion (CFML) Standards & Best Practices 2 | 3 | 4 | ## Table of Contents 5 | 6 | 1. [Introduction](#introduction) 7 | 1. [IDE Tools](#idetools) 8 | 1. [Naming & Conventions](#naming-conventions) 9 | 1. [Abbreviations](#abbreviations) 10 | 1. [Acronyms](#acronyms) 11 | 1. [Package Names](#package-names) 12 | 1. [Class/Component/Interface Names](#object-names) 13 | 1. [Methods](#methods) 14 | 1. [Types](#types) 15 | 1. [Tags](#tags) 16 | 1. [Arguments & Variables](#arguments) 17 | 1. [Constants](#constants) 18 | 1. [Whitespaces](#whitespace) 19 | 1. [Code Blocks](#code-blocks) 20 | 1. [Multi-Argument Declarations](#multi-argument) 21 | 1. [Multi-Argument Function Calls](#multi-function) 22 | 1. [Parenthesis Whitespace](#parenthesis) 23 | 1. [Method Chaining](#method-chaining) 24 | 1. [Object Creation](#object-creation) 25 | 1. [End of Lines](#eof) 26 | 1. [Components](#cfc) 27 | 1. [CFC Documentation](#cfc-documentation) 28 | 1. [CFC Scopes](#cfc-scopes) 29 | 1. [CFC Constructors](#cfc-constructors) 30 | 1. [CFC Var Scoping](#cfc-varscoping) 31 | 1. [CFC Output](#cfc-output) 32 | 1. [CFC Return Types](#cfc-returntypes) 33 | 1. [CFC External Scopes](#cfc-external-scopes) 34 | 1. [CFC Default Arguments](#cfc-default-arguments) 35 | 1. [CFC Inheritance vs Composition](#cfc-inheritance) 36 | 1. [General Best Practices](#general) 37 | 1. [ColdBox Best Practices](#coldbox) 38 | 39 | 40 | ## Introduction 41 | 42 | This document is intended to be a concise summary of best practices for anyone building CFML applications within the Ortus team. Several external resources used when creating this document. Please note that this is a guideline based on past development experience and industry standards. Please use common sense when applying them and note that this document is ever changing as development trends continue to change. 43 | 44 | * Hardly any software is maintained by the original author. Be Kind! 45 | * Coding conventions improve readability, code reviews, and just bring sanity to a team 46 | * Automated documentation tools like [DocBox](https://docbox.ortusbooks.com/) will help generate automated documentation from all of your source code. Use it! 47 | 48 | **[[⬆]](#TOC)** 49 | 50 | 51 | ## IDE Tools 52 | 53 | * [VSCode ColdBox](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-coldbox) 54 | * [VSCode CommandBox](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-commandbox) 55 | * [VSCode TestBox](https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-testbox) 56 | * [Eclipse Java Cleanup](https://drive.google.com/open?id=0B3aRjVTf2SeqSUZDbW5UUjVwOU0) 57 | * [Java Styles](https://github.com/Ortus-Solutions/coding-standards/blob/master/ortus-java-style.xml) 58 | * [Sublime ColdBox Platform](https://packagecontrol.io/packages/ColdBox%20Platform) 59 | 60 | **[[⬆]](#TOC)** 61 | 62 | 63 | ## Naming & Conventions 64 | 65 | Use good names for components, methods, arguments and local variables. This can sometimes be a disaster if developers choose random names or non qualified names for methods, arguments and local variables. Naming is very important and will most of the time document your code. Always remember to use meaningful names and stay away from cryptic abbreviations or naming strategies. 66 | 67 | 68 | **[[⬆]](#TOC)** 69 | 70 | 71 | ### Abbreviations 72 | 73 | AVOID abbreviations if possible. For example, `calculateSalary()` is a better method name than `calcSalary()`. Although you can use well known abbreviations, please try to avoid them if possible. Here are some *examples* NOT RULES: 74 | 75 | - **acc** for accessibility, as in ButtonAccImpl 76 | - **auto** for automatic, as in autoLayout 77 | - **eval** for evaluate, as in EvalBindingResponder 78 | - **impl** for implementation, as in ButtonAccImpl 79 | - **info** for information, as in GridRowInfo 80 | - **num** for number of, as in numChildren 81 | - **min** for minimum, as in minWidth 82 | - **max** for maximum, as in maxHeight 83 | - **nav** for navigation, as in NavBar 84 | - **regex** for regular expression, as in RegexValidator 85 | - **util** for utility, as in StringUtil 86 | 87 | 88 | **[[⬆]](#TOC)** 89 | 90 | ### Acronyms 91 | 92 | Acronyms should be avoided in names, but if they must be used, then treat them with the same Camelcase rules for classes or methods/arguments/variables: 93 | 94 | 95 | | ✅ DO THIS | ❌ NOT THIS | 96 | |-------------------------|-------------------------| 97 | | ```UrlScanner.cfc``` | ```url-scanner.cfc``` | 98 | | ```UrlScanner.cfc``` | ```urlscanner.cfc``` | 99 | | ```parseHttpString()``` | ```parseHTTPString()``` | 100 | | ```parseHttpString()``` | ```ParseHttpString()``` | 101 | | ```XmlHttpRequest.cfc```| ```xmlHTTPRequest.cfc```| 102 | | ```XmlHttpRequest.cfc```| ```XmlHTTPRequest.cfc```| 103 | 104 | 105 | * [Java Coding Standards](http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html) 106 | 107 | 108 | **[[⬆]](#TOC)** 109 | 110 | 111 | 112 | ### Package Names 113 | 114 | Package names should be unique and in lowercase letters. Underscores may be used or hyphens if necessary, but try to avoid them. You can package your objects/files using two well known approaches: 115 | 116 | 1. By Functionality (Best Practice) 117 | 2. By object types 118 | 119 | The best practice is to use packaging by functionality if at all possible. Here is an example from an application's model or business layer folder: 120 | 121 | ``` 122 | - model 123 | - security 124 | - remote-api 125 | - products 126 | - users 127 | - customers 128 | - invoices 129 | - templates 130 | - conversions 131 | - util 132 | ``` 133 | 134 | 135 | **[[⬆]](#TOC)** 136 | 137 | 138 | ### Class/Component/Interface Names 139 | 140 | Class/Component/Interface names should be nouns, as they represent most likely things or objects. They should be written in camel case with only the **first** letter capitalized for each word. Use whole words and avoid acronyms and abbreviations if possible. Interfaces should begin with the letter **I**. Base or abstract classes should denote themselves in the name as well as either **BaseClass or AbstractClass**. Examples: 141 | 142 | 143 | | ✅ DO THIS | ❌ NOT THIS | 144 | |----------------|---------------------| 145 | | ```URLConverter``` | ```urlConverter``` | 146 | | ```RSSReader``` | ```rssreader``` | 147 | | ```Serializable``` | ```serializable``` | 148 | | ```ISearchEngine``` | ```iSearchEngine``` | 149 | | ```IResults``` | ```results``` | 150 | | ```BaseEntity``` | ```entityToRuleThemAll``` | 151 | | ```AbstractLogger``` | ```ALogger``` | 152 | 153 | 154 | **[[⬆]](#TOC)** 155 | 156 | 157 | 158 | ### Methods 159 | 160 | Methods should be verbs, in mixed camel case with the **first** letter lower cased and then each internal first letter of words capitalized. If the method returns a boolean, try to use a boolean readable expression. Examples: 161 | 162 | 163 | 164 | 165 | 168 | 171 | 172 | 173 | 174 | 175 | 183 | 184 | 192 | 193 | 194 | 195 |
166 | ✅ DO THIS 167 | 169 | ❌ NOT THIS 170 |
176 |
 177 | run()
 178 | doThis()
 179 | executeInBackground()
 180 | isLocated()
 181 | 
182 |
185 |
 186 | RUN()
 187 | dothis()
 188 | executeINBackGround()
 189 | located()
 190 | 
191 |
196 | 197 | 198 | **[[⬆]](#TOC)** 199 | 200 | 201 | ### Type Names 202 | 203 | All ColdFusion type names in arguments, return types and the like should all be in lower case when they are native ColdFusion types. If they are components they should be the EXACT name of the component. This is extremely important if for some reason the code executes in a case-sensitive system, then the code will not work. ALWAYS have the exact case of components and definitions. If no type is defined, then it is assumed it is uses the **any** type. 204 | 205 | 206 | 207 | 208 | 211 | 214 | 215 | 216 | 217 | 218 | 225 | 226 | 233 | 234 | 235 | 236 | 237 |
209 | ✅ DO THIS 210 | 212 | ❌ NOT THIS 213 |
219 |
 220 | function test( array paths, model.users.User user ){}
 221 | boolean function isDone(){}
 222 | SecurityService function getSecurityService();
 223 | 
224 |
227 |
 228 | <CFARGUMENT name="paths" type="ARRAY" >
 229 | <cfargument NAME="user" type="model.users.user" >
 230 | <cffunction name="getSecurityService" returnType="model.security.SECURITYSERVICE" >
 231 | 
232 |
238 | 239 | **[[⬆]](#TOC)** 240 | 241 | 242 | ### CFML Tags, Custom Tags and Attributes 243 | 244 | All CFML and custom tags should be writing in lower case form, just like HTML tags. Attributes for CFML tags should follow the same behavior as arguments and variables as seen below. If attributes can all be placed in one line, then do that. However, if they will span and cause breaks, consider breaking the attributes into multiple lines and aligning them to the first attribute. Usually, you can do 2 or 3 in one line, else break. Same goes for method calls. 245 | 246 | 247 | 248 | 249 | 252 | 255 | 256 | 257 | 258 | 259 | 272 | 273 | 286 | 287 | 288 | 289 | 290 |
250 | ✅ DO THIS 251 | 253 | ❌ NOT THIS 254 |
260 |
 261 | <cfhttp url="...">
 262 | <cfabort>
 263 | <cfdump var="#session#">
 264 | <!-- Single Line cfhttp -->
 265 | <cfhttp url="#urladdress#" method="GET" resolveurl="Yes" throwOnError="Yes"/>
 266 |  
 267 |  
 268 |  
 269 |  
 270 | 
271 |
274 |
 275 | <CFHTTP>
 276 | <CFABORT>
 277 | <CFDump Var="#session#">
 278 | 
 279 | <!-- Unecessary Multi Line -->
 280 | <cfhttp url="#urladdress#" 
 281 | method="GET" 
 282 | resolveurl="Yes" 
 283 | throwOnError="Yes"/>
 284 | 
285 |
291 | 292 | 293 | **[[⬆]](#TOC)** 294 | 295 | 296 | ### Arguments and Variables 297 | 298 | They should be descriptive lowercase single words, acronyms or abbreviations. If multiple words are necessary they should follow camel case with first letter lowercase. Examples: 299 | 300 | 301 | 302 | 303 | 306 | 309 | 310 | 311 | 312 | 313 | 318 | 319 | 324 | 325 | 326 | 327 | 328 | 329 | 334 | 335 | 340 | 341 | 342 | 343 | 344 | 345 | 350 | 351 | 356 | 357 | 358 | 359 |
304 | ✅ DO THIS 305 | 307 | ❌ NOT THIS 308 |
314 |
 315 | niceLocation = "Miami";
 316 | 
317 |
320 |
 321 | NICELOCATION = "Miami";
 322 | 
323 |
330 |
 331 | results = "";
 332 | 
333 |
336 |
 337 | Results = "";
 338 | 
339 |
346 |
 347 | avgSalary = "323";
 348 | 
349 |
352 |
 353 | average-salary = "323";
 354 | 
355 |
360 | 361 | 362 | **[[⬆]](#TOC)** 363 | 364 | 365 | ### Constants or Static Variables 366 | 367 | They should all be in upper case separated by underscores "\_". Examples: 368 | 369 | 370 | 371 | 372 | 375 | 378 | 379 | 380 | 381 | 382 | 387 | 388 | 393 | 394 | 395 | 396 | 397 | 398 | 403 | 404 | 409 | 410 | 411 | 412 | 413 | 414 | 419 | 420 | 425 | 426 | 427 | 428 |
373 | ✅ DO THIS 374 | 376 | ❌ NOT THIS 377 |
383 |
 384 | INTERCEPTOR_POINTS = "";
 385 | 
386 |
389 |
 390 | interceptor-points = "";
 391 | 
392 |
399 |
 400 | LINE_SEP = "-";
 401 | 
402 |
405 |
 406 | line_sep = "-";
 407 | 
408 |
415 |
 416 | MAX = "123";
 417 | 
418 |
421 |
 422 | max = "123";
 423 | 
424 |
429 | 430 | 431 | **[[⬆]](#TOC)** 432 | 433 | 434 | ## Whitespaces 435 | 436 | This is more of a convenience for readability and preference, but these are the standards we set forward for consistency and for making code reviews easier to scan with the eyes. 437 | 438 | 439 | **[[⬆]](#TOC)** 440 | 441 | ### Code Blocks 442 | 443 | Code blocks should start in one line and end in another. 444 | 445 | 446 | 447 | 448 | 451 | 454 | 455 | 456 | 457 | 458 | 485 | 486 | 505 | 506 | 507 | 508 |
449 | ✅ DO THIS 450 | 452 | ❌ NOT THIS 453 |
459 |
 460 | component{
 461 | }
 462 | 
 463 | try{
 464 | }
 465 | 
 466 | transaction{
 467 | 
 468 | }
 469 | 
 470 | thread{
 471 | 
 472 | }
 473 | 
 474 | for( var x = 1; x lte 10; x++ ){
 475 | 
 476 | }
 477 | 
 478 | if( false ){
 479 | } else if( XX ){
 480 | } else {
 481 | }
 482 | 
  483 |
484 |
487 |
 488 | component
 489 | {
 490 | }
 491 | try {
 492 | }
 493 | try
 494 | {
 495 | }
 496 | if( ) {
 497 | }
 498 | if()
 499 | {
 500 | }
 501 | else{ 
 502 | }
 503 | 
504 |
509 | 510 | 511 | 512 | **[[⬆]](#TOC)** 513 | 514 | ### Multi-Argument Declarations 515 | 516 | When declaring 4 arguments or more go into multi-line layout 517 | 518 | 519 | 520 | 521 | 524 | 527 | 528 | 529 | 530 | 531 | 545 | 546 | 558 | 559 | 560 | 561 |
522 | ✅ DO THIS 523 | 525 | ❌ NOT THIS 526 |
532 |
 533 | function testThis(
 534 | 	required name,
 535 | 	required any target,
 536 | 	boolean isHappy="true",
 537 | 	any results
 538 | 	){
 539 |   
 540 |   ... function here
 541 | 
 542 | }
 543 | 
544 |
547 |
 548 | function testThis(required name, required any target, boolean isHappy="true", any results){
 549 | }
 550 | 
  551 |
  552 |
  553 |
  554 |
  555 |
  556 |
557 |
562 | 563 | 564 | **[[⬆]](#TOC)** 565 | 566 | ### Multi-Argument Function Calls 567 | 568 | When calling a function with 4 arguments or more go into multi-line layout: 569 | 570 | 571 | 572 | 573 | 576 | 579 | 580 | 581 | 582 | 583 | 593 | 594 | 604 | 605 | 606 | 607 |
574 | ✅ DO THIS 575 | 577 | ❌ NOT THIS 578 |
584 |
 585 | obj.callMethod( 
 586 | 	target 		= this,
 587 | 	name 		= "luis",
 588 | 	results		= true,
 589 | 	moreData 	= "false" 
 590 | ); 
 591 | 
592 |
595 |
 596 | obj.callMethod( target=this, name="luis", results=true, moreData="false" ); 
 597 | 
  598 |
  599 |
  600 |
  601 |
  602 |
603 |
608 | 609 | **[[⬆]](#TOC)** 610 | 611 | 612 | 613 | ### Parenthesis Whitespace 614 | 615 | Try to always leave a start and ending whitespace for parenthesis code like in method calls, evaluations, etc. 616 | 617 | 618 | 619 | 620 | 623 | 626 | 627 | 628 | 629 | 630 | 648 | 649 | 666 | 667 | 668 | 669 |
621 | ✅ DO THIS 622 | 624 | ❌ NOT THIS 625 |
631 |
 632 | obj.callMethod( 
 633 | 	target 		= this,
 634 | 	name 		= "luis",
 635 | 	results		= true,
 636 | 	moreData 	= "false" 
 637 | ); 
 638 |  
 639 | obj.test( this );
 640 | obj.setData( 1 * total + 4 );
 641 | if( x lt 4 ){
 642 | }
 643 | for( var x=1; x lte 45; x++ ){
 644 | }
 645 | return ( structKeyExists( local, "results" ) ? local.results : "null" );
 646 | 
647 |
650 |
 651 | obj.callMethod(target=this, name="luis", results=true, moreData="false"); 
 652 | obj.test(this);
 653 | obj.setData(1*total+4);
 654 | if(x lt 4){
 655 | }
 656 | for(var x=1;x lte 45;x++ ){
 657 | }
 658 | return(structKeyExists(local,"results")?local.results:"null");
 659 | 
  660 |
  661 |
  662 |
  663 |
  664 |
665 |
670 | 671 | **[[⬆]](#TOC)** 672 | 673 | 674 | ### Method Chaining 675 | 676 | When using method chaining and libraries that encourage this, remember that they do it for convenience and also readability. Do not chain for up to 1000 levels, use 2 or 3 and then break. 677 | 678 | 679 | 680 | 681 | 684 | 687 | 688 | 689 | 690 | 691 | 707 | 708 | 726 | 727 | 728 | 729 |
682 | ✅ DO THIS 683 | 685 | ❌ NOT THIS 686 |
692 |
 693 | obj.$( "test", this ).$args( 1,2,3,4 ).$results( this )
 694 |   .$( "another", method() )
 695 |   .$( "another", method());
 696 | 
697 | map( "MyCFC" ) 698 | .toPath( "this.path.Component" ) 699 | .asSingleton(); 700 |
701 | var c = newCriteria() 702 | .isEq( "id", arguments.id ) 703 | .createAlias( "orders", "o" ) 704 | .isIn( "o.tags", arguments.tags ); 705 |
706 |
709 |
 710 | obj.$("test", this).$args(1,2,3,4).$results(this).$("another", method() );
 711 | 
 712 | map( "MyCFC" ).toPath( "this.path.Component" ).asSingleton();
 713 | 
 714 | var c = newCriteria().isEq( "id", arguments.id ).createAlias( "orders", "o" ).isIn( "o.tags", arguments.tags );
 715 | 
  716 |
  717 |
  718 |
  719 |
  720 |
  721 |
  722 |
  723 |
  724 |
725 |
730 | 731 | 732 | **[[⬆]](#TOC)** 733 | 734 | ## Prefer *new* over *CreateObject* 735 | 736 | Prefer the `new` declaration over the `createObject` declaration to improve readability: 737 | 738 | 739 | 740 | 741 | 742 | 745 | 748 | 749 | 750 | 751 | 752 | 757 | 758 | 763 | 764 | 765 | 766 |
743 | ✅ DO THIS 744 | 746 | ❌ NOT THIS 747 |
753 |
 754 | obj = new coldbox.system.testing.TestBox();
 755 | 
756 |
759 |
 760 | obj = createObject( "component", "coldbox.system.testing.testBox" ).init();
 761 | 
762 |
767 | 768 | 769 | > However, please note that this conventions are only if you are writing libraries. If you are within an ecosystem that provides WireBox Dependency Injection, then **always** prefer WireBox. 770 | 771 | 772 | **[[⬆]](#TOC)** 773 | 774 | ## End of Line on Files 775 | 776 | Do not add extra lines to files when ending them: 777 | 778 | ``` coldfusion 779 | // dont this 780 | component{ 781 | ..... 782 | } 783 | ``` 784 | 785 | 786 | **[[⬆]](#TOC)** 787 | 788 | 789 | 790 | ## Components 791 | 792 | ### Documentation 793 | 794 | Yes, you will need to document **ALL** of your code, from classes to property definitions to code blocks to arguments. Our preference is to write all logic in script and **not** in tags unless we are targeting a specific CFML Engine. We leverage [DocBox](https://github.com/Ortus-Solutions/DocBox) for reading, parsing and creating documentation out of all CFCs in an application. Please also refer to the [Custom Anotations](https://github.com/Ortus-Solutions/DocBox/wiki/List-of-Custom-Annotations) that DocBox applies so you can extend the metadata in a CFC. The DockBlockr plugin is magnificent for this. 795 | 796 | 797 | ``` js 798 | /** 799 | * @author Luis Majano 800 | * 801 | * My component documentation 802 | * goes here in multiple lines if needed 803 | * You can add links and valid HTML if needed 804 | * 805 | * Copyright or License Information goes here 806 | */ 807 | component accessors="true"{ 808 | 809 | /** 810 | * First name of the user 811 | */ 812 | property name="firstName"; 813 | 814 | /** 815 | * Last name of the user 816 | */ 817 | property name="lastName"; 818 | 819 | /** 820 | * Constructor 821 | */ 822 | function init(){ 823 | return this; 824 | } 825 | 826 | /** 827 | * Submit an order 828 | * 829 | * @product The product object 830 | * @coupon The Coupon code needed 831 | * @results The results object 832 | * 833 | * @throws InvalidArgumentException - When an invalid product is sent 834 | * @throws InvalidCouponCode - When an invalid coupon is sent 835 | * 836 | * @return An Order object 837 | */ 838 | Order function submitOrder( required product, coupon="", boolean results=true ){ 839 | } 840 | 841 | } 842 | ``` 843 | 844 | **[[⬆]](#TOC)** 845 | 846 | ### Scopes 847 | 848 | 849 | Components can have instance data that can be placed in two different visibility scopes: **private** and **public**. Private variables are declared in the `variables` scope and public variables in the `this` scope. This means that the variables in the `this` scope will be available for modification from the outside world, while the `variables` scope is not accessible from the outside world directly. 850 | 851 | The only way to manipulate these private variables would be through methods that your object will expose to the outside world. This is called data-hiding or encapsulation. 852 | 853 | 854 | #### Use Accessors 855 | 856 | Leverage implicit getters and setters in all component declarations instead of creating getters and setters manually, unless you need to add behavior to them: 857 | 858 | ``` js 859 | component accessors="true"{ 860 | 861 | property name="firstName"; 862 | property name="lastName"; 863 | } 864 | ``` 865 | 866 | 867 | Be very careful of when to make internal properties public as you will be violating encapsulation (look at next point). One of the best reasons for making variables public is if they do not change and can act like static constants. If your variable does not meet this criteria, then DO NOT expose it as public. 868 | 869 | ``` coldfusion 870 | 871 | 872 | 873 | ``` 874 | 875 | 876 | > Even though you are treating these variables like final static variables they CAN still be modified as ColdFusion does not support *final or static* variables (Lucee does in 5+). It is more of a convention and agreement to use this approach. 877 | 878 | **[[⬆]](#TOC)** 879 | 880 | ### Encapsulation 881 | 882 | Encapsulation provides the basis for modularity by hiding information from unwanted outside access and attaching that information to only methods that need access to it. This binds data and operations tightly together and separates them from external access that may corrupt/change them intentionally or unintentionally. Encapsulation is achieved by declaring variables as private in a CFC (`variables` scope). 883 | 884 | This gives access to data to only public/package member functions of the CFC. You can then create their mutators (setters) and accessors (getters) via public methods. Some benefits of encapsulation are: 885 | 886 | - You can keep the exposed API the same while changing how your CFC works internally without breaking any code that uses your CFC 887 | - Prevents the developer from getting in trouble by violating your internal assumptions about how the instance data works 888 | - It hides your implementation from the outside world 889 | 890 | 891 | 892 | 893 | 894 | 895 | 898 | 901 | 902 | 903 | 904 | 905 | 911 | 912 | 918 | 919 | 920 | 921 |
896 | ✅ DO THIS 897 | 899 | ❌ NOT THIS 900 |
906 |
 907 | stuff = myCFC.getStuff();
 908 | myCFC.setStuff( stuff );
 909 | 
910 |
913 |
 914 | stuff = myCFC.stuff;
 915 | myCFC.stuff = stuff;
 916 | 
917 |
922 | 923 | **[[⬆]](#TOC)** 924 | 925 | ### Constructors 926 | 927 | Always have an `init()` method that acts as your constructor and returns `this` (unless you are building a web services/flash remoting facade). Even if the method has a simple return statement, it is always best practice that every object have a constructor method. 928 | 929 | ```js 930 | component{ 931 | function init(){ 932 | return this; 933 | } 934 | } 935 | ``` 936 | 937 | If you are using inheritance then you must call the parent constructor by accessing the `super` scope. 938 | 939 | ```js 940 | component extends="BaseConverter"{ 941 | function init(){ 942 | super.init(); 943 | return this; 944 | } 945 | } 946 | ``` 947 | 948 | **[[⬆]](#TOC)** 949 | 950 | ### Var Scoping 951 | 952 | 953 | Always, always, always use `var` or the `local` scope for local variables inside your methods, including ALL loop counters, temporary variables, queries, etc. This is called **var scoping**. If you do not do this, your component will not be thread-safe. 954 | 955 | This means that if somebody persists (stores) this component in memory, subsequent calls can and will override variables and create all sorts of memory problems. There is an open source project called [http://www.schierberl.com/cfblog/index.cfm/2006/7/20/varScoper-10-release varscoper] that can check all of your components for var scoping issues, even if they are using cfscript. Var scoping applies to methods inside components and also to UDF's/Closures in order to comply with best practices. 956 | 957 | 958 | 959 | 960 | 963 | 966 | 967 | 968 | 969 | 970 | 982 | 983 | 995 | 996 | 997 | 998 |
961 | ✅ DO THIS 962 | 964 | ❌ NOT THIS 965 |
971 |
 972 | <cffunction name="myFunction" access="public" returntype="void" output="false" hint="This methods does nothing">
 973 |   <cfset var i = 0>
 974 |   <cfset var qGet = "">
 975 |   <cfquery name="qGet">
 976 |   </cfquery>
 977 |   <cfloop from="1" to ="20" index="i">
 978 |   </cfloop>
 979 | </cffunction>
 980 | 
981 |
984 |
 985 | <cffunction name="myFunction" access="public" returntype="void" output="false" hint="This methods does nothing">
 986 | <cfquery name="qGet">
 987 | </cfquery>
 988 | <cfloop from="1" to ="20" index="i">
 989 | </cfloop>
 990 | </cffunction>
 991 | 
  992 |
  993 |
994 |
999 | 1000 | **[[⬆]](#TOC)** 1001 | ### Output From CFCs 1002 | 1003 | Always (*with rare exceptions*) use `output="false"` in your function and components. Do not output directly to the buffer inside a CFC method; instead return a string from the method. The main reason is that you don't want to break encapsulation. By outputting directly to the output stream you assume knowledge of the external environment of the CFC. However, if you return a string then you get the exact same behavior when you do `#myCFC.someHTMLGeneratingMethod()#` but you gain the advantage of not assuming that's how your method will be used. For instance, what if the method that returns the string is used inside of a big `cfscript` block where someone is building a string via concatenation? Everything will break. 1004 | 1005 | ```js 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | ``` 1012 | 1013 | **[[⬆]](#TOC)** 1014 | ### Return Types & Duck Typing 1015 | 1016 | 1017 | Use the `returnType` attribute of the functions and the `type` attribute of the argument add documentation and runtime type checking. Also remember that `void` is the return type when your method call does not return anything. 1018 | 1019 | Duck Typing is when you use the return type or type of `any`. This is a useful technique when dealing with a dynamic language such as ColdFusion. This means that the argument or object returned can be ANYTHING, which then your caller needs to determine what to do with it and what it is based on pre-determined conventions. Usually you will need to document this in a `@return ` annotation within your function call to document the possibilities. 1020 | 1021 | A side effect of not using a strong type is a speed enhancement, since ColdFusion does not check the validity of the types. This side effect should not be used to get more performance, unless absolutely necessary. 1022 | This dynamic nature of arguments and return types brings forth great power in a dynamic language, but it also opens holes for runtime exceptions. However, thanks to unit testing, these runtime exceptions should be minimized. So as a followup guideline to duck typing is that you must have unit tests for these components. 1023 | 1024 | **[[⬆]](#TOC)** 1025 | ### Referencing External Scopes 1026 | 1027 | Do not directly reference external scopes, i.e.: session/application/client/server/request variables, inside a CFC. If you reference external scopes you will be breaking the encapsulation and cohesiveness of the component at hand. You have now binded the component to an external scope that must exist in order for this component to work. This also provides difficulties when unit testing. 1028 | 1029 | However, the one exception to referencing external scopes is when building **facades**, especially for web services/flash remoting, in which case ALL references to shared scope variables should be encapsulated within the facade. This means, for instance, passing in the dsn instead of referring to application.dsn when doing database queries. If you do not know what a facade is, then please search for facade pattern to learn more about it. It basically encapsulates a shared scope such as application,session, etc into a CFC. 1030 | 1031 | **[[⬆]](#TOC)** 1032 | ### Default Arguments 1033 | 1034 | In general, non-required arguments of a CFC method should have a default value specified, unless you will be programmatically checking for existence using `structKeyExists(arguments, "key")`, which sometimes is useful. 1035 | 1036 | ```js 1037 | 1038 | 1039 | ``` 1040 | 1041 | **[[⬆]](#TOC)** 1042 | 1043 | ### Inheritance & Composition 1044 | 1045 | Use inheritance only when describing an **is-a** relationship, not for a **has-a** relationship (composition) or for code reuse only. For a nice summary, visit http://cnx.rice.edu/content/m11709/latest/ 1046 | 1047 | Do not use a component as a huge glorified set of methods and call that code reuse. Components are synonymous to objects, they should have an identity upon themselves. Put in practice your [Ontology](http://en.wikipedia.org/wiki/Ontology) skills and define what the CFC will do for you and what is their identity. 1048 | 1049 | Always prefer object composition over inheritance. This is where another component is created or injected as a property of the object at hand. There are several reasons of why to choose composition over inheritance in order to make your designs more flexible and not coupled at compile time, which inheritance does. Composition brings in functionality at runtime as you can switch implementations, etc. Some resources are: 1050 | 1051 | * https://en.wikipedia.org/wiki/Composition_over_inheritance 1052 | * http://www.artima.com/lejava/articles/designprinciples4.html 1053 | * http://web.archive.org/web/20090225065341/http://guidewiredevelopment.wordpress.com/2008/02/05/favoring-composition-over-inheritance/ 1054 | 1055 | **[[⬆]](#TOC)** 1056 | 1057 | ## General Best Practices 1058 | 1059 | * Avoid using `Application.cfm` and move to `Application.cfc`. Not only will you get more functionality, but it is a standard. Also, **always** have an `Application.cfc` for your application. If not, CF will search for one and use it's settings and you do not want that. 1060 | * Only create Application listener methods that you will use, do not create them as empty functions unecessarily. 1061 | 1062 | **[[⬆]](#TOC)** 1063 | 1064 | ### Session Scope Usage 1065 | Be very careful when using `session` scoped variables in your applications, especially if used under heavy load or high traffic. Remember that `session` variables are per user and consume memory. If they are misused or you issue `session` variables randomly, your RAM usage will increase exponentially. Consider always having low timeouts for your `session` scopes and always disallowing bots to have `session` variables. Do not pre-set `session` scoped variables if not necessary. Usually, when somebody logs in, then give memory away. 1066 | 1067 | 1068 | **[[⬆]](#TOC)** 1069 | 1070 | ### Use `cflock` On Shared Resources 1071 | Use `cflock` whenever you need to make your code thread safe. This applies to variables in shared scopes such as: `server and application` scope. You sometimes want to even lock `session,request` scope if you are working with framesets, but usually locking `session,request` scope is not necessary anymore. Also remember to use `cflock` whenever you are accessing shared resources, such as file operations, cache operations, etc. 1072 | * Always use a `timeout` and `throwOnTimeout` attributes on the `cflock` tag. 1073 | * If you use **exclusive** locks on a resource, make sure that you also provide **readonly** locks when trying to read from such resources. 1074 | * Use named locks for locking resources that do not apply to scopes such as `server, application, session, request`. However, please understand that the name of the lock is on a **per server** basis. So make sure the name is unique enough so other applications running on the same server do not collide with it. If they do, you will be providing unecesarry bottlenecks as named locks are global. 1075 | * Good locking article: http://www.adobe.com/devnet/server_archive/articles/cf_locking_best_practices.html 1076 | * Do not overinflate the code within lock tags. Locking code should only occur on small bits of code and when you are acessing the shared resource. Of course, there are special ocassions to do more than just saving in shared scope, but use it as a rule of thumb. 1077 | 1078 | 1079 | 1080 | 1081 | 1084 | 1087 | 1088 | 1089 | 1090 | 1091 | 1110 | 1111 | 1128 | 1129 | 1130 | 1131 |
1082 | ✅ DO THIS 1083 | 1085 | ❌ NOT THIS 1086 |
1092 |
1093 | <cflock name="FileOperation" timeout="20" throwOnTimeout="true">
1094 | <cffile action="write" file="#filePath#" output="#content#">
1095 | </cflock>
1096 | 
1097 | <cflock type="readonly" scope="application" timeout="10" throwOnTimeout="true">
1098 | <cfset myVar = application.cache.getValue("x")>
1099 | </cflock>
1100 | <cfquery name="variables.qUser" datasource="#request.dsn#">
1101 | SELECT FirstName, LastName
1102 | FROM Users
1103 | WHERE UserID = #request.UserID#
1104 | </cfquery>
1105 | <cflock scope="application" timeout="2" type="exclusive">
1106 | <cfset application.qUser=variables.qUser>
1107 | </cflock>
1108 | 
1109 |
1112 |
1113 | <cflock name="FileOperation" >
1114 | <cffile action="write" file="#filePath#" output="#content#">
1115 | </cflock>
1116 | <cfset myVar = application.cache.getValue("x")>
1117 | <cflock scope="application" timeout="2" type="exclusive">
1118 | <cfquery name="application.qUser" datasource="#request.dsn#">
1119 | SELECT FirstName, LastName
1120 | FROM Users
1121 | WHERE UserID = #request.UserID#
1122 | </cfquery>
1123 | </cflock>
1124 | 
  1125 |
  1126 |
1127 |
1132 | 1133 | **[[⬆]](#TOC)** 1134 | 1135 | ### Race Conditions 1136 | There will be cases where you need to do a double tests in order to avoid race conditions on shared resources. This strategy can be applied when you need to test, for example, if a resource is created, an object is configured, etc. What this strategy does is provide two if statement criterias that can verify behavior on the resource, squished between a `cflock` tag. This prevents threads that have already entered the locking stage and are waiting execution, to re-execute the locked code. 1137 | 1138 | 1139 | 1140 | 1141 | 1144 | 1147 | 1148 | 1149 | 1150 | 1151 | 1162 | 1163 | 1174 | 1175 | 1176 | 1177 |
1142 | ✅ DO THIS 1143 | 1145 | ❌ NOT THIS 1146 |
1152 |
1153 | <cfif not structKeyExists(application,"controller")>
1154 |    <cflock name="mainControllerCreation" timeout="20" throwOnTimeout="true" type="exclusive">
1155 |       <cfif not structKeyExists(application,"controller")>
1156 |          <cfset application.controller = createObject("component","coldbox.MainController").init()>
1157 |       </cfif>
1158 |    </cflock>
1159 | </cfif>
1160 | 
1161 |
1164 |
1165 | <cfif not structKeyExists(application,"controller")>
1166 |    <cflock name="mainControllerCreation" timeout="20" throwOnTimeout="true" type="exclusive">
1167 |       <cfset application.controller = createObject("component","coldbox.MainController").init()>
1168 |    </cflock>
1169 | </cfif>
1170 | 
  1171 |
  1172 |
1173 |
1178 | 1179 | 1180 | As you can see from the previous code snippet, if you do not have the double if statements, then code that is waiting on the lock, will re-execute the creation of the controller object. Therefore, since we can test the resource state, we can provide a multi-thread safety net. 1181 | 1182 | ### Do Not Abuse Pound Signs 1183 | Pound signs are most often used to output variables to their set values or evaluate them. There are many places where you DO NOT need to place hash signs. This only delays the evaluation and is not best practice. Most likely you will only need to use pound signs when using ''cfoutput'' or when dealing with certain tag attributes that require the evaluation of a variable. 1184 | 1185 | 1186 | 1187 | 1188 | 1191 | 1194 | 1195 | 1196 | 1197 | 1198 | 1205 | 1206 | 1213 | 1214 | 1215 | 1216 |
1189 | ✅ DO THIS 1190 | 1192 | ❌ NOT THIS 1193 |
1199 |
1200 | <cfset name = request.firstname>
1201 | <cfif isValid></cfif>
1202 | <cfset SomeVar = Var1 + Max(Var2, 10* Var3) + Var4>
1203 | 
1204 |
1207 |
1208 | <cfset name = #request.firstname#>
1209 | <cfif #isValid#></cfif>
1210 | <cfset #SomeVar# = #Var1# + #Max(Var2, 10* Var3)# + #Var4#>
1211 | 
1212 |
1217 | 1218 | **[[⬆]](#TOC)** 1219 | 1220 | ### More General Recommendations 1221 | 1222 | * Components are supposed to be objects and have an identity. Always ask yourself what this component's responsibilities are and how will it interact with its surroundings. 1223 | * Variables pass in and out of components by **reference** or by value based on the same rules as the rest of CFML. For instance, strings, arrays, numbers, and dates all pass by value, but structures, queries, and all other "complex" objects (including CFC instances) pass by reference. 1224 | * Arrays in ColdFusion pass by value in Adobe ColdFusion, so beware of this behavior as it is not the same as in Java or other CFML engines. 1225 | * `Duplicate()` and CFWDDX do not work on CFC instances (ColdFusion 7 and below). CFC’s can only be serialized in ColdFusion 8 and with several restrictions. Be careful when serializing objects as the entire object graphs have the potential of being serialized. ColdFusion 9 presents mechanisms to restrict component serializations which helps incredibly. 1226 | * When extending a component outside the base component's package, the sub-component does not inherit `package` permissions -- thus, you cannot call `package` methods on other CFCs in the package of the base component from the sub-component. 1227 | * You can have a method that has a `returnType` or an argument that has a `type` of a base component and return any component that extends that base component. For example, if `methodA` takes an argument `foo` of type `motorVehicle` and you pass `foo` as an instance of `car`, which extends `motorVehicle` then `methodA` will honor that `car` is a `motorVehicle` when doing type checking on the argument `foo`. 1228 | * The previous concept applies to interfaces and inheritance. 1229 | * Use interfaces when you want to provide clear API definitions that need to be implemented. They can be good documentation tools and provide compile time checks on your code. 1230 | * Use `structKeyExists` instead of `isDefined` when checking for existence. 1231 | 1232 | 1233 | 1234 | 1235 | 1238 | 1241 | 1242 | 1243 | 1244 | 1245 | 1251 | 1252 | 1258 | 1259 | 1260 | 1261 |
1236 | ✅ DO THIS 1237 | 1239 | ❌ NOT THIS 1240 |
1246 |
1247 | if( structKeyExists( arguments, "car" ) )
1248 | if( arguments.exists( "car" ) )
1249 | 
1250 |
1253 |
1254 | if( isDefined("arguments.car") )
1255 | 
  1256 |
1257 |
1262 | 1263 | * Use `cfswitch` instead of `cfif` if you have a specific expression that you can evaluate against and if you will have more than 2 `cfelseif` clauses. Not only does it provide more readability, but your code will make more sense. 1264 | * Avoid usage of `iif` if at all possible as it is documented to be slower. However, sometimes it can prove handy. 1265 | * Avoid usage of `evaluate()` expressions. They have to be evaluated by the ColdFusion engine and will always run slower. There are times when you will have to use them, especially when doing dynamic concatenations, but try to avoid them at all possible. 1266 | 1267 | 1268 | 1269 | 1270 | 1273 | 1276 | 1277 | 1278 | 1279 | 1280 | 1285 | 1286 | 1291 | 1292 | 1293 | 1294 |
1271 | ✅ DO THIS 1272 | 1274 | ❌ NOT THIS 1275 |
1281 |
1282 | <cfset value = form[ "field#i#" ]>
1283 | 
1284 |
1287 |
1288 | <cfset value = evaluate("form.field#i#")>
1289 | 
1290 |
1295 | 1296 | * Use boolean evaluations 1297 | 1298 | 1299 | 1300 | 1301 | 1304 | 1307 | 1308 | 1309 | 1310 | 1311 | 1319 | 1320 | 1328 | 1329 | 1330 | 1331 |
1302 | ✅ DO THIS 1303 | 1305 | ❌ NOT THIS 1306 |
1312 |
1313 | <cfif len(firstName)></cfif>
1314 | <cfif NOT obj.isEmpty()></cfif>
1315 | <cfif query.recordcount></cfif>
1316 | <cfif arrayLen(myArray)></cfif>
1317 | 
1318 |
1321 |
1322 | <cfif firstName eq ""></cfif>
1323 | <cfif obj.isEmpty() eq false></cfif>
1324 | <cfif query.recordcount gt 0></cfif>
1325 | <cfif arrayLen(myArray) gt 0></cfif>
1326 | 
1327 |
1332 | 1333 | * When you are creating view templates, try to always surround it with `cfoutput` tag, instead of nesting them all over the place. 1334 | 1335 | 1336 | 1337 | 1338 | 1341 | 1344 | 1345 | 1346 | 1347 | 1348 | 1364 | 1365 | 1381 | 1382 | 1383 | 1384 |
1339 | ✅ DO THIS 1340 | 1342 | ❌ NOT THIS 1343 |
1349 |
1350 | <cfoutput>
1351 | <html>
1352 | <head>
1353 | #head#
1354 | </head>
1355 | <body>
1356 | #leftBar#
1357 | #content#
1358 | #footer#
1359 | </body>
1360 | </html>
1361 | </cfoutput>
1362 | 
1363 |
1366 |
1367 | <html>
1368 | <head>
1369 | <cfoutput>#head#</cfoutput>
1370 | </head>
1371 | <body>
1372 | <cfoutput>#leftBar#</cfoutput>
1373 | <cfoutput>#body#</cfoutput>
1374 | <cfoutput>#footer#</cfoutput>
1375 | </body>
1376 | </html>
1377 | 
  1378 |
  1379 |
1380 |
1385 | 1386 | * Code for portability. Avoid at all costs on hardcoding paths, urls, file locations, etc. If you are using a framework, which you should, they usually provide a way to setup application global variables. If not within a framework context, try to set global variables in a shared scope such as `application` scope once when your application loads and then just grab settings from it. Always believe that your application locations can change. 1387 | 1388 | * Prefer double quotation marks for denoting strings. 1389 | 1390 | ``` js 1391 | function getFullName( string firstname = "", string lastname = "" ){ 1392 | return "#arguments.lastname#, #arguments.firstname#"; 1393 | } 1394 | ``` 1395 | 1396 | **[[⬆]](#TOC)** 1397 | 1398 | ## ColdBox Specific Best Practices 1399 | 1400 | * Leverage the `rc and prc` scopes directly instead of referencing the `event` object unless you need default values 1401 | * Leverage `var` or `local` scope in the event handlers if those variables will NOT be used in layouts/views 1402 | * Leverage the `prc` for data set/read safely within your application. Incoming data through the `rc` is NEVER to be trusted. This should remain as what a client sent into a request. 1403 | * Do not mix `local` scope usage and `var` scope declared variables in your handlers. PICK ONE approach. 1404 | * Do not create dual performing actions that respond to different HTTP verbs. Like a `list()` action that lists and saves to the database in a post. Create two actions, two concerns. 1405 | * Always always always leverage injection via WireBox 1406 | * Remember that all event handlers are singletons 1407 | 1408 | **[[⬆]](#TOC)** 1409 | -------------------------------------------------------------------------------- /guides/css-sass.md: -------------------------------------------------------------------------------- 1 | # Airbnb CSS / Sass Styleguide 2 | 3 | *A mostly reasonable approach to CSS and Sass* 4 | 5 | ## Table of Contents 6 | 7 | 1. [Terminology](#terminology) 8 | - [Rule Declaration](#rule-declaration) 9 | - [Selectors](#selectors) 10 | - [Properties](#properties) 11 | 1. [CSS](#css) 12 | - [Formatting](#formatting) 13 | - [Comments](#comments) 14 | - [OOCSS and BEM](#oocss-and-bem) 15 | - [ID Selectors](#id-selectors) 16 | - [JavaScript hooks](#javascript-hooks) 17 | - [Border](#border) 18 | 1. [Sass](#sass) 19 | - [Syntax](#syntax) 20 | - [Ordering](#ordering-of-property-declarations) 21 | - [Variables](#variables) 22 | - [Mixins](#mixins) 23 | - [Extend directive](#extend-directive) 24 | - [Nested selectors](#nested-selectors) 25 | 1. [Translation](#translation) 26 | 1. [License](#license) 27 | 28 | ## Terminology 29 | 30 | ### Rule declaration 31 | 32 | A “rule declaration” is the name given to a selector (or a group of selectors) with an accompanying group of properties. Here's an example: 33 | 34 | ```css 35 | .listing { 36 | font-size: 18px; 37 | line-height: 1.2; 38 | } 39 | ``` 40 | 41 | ### Selectors 42 | 43 | In a rule declaration, “selectors” are the bits that determine which elements in the DOM tree will be styled by the defined properties. Selectors can match HTML elements, as well as an element's class, ID, or any of its attributes. Here are some examples of selectors: 44 | 45 | ```css 46 | .my-element-class { 47 | /* ... */ 48 | } 49 | [aria-hidden] { 50 | /* ... */ 51 | } 52 | ``` 53 | 54 | ### Properties 55 | 56 | Finally, properties are what give the selected elements of a rule declaration their style. Properties are key-value pairs, and a rule declaration can contain one or more property declarations. Property declarations look like this: 57 | 58 | ```css 59 | /* some selector */ { 60 | background: #f1f1f1; 61 | color: #333; 62 | } 63 | ``` 64 | 65 | **[⬆ back to top](#table-of-contents)** 66 | 67 | ## CSS 68 | 69 | ### Formatting 70 | 71 | * Use tabs for indentation. 72 | * Prefer dashes over camelCasing in class names. 73 | - Underscores and PascalCasing are okay if you are using BEM (see [OOCSS and BEM](#oocss-and-bem) below). 74 | * Avoid ID selectors if at all possible. 75 | * When using multiple selectors in a rule declaration, give each selector its own line. 76 | * Put a space before the opening brace `{` in rule declarations. 77 | * In properties, put a space after, but not before, the `:` character. 78 | * Put closing braces `}` of rule declarations on a new line. 79 | * Put blank lines between rule declarations. 80 | 81 | **Bad** 82 | 83 | ```css 84 | .avatar{ 85 | border-radius:50%; 86 | border:2px solid white; } 87 | .no, .nope, .not_good { 88 | // ... 89 | } 90 | #lol-no { 91 | // ... 92 | } 93 | ``` 94 | 95 | **Good** 96 | 97 | ```css 98 | .avatar { 99 | border-radius: 50%; 100 | border: 2px solid white; 101 | } 102 | .one, 103 | .selector, 104 | .per-line { 105 | // ... 106 | } 107 | ``` 108 | 109 | ### Comments 110 | 111 | * Prefer line comments (`//` in Sass-land) to block comments. 112 | * Prefer comments on their own line. Avoid end-of-line comments. 113 | * Write detailed comments for code that isn't self-documenting: 114 | - Uses of z-index 115 | - Compatibility or browser-specific hacks 116 | 117 | ### OOCSS and BEM 118 | 119 | We encourage some combination of OOCSS and BEM for these reasons: 120 | 121 | * It helps create clear, strict relationships between CSS and HTML 122 | * It helps us create reusable, composable components 123 | * It allows for less nesting and lower specificity 124 | * It helps in building scalable stylesheets 125 | 126 | **OOCSS**, or “Object Oriented CSS”, is an approach for writing CSS that encourages you to think about your stylesheets as a collection of “objects”: reusable, repeatable snippets that can be used independently throughout a website. 127 | 128 | * Nicole Sullivan's [OOCSS wiki](https://github.com/stubbornella/oocss/wiki) 129 | * Smashing Magazine's [Introduction to OOCSS](http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/) 130 | 131 | **BEM**, or “Block-Element-Modifier”, is a _naming convention_ for classes in HTML and CSS. It was originally developed by Yandex with large codebases and scalability in mind, and can serve as a solid set of guidelines for implementing OOCSS. 132 | 133 | * CSS Trick's [BEM 101](https://css-tricks.com/bem-101/) 134 | * Harry Roberts' [introduction to BEM](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) 135 | 136 | We recommend a variant of BEM with PascalCased “blocks”, which works particularly well when combined with components (e.g. React). Underscores and dashes are still used for modifiers and children. 137 | 138 | **Example** 139 | 140 | ```jsx 141 | // ListingCard.jsx 142 | function ListingCard() { 143 | return ( 144 | 150 | ); 151 | } 152 | ``` 153 | 154 | ```css 155 | /* ListingCard.css */ 156 | .ListingCard { } 157 | .ListingCard--featured { } 158 | .ListingCard__title { } 159 | .ListingCard__content { } 160 | ``` 161 | 162 | * `.ListingCard` is the “block” and represents the higher-level component 163 | * `.ListingCard__title` is an “element” and represents a descendant of `.ListingCard` that helps compose the block as a whole. 164 | * `.ListingCard--featured` is a “modifier” and represents a different state or variation on the `.ListingCard` block. 165 | 166 | ### ID selectors 167 | 168 | While it is possible to select elements by ID in CSS, it should generally be considered an anti-pattern. ID selectors introduce an unnecessarily high level of [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) to your rule declarations, and they are not reusable. 169 | 170 | For more on this subject, read [CSS Wizardry's article](http://csswizardry.com/2014/07/hacks-for-dealing-with-specificity/) on dealing with specificity. 171 | 172 | ### JavaScript hooks 173 | 174 | Avoid binding to the same class in both your CSS and JavaScript. Conflating the two often leads to, at a minimum, time wasted during refactoring when a developer must cross-reference each class they are changing, and at its worst, developers being afraid to make changes for fear of breaking functionality. 175 | 176 | We recommend creating JavaScript-specific classes to bind to, prefixed with `.js-`: 177 | 178 | ```html 179 | 180 | ``` 181 | 182 | ### Border 183 | 184 | Use `0` instead of `none` to specify that a style has no border. 185 | 186 | **Bad** 187 | 188 | ```css 189 | .foo { 190 | border: none; 191 | } 192 | ``` 193 | 194 | **Good** 195 | 196 | ```css 197 | .foo { 198 | border: 0; 199 | } 200 | ``` 201 | **[⬆ back to top](#table-of-contents)** 202 | 203 | ## Sass 204 | 205 | ### Syntax 206 | 207 | * Order your regular CSS and `@include` declarations logically (see below) 208 | 209 | ### Ordering of property declarations 210 | 211 | 1. Property declarations 212 | 213 | List all standard property declarations, anything that isn't an `@include` or a nested selector. 214 | 215 | ```scss 216 | .btn-green { 217 | background: green; 218 | font-weight: bold; 219 | // ... 220 | } 221 | ``` 222 | 223 | 2. `@include` declarations 224 | 225 | Grouping `@include`s at the end makes it easier to read the entire selector. 226 | 227 | ```scss 228 | .btn-green { 229 | background: green; 230 | font-weight: bold; 231 | @include transition(background 0.5s ease); 232 | // ... 233 | } 234 | ``` 235 | 236 | 3. Nested selectors 237 | 238 | Nested selectors, _if necessary_, go last, and nothing goes after them. Add whitespace between your rule declarations and nested selectors, as well as between adjacent nested selectors. Apply the same guidelines as above to your nested selectors. 239 | 240 | ```scss 241 | .btn { 242 | background: green; 243 | font-weight: bold; 244 | @include transition(background 0.5s ease); 245 | .icon { 246 | margin-right: 10px; 247 | } 248 | } 249 | ``` 250 | 251 | ### Variables 252 | 253 | Prefer dash-cased variable names (e.g. `$my-variable`) over camelCased or snake_cased variable names. It is acceptable to prefix variable names that are intended to be used only within the same file with an underscore (e.g. `$_my-variable`). 254 | 255 | ### Mixins 256 | 257 | Mixins should be used to DRY up your code, add clarity, or abstract complexity--in much the same way as well-named functions. Mixins that accept no arguments can be useful for this, but note that if you are not compressing your payload (e.g. gzip), this may contribute to unnecessary code duplication in the resulting styles. 258 | 259 | ### Extend directive 260 | 261 | `@extend` should be avoided because it has unintuitive and potentially dangerous behavior, especially when used with nested selectors. Even extending top-level placeholder selectors can cause problems if the order of selectors ends up changing later (e.g. if they are in other files and the order the files are loaded shifts). Gzipping should handle most of the savings you would have gained by using `@extend`, and you can DRY up your stylesheets nicely with mixins. 262 | 263 | ### Nested selectors 264 | 265 | **Do not nest selectors more than three levels deep!** 266 | 267 | ```scss 268 | .page-container { 269 | .content { 270 | .profile { 271 | // STOP! 272 | } 273 | } 274 | } 275 | ``` 276 | 277 | When selectors become this long, you're likely writing CSS that is: 278 | 279 | * Strongly coupled to the HTML (fragile) *—OR—* 280 | * Overly specific (powerful) *—OR—* 281 | * Not reusable 282 | 283 | 284 | Again: **never nest ID selectors!** 285 | 286 | If you must use an ID selector in the first place (and you should really try not to), they should never be nested. If you find yourself doing this, you need to revisit your markup, or figure out why such strong specificity is needed. If you are writing well formed HTML and CSS, you should **never** need to do this. 287 | 288 | **[⬆ back to top](#table-of-contents)** 289 | 290 | ## Translation 291 | 292 | This style guide is also available in other languages: 293 | 294 | - ![id](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Indonesia.png) **Bahasa Indonesia**: [mazipan/css-style-guide](https://github.com/mazipan/css-style-guide) 295 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese (Traditional)**: [ArvinH/css-style-guide](https://github.com/ArvinH/css-style-guide) 296 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [Zhangjd/css-style-guide](https://github.com/Zhangjd/css-style-guide) 297 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [mat-u/css-style-guide](https://github.com/mat-u/css-style-guide) 298 | - ![ka](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Georgia.png) **Georgian**: [DavidKadaria/css-style-guide](https://github.com/davidkadaria/css-style-guide) 299 | - ![ja](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [nao215/css-style-guide](https://github.com/nao215/css-style-guide) 300 | - ![ko](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [CodeMakeBros/css-style-guide](https://github.com/CodeMakeBros/css-style-guide) 301 | - ![PT-BR](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Portuguese (Brazil)**: [felipevolpatto/css-style-guide](https://github.com/felipevolpatto/css-style-guide) 302 | - ![pt-PT](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Portugal.png) **Portuguese (Portugal)**: [SandroMiguel/airbnb-css-style-guide](https://github.com/SandroMiguel/airbnb-css-style-guide) 303 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [rtplv/airbnb-css-ru](https://github.com/rtplv/airbnb-css-ru) 304 | - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [ismamz/guia-de-estilo-css](https://github.com/ismamz/guia-de-estilo-css) 305 | - ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnamese**: [trungk18/css-style-guide](https://github.com/trungk18/css-style-guide) 306 | - ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [antoniofull/linee-guida-css](https://github.com/antoniofull/linee-guida-css) 307 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [tderflinger/css-styleguide](https://github.com/tderflinger/css-styleguide) 308 | 309 | **[⬆ back to top](#table-of-contents)** 310 | 311 | ## License 312 | 313 | (The MIT License) 314 | 315 | Copyright (c) 2015 Airbnb 316 | 317 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 318 | 319 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 320 | 321 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 322 | 323 | **[⬆ back to top](#table-of-contents)** -------------------------------------------------------------------------------- /guides/database.md: -------------------------------------------------------------------------------- 1 | # Ortus Database Naming Conventions 2 | 3 | 4 | A naming convention is important when working with databases in order to provide a clear structure and format; especially in team environments. By using these conventions the database can be understood by anyone applying these conventions; thus increasing maintainability. 5 | 6 | At Ortus, our preference is to levarage Hibernate ORM with additional SQL additions. 7 | 8 | ## Table of Contents 9 | 10 | 1. [General Conventions](#general) 11 | 1. [Table Conventions](#tables) 12 | 1. [Column Conventions](#columns) 13 | 1. [Index Conventions](#indexes) 14 | 1. [View Conventions](#views) 15 | 16 | 17 | ## General Conventions 18 | 19 | - All names should be in camelcase with the first letter in lower case and should match their respective ORM objects. 20 | 21 | ``` 22 | -- DO THIS -- 23 | user 24 | permision 25 | userPermission 26 | 27 | -- NOT THIS -- 28 | User 29 | Permission 30 | User_Permission 31 | user_permission 32 | ``` 33 | 34 | - Separate name parts by using camel case and NOT underscores or spaces. This provides better readibility and you will not have to use quotes when doing SQL statements. Look at example in the previous point. 35 | - Prefixes or namespaces are the ONLY parts of names that should be separated by underscores. This defines a clear separation between names and areas. 36 | 37 | ``` 38 | -- DO THIS -- 39 | blog_user 40 | blog_userPermission 41 | 42 | -- NOT THIS -- 43 | BlogUser 44 | BlogUserPermission 45 | Blog_UserPermission 46 | ``` 47 | 48 | - Do not use numbers in names. This is poor design, indicating divided table structures. 49 | - Do not use dot (`.`) separator between names, remember use camel casing. This way you will avoid problems when doing SQL statements as fields are accessed using dot notation. 50 | - It goes without saying, do not use reserved database words in any name. 51 | - Always try to use names that make sense and are descriptive of their purpose. 52 | - Avoid abbreviations whenever possible. ONLY use abbreviations that are well known and documented. 53 | - Avoid acronyms whenever possible. Only use acronyms that are well known and documented. Also, they should all be in uppercase if used. 54 | 55 | ``` 56 | -- DO THIS -- 57 | HTTPRequests 58 | savedURL 59 | 60 | -- NOT THIS -- 61 | http_requests 62 | httprequests 63 | savedurl 64 | saved_url 65 | ``` 66 | 67 | 68 | **[[⬆]](#TOC)** 69 | 70 | ## Table Conventions 71 | 72 | - Tables are usually entities you are modeling for persistence. So make sure the names are in proper English and carry natural meanings. These names should make sense and should be descriptive. 73 | - Avoid acronyms and abbreviations if at all possible. If acronyms are used, then make sure to capitalize them. Abbreviations used should be well known abbreviations and should be camel cased. 74 | - Avoid using plural names for tables, use singular forms. This will avoid errors due to pluralization of words and also when moving table design to objects or entities. The name should map to the entity it is modeling. 75 | 76 | ``` 77 | -- DO THIS -- 78 | blog_user 79 | blog_page 80 | person 81 | box 82 | activity 83 | 84 | -- NOT THIS -- 85 | blog_users 86 | blog_pages 87 | people 88 | boxes 89 | activities 90 | ``` 91 | 92 | - Use namespaces for tables whenever grouping is needed. This grouping is a clear separation when working with the tables and can also provide a good basis for security, as you could secure via the namespace. Namespaces should be separated by anunderscore and then the name should be camel cased. 93 | 94 | ``` 95 | -- DO THIS -- 96 | lookups_country 97 | lookups_state 98 | lookups_regionalOffice 99 | hr_employee 100 | hr_salary 101 | is_employee 102 | is_vacationDay 103 | 104 | -- NOT THIS -- 105 | LookupsCountry 106 | lookupsState 107 | LOOKUPS_RegionalOffice 108 | HREmployee 109 | ISEmployee 110 | ISVacationDay 111 | ``` 112 | 113 | * Do not use prefixes like `tbl,db` as they are EXTREMELY redundant and useless. 114 | * All tables should have at least ONE primary key. 115 | 116 | 117 | **[[⬆]](#TOC)** 118 | 119 | ## Column Conventions 120 | 121 | * Columns are usually attributes of an entity you are modeling via a table. So make sure the names are in proper English and carry natural meanings. These names should make sense and should be descriptive. 122 | * Avoid acronyms and abbreviations if at all possible. If acronyms are used, then make sure to capitalize them. Abbreviations used should be well known abbreviations and should be camel cased. 123 | * Get used to naming primary or foreign keys with an `ID` identifier suffix. DO NOT use the column name `id` to identify a primary key. Be more descriptive, usually looking at the table name. 124 | 125 | ``` 126 | -- DO THIS -- 127 | userID 128 | userPermissionID 129 | 130 | -- NOT THIS -- 131 | id 132 | userid 133 | upid 134 | ``` 135 | 136 | * Foreign keys should be prefixed with a capitalized `FK_` in order to visually denote relationships and also to avoid ambigous table selects. After the `FK_` the name of the column must comply with our naming conventions. 137 | ``` 138 | -- DO THIS -- 139 | FK_userID 140 | 141 | -- NOT THIS -- 142 | fkuserid 143 | userID 144 | ``` 145 | 146 | * Boolean columns should use the `is` prefix. 147 | ``` 148 | -- DO THIS -- 149 | isActive 150 | isSold 151 | 152 | -- NOT THIS -- 153 | active 154 | sold 155 | ``` 156 | 157 | * Date columns should be suffixed in camel case with the word `Date`. 158 | ``` 159 | -- DO THIS -- 160 | createdDate 161 | updatedDate 162 | 163 | -- NOT THIS -- 164 | date_created 165 | date_updated 166 | ``` 167 | 168 | 169 | **[[⬆]](#TOC)** 170 | 171 | ## Index Conventions 172 | 173 | * Always prefix all index names with `idx_` to distinguish it as an index. 174 | * The names of the index should at least convey the columns it reaches or at least the purpose of the index. 175 | 176 | **[[⬆]](#TOC)** 177 | 178 | ## Views Conventions 179 | 180 | * Always try to use names that make sense and are descriptive for the views. Avoid acronyms and abbreviations if at all possible. If acronyms are used, then make sure to capitalize them. Abbreviations used should be well known abbreviations and should be camel cased. 181 | * All views should be prefixed with `vw_` in order to distinguish them in SQL statements from regular database tables. 182 | 183 | **[[⬆]](#TOC)** 184 | -------------------------------------------------------------------------------- /guides/do-this-not-this-table.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 24 | 25 | 26 | 27 |
4 | ✅ DO THIS 5 | 7 | ❌ NOT THIS 8 |
14 |
15 | 
16 | 
17 |
20 |
21 | 
22 | 
23 |
28 | -------------------------------------------------------------------------------- /guides/security.md: -------------------------------------------------------------------------------- 1 | # Ortus Security Guidelines 2 | 3 | 4 | This guide delineates some best practices when dealing with SQL injection attempts or just plain old URL/FORM variable manipulations, when building ColdFusion web applications. 5 | 6 | ## Table of Contents 7 | 8 | 1. [HTTP Methods](#http_methods) 9 | 1. [Protecting Your Code](#protecting_code) 10 | 11 | ## Golden Rule of Web Applications 12 | > Never ever ever trust the incoming data. It is YOUR responsibility to protect your code. 13 | 14 | ## Understanding The HTTP Methods 15 | 16 | First of all, you also need to understand what a POST, GET, DELETE, PUT are used for. The method attribute of the `FORM` element specifies the HTTP method used to send the form to the processing agent. This attribute may take the following values: 17 | 18 | * `GET` : With the HTTP `GET` method, the form data set is appended to the URI specified by the action attribute (with a question-mark (`?`) as separator) and this new URI is sent to the processing agent. 19 | * `POST,PUT,DELETE` : The form data set is included in the body of the form and sent to the processing agent, with expectations of either a save, update or delete. 20 | 21 | The `GET` method should be used when the form is **idempotent** (i.e., causes no side-effects). Many database searches have no visible side effects and make ideal applications for the `GET` method. If the service associated with the processing of a form causes side effects (for example, if the form modifies a database or subscription to a service), the `POST,PUT, or DELETE` method should be used. 22 | 23 | The most important fact is that the `GET` method should be used for idempotent transactions. Here is the definition for idempotent: 24 | 25 |
26 | "Idempotent operation means that it can be repeated without causing any errors or inconsistencies if the operation is carried out once or many times". 27 |
28 | 29 | Thanks to Roger Benningfield: 30 | 31 |
32 | "Allowing GET requests to change the state of server resources can be a very dangerous game, without so much as a whiff of malicious behavior. An app that allows clients to change or delete data just by fetching a URI is asking for trouble in 2020." 33 | 34 |
35 | 36 | There is a time for using `GET` and a time for using `POST,PUT,DELETE` and **NONE OF THEM should trust the client data**. 37 | 38 | **[[⬆]](#TOC)** 39 | 40 | ## Protecting Your Code 41 | 42 | As for security, FORM variables are just as easy to modify as URL variables. However, there are several ways to protect from attacks, SQL injection or plain mischief: 43 | 44 | * `` tag with strict data-type and scaling will prevent URL and FORM variable abuse. This tag binds incoming FORM or URL variables to specific types and even create default values for them. 45 | * Use of `` is the most common form of stopping URL/FORM variable abuse with direct SQL and it makes your queries faster as well (If your db supports it). Use this tag to protect any part of your SQL statements that come from an external source, even `ORDER BY` or `GROUP BY` statements. 46 | * Get into the habit of adding the `maxlength` attribute to `cfqueryparam`, to limit the number of characters/digits to bind a column with. 47 | * Use of Stored Procedures will prevent SQL injection as all variables are binded by the use of ``. 48 | * Try to always use a custom error page that cannot display to the user the entire error message. This will hide your internal information and encapsulate your errors. 49 | * It is the role of the developer to protect the database and its contents, no matter if you are using a POST or a GET. 50 | * Do not trust the client on the incoming data; always do data type checking and authorization/authentication checking on the server-side. 51 | 52 | **[[⬆]](#TOC)** 53 | -------------------------------------------------------------------------------- /linters/.cflintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rule": [], 3 | "includes": [ 4 | { "code": "AVOID_USING_CFINCLUDE_TAG" }, 5 | { "code": "AVOID_USING_CFABORT_TAG" }, 6 | { "code": "AVOID_USING_CFEXECUTE_TAG" }, 7 | { "code": "AVOID_USING_DEBUG_ATTR" }, 8 | { "code": "AVOID_USING_ABORT" }, 9 | { "code": "AVOID_USING_ISDATE" }, 10 | { "code": "AVOID_USING_ISDEBUGMODE" }, 11 | { "code": "AVOID_USING_CFINSERT_TAG" }, 12 | { "code": "AVOID_USING_CFUPDATE_TAG" }, 13 | { "code": "ARG_VAR_CONFLICT" }, 14 | { "code": "ARG_HINT_MISSING" }, 15 | { "code": "ARG_HINT_MISSING_SCRIPT" }, 16 | { "code" : "ARGUMENT_INVALID_NAME" }, 17 | { "code" : "ARGUMENT_ALLCAPS_NAME" }, 18 | { "code" : "ARGUMENT_TOO_WORDY" }, 19 | { "code" : "ARGUMENT_IS_TEMPORARY" }, 20 | { "code": "CFQUERYPARAM_REQ" }, 21 | { "code": "COMPARE_INSTEAD_OF_ASSIGN" }, 22 | { "code": "COMPONENT_HINT_MISSING" }, 23 | { "code" : "COMPONENT_INVALID_NAME" }, 24 | { "code" : "COMPONENT_ALLCAPS_NAME" }, 25 | { "code" : "COMPONENT_TOO_SHORT" }, 26 | { "code" : "COMPONENT_TOO_LONG" }, 27 | { "code" : "COMPONENT_TOO_WORDY" }, 28 | { "code" : "COMPONENT_IS_TEMPORARY" }, 29 | { "code" : "COMPONENT_HAS_PREFIX_OR_POSTFIX" }, 30 | { "code": "COMPLEX_BOOLEAN_CHECK" }, 31 | { "code": "EXCESSIVE_ARGUMENTS" }, 32 | { "code": "EXCESSIVE_FUNCTIONS" }, 33 | { "code": "EXPLICIT_BOOLEAN_CHECK" }, 34 | { "code": "FUNCTION_TOO_COMPLEX" }, 35 | { "code": "FUNCTION_HINT_MISSING" }, 36 | { "code": "FILE_SHOULD_START_WITH_LOWERCASE" }, 37 | { "code": "LOCAL_LITERAL_VALUE_USED_TOO_OFTEN" }, 38 | { "code": "GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN" }, 39 | { "code": "MISSING_VAR" }, 40 | { "code" : "METHOD_INVALID_NAME" }, 41 | { "code" : "METHOD_ALLCAPS_NAME" }, 42 | { "code" : "METHOD_IS_TEMPORARY" }, 43 | { "code": "NESTED_CFOUTPUT" }, 44 | { "code": "NEVER_USE_QUERY_IN_CFM" }, 45 | { "code": "OUTPUT_ATTR" }, 46 | { "code" : "QUERYPARAM_REQ" }, 47 | { "code": "UNUSED_LOCAL_VARIABLE" }, 48 | { "code": "UNUSED_METHOD_ARGUMENT" }, 49 | { "code": "SQL_SELECT_STAR" }, 50 | { "code": "SCOPE_ALLCAPS_NAME" }, 51 | { "code": "VAR_ALLCAPS_NAME" }, 52 | { "code": "VAR_INVALID_NAME" }, 53 | { "code": "VAR_TOO_WORDY" } 54 | ], 55 | "inheritParent": false, 56 | "parameters": { 57 | "TooManyFunctionsChecker.maximum" : 50 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /linters/.cflintrc-handlers: -------------------------------------------------------------------------------- 1 | { 2 | "rule": [], 3 | "includes": [ 4 | { "code": "AVOID_USING_STRUCTNEW" }, 5 | { "code": "AVOID_USING_ARRAYNEW" }, 6 | { "code": "AVOID_USING_CFINCLUDE_TAG" }, 7 | { "code": "AVOID_USING_CFABORT_TAG" }, 8 | { "code": "AVOID_USING_CFEXECUTE_TAG" }, 9 | { "code": "AVOID_USING_DEBUG_ATTR" }, 10 | { "code": "AVOID_USING_CREATEOBJECT" }, 11 | { "code": "AVOID_USING_ABORT" }, 12 | { "code": "AVOID_USING_ISDATE" }, 13 | { "code": "AVOID_USING_ISDEBUGMODE" }, 14 | { "code": "AVOID_USING_CFINSERT_TAG" }, 15 | { "code": "AVOID_USING_CFUPDATE_TAG" }, 16 | { "code": "ARG_VAR_CONFLICT" }, 17 | { "code": "ARG_VAR_MIXED" }, 18 | { "code" : "ARGUMENT_INVALID_NAME" }, 19 | { "code" : "ARGUMENT_TOO_WORDY" }, 20 | { "code" : "ARGUMENT_IS_TEMPORARY" }, 21 | { "code": "CFQUERYPARAM_REQ" }, 22 | { "code": "COMPARE_INSTEAD_OF_ASSIGN" }, 23 | { "code": "COMPONENT_HINT_MISSING" }, 24 | { "code" : "COMPONENT_INVALID_NAME" }, 25 | { "code" : "COMPONENT_ALLCAPS_NAME" }, 26 | { "code" : "COMPONENT_TOO_SHORT" }, 27 | { "code" : "COMPONENT_TOO_LONG" }, 28 | { "code" : "COMPONENT_TOO_WORDY" }, 29 | { "code" : "COMPONENT_IS_TEMPORARY" }, 30 | { "code" : "COMPONENT_HAS_PREFIX_OR_POSTFIX" }, 31 | { "code": "COMPLEX_BOOLEAN_CHECK" }, 32 | { "code": "EXCESSIVE_FUNCTION_LENGTH" }, 33 | { "code": "EXCESSIVE_COMPONENT_LENGTH" }, 34 | { "code": "EXCESSIVE_ARGUMENTS" }, 35 | { "code": "EXCESSIVE_FUNCTIONS" }, 36 | { "code": "EXPLICIT_BOOLEAN_CHECK" }, 37 | { "code": "FUNCTION_TOO_COMPLEX" }, 38 | { "code": "FUNCTION_HINT_MISSING" }, 39 | { "code": "FILE_SHOULD_START_WITH_LOWERCASE" }, 40 | { "code": "MISSING_VAR" }, 41 | { "code" : "METHOD_ALLCAPS_NAME" }, 42 | { "code" : "METHOD_IS_TEMPORARY" }, 43 | { "code": "NESTED_CFOUTPUT" }, 44 | { "code": "NEVER_USE_QUERY_IN_CFM" }, 45 | { "code": "OUTPUT_ATTR" }, 46 | { "code" : "QUERYPARAM_REQ" }, 47 | { "code": "UNUSED_LOCAL_VARIABLE" }, 48 | { "code": "SQL_SELECT_STAR" }, 49 | { "code": "SCOPE_ALLCAPS_NAME" }, 50 | { "code": "VAR_ALLCAPS_NAME" }, 51 | { "code": "VAR_TOO_WORDY" }, 52 | { "code": "VAR_IS_TEMPORARY" } 53 | ], 54 | "inheritParent": false, 55 | "parameters": { 56 | "TooManyFunctionsChecker.maximum" : 20 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /linters/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = false 10 | indent_style = tab 11 | indent_size = 4 12 | tab_width = 4 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{md,markdown}] 19 | trim_trailing_whitespace = false 20 | insert_final_newline = false -------------------------------------------------------------------------------- /linters/.eslintrc.json: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 4 | parserOptions: { 5 | parser: "babel-eslint", 6 | sourceType: "module" 7 | }, 8 | 9 | env: { 10 | "browser": true, 11 | "es6" : true 12 | }, 13 | 14 | extends: [ 15 | "prettier", 16 | // Uncomment any of the lines below to choose desired strictness, 17 | // but leave only one uncommented! 18 | // See https://eslint.vuejs.org/rules/#available-rules 19 | // "plugin:vue/essential" // Priority A: Essential (Error Prevention) 20 | "plugin:vue/strongly-recommended" // Priority B: Strongly Recommended (Improving Readability) 21 | // "plugin:vue/recommended" // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) 22 | ], 23 | 24 | // required to lint *.vue files 25 | plugins: [ 26 | "vue" 27 | ], 28 | 29 | globals: { 30 | "ga": true, // Google Analytics 31 | "cordova": true, 32 | "__statics": true, 33 | "process": true, 34 | "Capacitor": true, 35 | "chrome": true 36 | }, 37 | 38 | // add your custom rules here 39 | rules: { 40 | "array-bracket-spacing": ["error", "always", { 41 | "singleValue": true, 42 | "arraysInArrays": true, 43 | "objectsInArrays": true 44 | }], 45 | "array-bracket-newline" : [ "error", { 46 | "multiline" : true 47 | } ], 48 | "array-element-newline" : [ "error", 49 | { "multiline": true, "minItems": 2 } 50 | ], 51 | "camelcase" : [ "error" , { 52 | "properties" : "always" 53 | }], 54 | "indent": ["error", "tab", { 55 | ignoredNodes: ["TemplateLiteral"] 56 | }], 57 | "keyword-spacing": ["error", { "after": true, "before": true }], 58 | "key-spacing": ["error", { 59 | "singleLine": { 60 | "beforeColon": false, 61 | "afterColon": true 62 | }, 63 | "multiLine": { 64 | "beforeColon": true, 65 | "afterColon": true, 66 | "align": "colon" 67 | } 68 | }], 69 | "no-trailing-spaces": ["error", { 70 | "skipBlankLines": false, 71 | "ignoreComments": false 72 | }], 73 | "no-fallthrough" : "error", 74 | // allow debugger during development only 75 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", 76 | "object-curly-newline" : [ "error", { "multiline" : true } ], 77 | "object-curly-spacing": ["error", "always", { 78 | "objectsInObjects": true, 79 | "arraysInObjects": true 80 | }], 81 | "object-property-newline" : [ "error", { "allowAllPropertiesOnSameLine" : true } ], 82 | "prefer-promise-reject-errors": "off", 83 | "quotes" : [ "error", "double" ], 84 | "semi": ["error", "always"], 85 | "space-in-parens": ["error", "always"], 86 | "space-before-function-paren": ["error", { 87 | "anonymous": "never", 88 | "named": "never", 89 | "asyncArrow": "never" 90 | }], 91 | "vue/html-indent": ["error", "tab"], 92 | "vue/html-self-closing": [ "error", { 93 | "html": { 94 | "void": "any", 95 | "normal": "always", 96 | "component": "always" 97 | } 98 | } ] 99 | } 100 | } -------------------------------------------------------------------------------- /linters/.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "beautify.language": { 3 | "js": ["js","json","cfc"], 4 | "css": ["css", "scss"], 5 | "html": ["htm", "html", "cfml", "cfm"] 6 | }, 7 | "brace_style": "collapse", 8 | "indent_with_tabs": true, 9 | "indent_size": 4, 10 | "indent_level": 0, 11 | "preserve_newlines": true, 12 | "max_preserve_newlines": 5, 13 | "html": { 14 | "allowed_file_extensions": ["htm", "html", "xhtml", "shtml", "xml", "svg", "cfm", "cfml"], 15 | "indent_scripts": "keep", 16 | "indent_inner_html": true, 17 | "indent_body_inner_html": true, 18 | "indent_handlebars": true, 19 | "unformatted": ["code", "pre"], 20 | "content_unformatted": ["pre", "code"], 21 | "wrap_line_length": 0 22 | }, 23 | "css": { 24 | "selector_separator_newline": true 25 | }, 26 | "js": { 27 | "break_chained_methods": true, 28 | "comma_first": false, 29 | "e4x": false, 30 | "jslint_happy": true, 31 | "keep_function_indentation": true, 32 | "keep_array_indentation": true, 33 | "space_after_anon_function": false, 34 | "spaceBeforeConditional": true, 35 | "space_in_paren": true, 36 | "space_in_empty_paren": false, 37 | "space_before_conditional": true, 38 | "operator_position": "before-newline", 39 | "unescape_strings": false, 40 | "wrap_line_length": 0 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /linters/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "browser": true, 7 | "devel": true, 8 | "sub": true, 9 | "noarg": true, 10 | "node": true, 11 | "latedef": true, 12 | "unused": true, 13 | "esversion": 6, 14 | "globals": { 15 | "jQuery": true, 16 | "$": true, 17 | "module": true, 18 | "angular": true 19 | } 20 | } -------------------------------------------------------------------------------- /linters/.sass-lint.yml: -------------------------------------------------------------------------------- 1 | severity: error 2 | 3 | linters: 4 | 5 | BorderZero: 6 | enabled: true 7 | convention: zero 8 | 9 | BemDepth: 10 | enabled: true 11 | 12 | DeclarationOrder: 13 | enabled: false 14 | 15 | ExtendDirective: 16 | enabled: true 17 | 18 | LeadingZero: 19 | enabled: false 20 | 21 | NameFormat: 22 | enabled: true 23 | 24 | PrivateNamingConvention: 25 | enabled: true 26 | prefix: _ 27 | 28 | PropertySortOrder: 29 | enabled: false 30 | 31 | QualifyingElement: 32 | enabled: false 33 | 34 | SelectorFormat: 35 | enabled: true 36 | convention: hyphenated_BEM 37 | class_convention: ^(?!js-).* 38 | class_convention_explanation: should not be written in the form js-* 39 | 40 | SingleLinePerProperty: 41 | enabled: true 42 | allow_single_line_rule_sets: false 43 | 44 | StringQuotes: 45 | enabled: true 46 | style: double_quotes -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Ortus Coding Style Guides 2 | 3 | 4 | 5 | This repository includes all of the Ortus coding style guides, linter and formatting configurations. Read, collaborate and enjoy. 6 | 7 | ## Guides 8 | 9 | * [ColdFusion](guides/coldfusion.md) 10 | * [CSS-SASS](guides/css-sass.md) 11 | * [Database](guides/database.md) 12 | * [JavaScript](guides/javascript.md) 13 | * [Security](guides/security.md) 14 | 15 | 16 | ## Linters 17 | 18 | * [CFlint](linters/.cflintrc) - Leverages the cflint project (`box install commandbox-cflint`) 19 | * [CFlint ColdBox Handlers](linters/.cflintrc-handlers) - Specific linting of ColdBox Handlers 20 | * [Editorconfig](linters/.editorconfig) - Leverages the EditorConfig Plugins for your IDE 21 | * [ESLint](linters/.eslintrc.json) - ESLinting of JavaScript and Vue files. 22 | * [JSBeautify](linters/.jsbeautifyrc) 23 | * [JSHint](linters/.jshintrc) 24 | * [SASS](linters/.sass-lint.yml) 25 | 26 | ## Formatters 27 | 28 | * [ColdFusion - CFFormat](formatters/.cfformat.json) 29 | * [ColdFusion - Submlime](formatters/cfml_format.sublime-settings) 30 | * [Java - Eclipse/VSCode](formatters/ortus-java-style.xml) 31 | 32 | 33 | ## IDE Automatic Coding Standards 34 | 35 | We also provide ways to apply our formatting rules automatically via modern IDEs. 36 | 37 | ### CommandBox Formatting 38 | 39 | Start off by installing the cfformat CommandBox package: `box install commandbox-cfformat`. Then in the root of your application if you have a `box.json` open it. If you don't, then initialize your application as a CommandBox package: `box init`. Then open the file and look for a `scripts` section, if you don't have one, then add it. We will create three scripts to format your source code: 40 | 41 | * `format` : Format all the files/directories you want 42 | * `format:watch` : Start a watcher for all the files/directories you want and if a save is detected, automatically format the changed files. 43 | * `format:check` : Verifies if the watched files/directories adhere to your style guides. 44 | 45 | ```js 46 | scripts : { 47 | "format" : "cfformat run handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc --overwrite", 48 | "format:watch" : "cfformat watch handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc ./.cfformat.json", 49 | "format:check" : "cfformat check handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc", 50 | } 51 | ``` 52 | 53 | Then you can run a watcher: `box run-script format:watch` and everytime you save a change in the files being watched, the formatter will automatically format the CFML code. 54 | 55 | 56 | ### VSCode ESLint 57 | 58 | We are using ESLint as our standards for formatting and linting for JavaScript and Vue files. You can follow this guide to setup your VSCode editor for formatting and linting: [Setup VSCode](https://www.digitalocean.com/community/tutorials/linting-and-formatting-with-eslint-in-vs-code) 59 | 60 | 61 | ### Sublime 62 | 63 | If you use Sublime as your IDE, you can install the `CFML` package and use the built-in formatter to help you format CFML files according to our standards. Just open the **Format Settings** and paste in the [Sublime Settings](formatters/cfml_format.sublime-settings) contents. Then you can use the shortcut for it according to OS to execute it. You can read it here: https://github.com/jcberquist/sublimetext-cfml#code-formatting 64 | 65 | ![sublime settings](./resources/sublime-format-settings.png) 66 | 67 | The CFML Format operation is a manual command in Sublime by default. To make it automatic, install the "Hooks" (https://packagecontrol.io/packages/Hooks) plugin for Sublime and then add the following hook to your Syntax specific settings for CFML. To get to the Syntax specific settings, open a CFM or CFC file in Sublime then select the menu item Sublime Text > Preferences > Syntax - Specific Settings 68 | 69 | ```json 70 | // These settings override both User and Default settings for the cfml 71 | syntax 72 | { 73 | "on_pre_save_language": [ 74 | { 75 | "command": "cfml_format", 76 | "args": { 77 | "current_method": false 78 | }, } 79 | ] } 80 | ``` 81 | 82 | 83 | --- 84 | 85 | **Copyright Ortus Solutions Corp** 86 | 87 | If otherwise noted, this content is property of Ortus Solutions, Corp. 88 | 89 | > Soli Deo Gloria 90 | -------------------------------------------------------------------------------- /resources/ortus-spaceman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ortus-Solutions/coding-standards/f73c446f917264598c80531c89499df8573fc90a/resources/ortus-spaceman.jpg -------------------------------------------------------------------------------- /resources/sublime-format-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ortus-Solutions/coding-standards/f73c446f917264598c80531c89499df8573fc90a/resources/sublime-format-settings.png -------------------------------------------------------------------------------- /resources/vscode-beautify-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ortus-Solutions/coding-standards/f73c446f917264598c80531c89499df8573fc90a/resources/vscode-beautify-settings.png --------------------------------------------------------------------------------