├── .editorconfig ├── .eslintrc.yml ├── .gitignore ├── .prettierignore ├── .travis.yml ├── README.md ├── jest.eslint.config.js ├── jest.test.config.js ├── package.json ├── scripts ├── ci │ └── download ├── dump ├── dump-clean ├── dump-doc ├── dump-js ├── dumper.js └── run ├── src ├── index.js ├── parser │ ├── index.js │ ├── preprocessor.js │ └── wrapper.js └── printer │ ├── builders.js │ ├── chain.js │ ├── generic.js │ ├── index.js │ ├── tokens.js │ └── verbatim.js ├── tests ├── accessors │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── accessors.swift │ └── jsfmt.spec.js ├── args │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── args.swift │ └── jsfmt.spec.js ├── arrays │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── arrays.swift │ └── jsfmt.spec.js ├── as │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── as.swift │ └── jsfmt.spec.js ├── associatedtype │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── associatedtype.swift │ └── jsfmt.spec.js ├── attributes │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── attributes.swift │ └── jsfmt.spec.js ├── backtick │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── backtick.swift │ └── jsfmt.spec.js ├── bugs │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── bugs.swift │ ├── closure_with_parens.swift │ └── jsfmt.spec.js ├── captures │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── captures.swift │ └── jsfmt.spec.js ├── chains │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── chains.swift │ └── jsfmt.spec.js ├── comments │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── chain.swift │ ├── comments.swift │ ├── jsfmt.spec.js │ └── only.swift ├── composition │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── composition.swift │ └── jsfmt.spec.js ├── continue │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── continue.swift │ └── jsfmt.spec.js ├── defer │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── defer.swift │ └── jsfmt.spec.js ├── deinit │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── deinit.swift │ └── jsfmt.spec.js ├── dictionaries │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── dictionaries.swift │ └── jsfmt.spec.js ├── dummy │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── dummy.swift │ └── jsfmt.spec.js ├── enum │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── enum.swift │ └── jsfmt.spec.js ├── extensions │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── extensions.swift │ └── jsfmt.spec.js ├── for_in │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── for_in.swift │ └── jsfmt.spec.js ├── func │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── func.swift │ └── jsfmt.spec.js ├── function_calls │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── function_calls.swift │ └── jsfmt.spec.js ├── generic_where_clause │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── generic_where_clause.swift │ └── jsfmt.spec.js ├── generics │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── generics.swift │ └── jsfmt.spec.js ├── guard │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── guard.swift │ └── jsfmt.spec.js ├── if │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── if.swift │ └── jsfmt.spec.js ├── if_config_decl │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── if_config_decl.swift │ └── jsfmt.spec.js ├── ignore │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── ignore.swift │ └── jsfmt.spec.js ├── import │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── import.swift │ └── jsfmt.spec.js ├── init │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── init.swift │ └── jsfmt.spec.js ├── is │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── is.swift │ └── jsfmt.spec.js ├── is_type_pattern │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── is_type_pattern.swift │ └── jsfmt.spec.js ├── keypath │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── keypath.swift ├── lazy │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── lazy.swift ├── operators │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── operators.swift ├── optional_chaining │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── optional_chaining.swift ├── protocols │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── protocols.swift ├── repeat_while_stmt │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── repeat_while_stmt.swift ├── specialize_expr │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── specialize_expr.swift ├── strings │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── strings.swift ├── subscript │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── subscript.swift ├── switch │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── switch.swift ├── ternary_expr │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── ternary_expr.swift ├── trailing_closure │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── trailing_closure.swift ├── try │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── try.swift ├── try_catch │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── try_catch.swift ├── tuple_expr │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── tuple_expr.swift ├── type_self │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── type_self.swift ├── typealias │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── typealias.swift ├── underscore │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── underscore.swift ├── while │ ├── __snapshots__ │ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── while.swift └── wildcard │ ├── __snapshots__ │ └── jsfmt.spec.js.snap │ ├── jsfmt.spec.js │ └── wildcard.swift ├── tests_config ├── raw-serializer.js └── run_spec.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [scripts/*] 12 | indent_size = 2 13 | 14 | [*.js] 15 | indent_size = 2 16 | 17 | [*.{snap,swift}] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: 3 | - eslint:recommended 4 | - plugin:prettier/recommended 5 | - plugin:jest/recommended 6 | plugins: 7 | - import 8 | root: true 9 | env: 10 | es6: true 11 | node: true 12 | jest: true 13 | rules: 14 | curly: error 15 | import/no-extraneous-dependencies: 16 | - error 17 | - devDependencies: ["tests*/**", "scripts/**"] 18 | no-else-return: error 19 | no-inner-declarations: error 20 | no-unneeded-ternary: error 21 | no-useless-return: error 22 | no-var: error 23 | one-var: 24 | - error 25 | - never 26 | prefer-arrow-callback: error 27 | prefer-const: error 28 | react/no-deprecated: off 29 | strict: error 30 | symbol-description: error 31 | yoda: 32 | - error 33 | - never 34 | - exceptRange: true 35 | overrides: 36 | - files: "tests/**/*.js" 37 | rules: 38 | strict: off 39 | globals: 40 | run_spec: true 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /.vscode 3 | .DS_Store 4 | .idea 5 | *.swp 6 | /vendor 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - 6 5 | - 8 6 | - 9 7 | cache: 8 | yarn: true 9 | apt: true 10 | directories: 11 | - node_modules 12 | - vendor 13 | addons: 14 | apt: 15 | packages: 16 | - clang 17 | - libicu-dev 18 | env: 19 | global: 20 | - TMPDIR=/tmp 21 | - PRETTIER_SWIFT_SWIFTC=vendor/swiftc 22 | install: 23 | - yarn install 24 | - scripts/ci/download 25 | - vendor/swiftc --version 26 | script: 27 | - yarn lint 28 | - yarn test -- --runInBand 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | 3 | `prettier/plugin-swift` is deprecated. It hasn’t been updated since early 2018, and the Swift community seems to have moved towards [Apple’s swift-format](https://github.com/apple/swift-format) and [Nick Lockwood’s SwiftFormat](https://github.com/nicklockwood/SwiftFormat) instead. 4 | 5 | We hope to someday have plugins for one or both of these tools, but the Prettier team has no current plans to develop such an integration. If you do make something, let us know by opening an issue on [the main Prettier repository](https://github.com/prettier/prettier/issues/new), and we will consider adding a link to this README. 6 | 7 | - - - 8 | 9 |
10 | Prettier 12 | Swift 14 |
15 | 16 |

Swift Plugin for the Opinionated Code Formatter

17 | 18 |

19 | 20 | Gitter 21 | 22 | 23 | Travis 24 | 25 | 26 | npm version 27 | 28 | 31 | 32 | code style: prettier 33 | 34 | 35 | Follow+Prettier+on+Twitter 36 | 37 |

38 | 39 | ## What does it do? 40 | 41 | **:warning: Warning :warning:** This plugin might eat your homework in its early stage. 42 | It also depends on [Swift's lib/Syntax](https://github.com/apple/swift/blob/master/lib/Syntax) which is 43 | [in flux](https://github.com/apple/swift/blob/master/lib/Syntax/Status.md). 44 | Please stage or commit your code before performing any in-place formatting. 45 | 46 | You can check out [how it formatted Artsy's Eidolon](https://github.com/sirlantis/eidolon/pull/1/files). 47 | 48 | ## Prerequisites 49 | 50 | You need one of the following: 51 | 52 | 1. A [snapshot from March 30, 2018 or later](https://swift.org/download/#snapshots), 53 | 2. a recent manual build from Swift's [`master`](https://github.com/apple/swift), or 54 | 3. Swift 4.2 (once it's available as a beta or released completely). 55 | 56 | Assuming you picked **(1)** please follow the 57 | [installation instructions](https://swift.org/download/#using-downloads), 58 | which recommend updating your `PATH` at the end: 59 | 60 | ``` 61 | TOOLCHAIN=swift-DEVELOPMENT-SNAPSHOT-2018-03-30-a.xctoolchain 62 | export PATH=/Library/Developer/Toolchains/${TOOLCHAIN}/usr/bin/:"${PATH}" 63 | ``` 64 | 65 | Alternatively you can pass the full path to the `swiftc` binary 66 | via the environment variable `PRETTIER_SWIFT_SWIFTC`: 67 | 68 | ``` 69 | TOOLCHAIN=swift-DEVELOPMENT-SNAPSHOT-2018-03-30-a.xctoolchain 70 | export PRETTIER_SWIFT_SWIFTC=/Library/Developer/Toolchains/${TOOLCHAIN}/usr/bin/swiftc 71 | ``` 72 | 73 | ## Contributing 74 | 75 | If you're interested in contributing to the development of Prettier for Swift, you can follow the [CONTRIBUTING guide from Prettier](https://github.com/prettier/prettier/blob/master/CONTRIBUTING.md), as it all applies to this repository too. 76 | 77 | To test it out on a Swift file: 78 | 79 | * Clone this repository. 80 | * Run `yarn`. 81 | * Create a file called `test.swift`. 82 | * Run `yarn prettier test.swift` to check the output. 83 | 84 | ## Install 85 | 86 | ```bash 87 | yarn add --dev --exact prettier prettier/plugin-swift 88 | ``` 89 | 90 | ## Use 91 | 92 | ```bash 93 | prettier --write "**/*.swift" 94 | ``` 95 | 96 | ## Maintainers 97 | 98 | 99 | 100 | 101 | 108 | 109 | 110 |
102 | 103 | 104 |
105 | Marcel Jackwerth 106 |
107 |
111 | -------------------------------------------------------------------------------- /jest.eslint.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = { 4 | runner: "jest-runner-eslint", 5 | displayName: "lint", 6 | testMatch: ["/**/*.js"], 7 | testPathIgnorePatterns: ["node_modules/"] 8 | }; 9 | -------------------------------------------------------------------------------- /jest.test.config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const ENABLE_COVERAGE = false; // !!process.env.CI; 4 | 5 | module.exports = { 6 | displayName: "test", 7 | setupFiles: ["/tests_config/run_spec.js"], 8 | snapshotSerializers: ["/tests_config/raw-serializer.js"], 9 | testRegex: "jsfmt\\.spec\\.js$|__tests__/.*\\.js$", 10 | testPathIgnorePatterns: ["tests/new_react", "tests/more_react"], 11 | collectCoverage: ENABLE_COVERAGE, 12 | collectCoverageFrom: ["src/**/*.js", "!/node_modules/"], 13 | transform: {} 14 | }; 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prettier/plugin-swift", 3 | "version": "0.0.0-development", 4 | "description": "Prettier Swift Plugin", 5 | "main": "src", 6 | "repository": "prettier/prettier-swift", 7 | "author": "Marcel Jackwerth <@sirlantis>", 8 | "deprecated": "Please consider using https://github.com/apple/swift-format or https://github.com/nicklockwood/SwiftFormat instead.", 9 | "license": "MIT", 10 | "files": [ 11 | "src", 12 | "vendor" 13 | ], 14 | "engines": { 15 | "node": ">=6" 16 | }, 17 | "dependencies": { 18 | "chalk": "2", 19 | "prettier": "prettier/prettier#1.11.1" 20 | }, 21 | "devDependencies": { 22 | "eslint": "^4.14.0", 23 | "eslint-config-prettier": "^2.9.0", 24 | "eslint-plugin-import": "^2.8.0", 25 | "eslint-plugin-jest": "^21.5.0", 26 | "eslint-plugin-prettier": "^2.4.0", 27 | "jest": "^21.1.0", 28 | "jest-runner-eslint": "^0.3.0", 29 | "prettyjson": "^1.2.1" 30 | }, 31 | "scripts": { 32 | "lint": "prettier src/**/*.js --list-different", 33 | "test": "jest", 34 | "prettier": "prettier --plugin=. --parser=swift" 35 | }, 36 | "jest": { 37 | "projects": [ 38 | "/jest.*.config.js" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /scripts/ci/download: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | VERSION_PREFIX=${BRANCH:-swift} 5 | VERSION_PREFIX=${VERSION_PREFIX//-branch/} 6 | BRANCH=${BRANCH:-development} 7 | VERSION=${VERSION_PREFIX}-DEVELOPMENT-SNAPSHOT-2018-03-30-a 8 | SERVER_PATH=https://swift.org/builds/${BRANCH} 9 | 10 | OS=${OS:-${OSTYPE}} 11 | 12 | case "$OS" in 13 | darwin*) 14 | SERVER_PATH_SUFFIX=xcode 15 | ARCHIVE_SUFFIX=-osx 16 | ARCHIVE_EXT=.pkg 17 | ;; 18 | linux*) 19 | if [ -z "${LSB_RELEASE:-}" ]; then 20 | LSB_RELEASE=$(lsb_release -r -s) 21 | fi 22 | 23 | SERVER_PATH_SUFFIX=ubuntu${LSB_RELEASE//./} 24 | ARCHIVE_SUFFIX=-ubuntu${LSB_RELEASE} 25 | ARCHIVE_EXT=.tar.gz 26 | ;; 27 | *) 28 | echo "Unsupported OS: $OS" 29 | exit 1 30 | ;; 31 | esac 32 | 33 | ARCHIVE_NAME=${VERSION}${ARCHIVE_SUFFIX}${ARCHIVE_EXT} 34 | 35 | CACHE_DIR=vendor 36 | SWIFTC=${CACHE_DIR}/swiftc 37 | SWIFTC_METADATA=${CACHE_DIR}/swiftc.metadata 38 | 39 | ARCHIVE_PATH=${TMPDIR}/${ARCHIVE_NAME} 40 | 41 | function download() { 42 | if [ -f "${ARCHIVE_PATH}" ]; then 43 | echo "Using existing archive at ${ARCHIVE_PATH}" 44 | return 45 | fi 46 | 47 | DOWNLOAD_URL=${SERVER_PATH}/${SERVER_PATH_SUFFIX}/${VERSION}/${ARCHIVE_NAME} 48 | 49 | echo "Downloading ${ARCHIVE_PATH}" 50 | echo " from ${DOWNLOAD_URL}" 51 | 52 | curl -o "${ARCHIVE_PATH}" "${DOWNLOAD_URL}" 53 | } 54 | 55 | function extract() { 56 | ARCHIVE_ENTRY=${VERSION}${ARCHIVE_SUFFIX}/usr/bin/swift 57 | 58 | pushd "${TMPDIR}" 59 | tar -xzf "${ARCHIVE_NAME}" "${ARCHIVE_ENTRY}" 60 | popd 61 | 62 | mkdir -p "${CACHE_DIR}" 63 | cp "${TMPDIR}/${ARCHIVE_ENTRY}" "${SWIFTC}" 64 | echo "${ARCHIVE_NAME}" > "${SWIFTC_METADATA}" 65 | } 66 | 67 | function check() { 68 | "${SWIFTC}" --version 69 | } 70 | 71 | if [ -f "${SWIFTC}" ]; then 72 | echo "Found cached binary at ${SWIFTC}" 73 | 74 | if [ -f "${SWIFTC_METADATA}" ]; then 75 | metadata=$(<${SWIFTC_METADATA}) 76 | 77 | if [ "${ARCHIVE_NAME}" == "${metadata}" ]; then 78 | echo "Metadata matched expected ${ARCHIVE_NAME}" 79 | exit 0 80 | else 81 | echo "Metadata was ${metadata} (expected: ${ARCHIVE_NAME})" 82 | fi 83 | else 84 | echo "${SWIFTC_METADATA} did not exist." 85 | fi 86 | fi 87 | 88 | download 89 | extract 90 | -------------------------------------------------------------------------------- /scripts/dump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | const fs = require("fs"); 5 | const { emitSyntax } = require("../src/parser/wrapper"); 6 | const dumper = require("./dumper"); 7 | 8 | const text = fs.readFileSync(process.argv[2], "utf-8"); 9 | const ast = emitSyntax(text); 10 | 11 | // eslint-disable-next-line no-console 12 | console.log(dumper(ast)); 13 | -------------------------------------------------------------------------------- /scripts/dump-clean: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | const fs = require("fs"); 5 | const prettierSwift = require("../src"); 6 | const dumper = require("./dumper"); 7 | const comments = require("prettier/src/main/comments"); 8 | const { printDocToString } = require("prettier").doc.printer; 9 | const printAstToDoc = require("prettier/src/main/ast-to-doc"); 10 | 11 | const opts = { 12 | printWidth: 140, 13 | tabWidth: 2, 14 | parser: prettierSwift.parsers.swift, 15 | printer: prettierSwift.printers.swift, 16 | locStart: prettierSwift.parsers.swift.locStart, 17 | locEnd: prettierSwift.parsers.swift.locEnd 18 | }; 19 | 20 | let text = fs.readFileSync(process.argv[2], "utf-8"); 21 | text = opts.parser.preprocess(text, opts); 22 | const ast = opts.parser.parse(text, opts); 23 | 24 | function attachComments(text, ast, opts) { 25 | const astComments = ast.comments; 26 | if (astComments) { 27 | delete ast.comments; 28 | comments.attach(astComments, ast, text, opts); 29 | } 30 | ast.tokens = []; 31 | opts.originalText = text.trimRight(); 32 | return astComments; 33 | } 34 | 35 | attachComments(text, ast, opts); 36 | 37 | // eslint-disable-next-line no-console 38 | console.log(dumper(ast)); 39 | 40 | printDocToString(printAstToDoc(ast, opts), opts).formatted; 41 | -------------------------------------------------------------------------------- /scripts/dump-doc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | scripts/run --debug-print-doc $@ 3 | -------------------------------------------------------------------------------- /scripts/dump-js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | 4 | const fs = require("fs"); 5 | const parse = require("prettier/src/language-js/parser-babylon"); 6 | const dumper = require("./dumper"); 7 | 8 | const text = fs.readFileSync(process.argv[2], "utf-8"); 9 | const ast = parse(text); 10 | 11 | // eslint-disable-next-line no-console 12 | console.log(dumper(ast)); 13 | -------------------------------------------------------------------------------- /scripts/dumper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const { printDocToString } = require("prettier").doc.printer; 4 | const printAstToDoc = require("prettier/src/main/ast-to-doc"); 5 | const { 6 | concat, 7 | hardline, 8 | join, 9 | indent, 10 | group, 11 | line, 12 | lineSuffix 13 | } = require("prettier").doc.builders; 14 | 15 | function genericPrint(path, options, print) { 16 | const node = path.getValue(); 17 | 18 | if (Array.isArray(node)) { 19 | if (node.length === 0) { 20 | return "[]"; 21 | } 22 | 23 | return concat([ 24 | join(hardline, path.map(print).map(s => indent(concat(["- ", s])))) 25 | ]); 26 | } else if (node === null) { 27 | return "~"; 28 | } else if (typeof node === "object") { 29 | let metadata; 30 | 31 | if (node.__location) { 32 | metadata = `${node.__location.startOffset}-${node.__location.endOffset}`; 33 | } else if (node.start && node.end) { 34 | metadata = `${node.start}-${node.end}`; 35 | } 36 | 37 | return concat([ 38 | metadata ? lineSuffix(` // ${metadata}`) : "", 39 | join( 40 | hardline, 41 | Object.entries(node) 42 | .filter( 43 | entry => !["__location", "loc", "start", "end"].includes(entry[0]) 44 | ) 45 | .filter(entry => typeof entry[1] !== "undefined") 46 | .map(entry => { 47 | return group( 48 | indent( 49 | concat([ 50 | entry[0], 51 | concat([":", line]), 52 | path.call(print, entry[0]) 53 | ]) 54 | ) 55 | ); 56 | }) 57 | ) 58 | ]); 59 | } 60 | 61 | return JSON.stringify(node); 62 | } 63 | 64 | const opts = { 65 | printWidth: 140, 66 | tabWidth: 2, 67 | printer: { 68 | print: genericPrint, 69 | willPrintOwnComments: () => { 70 | return true; 71 | } 72 | } 73 | }; 74 | 75 | module.exports = ast => { 76 | return printDocToString(printAstToDoc(ast, opts), opts).formatted; 77 | }; 78 | -------------------------------------------------------------------------------- /scripts/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | node_modules/.bin/prettier --plugin . --parser swift --tab-width 4 $@ 3 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const util = require("prettier/src/common/util"); 4 | const { parse, preprocess } = require("./parser"); 5 | const print = require("./printer"); 6 | 7 | const languages = [ 8 | { 9 | name: "Swift", 10 | parsers: ["swift"], 11 | extensions: [".swift"], 12 | tmScope: "source.swift", 13 | aceMode: "text", 14 | linguistLanguageId: 362, 15 | vscodeLanguageIds: ["swift"] 16 | } 17 | ]; 18 | 19 | const parsers = { 20 | swift: { 21 | parse, 22 | preprocess, 23 | astFormat: "swift", 24 | locStart: n => n.__location.startOffset, 25 | locEnd: n => n.__location.endOffset 26 | } 27 | }; 28 | 29 | function canAttachComment(node) { 30 | if (node.token) { 31 | return false; 32 | } else if (["StmtList", "DeclList"].includes(node.type)) { 33 | return !node.layout.length; 34 | } else if (node.type.endsWith("List")) { 35 | return false; 36 | } 37 | 38 | return !["SourceFile", "IfConfigDecl", "FunctionCallArgument"].includes( 39 | node.type 40 | ); 41 | } 42 | 43 | function printComment(commentPath) { 44 | const comment = commentPath.getValue(); 45 | 46 | switch (comment.type) { 47 | case "CommentBlock": 48 | return comment.originalValue; 49 | case "CommentLine": 50 | return comment.originalValue.trimRight(); 51 | default: 52 | throw new Error("Not a valid comment: " + JSON.stringify(comment)); 53 | } 54 | } 55 | 56 | const printers = { 57 | swift: { 58 | print, 59 | hasPrettierIgnore: util.hasIgnoreComment, 60 | canAttachComment, 61 | printComment, 62 | getCommentChildNodes, 63 | willPrintOwnComments 64 | } 65 | }; 66 | 67 | function willPrintOwnComments() { 68 | return true; 69 | } 70 | 71 | function getCommentChildNodes(node) { 72 | return node.layout; 73 | } 74 | 75 | module.exports = { 76 | languages, 77 | printers, 78 | parsers 79 | }; 80 | -------------------------------------------------------------------------------- /src/parser/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const assert = require("assert"); 4 | 5 | const { verbatimPrint } = require("../printer/verbatim"); 6 | const { emitSyntax, checkVersion } = require("./wrapper"); 7 | const preprocessor = require("./preprocessor"); 8 | const { printToken } = require("../printer/tokens"); 9 | 10 | function massage(node) { 11 | if (node.presence === "Missing") { 12 | return; 13 | } 14 | 15 | let { 16 | tokenKind: token, 17 | kind: type, 18 | value, 19 | text, 20 | layout, 21 | leadingTrivia, 22 | trailingTrivia 23 | } = node; 24 | 25 | if (token) { 26 | ({ kind: type, text } = token); 27 | token = true; 28 | } 29 | 30 | if (layout) { 31 | layout = layout 32 | .filter(v => v) 33 | .map(massage) 34 | .filter(v => v); 35 | } 36 | 37 | if (type === "UnknownDecl") { 38 | if (layout.some(n => n.type == "kw_extension")) { 39 | type = "_ExtensionDecl"; 40 | } else if (layout.some(n => n.type == "kw_enum")) { 41 | type = "_EnumDecl"; 42 | 43 | const rBrace = layout.pop(); 44 | const decl = layout.pop(); 45 | const lBrace = layout.pop(); 46 | 47 | layout.push({ 48 | type: "_EnumDeclBlock", 49 | layout: [lBrace, decl, rBrace] 50 | }); 51 | } else if (layout.some(n => n.type == "kw_case")) { 52 | type = "_CaseDecl"; 53 | 54 | const tokens = layout.splice(1); 55 | const elements = []; 56 | let currentElement = []; 57 | let currentInitializerClause; 58 | 59 | tokens.forEach(n => { 60 | if (n.type === "comma") { 61 | currentElement.push(n); 62 | 63 | elements.push({ 64 | type: "_CaseDeclElement", 65 | layout: currentElement 66 | }); 67 | 68 | currentElement = []; 69 | } else if (n.type == "equal") { 70 | currentInitializerClause = { 71 | type: "InitializerClause", 72 | layout: [n] 73 | }; 74 | currentElement.push(currentInitializerClause); 75 | } else if (currentInitializerClause) { 76 | currentInitializerClause.layout.push(n); 77 | } else if (n.type === "Unknown") { 78 | currentElement.push({ 79 | token: true, 80 | type: "identifier", 81 | text: verbatimPrint(n) 82 | }); 83 | } else { 84 | currentElement.push(n); 85 | } 86 | }); 87 | 88 | if (currentElement.length > 0) { 89 | elements.push({ 90 | type: "_CaseDeclElement", 91 | layout: currentElement 92 | }); 93 | } 94 | 95 | layout.push({ 96 | type: "_CaseDeclElementList", 97 | layout: elements 98 | }); 99 | } else if (layout.some(n => n.type == "kw_class")) { 100 | type = "ClassDecl"; 101 | } else if (layout.some(n => n.type == "kw_associatedtype")) { 102 | type = "AssociatedtypeDecl"; 103 | } else if (layout.some(n => n.type == "pound_if")) { 104 | type = "_IfWithElseConfigDecl"; 105 | } 106 | } else if (type === "UnknownStmt") { 107 | if ( 108 | (layout[0].type === "kw_if" && 109 | layout[1].layout[0].layout[0].layout[0].type) === "pound_available" 110 | ) { 111 | type = "IfStmt"; 112 | 113 | layout[1].type = "ConditionElementList"; 114 | layout[1].layout[0].type = "ConditionElement"; 115 | const expr = layout[1].layout[0].layout[0]; 116 | 117 | expr.type = "_AvailabilityExpr"; 118 | expr.layout.push({ 119 | type: "TokenList", 120 | layout: expr.layout.splice(1) 121 | }); 122 | } 123 | } else if (type === "UnknownExpr") { 124 | if (layout.length === 1 && layout[0].token) { 125 | const t = layout[0]; 126 | ({ token, type, value, text, layout } = t); 127 | 128 | if (t.leadingTrivia) { 129 | leadingTrivia = (leadingTrivia || []).concat(t.leadingTrivia); 130 | } 131 | 132 | if (t.trailingTrivia) { 133 | trailingTrivia = (trailingTrivia || []).concat(t.trailingTrivia); 134 | } 135 | } else if (layout.length === 2 && layout[0].type === "amp_prefix") { 136 | type = "_RefExpr"; 137 | } else if ( 138 | layout.length === 2 && 139 | layout[0].type == "l_square" && 140 | layout[1].type == "r_square" 141 | ) { 142 | type = "ArrayExpr"; 143 | layout.splice(1, 0, { 144 | type: "ArrayElementList", 145 | layout: [] 146 | }); 147 | } else if ( 148 | layout.length == 2 && 149 | layout[0].type === "identifier" && 150 | layout[1].type === "GenericArgumentClause" 151 | ) { 152 | type = "_GenericTypeExpr"; 153 | } else if ( 154 | layout.length == 3 && 155 | (layout[0].type.endsWith("TypeExpr") || 156 | [ 157 | "IdentifierExpr", 158 | "MemberAccessExpr", 159 | "DictionaryExpr", 160 | "ArrayExpr" 161 | ].includes(layout[0].type)) && 162 | layout[1].type == "period" && 163 | layout[2].type == "kw_self" 164 | ) { 165 | type = "MemberAccessExpr"; 166 | } else if ( 167 | layout.length == 3 && 168 | layout[1].type == "period" && 169 | layout[2].type == "integer_literal" 170 | ) { 171 | type = "MemberAccessExpr"; 172 | } else if ( 173 | layout.length == 5 && 174 | layout[1].type == "period" && 175 | layout[2].type == "integer_literal" && 176 | layout[3].type == "period" 177 | ) { 178 | type = "MemberAccessExpr"; 179 | layout.unshift({ 180 | type: "MemberAccessExpr", 181 | layout: layout.splice(0, 3) 182 | }); 183 | } else if (layout.length > 0 && layout[0].type == "pound_selector") { 184 | type = "_SelectorExpr"; 185 | } 186 | } else if (type === "UnknownType") { 187 | if (layout.length === 1 && layout[0].type === "kw_class") { 188 | type = "_ClassTypeIdentifier"; 189 | } 190 | } else if (type === "Unknown") { 191 | if (layout.some(n => n.type == "pound_elseif")) { 192 | type = "ElseifDirectiveClause"; 193 | } else if (layout.some(n => n.type == "pound_else")) { 194 | type = "ElseDirectiveClause"; 195 | } 196 | } 197 | 198 | const massageTrivia = trivia => { 199 | if (!trivia || trivia.length === 0) { 200 | return; 201 | } 202 | 203 | trivia.forEach(trivium => { 204 | trivium.type = trivium.type || trivium.kind; 205 | delete trivium.kind; 206 | }); 207 | 208 | return trivia; 209 | }; 210 | 211 | const result = { 212 | type, 213 | token, 214 | value, 215 | leadingTrivia: massageTrivia(leadingTrivia), 216 | text, 217 | layout, 218 | trailingTrivia: massageTrivia(trailingTrivia) 219 | }; 220 | 221 | Object.defineProperty(result, "nodes", { 222 | enumerable: false, 223 | get: function() { 224 | return this.layout; 225 | } 226 | }); 227 | 228 | return result; 229 | } 230 | 231 | const findLastLeaf = curr => { 232 | if ( 233 | !curr || 234 | curr.token || 235 | curr.type == "IdentifierExpr" || 236 | curr.type.endsWith("LiteralExpr") 237 | ) { 238 | return; 239 | } 240 | 241 | if ( 242 | curr.type.startsWith("Unknown") || 243 | curr.type.endsWith("Stmt") || 244 | curr.type == "IfConfigDecl" 245 | ) { 246 | return curr; 247 | } 248 | 249 | if (curr.trailingTrivia && curr.trailingTrivia.length > 0) { 250 | return curr; 251 | } 252 | 253 | return ( 254 | findLastLeaf(curr.layout && curr.layout[curr.layout.length - 1]) || curr 255 | ); 256 | }; 257 | 258 | function preferTrailingOverLeadingTrivia(node, path) { 259 | const { type, layout } = node; 260 | 261 | if (!layout || layout.length === 0 || node.type.startsWith("Unknown")) { 262 | return; 263 | } 264 | 265 | layout.forEach(child => 266 | preferTrailingOverLeadingTrivia(child, [node].concat(path)) 267 | ); 268 | 269 | const leadingTrivia = (node.leadingTrivia || []).slice(); 270 | const trailingTrivia = (node.trailingTrivia || []).slice(); 271 | 272 | const elements = []; 273 | 274 | const canMoveUp = () => { 275 | switch (node.type) { 276 | case "StmtList": 277 | case "CodeBlock": 278 | case "CodeBlockItemList": 279 | return path[0].type == "SourceFile"; 280 | case "DeclList": 281 | case "SourceFile": 282 | return false; 283 | default: 284 | return true; 285 | } 286 | }; 287 | 288 | if (canMoveUp()) { 289 | elements.push({ 290 | parent: true, 291 | type: "(" + type + ")", 292 | trailingTrivia: leadingTrivia 293 | }); 294 | } 295 | 296 | elements.push(...layout); 297 | elements.push({ 298 | type, 299 | leadingTrivia: trailingTrivia 300 | }); 301 | 302 | for (let leftIndex = 0; leftIndex < elements.length - 1; leftIndex++) { 303 | const left = elements[leftIndex]; 304 | const right = elements[leftIndex + 1]; 305 | 306 | if (left.type.startsWith("Unknown") || right.type.startsWith("Unknown")) { 307 | continue; 308 | } 309 | 310 | const rightLeadingTrivia = right.leadingTrivia; 311 | 312 | if (!rightLeadingTrivia || rightLeadingTrivia.length === 0) { 313 | continue; 314 | } 315 | 316 | const target = findLastLeaf(left); 317 | 318 | if (!target) { 319 | continue; 320 | } 321 | 322 | const targetTrailingTrivia = target.trailingTrivia || []; 323 | 324 | loop: for ( 325 | let triviumIndex = 0; 326 | triviumIndex < rightLeadingTrivia.length; 327 | triviumIndex++ 328 | ) { 329 | const trivium = rightLeadingTrivia[triviumIndex]; 330 | 331 | switch (trivium.type) { 332 | case "Newline": 333 | case "Tab": 334 | case "Space": 335 | case "GarbageText": 336 | case "DocBlockComment": 337 | case "DocLineComment": 338 | case "BlockComment": 339 | case "LineComment": 340 | break; 341 | case "Backtick": 342 | break loop; 343 | default: 344 | throw new Error( 345 | "Unexpected trivium: " + 346 | trivium.type + 347 | "\n" + 348 | JSON.stringify(trivium, null, 2) 349 | ); 350 | } 351 | 352 | rightLeadingTrivia.splice(triviumIndex--, 1); 353 | targetTrailingTrivia.push(trivium); 354 | } 355 | 356 | if (rightLeadingTrivia.length === 0) { 357 | right.leadingTrivia = undefined; 358 | } 359 | 360 | if (targetTrailingTrivia.length > 0) { 361 | target.trailingTrivia = targetTrailingTrivia; 362 | } 363 | } 364 | 365 | node.leadingTrivia = leadingTrivia.length > 0 ? leadingTrivia : undefined; 366 | node.trailingTrivia = trailingTrivia.length > 0 ? trailingTrivia : undefined; 367 | } 368 | 369 | function extractComments(node, path) { 370 | const processTrivia = (trivia, resultArray, isLeading) => { 371 | if (!trivia) { 372 | return; 373 | } 374 | 375 | let consumeNewline = false; 376 | let onNewLine = trivia.length && trivia[0].__location.startOffset === 0; 377 | 378 | for (let i = 0; i < trivia.length; i++) { 379 | const trivium = trivia[i]; 380 | const { type } = trivium; 381 | 382 | switch (type) { 383 | case "Backtick": 384 | case "Tab": 385 | case "Space": { 386 | break; 387 | } 388 | case "Newline": { 389 | if (consumeNewline) { 390 | consumeNewline = false; 391 | 392 | trivium.value--; 393 | trivium.__location.startOffset++; 394 | 395 | if (trivium.value <= 0) { 396 | trivia.splice(i--, 1); 397 | } 398 | } else { 399 | loop: while (i > 0) { 400 | const previous = trivia[i - 1]; 401 | 402 | switch (previous.type) { 403 | case "Tab": 404 | case "Space": { 405 | trivia.splice(--i, 1); 406 | break; 407 | } 408 | case "Newline": { 409 | trivium.value += previous.value; 410 | trivia.splice(--i, 1); 411 | break; 412 | } 413 | default: { 414 | break loop; 415 | } 416 | } 417 | } 418 | } 419 | 420 | onNewLine = true; 421 | break; 422 | } 423 | case "GarbageText": 424 | case "DocBlockComment": 425 | case "DocLineComment": 426 | case "BlockComment": 427 | case "LineComment": { 428 | const { __location } = trivium; 429 | let { value } = trivium; 430 | 431 | const isBlockComment = type.endsWith("BlockComment"); 432 | 433 | while (i > 0 && ["Space", "Tab"].includes(trivia[i - 1].type)) { 434 | trivia.splice(--i, 1); 435 | } 436 | 437 | const couldRemainTrivia = 438 | onNewLine && 439 | !node.token && 440 | path[1].type != "IfStmt" && 441 | (![ 442 | "DeclList", 443 | "StmtList", 444 | "CodeBlock", 445 | "CodeBlockItemList" 446 | ].includes(path[0].type) || 447 | path[0].layout.length); 448 | 449 | if (isLeading) { 450 | if (couldRemainTrivia) { 451 | onNewLine = false; 452 | consumeNewline = false; 453 | break; 454 | } 455 | 456 | if (i > 0 && trivia[i - 1].type === "Newline") { 457 | const newline = trivia[i - 1]; 458 | newline.value--; 459 | if (newline.value <= 0) { 460 | trivia.splice(--i, 1); 461 | } else { 462 | newline.__location.endOffset--; 463 | } 464 | } 465 | } else if (couldRemainTrivia) { 466 | onNewLine = false; 467 | consumeNewline = false; 468 | break; 469 | } else { 470 | consumeNewline = !isBlockComment; 471 | } 472 | 473 | const originalValue = value; 474 | 475 | switch (type) { 476 | case "LineComment": 477 | value = value.slice(2); 478 | break; 479 | case "BlockComment": 480 | value = value.slice(2, value.length - 2); 481 | break; 482 | case "DocLineComment": 483 | value = value.slice(3); 484 | break; 485 | case "DocBlockComment": 486 | value = value.slice(3, value.length - 2); 487 | break; 488 | case "GarbageText": 489 | break; 490 | default: 491 | throw new Error("Unexpected type: " + type); 492 | } 493 | 494 | const comment = { 495 | type: isBlockComment ? "CommentBlock" : "CommentLine", 496 | value, 497 | originalValue 498 | }; 499 | 500 | Object.defineProperty(comment, "__location", { 501 | value: __location, 502 | enumerable: Object.getOwnPropertyDescriptor(trivium, "__location") 503 | .enumerable 504 | }); 505 | 506 | resultArray.push(comment); 507 | trivia.splice(i--, 1); 508 | onNewLine = false; 509 | 510 | break; 511 | } 512 | default: { 513 | throw new Error("Unexpected type: " + type); 514 | } 515 | } 516 | } 517 | 518 | trivia = trivia.filter(t => t.type != "Space"); 519 | return trivia.length > 0 ? trivia : undefined; 520 | }; 521 | 522 | const leadingComments = []; 523 | node.leadingTrivia = processTrivia(node.leadingTrivia, leadingComments, true); 524 | 525 | const innerComments = []; 526 | if (node.layout) { 527 | node.layout.forEach(child => 528 | innerComments.push(...extractComments(child, [child].concat(path))) 529 | ); 530 | } 531 | 532 | const trailingComments = []; 533 | node.trailingTrivia = processTrivia(node.trailingTrivia, trailingComments); 534 | return leadingComments.concat(innerComments, trailingComments); 535 | } 536 | 537 | function synthesizeLocation(node, start, text) { 538 | if (!node) { 539 | return start; 540 | } else if (Array.isArray(node)) { 541 | return node.reduce( 542 | (start, node) => synthesizeLocation(node, start, text), 543 | start 544 | ); 545 | } 546 | 547 | const outerLocation = { startOffset: start }; 548 | 549 | let current = start; 550 | 551 | current = synthesizeLocation(node.leadingTrivia, current, text); 552 | 553 | const innerLocation = { startOffset: current }; 554 | 555 | if (node.layout) { 556 | current = synthesizeLocation(node.layout, current, text); 557 | } else if (typeof node.text !== "undefined") { 558 | const s = node.text; 559 | assert.strictEqual(text.slice(current, current + s.length), s); 560 | current += s.length; 561 | } else if (typeof node.value !== "undefined") { 562 | if (Number.isInteger(node.value)) { 563 | current += node.value; 564 | } else { 565 | current += node.value.length; 566 | } 567 | } else if (node.token) { 568 | const s = printToken(node); 569 | assert.strictEqual(text.slice(current, current + s.length), s); 570 | current += s.length; 571 | } else { 572 | throw new Error( 573 | "Don't know how to express " + 574 | JSON.stringify(node.type) + 575 | ":\n" + 576 | JSON.stringify(node, null, 2) 577 | ); 578 | } 579 | 580 | innerLocation.endOffset = current; 581 | 582 | current = synthesizeLocation(node.trailingTrivia, current, text); 583 | 584 | outerLocation.endOffset = current; 585 | 586 | const location = node.type.endsWith("List") ? outerLocation : innerLocation; 587 | 588 | Object.defineProperty(node, "__location", { 589 | value: location, 590 | enumerable: false 591 | }); 592 | 593 | return current; 594 | } 595 | 596 | function preprocess(text, opts) { 597 | opts.preprocessingCache = {}; 598 | 599 | const ast = emitSyntax(text); 600 | 601 | const result = preprocessor.preprocess(ast); 602 | 603 | if (result.bail) { 604 | // eslint-disable-next-line no-console 605 | console.warn("libSyntax had issues parsing this file. Skipping..."); 606 | 607 | opts.preprocessingCache = { 608 | ast: { 609 | kind: "GarbageText", 610 | value: text 611 | } 612 | }; 613 | } else if (result.modified) { 614 | // eslint-disable-next-line no-console 615 | console.warn( 616 | "libSyntax had issues parsing this file. Re-writing and parsing it again..." 617 | ); 618 | text = verbatimPrint(ast); 619 | } else { 620 | opts.preprocessingCache = { ast }; 621 | } 622 | 623 | return text; 624 | } 625 | 626 | /** Parses the document */ 627 | function parse(text, opts) { 628 | checkVersion(); 629 | 630 | let ast; 631 | 632 | // If we are called a second time (i.e. preprocessingCache is already set) 633 | // don't do preprocessing again. 634 | if (opts.preprocessingCache) { 635 | ast = opts.preprocessingCache.ast; 636 | } else { 637 | text = preprocess(text, opts); 638 | ast = opts.preprocessingCache.ast; 639 | } 640 | 641 | delete opts.preprocessingCache; 642 | 643 | if (!ast) { 644 | ast = emitSyntax(text); 645 | } 646 | 647 | ast = massage(ast); 648 | preferTrailingOverLeadingTrivia(ast, []); 649 | const end = synthesizeLocation(ast, 0, text); 650 | 651 | assert.strictEqual(end, text.length); 652 | 653 | ast.comments = extractComments(ast, [ast]); 654 | 655 | return ast; 656 | } 657 | 658 | module.exports = { preprocess, parse }; 659 | -------------------------------------------------------------------------------- /src/parser/preprocessor.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const transferTriviaFromRightToLeft = (left, right) => { 4 | const trailingTrivia = (left.trailingTrivia || []).concat( 5 | right.leadingTrivia || [], 6 | right.trailingTrivia || [] 7 | ); 8 | 9 | if (trailingTrivia.length > 0) { 10 | left.trailingTrivia = trailingTrivia; 11 | } 12 | }; 13 | 14 | const transferTriviaFromLeftToRight = (left, right) => { 15 | const leadingTrivia = (left.leadingTrivia || []).concat( 16 | left.trailingTrivia || [], 17 | right.leadingTrivia || [] 18 | ); 19 | 20 | if (leadingTrivia.length > 0) { 21 | right.leadingTrivia = leadingTrivia; 22 | } 23 | }; 24 | 25 | /** 26 | * Pre-processes a parsed AST to work around limitations of the current libSyntax implementation. 27 | * @param {*} ast 28 | * @returns True, if modifications were necessary. 29 | */ 30 | function preprocess(ast) { 31 | const result = { modified: false }; 32 | 33 | function visit(node, parent) { 34 | if (!node || !node.layout) { 35 | return; 36 | } else if (!node.kind.startsWith("Unknown")) { 37 | node.layout.filter(n => n).forEach(n => visit(n, node)); 38 | return; 39 | } 40 | 41 | const layout = node.layout.filter(n => n.presence === "Present"); 42 | 43 | if ( 44 | layout.length === 2 && 45 | layout[1].tokenKind && 46 | layout[1].tokenKind.kind === "semi" 47 | ) { 48 | const canStrip = 49 | parent.layout.filter(n => n.presence === "Present").length === 1; 50 | 51 | // eslint-disable-next-line no-console 52 | console.warn( 53 | "Found semicolon that confused libSyntax. " + 54 | (canStrip ? "Stripping" : "Breaking") + 55 | "..." 56 | ); 57 | 58 | if (!canStrip) { 59 | (layout[1].leadingTrivia || (layout[1].leadingTrivia = [])).push({ 60 | kind: "Newline", 61 | value: 1 62 | }); 63 | } 64 | 65 | transferTriviaFromRightToLeft(layout[0], layout[1]); 66 | 67 | // Clear out current node 68 | Object.keys(node) 69 | .filter(k => k.indexOf("Trivia") < 0) 70 | .forEach(k => { 71 | delete node[k]; 72 | }); 73 | 74 | Object.assign(node, layout[0]); 75 | result.modified = true; 76 | } else if ( 77 | layout.length === 3 && 78 | layout[0].tokenKind && 79 | layout[0].tokenKind.kind === "l_paren" && 80 | parent.kind !== "UnknownDecl" 81 | ) { 82 | const parameters = layout[1].layout; 83 | 84 | const canStrip = parameters.every( 85 | n => 86 | !n.layout || 87 | n.layout.every( 88 | n => !n || !n.tokenKind || n.tokenKind.kind !== "colon" 89 | ) 90 | ); 91 | 92 | // eslint-disable-next-line no-console 93 | console.warn( 94 | "Found closure with " + 95 | (canStrip ? "optional" : "required") + 96 | " parentheses that confused libSyntax. " + 97 | (canStrip ? "Stripping" : "Bailing") + 98 | "..." 99 | ); 100 | 101 | if (canStrip) { 102 | transferTriviaFromLeftToRight(layout[0], layout[1]); 103 | transferTriviaFromRightToLeft(layout[1], layout[2]); 104 | node.layout = [layout[1]]; 105 | result.modified = true; 106 | } else { 107 | result.bail = true; 108 | } 109 | } 110 | 111 | node.layout.forEach(c => visit(c, node)); 112 | } 113 | 114 | visit(ast); 115 | return result; 116 | } 117 | 118 | module.exports = { preprocess }; 119 | -------------------------------------------------------------------------------- /src/parser/wrapper.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const spawnSync = require("child_process").spawnSync; 4 | 5 | function getCommand() { 6 | return process.env.PRETTIER_SWIFT_SWIFTC || process.env.SWIFTC || "swiftc"; 7 | } 8 | 9 | function checkVersion() { 10 | const result = spawnSync(getCommand(), ["--version"]); 11 | 12 | if (result.error || result.status) { 13 | throw new Error(result.error || result.stderr.toString()); 14 | } 15 | 16 | const stdout = result.stdout.toString(); 17 | const match = /Swift version ([0-9]+\.[0-9]+(\.[0-9]+)?)/.exec(stdout); 18 | 19 | if (!match) { 20 | // eslint-disable-next-line no-console 21 | console.error("Could not detect Swift version:", stdout); 22 | throw new Error("Unsupported Swift version (required: >4.1): " + stdout); 23 | } 24 | 25 | const components = match[1].split("."); 26 | 27 | if (components[0] === "4") { 28 | if (components[1] < 2) { 29 | throw new Error("Unsupported Swift version. Required: 4.2"); 30 | } else { 31 | return; 32 | } 33 | } else if (components[0] < 4) { 34 | throw new Error("Unsupported Swift version. Required: 4.2"); 35 | } 36 | 37 | // eslint-disable-next-line no-console 38 | console.error("Potentially unsupported Swift version. Use Swift 4.2"); 39 | } 40 | 41 | function emitSyntax(text) { 42 | const result = spawnSync(getCommand(), ["-frontend", "-emit-syntax", "-"], { 43 | input: text, 44 | timeout: 60000 45 | }); 46 | 47 | if (result.error || result.status) { 48 | throw new Error(result.error || result.stderr.toString()); 49 | } 50 | 51 | return JSON.parse(result.stdout.toString()); 52 | } 53 | 54 | module.exports = { 55 | emitSyntax, 56 | checkVersion 57 | }; 58 | -------------------------------------------------------------------------------- /src/printer/builders.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const doc = require("prettier").doc; 4 | const docBuilders = doc.builders; 5 | 6 | const { join, hardline, softline, line } = docBuilders; 7 | 8 | function smartJoin(separator, parts) { 9 | const result = []; 10 | let lastPart; 11 | 12 | parts.filter(x => x).forEach((part, index) => { 13 | const firstPart = part.parts ? part.parts[0] : part; 14 | if ( 15 | index > 0 && 16 | firstPart !== ":" && 17 | firstPart !== "..." && 18 | firstPart !== ")" && 19 | firstPart !== "<" && 20 | lastPart !== "(" 21 | ) { 22 | result.push(separator); 23 | } 24 | 25 | lastPart = part; 26 | result.push(part); 27 | }); 28 | 29 | return concat(result); 30 | } 31 | 32 | function concat(parts) { 33 | parts = parts.filter(x => x); 34 | 35 | switch (parts.length) { 36 | case 0: 37 | return ""; 38 | case 1: 39 | return parts[0]; 40 | default: 41 | return docBuilders.concat(parts); 42 | } 43 | } 44 | 45 | module.exports = { 46 | smartJoin, 47 | concat, 48 | join, 49 | hardline, 50 | softline, 51 | line 52 | }; 53 | -------------------------------------------------------------------------------- /src/printer/chain.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const util = require("prettier/src/common/util"); 4 | const comments = require("prettier/src/main/comments"); 5 | const doc = require("prettier").doc; 6 | const { 7 | indent, 8 | hardline, 9 | group, 10 | breakParent, 11 | join, 12 | conditionalGroup 13 | } = doc.builders; 14 | const { willBreak } = doc.utils; 15 | 16 | const { concat } = require("./builders"); 17 | 18 | // We detect calls on member expressions specially to format a 19 | // common pattern better. The pattern we are looking for is this: 20 | // 21 | // arr 22 | // .map(x => x + 1) 23 | // .filter(x => x > 10) 24 | // .some(x => x % 2) 25 | // 26 | // The way it is structured in the AST is via a nested sequence of 27 | // MemberAccessExpr and FunctionCallExpr. We need to traverse the AST 28 | // and make groups out of it to print it in the desired way. 29 | function printMemberChain(path, options, print) { 30 | // The first phase is to linearize the AST by traversing it down. 31 | // 32 | // a().b() 33 | // has the following AST structure: 34 | // FunctionCallExpr(MemberAccessExpr(FunctionCallExpr(IdentifierExpr))) 35 | // and we transform it into 36 | // [IdentifierExpr, FunctionCallExpr, MemberAccessExpr, FunctionCallExpr] 37 | const printedNodes = []; 38 | 39 | // Here we try to retain one typed empty line after each call expression or 40 | // the first group whether it is in parentheses or not 41 | function shouldInsertEmptyLineAfter(node) { 42 | const originalText = options.originalText; 43 | const nextCharIndex = util.getNextNonSpaceNonCommentCharacterIndex( 44 | originalText, 45 | node, 46 | options.locEnd 47 | ); 48 | const nextChar = originalText.charAt(nextCharIndex); 49 | 50 | // if it is cut off by a parenthesis, we only account for one typed empty 51 | // line after that parenthesis 52 | if (nextChar == ")") { 53 | return util.isNextLineEmptyAfterIndex(originalText, nextCharIndex + 1); 54 | } 55 | 56 | return util.isNextLineEmpty(originalText, node, options.locEnd); 57 | } 58 | 59 | function rec(path) { 60 | const node = path.getValue(); 61 | if ( 62 | node.type === "FunctionCallExpr" && 63 | (isMemberish(node.layout[0]) || 64 | node.layout[0].type === "FunctionCallExpr") 65 | ) { 66 | printedNodes.unshift({ 67 | node: node, 68 | printed: concat([ 69 | comments.printComments( 70 | path, 71 | () => 72 | concat([ 73 | printOptionalToken(path), 74 | printFunctionTypeParameters(path, options, print), 75 | printArgumentsList(path, options, print) 76 | ]), 77 | options 78 | ), 79 | shouldInsertEmptyLineAfter(node) ? hardline : "" 80 | ]) 81 | }); 82 | 83 | Object.defineProperty(node, "callee", { 84 | enumerable: false, 85 | value: node.layout[0] 86 | }); 87 | 88 | path.call(callee => rec(callee), "callee"); 89 | } else if (isMemberish(node)) { 90 | printedNodes.unshift({ 91 | node: node, 92 | printed: comments.printComments( 93 | path, 94 | () => 95 | node.type === "MemberAccessExpr" 96 | ? printMemberLookup(path, options, print) 97 | : printBindExpressionCallee(path, options, print), 98 | options 99 | ) 100 | }); 101 | 102 | Object.defineProperty(node, "object", { 103 | enumerable: false, 104 | value: node.layout[0] 105 | }); 106 | 107 | path.call(object => rec(object), "object"); 108 | } else { 109 | printedNodes.unshift({ 110 | node: node, 111 | printed: path.call(print) 112 | }); 113 | } 114 | } 115 | // Note: the comments of the root node have already been printed, so we 116 | // need to extract this first call without printing them as they would 117 | // if handled inside of the recursive call. 118 | const node = path.getValue(); 119 | printedNodes.unshift({ 120 | node, 121 | printed: concat([ 122 | printOptionalToken(path), 123 | printFunctionTypeParameters(path, options, print), 124 | printArgumentsList(path, options, print) 125 | ]) 126 | }); 127 | path.call(callee => rec(callee), "callee"); 128 | 129 | // Once we have a linear list of printed nodes, we want to create groups out 130 | // of it. 131 | // 132 | // a().b.c().d().e 133 | // will be grouped as 134 | // [ 135 | // [Identifier, FunctionCallExpr], 136 | // [MemberAccessExpr, MemberAccessExpr, FunctionCallExpr], 137 | // [MemberAccessExpr, FunctionCallExpr], 138 | // [MemberAccessExpr], 139 | // ] 140 | // so that we can print it as 141 | // a() 142 | // .b.c() 143 | // .d() 144 | // .e 145 | 146 | // The first group is the first node followed by 147 | // - as many FunctionCallExpr as possible 148 | // < fn()()() >.something() 149 | // - as many array acessors as possible 150 | // < fn()[0][1][2] >.something() 151 | // - then, as many MemberAccessExpr as possible but the last one 152 | // < this.items >.something() 153 | const groups = []; 154 | let currentGroup = [printedNodes[0]]; 155 | let i = 1; 156 | for (; i < printedNodes.length; ++i) { 157 | if ( 158 | printedNodes[i].node.type === "FunctionCallExpr" || 159 | (printedNodes[i].node.type === "MemberAccessExpr" && 160 | printedNodes[i].node.computed && 161 | isNumericLiteral(printedNodes[i].node.property)) 162 | ) { 163 | currentGroup.push(printedNodes[i]); 164 | } else { 165 | break; 166 | } 167 | } 168 | if (printedNodes[0].node.type !== "FunctionCallExpr") { 169 | for (; i + 1 < printedNodes.length; ++i) { 170 | if ( 171 | isMemberish(printedNodes[i].node) && 172 | isMemberish(printedNodes[i + 1].node) 173 | ) { 174 | currentGroup.push(printedNodes[i]); 175 | } else { 176 | break; 177 | } 178 | } 179 | } 180 | groups.push(currentGroup); 181 | currentGroup = []; 182 | 183 | // Then, each following group is a sequence of MemberAccessExpr followed by 184 | // a sequence of FunctionCallExpr. To compute it, we keep adding things to the 185 | // group until we has seen a FunctionCallExpr in the past and reach a 186 | // MemberAccessExpr 187 | let hasSeenFunctionCallExpr = false; 188 | for (; i < printedNodes.length; ++i) { 189 | if (hasSeenFunctionCallExpr && isMemberish(printedNodes[i].node)) { 190 | // [0] should be appended at the end of the group instead of the 191 | // beginning of the next one 192 | if ( 193 | printedNodes[i].node.computed && 194 | isNumericLiteral(printedNodes[i].node.property) 195 | ) { 196 | currentGroup.push(printedNodes[i]); 197 | continue; 198 | } 199 | 200 | groups.push(currentGroup); 201 | currentGroup = []; 202 | hasSeenFunctionCallExpr = false; 203 | } 204 | 205 | if (printedNodes[i].node.type === "FunctionCallExpr") { 206 | hasSeenFunctionCallExpr = true; 207 | } 208 | currentGroup.push(printedNodes[i]); 209 | 210 | if ( 211 | printedNodes[i].node.comments && 212 | printedNodes[i].node.comments.some(comment => comment.trailing) 213 | ) { 214 | groups.push(currentGroup); 215 | currentGroup = []; 216 | hasSeenFunctionCallExpr = false; 217 | } 218 | } 219 | if (currentGroup.length > 0) { 220 | groups.push(currentGroup); 221 | } 222 | 223 | // There are cases like Object.keys(), Observable.of(), _.values() where 224 | // they are the subject of all the chained calls and therefore should 225 | // be kept on the same line: 226 | // 227 | // Object.keys(items) 228 | // .filter(x => x) 229 | // .map(x => x) 230 | // 231 | // In order to detect those cases, we use an heuristic: if the first 232 | // node is just an identifier with the name starting with a capital 233 | // letter, just a sequence of _$ or this. The rationale is that they are 234 | // likely to be factories. 235 | function isFactory(node) { 236 | return ( 237 | node.type === "kw_self" || 238 | (node.text && node.text.match(/(^[A-Z])|^[_$]+$/)) 239 | ); 240 | } 241 | 242 | const shouldMerge = 243 | groups.length >= 2 && 244 | !groups[1][0].node.comments && 245 | ((groups[0].length === 1 && 246 | (groups[0][0].node.type === "kw_self" || 247 | groups[0][0].node.type.endsWith("TypeExpr") || 248 | groups[0][0].node.type.endsWith("SpecializeExpr") || 249 | (groups[0][0].node.type === "IdentifierExpr" && 250 | (isFactory(groups[0][0].node.layout[0]) || 251 | (groups[1].length && groups[1][0].node.computed))))) || 252 | (groups[0].length > 1 && 253 | groups[0][groups[0].length - 1].node.type === "MemberAccessExpr" && 254 | groups[0][groups[0].length - 1].node.layout[2].type === "identifier" && 255 | (isFactory(groups[0][groups[0].length - 1].node.layout[2]) || 256 | (groups[1].length && groups[1][0].node.computed)))); 257 | 258 | function printGroup(printedGroup) { 259 | return concat(printedGroup.map(tuple => tuple.printed)); 260 | } 261 | 262 | function printIndentedGroup(groups) { 263 | if (groups.length === 0) { 264 | return ""; 265 | } 266 | return indent( 267 | group(concat([hardline, join(hardline, groups.map(printGroup))])) 268 | ); 269 | } 270 | 271 | const printedGroups = groups.map(printGroup); 272 | const oneLine = concat(printedGroups); 273 | 274 | const cutoff = shouldMerge ? 3 : 2; 275 | const flatGroups = groups 276 | .slice(0, cutoff) 277 | .reduce((res, group) => res.concat(group), []); 278 | 279 | const hasComment = 280 | flatGroups.slice(1, -1).some(node => hasLeadingComment(node.node)) || 281 | flatGroups.slice(0, -1).some(node => hasTrailingComment(node.node)) || 282 | (groups[cutoff] && hasLeadingComment(groups[cutoff][0].node)); 283 | 284 | // If we only have a single `.`, we shouldn't do anything fancy and just 285 | // render everything concatenated together. 286 | if (groups.length <= cutoff && !hasComment) { 287 | return group(concat(printedGroups)); 288 | } 289 | 290 | // Find out the last node in the first group and check if it has an 291 | // empty line after 292 | const lastNodeBeforeIndent = util.getLast( 293 | shouldMerge ? groups.slice(1, 2)[0] : groups[0] 294 | ).node; 295 | const shouldHaveEmptyLineBeforeIndent = 296 | lastNodeBeforeIndent.type !== "FunctionCallExpr" && 297 | shouldInsertEmptyLineAfter(lastNodeBeforeIndent); 298 | 299 | const expanded = concat([ 300 | printGroup(groups[0]), 301 | shouldMerge ? concat(groups.slice(1, 2).map(printGroup)) : "", 302 | shouldHaveEmptyLineBeforeIndent ? hardline : "", 303 | printIndentedGroup(groups.slice(shouldMerge ? 2 : 1)) 304 | ]); 305 | 306 | const functionCallExprCount = printedNodes.filter( 307 | tuple => tuple.node.type === "FunctionCallExpr" 308 | ).length; 309 | 310 | // We don't want to print in one line if there's: 311 | // * A comment. 312 | // * 3 or more chained calls. 313 | // * Any group but the last one has a hard line. 314 | // If the last group is a function it's okay to inline if it fits. 315 | if ( 316 | hasComment || 317 | functionCallExprCount >= 3 || 318 | printedGroups.slice(0, -1).some(willBreak) 319 | ) { 320 | return group(expanded); 321 | } 322 | 323 | return concat([ 324 | // We only need to check `oneLine` because if `expanded` is chosen 325 | // that means that the parent group has already been broken 326 | // naturally 327 | willBreak(oneLine) || shouldHaveEmptyLineBeforeIndent ? breakParent : "", 328 | conditionalGroup([oneLine, expanded]) 329 | ]); 330 | } 331 | 332 | function isNumericLiteral(node) { 333 | return node.type === "IntegerLiteralExpr"; 334 | } 335 | 336 | function isMemberish(node) { 337 | return node.type === "MemberAccessExpr" || node.type === "ImplicitMemberExpr"; 338 | } 339 | 340 | function printOptionalToken() { 341 | return ""; 342 | } 343 | 344 | function printFunctionTypeParameters() { 345 | return ""; 346 | } 347 | 348 | function printBindExpressionCallee(path) { 349 | const part = path.getValue().layout.find(l => l.type == "identifier"); 350 | return part.text; 351 | } 352 | 353 | function printArgumentsList(path, options, print) { 354 | return require("./generic").genericPrint( 355 | path, 356 | Object.assign({}, options, { argumentsOnly: true }), 357 | print 358 | ); 359 | } 360 | 361 | function printMemberLookup(path, options, print) { 362 | const n = path.getValue(); 363 | n.memberLookup = n.layout.slice(1); 364 | return concat(path.map(print, "memberLookup")); 365 | } 366 | 367 | function hasLeadingComment(node) { 368 | return node.comments && node.comments.some(comment => comment.leading); 369 | } 370 | 371 | function hasTrailingComment(node) { 372 | return node.comments && node.comments.some(comment => comment.trailing); 373 | } 374 | 375 | module.exports = { 376 | printMemberChain, 377 | isMemberish 378 | }; 379 | -------------------------------------------------------------------------------- /src/printer/generic.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const assert = require("assert"); 4 | 5 | const { mapDoc } = require("prettier/src/common/util"); 6 | const comments = require("prettier/src/main/comments"); 7 | 8 | const doc = require("prettier").doc; 9 | const docBuilders = doc.builders; 10 | 11 | const { printToken } = require("./tokens"); 12 | const { verbatimPrint } = require("./verbatim"); 13 | const chain = require("./chain"); 14 | const isMemberish = chain.isMemberish; 15 | const printMemberChain = chain.printMemberChain; 16 | 17 | const identity = o => o; 18 | 19 | const { 20 | align, 21 | indent, 22 | line, 23 | hardline, 24 | softline, 25 | group, 26 | breakParent, 27 | join, 28 | ifBreak 29 | } = docBuilders; 30 | 31 | const { smartJoin, concat } = require("./builders"); 32 | 33 | function printList(path, print) { 34 | return concat([ 35 | softline, 36 | group(smartJoin(concat([",", line]), path.map(print, "layout"))) 37 | ]); 38 | } 39 | 40 | function printWithoutNewlines(doc) { 41 | return mapDoc(doc, doc => { 42 | if (doc === line) { 43 | return " "; 44 | } else if (doc === softline) { 45 | return ""; 46 | } 47 | 48 | return doc; 49 | }); 50 | } 51 | 52 | function genericPrint(path, options, print) { 53 | const n = path.getValue(); 54 | 55 | if (typeof n === "string") { 56 | return n; 57 | } 58 | 59 | const { type } = n; 60 | 61 | if (!type) { 62 | throw new Error("Node without type: " + JSON.stringify(n, null, 2)); 63 | } 64 | 65 | const parentType = path.getParentNode() ? path.getParentNode().type : ""; 66 | 67 | if ( 68 | type === "r_paren" && 69 | parentType.startsWith("_") && 70 | parentType.endsWith("Decl") 71 | ) { 72 | return ") "; 73 | } else if (n.token) { 74 | return printToken(n); 75 | } 76 | 77 | switch (type) { 78 | case "SourceFile": { 79 | const parts = path.map(print, "layout"); 80 | 81 | // Only force a trailing newline if there were any contents. 82 | if (n.layout.length || n.comments) { 83 | parts.push(hardline); 84 | } 85 | 86 | parts.unshift( 87 | concat([comments.printDanglingComments(path, options, true)]) 88 | ); 89 | 90 | return concat(parts); 91 | } 92 | case "DeclList": 93 | case "CodeBlockItemList": { 94 | if (n.layout.length === 0) { 95 | return " "; 96 | } 97 | 98 | const isInsideClosureExpression = parentType === "ClosureExpr"; 99 | const isInsideGuardStatement = 100 | (path.getParentNode(1) || {}).type === "GuardStmt"; 101 | const isInsideDeferStatement = 102 | (path.getParentNode(1) || {}).type === "DeferStmt"; 103 | 104 | const shouldBreak = 105 | !isInsideGuardStatement && 106 | !isInsideDeferStatement && 107 | !isInsideClosureExpression; 108 | 109 | return concat([ 110 | shouldBreak ? breakParent : "", 111 | join(hardline, path.map(print, "layout")) 112 | ]); 113 | } 114 | case "_EnumDeclBlock": 115 | case "AccessorBlock": 116 | case "MemberDeclBlock": 117 | case "CodeBlock": { 118 | const body = path.map(print, "layout"); 119 | const first = body.shift(); 120 | const last = body.pop(); 121 | 122 | // Special case: empty block 123 | if (!n.layout[1].layout.length) { 124 | return concat([first, " ", last]); 125 | } 126 | 127 | return group( 128 | concat([indent(concat([first, line, ...body])), line, last]) 129 | ); 130 | } 131 | case "TuplePatternElementList": 132 | case "GenericRequirementList": { 133 | if (!n.layout.length) { 134 | return ""; 135 | } 136 | 137 | return group(indent(printList(path, print))); 138 | } 139 | case "AccessorList": { 140 | return join(line, path.map(print, "layout")); 141 | } 142 | case "SwitchCaseList": { 143 | return concat([ 144 | hardline, 145 | smartJoin(hardline, path.map(print, "layout")), 146 | hardline 147 | ]); 148 | } 149 | case "StmtList": { 150 | const children = path.map(print, "layout"); 151 | 152 | if (!children.length) { 153 | if (n.comments) { 154 | return concat([ 155 | comments.printDanglingComments( 156 | path, 157 | options, 158 | /* sameIndent */ parentType === "SourceFile" 159 | ), 160 | hardline 161 | ]); 162 | } 163 | 164 | return ""; 165 | } 166 | 167 | if (parentType === "_CaseBlock") { 168 | return indent( 169 | concat([breakParent, softline, join(hardline, children)]) 170 | ); 171 | } else if ( 172 | parentType === "SourceFile" || 173 | parentType.match(/DirectiveClause/) || 174 | parentType.match(/ConfigDecl/) 175 | ) { 176 | return join(hardline, children); 177 | } 178 | 179 | let forceBreak = children.length > 1; 180 | 181 | if ( 182 | parentType === "ClosureExpr" && 183 | path.getParentNode(1).type === "FunctionCallExpr" && 184 | path.getParentNode(5).type === "VariableDecl" && 185 | path 186 | .getParentNode(5) 187 | .layout.some( 188 | c => 189 | c.type === "ModifierList" && 190 | c.layout.some(c => c.layout.some(c => c.text === "lazy")) 191 | ) 192 | ) { 193 | forceBreak = true; 194 | } 195 | 196 | return concat([ 197 | indent(concat([softline, join(hardline, children)])), 198 | forceBreak ? breakParent : "", 199 | line 200 | ]); 201 | } 202 | case "ClosureParamList": { 203 | // never break for single parameters or _, _, _, 204 | if ( 205 | n.layout.length < 2 || 206 | n.layout.every(param => param.type === "kw__") 207 | ) { 208 | return concat(path.map(print, "layout")); 209 | } 210 | 211 | return group(indent(printList(path, print))); 212 | } 213 | case "_CaseDeclElementList": 214 | case "CaseItemList": 215 | case "ConditionElementList": 216 | case "InheritedTypeList": 217 | case "PatternBindingList": { 218 | if (!n.layout.length) { 219 | return ""; 220 | } else if (n.layout.length === 1) { 221 | const maybeIndent = 222 | n.type == "ConditionElementList" ? indent : identity; 223 | 224 | return group( 225 | concat([ 226 | maybeIndent(concat(path.map(print, "layout"))), 227 | parentType === "GuardStmt" ? " " : "" 228 | ]) 229 | ); 230 | } else if (path.getParentNode(1).type === "SwitchCase") { 231 | return group( 232 | indent(join(concat([",", line]), path.map(print, "layout"))) 233 | ); 234 | } 235 | 236 | return group( 237 | concat([ 238 | indent(printList(path, print)), 239 | parentType === "GuardStmt" ? line : softline 240 | ]) 241 | ); 242 | } 243 | // Lists that are already surrounded by characters (parens, braces...) 244 | // where indenting is handled by the parent node. 245 | case "FunctionCallArgumentList": 246 | case "GenericParameterList": 247 | case "GenericArgumentList": 248 | case "TupleElementList": 249 | case "TupleTypeElementList": 250 | case "FunctionParameterList": 251 | case "ClosureCaptureItemList": { 252 | if (!n.layout.length) { 253 | return ""; 254 | } 255 | 256 | return smartJoin(concat([",", line]), path.map(print, "layout")); 257 | } 258 | case "ArrayElementList": 259 | case "DictionaryElementList": { 260 | if (!n.layout.length) { 261 | return ""; 262 | } else if (n.type === "ArrayElementList" && n.layout.length === 1) { 263 | return concat(path.map(print, "layout")); 264 | } 265 | 266 | return concat([ 267 | smartJoin(concat([",", line]), path.map(print, "layout")), 268 | options.trailingComma === "all" ? ifBreak(",", "") : "" 269 | ]); 270 | } 271 | case "SubscriptDecl": { 272 | const body = path.map(print, "layout"); 273 | const first = body.shift(); 274 | return concat([first, join(" ", body)]); 275 | } 276 | case "InitializerDecl": 277 | case "DeinitializerDecl": 278 | case "TypealiasDecl": 279 | case "VariableDecl": 280 | case "FunctionDecl": 281 | case "AccessorDecl": 282 | case "ProtocolDecl": 283 | case "StructDecl": 284 | case "ImportDecl": 285 | case "ExtensionDecl": 286 | case "ClassDecl": { 287 | const body = n.layout.slice(); 288 | let prefix; 289 | 290 | if (body[0].type === "AttributeList" || body[0].type === "ModifierList") { 291 | prefix = body.shift(); 292 | } 293 | 294 | const index = body.findIndex(n => { 295 | return ( 296 | [ 297 | "identifier", 298 | "contextual_keyword", 299 | "kw_subscript", 300 | "kw_init", 301 | "kw_deinit", 302 | "kw_var", 303 | "kw_let", 304 | "kw_import" 305 | ].includes(n.type) || 306 | n.type.endsWith("Identifier") || 307 | n.type.startsWith("oper_") 308 | ); 309 | }); 310 | 311 | if (index < 0) { 312 | throw new Error( 313 | "No identifier found: " + body.map(c => c.type).join(", ") 314 | ); 315 | } 316 | 317 | const start = body.splice(0, index); 318 | const middle = [body.shift()]; 319 | 320 | if (middle[0].type.startsWith("oper_")) { 321 | middle.push(" "); // add spacing after operators 322 | } 323 | 324 | while ( 325 | body[0] && 326 | [ 327 | "GenericParameterClause", 328 | "AccessorParameter", 329 | "FunctionSignature", 330 | // For InitializerDecl: 331 | "ParameterClause", 332 | "question_postfix", 333 | "question_infix" // if developer inserted an accidental space 334 | ].includes(body[0].type) 335 | ) { 336 | middle.push(body.shift()); 337 | } 338 | 339 | const last = body.pop(); 340 | 341 | Object.assign(n, { 342 | prefix, 343 | start, 344 | middle, 345 | body, 346 | last 347 | }); 348 | 349 | return concat([ 350 | prefix ? path.call(print, "prefix") : "", 351 | group( 352 | smartJoin(" ", [ 353 | ...path.map(print, "start"), 354 | concat(path.map(print, "middle")), 355 | ...path.map(print, "body") 356 | ]) 357 | ), 358 | last ? concat([" ", path.call(print, "last")]) : "" 359 | ]); 360 | } 361 | case "_EnumDecl": 362 | case "_ExtensionDecl": { 363 | const index = n.layout.findIndex(n => n.type == "l_brace"); 364 | const result = path.map(print, "layout"); 365 | const start = result.slice(0, index); 366 | const end = result.slice(index); 367 | return concat([smartJoin(" ", start), " ", ...end]); 368 | } 369 | case "GuardStmt": { 370 | const body = path.map(print, "layout"); 371 | const index = n.layout.findIndex(n => n.type == "kw_else"); 372 | const start = body.slice(0, index); 373 | const end = body.slice(index); 374 | return group(concat([smartJoin(" ", start), group(smartJoin(" ", end))])); 375 | } 376 | case "ReturnStmt": { 377 | const result = smartJoin(" ", path.map(print, "layout")); 378 | 379 | return concat([ 380 | path.getParentNode().layout[0] === n && 381 | path.getParentNode(3).type === "GuardStmt" 382 | ? "" 383 | : breakParent, 384 | result 385 | ]); 386 | } 387 | case "SwitchCase": { 388 | return group(indent(join(line, path.map(print, "layout")))); 389 | } 390 | case "SwitchStmt": { 391 | const body = path.map(print, "layout"); 392 | const first = body.shift(); 393 | const variable = body.shift(); 394 | const last = body.pop(); 395 | return concat([first, " ", variable, " ", concat(body), last]); 396 | } 397 | case "ThrowStmt": { 398 | return concat([breakParent, smartJoin(" ", path.map(print, "layout"))]); 399 | } 400 | case "CompositionType": 401 | case "FallthroughStmt": 402 | case "IfStmt": 403 | case "AssociatedtypeDecl": // decls 404 | case "TypeAnnotation": // annotations 405 | case "OptionalBindingCondition": // conditions 406 | case "MatchingPatternCondition": 407 | case "CompositionTypeElementList": // lists 408 | case "ForInStmt": // statements 409 | case "WhileStmt": 410 | case "RepeatWhileStmt": 411 | case "BreakStmt": 412 | case "ContinueStmt": 413 | case "DoStmt": 414 | case "DeclarationStmt": 415 | case "ExpressionStmt": { 416 | return smartJoin(" ", path.map(print, "layout")); 417 | } 418 | case "ModifierList": { 419 | n.body = n.layout.slice(); 420 | 421 | if (n.body[0].type === "AttributeList") { 422 | n.attributes = n.body.shift(); 423 | } 424 | 425 | return concat([ 426 | n.attributes ? path.call(print, "attributes") : "", 427 | join(" ", path.map(print, "body")), 428 | n.body.length ? " " : "" 429 | ]); 430 | } 431 | case "AttributeList": { 432 | if (n.layout.length === 0) { 433 | return ""; 434 | } else if ( 435 | !parentType.endsWith("Decl") && 436 | !path.getParentNode(1).type.endsWith("Decl") 437 | ) { 438 | return join(" ", path.map(print, "layout")); 439 | } 440 | 441 | const inline = n.layout.every( 442 | c => 443 | ["IBOutlet", "IBAction", "objc", "testable"].includes( 444 | c.layout[1].text 445 | ) && !(c.layout[2] && c.layout[2].layout.length) 446 | ); 447 | 448 | const breaker = inline ? line : hardline; 449 | 450 | return group(concat([join(breaker, path.map(print, "layout")), breaker])); 451 | } 452 | case "TypeInitializerClause": 453 | case "InitializerClause": { 454 | n.op = n.layout[0]; 455 | n.end = n.layout.slice(1); 456 | 457 | return concat([ 458 | parentType == "PatternBinding" ? " " : "", 459 | path.call(print, "op"), 460 | " ", 461 | group(...path.map(print, "end")) 462 | ]); 463 | } 464 | case "TryExpr": { 465 | const body = path.map(print, "layout"); 466 | const last = body.pop(); 467 | return smartJoin(" ", [concat(body), last]); 468 | } 469 | case "IsExpr": 470 | case "AsExpr": { 471 | const body = path.map(print, "layout"); 472 | const last = body.pop(); 473 | 474 | const maybeIndent = doc => 475 | parentType === "ExprList" ? doc : indent(doc); 476 | 477 | return group(maybeIndent(concat([line, ...body, " ", last]))); 478 | } 479 | case "WhereClause": 480 | case "GenericWhereClause": { 481 | const body = n.layout.slice(); 482 | n.keyword = body.shift(); 483 | n.body = body; 484 | return group( 485 | indent( 486 | concat([ 487 | softline, 488 | path.call(print, "keyword"), 489 | " ", 490 | join(" ", path.map(print, "body")) 491 | ]) 492 | ) 493 | ); 494 | } 495 | case "ExprList": { 496 | if ( 497 | n.layout.length === 3 && 498 | n.layout[1].type === "AssignmentExpr" && 499 | ([ 500 | "ArrayExpr", 501 | "DictionaryExpr", 502 | "FunctionCallExpr", 503 | "ClosureExpr" 504 | ].includes(n.layout[2].type) || 505 | n.layout[2].type.endsWith("LiteralExpr")) 506 | ) { 507 | return group(concat(path.map(print, "layout"))); 508 | } 509 | 510 | return group(indent(concat(path.map(print, "layout")))); 511 | } 512 | case "StringInterpolationExpr": { 513 | return printWithoutNewlines(concat(path.map(print, "layout"))); 514 | } 515 | case "CatchClauseList": { 516 | return join(" ", path.map(print, "layout")); 517 | } 518 | case "ElseDirectiveClause": 519 | case "ElseifDirectiveClause": 520 | case "_IfWithElseConfigDecl": 521 | case "IfConfigDecl": { 522 | const hasCondition = type != "ElseDirectiveClause"; 523 | const body = n.layout.slice(); 524 | 525 | n.keyword = body.shift(); 526 | n.condition = hasCondition ? body.shift() : undefined; 527 | n.code = body.shift(); 528 | n.tail = body; 529 | 530 | const condition = 531 | hasCondition && printWithoutNewlines(path.call(print, "condition")); 532 | 533 | return concat([ 534 | path.call(print, "keyword"), 535 | hasCondition ? concat([" ", condition]) : "", 536 | join(hardline, [ 537 | indent(concat([hardline, path.call(print, "code")])), 538 | ...path.map(print, "tail") 539 | ]) 540 | ]); 541 | } 542 | case "DictionaryType": { 543 | const body = path.map(print, "layout"); 544 | assert.strictEqual(body.length, 5); 545 | const left = body.slice(0, 3); 546 | const right = body.slice(3); 547 | return join(" ", [concat(left), concat(right)]); 548 | } 549 | case "PatternBinding": { 550 | const body = path.map(print, "layout"); 551 | 552 | // Explicit insertion of space for accessor blocks: 553 | // `var name: String_HERE_{ return "123" }` 554 | if (n.layout[n.layout.length - 1].type === "AccessorBlock") { 555 | const rest = body.pop(); 556 | return concat([...body, " ", rest]); 557 | } 558 | 559 | return concat(path.map(print, "layout")); 560 | } 561 | case "TokenList": { 562 | const printedTokens = path.map(print, "layout"); 563 | const elements = []; 564 | let currentElement = []; 565 | 566 | const leftParen = printedTokens.shift(); 567 | const rightParen = printedTokens.pop(); 568 | 569 | printedTokens.forEach(t => { 570 | if (t === ",") { 571 | elements.push(currentElement); 572 | currentElement = []; 573 | } else { 574 | currentElement.push(t); 575 | } 576 | }); 577 | 578 | if (currentElement.length > 0) { 579 | elements.push(currentElement); 580 | } 581 | 582 | return concat([ 583 | leftParen, 584 | join(", ", elements.map(e => join(" ", e))), 585 | rightParen 586 | ]); 587 | } 588 | case "_CaseDecl": { 589 | const body = path.map(print, "layout"); 590 | const keyword = body.shift(); 591 | return concat([keyword, " ", ...body]); 592 | } 593 | case "ParameterClause": { 594 | if (n.layout[1].layout.length === 0) { 595 | return concat(path.map(print, "layout")); 596 | } 597 | 598 | const body = path.map(print, "layout"); 599 | const first = body.shift(); 600 | const last = body.pop(); 601 | 602 | return group( 603 | concat([ 604 | group(concat([indent(concat([first, softline, ...body])), softline])), 605 | last 606 | ]) 607 | ); 608 | } 609 | case "TypeInheritanceClause": { 610 | const body = path.map(print, "layout"); 611 | const first = body.shift(); 612 | return concat([first, " ", group(indent(smartJoin(" ", body)))]); 613 | } 614 | case "FunctionSignature": { 615 | return smartJoin(" ", path.map(print, "layout")); 616 | } 617 | case "ClosureSignature": { 618 | const body = path.map(print, "layout"); 619 | const inKeyword = body.pop(); 620 | 621 | const numberOfStatements = path 622 | .getParentNode() 623 | .layout.find(n => n.type == "CodeBlockItemList").layout.length; 624 | 625 | const printedBody = concat([join(line, body), " ", inKeyword]); 626 | 627 | // Never break for an empty closure expr 628 | if (numberOfStatements === 0) { 629 | return group(printedBody); 630 | } 631 | 632 | return group(indent(indent(concat([softline, group(printedBody)])))); 633 | } 634 | case "CatchClause": { 635 | return smartJoin(" ", path.map(print, "layout")); 636 | } 637 | case "DeferStmt": 638 | case "ValueBindingPattern": 639 | case "AttributedType": 640 | case "ReturnClause": { 641 | return group(smartJoin(" ", path.map(print, "layout"))); 642 | } 643 | case "ClosureCaptureSignature": 644 | case "TupleExpr": 645 | case "TupleType": 646 | case "DictionaryExpr": 647 | case "ArrayExpr": { 648 | const list = n.layout[1]; 649 | 650 | if ( 651 | // Never break inside [:] 652 | !list.layout || 653 | // Never break inside `[]` or `()` 654 | list.layout.length === 0 || 655 | // Never break single element tuples or arrays 656 | (list.layout.length < 2 && 657 | ["TupleExpr", "TupleType", "ArrayExpr"].includes(n.type)) 658 | ) { 659 | return group(concat(path.map(print, "layout"))); 660 | } 661 | 662 | n.left = n.layout[0]; 663 | n.list = list; 664 | n.right = n.layout[2]; 665 | n.rest = n.layout.slice(3); 666 | 667 | return group( 668 | smartJoin(" ", [ 669 | concat([ 670 | path.call(print, "left"), 671 | indent(concat([softline, path.call(print, "list")])), 672 | softline, 673 | path.call(print, "right") 674 | ]), 675 | ...path.map(print, "rest") 676 | ]) 677 | ); 678 | } 679 | case "FunctionType": { 680 | const parts = []; 681 | 682 | for (let i = 0; i < n.layout.length; i++) { 683 | const child = n.layout[i]; 684 | 685 | if (child.type === "l_paren") { 686 | parts.push({ 687 | type: "TupleType", 688 | layout: n.layout.slice(i, i + 3) 689 | }); 690 | 691 | i += 2; 692 | } else { 693 | parts.push(child); 694 | } 695 | } 696 | 697 | n.parts = parts; 698 | return group(smartJoin(" ", path.map(print, "parts"))); 699 | } 700 | case "GenericArgument": 701 | case "SameTypeRequirement": 702 | case "ConformanceRequirement": 703 | case "InheritedType": 704 | case "CaseItem": 705 | case "ClosureCaptureItem": 706 | case "ClosureParam": 707 | case "CompositionTypeElement": 708 | case "ConditionElement": 709 | case "TuplePatternElement": 710 | case "TupleTypeElement": 711 | case "ArrayElement": 712 | case "DictionaryElement": 713 | case "TupleElement": 714 | case "GenericParameter": 715 | case "FunctionCallArgument": 716 | case "FunctionParameter": { 717 | return group( 718 | smartJoin( 719 | " ", 720 | path.map(() => { 721 | return path.getValue().type === "comma" ? "" : print(path); 722 | }, "layout") 723 | ) 724 | ); 725 | } 726 | case "_CaseDeclElement": { 727 | const hasComma = n.layout.some(n => n.type === "comma"); 728 | const hasInitializerClause = n.layout.some( 729 | n => n.type === "InitializerClause" 730 | ); 731 | 732 | const body = path.map(print, "layout"); 733 | 734 | if (hasComma) { 735 | body.pop(); 736 | } 737 | 738 | if (hasInitializerClause) { 739 | const last = body.pop(); 740 | return group(concat([concat(body), " ", last])); 741 | } 742 | 743 | return group(concat(body)); 744 | } 745 | case "ClosureExpr": { 746 | const body = path.map(print, "layout"); 747 | const first = body.shift(); 748 | const last = body.pop(); 749 | const signature = body.length === 1 ? null : body.shift(); 750 | const parent = path.getParentNode(); 751 | const closureIsCallee = parent.layout[0] === n; 752 | 753 | // Don't break when there's no statements, e.g. `{ _ in }` 754 | const hasStatements = n.layout.some( 755 | c => c.type === "CodeBlockItemList" && c.layout.length > 0 756 | ); 757 | 758 | const hasNamedParameters = n.layout.some( 759 | c => 760 | c.type === "ClosureSignature" && 761 | c.layout.some( 762 | c => 763 | c.type === "ClosureParamList" && 764 | c.layout.some(c => 765 | c.layout.some(c => c.type === "identifier" && c.text) 766 | ) 767 | ) 768 | ); 769 | 770 | // Always break if parameters are named 771 | const shouldBreak = 772 | hasStatements && (closureIsCallee || hasNamedParameters); 773 | 774 | // Ensure space when trailing closure `it { ... }` 775 | const prefix = 776 | parent.type === "FunctionCallExpr" && !closureIsCallee ? " " : ""; 777 | 778 | return group( 779 | concat([ 780 | prefix, 781 | first, 782 | signature ? concat([" ", signature]) : "", 783 | hasStatements ? indent(concat([line, ...body])) : "", 784 | shouldBreak ? hardline : line, 785 | last 786 | ]) 787 | ); 788 | } 789 | case "Backtick": { 790 | return "`"; 791 | } 792 | case "Tab": 793 | case "Space": { 794 | return ""; // ignore 795 | } 796 | case "Newline": { 797 | return n.value >= 2 ? hardline : ""; 798 | } 799 | case "GarbageText": 800 | case "DocBlockComment": 801 | case "DocLineComment": 802 | case "BlockComment": 803 | case "LineComment": { 804 | return concat([ 805 | options.leading ? "" : hardline, 806 | n.value, 807 | options.leading ? hardline : "" 808 | ]); 809 | } 810 | case "Unknown": 811 | case "UnknownType": 812 | case "UnknownExpr": 813 | case "UnknownDecl": 814 | case "UnknownStmt": { 815 | const fallback = verbatimPrint(n) 816 | .replace(/^[ \t]+/, "") 817 | .replace(/^[\n]+/, s => (s.split("\n").length >= 2 ? "\n" : "")) 818 | .replace(/\s+$/, s => (s.split("\n").length >= 2 ? "\n" : "")); 819 | 820 | const shorten = s => { 821 | if (s[0] === "\n") { 822 | s = s.slice(1); 823 | } 824 | 825 | s = fallback.replace(/\n/g, "\u23ce"); 826 | 827 | if (s.length > 30) { 828 | s = s.slice(0, 30) + "\u2026"; 829 | } 830 | 831 | return s; 832 | }; 833 | 834 | const message = "libSyntax(" + type + "): " + shorten(fallback); 835 | 836 | if (!process.env.PRETTIER_SWIFT_RENDER_UNKNOWN) { 837 | throw new Error(message); 838 | } 839 | 840 | // eslint-disable-next-line no-console 841 | console.warn(message); 842 | 843 | if (type === "UnknownExpr") { 844 | return concat(path.map(print, "layout")); 845 | } 846 | 847 | return join(hardline, fallback.split("\n")); 848 | } 849 | case "AssignmentExpr": { 850 | return concat([" ", ...path.map(print, "layout"), " "]); 851 | } 852 | case "BinaryOperatorExpr": { 853 | const operator = n.layout[0]; 854 | 855 | if (operator.type.endsWith("_unspaced")) { 856 | return concat(path.map(print, "layout")); 857 | } 858 | 859 | const allowBreak = !operator.text.endsWith("="); 860 | 861 | return concat([ 862 | allowBreak ? line : " ", 863 | ...path.map(print, "layout"), 864 | " " 865 | ]); 866 | } 867 | case "MemberAccessExpr": { 868 | const parts = path.map(print, "layout"); 869 | const first = parts.shift(); 870 | return concat([group(first), concat(parts)]); 871 | } 872 | case "FunctionCallExpr": { 873 | if (!options.argumentsOnly && n.layout[0] && isMemberish(n.layout[0])) { 874 | n.callee = n.layout[0]; 875 | n.callee.object = n.callee.layout[0]; 876 | 877 | try { 878 | return printMemberChain(path, options, print); 879 | } catch (error) { 880 | throw error; 881 | } 882 | } 883 | 884 | const leftIndex = n.layout.findIndex(n => n.type === "l_paren"); 885 | const rightIndex = n.layout.findIndex(n => n.type === "r_paren"); 886 | 887 | if (leftIndex < 0 || rightIndex < 0) { 888 | n.start = n.layout.slice(options.argumentsOnly ? 1 : 0); 889 | return group(concat(path.map(print, "start"))); 890 | } 891 | 892 | const start = options.argumentsOnly 893 | ? n.layout.slice(leftIndex, leftIndex + 1) 894 | : n.layout.slice(0, leftIndex + 1); 895 | const middle = n.layout.slice(leftIndex + 1, rightIndex); 896 | const end = n.layout.slice(rightIndex); 897 | 898 | Object.assign(n, { 899 | start, 900 | middle, 901 | end 902 | }); 903 | 904 | // Optimize: Never break inside if we don't have a parameter 905 | if (middle[0] && middle[0].layout.length == 0) { 906 | return concat([...path.map(print, "start"), ...path.map(print, "end")]); 907 | } 908 | 909 | if ( 910 | middle[0].layout.length == 1 && 911 | // Optimize: Just a closure as argument (RxSwift) 912 | // 913 | // observable.subscribe(onNext: { 914 | // ... 915 | // }) 916 | (middle[0].layout[0].layout.some(n => n.type === "ClosureExpr") || 917 | // Optimize: Plain function invocation as only argument 918 | // 919 | // array.add(User( 920 | // name: "John Doe" 921 | // }) 922 | middle[0].layout[0].layout.some( 923 | n => 924 | n.type === "FunctionCallExpr" && 925 | n.layout[0].type === "IdentifierExpr" 926 | ) || 927 | // Optimize: Array or Dictionary expressions as only argument 928 | // 929 | // array.add([ 930 | // 1, 931 | // 2, 932 | // 3 933 | // }) 934 | middle[0].layout[0].layout.some(n => 935 | ["ArrayExpr", "DictionaryExpr"].includes(n.type) 936 | )) 937 | ) { 938 | return concat([ 939 | ...path.map(print, "start"), 940 | group(concat(path.map(print, "middle"))), 941 | ...path.map(print, "end") 942 | ]); 943 | } 944 | 945 | return concat([ 946 | ...path.map(print, "start"), 947 | group( 948 | concat([ 949 | indent(concat([softline, ...path.map(print, "middle")])), 950 | softline 951 | ]) 952 | ), 953 | ...path.map(print, "end") 954 | ]); 955 | } 956 | case "TernaryExpr": { 957 | const [condition, questionMark, ifTrue, colon, ifFalse] = path.map( 958 | print, 959 | "layout" 960 | ); 961 | 962 | const maybeIndent = doc => 963 | ["ExprList", "TernaryType"].includes(parentType) ? doc : indent(doc); 964 | 965 | // Break the closing paren to keep the chain right after it: 966 | // (a 967 | // ? b 968 | // : c 969 | // ).call() 970 | const breakClosingParen = parentType == "MemberAccessExpr"; 971 | 972 | return group( 973 | concat([ 974 | condition, 975 | maybeIndent( 976 | concat([ 977 | line, 978 | questionMark, 979 | " ", 980 | ifTrue.type === "TernaryExpr" ? ifBreak("", "(") : "", 981 | align(2, group(ifTrue)), 982 | ifTrue.type === "TernaryExpr" ? ifBreak("", "(") : "", 983 | line, 984 | colon, 985 | " ", 986 | align(2, ifFalse) 987 | ]) 988 | ), 989 | breakClosingParen ? softline : "" 990 | ]) 991 | ); 992 | } 993 | 994 | case "SwitchCaseLabel": { 995 | const body = path.map(print, "layout"); 996 | const first = body.shift(); 997 | const last = body.pop(); 998 | return concat([first, " ", ...body, last]); 999 | } 1000 | 1001 | // Types without special formatting but with grouping behavior 1002 | case "_AvailabilityExpr": 1003 | case "_GenericTypeExpr": 1004 | case "_RefExpr": 1005 | case "_SelectorExpr": 1006 | case "AccessorParameter": 1007 | case "AssignExpr": 1008 | case "Attribute": 1009 | case "DeclNameArgument": 1010 | case "DeclNameArgumentList": 1011 | case "DeclNameArguments": 1012 | case "DeclRefExpr": 1013 | case "DiscardAssignmentExpr": 1014 | case "DotSelfExpr": 1015 | case "ExpressionSegment": 1016 | case "ForcedValueExpr": 1017 | case "ForceTryExpr": 1018 | case "GenericArgumentClause": 1019 | case "GenericParameterClause": 1020 | case "IdentifierExpr": 1021 | case "IfExpr": 1022 | case "ImplicitMemberExpr": 1023 | case "InOutExpr": 1024 | case "OptionalChainingExpr": 1025 | case "OptionalTryExpr": 1026 | case "PostfixUnaryExpr": 1027 | case "PrefixOperatorExpr": 1028 | case "PrefixUnaryExpr": 1029 | case "SequenceExpr": 1030 | case "SpecializeExpr": 1031 | case "StringInterpolationSegments": 1032 | case "StringSegment": 1033 | case "SubscriptExpr": 1034 | case "SuperRefExpr": 1035 | case "TupleElementExpr": 1036 | case "TypeExpr": 1037 | case "UnresolvedMemberExpr": 1038 | case "UnresolvedPatternExpr": 1039 | return group(concat(path.map(print, "layout"))); 1040 | 1041 | // Types without special formatting and no grouping behavior 1042 | case "_CaseBlock": 1043 | case "_ClassTypeIdentifier": 1044 | case "AccessPath": 1045 | case "AccessPathComponent": 1046 | case "ArrayType": 1047 | case "BooleanLiteralExpr": 1048 | case "CodeBlockItem": 1049 | case "DeclModifier": 1050 | case "ElseifDirectiveClauseList": 1051 | case "ExpressionPattern": 1052 | case "FloatLiteralExpr": 1053 | case "IdentifierPattern": 1054 | case "ImplicitlyUnwrappedOptionalType": 1055 | case "IntegerLiteralExpr": 1056 | case "InterpolatedStringLiteralExpr": 1057 | case "IsTypePattern": 1058 | case "KeyPathExpr": 1059 | case "MemberTypeIdentifier": 1060 | case "MetatypeType": 1061 | case "NilLiteralExpr": 1062 | case "ObjcKeyPathExpr": 1063 | case "ObjcName": 1064 | case "ObjcNamePiece": 1065 | case "OptionalType": 1066 | case "PoundFileExpr": 1067 | case "PoundFunctionExpr": 1068 | case "PoundLineExpr": 1069 | case "SimpleTypeIdentifier": 1070 | case "StringLiteralExpr": 1071 | case "SwitchDefaultLabel": 1072 | case "TuplePattern": 1073 | case "WildcardPattern": 1074 | return concat(path.map(print, "layout")); 1075 | 1076 | default: 1077 | if (type.endsWith("LiteralExpr")) { 1078 | // eslint-disable-next-line no-console 1079 | console.warn("Unknown literal expression: " + type); 1080 | return concat(path.map(print, "layout")); 1081 | } else if (type.endsWith("Expr")) { 1082 | // eslint-disable-next-line no-console 1083 | console.warn("Unknown expression: " + type); 1084 | return group(concat(path.map(print, "layout"))); 1085 | } 1086 | 1087 | // Maybe someone forgot to add it here: 1088 | // swift/Syntax/Serialization/SyntaxSerialization.h 1089 | // struct ObjectTraits 1090 | error("Unhandled type: " + type); 1091 | return concat(path.map(print, "layout")); 1092 | } 1093 | } 1094 | 1095 | function error(message) { 1096 | // eslint-disable-next-line no-console 1097 | console.error(message); 1098 | 1099 | if (!process.env.IGNORE_ERRORS) { 1100 | throw new Error(message); 1101 | } 1102 | } 1103 | 1104 | module.exports = { 1105 | genericPrint 1106 | }; 1107 | -------------------------------------------------------------------------------- /src/printer/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const comments = require("prettier/src/main/comments"); 4 | const { concat } = require("./builders"); 5 | const { genericPrint } = require("./generic"); 6 | 7 | module.exports = function(path, options, print) { 8 | const n = path.getValue(); 9 | 10 | if (!n) { 11 | throw new Error( 12 | "Illegal navigation into " + 13 | path.getName() + 14 | " from " + 15 | path.getParentNode().type 16 | ); 17 | } 18 | 19 | return concat([ 20 | ...(n.leadingTrivia 21 | ? path.map( 22 | (path, options) => 23 | genericPrint( 24 | path, 25 | Object.assign({}, options, { leading: true }), 26 | print 27 | ), 28 | "leadingTrivia" 29 | ) 30 | : []), 31 | comments.printComments( 32 | path, 33 | () => genericPrint(path, options, print), 34 | options 35 | ), 36 | ...(n.trailingTrivia ? path.map(print, "trailingTrivia") : []) 37 | ]); 38 | }; 39 | -------------------------------------------------------------------------------- /src/printer/tokens.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const tokens = { 4 | amp_prefix: "&", 5 | l_paren: "(", 6 | r_paren: ")", 7 | l_brace: "{", 8 | r_brace: "}", 9 | l_square: "[", 10 | r_square: "]", 11 | l_angle: "<", 12 | r_angle: ">", 13 | arrow: "->", 14 | eof: "", 15 | colon: ":", 16 | comma: ",", 17 | equal: "=", 18 | period: ".", 19 | period_prefix: ".", 20 | question_postfix: "?", 21 | exclaim_postfix: "!", 22 | at_sign: "@", 23 | semi: ";", 24 | question_infix: "?", 25 | string_quote: '"', 26 | backslash: "\\", 27 | string_interpolation_anchor: ")", 28 | multiline_string_quote: '"""' 29 | }; 30 | 31 | const poundPrefix = "pound_"; 32 | 33 | const keywordPrefix = "kw_"; 34 | 35 | function printToken(token) { 36 | if (typeof token.text !== "undefined") { 37 | return token.text; 38 | } 39 | 40 | const type = token.type; 41 | 42 | if (tokens.hasOwnProperty(type)) { 43 | return tokens[type]; 44 | } else if (type.startsWith(poundPrefix)) { 45 | const keyword = type.slice(poundPrefix.length); 46 | return "#" + keyword; 47 | } else if (type.startsWith(keywordPrefix)) { 48 | return type.slice(keywordPrefix.length); 49 | } 50 | 51 | throw new Error( 52 | "Don't know how to express " + 53 | JSON.stringify(type) + 54 | ":\n" + 55 | JSON.stringify(token, null, 2) 56 | ); 57 | } 58 | 59 | module.exports = { 60 | printToken, 61 | tokens 62 | }; 63 | -------------------------------------------------------------------------------- /src/printer/verbatim.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const assert = require("assert"); 4 | const { printToken } = require("./tokens"); 5 | 6 | const characters = { 7 | Newline: "\n", 8 | Tab: "\t", 9 | Space: " ", 10 | Backtick: "`" 11 | }; 12 | 13 | function triviaPrint(n) { 14 | const type = n.type || n.kind; 15 | 16 | switch (type) { 17 | case "Newline": 18 | case "Tab": 19 | case "Space": 20 | case "Backtick": 21 | return Array(n.value) 22 | .fill(characters[type]) 23 | .join(""); 24 | case "GarbageText": 25 | case "DocBlockComment": 26 | case "DocLineComment": 27 | case "BlockComment": 28 | case "LineComment": 29 | return n.value; 30 | default: 31 | throw new Error( 32 | "Unexpected trivium: " + type + "\n" + JSON.stringify(n, null, 2) 33 | ); 34 | } 35 | } 36 | 37 | function verbatimPrint(n) { 38 | if (!n) { 39 | return ""; 40 | } else if (n.presence === "Missing") { 41 | return ""; 42 | } else if (n.presence) { 43 | assert.equal(n.presence, "Present"); 44 | } 45 | 46 | let result = ""; 47 | 48 | if (n.leadingTrivia) { 49 | result += n.leadingTrivia.map(triviaPrint).join(""); 50 | } 51 | 52 | if (n.token) { 53 | result += printToken(n); 54 | } else if (n.tokenKind) { 55 | result += printToken( 56 | Object.assign({}, n.tokenKind, { type: n.tokenKind.kind }) 57 | ); 58 | } else { 59 | result += n.layout.map(verbatimPrint).join(""); 60 | } 61 | 62 | if (n.trailingTrivia) { 63 | result += n.trailingTrivia.map(triviaPrint).join(""); 64 | } 65 | 66 | return result; 67 | } 68 | 69 | module.exports = { 70 | verbatimPrint 71 | }; 72 | -------------------------------------------------------------------------------- /tests/accessors/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`accessors.swift 1`] = ` 4 | class Instance { 5 | public func foo() {} 6 | private func foo() {} 7 | internal func foo() {} 8 | public dynamic func foo() {} 9 | public var foo: String { return "123" } 10 | public private(set) var foo: String { return "123" } 11 | @objc public var foo: String { return "123" } 12 | @objc public var foo: String { 13 | get { 14 | return "123" 15 | } 16 | set(v) { 17 | print(v) 18 | } 19 | } 20 | @IBOutlet public var foo: String { 21 | didSet { 22 | print(oldValue, foo) 23 | } 24 | } 25 | } 26 | class Class { 27 | public class func foo() {} 28 | private class func foo() {} 29 | internal class func foo() {} 30 | } 31 | class Static { 32 | public static func foo() {} 33 | private static func foo() {} 34 | internal static func foo() {} 35 | } 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | class Instance { 38 | public func foo() { } 39 | private func foo() { } 40 | internal func foo() { } 41 | public dynamic func foo() { } 42 | public var foo: String { 43 | return "123" 44 | } 45 | public private(set) var foo: String { 46 | return "123" 47 | } 48 | @objc public var foo: String { 49 | return "123" 50 | } 51 | @objc public var foo: String { 52 | get { 53 | return "123" 54 | } 55 | set(v) { 56 | print(v) 57 | } 58 | } 59 | @IBOutlet public var foo: String { 60 | didSet { 61 | print(oldValue, foo) 62 | } 63 | } 64 | } 65 | class Class { 66 | public class func foo() { } 67 | private class func foo() { } 68 | internal class func foo() { } 69 | } 70 | class Static { 71 | public static func foo() { } 72 | private static func foo() { } 73 | internal static func foo() { } 74 | } 75 | 76 | `; 77 | -------------------------------------------------------------------------------- /tests/accessors/accessors.swift: -------------------------------------------------------------------------------- 1 | class Instance { 2 | public func foo() {} 3 | private func foo() {} 4 | internal func foo() {} 5 | public dynamic func foo() {} 6 | public var foo: String { return "123" } 7 | public private(set) var foo: String { return "123" } 8 | @objc public var foo: String { return "123" } 9 | @objc public var foo: String { 10 | get { 11 | return "123" 12 | } 13 | set(v) { 14 | print(v) 15 | } 16 | } 17 | @IBOutlet public var foo: String { 18 | didSet { 19 | print(oldValue, foo) 20 | } 21 | } 22 | } 23 | class Class { 24 | public class func foo() {} 25 | private class func foo() {} 26 | internal class func foo() {} 27 | } 28 | class Static { 29 | public static func foo() {} 30 | private static func foo() {} 31 | internal static func foo() {} 32 | } 33 | -------------------------------------------------------------------------------- /tests/accessors/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/args/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`args.swift 1`] = ` 4 | func foo() {} 5 | func foo() -> Void {} 6 | func foo(bar: Int) {} 7 | func foo(bar: Int) -> Void {} 8 | func foo(_ bar: Int) {} 9 | func foo(_ bar: Int) -> Void {} 10 | func foo(_ bar: Int = 3) {} 11 | func foo(_ bar: Int = 3) -> Void {} 12 | func foo(_ bar: Int, baz: Int) {} 13 | func foo(_ bar: Int, baz: Int) -> Void {} 14 | func foo(_ bar: Int, _ baz: Int) {} 15 | func foo(_ bar: Int, _ baz: Int) -> Void {} 16 | 17 | func foo(f: @escaping (Int) -> Int) {} 18 | func foo(f: @escaping (Int) -> Int) -> Void {} 19 | func foo(_ f: @escaping (Int) -> Int) {} 20 | func foo(_ f: @escaping (Int) -> Int) -> Void {} 21 | func foo(_ bar: Int, f: @escaping () -> ()) {} 22 | func foo(_ bar: Int, f: @escaping () -> ()) -> Void {} 23 | 24 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheVeryLazyDog() { 25 | print() 26 | } 27 | 28 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog) { 29 | print() 30 | } 31 | 32 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog) -> Bool { 33 | return true 34 | } 35 | 36 | func == (lhs: Record, rhs: Record) -> Bool { 37 | return lhs.id == rhs.id 38 | } 39 | 40 | func isZeroLength(string: String) -> Bool { 41 | return string.isEmpty 42 | } 43 | 44 | class Somewhere { 45 | func hello(title: String = "Hello", _ args: Any...) throws -> SomeType where Foo.E == Bar { 46 | let arr = [ 47 | 1,2,3 48 | ] 49 | let dict = [:]() 50 | _ = hello2(whoCreatesAFunction: "That is sooooooo veeeery long that we need to", breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: false) 51 | return 42 52 | } 53 | 54 | func hello2(whoCreatesAFunction: String = "That is so long that we need to", breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: Bool) -> Int { 55 | print(msg: "hi") { 56 | print("ho") 57 | } 58 | 59 | print(msg: "hi") { 60 | // or what? 61 | print("ho") 62 | } 63 | 64 | return 42 65 | } 66 | 67 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFox: TheQuickBrownFox) -> JumpsOverTheLazyDog<(whetherTheDogIsLazyOrNot: Bool, theMaybeLazyDog: TheMaybeLazyDog)> { 68 | print("jump") 69 | } 70 | } 71 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 72 | func foo() { } 73 | func foo() -> Void { } 74 | func foo(bar: Int) { } 75 | func foo(bar: Int) -> Void { } 76 | func foo(_ bar: Int) { } 77 | func foo(_ bar: Int) -> Void { } 78 | func foo(_ bar: Int = 3) { } 79 | func foo(_ bar: Int = 3) -> Void { } 80 | func foo(_ bar: Int, baz: Int) { } 81 | func foo(_ bar: Int, baz: Int) -> Void { } 82 | func foo(_ bar: Int, _ baz: Int) { } 83 | func foo(_ bar: Int, _ baz: Int) -> Void { } 84 | 85 | func foo(f: @escaping (Int) -> Int) { } 86 | func foo(f: @escaping (Int) -> Int) -> Void { } 87 | func foo(_ f: @escaping (Int) -> Int) { } 88 | func foo(_ f: @escaping (Int) -> Int) -> Void { } 89 | func foo(_ bar: Int, f: @escaping () -> ()) { } 90 | func foo(_ bar: Int, f: @escaping () -> ()) -> Void { } 91 | 92 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheVeryLazyDog() { 93 | print() 94 | } 95 | 96 | func theQuickBrownFoxJumpsOverTheLazyDog( 97 | theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog 98 | ) { 99 | print() 100 | } 101 | 102 | func theQuickBrownFoxJumpsOverTheLazyDog( 103 | theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog 104 | ) -> Bool { 105 | return true 106 | } 107 | 108 | func == (lhs: Record, rhs: Record) -> Bool { 109 | return lhs.id == rhs.id 110 | } 111 | 112 | func isZeroLength(string: String) -> Bool { 113 | return string.isEmpty 114 | } 115 | 116 | class Somewhere { 117 | func hello( 118 | title: String = "Hello", 119 | _ args: Any... 120 | ) throws -> SomeType where Foo.E == Bar { 121 | let arr = [1, 2, 3] 122 | let dict = [:]() 123 | _ = hello2( 124 | whoCreatesAFunction: "That is sooooooo veeeery long that we need to", 125 | breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: false 126 | ) 127 | return 42 128 | } 129 | 130 | func hello2( 131 | whoCreatesAFunction: String = "That is so long that we need to", 132 | breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: Bool 133 | ) -> Int { 134 | print(msg: "hi") { print("ho") } 135 | 136 | print(msg: "hi") { 137 | // or what? 138 | print("ho") 139 | } 140 | 141 | return 42 142 | } 143 | 144 | func theQuickBrownFoxJumpsOverTheLazyDog( 145 | theQuickBrownFox: TheQuickBrownFox 146 | ) -> JumpsOverTheLazyDog<( 147 | whetherTheDogIsLazyOrNot: Bool, 148 | theMaybeLazyDog: TheMaybeLazyDog 149 | )> { 150 | print("jump") 151 | } 152 | } 153 | 154 | `; 155 | -------------------------------------------------------------------------------- /tests/args/args.swift: -------------------------------------------------------------------------------- 1 | func foo() {} 2 | func foo() -> Void {} 3 | func foo(bar: Int) {} 4 | func foo(bar: Int) -> Void {} 5 | func foo(_ bar: Int) {} 6 | func foo(_ bar: Int) -> Void {} 7 | func foo(_ bar: Int = 3) {} 8 | func foo(_ bar: Int = 3) -> Void {} 9 | func foo(_ bar: Int, baz: Int) {} 10 | func foo(_ bar: Int, baz: Int) -> Void {} 11 | func foo(_ bar: Int, _ baz: Int) {} 12 | func foo(_ bar: Int, _ baz: Int) -> Void {} 13 | 14 | func foo(f: @escaping (Int) -> Int) {} 15 | func foo(f: @escaping (Int) -> Int) -> Void {} 16 | func foo(_ f: @escaping (Int) -> Int) {} 17 | func foo(_ f: @escaping (Int) -> Int) -> Void {} 18 | func foo(_ bar: Int, f: @escaping () -> ()) {} 19 | func foo(_ bar: Int, f: @escaping () -> ()) -> Void {} 20 | 21 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheVeryLazyDog() { 22 | print() 23 | } 24 | 25 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog) { 26 | print() 27 | } 28 | 29 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFoxJumpsOverTheLazyDog: TheQuickBrownFoxJumpsOverTheLazyDog) -> Bool { 30 | return true 31 | } 32 | 33 | func == (lhs: Record, rhs: Record) -> Bool { 34 | return lhs.id == rhs.id 35 | } 36 | 37 | func isZeroLength(string: String) -> Bool { 38 | return string.isEmpty 39 | } 40 | 41 | class Somewhere { 42 | func hello(title: String = "Hello", _ args: Any...) throws -> SomeType where Foo.E == Bar { 43 | let arr = [ 44 | 1,2,3 45 | ] 46 | let dict = [:]() 47 | _ = hello2(whoCreatesAFunction: "That is sooooooo veeeery long that we need to", breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: false) 48 | return 42 49 | } 50 | 51 | func hello2(whoCreatesAFunction: String = "That is so long that we need to", breakItToFitTheScreenComeOnNowBREAKBREAKBREAK: Bool) -> Int { 52 | print(msg: "hi") { 53 | print("ho") 54 | } 55 | 56 | print(msg: "hi") { 57 | // or what? 58 | print("ho") 59 | } 60 | 61 | return 42 62 | } 63 | 64 | func theQuickBrownFoxJumpsOverTheLazyDog(theQuickBrownFox: TheQuickBrownFox) -> JumpsOverTheLazyDog<(whetherTheDogIsLazyOrNot: Bool, theMaybeLazyDog: TheMaybeLazyDog)> { 65 | print("jump") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/args/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/arrays/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`arrays.swift 1`] = ` 4 | let oneElement = [42] 5 | let twoElements = ["apple", "banana"] 6 | let someArrayExpressionThatShouldNotBreak = ["becauseItHasSomeVeryLongElementButThatsTheOnlyOne"] 7 | let someArrayExpressionThatShouldBreak = ["becauseItHasSoLongElementsInItThatItHasTo", "andNotJustSingleOne"] 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | let oneElement = [42] 10 | let twoElements = ["apple", "banana"] 11 | let someArrayExpressionThatShouldNotBreak = ["becauseItHasSomeVeryLongElementButThatsTheOnlyOne"] 12 | let someArrayExpressionThatShouldBreak = [ 13 | "becauseItHasSoLongElementsInItThatItHasTo", 14 | "andNotJustSingleOne" 15 | ] 16 | 17 | `; 18 | 19 | exports[`arrays.swift 2`] = ` 20 | let oneElement = [42] 21 | let twoElements = ["apple", "banana"] 22 | let someArrayExpressionThatShouldNotBreak = ["becauseItHasSomeVeryLongElementButThatsTheOnlyOne"] 23 | let someArrayExpressionThatShouldBreak = ["becauseItHasSoLongElementsInItThatItHasTo", "andNotJustSingleOne"] 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 | let oneElement = [42] 26 | let twoElements = ["apple", "banana"] 27 | let someArrayExpressionThatShouldNotBreak = ["becauseItHasSomeVeryLongElementButThatsTheOnlyOne"] 28 | let someArrayExpressionThatShouldBreak = [ 29 | "becauseItHasSoLongElementsInItThatItHasTo", 30 | "andNotJustSingleOne", 31 | ] 32 | 33 | `; 34 | -------------------------------------------------------------------------------- /tests/arrays/arrays.swift: -------------------------------------------------------------------------------- 1 | let oneElement = [42] 2 | let twoElements = ["apple", "banana"] 3 | let someArrayExpressionThatShouldNotBreak = ["becauseItHasSomeVeryLongElementButThatsTheOnlyOne"] 4 | let someArrayExpressionThatShouldBreak = ["becauseItHasSoLongElementsInItThatItHasTo", "andNotJustSingleOne"] 5 | -------------------------------------------------------------------------------- /tests/arrays/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | run_spec(__dirname, ["swift"], { trailingComma: "all" }); 3 | -------------------------------------------------------------------------------- /tests/as/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`as.swift 1`] = ` 4 | let a = b as? C 5 | 6 | theQuickBrownFoxJumpsOverTheLazyDog as? TheQuickBrownFoxJumpsOverTheLazyDog 7 | 8 | let letTheQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog.theQuickBrownFoxJumpsOverTheLazyDog() as? AppViewController 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | let a = b 11 | as? C 12 | 13 | theQuickBrownFoxJumpsOverTheLazyDog 14 | as? TheQuickBrownFoxJumpsOverTheLazyDog 15 | 16 | let letTheQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog.theQuickBrownFoxJumpsOverTheLazyDog() 17 | as? AppViewController 18 | 19 | `; 20 | -------------------------------------------------------------------------------- /tests/as/as.swift: -------------------------------------------------------------------------------- 1 | let a = b as? C 2 | 3 | theQuickBrownFoxJumpsOverTheLazyDog as? TheQuickBrownFoxJumpsOverTheLazyDog 4 | 5 | let letTheQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog.theQuickBrownFoxJumpsOverTheLazyDog() as? AppViewController 6 | -------------------------------------------------------------------------------- /tests/as/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/associatedtype/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`associatedtype.swift 1`] = ` 4 | protocol SomeType { 5 | associatedtype Wrapped 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | protocol SomeType { 9 | associatedtype Wrapped 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/associatedtype/associatedtype.swift: -------------------------------------------------------------------------------- 1 | protocol SomeType { 2 | associatedtype Wrapped 3 | } 4 | -------------------------------------------------------------------------------- /tests/associatedtype/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/attributes/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`attributes.swift 1`] = ` 4 | @testable import SomeModule 5 | 6 | @UIApplicationMain public class MyApp {} 7 | 8 | @objc public class MyApp {} 9 | 10 | @UIApplicationMain @objc public class MyApp {} 11 | 12 | @objc(PSWMyApp) public class MyApp {} 13 | 14 | class SomeClass { 15 | @available(iOS 8, OSX 10.10, *) public func function() {} 16 | 17 | @discardableResult public func function() {} 18 | 19 | @objc public var property: String 20 | 21 | @objc(psw_property) public let property: String 22 | 23 | internal var active: Bool { 24 | @objc(isActive) get {} 25 | set {} 26 | } 27 | } 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | @testable import SomeModule 30 | 31 | @UIApplicationMain 32 | public class MyApp { } 33 | 34 | @objc public class MyApp { } 35 | 36 | @UIApplicationMain 37 | @objc 38 | public class MyApp { } 39 | 40 | @objc(PSWMyApp) 41 | public class MyApp { } 42 | 43 | class SomeClass { 44 | @available(iOS 8, OSX 10.10, *) 45 | public func function() { } 46 | 47 | @discardableResult 48 | public func function() { } 49 | 50 | @objc public var property: String 51 | 52 | @objc(psw_property) 53 | public let property: String 54 | 55 | internal var active: Bool { 56 | @objc(isActive) 57 | get { } 58 | set { } 59 | } 60 | } 61 | 62 | `; 63 | -------------------------------------------------------------------------------- /tests/attributes/attributes.swift: -------------------------------------------------------------------------------- 1 | @testable import SomeModule 2 | 3 | @UIApplicationMain public class MyApp {} 4 | 5 | @objc public class MyApp {} 6 | 7 | @UIApplicationMain @objc public class MyApp {} 8 | 9 | @objc(PSWMyApp) public class MyApp {} 10 | 11 | class SomeClass { 12 | @available(iOS 8, OSX 10.10, *) public func function() {} 13 | 14 | @discardableResult public func function() {} 15 | 16 | @objc public var property: String 17 | 18 | @objc(psw_property) public let property: String 19 | 20 | internal var active: Bool { 21 | @objc(isActive) get {} 22 | set {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/attributes/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/backtick/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`backtick.swift 1`] = ` 4 | call { [weak self] in 5 | let \`self\` = self 6 | print(self) 7 | } 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | call { [weak self] in 10 | let \`self\` = self 11 | print(self) 12 | } 13 | 14 | `; 15 | -------------------------------------------------------------------------------- /tests/backtick/backtick.swift: -------------------------------------------------------------------------------- 1 | call { [weak self] in 2 | let `self` = self 3 | print(self) 4 | } 5 | -------------------------------------------------------------------------------- /tests/backtick/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/bugs/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`bugs.swift 1`] = ` 4 | #!/usr/bin/swift 5 | button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside) 6 | 7 | print(optional ?? []) 8 | 9 | let x = PublishSubject() 10 | 11 | NSNumber.self 12 | 13 | class Spinner: UIView { 14 | let rotationDuration = 0.9; 15 | } 16 | 17 | protocol Something { 18 | associatedtype T1 19 | associatedtype T2: Foo, Bar 20 | } 21 | 22 | [1, 2, 3].map { (partial) -> String in 23 | "\\(partial)" 24 | } 25 | 26 | let firstTupleElement = tuple.0 27 | 28 | let semicolons = foo(); 29 | 30 | [1,2,3].map { $0 + 1 } 31 | 32 | let foo = { bar(); baz() } 33 | 34 | let sub = { (\`self\`) -> Disposable in self.subscribe() } 35 | 36 | @available(iOS 8, OSX 10.10, *) 37 | func foo(x: Int) -> String { 38 | 39 | } 40 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 41 | #!/usr/bin/swift 42 | button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside) 43 | 44 | print(optional ?? []) 45 | 46 | let x = PublishSubject() 47 | 48 | NSNumber.self 49 | 50 | class Spinner: UIView { 51 | let rotationDuration = 0.9 52 | } 53 | 54 | protocol Something { 55 | associatedtype T1 56 | associatedtype T2: Foo, Bar 57 | } 58 | 59 | [1, 2, 3].map { partial -> String in 60 | "\\(partial)" 61 | } 62 | 63 | let firstTupleElement = tuple.0 64 | 65 | let semicolons = foo(); 66 | 67 | [1, 2, 3].map { $0 + 1 } 68 | 69 | let foo = { 70 | bar(); 71 | baz() 72 | } 73 | 74 | let sub = { \`self\` -> Disposable in 75 | self.subscribe() 76 | } 77 | 78 | @available(iOS 8, OSX 10.10, *) 79 | func foo(x: Int) -> String { } 80 | 81 | `; 82 | 83 | exports[`closure_with_parens.swift 1`] = ` 84 | let foo = { (_, user: User) in print(user) } 85 | 86 | // This will not be formatted because the above line prevents us 87 | // from processing this whole file. 88 | let array = [1,2,3] 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | 91 | let foo = { (_, user: User) in print(user) } 92 | 93 | // This will not be formatted because the above line prevents us 94 | // from processing this whole file. 95 | let array = [1,2,3] 96 | 97 | `; 98 | -------------------------------------------------------------------------------- /tests/bugs/bugs.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/swift 2 | button.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside) 3 | 4 | print(optional ?? []) 5 | 6 | let x = PublishSubject() 7 | 8 | NSNumber.self 9 | 10 | class Spinner: UIView { 11 | let rotationDuration = 0.9; 12 | } 13 | 14 | protocol Something { 15 | associatedtype T1 16 | associatedtype T2: Foo, Bar 17 | } 18 | 19 | [1, 2, 3].map { (partial) -> String in 20 | "\(partial)" 21 | } 22 | 23 | let firstTupleElement = tuple.0 24 | 25 | let semicolons = foo(); 26 | 27 | [1,2,3].map { $0 + 1 } 28 | 29 | let foo = { bar(); baz() } 30 | 31 | let sub = { (`self`) -> Disposable in self.subscribe() } 32 | 33 | @available(iOS 8, OSX 10.10, *) 34 | func foo(x: Int) -> String { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /tests/bugs/closure_with_parens.swift: -------------------------------------------------------------------------------- 1 | let foo = { (_, user: User) in print(user) } 2 | 3 | // This will not be formatted because the above line prevents us 4 | // from processing this whole file. 5 | let array = [1,2,3] 6 | -------------------------------------------------------------------------------- /tests/bugs/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/captures/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`captures.swift 1`] = ` 4 | do { 5 | do { 6 | do { 7 | do { 8 | theQuickBrownFoxJumpsOverTheLazyDog { [capture, something] () -> TheQuickBrownFoxJumpsOverTheLazyDog in 9 | print(1) 10 | print(2) 11 | } 12 | } 13 | } 14 | } 15 | }~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | do { 17 | do { 18 | do { 19 | do { 20 | theQuickBrownFoxJumpsOverTheLazyDog { 21 | [capture, something] 22 | () 23 | -> TheQuickBrownFoxJumpsOverTheLazyDog in 24 | print(1) 25 | print(2) 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | `; 33 | -------------------------------------------------------------------------------- /tests/captures/captures.swift: -------------------------------------------------------------------------------- 1 | do { 2 | do { 3 | do { 4 | do { 5 | theQuickBrownFoxJumpsOverTheLazyDog { [capture, something] () -> TheQuickBrownFoxJumpsOverTheLazyDog in 6 | print(1) 7 | print(2) 8 | } 9 | } 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /tests/captures/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/chains/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`chains.swift 1`] = ` 4 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog).map( 5 | theQuickBrownFoxJumpsOverTheLazyDog 6 | ) 7 | 8 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog) 9 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 10 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 11 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 12 | 13 | Observable.using(resource) { return theQuickBrownFoxJumpsOverTheLazyDog } 14 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 15 | 16 | // The first line will be formatted weirdly, 17 | // but prettier JS exposes the same issue. 18 | TheQuickBrownFoxJumpsOverTheLazyDog 19 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 20 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 21 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 22 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog).map( 24 | theQuickBrownFoxJumpsOverTheLazyDog 25 | ) 26 | 27 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog) 28 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 29 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 30 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 31 | 32 | Observable.using(resource) { 33 | return theQuickBrownFoxJumpsOverTheLazyDog 34 | }.map(theQuickBrownFoxJumpsOverTheLazyDog) 35 | 36 | // The first line will be formatted weirdly, 37 | // but prettier JS exposes the same issue. 38 | TheQuickBrownFoxJumpsOverTheLazyDog.map( 39 | theQuickBrownFoxJumpsOverTheLazyDog 40 | ) 41 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 42 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 43 | 44 | `; 45 | -------------------------------------------------------------------------------- /tests/chains/chains.swift: -------------------------------------------------------------------------------- 1 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog).map( 2 | theQuickBrownFoxJumpsOverTheLazyDog 3 | ) 4 | 5 | Observable.just(theQuickBrownFoxJumpsOverTheLazyDog) 6 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 7 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 8 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 9 | 10 | Observable.using(resource) { return theQuickBrownFoxJumpsOverTheLazyDog } 11 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 12 | 13 | // The first line will be formatted weirdly, 14 | // but prettier JS exposes the same issue. 15 | TheQuickBrownFoxJumpsOverTheLazyDog 16 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 17 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 18 | .map(theQuickBrownFoxJumpsOverTheLazyDog) 19 | -------------------------------------------------------------------------------- /tests/chains/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/comments/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`chain.swift 1`] = ` 4 | chain // next to root 5 | .map({ true /* inside */ }) // same line as map 6 | .map { true } 7 | // after 8 | .map { true } 9 | // after all 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | chain // next to root 12 | .map({ 13 | true /* inside */ 14 | }) // same line as map 15 | .map { true } 16 | // after 17 | .map { true } 18 | // after all 19 | 20 | `; 21 | 22 | exports[`comments.swift 1`] = ` 23 | // before print("1") 24 | print("1") // same line as print("1") 25 | // after print("1") 26 | 27 | print("2") 28 | 29 | // with empty line 30 | 31 | print("3") 32 | 33 | print/* inside */(/* inside */"4") 34 | 35 | print( 36 | "5" // after argument 37 | ) 38 | 39 | chain 40 | // after root 41 | .map { true } 42 | // after 43 | 44 | self.map { true } 45 | 46 | let answer = /* deep */ /* blue */ 42 47 | 48 | let array = [ 49 | 0, // 0% 50 | 25, 51 | 50, // 50%, 52 | 75, 53 | 100 // 100% 54 | ] 55 | 56 | if something { 57 | print("ifTrue") 58 | } 59 | // comment 60 | else { 61 | print("ifFalse") 62 | } 63 | 64 | // asd 65 | a() 66 | 67 | // available-check 68 | if #available(iOS 11.3, tvOS 11.3, *) { 69 | print("available") 70 | } 71 | 72 | class SomeClass { 73 | var property: String { 74 | get { 75 | // comment 76 | return "hello" 77 | } 78 | } 79 | } 80 | 81 | let loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore = [ 82 | "loremIpsumDolorSitAmetConsecteturAdipiscing", // elitSedDoEiusmodTemporIncididuntUtLabore 83 | "loremIpsumDolorSitAmetConsecteturAdipiscing" // elitSedDoEiusmodTemporIncididuntUtLabore 84 | ] 85 | 86 | private enum EditEvent : CustomDebugStringConvertible { 87 | case inserted // can't be found in old sections 88 | } 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 90 | // before print("1") 91 | print("1") // same line as print("1") 92 | // after print("1") 93 | 94 | print("2") 95 | 96 | // with empty line 97 | 98 | print("3") 99 | 100 | print(/* inside */ /* inside */ "4") 101 | 102 | print( 103 | "5" // after argument 104 | ) 105 | 106 | chain 107 | // after root 108 | .map { true } 109 | // after 110 | 111 | self.map { true } 112 | 113 | let answer = /* deep */ /* blue */ 42 114 | 115 | let array = [ 116 | 0, // 0% 117 | 25, 118 | 50, // 50%, 119 | 75, 120 | 100 // 100% 121 | ] 122 | 123 | if something { 124 | print("ifTrue") 125 | } else // comment 126 | { 127 | print("ifFalse") 128 | } 129 | 130 | // asd 131 | a() 132 | 133 | // available-check 134 | if #available(iOS 11.3, tvOS 11.3, *) { 135 | print("available") 136 | } 137 | 138 | class SomeClass { 139 | var property: String { 140 | get { 141 | // comment 142 | return "hello" 143 | } 144 | } 145 | } 146 | 147 | let loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore = [ 148 | "loremIpsumDolorSitAmetConsecteturAdipiscing", // elitSedDoEiusmodTemporIncididuntUtLabore 149 | "loremIpsumDolorSitAmetConsecteturAdipiscing" // elitSedDoEiusmodTemporIncididuntUtLabore 150 | ] 151 | 152 | private enum EditEvent: CustomDebugStringConvertible { 153 | case inserted // can't be found in old sections 154 | } 155 | 156 | `; 157 | 158 | exports[`only.swift 1`] = ` 159 | // Only comment 160 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 161 | // Only comment 162 | 163 | `; 164 | -------------------------------------------------------------------------------- /tests/comments/chain.swift: -------------------------------------------------------------------------------- 1 | chain // next to root 2 | .map({ true /* inside */ }) // same line as map 3 | .map { true } 4 | // after 5 | .map { true } 6 | // after all 7 | -------------------------------------------------------------------------------- /tests/comments/comments.swift: -------------------------------------------------------------------------------- 1 | // before print("1") 2 | print("1") // same line as print("1") 3 | // after print("1") 4 | 5 | print("2") 6 | 7 | // with empty line 8 | 9 | print("3") 10 | 11 | print/* inside */(/* inside */"4") 12 | 13 | print( 14 | "5" // after argument 15 | ) 16 | 17 | chain 18 | // after root 19 | .map { true } 20 | // after 21 | 22 | self.map { true } 23 | 24 | let answer = /* deep */ /* blue */ 42 25 | 26 | let array = [ 27 | 0, // 0% 28 | 25, 29 | 50, // 50%, 30 | 75, 31 | 100 // 100% 32 | ] 33 | 34 | if something { 35 | print("ifTrue") 36 | } 37 | // comment 38 | else { 39 | print("ifFalse") 40 | } 41 | 42 | // asd 43 | a() 44 | 45 | // available-check 46 | if #available(iOS 11.3, tvOS 11.3, *) { 47 | print("available") 48 | } 49 | 50 | class SomeClass { 51 | var property: String { 52 | get { 53 | // comment 54 | return "hello" 55 | } 56 | } 57 | } 58 | 59 | let loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore = [ 60 | "loremIpsumDolorSitAmetConsecteturAdipiscing", // elitSedDoEiusmodTemporIncididuntUtLabore 61 | "loremIpsumDolorSitAmetConsecteturAdipiscing" // elitSedDoEiusmodTemporIncididuntUtLabore 62 | ] 63 | 64 | private enum EditEvent : CustomDebugStringConvertible { 65 | case inserted // can't be found in old sections 66 | } 67 | -------------------------------------------------------------------------------- /tests/comments/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/comments/only.swift: -------------------------------------------------------------------------------- 1 | // Only comment 2 | -------------------------------------------------------------------------------- /tests/composition/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`composition.swift 1`] = ` 4 | typealias AB = A & B 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | typealias AB = A & B 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /tests/composition/composition.swift: -------------------------------------------------------------------------------- 1 | typealias AB = A & B 2 | -------------------------------------------------------------------------------- /tests/composition/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/continue/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`continue.swift 1`] = ` 4 | for i in 0...16 { 5 | continue 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | for i in 0...16 { 9 | continue 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/continue/continue.swift: -------------------------------------------------------------------------------- 1 | for i in 0...16 { 2 | continue 3 | } 4 | -------------------------------------------------------------------------------- /tests/continue/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/defer/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`defer.swift 1`] = ` 4 | func test() { 5 | defer { print("hi") } 6 | 7 | defer { 8 | print("hello") 9 | print("world") 10 | } 11 | } 12 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 | func test() { 14 | defer { print("hi") } 15 | 16 | defer { 17 | print("hello") 18 | print("world") 19 | } 20 | } 21 | 22 | `; 23 | -------------------------------------------------------------------------------- /tests/defer/defer.swift: -------------------------------------------------------------------------------- 1 | func test() { 2 | defer { print("hi") } 3 | 4 | defer { 5 | print("hello") 6 | print("world") 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/defer/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/deinit/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`deinit.swift 1`] = ` 4 | class Something { 5 | deinit {} 6 | deinit { 7 | print("deinit") 8 | } 9 | } 10 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 | class Something { 12 | deinit { } 13 | deinit { 14 | print("deinit") 15 | } 16 | } 17 | 18 | `; 19 | -------------------------------------------------------------------------------- /tests/deinit/deinit.swift: -------------------------------------------------------------------------------- 1 | class Something { 2 | deinit {} 3 | deinit { 4 | print("deinit") 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/deinit/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/dictionaries/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`dictionaries.swift 1`] = ` 4 | let oneElement = ["answer": 42] 5 | let twoElements = ["apple": 1, "banana": 2] 6 | let someDictionaryExpressionThatShouldBreak = ["becauseItHasOneVeryLongElement": "thatForcesItToBreak"] 7 | let someDictionaryExpressionThatShouldAlsoBreak = ["because": "itHas", "soLongElementsInIt": "thatItHasTo"] 8 | let someDictionaryExpressionThatIsJustPrintedOfTheDocumentPrintWidthBoundary = [:] 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | let oneElement = ["answer": 42] 11 | let twoElements = ["apple": 1, "banana": 2] 12 | let someDictionaryExpressionThatShouldBreak = [ 13 | "becauseItHasOneVeryLongElement": "thatForcesItToBreak" 14 | ] 15 | let someDictionaryExpressionThatShouldAlsoBreak = [ 16 | "because": "itHas", 17 | "soLongElementsInIt": "thatItHasTo" 18 | ] 19 | let someDictionaryExpressionThatIsJustPrintedOfTheDocumentPrintWidthBoundary = [:] 20 | 21 | `; 22 | 23 | exports[`dictionaries.swift 2`] = ` 24 | let oneElement = ["answer": 42] 25 | let twoElements = ["apple": 1, "banana": 2] 26 | let someDictionaryExpressionThatShouldBreak = ["becauseItHasOneVeryLongElement": "thatForcesItToBreak"] 27 | let someDictionaryExpressionThatShouldAlsoBreak = ["because": "itHas", "soLongElementsInIt": "thatItHasTo"] 28 | let someDictionaryExpressionThatIsJustPrintedOfTheDocumentPrintWidthBoundary = [:] 29 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 30 | let oneElement = ["answer": 42] 31 | let twoElements = ["apple": 1, "banana": 2] 32 | let someDictionaryExpressionThatShouldBreak = [ 33 | "becauseItHasOneVeryLongElement": "thatForcesItToBreak", 34 | ] 35 | let someDictionaryExpressionThatShouldAlsoBreak = [ 36 | "because": "itHas", 37 | "soLongElementsInIt": "thatItHasTo", 38 | ] 39 | let someDictionaryExpressionThatIsJustPrintedOfTheDocumentPrintWidthBoundary = [:] 40 | 41 | `; 42 | -------------------------------------------------------------------------------- /tests/dictionaries/dictionaries.swift: -------------------------------------------------------------------------------- 1 | let oneElement = ["answer": 42] 2 | let twoElements = ["apple": 1, "banana": 2] 3 | let someDictionaryExpressionThatShouldBreak = ["becauseItHasOneVeryLongElement": "thatForcesItToBreak"] 4 | let someDictionaryExpressionThatShouldAlsoBreak = ["because": "itHas", "soLongElementsInIt": "thatItHasTo"] 5 | let someDictionaryExpressionThatIsJustPrintedOfTheDocumentPrintWidthBoundary = [:] 6 | -------------------------------------------------------------------------------- /tests/dictionaries/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | run_spec(__dirname, ["swift"], { trailingComma: "all" }); 3 | -------------------------------------------------------------------------------- /tests/dummy/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`dummy.swift 1`] = ` 4 | // A reminder to myself on how to quickly create a throw away gui app on OSX (i.e. a single file, 5 | // w/o relying on XCode project templates 6 | 7 | //Notes: In general it is hard to know how to create a Cocoa based gui without using XCode. 8 | //This issue has existed for both Objective-C and now Swift 9 | 10 | //Furthermore, Swift<-->Cocoa syntax has changed dramatically over various Swift versions, 11 | //making stackoverflow posts unreliable 12 | 13 | //This file provides a template for creating a throw away gui app 14 | 15 | //Status: macOS only -- throw away apps for devices have many non-trivial aspects 16 | 17 | //Status: This currenty works under swift 3 + package manager (just replace the main.swift generated 18 | // with swift init --executable with this file 19 | // However, it is not currently Swifty 20 | 21 | //todo: 22 | // add metal custom view or sprite kit demo to demonstrate using more frameworks 23 | 24 | import Cocoa 25 | 26 | print("Hello, world!") 27 | 28 | //todo: remind myself what this does 29 | NSApplication.shared() 30 | 31 | //#1 status bar 32 | let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength).foo() 33 | statusItem.title = "Quit" 34 | // statusItem.action = #selector(NSApplication.terminate) 35 | 36 | 37 | //#2 random window (not the typical pattern) 38 | let window = NSWindow(contentRect: NSMakeRect(0, 0, 320, 200), 39 | styleMask: .titled, 40 | backing: .buffered, 41 | defer: true) 42 | window.orderFrontRegardless() 43 | 44 | 45 | //#3 App delegate (more typical pattern) 46 | class AppDel: NSObject, NSApplicationDelegate { 47 | var mainWindow: NSWindow? 48 | 49 | var foo: Bar 50 | 51 | func applicationDidFinishLaunching(_ aNotification: Notification) { 52 | print("Finished Launching") 53 | 54 | 55 | let window = NSWindow(contentRect: NSMakeRect(800, 600, 320, 200), 56 | styleMask: [.titled, .closable], 57 | backing: .buffered, 58 | defer: true) 59 | window.orderFrontRegardless() 60 | self.mainWindow = window 61 | 62 | NSApp.activate(ignoringOtherApps: true) 63 | } 64 | 65 | func applicationShouldTerminateAfterLastWindowClosed(_ app: NSApplication) -> Bool { 66 | return true 67 | } 68 | 69 | var fooProp: String { 70 | return "foo" 71 | } 72 | 73 | public override init() { 74 | super.init() 75 | } 76 | 77 | init(whitelist: @escaping Comparison = { _ -> Bool in return true }, blacklist: @escaping Comparison = { _ -> Bool in return true } ) { 78 | self.whitelist = whitelist 79 | self.blacklist = blacklist 80 | } 81 | 82 | init(endpointClosure: @escaping MoyaProvider.EndpointClosure = MoyaProvider.defaultEndpointMapping, 83 | requestClosure: @escaping MoyaProvider.RequestClosure = MoyaProvider.defaultRequestMapping) { 84 | print("foo") 85 | } 86 | 87 | deinit { 88 | print("deinit") 89 | } 90 | 91 | lazy var lazyFooProp: String = { 92 | return "foo" 93 | }() 94 | 95 | func logPath() -> URL { 96 | let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! 97 | print(docs) 98 | } 99 | 100 | dynamic let artworkImageView = ListingsCollectionViewCell._artworkImageView() 101 | 102 | typealias DownloadImageClosure = (_ url: URL?, _ imageView: UIImageView) -> () 103 | } 104 | 105 | typealias Dictionary = [String: AnyObject] 106 | 107 | NSApp.setActivationPolicy(.regular) 108 | 109 | let del = AppDel() 110 | NSApp.delegate = del 111 | 112 | NSApp.run() 113 | 114 | typealias Foo = Int 115 | 116 | func foo123() -> (String) -> Void { } 117 | 118 | enum Foo { 119 | case bar 120 | } 121 | 122 | enum FooInt: Int { 123 | case bar = 3 124 | case baz, bat = 3 125 | } 126 | 127 | extension Foo: CustomStringConvertible { } 128 | extension Observable where Element: BooleanType { } 129 | 130 | let bar1 = foo as? Int 131 | let bar2 = foo as! Int 132 | let bar3 = foo as Int 133 | 134 | if foo { 135 | print("1") 136 | } else if bar { 137 | print("2") 138 | } else { 139 | print("3") 140 | } 141 | 142 | let x = foo ? "YES" : "NO" 143 | 144 | present(vc) {} 145 | 146 | func foo(completion: @escaping (String) -> Void) { } 147 | 148 | observer.onNext((self.appViewController.presentedViewController as? FulfillmentContainerViewController) != nil) 149 | 150 | if case .leaf(let value) = node { 151 | print(value) 152 | } 153 | 154 | let o = AnyObserver { [weak self, foo] event in 155 | print(event, foo) 156 | } 157 | 158 | var requestBidderDetailsCommand = { (enabled: Observable) -> CocoaAction in 159 | appDelegate().requestBidderDetailsCommand(enabled: enabled) 160 | } 161 | 162 | let rotationAnimation = CABasicAnimation(keyPath:"transform") 163 | 164 | extension Collection where Iterator.Element: ObservableType, Iterator.Element.E: BooleanType { 165 | 166 | } 167 | 168 | guard let dollars = formatter.string(from: NSDecimalNumber(mantissa: cents, exponent: -2, isNegative: false)) else { 169 | return "" 170 | } 171 | 172 | cardHandler.cardStatus 173 | .subscribe { (event) in 174 | print(event) 175 | } 176 | .addDisposableTo(rx_disposeBag) 177 | 178 | func detectDevelopmentEnvironment() -> Bool { 179 | var developmentEnvironment = false 180 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 181 | developmentEnvironment = true 182 | #elseif os(macOS) 183 | developmentEnvironment = false 184 | #else 185 | developmentEnvironment = 32 186 | #endif 187 | return developmentEnvironment 188 | } 189 | 190 | extension UIView { 191 | public var rx_hidden: AnyObserver { 192 | return AnyObserver { [weak self] event in 193 | MainScheduler.ensureExecutingOnScheduler() 194 | } 195 | } 196 | } 197 | 198 | func didReceiveResponse(_ result: Result, target: TargetType) { 199 | print() 200 | } 201 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 202 | // A reminder to myself on how to quickly create a throw away gui app on OSX (i.e. a single file, 203 | // w/o relying on XCode project templates 204 | 205 | //Notes: In general it is hard to know how to create a Cocoa based gui without using XCode. 206 | //This issue has existed for both Objective-C and now Swift 207 | 208 | //Furthermore, Swift<-->Cocoa syntax has changed dramatically over various Swift versions, 209 | //making stackoverflow posts unreliable 210 | 211 | //This file provides a template for creating a throw away gui app 212 | 213 | //Status: macOS only -- throw away apps for devices have many non-trivial aspects 214 | 215 | //Status: This currenty works under swift 3 + package manager (just replace the main.swift generated 216 | // with swift init --executable with this file 217 | // However, it is not currently Swifty 218 | 219 | //todo: 220 | // add metal custom view or sprite kit demo to demonstrate using more frameworks 221 | 222 | import Cocoa 223 | 224 | print("Hello, world!") 225 | 226 | //todo: remind myself what this does 227 | NSApplication.shared() 228 | 229 | //#1 status bar 230 | let statusItem = NSStatusBar.system() 231 | .statusItem(withLength: NSVariableStatusItemLength) 232 | .foo() 233 | statusItem.title = "Quit" 234 | // statusItem.action = #selector(NSApplication.terminate) 235 | 236 | //#2 random window (not the typical pattern) 237 | let window = NSWindow( 238 | contentRect: NSMakeRect(0, 0, 320, 200), 239 | styleMask: .titled, 240 | backing: .buffered, 241 | defer: true 242 | ) 243 | window.orderFrontRegardless() 244 | 245 | //#3 App delegate (more typical pattern) 246 | class AppDel: NSObject, NSApplicationDelegate { 247 | var mainWindow: NSWindow? 248 | 249 | var foo: Bar 250 | 251 | func applicationDidFinishLaunching(_ aNotification: Notification) { 252 | print("Finished Launching") 253 | 254 | let window = NSWindow( 255 | contentRect: NSMakeRect(800, 600, 320, 200), 256 | styleMask: [.titled, .closable], 257 | backing: .buffered, 258 | defer: true 259 | ) 260 | window.orderFrontRegardless() 261 | self.mainWindow = window 262 | 263 | NSApp.activate(ignoringOtherApps: true) 264 | } 265 | 266 | func applicationShouldTerminateAfterLastWindowClosed( 267 | _ app: NSApplication 268 | ) -> Bool { 269 | return true 270 | } 271 | 272 | var fooProp: String { 273 | return "foo" 274 | } 275 | 276 | public override init() { 277 | super.init() 278 | } 279 | 280 | init( 281 | whitelist: @escaping Comparison = { _ -> Bool in 282 | return true 283 | }, 284 | blacklist: @escaping Comparison = { _ -> Bool in 285 | return true 286 | } 287 | ) { 288 | self.whitelist = whitelist 289 | self.blacklist = blacklist 290 | } 291 | 292 | init( 293 | endpointClosure: @escaping MoyaProvider.EndpointClosure = MoyaProvider.defaultEndpointMapping, 294 | requestClosure: @escaping MoyaProvider.RequestClosure = MoyaProvider.defaultRequestMapping 295 | ) { 296 | print("foo") 297 | } 298 | 299 | deinit { 300 | print("deinit") 301 | } 302 | 303 | lazy var lazyFooProp: String = { 304 | return "foo" 305 | }() 306 | 307 | func logPath() -> URL { 308 | let docs = FileManager.default.urls( 309 | for: .documentDirectory, 310 | in: .userDomainMask 311 | ).last! 312 | print(docs) 313 | } 314 | 315 | dynamic let artworkImageView = ListingsCollectionViewCell._artworkImageView() 316 | 317 | typealias DownloadImageClosure = ( 318 | _ url: URL?, 319 | _ imageView: UIImageView 320 | ) -> () 321 | } 322 | 323 | typealias Dictionary = [String: AnyObject] 324 | 325 | NSApp.setActivationPolicy(.regular) 326 | 327 | let del = AppDel() 328 | NSApp.delegate = del 329 | 330 | NSApp.run() 331 | 332 | typealias Foo = Int 333 | 334 | func foo123() -> (String) -> Void { } 335 | 336 | enum Foo { 337 | case bar 338 | } 339 | 340 | enum FooInt: Int { 341 | case bar = 3 342 | case baz, bat = 3 343 | } 344 | 345 | extension Foo: CustomStringConvertible { } 346 | extension Observable where Element: BooleanType { } 347 | 348 | let bar1 = foo as? Int 349 | let bar2 = foo as! Int 350 | let bar3 = foo 351 | as Int 352 | 353 | if foo { 354 | print("1") 355 | } else if bar { 356 | print("2") 357 | } else { 358 | print("3") 359 | } 360 | 361 | let x = foo ? "YES" : "NO" 362 | 363 | present(vc) { } 364 | 365 | func foo(completion: @escaping (String) -> Void) { } 366 | 367 | observer.onNext( 368 | (self.appViewController.presentedViewController 369 | as? FulfillmentContainerViewController) != nil 370 | ) 371 | 372 | if case .leaf(let value) = node { 373 | print(value) 374 | } 375 | 376 | let o = AnyObserver { [weak self, foo] event in 377 | print(event, foo) 378 | } 379 | 380 | var requestBidderDetailsCommand = { 381 | (enabled: Observable) -> CocoaAction in 382 | appDelegate().requestBidderDetailsCommand(enabled: enabled) 383 | } 384 | 385 | let rotationAnimation = CABasicAnimation(keyPath: "transform") 386 | 387 | extension Collection 388 | where Iterator.Element: ObservableType, Iterator.Element.E: BooleanType { } 389 | 390 | guard let dollars = formatter.string(from: NSDecimalNumber( 391 | mantissa: cents, 392 | exponent: -2, 393 | isNegative: false 394 | )) else { return "" } 395 | 396 | cardHandler.cardStatus 397 | .subscribe { event in 398 | print(event) 399 | } 400 | .addDisposableTo(rx_disposeBag) 401 | 402 | func detectDevelopmentEnvironment() -> Bool { 403 | var developmentEnvironment = false 404 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 405 | developmentEnvironment = true 406 | #elseif os(macOS) 407 | developmentEnvironment = false 408 | #else 409 | developmentEnvironment = 32 410 | #endif 411 | return developmentEnvironment 412 | } 413 | 414 | extension UIView { 415 | public var rx_hidden: AnyObserver { 416 | return AnyObserver { [weak self] event in 417 | MainScheduler.ensureExecutingOnScheduler() 418 | } 419 | } 420 | } 421 | 422 | func didReceiveResponse( 423 | _ result: Result, 424 | target: TargetType 425 | ) { 426 | print() 427 | } 428 | 429 | `; 430 | -------------------------------------------------------------------------------- /tests/dummy/dummy.swift: -------------------------------------------------------------------------------- 1 | // A reminder to myself on how to quickly create a throw away gui app on OSX (i.e. a single file, 2 | // w/o relying on XCode project templates 3 | 4 | //Notes: In general it is hard to know how to create a Cocoa based gui without using XCode. 5 | //This issue has existed for both Objective-C and now Swift 6 | 7 | //Furthermore, Swift<-->Cocoa syntax has changed dramatically over various Swift versions, 8 | //making stackoverflow posts unreliable 9 | 10 | //This file provides a template for creating a throw away gui app 11 | 12 | //Status: macOS only -- throw away apps for devices have many non-trivial aspects 13 | 14 | //Status: This currenty works under swift 3 + package manager (just replace the main.swift generated 15 | // with swift init --executable with this file 16 | // However, it is not currently Swifty 17 | 18 | //todo: 19 | // add metal custom view or sprite kit demo to demonstrate using more frameworks 20 | 21 | import Cocoa 22 | 23 | print("Hello, world!") 24 | 25 | //todo: remind myself what this does 26 | NSApplication.shared() 27 | 28 | //#1 status bar 29 | let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength).foo() 30 | statusItem.title = "Quit" 31 | // statusItem.action = #selector(NSApplication.terminate) 32 | 33 | 34 | //#2 random window (not the typical pattern) 35 | let window = NSWindow(contentRect: NSMakeRect(0, 0, 320, 200), 36 | styleMask: .titled, 37 | backing: .buffered, 38 | defer: true) 39 | window.orderFrontRegardless() 40 | 41 | 42 | //#3 App delegate (more typical pattern) 43 | class AppDel: NSObject, NSApplicationDelegate { 44 | var mainWindow: NSWindow? 45 | 46 | var foo: Bar 47 | 48 | func applicationDidFinishLaunching(_ aNotification: Notification) { 49 | print("Finished Launching") 50 | 51 | 52 | let window = NSWindow(contentRect: NSMakeRect(800, 600, 320, 200), 53 | styleMask: [.titled, .closable], 54 | backing: .buffered, 55 | defer: true) 56 | window.orderFrontRegardless() 57 | self.mainWindow = window 58 | 59 | NSApp.activate(ignoringOtherApps: true) 60 | } 61 | 62 | func applicationShouldTerminateAfterLastWindowClosed(_ app: NSApplication) -> Bool { 63 | return true 64 | } 65 | 66 | var fooProp: String { 67 | return "foo" 68 | } 69 | 70 | public override init() { 71 | super.init() 72 | } 73 | 74 | init(whitelist: @escaping Comparison = { _ -> Bool in return true }, blacklist: @escaping Comparison = { _ -> Bool in return true } ) { 75 | self.whitelist = whitelist 76 | self.blacklist = blacklist 77 | } 78 | 79 | init(endpointClosure: @escaping MoyaProvider.EndpointClosure = MoyaProvider.defaultEndpointMapping, 80 | requestClosure: @escaping MoyaProvider.RequestClosure = MoyaProvider.defaultRequestMapping) { 81 | print("foo") 82 | } 83 | 84 | deinit { 85 | print("deinit") 86 | } 87 | 88 | lazy var lazyFooProp: String = { 89 | return "foo" 90 | }() 91 | 92 | func logPath() -> URL { 93 | let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! 94 | print(docs) 95 | } 96 | 97 | dynamic let artworkImageView = ListingsCollectionViewCell._artworkImageView() 98 | 99 | typealias DownloadImageClosure = (_ url: URL?, _ imageView: UIImageView) -> () 100 | } 101 | 102 | typealias Dictionary = [String: AnyObject] 103 | 104 | NSApp.setActivationPolicy(.regular) 105 | 106 | let del = AppDel() 107 | NSApp.delegate = del 108 | 109 | NSApp.run() 110 | 111 | typealias Foo = Int 112 | 113 | func foo123() -> (String) -> Void { } 114 | 115 | enum Foo { 116 | case bar 117 | } 118 | 119 | enum FooInt: Int { 120 | case bar = 3 121 | case baz, bat = 3 122 | } 123 | 124 | extension Foo: CustomStringConvertible { } 125 | extension Observable where Element: BooleanType { } 126 | 127 | let bar1 = foo as? Int 128 | let bar2 = foo as! Int 129 | let bar3 = foo as Int 130 | 131 | if foo { 132 | print("1") 133 | } else if bar { 134 | print("2") 135 | } else { 136 | print("3") 137 | } 138 | 139 | let x = foo ? "YES" : "NO" 140 | 141 | present(vc) {} 142 | 143 | func foo(completion: @escaping (String) -> Void) { } 144 | 145 | observer.onNext((self.appViewController.presentedViewController as? FulfillmentContainerViewController) != nil) 146 | 147 | if case .leaf(let value) = node { 148 | print(value) 149 | } 150 | 151 | let o = AnyObserver { [weak self, foo] event in 152 | print(event, foo) 153 | } 154 | 155 | var requestBidderDetailsCommand = { (enabled: Observable) -> CocoaAction in 156 | appDelegate().requestBidderDetailsCommand(enabled: enabled) 157 | } 158 | 159 | let rotationAnimation = CABasicAnimation(keyPath:"transform") 160 | 161 | extension Collection where Iterator.Element: ObservableType, Iterator.Element.E: BooleanType { 162 | 163 | } 164 | 165 | guard let dollars = formatter.string(from: NSDecimalNumber(mantissa: cents, exponent: -2, isNegative: false)) else { 166 | return "" 167 | } 168 | 169 | cardHandler.cardStatus 170 | .subscribe { (event) in 171 | print(event) 172 | } 173 | .addDisposableTo(rx_disposeBag) 174 | 175 | func detectDevelopmentEnvironment() -> Bool { 176 | var developmentEnvironment = false 177 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 178 | developmentEnvironment = true 179 | #elseif os(macOS) 180 | developmentEnvironment = false 181 | #else 182 | developmentEnvironment = 32 183 | #endif 184 | return developmentEnvironment 185 | } 186 | 187 | extension UIView { 188 | public var rx_hidden: AnyObserver { 189 | return AnyObserver { [weak self] event in 190 | MainScheduler.ensureExecutingOnScheduler() 191 | } 192 | } 193 | } 194 | 195 | func didReceiveResponse(_ result: Result, target: TargetType) { 196 | print() 197 | } 198 | -------------------------------------------------------------------------------- /tests/dummy/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/enum/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`enum.swift 1`] = ` 4 | enum Edible { 5 | case apple 6 | case banana, cucumber 7 | } 8 | 9 | enum Count { 10 | case zero, one 11 | case some(i16: Int16), more(i32: Int32), many(Int64) 12 | } 13 | 14 | enum DifferentCount: Int { 15 | case zero = 0 16 | // libSyntax can't parse this yet: 17 | // case one = 1, two = 2 18 | case three = 3 19 | } 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | enum Edible { 22 | case apple 23 | case banana, cucumber 24 | } 25 | 26 | enum Count { 27 | case zero, one 28 | case some(i16: Int16), more(i32: Int32), many(Int64) 29 | } 30 | 31 | enum DifferentCount: Int { 32 | case zero = 0 33 | // libSyntax can't parse this yet: 34 | // case one = 1, two = 2 35 | case three = 3 36 | } 37 | 38 | `; 39 | -------------------------------------------------------------------------------- /tests/enum/enum.swift: -------------------------------------------------------------------------------- 1 | enum Edible { 2 | case apple 3 | case banana, cucumber 4 | } 5 | 6 | enum Count { 7 | case zero, one 8 | case some(i16: Int16), more(i32: Int32), many(Int64) 9 | } 10 | 11 | enum DifferentCount: Int { 12 | case zero = 0 13 | // libSyntax can't parse this yet: 14 | // case one = 1, two = 2 15 | case three = 3 16 | } 17 | -------------------------------------------------------------------------------- /tests/enum/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/extensions/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`extensions.swift 1`] = ` 4 | extension Foo {} 5 | public extension Foo {} 6 | extension Foo: Swift.Error {} 7 | 8 | public final class Artist: NSObject, JSONAbleType {} 9 | 10 | @objc 11 | class OnlineProvider where Target: Moya.TargetType {} 12 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 | extension Foo { } 14 | public extension Foo { } 15 | extension Foo: Swift.Error { } 16 | 17 | public final class Artist: NSObject, JSONAbleType { } 18 | 19 | @objc class OnlineProvider where Target: Moya.TargetType { } 20 | 21 | `; 22 | -------------------------------------------------------------------------------- /tests/extensions/extensions.swift: -------------------------------------------------------------------------------- 1 | extension Foo {} 2 | public extension Foo {} 3 | extension Foo: Swift.Error {} 4 | 5 | public final class Artist: NSObject, JSONAbleType {} 6 | 7 | @objc 8 | class OnlineProvider where Target: Moya.TargetType {} 9 | -------------------------------------------------------------------------------- /tests/extensions/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/for_in/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`for_in.swift 1`] = ` 4 | for e0 in [1, 2, 3] { print(e0) } 5 | 6 | for e1 in [1, 2, 3] { 7 | print(e1) 8 | } 9 | 10 | for e2 in elements { 11 | print(e2) 12 | } 13 | 14 | for e2 in elements where e2 % 2 == 0 { 15 | print(e2) 16 | } 17 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | for e0 in [1, 2, 3] { 19 | print(e0) 20 | } 21 | 22 | for e1 in [1, 2, 3] { 23 | print(e1) 24 | } 25 | 26 | for e2 in elements { 27 | print(e2) 28 | } 29 | 30 | for e2 in elements where e2 % 2 == 0 { 31 | print(e2) 32 | } 33 | 34 | `; 35 | -------------------------------------------------------------------------------- /tests/for_in/for_in.swift: -------------------------------------------------------------------------------- 1 | for e0 in [1, 2, 3] { print(e0) } 2 | 3 | for e1 in [1, 2, 3] { 4 | print(e1) 5 | } 6 | 7 | for e2 in elements { 8 | print(e2) 9 | } 10 | 11 | for e2 in elements where e2 % 2 == 0 { 12 | print(e2) 13 | } 14 | -------------------------------------------------------------------------------- /tests/for_in/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/func/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`func.swift 1`] = ` 4 | func noItems() {} 5 | 6 | func singleItem() { 7 | print("bar") 8 | } 9 | 10 | func multipleItems() { 11 | print("bar") 12 | } 13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | func noItems() { } 15 | 16 | func singleItem() { 17 | print("bar") 18 | } 19 | 20 | func multipleItems() { 21 | print("bar") 22 | } 23 | 24 | `; 25 | -------------------------------------------------------------------------------- /tests/func/func.swift: -------------------------------------------------------------------------------- 1 | func noItems() {} 2 | 3 | func singleItem() { 4 | print("bar") 5 | } 6 | 7 | func multipleItems() { 8 | print("bar") 9 | } 10 | -------------------------------------------------------------------------------- /tests/func/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/function_calls/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`function_calls.swift 1`] = ` 4 | foo() 5 | foo(1) 6 | foo(1, bar: 2) 7 | foo(bar: 1, baz: 2) 8 | foo(bar: { _ in 3 }) 9 | 10 | theQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog())) 11 | letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog: [ 12 | letTheQuickBrownFoxJumpsOverTheLazyDog, 13 | letTheQuickBrownFoxJumpsOverTheLazyDog 14 | ]) 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | foo() 17 | foo(1) 18 | foo(1, bar: 2) 19 | foo(bar: 1, baz: 2) 20 | foo(bar: { _ in 3 }) 21 | 22 | theQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog())) 23 | letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog: [ 24 | letTheQuickBrownFoxJumpsOverTheLazyDog, 25 | letTheQuickBrownFoxJumpsOverTheLazyDog 26 | ]) 27 | 28 | `; 29 | -------------------------------------------------------------------------------- /tests/function_calls/function_calls.swift: -------------------------------------------------------------------------------- 1 | foo() 2 | foo(1) 3 | foo(1, bar: 2) 4 | foo(bar: 1, baz: 2) 5 | foo(bar: { _ in 3 }) 6 | 7 | theQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog())) 8 | letTheQuickBrownFoxJumpsOverTheLazyDog(letTheQuickBrownFoxJumpsOverTheLazyDog: [ 9 | letTheQuickBrownFoxJumpsOverTheLazyDog, 10 | letTheQuickBrownFoxJumpsOverTheLazyDog 11 | ]) 12 | -------------------------------------------------------------------------------- /tests/function_calls/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/generic_where_clause/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`generic_where_clause.swift 1`] = ` 4 | extension ShapedFruit where Shape: Pear { 5 | 6 | } 7 | 8 | extension TheQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheLazyDog where TheLazyDog: VeryLazyDog { 9 | 10 | } 11 | 12 | class Fox { 13 | func jump(over: Dog) where Dog: LazyDog { 14 | 15 | } 16 | 17 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOver() where TheLazyDog: VeryLazyDog { 18 | 19 | } 20 | } 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | extension ShapedFruit where Shape: Pear { } 23 | 24 | extension TheQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheLazyDog 25 | where TheLazyDog: VeryLazyDog { } 26 | 27 | class Fox { 28 | func jump(over: Dog) where Dog: LazyDog { } 29 | 30 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOver() 31 | where TheLazyDog: VeryLazyDog { } 32 | } 33 | 34 | `; 35 | -------------------------------------------------------------------------------- /tests/generic_where_clause/generic_where_clause.swift: -------------------------------------------------------------------------------- 1 | extension ShapedFruit where Shape: Pear { 2 | 3 | } 4 | 5 | extension TheQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOverTheLazyDog where TheLazyDog: VeryLazyDog { 6 | 7 | } 8 | 9 | class Fox { 10 | func jump(over: Dog) where Dog: LazyDog { 11 | 12 | } 13 | 14 | func theQuickBrownFoxJumpsOverTheLazyDogTheQuickBrownFoxJumpsOver() where TheLazyDog: VeryLazyDog { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/generic_where_clause/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/generics/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`generics.swift 1`] = ` 4 | class Instance {} 5 | class Instance {} 6 | func foo() {} 7 | func foo() {} 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | class Instance { } 10 | class Instance { } 11 | func foo() { } 12 | func foo() { } 13 | 14 | `; 15 | -------------------------------------------------------------------------------- /tests/generics/generics.swift: -------------------------------------------------------------------------------- 1 | class Instance {} 2 | class Instance {} 3 | func foo() {} 4 | func foo() {} 5 | -------------------------------------------------------------------------------- /tests/generics/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/guard/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`guard.swift 1`] = ` 4 | guard let foo = bar else { return } 5 | 6 | guard let foo = bar else { return bar() } 7 | 8 | guard let foo = bar, let thisIsATriumphLetsSeeasdASDasdasdasdasdas = theWorldIsTooLargeForUs else { return bar() } 9 | 10 | // If the target is in the blacklist, don't log it. 11 | guard blacklist(target) == false else { return } 12 | 13 | do { 14 | reuseBag = DisposeBag() 15 | 16 | guard let reuseBag = reuseBag else { return } 17 | 18 | // Start with things not expected to ever change. 19 | } 20 | 21 | guard foo else { throw SomeError.error } 22 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | guard let foo = bar else { return } 24 | 25 | guard let foo = bar else { return bar() } 26 | 27 | guard 28 | let foo = bar, 29 | let thisIsATriumphLetsSeeasdASDasdasdasdasdas = theWorldIsTooLargeForUs 30 | else { return bar() } 31 | 32 | // If the target is in the blacklist, don't log it. 33 | guard blacklist(target) == false else { return } 34 | 35 | do { 36 | reuseBag = DisposeBag() 37 | 38 | guard let reuseBag = reuseBag else { return } 39 | 40 | // Start with things not expected to ever change. 41 | } 42 | 43 | guard foo else { 44 | throw SomeError.error 45 | } 46 | 47 | `; 48 | -------------------------------------------------------------------------------- /tests/guard/guard.swift: -------------------------------------------------------------------------------- 1 | guard let foo = bar else { return } 2 | 3 | guard let foo = bar else { return bar() } 4 | 5 | guard let foo = bar, let thisIsATriumphLetsSeeasdASDasdasdasdasdas = theWorldIsTooLargeForUs else { return bar() } 6 | 7 | // If the target is in the blacklist, don't log it. 8 | guard blacklist(target) == false else { return } 9 | 10 | do { 11 | reuseBag = DisposeBag() 12 | 13 | guard let reuseBag = reuseBag else { return } 14 | 15 | // Start with things not expected to ever change. 16 | } 17 | 18 | guard foo else { throw SomeError.error } 19 | -------------------------------------------------------------------------------- /tests/guard/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/if/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`if.swift 1`] = ` 4 | if let imageDicts = json["images"].object as? Array> { 5 | print("foo") 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | if let imageDicts = json["images"].object 9 | as? Array> { 10 | print("foo") 11 | } 12 | 13 | `; 14 | -------------------------------------------------------------------------------- /tests/if/if.swift: -------------------------------------------------------------------------------- 1 | if let imageDicts = json["images"].object as? Array> { 2 | print("foo") 3 | } 4 | -------------------------------------------------------------------------------- /tests/if/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/if_config_decl/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`if_config_decl.swift 1`] = ` 4 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 5 | developmentEnvironment = true 6 | #elseif os(macOS) 7 | developmentEnvironment = false 8 | #else 9 | developmentEnvironment = 32 10 | #endif 11 | 12 | // This doesn't render correctly 13 | class SomeClass { 14 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 15 | func f1() { 16 | print("1") 17 | } 18 | #elseif os(macOS) 19 | func f2() { 20 | print("2") 21 | } 22 | #else 23 | func f3() { 24 | print("3") 25 | } 26 | #endif 27 | } 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 30 | developmentEnvironment = true 31 | #elseif os(macOS) 32 | developmentEnvironment = false 33 | #else 34 | developmentEnvironment = 32 35 | #endif 36 | 37 | // This doesn't render correctly 38 | class SomeClass { 39 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 40 | func f1() { 41 | print("1") 42 | } 43 | #elseif os(macOS) 44 | func f2() { 45 | print("2") 46 | } 47 | #else 48 | func f3() { 49 | print("3") 50 | } 51 | #endif 52 | } 53 | 54 | `; 55 | -------------------------------------------------------------------------------- /tests/if_config_decl/if_config_decl.swift: -------------------------------------------------------------------------------- 1 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 2 | developmentEnvironment = true 3 | #elseif os(macOS) 4 | developmentEnvironment = false 5 | #else 6 | developmentEnvironment = 32 7 | #endif 8 | 9 | // This doesn't render correctly 10 | class SomeClass { 11 | #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) 12 | func f1() { 13 | print("1") 14 | } 15 | #elseif os(macOS) 16 | func f2() { 17 | print("2") 18 | } 19 | #else 20 | func f3() { 21 | print("3") 22 | } 23 | #endif 24 | } 25 | -------------------------------------------------------------------------------- /tests/if_config_decl/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/ignore/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ignore.swift 1`] = ` 4 | do { 5 | let identity = Matrix.create( 6 | 1, 0, 0, 7 | 0, 1, 0, 8 | 0, 0, 0 9 | ) // prettier-ignore 10 | } 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 | do { 13 | let identity = Matrix.create( 14 | 1, 0, 0, 15 | 0, 1, 0, 16 | 0, 0, 0 17 | ) 18 | } 19 | 20 | `; 21 | -------------------------------------------------------------------------------- /tests/ignore/ignore.swift: -------------------------------------------------------------------------------- 1 | do { 2 | let identity = Matrix.create( 3 | 1, 0, 0, 4 | 0, 1, 0, 5 | 0, 0, 0 6 | ) // prettier-ignore 7 | } 8 | -------------------------------------------------------------------------------- /tests/ignore/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/import/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`import.swift 1`] = ` 4 | import Foundation 5 | @testable import SomeModule 6 | 7 | import typealias SomeModule.Something 8 | import struct SomeModule.Something 9 | import class SomeModule.Something 10 | import enum SomeModule.Something 11 | import protocol SomeModule.Something 12 | import let SomeModule.something 13 | import var SomeModule.something 14 | import func SomeModule.something 15 | 16 | import typealias SomeModule.SomeNamespace.Something 17 | import struct SomeModule.SomeNamespace.Something 18 | import class SomeModule.SomeNamespace.Something 19 | import enum SomeModule.SomeNamespace.Something 20 | import protocol SomeModule.SomeNamespace.Something 21 | import let SomeModule.SomeNamespace.something 22 | import var SomeModule.SomeNamespace.something 23 | import func SomeModule.SomeNamespace.something 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 | import Foundation 26 | @testable import SomeModule 27 | 28 | import typealias SomeModule.Something 29 | import struct SomeModule.Something 30 | import class SomeModule.Something 31 | import enum SomeModule.Something 32 | import protocol SomeModule.Something 33 | import let SomeModule.something 34 | import var SomeModule.something 35 | import func SomeModule.something 36 | 37 | import typealias SomeModule.SomeNamespace.Something 38 | import struct SomeModule.SomeNamespace.Something 39 | import class SomeModule.SomeNamespace.Something 40 | import enum SomeModule.SomeNamespace.Something 41 | import protocol SomeModule.SomeNamespace.Something 42 | import let SomeModule.SomeNamespace.something 43 | import var SomeModule.SomeNamespace.something 44 | import func SomeModule.SomeNamespace.something 45 | 46 | `; 47 | -------------------------------------------------------------------------------- /tests/import/import.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @testable import SomeModule 3 | 4 | import typealias SomeModule.Something 5 | import struct SomeModule.Something 6 | import class SomeModule.Something 7 | import enum SomeModule.Something 8 | import protocol SomeModule.Something 9 | import let SomeModule.something 10 | import var SomeModule.something 11 | import func SomeModule.something 12 | 13 | import typealias SomeModule.SomeNamespace.Something 14 | import struct SomeModule.SomeNamespace.Something 15 | import class SomeModule.SomeNamespace.Something 16 | import enum SomeModule.SomeNamespace.Something 17 | import protocol SomeModule.SomeNamespace.Something 18 | import let SomeModule.SomeNamespace.something 19 | import var SomeModule.SomeNamespace.something 20 | import func SomeModule.SomeNamespace.something 21 | -------------------------------------------------------------------------------- /tests/import/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/init/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`init.swift 1`] = ` 4 | class SomeClass { 5 | init() { 6 | 7 | } 8 | 9 | init?() { 10 | super.init() 11 | } 12 | 13 | init() throws { 14 | 15 | } 16 | 17 | public init() { 18 | 19 | } 20 | 21 | private init?() { 22 | 23 | } 24 | 25 | internal init() throws { 26 | 27 | } 28 | 29 | override init() { 30 | 31 | } 32 | 33 | required init() { 34 | 35 | } 36 | 37 | convenience init() { 38 | 39 | } 40 | 41 | public override init?() { 42 | super.init() 43 | } 44 | 45 | init(string: String) { 46 | 47 | } 48 | } 49 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 | class SomeClass { 51 | init() { } 52 | 53 | init?() { 54 | super.init() 55 | } 56 | 57 | init() throws { } 58 | 59 | public init() { } 60 | 61 | private init?() { } 62 | 63 | internal init() throws { } 64 | 65 | override init() { } 66 | 67 | required init() { } 68 | 69 | convenience init() { } 70 | 71 | public override init?() { 72 | super.init() 73 | } 74 | 75 | init(string: String) { } 76 | } 77 | 78 | `; 79 | -------------------------------------------------------------------------------- /tests/init/init.swift: -------------------------------------------------------------------------------- 1 | class SomeClass { 2 | init() { 3 | 4 | } 5 | 6 | init?() { 7 | super.init() 8 | } 9 | 10 | init() throws { 11 | 12 | } 13 | 14 | public init() { 15 | 16 | } 17 | 18 | private init?() { 19 | 20 | } 21 | 22 | internal init() throws { 23 | 24 | } 25 | 26 | override init() { 27 | 28 | } 29 | 30 | required init() { 31 | 32 | } 33 | 34 | convenience init() { 35 | 36 | } 37 | 38 | public override init?() { 39 | super.init() 40 | } 41 | 42 | init(string: String) { 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/init/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/is/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`is.swift 1`] = ` 4 | if apple is Apple { 5 | print("Apple") 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | if apple is Apple { 9 | print("Apple") 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/is/is.swift: -------------------------------------------------------------------------------- 1 | if apple is Apple { 2 | print("Apple") 3 | } 4 | -------------------------------------------------------------------------------- /tests/is/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/is_type_pattern/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`is_type_pattern.swift 1`] = ` 4 | for case is Apple in fruits { 5 | print("Apple") 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | for case isApple in fruits { 9 | print("Apple") 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/is_type_pattern/is_type_pattern.swift: -------------------------------------------------------------------------------- 1 | for case is Apple in fruits { 2 | print("Apple") 3 | } 4 | -------------------------------------------------------------------------------- /tests/is_type_pattern/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/keypath/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`keypath.swift 1`] = ` 4 | _ = \\a.b.c 5 | _ = \\a.b[1] 6 | _ = #keyPath(a.b.c) 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | _ = \\a.b.c 9 | _ = \\a.b[1] 10 | _ = #keyPath(a.b.c) 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/keypath/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/keypath/keypath.swift: -------------------------------------------------------------------------------- 1 | _ = \a.b.c 2 | _ = \a.b[1] 3 | _ = #keyPath(a.b.c) 4 | -------------------------------------------------------------------------------- /tests/lazy/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`lazy.swift 1`] = ` 4 | class SomeClass { 5 | public lazy var isActive = Something.isActive() 6 | public private(set) lazy var isActive = { Something.isActive }() 7 | } 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | class SomeClass { 10 | public lazy var isActive = Something.isActive() 11 | public private(set) lazy var isActive = { 12 | Something.isActive 13 | }() 14 | } 15 | 16 | `; 17 | -------------------------------------------------------------------------------- /tests/lazy/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/lazy/lazy.swift: -------------------------------------------------------------------------------- 1 | class SomeClass { 2 | public lazy var isActive = Something.isActive() 3 | public private(set) lazy var isActive = { Something.isActive }() 4 | } 5 | -------------------------------------------------------------------------------- /tests/operators/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`operators.swift 1`] = ` 4 | let a = b + c * d - e || f << g ?? h 5 | let a = -b 6 | let a = !b 7 | 8 | let ref = &a 9 | let ref = &_a 10 | let ref = &a[i] 11 | 12 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog - theQuickBrownFoxJumpsOverTheLazyDog 13 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog < theQuickBrownFoxJumpsOverTheLazyDog 14 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog <= theQuickBrownFoxJumpsOverTheLazyDog 15 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog != theQuickBrownFoxJumpsOverTheLazyDog 16 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog || theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog 17 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | let a = b + c * d - e || f << g ?? h 19 | let a = -b 20 | let a = !b 21 | 22 | let ref = &a 23 | let ref = &_a 24 | let ref = &a[i] 25 | 26 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog 27 | + theQuickBrownFoxJumpsOverTheLazyDog 28 | - theQuickBrownFoxJumpsOverTheLazyDog 29 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog 30 | + theQuickBrownFoxJumpsOverTheLazyDog 31 | < theQuickBrownFoxJumpsOverTheLazyDog 32 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog 33 | + theQuickBrownFoxJumpsOverTheLazyDog <= theQuickBrownFoxJumpsOverTheLazyDog 34 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog 35 | + theQuickBrownFoxJumpsOverTheLazyDog != theQuickBrownFoxJumpsOverTheLazyDog 36 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog 37 | || theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog 38 | 39 | `; 40 | -------------------------------------------------------------------------------- /tests/operators/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/operators/operators.swift: -------------------------------------------------------------------------------- 1 | let a = b + c * d - e || f << g ?? h 2 | let a = -b 3 | let a = !b 4 | 5 | let ref = &a 6 | let ref = &_a 7 | let ref = &a[i] 8 | 9 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog - theQuickBrownFoxJumpsOverTheLazyDog 10 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog < theQuickBrownFoxJumpsOverTheLazyDog 11 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog <= theQuickBrownFoxJumpsOverTheLazyDog 12 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog + theQuickBrownFoxJumpsOverTheLazyDog != theQuickBrownFoxJumpsOverTheLazyDog 13 | theQuickBrownFoxJumpsOverTheLazyDog = theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog || theQuickBrownFoxJumpsOverTheLazyDog == theQuickBrownFoxJumpsOverTheLazyDog 14 | -------------------------------------------------------------------------------- /tests/optional_chaining/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`optional_chaining.swift 1`] = ` 4 | foo()?.bar() 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | foo()?.bar() 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /tests/optional_chaining/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/optional_chaining/optional_chaining.swift: -------------------------------------------------------------------------------- 1 | foo()?.bar() 2 | -------------------------------------------------------------------------------- /tests/protocols/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`protocols.swift 1`] = ` 4 | protocol SomeType {} 5 | public protocol SomeType {} 6 | 7 | protocol SomeType { 8 | var property: String 9 | } 10 | 11 | protocol SomeType { 12 | var property: String { get } 13 | } 14 | 15 | protocol SomeType { 16 | var property: String { get set } 17 | } 18 | 19 | protocol SomeType { 20 | func foo() 21 | } 22 | 23 | protocol SomeType { 24 | associatedtype E 25 | } 26 | 27 | internal protocol SomeType { 28 | associatedtype E 29 | func foo() 30 | func bar() 31 | var property: String { get set } 32 | } 33 | 34 | protocol ClassishType: class { 35 | 36 | } 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | protocol SomeType { } 39 | public protocol SomeType { } 40 | 41 | protocol SomeType { 42 | var property: String 43 | } 44 | 45 | protocol SomeType { 46 | var property: String { get } 47 | } 48 | 49 | protocol SomeType { 50 | var property: String { get set } 51 | } 52 | 53 | protocol SomeType { 54 | func foo() 55 | } 56 | 57 | protocol SomeType { 58 | associatedtype E 59 | } 60 | 61 | internal protocol SomeType { 62 | associatedtype E 63 | func foo() 64 | func bar() 65 | var property: String { get set } 66 | } 67 | 68 | protocol ClassishType: class { } 69 | 70 | `; 71 | -------------------------------------------------------------------------------- /tests/protocols/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/protocols/protocols.swift: -------------------------------------------------------------------------------- 1 | protocol SomeType {} 2 | public protocol SomeType {} 3 | 4 | protocol SomeType { 5 | var property: String 6 | } 7 | 8 | protocol SomeType { 9 | var property: String { get } 10 | } 11 | 12 | protocol SomeType { 13 | var property: String { get set } 14 | } 15 | 16 | protocol SomeType { 17 | func foo() 18 | } 19 | 20 | protocol SomeType { 21 | associatedtype E 22 | } 23 | 24 | internal protocol SomeType { 25 | associatedtype E 26 | func foo() 27 | func bar() 28 | var property: String { get set } 29 | } 30 | 31 | protocol ClassishType: class { 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/repeat_while_stmt/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`repeat_while_stmt.swift 1`] = ` 4 | repeat { print("ping") } while !pong 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | repeat { 7 | print("ping") 8 | } while !pong 9 | 10 | `; 11 | -------------------------------------------------------------------------------- /tests/repeat_while_stmt/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/repeat_while_stmt/repeat_while_stmt.swift: -------------------------------------------------------------------------------- 1 | repeat { print("ping") } while !pong 2 | -------------------------------------------------------------------------------- /tests/specialize_expr/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`specialize_expr.swift 1`] = ` 4 | var viewModel = PublishSubject() 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | var viewModel = PublishSubject() 7 | 8 | `; 9 | -------------------------------------------------------------------------------- /tests/specialize_expr/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/specialize_expr/specialize_expr.swift: -------------------------------------------------------------------------------- 1 | var viewModel = PublishSubject() 2 | -------------------------------------------------------------------------------- /tests/strings/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`strings.swift 1`] = ` 4 | "string" 5 | 6 | "inter\\(po)lated" 7 | 8 | """ 9 | multiline 10 | string 11 | """ 12 | 13 | """ 14 | some 15 | \\( 16 | multi 17 | ) 18 | \\(line) 19 | string 20 | """ 21 | 22 | "The quick brown fox jumps over the lazy dog. The \\(quick + brown) fox jumps over the \\(String(describing: lazy)) dog." 23 | 24 | """ 25 | The quick brown fox jumps over the lazy dog. The \\(quick + brown) fox jumps over the \\(String(describing: lazy)) dog. 26 | """ 27 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | "string" 29 | 30 | "inter\\(po)lated" 31 | 32 | """ 33 | multiline 34 | string 35 | """ 36 | 37 | """ 38 | some 39 | \\(multi) 40 | \\(line) 41 | string 42 | """ 43 | 44 | "The quick brown fox jumps over the lazy dog. The \\(quick + brown) fox jumps over the \\(String(describing: lazy)) dog." 45 | 46 | """ 47 | The quick brown fox jumps over the lazy dog. The \\(quick + brown) fox jumps over the \\(String(describing: lazy)) dog. 48 | """ 49 | 50 | `; 51 | -------------------------------------------------------------------------------- /tests/strings/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/strings/strings.swift: -------------------------------------------------------------------------------- 1 | "string" 2 | 3 | "inter\(po)lated" 4 | 5 | """ 6 | multiline 7 | string 8 | """ 9 | 10 | """ 11 | some 12 | \( 13 | multi 14 | ) 15 | \(line) 16 | string 17 | """ 18 | 19 | "The quick brown fox jumps over the lazy dog. The \(quick + brown) fox jumps over the \(String(describing: lazy)) dog." 20 | 21 | """ 22 | The quick brown fox jumps over the lazy dog. The \(quick + brown) fox jumps over the \(String(describing: lazy)) dog. 23 | """ 24 | -------------------------------------------------------------------------------- /tests/subscript/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`subscript.swift 1`] = ` 4 | class Basket { 5 | subscript(name: String) -> Int { 6 | return fruits[name] 7 | } 8 | 9 | subscript(name: String) -> Int { 10 | get { 11 | return fruits[name] 12 | } 13 | set(newValue) { 14 | fruits[name] = newValue 15 | } 16 | } 17 | } 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | class Basket { 20 | subscript(name: String) -> Int { 21 | return fruits[name] 22 | } 23 | 24 | subscript(name: String) -> Int { 25 | get { 26 | return fruits[name] 27 | } 28 | set(newValue) { 29 | fruits[name] = newValue 30 | } 31 | } 32 | } 33 | 34 | `; 35 | -------------------------------------------------------------------------------- /tests/subscript/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/subscript/subscript.swift: -------------------------------------------------------------------------------- 1 | class Basket { 2 | subscript(name: String) -> Int { 3 | return fruits[name] 4 | } 5 | 6 | subscript(name: String) -> Int { 7 | get { 8 | return fruits[name] 9 | } 10 | set(newValue) { 11 | fruits[name] = newValue 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/switch/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`switch.swift 1`] = ` 4 | do { 5 | do { 6 | switch variable { 7 | case .foo: fallthrough 8 | case .foo, .bar: break 9 | case .error(let message): 10 | fallthrough 11 | case let label as UILabel: 12 | break 13 | case _ where variable < 20: fallthrough 14 | case TheQuickBrownFoxJumpsOver.theLazyDog, TheQuickBrownFoxJumpsOver.theVeryLazyDog, TheQuickBrownFoxJumpsOver.theLaziestDog: 15 | return 123 16 | default: 17 | print(12) 18 | } 19 | } 20 | } 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | do { 23 | do { 24 | switch variable { 25 | case .foo: 26 | fallthrough 27 | case .foo, .bar: 28 | break 29 | case .error(let message): 30 | fallthrough 31 | case let label as UILabel: 32 | break 33 | case _ where variable < 20: 34 | fallthrough 35 | case TheQuickBrownFoxJumpsOver.theLazyDog, 36 | TheQuickBrownFoxJumpsOver.theVeryLazyDog, 37 | TheQuickBrownFoxJumpsOver.theLaziestDog: 38 | return 123 39 | default: 40 | print(12) 41 | } 42 | } 43 | } 44 | 45 | `; 46 | -------------------------------------------------------------------------------- /tests/switch/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/switch/switch.swift: -------------------------------------------------------------------------------- 1 | do { 2 | do { 3 | switch variable { 4 | case .foo: fallthrough 5 | case .foo, .bar: break 6 | case .error(let message): 7 | fallthrough 8 | case let label as UILabel: 9 | break 10 | case _ where variable < 20: fallthrough 11 | case TheQuickBrownFoxJumpsOver.theLazyDog, TheQuickBrownFoxJumpsOver.theVeryLazyDog, TheQuickBrownFoxJumpsOver.theLaziestDog: 12 | return 123 13 | default: 14 | print(12) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/ternary_expr/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ternary_expr.swift 1`] = ` 4 | let variable = condition ? ifTrue : ifFalse 5 | 6 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore ? ifTrue : ifFalse 7 | 8 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore ? 9 | ["loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore"] : 10 | ["loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore"] 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 | let variable = condition ? ifTrue : ifFalse 13 | 14 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore 15 | ? ifTrue 16 | : ifFalse 17 | 18 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore 19 | ? [ 20 | "loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore" 21 | ] 22 | : [ 23 | "loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore" 24 | ] 25 | 26 | `; 27 | -------------------------------------------------------------------------------- /tests/ternary_expr/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/ternary_expr/ternary_expr.swift: -------------------------------------------------------------------------------- 1 | let variable = condition ? ifTrue : ifFalse 2 | 3 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore ? ifTrue : ifFalse 4 | 5 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore ? 6 | ["loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore"] : 7 | ["loremIpsumDolorSitAmetConsectetur": "AdipiscingElitSedDoEiusmodTemporIncididuntUtLabore"] 8 | -------------------------------------------------------------------------------- /tests/trailing_closure/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`trailing_closure.swift 1`] = ` 4 | [1,2,3].map { $0 + 1 } 5 | 6 | [1,2,3].map { _ in 42 } 7 | 8 | [1,2,3].map { element in 9 | element + 2 10 | } 11 | 12 | [1,2,3].map({ element in 13 | element + 3 14 | }) 15 | 16 | [1,2,3].map(transform: { element in 17 | element + 4 18 | }) 19 | 20 | [1,2,3].map(transform: { (element) -> Int in 21 | element + 5 22 | }) 23 | 24 | [1,2,3].map(transform: { (element: Int) -> Int in 25 | element + 6 26 | }) 27 | 28 | [1,2,3].map(transform: { (element: Int) -> Int in 29 | element + somethingThatIsQuiteLong 30 | }) 31 | 32 | [1,2,3].map(transform: { (element: Int) -> Int in 33 | element + somethingThatIsFarTooLongToBePrinted 34 | }) 35 | 36 | [1,2,3].map(transform: { (element: Int) -> Int in 37 | let v = element + 7 38 | return v 39 | }) 40 | 41 | [1, 2, 3].map { $0 + 1 }.lazy.map { $0 + 2 }.map { $0 + 3 }.map { $0 + 4 } 42 | 43 | // Can't be formatted since libSyntax reports it as UnknownExpr 44 | filter { (e) -> Bool in return value != e } 45 | 46 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { _ in } 47 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { [self] _ in self } 48 | 49 | Binder(self.base) { label, color in 50 | label.textColor = color 51 | } 52 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | [1, 2, 3].map { $0 + 1 } 54 | 55 | [1, 2, 3].map { _ in 42 } 56 | 57 | [1, 2, 3].map { element in 58 | element + 2 59 | } 60 | 61 | [1, 2, 3].map({ element in 62 | element + 3 63 | }) 64 | 65 | [1, 2, 3].map(transform: { element in 66 | element + 4 67 | }) 68 | 69 | [1, 2, 3].map(transform: { element -> Int in 70 | element + 5 71 | }) 72 | 73 | [1, 2, 3].map(transform: { (element: Int) -> Int in element + 6 }) 74 | 75 | [1, 2, 3].map(transform: { (element: Int) -> Int in 76 | element + somethingThatIsQuiteLong 77 | }) 78 | 79 | [1, 2, 3].map(transform: { (element: Int) -> Int in 80 | element + somethingThatIsFarTooLongToBePrinted 81 | }) 82 | 83 | [1, 2, 3].map(transform: { (element: Int) -> Int in 84 | let v = element + 7 85 | return v 86 | }) 87 | 88 | [1, 2, 3] 89 | .map { $0 + 1 } 90 | .lazy.map { $0 + 2 } 91 | .map { $0 + 3 } 92 | .map { $0 + 4 } 93 | 94 | // Can't be formatted since libSyntax reports it as UnknownExpr 95 | filter { e -> Bool in 96 | return value != e 97 | } 98 | 99 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { _ in 100 | } 101 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { 102 | [self] _ in 103 | self 104 | } 105 | 106 | Binder(self.base) { label, color in 107 | label.textColor = color 108 | } 109 | 110 | `; 111 | -------------------------------------------------------------------------------- /tests/trailing_closure/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/trailing_closure/trailing_closure.swift: -------------------------------------------------------------------------------- 1 | [1,2,3].map { $0 + 1 } 2 | 3 | [1,2,3].map { _ in 42 } 4 | 5 | [1,2,3].map { element in 6 | element + 2 7 | } 8 | 9 | [1,2,3].map({ element in 10 | element + 3 11 | }) 12 | 13 | [1,2,3].map(transform: { element in 14 | element + 4 15 | }) 16 | 17 | [1,2,3].map(transform: { (element) -> Int in 18 | element + 5 19 | }) 20 | 21 | [1,2,3].map(transform: { (element: Int) -> Int in 22 | element + 6 23 | }) 24 | 25 | [1,2,3].map(transform: { (element: Int) -> Int in 26 | element + somethingThatIsQuiteLong 27 | }) 28 | 29 | [1,2,3].map(transform: { (element: Int) -> Int in 30 | element + somethingThatIsFarTooLongToBePrinted 31 | }) 32 | 33 | [1,2,3].map(transform: { (element: Int) -> Int in 34 | let v = element + 7 35 | return v 36 | }) 37 | 38 | [1, 2, 3].map { $0 + 1 }.lazy.map { $0 + 2 }.map { $0 + 3 }.map { $0 + 4 } 39 | 40 | // Can't be formatted since libSyntax reports it as UnknownExpr 41 | filter { (e) -> Bool in return value != e } 42 | 43 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { _ in } 44 | loremIpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore { [self] _ in self } 45 | 46 | Binder(self.base) { label, color in 47 | label.textColor = color 48 | } 49 | -------------------------------------------------------------------------------- /tests/try/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`try.swift 1`] = ` 4 | try somethingDangerous() 5 | 6 | _ = try? somethingDangerous() 7 | 8 | let x = try? somethingDangerous() 9 | 10 | try! somethingDangerous() 11 | 12 | let x = try! somethingDangerous() 13 | 14 | let theQuickBrownFoxJumpsOverTheLazyDog = try makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 15 | 16 | let theQuickBrownFoxJumpsOverTheLazyDog = try? makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 17 | 18 | let theQuickBrownFoxJumpsOverTheLazyDog = try! makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | try somethingDangerous() 21 | 22 | _ = try? somethingDangerous() 23 | 24 | let x = try? somethingDangerous() 25 | 26 | try! somethingDangerous() 27 | 28 | let x = try! somethingDangerous() 29 | 30 | let theQuickBrownFoxJumpsOverTheLazyDog = try makeTheQuickBrownFoxJumpsOverTheLazyDog( 31 | fox: fox, 32 | dog: dog 33 | ) 34 | 35 | let theQuickBrownFoxJumpsOverTheLazyDog = try? makeTheQuickBrownFoxJumpsOverTheLazyDog( 36 | fox: fox, 37 | dog: dog 38 | ) 39 | 40 | let theQuickBrownFoxJumpsOverTheLazyDog = try! makeTheQuickBrownFoxJumpsOverTheLazyDog( 41 | fox: fox, 42 | dog: dog 43 | ) 44 | 45 | `; 46 | -------------------------------------------------------------------------------- /tests/try/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/try/try.swift: -------------------------------------------------------------------------------- 1 | try somethingDangerous() 2 | 3 | _ = try? somethingDangerous() 4 | 5 | let x = try? somethingDangerous() 6 | 7 | try! somethingDangerous() 8 | 9 | let x = try! somethingDangerous() 10 | 11 | let theQuickBrownFoxJumpsOverTheLazyDog = try makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 12 | 13 | let theQuickBrownFoxJumpsOverTheLazyDog = try? makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 14 | 15 | let theQuickBrownFoxJumpsOverTheLazyDog = try! makeTheQuickBrownFoxJumpsOverTheLazyDog(fox: fox, dog: dog) 16 | -------------------------------------------------------------------------------- /tests/try_catch/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`try_catch.swift 1`] = ` 4 | do { try foo() } catch {} 5 | 6 | do { try foo() } catch { print(error) } 7 | 8 | do { 9 | try foo() 10 | } catch let someError as SomeError { 11 | print(someError) 12 | } 13 | 14 | do { 15 | try foo() 16 | } catch let someError as SomeError { 17 | print(someError) 18 | } catch let someOtherError as SomeOtherError { 19 | print(someOtherError) 20 | } 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | do { 23 | try foo() 24 | } catch { } 25 | 26 | do { 27 | try foo() 28 | } catch { 29 | print(error) 30 | } 31 | 32 | do { 33 | try foo() 34 | } catch let someError as SomeError { 35 | print(someError) 36 | } 37 | 38 | do { 39 | try foo() 40 | } catch let someError as SomeError { 41 | print(someError) 42 | } catch let someOtherError as SomeOtherError { 43 | print(someOtherError) 44 | } 45 | 46 | `; 47 | -------------------------------------------------------------------------------- /tests/try_catch/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/try_catch/try_catch.swift: -------------------------------------------------------------------------------- 1 | do { try foo() } catch {} 2 | 3 | do { try foo() } catch { print(error) } 4 | 5 | do { 6 | try foo() 7 | } catch let someError as SomeError { 8 | print(someError) 9 | } 10 | 11 | do { 12 | try foo() 13 | } catch let someError as SomeError { 14 | print(someError) 15 | } catch let someOtherError as SomeOtherError { 16 | print(someOtherError) 17 | } 18 | -------------------------------------------------------------------------------- /tests/tuple_expr/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`tuple_expr.swift 1`] = ` 4 | let x = tuple.0 5 | let x = tuple.0.prop 6 | let x = tuple.0.prop.a 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | let x = tuple.0 9 | let x = tuple.0.prop 10 | let x = tuple.0.prop.a 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/tuple_expr/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/tuple_expr/tuple_expr.swift: -------------------------------------------------------------------------------- 1 | let x = tuple.0 2 | let x = tuple.0.prop 3 | let x = tuple.0.prop.a 4 | -------------------------------------------------------------------------------- /tests/type_self/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`type_self.swift 1`] = ` 4 | let a = SomeType.self 5 | let b = Something.SomeType.self 6 | let c = [SomeType].self 7 | let d = [SomeType: SomeType].self 8 | let e = SomeGenericType.self 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 | let a = SomeType.self 11 | let b = Something.SomeType.self 12 | let c = [SomeType].self 13 | let d = [SomeType: SomeType].self 14 | let e = SomeGenericType.self 15 | 16 | `; 17 | -------------------------------------------------------------------------------- /tests/type_self/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/type_self/type_self.swift: -------------------------------------------------------------------------------- 1 | let a = SomeType.self 2 | let b = Something.SomeType.self 3 | let c = [SomeType].self 4 | let d = [SomeType: SomeType].self 5 | let e = SomeGenericType.self 6 | -------------------------------------------------------------------------------- /tests/typealias/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`typealias.swift 1`] = ` 4 | typealias LetterList = String 5 | typealias StringKeyedDictionary = Dictionary 6 | public typealias LetterList = String 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | typealias LetterList = String 9 | typealias StringKeyedDictionary = Dictionary 10 | public typealias LetterList = String 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/typealias/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/typealias/typealias.swift: -------------------------------------------------------------------------------- 1 | typealias LetterList = String 2 | typealias StringKeyedDictionary = Dictionary 3 | public typealias LetterList = String 4 | -------------------------------------------------------------------------------- /tests/underscore/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`underscore.swift 1`] = ` 4 | func foo(_: String) { } 5 | func foo(_ string: String) { } 6 | _ = 32 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | func foo(_: String) { } 9 | func foo(_ string: String) { } 10 | _ = 32 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/underscore/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/underscore/underscore.swift: -------------------------------------------------------------------------------- 1 | func foo(_: String) { } 2 | func foo(_ string: String) { } 3 | _ = 32 4 | -------------------------------------------------------------------------------- /tests/while/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`while.swift 1`] = ` 4 | while true { 5 | print("always") 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | while true { 9 | print("always") 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/while/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/while/while.swift: -------------------------------------------------------------------------------- 1 | while true { 2 | print("always") 3 | } 4 | -------------------------------------------------------------------------------- /tests/wildcard/__snapshots__/jsfmt.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`wildcard.swift 1`] = ` 4 | for _ in 1...3 { 5 | print("Ping") 6 | } 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | for _ in 1...3 { 9 | print("Ping") 10 | } 11 | 12 | `; 13 | -------------------------------------------------------------------------------- /tests/wildcard/jsfmt.spec.js: -------------------------------------------------------------------------------- 1 | run_spec(__dirname, ["swift"]); 2 | -------------------------------------------------------------------------------- /tests/wildcard/wildcard.swift: -------------------------------------------------------------------------------- 1 | for _ in 1...3 { 2 | print("Ping") 3 | } 4 | -------------------------------------------------------------------------------- /tests_config/raw-serializer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const RAW = Symbol.for("raw"); 4 | 5 | module.exports = { 6 | print(val) { 7 | return val[RAW]; 8 | }, 9 | test(val) { 10 | return ( 11 | val && 12 | Object.prototype.hasOwnProperty.call(val, RAW) && 13 | typeof val[RAW] === "string" 14 | ); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /tests_config/run_spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require("fs"); 4 | const { extname } = require("path"); 5 | const prettier = require("prettier"); 6 | const plugin = require("../src"); 7 | const { massageAST } = require("prettier/src/common/clean-ast"); 8 | const { normalize } = require("prettier/src/main/options"); 9 | 10 | const { AST_COMPARE } = process.env; 11 | 12 | function run_spec(dirname, parsers, options) { 13 | options = Object.assign( 14 | { 15 | plugins: ["."] 16 | }, 17 | options 18 | ); 19 | 20 | /* instabul ignore if */ 21 | if (!parsers || !parsers.length) { 22 | throw new Error(`No parsers were specified for ${dirname}`); 23 | } 24 | 25 | fs.readdirSync(dirname).forEach(filename => { 26 | const path = `${dirname}/${filename}`; 27 | if ( 28 | extname(filename) !== ".snap" && 29 | fs.lstatSync(path).isFile() && 30 | filename[0] !== "." && 31 | filename !== "jsfmt.spec.js" 32 | ) { 33 | const source = read(path).replace(/\r\n/g, "\n"); 34 | 35 | const mergedOptions = Object.assign(mergeDefaultOptions(options || {}), { 36 | parser: parsers[0] 37 | }); 38 | const output = prettyprint(source, path, mergedOptions); 39 | test(`${filename} - ${mergedOptions.parser}-verify`, () => { 40 | expect(raw(`${source + "~".repeat(80)}\n${output}`)).toMatchSnapshot( 41 | filename 42 | ); 43 | }); 44 | 45 | parsers.slice(1).forEach(parserName => { 46 | test(`${filename} - ${parserName}-verify`, () => { 47 | const verifyOptions = Object.assign(mergedOptions, { 48 | parser: parserName 49 | }); 50 | const verifyOutput = prettyprint(source, path, verifyOptions); 51 | expect(output).toEqual(verifyOutput); 52 | }); 53 | }); 54 | 55 | if (AST_COMPARE) { 56 | const normalizedOptions = normalize(mergedOptions); 57 | const ast = parse(source, mergedOptions); 58 | const astMassaged = massageAST(ast, normalizedOptions); 59 | let ppastMassaged; 60 | let pperr = null; 61 | try { 62 | const ppast = parse( 63 | prettyprint(source, path, mergedOptions), 64 | mergedOptions 65 | ); 66 | ppastMassaged = massageAST(ppast, normalizedOptions); 67 | } catch (e) { 68 | pperr = e.stack; 69 | } 70 | 71 | test(`${path} parse`, () => { 72 | expect(pperr).toBe(null); 73 | expect(ppastMassaged).toBeDefined(); 74 | if (!ast.errors || ast.errors.length === 0) { 75 | expect(astMassaged).toEqual(ppastMassaged); 76 | } 77 | }); 78 | } 79 | } 80 | }); 81 | } 82 | global.run_spec = run_spec; 83 | 84 | function stripLocation(ast) { 85 | if (Array.isArray(ast)) { 86 | return ast.map(e => stripLocation(e)); 87 | } 88 | if (typeof ast === "object") { 89 | const newObj = {}; 90 | for (const key in ast) { 91 | if ( 92 | key === "loc" || 93 | key === "range" || 94 | key === "raw" || 95 | key === "comments" || 96 | key === "parent" || 97 | key === "prev" 98 | ) { 99 | continue; 100 | } 101 | newObj[key] = stripLocation(ast[key]); 102 | } 103 | return newObj; 104 | } 105 | return ast; 106 | } 107 | 108 | function parse(string, opts) { 109 | return stripLocation(plugin.parsers.php.parse(string, {}, opts)); 110 | } 111 | 112 | function prettyprint(src, filename, options) { 113 | return prettier.format( 114 | src, 115 | Object.assign( 116 | { 117 | filepath: filename 118 | }, 119 | options 120 | ) 121 | ); 122 | } 123 | 124 | function read(filename) { 125 | return fs.readFileSync(filename, "utf8"); 126 | } 127 | 128 | /** 129 | * Wraps a string in a marker object that is used by `./raw-serializer.js` to 130 | * directly print that string in a snapshot without escaping all double quotes. 131 | * Backticks will still be escaped. 132 | */ 133 | function raw(string) { 134 | if (typeof string !== "string") { 135 | throw new Error("Raw snapshots have to be strings."); 136 | } 137 | return { [Symbol.for("raw")]: string }; 138 | } 139 | 140 | function mergeDefaultOptions(parserConfig) { 141 | return Object.assign( 142 | { 143 | printWidth: 80, 144 | tabWidth: 4 145 | }, 146 | parserConfig 147 | ); 148 | } 149 | --------------------------------------------------------------------------------