├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── demo.sqlx ├── mod.sqlx ├── requirements.txt ├── setup.py ├── sqlformat.py ├── sqlx.py ├── test.py └── todo.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tao Jiayuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md LICENSE requirements.txt 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sqlx 2 | 3 | SQL Extension 4 | 5 | 强大的 SQL 语法拓展,目标是打造 "易读易写 方便维护" 的 sql 脚本 6 | 7 | 8 | ## 应用场景 9 | 10 | 假设有一张商品价目表(product),每天价格变动的商品都会更新报价。 11 | 12 | 例如,苹果的最新价格为 10 元, 因为苹果最新的一次报价是在 20191211, 当时价格为 10 元。 13 | 14 | name(商品名称)|price(价格)|date(报价日期) 15 | -|-|- 16 | 苹果|15|20191208 17 | 香蕉|18|20191208 18 | 橘子|12|20191208 19 | 香蕉|16|20191209 20 | 橘子|11|20191209 21 | 苹果|11|20191210 22 | 橘子|13|20191210 23 | 苹果|10|20191211 24 | 香蕉|22|20191211 25 | 橘子|14|20191212 26 | 27 | 现在要求通过 sql 统计出 `20191212 这天的平均价格 比 20191209 那天涨了多少` ? 28 | 29 | 正常情况下我们可能会写出这样的 sql 30 | ```sql 31 | SELECT 32 | a1.avg_price AS `20191209 平均价格`, 33 | a2.avg_price AS `20191212 平均价格`, 34 | (a2.avg_price - a1.avg_price) AS `涨价金额` 35 | FROM 36 | ( 37 | -- 求出各类别 20191209 前最后一次报价的平均价格 38 | SELECT 39 | avg(product.price) AS avg_price 40 | FROM 41 | ( 42 | -- 求出各商品在 20191209 前最后一次报价的日期 43 | SELECT 44 | name, 45 | max(date) AS max_date 46 | FROM 47 | product 48 | WHERE 49 | date <= '20191209' 50 | GROUP BY 51 | name 52 | ) AS t1 53 | LEFT JOIN product 54 | ON t1.name = product.name AND t1.max_date = product.date 55 | ) AS a1 56 | LEFT JOIN 57 | ( 58 | -- 再求出各类别 20191212 前最后一次报价的平均价格 59 | SELECT 60 | avg(product.price) AS avg_price 61 | FROM 62 | ( 63 | -- 先求出各商品在 20191212 前最后一次报价的日期 64 | SELECT 65 | name, 66 | max(date) AS max_date 67 | FROM 68 | product 69 | WHERE 70 | date <= '20191212' 71 | GROUP BY 72 | name 73 | ) AS t2 74 | LEFT JOIN product 75 | ON t2.name = product.name AND t2.max_date = product.date 76 | ) AS a2 77 | ON true 78 | ``` 79 | 80 | 得到统计结果如下: 81 | 82 | 20191209 平均价格|20191212 平均价格|涨价金额 83 | -|-|- 84 | 14.0000|15.3333|1.3333 85 | 86 | 87 | 传统做法虽然得到的结果是正确的,但同时暴露出以下问题: 88 | 1. 子查询多层嵌套,代码可读性极低 89 | 2. `t1` `t2` 两个子查询内容基本一致,也就说我们要维护两处相同的代码 90 | 3. `a1` `a2` 两个子查询也基本一致,并且其中相同的注释我们要写两遍,感觉太"蠢"了 91 | 4. 这只是个很简单的示例,在实际工作中,针对更复杂的统计需求,代码的复杂度将会以指数形式递增 92 | 93 | 94 | 下面看看如何使用 sqlx 来解决上述问题: 95 | ```sql 96 | func product_max_date(day) 97 | -- 子查询: 统计出各个商品在 {day} 前最后一次报价的日期 98 | ( 99 | SELECT 100 | name, 101 | max(date) AS max_date 102 | FROM 103 | product 104 | WHERE 105 | date <= '{day}' 106 | GROUP BY 107 | name 108 | ) 109 | end 110 | 111 | func date_avg_price(day): 112 | -- 子查询: 统计出 {day} 这天各个类别的平均价格 113 | ( 114 | SELECT 115 | avg(product.price) AS avg_price 116 | FROM 117 | {product_max_date($day)} AS t1 118 | LEFT JOIN product 119 | ON t1.name = product.name AND t1.max_date = product.date 120 | ) 121 | end 122 | 123 | SELECT 124 | a1.avg_price AS `20191209 平均价格`, 125 | a2.avg_price AS `20191212 平均价格`, 126 | (a2.avg_price - a1.avg_price) AS `涨价金额` 127 | FROM 128 | {date_avg_price(20191209)} AS a1 129 | LEFT JOIN 130 | {date_avg_price(20191212)} AS a2 131 | ON true 132 | ``` 133 | 134 | 135 | 优势非常明显: 136 | 1. 核心代码是一段短小的 `SELECT`,外加两个子查询的定义就搞定了,代码逻辑清晰,可读性高 137 | 2. `a1` `a2` 使用类似 `函数` 的概念进行封装,通过传入不同的参数来生成不同的子查询内容 138 | 3. 相同逻辑的代码片段只需要写一遍,大大降低了代码维护的工作量 139 | 4. 使用 sqlx 提供的编译工具或插件,可快速编译成 sql 代码,在数据库中执行结果一致 140 | 141 | 142 | ## 语法简介 143 | 144 | ### 1. 通过 `var` 定义变量,可在脚本中反复引用 145 | 146 | 示例: 147 | ```sql 148 | var field_name = age 149 | var field_value = 30 150 | 151 | SELECT {field_name} from students WHERE {field_name} < {field_value}; 152 | SELECT {field_name} from teachers WHERE {field_name} > {field_value}; 153 | ``` 154 | 155 | 编译生成 sql 为: 156 | ```sql 157 | SELECT age from students WHERE age < 30; 158 | SELECT age from teachers WHERE age > 30; 159 | ``` 160 | 161 | 162 | ### 2. 通过 `func` 定义脚本片段,并反复引用 163 | 164 | 示例: 165 | ```sql 166 | -- ! 定义片段 167 | func good_students(score): 168 | ( 169 | SELECT 170 | * 171 | FROM 172 | students 173 | WHERE 174 | score > {score} 175 | ) AS good_students 176 | end 177 | 178 | SELECT name FROM {good_students(80)}; 179 | SELECT count(*) FROM {good_students(80)}; 180 | ``` 181 | 182 | 编译生成 sql 为: 183 | ```sql 184 | SELECT name FROM 185 | ( 186 | SELECT 187 | * 188 | FROM 189 | students 190 | WHERE 191 | score > 80 192 | ) AS good_students 193 | ; 194 | SELECT count(*) FROM 195 | ( 196 | SELECT 197 | * 198 | FROM 199 | students 200 | WHERE 201 | score > 80 202 | ) AS good_students 203 | ; 204 | ``` 205 | 206 | 207 | ### 3. 循环 208 | 通过 `for` 批量循环生成脚本(暂不支持循环嵌套) 209 | 210 | 211 | 212 | 示例1: 213 | ```sql 214 | {% for n in table1,table2,table3 %} 215 | SELECT * FROM {n}; 216 | {% endfor %} 217 | ``` 218 | 219 | 编译生成 sql 为: 220 | ```sql 221 | SELECT * FROM table1; 222 | SELECT * FROM table2; 223 | SELECT * FROM table3; 224 | ``` 225 | 226 | 227 | 示例2: 228 | ```sql 229 | {% for n|m in table1|id,table2|name,table3|age %} 230 | SELECT {m} FROM {n}; 231 | {% endfor %} 232 | ``` 233 | 234 | 编译生成 sql 为: 235 | ```sql 236 | SELECT id FROM table1; 237 | SELECT name FROM table2; 238 | SELECT age FROM table3; 239 | ``` 240 | 241 | 242 | ### 4. 判断 243 | 通过 `if` 生成逻辑分支脚本(暂不支持 if 嵌套) 244 | 245 | 246 | 示例1: 247 | ```sql 248 | var a 8 249 | 250 | {% if $a > 4 %} 251 | SELECT * FROM table1; 252 | {% endif %} 253 | ``` 254 | 255 | 编译生成 sql 为: 256 | ```sql 257 | SELECT * FROM table1; 258 | ``` 259 | 260 | 示例2: 261 | ```sql 262 | {% for n in table1,table2,table3 %} 263 | {% if $n == table1 %} 264 | SELECT id, name FROM {n}; 265 | {% else %} 266 | SELECT * FROM {n}; 267 | {% endif %} 268 | {% endfor %} 269 | ``` 270 | 271 | 编译生成 sql 为: 272 | ```sql 273 | SELECT id, name FROM table1; 274 | SELECT * FROM table2; 275 | SELECT * FROM table3; 276 | ``` 277 | 278 | 279 | 更多示例可参考 [demo.sqlx](https://github.com/taojy123/sqlx/blob/master/demo.sqlx) 280 | 281 | 282 | ### 5. 处理 `{` `}` 字符 283 | 284 | 如果你需要在生成的 sql 内容中包含 `{` `}` 这样的字符,不能直接在 sqlx 中写 `{` 或 `}`,因为这样会被认为是变量引用的起止标记 285 | 286 | 你需要在这些字符前加上一个转义符(默认是`\`),如 `\{` `\}` 这样即可 287 | 288 | 示例: 289 | ```sql 290 | var cc dd 291 | SELECT * FROM table1 WHERE name = 'aa\{bb\}{cc}' 292 | ``` 293 | 294 | 编译生成 sql 为: 295 | ```sql 296 | SELECT * FROM table1 WHERE name = 'aa{bb}dd' 297 | ``` 298 | 299 | 300 | ### 6. 使用 `import` 导入模块 301 | 302 | 通过 import 可以引入现有的 sqlx 脚本文件作,但只能导入其中的 var 和 func 303 | 304 | 如果在当前脚本有重复同名变量或 func,会被覆盖以当前脚本为准 305 | 306 | 示例: 307 | ```sql 308 | -- mod.sqlx 309 | var colume name 310 | var colume2 score 311 | 312 | func good_students(score): 313 | ( 314 | SELECT 315 | * 316 | FROM 317 | students 318 | WHERE 319 | score > {score} 320 | ) AS good_students 321 | end 322 | ``` 323 | 324 | ```sql 325 | import mod 326 | var colume2 age 327 | SELECT {colume} from teachers WHERE {colume2} > 10; 328 | SELECT name FROM {good_students(60)}; 329 | SELECT count(*) FROM {good_students(80)}; 330 | ``` 331 | 332 | 编译生成 sql 为: 333 | ```sql 334 | SELECT name from teachers WHERE age > 10; 335 | SELECT name FROM 336 | ( 337 | SELECT 338 | * 339 | FROM 340 | students 341 | WHERE 342 | score > 60 343 | ) AS good_students 344 | ; 345 | SELECT count(*) FROM 346 | ( 347 | SELECT 348 | * 349 | FROM 350 | students 351 | WHERE 352 | score > 80 353 | ) AS good_students 354 | ; 355 | ``` 356 | 357 | 358 | ------- 359 | 360 | ## 安装使用 361 | 362 | Windows 64位系统,可以直接下载 [sqlx.exe](https://github.com/taojy123/sqlx/releases)  363 | 364 | 双击运行,即可将当前目录下的 `sqlx 脚本文件 `编译为 `sql`, 放置于 `dist` 目录中。 365 | 366 | 367 | ------- 368 | 369 | ## 使用 Sublime Text 插件 370 | 371 | 372 | Sqlx 插件已被 `Sublime Text` 官方收录。 373 | 374 | 可搜索安装 `Sqlx Builder` 插件,在 Build System 中选择 `Sqlx`,可快捷将 sqlx 脚本编译为 sql。 375 | 376 | ![](https://raw.githubusercontent.com/taojy123/SublimeText-Sqlx/master/sqlx.png) 377 | 378 | ![](https://raw.githubusercontent.com/taojy123/SublimeText-Sqlx/master/sqlx2.png) 379 | 380 | ------- 381 | 382 | 383 | ## 其他系统平台,可通过 Python3 安装使用 384 | 385 | 如果你的系统无法运行 `sqlx.exe`,可以先安装 [Python3](https://www.python.org/downloads/),然后使用 `pip` 命令一键安装 386 | 387 | ``` 388 | pip install sqlx 389 | ``` 390 | 391 | 392 | ### 使用 `sqlx` 命令行工具 393 | 394 | 1. 安装后直接执行 `sqlx` 命令,可一键编译当前目录下的所有 `.sqlx 脚本文件` 395 | ``` 396 | $ ls 397 | test1.sqlx test2.sqlx 398 | 399 | $ sqlx 400 | dist/test1.sql built 401 | dist/test2.sql built 402 | Finish! 403 | 404 | $ ls dist 405 | test1.sql test2.sql 406 | ``` 407 | 408 | 409 | 2. `sqlx` 命令后跟随目录路径参数,可编译指定路径下的所有脚本 410 | ``` 411 | $ ls test 412 | test3.sqlx test4.sqlx 413 | 414 | $ sqlx ./test/ 415 | test/dist/test3.sql built 416 | test/dist/test4.sql built 417 | Finish! 418 | 419 | $ ls test/dist 420 | test3.sql test4.sql 421 | ``` 422 | 423 | 424 | 3. `sqlx` 命令后跟随文件路径参数,可编译指定的单个脚本 425 | ``` 426 | $ sqlx ./test/test3.sqlx 427 | test/dist/test3.sql built 428 | Finish! 429 | 430 | $ ls test/dist 431 | test3.sql 432 | ``` 433 | 434 | 435 | ### 在 Python3 程序中使用 `sqlx.build` 方法 436 | ```python 437 | import sqlx 438 | 439 | my_script = """ 440 | {% for n in table1,table2,table3 %} 441 | {% if $n == table1 %} 442 | SELECT id, name FROM {n}; 443 | {% else %} 444 | SELECT * FROM {n}; 445 | {% endif %} 446 | {% endfor %} 447 | """ 448 | 449 | sql = sqlx.build(my_script, pretty=True) 450 | print(sql) 451 | ``` 452 | 453 | 454 | ------- 455 | 456 | 457 | ## 版本更新说明 458 | 459 | 460 | ### v0.2.0 461 | 462 | 为提高脚本书写体验,变更了语法关键词 463 | 464 | - `define` 改成 `var` 465 | - `block .. endblock` 改成 `func .. end` 466 | 467 | 老版本语法目前依旧兼容 468 | 469 | 470 | ### v0.1.1 471 | 472 | 第一个可用版本发布 473 | 474 | - 支持 `escape` (默认`\`) 475 | - 自动复制编译后的 `sql` 进剪切板 476 | - 支持 import 导入 sqlx 脚本模块 477 | 478 | 479 | ### v0.1.0 480 | 481 | 第一个可用版本发布 482 | 483 | - 支持 `var` 语法 484 | - 支持 `func` 语法 485 | - 支持 `for` 语法 486 | - 支持 `if` 语法 487 | 488 | -------------------------------------------------------------------------------- /demo.sqlx: -------------------------------------------------------------------------------- 1 | -- ! sqlx 脚本语法示例 2 | 3 | 4 | -- ! var 关键词定义全局变量 5 | var flag = f001 6 | 7 | 8 | -- ! func 定义一个可重用的内容块(类似函数),并可接受形式参数 9 | func t1(day): 10 | ( 11 | SELECT 12 | name, 13 | max(date) AS max_date 14 | FROM 15 | product 16 | WHERE 17 | date <= '{day}' 18 | GROUP BY 19 | name 20 | ) as t1 21 | end 22 | 23 | 24 | -- ! for 循环语法 25 | {% for n|m in 1|a,2|b,3|c %} 26 | -- --- 循环 --- {n} --- {m} ----- 27 | SELECT 28 | -- ! 使用变量 29 | '{flag}' AS flag, 30 | 31 | -- ! if 判断语法 32 | {% if $m == a %} 33 | 1 as is_a, 34 | {% endif %} 35 | 36 | {% if $n > 1 %} 37 | 1 as is_more, 38 | {% else %} 39 | 0 as is_more, 40 | {% endif %} 41 | 42 | -- ! 转义符 \ 43 | {n}_{m}_$\{xxx\} as mark 44 | FROM 45 | product 46 | LEFT JOIN {t1(20191208)} -- ! 调用 func 47 | ON t1.max_date = product.date AND t1.name = product.name 48 | ; 49 | {% endfor %} 50 | 51 | 52 | -- ----------------- 53 | 54 | -- ! 通过 import 可以引入现有的 sqlx 脚本文件作,但只能导入其中的 var 和 func 55 | -- ! 如果当前脚本有重复同名变量或 func,会被覆盖 56 | import mod 57 | 58 | var colume2 = age 59 | 60 | SELECT {colume} from teachers WHERE {colume2} > 10; 61 | SELECT name FROM {good_students(60)}; 62 | SELECT count(*) FROM {good_students(80)}; 63 | 64 | -------------------------------------------------------------------------------- /mod.sqlx: -------------------------------------------------------------------------------- 1 | 2 | var colume = name 3 | var colume2 = score 4 | 5 | func good_students(score): 6 | ( 7 | SELECT 8 | * 9 | FROM 10 | students 11 | WHERE 12 | score > {score} 13 | ) AS good_students 14 | end 15 | 16 | 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Python3 2 | 3 | pyperclip 4 | js2py 5 | 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #coding=utf8 2 | 3 | from setuptools import setup, find_packages 4 | 5 | from sqlx import VERSION 6 | 7 | 8 | try: 9 | long_description = open('README.md', encoding='utf8').read() 10 | except Exception as e: 11 | long_description = '' 12 | 13 | 14 | install_requires = [] 15 | for line in open('requirements.txt', encoding='utf8').readlines(): 16 | line = line.strip() 17 | if line and not line.startswith('#'): 18 | install_requires.append(line) 19 | 20 | 21 | setup( 22 | name='sqlx', 23 | version=VERSION, 24 | description='SQL Extension | SQL 语法拓展,目标是打造 "易读易写 方便维护" 的 sql 脚本', 25 | long_description=long_description, 26 | long_description_content_type="text/markdown", 27 | author='tao.py', 28 | author_email='taojy123@163.com', 29 | maintainer='tao.py', 30 | maintainer_email='taojy123@163.com', 31 | install_requires=install_requires, 32 | license='MIT License', 33 | packages=find_packages(), 34 | py_modules=['sqlx', 'sqlformat'], 35 | entry_points={ 36 | 'console_scripts': ['sqlx=sqlx:auto'], 37 | }, 38 | include_package_data=True, 39 | platforms=["all"], 40 | url='https://github.com/taojy123/sqlx', 41 | classifiers=[ 42 | 'Programming Language :: Python', 43 | 'Programming Language :: Python :: Implementation', 44 | 'Programming Language :: Python :: 3 :: Only', 45 | 'Topic :: Software Development :: Libraries' 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /sqlformat.py: -------------------------------------------------------------------------------- 1 | 2 | import js2py 3 | 4 | 5 | js = r""" 6 | // https://github.com/zeroturnaround/sql-formatter 7 | var factory = function() { 8 | return /******/ (function(modules) { // webpackBootstrap 9 | /******/ // The module cache 10 | /******/ var installedModules = {}; 11 | 12 | /******/ // The require function 13 | /******/ function __webpack_require__(moduleId) { 14 | 15 | /******/ // Check if module is in cache 16 | /******/ if(installedModules[moduleId]) 17 | /******/ return installedModules[moduleId].exports; 18 | 19 | /******/ // Create a new module (and put it into the cache) 20 | /******/ var module = installedModules[moduleId] = { 21 | /******/ exports: {}, 22 | /******/ id: moduleId, 23 | /******/ loaded: false 24 | /******/ }; 25 | 26 | /******/ // Execute the module function 27 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 28 | 29 | /******/ // Flag the module as loaded 30 | /******/ module.loaded = true; 31 | 32 | /******/ // Return the exports of the module 33 | /******/ return module.exports; 34 | /******/ } 35 | 36 | 37 | /******/ // expose the modules object (__webpack_modules__) 38 | /******/ __webpack_require__.m = modules; 39 | 40 | /******/ // expose the module cache 41 | /******/ __webpack_require__.c = installedModules; 42 | 43 | /******/ // __webpack_public_path__ 44 | /******/ __webpack_require__.p = ""; 45 | 46 | /******/ // Load entry module and return exports 47 | /******/ return __webpack_require__(0); 48 | /******/ }) 49 | /************************************************************************/ 50 | /******/ ([ 51 | /* 0 */ 52 | /***/ (function(module, exports, __webpack_require__) { 53 | 54 | "use strict"; 55 | 56 | exports.__esModule = true; 57 | 58 | var _Db2Formatter = __webpack_require__(24); 59 | 60 | var _Db2Formatter2 = _interopRequireDefault(_Db2Formatter); 61 | 62 | var _N1qlFormatter = __webpack_require__(25); 63 | 64 | var _N1qlFormatter2 = _interopRequireDefault(_N1qlFormatter); 65 | 66 | var _PlSqlFormatter = __webpack_require__(26); 67 | 68 | var _PlSqlFormatter2 = _interopRequireDefault(_PlSqlFormatter); 69 | 70 | var _StandardSqlFormatter = __webpack_require__(27); 71 | 72 | var _StandardSqlFormatter2 = _interopRequireDefault(_StandardSqlFormatter); 73 | 74 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 75 | 76 | exports["default"] = { 77 | /** 78 | * Format whitespaces in a query to make it easier to read. 79 | * 80 | * @param {String} query 81 | * @param {Object} cfg 82 | * @param {String} cfg.language Query language, default is Standard SQL 83 | * @param {String} cfg.indent Characters used for indentation, default is " " (2 spaces) 84 | * @param {Object} cfg.params Collection of params for placeholder replacement 85 | * @return {String} 86 | */ 87 | format: function format(query, cfg) { 88 | cfg = cfg || {}; 89 | 90 | switch (cfg.language) { 91 | case "db2": 92 | return new _Db2Formatter2["default"](cfg).format(query); 93 | case "n1ql": 94 | return new _N1qlFormatter2["default"](cfg).format(query); 95 | case "pl/sql": 96 | return new _PlSqlFormatter2["default"](cfg).format(query); 97 | case "sql": 98 | case undefined: 99 | return new _StandardSqlFormatter2["default"](cfg).format(query); 100 | default: 101 | throw Error("Unsupported SQL dialect: " + cfg.language); 102 | } 103 | } 104 | }; 105 | module.exports = exports["default"]; 106 | 107 | /***/ }), 108 | /* 1 */ 109 | /***/ (function(module, exports, __webpack_require__) { 110 | 111 | var freeGlobal = __webpack_require__(12); 112 | 113 | /** Detect free variable `self`. */ 114 | var freeSelf = typeof self == 'object' && self && self.Object === Object && self; 115 | 116 | /** Used as a reference to the global object. */ 117 | var root = freeGlobal || freeSelf || Function('return this')(); 118 | 119 | module.exports = root; 120 | 121 | 122 | /***/ }), 123 | /* 2 */ 124 | /***/ (function(module, exports, __webpack_require__) { 125 | 126 | var Symbol = __webpack_require__(9), 127 | getRawTag = __webpack_require__(48), 128 | objectToString = __webpack_require__(57); 129 | 130 | /** `Object#toString` result references. */ 131 | var nullTag = '[object Null]', 132 | undefinedTag = '[object Undefined]'; 133 | 134 | /** Built-in value references. */ 135 | var symToStringTag = Symbol ? Symbol.toStringTag : undefined; 136 | 137 | /** 138 | * The base implementation of `getTag` without fallbacks for buggy environments. 139 | * 140 | * @private 141 | * @param {*} value The value to query. 142 | * @returns {string} Returns the `toStringTag`. 143 | */ 144 | function baseGetTag(value) { 145 | if (value == null) { 146 | return value === undefined ? undefinedTag : nullTag; 147 | } 148 | return (symToStringTag && symToStringTag in Object(value)) 149 | ? getRawTag(value) 150 | : objectToString(value); 151 | } 152 | 153 | module.exports = baseGetTag; 154 | 155 | 156 | /***/ }), 157 | /* 3 */ 158 | /***/ (function(module, exports, __webpack_require__) { 159 | 160 | var baseIsNative = __webpack_require__(39), 161 | getValue = __webpack_require__(50); 162 | 163 | /** 164 | * Gets the native function at `key` of `object`. 165 | * 166 | * @private 167 | * @param {Object} object The object to query. 168 | * @param {string} key The key of the method to get. 169 | * @returns {*} Returns the function if it's native, else `undefined`. 170 | */ 171 | function getNative(object, key) { 172 | var value = getValue(object, key); 173 | return baseIsNative(value) ? value : undefined; 174 | } 175 | 176 | module.exports = getNative; 177 | 178 | 179 | /***/ }), 180 | /* 4 */ 181 | /***/ (function(module, exports, __webpack_require__) { 182 | 183 | "use strict"; 184 | 185 | exports.__esModule = true; 186 | 187 | var _trimEnd = __webpack_require__(74); 188 | 189 | var _trimEnd2 = _interopRequireDefault(_trimEnd); 190 | 191 | var _tokenTypes = __webpack_require__(8); 192 | 193 | var _tokenTypes2 = _interopRequireDefault(_tokenTypes); 194 | 195 | var _Indentation = __webpack_require__(21); 196 | 197 | var _Indentation2 = _interopRequireDefault(_Indentation); 198 | 199 | var _InlineBlock = __webpack_require__(22); 200 | 201 | var _InlineBlock2 = _interopRequireDefault(_InlineBlock); 202 | 203 | var _Params = __webpack_require__(23); 204 | 205 | var _Params2 = _interopRequireDefault(_Params); 206 | 207 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 208 | 209 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 210 | 211 | var Formatter = function () { 212 | /** 213 | * @param {Object} cfg 214 | * @param {Object} cfg.indent 215 | * @param {Object} cfg.params 216 | * @param {Tokenizer} tokenizer 217 | */ 218 | function Formatter(cfg, tokenizer) { 219 | _classCallCheck(this, Formatter); 220 | 221 | this.cfg = cfg || {}; 222 | this.indentation = new _Indentation2["default"](this.cfg.indent); 223 | this.inlineBlock = new _InlineBlock2["default"](); 224 | this.params = new _Params2["default"](this.cfg.params); 225 | this.tokenizer = tokenizer; 226 | this.previousReservedWord = {}; 227 | this.tokens = []; 228 | this.index = 0; 229 | } 230 | 231 | /** 232 | * Formats whitespaces in a SQL string to make it easier to read. 233 | * 234 | * @param {String} query The SQL query string 235 | * @return {String} formatted query 236 | */ 237 | 238 | 239 | Formatter.prototype.format = function format(query) { 240 | this.tokens = this.tokenizer.tokenize(query); 241 | var formattedQuery = this.getFormattedQueryFromTokens(); 242 | 243 | return formattedQuery.trim(); 244 | }; 245 | 246 | Formatter.prototype.getFormattedQueryFromTokens = function getFormattedQueryFromTokens() { 247 | var _this = this; 248 | 249 | var formattedQuery = ""; 250 | 251 | this.tokens.forEach(function (token, index) { 252 | _this.index = index; 253 | 254 | if (token.type === _tokenTypes2["default"].WHITESPACE) { 255 | // ignore (we do our own whitespace formatting) 256 | } else if (token.type === _tokenTypes2["default"].LINE_COMMENT) { 257 | formattedQuery = _this.formatLineComment(token, formattedQuery); 258 | } else if (token.type === _tokenTypes2["default"].BLOCK_COMMENT) { 259 | formattedQuery = _this.formatBlockComment(token, formattedQuery); 260 | } else if (token.type === _tokenTypes2["default"].RESERVED_TOPLEVEL) { 261 | formattedQuery = _this.formatToplevelReservedWord(token, formattedQuery); 262 | _this.previousReservedWord = token; 263 | } else if (token.type === _tokenTypes2["default"].RESERVED_NEWLINE) { 264 | formattedQuery = _this.formatNewlineReservedWord(token, formattedQuery); 265 | _this.previousReservedWord = token; 266 | } else if (token.type === _tokenTypes2["default"].RESERVED) { 267 | formattedQuery = _this.formatWithSpaces(token, formattedQuery); 268 | _this.previousReservedWord = token; 269 | } else if (token.type === _tokenTypes2["default"].OPEN_PAREN) { 270 | formattedQuery = _this.formatOpeningParentheses(token, formattedQuery); 271 | } else if (token.type === _tokenTypes2["default"].CLOSE_PAREN) { 272 | formattedQuery = _this.formatClosingParentheses(token, formattedQuery); 273 | } else if (token.type === _tokenTypes2["default"].PLACEHOLDER) { 274 | formattedQuery = _this.formatPlaceholder(token, formattedQuery); 275 | } else if (token.value === ",") { 276 | formattedQuery = _this.formatComma(token, formattedQuery); 277 | } else if (token.value === ":") { 278 | formattedQuery = _this.formatWithSpaceAfter(token, formattedQuery); 279 | } else if (token.value === ".") { 280 | formattedQuery = _this.formatWithoutSpaces(token, formattedQuery); 281 | } else if (token.value === ";") { 282 | formattedQuery = _this.formatQuerySeparator(token, formattedQuery); 283 | } else { 284 | formattedQuery = _this.formatWithSpaces(token, formattedQuery); 285 | } 286 | }); 287 | return formattedQuery; 288 | }; 289 | 290 | Formatter.prototype.formatLineComment = function formatLineComment(token, query) { 291 | return this.addNewline(query + token.value); 292 | }; 293 | 294 | Formatter.prototype.formatBlockComment = function formatBlockComment(token, query) { 295 | return this.addNewline(this.addNewline(query) + this.indentComment(token.value)); 296 | }; 297 | 298 | Formatter.prototype.indentComment = function indentComment(comment) { 299 | return comment.replace(/\n/g, "\n" + this.indentation.getIndent()); 300 | }; 301 | 302 | Formatter.prototype.formatToplevelReservedWord = function formatToplevelReservedWord(token, query) { 303 | this.indentation.decreaseTopLevel(); 304 | 305 | query = this.addNewline(query); 306 | 307 | this.indentation.increaseToplevel(); 308 | 309 | query += this.equalizeWhitespace(token.value); 310 | return this.addNewline(query); 311 | }; 312 | 313 | Formatter.prototype.formatNewlineReservedWord = function formatNewlineReservedWord(token, query) { 314 | return this.addNewline(query) + this.equalizeWhitespace(token.value) + " "; 315 | }; 316 | 317 | // Replace any sequence of whitespace characters with single space 318 | 319 | 320 | Formatter.prototype.equalizeWhitespace = function equalizeWhitespace(string) { 321 | return string.replace(/\s+/g, " "); 322 | }; 323 | 324 | // Opening parentheses increase the block indent level and start a new line 325 | 326 | 327 | Formatter.prototype.formatOpeningParentheses = function formatOpeningParentheses(token, query) { 328 | // Take out the preceding space unless there was whitespace there in the original query 329 | // or another opening parens or line comment 330 | var preserveWhitespaceFor = [_tokenTypes2["default"].WHITESPACE, _tokenTypes2["default"].OPEN_PAREN, _tokenTypes2["default"].LINE_COMMENT]; 331 | if (!preserveWhitespaceFor.includes(this.previousToken().type)) { 332 | query = (0, _trimEnd2["default"])(query); 333 | } 334 | query += token.value; 335 | 336 | this.inlineBlock.beginIfPossible(this.tokens, this.index); 337 | 338 | if (!this.inlineBlock.isActive()) { 339 | this.indentation.increaseBlockLevel(); 340 | query = this.addNewline(query); 341 | } 342 | return query; 343 | }; 344 | 345 | // Closing parentheses decrease the block indent level 346 | 347 | 348 | Formatter.prototype.formatClosingParentheses = function formatClosingParentheses(token, query) { 349 | if (this.inlineBlock.isActive()) { 350 | this.inlineBlock.end(); 351 | return this.formatWithSpaceAfter(token, query); 352 | } else { 353 | this.indentation.decreaseBlockLevel(); 354 | return this.formatWithSpaces(token, this.addNewline(query)); 355 | } 356 | }; 357 | 358 | Formatter.prototype.formatPlaceholder = function formatPlaceholder(token, query) { 359 | return query + this.params.get(token) + " "; 360 | }; 361 | 362 | // Commas start a new line (unless within inline parentheses or SQL "LIMIT" clause) 363 | 364 | 365 | Formatter.prototype.formatComma = function formatComma(token, query) { 366 | query = this.trimTrailingWhitespace(query) + token.value + " "; 367 | 368 | if (this.inlineBlock.isActive()) { 369 | return query; 370 | } else if (/^LIMIT$/i.test(this.previousReservedWord.value)) { 371 | return query; 372 | } else { 373 | return this.addNewline(query); 374 | } 375 | }; 376 | 377 | Formatter.prototype.formatWithSpaceAfter = function formatWithSpaceAfter(token, query) { 378 | return this.trimTrailingWhitespace(query) + token.value + " "; 379 | }; 380 | 381 | Formatter.prototype.formatWithoutSpaces = function formatWithoutSpaces(token, query) { 382 | return this.trimTrailingWhitespace(query) + token.value; 383 | }; 384 | 385 | Formatter.prototype.formatWithSpaces = function formatWithSpaces(token, query) { 386 | return query + token.value + " "; 387 | }; 388 | 389 | Formatter.prototype.formatQuerySeparator = function formatQuerySeparator(token, query) { 390 | return this.trimTrailingWhitespace(query) + token.value + "\n"; 391 | }; 392 | 393 | Formatter.prototype.addNewline = function addNewline(query) { 394 | return (0, _trimEnd2["default"])(query) + "\n" + this.indentation.getIndent(); 395 | }; 396 | 397 | Formatter.prototype.trimTrailingWhitespace = function trimTrailingWhitespace(query) { 398 | if (this.previousNonWhitespaceToken().type === _tokenTypes2["default"].LINE_COMMENT) { 399 | return (0, _trimEnd2["default"])(query) + "\n"; 400 | } else { 401 | return (0, _trimEnd2["default"])(query); 402 | } 403 | }; 404 | 405 | Formatter.prototype.previousNonWhitespaceToken = function previousNonWhitespaceToken() { 406 | var n = 1; 407 | while (this.previousToken(n).type === _tokenTypes2["default"].WHITESPACE) { 408 | n++; 409 | } 410 | return this.previousToken(n); 411 | }; 412 | 413 | Formatter.prototype.previousToken = function previousToken() { 414 | var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; 415 | 416 | return this.tokens[this.index - offset] || {}; 417 | }; 418 | 419 | return Formatter; 420 | }(); 421 | 422 | exports["default"] = Formatter; 423 | module.exports = exports["default"]; 424 | 425 | /***/ }), 426 | /* 5 */ 427 | /***/ (function(module, exports, __webpack_require__) { 428 | 429 | "use strict"; 430 | 431 | exports.__esModule = true; 432 | 433 | var _isEmpty = __webpack_require__(66); 434 | 435 | var _isEmpty2 = _interopRequireDefault(_isEmpty); 436 | 437 | var _escapeRegExp = __webpack_require__(63); 438 | 439 | var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp); 440 | 441 | var _tokenTypes = __webpack_require__(8); 442 | 443 | var _tokenTypes2 = _interopRequireDefault(_tokenTypes); 444 | 445 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 446 | 447 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 448 | 449 | var Tokenizer = function () { 450 | /** 451 | * @param {Object} cfg 452 | * @param {String[]} cfg.reservedWords Reserved words in SQL 453 | * @param {String[]} cfg.reservedToplevelWords Words that are set to new line separately 454 | * @param {String[]} cfg.reservedNewlineWords Words that are set to newline 455 | * @param {String[]} cfg.stringTypes String types to enable: "", '', ``, [], N'' 456 | * @param {String[]} cfg.openParens Opening parentheses to enable, like (, [ 457 | * @param {String[]} cfg.closeParens Closing parentheses to enable, like ), ] 458 | * @param {String[]} cfg.indexedPlaceholderTypes Prefixes for indexed placeholders, like ? 459 | * @param {String[]} cfg.namedPlaceholderTypes Prefixes for named placeholders, like @ and : 460 | * @param {String[]} cfg.lineCommentTypes Line comments to enable, like # and -- 461 | * @param {String[]} cfg.specialWordChars Special chars that can be found inside of words, like @ and # 462 | */ 463 | function Tokenizer(cfg) { 464 | _classCallCheck(this, Tokenizer); 465 | 466 | this.WHITESPACE_REGEX = /^(\s+)/; 467 | this.NUMBER_REGEX = /^((-\s*)?[0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)\b/; 468 | this.OPERATOR_REGEX = /^(!=|<>|==|<=|>=|!<|!>|\|\||::|->>|->|~~\*|~~|!~~\*|!~~|~\*|!~\*|!~|.)/; 469 | 470 | this.BLOCK_COMMENT_REGEX = /^(\/\*[^]*?(?:\*\/|$))/; 471 | this.LINE_COMMENT_REGEX = this.createLineCommentRegex(cfg.lineCommentTypes); 472 | 473 | this.RESERVED_TOPLEVEL_REGEX = this.createReservedWordRegex(cfg.reservedToplevelWords); 474 | this.RESERVED_NEWLINE_REGEX = this.createReservedWordRegex(cfg.reservedNewlineWords); 475 | this.RESERVED_PLAIN_REGEX = this.createReservedWordRegex(cfg.reservedWords); 476 | 477 | this.WORD_REGEX = this.createWordRegex(cfg.specialWordChars); 478 | this.STRING_REGEX = this.createStringRegex(cfg.stringTypes); 479 | 480 | this.OPEN_PAREN_REGEX = this.createParenRegex(cfg.openParens); 481 | this.CLOSE_PAREN_REGEX = this.createParenRegex(cfg.closeParens); 482 | 483 | this.INDEXED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.indexedPlaceholderTypes, "[0-9]*"); 484 | this.IDENT_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.namedPlaceholderTypes, "[a-zA-Z0-9._$]+"); 485 | this.STRING_NAMED_PLACEHOLDER_REGEX = this.createPlaceholderRegex(cfg.namedPlaceholderTypes, this.createStringPattern(cfg.stringTypes)); 486 | } 487 | 488 | Tokenizer.prototype.createLineCommentRegex = function createLineCommentRegex(lineCommentTypes) { 489 | return new RegExp("^((?:" + lineCommentTypes.map(function (c) { 490 | return (0, _escapeRegExp2["default"])(c); 491 | }).join("|") + ").*?(?:\n|$))"); 492 | }; 493 | 494 | Tokenizer.prototype.createReservedWordRegex = function createReservedWordRegex(reservedWords) { 495 | var reservedWordsPattern = reservedWords.join("|").replace(/ /g, "\\s+"); 496 | return new RegExp("^(" + reservedWordsPattern + ")\\b", "i"); 497 | }; 498 | 499 | Tokenizer.prototype.createWordRegex = function createWordRegex() { 500 | var specialChars = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; 501 | 502 | return new RegExp("^([\\w" + specialChars.join("") + "]+)"); 503 | }; 504 | 505 | Tokenizer.prototype.createStringRegex = function createStringRegex(stringTypes) { 506 | return new RegExp("^(" + this.createStringPattern(stringTypes) + ")"); 507 | }; 508 | 509 | // This enables the following string patterns: 510 | // 1. backtick quoted string using `` to escape 511 | // 2. square bracket quoted string (SQL Server) using ]] to escape 512 | // 3. double quoted string using "" or \" to escape 513 | // 4. single quoted string using '' or \' to escape 514 | // 5. national character quoted string using N'' or N\' to escape 515 | 516 | 517 | Tokenizer.prototype.createStringPattern = function createStringPattern(stringTypes) { 518 | var patterns = { 519 | "``": "((`[^`]*($|`))+)", 520 | "[]": "((\\[[^\\]]*($|\\]))(\\][^\\]]*($|\\]))*)", 521 | "\"\"": "((\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*(\"|$))+)", 522 | "''": "(('[^'\\\\]*(?:\\\\.[^'\\\\]*)*('|$))+)", 523 | "N''": "((N'[^N'\\\\]*(?:\\\\.[^N'\\\\]*)*('|$))+)" 524 | }; 525 | 526 | return stringTypes.map(function (t) { 527 | return patterns[t]; 528 | }).join("|"); 529 | }; 530 | 531 | Tokenizer.prototype.createParenRegex = function createParenRegex(parens) { 532 | var _this = this; 533 | 534 | return new RegExp("^(" + parens.map(function (p) { 535 | return _this.escapeParen(p); 536 | }).join("|") + ")", "i"); 537 | }; 538 | 539 | Tokenizer.prototype.escapeParen = function escapeParen(paren) { 540 | if (paren.length === 1) { 541 | // A single punctuation character 542 | return (0, _escapeRegExp2["default"])(paren); 543 | } else { 544 | // longer word 545 | return "\\b" + paren + "\\b"; 546 | } 547 | }; 548 | 549 | Tokenizer.prototype.createPlaceholderRegex = function createPlaceholderRegex(types, pattern) { 550 | if ((0, _isEmpty2["default"])(types)) { 551 | return false; 552 | } 553 | var typesRegex = types.map(_escapeRegExp2["default"]).join("|"); 554 | 555 | return new RegExp("^((?:" + typesRegex + ")(?:" + pattern + "))"); 556 | }; 557 | 558 | /** 559 | * Takes a SQL string and breaks it into tokens. 560 | * Each token is an object with type and value. 561 | * 562 | * @param {String} input The SQL string 563 | * @return {Object[]} tokens An array of tokens. 564 | * @return {String} token.type 565 | * @return {String} token.value 566 | */ 567 | 568 | 569 | Tokenizer.prototype.tokenize = function tokenize(input) { 570 | var tokens = []; 571 | var token = void 0; 572 | 573 | // Keep processing the string until it is empty 574 | while (input.length) { 575 | // Get the next token and the token type 576 | token = this.getNextToken(input, token); 577 | // Advance the string 578 | input = input.substring(token.value.length); 579 | 580 | tokens.push(token); 581 | } 582 | return tokens; 583 | }; 584 | 585 | Tokenizer.prototype.getNextToken = function getNextToken(input, previousToken) { 586 | return this.getWhitespaceToken(input) || this.getCommentToken(input) || this.getStringToken(input) || this.getOpenParenToken(input) || this.getCloseParenToken(input) || this.getPlaceholderToken(input) || this.getNumberToken(input) || this.getReservedWordToken(input, previousToken) || this.getWordToken(input) || this.getOperatorToken(input); 587 | }; 588 | 589 | Tokenizer.prototype.getWhitespaceToken = function getWhitespaceToken(input) { 590 | return this.getTokenOnFirstMatch({ 591 | input: input, 592 | type: _tokenTypes2["default"].WHITESPACE, 593 | regex: this.WHITESPACE_REGEX 594 | }); 595 | }; 596 | 597 | Tokenizer.prototype.getCommentToken = function getCommentToken(input) { 598 | return this.getLineCommentToken(input) || this.getBlockCommentToken(input); 599 | }; 600 | 601 | Tokenizer.prototype.getLineCommentToken = function getLineCommentToken(input) { 602 | return this.getTokenOnFirstMatch({ 603 | input: input, 604 | type: _tokenTypes2["default"].LINE_COMMENT, 605 | regex: this.LINE_COMMENT_REGEX 606 | }); 607 | }; 608 | 609 | Tokenizer.prototype.getBlockCommentToken = function getBlockCommentToken(input) { 610 | return this.getTokenOnFirstMatch({ 611 | input: input, 612 | type: _tokenTypes2["default"].BLOCK_COMMENT, 613 | regex: this.BLOCK_COMMENT_REGEX 614 | }); 615 | }; 616 | 617 | Tokenizer.prototype.getStringToken = function getStringToken(input) { 618 | return this.getTokenOnFirstMatch({ 619 | input: input, 620 | type: _tokenTypes2["default"].STRING, 621 | regex: this.STRING_REGEX 622 | }); 623 | }; 624 | 625 | Tokenizer.prototype.getOpenParenToken = function getOpenParenToken(input) { 626 | return this.getTokenOnFirstMatch({ 627 | input: input, 628 | type: _tokenTypes2["default"].OPEN_PAREN, 629 | regex: this.OPEN_PAREN_REGEX 630 | }); 631 | }; 632 | 633 | Tokenizer.prototype.getCloseParenToken = function getCloseParenToken(input) { 634 | return this.getTokenOnFirstMatch({ 635 | input: input, 636 | type: _tokenTypes2["default"].CLOSE_PAREN, 637 | regex: this.CLOSE_PAREN_REGEX 638 | }); 639 | }; 640 | 641 | Tokenizer.prototype.getPlaceholderToken = function getPlaceholderToken(input) { 642 | return this.getIdentNamedPlaceholderToken(input) || this.getStringNamedPlaceholderToken(input) || this.getIndexedPlaceholderToken(input); 643 | }; 644 | 645 | Tokenizer.prototype.getIdentNamedPlaceholderToken = function getIdentNamedPlaceholderToken(input) { 646 | return this.getPlaceholderTokenWithKey({ 647 | input: input, 648 | regex: this.IDENT_NAMED_PLACEHOLDER_REGEX, 649 | parseKey: function parseKey(v) { 650 | return v.slice(1); 651 | } 652 | }); 653 | }; 654 | 655 | Tokenizer.prototype.getStringNamedPlaceholderToken = function getStringNamedPlaceholderToken(input) { 656 | var _this2 = this; 657 | 658 | return this.getPlaceholderTokenWithKey({ 659 | input: input, 660 | regex: this.STRING_NAMED_PLACEHOLDER_REGEX, 661 | parseKey: function parseKey(v) { 662 | return _this2.getEscapedPlaceholderKey({ key: v.slice(2, -1), quoteChar: v.slice(-1) }); 663 | } 664 | }); 665 | }; 666 | 667 | Tokenizer.prototype.getIndexedPlaceholderToken = function getIndexedPlaceholderToken(input) { 668 | return this.getPlaceholderTokenWithKey({ 669 | input: input, 670 | regex: this.INDEXED_PLACEHOLDER_REGEX, 671 | parseKey: function parseKey(v) { 672 | return v.slice(1); 673 | } 674 | }); 675 | }; 676 | 677 | Tokenizer.prototype.getPlaceholderTokenWithKey = function getPlaceholderTokenWithKey(_ref) { 678 | var input = _ref.input, 679 | regex = _ref.regex, 680 | parseKey = _ref.parseKey; 681 | 682 | var token = this.getTokenOnFirstMatch({ input: input, regex: regex, type: _tokenTypes2["default"].PLACEHOLDER }); 683 | if (token) { 684 | token.key = parseKey(token.value); 685 | } 686 | return token; 687 | }; 688 | 689 | Tokenizer.prototype.getEscapedPlaceholderKey = function getEscapedPlaceholderKey(_ref2) { 690 | var key = _ref2.key, 691 | quoteChar = _ref2.quoteChar; 692 | 693 | return key.replace(new RegExp((0, _escapeRegExp2["default"])("\\") + quoteChar, "g"), quoteChar); 694 | }; 695 | 696 | // Decimal, binary, or hex numbers 697 | 698 | 699 | Tokenizer.prototype.getNumberToken = function getNumberToken(input) { 700 | return this.getTokenOnFirstMatch({ 701 | input: input, 702 | type: _tokenTypes2["default"].NUMBER, 703 | regex: this.NUMBER_REGEX 704 | }); 705 | }; 706 | 707 | // Punctuation and symbols 708 | 709 | 710 | Tokenizer.prototype.getOperatorToken = function getOperatorToken(input) { 711 | return this.getTokenOnFirstMatch({ 712 | input: input, 713 | type: _tokenTypes2["default"].OPERATOR, 714 | regex: this.OPERATOR_REGEX 715 | }); 716 | }; 717 | 718 | Tokenizer.prototype.getReservedWordToken = function getReservedWordToken(input, previousToken) { 719 | // A reserved word cannot be preceded by a "." 720 | // this makes it so in "mytable.from", "from" is not considered a reserved word 721 | if (previousToken && previousToken.value && previousToken.value === ".") { 722 | return; 723 | } 724 | return this.getToplevelReservedToken(input) || this.getNewlineReservedToken(input) || this.getPlainReservedToken(input); 725 | }; 726 | 727 | Tokenizer.prototype.getToplevelReservedToken = function getToplevelReservedToken(input) { 728 | return this.getTokenOnFirstMatch({ 729 | input: input, 730 | type: _tokenTypes2["default"].RESERVED_TOPLEVEL, 731 | regex: this.RESERVED_TOPLEVEL_REGEX 732 | }); 733 | }; 734 | 735 | Tokenizer.prototype.getNewlineReservedToken = function getNewlineReservedToken(input) { 736 | return this.getTokenOnFirstMatch({ 737 | input: input, 738 | type: _tokenTypes2["default"].RESERVED_NEWLINE, 739 | regex: this.RESERVED_NEWLINE_REGEX 740 | }); 741 | }; 742 | 743 | Tokenizer.prototype.getPlainReservedToken = function getPlainReservedToken(input) { 744 | return this.getTokenOnFirstMatch({ 745 | input: input, 746 | type: _tokenTypes2["default"].RESERVED, 747 | regex: this.RESERVED_PLAIN_REGEX 748 | }); 749 | }; 750 | 751 | Tokenizer.prototype.getWordToken = function getWordToken(input) { 752 | return this.getTokenOnFirstMatch({ 753 | input: input, 754 | type: _tokenTypes2["default"].WORD, 755 | regex: this.WORD_REGEX 756 | }); 757 | }; 758 | 759 | Tokenizer.prototype.getTokenOnFirstMatch = function getTokenOnFirstMatch(_ref3) { 760 | var input = _ref3.input, 761 | type = _ref3.type, 762 | regex = _ref3.regex; 763 | 764 | var matches = input.match(regex); 765 | 766 | if (matches) { 767 | return { type: type, value: matches[1] }; 768 | } 769 | }; 770 | 771 | return Tokenizer; 772 | }(); 773 | 774 | exports["default"] = Tokenizer; 775 | module.exports = exports["default"]; 776 | 777 | /***/ }), 778 | /* 6 */ 779 | /***/ (function(module, exports) { 780 | 781 | /** 782 | * Checks if `value` is the 783 | * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) 784 | * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) 785 | * 786 | * @static 787 | * @memberOf _ 788 | * @since 0.1.0 789 | * @category Lang 790 | * @param {*} value The value to check. 791 | * @returns {boolean} Returns `true` if `value` is an object, else `false`. 792 | * @example 793 | * 794 | * _.isObject({}); 795 | * // => true 796 | * 797 | * _.isObject([1, 2, 3]); 798 | * // => true 799 | * 800 | * _.isObject(_.noop); 801 | * // => true 802 | * 803 | * _.isObject(null); 804 | * // => false 805 | */ 806 | function isObject(value) { 807 | var type = typeof value; 808 | return value != null && (type == 'object' || type == 'function'); 809 | } 810 | 811 | module.exports = isObject; 812 | 813 | 814 | /***/ }), 815 | /* 7 */ 816 | /***/ (function(module, exports) { 817 | 818 | /** 819 | * Checks if `value` is object-like. A value is object-like if it's not `null` 820 | * and has a `typeof` result of "object". 821 | * 822 | * @static 823 | * @memberOf _ 824 | * @since 4.0.0 825 | * @category Lang 826 | * @param {*} value The value to check. 827 | * @returns {boolean} Returns `true` if `value` is object-like, else `false`. 828 | * @example 829 | * 830 | * _.isObjectLike({}); 831 | * // => true 832 | * 833 | * _.isObjectLike([1, 2, 3]); 834 | * // => true 835 | * 836 | * _.isObjectLike(_.noop); 837 | * // => false 838 | * 839 | * _.isObjectLike(null); 840 | * // => false 841 | */ 842 | function isObjectLike(value) { 843 | return value != null && typeof value == 'object'; 844 | } 845 | 846 | module.exports = isObjectLike; 847 | 848 | 849 | /***/ }), 850 | /* 8 */ 851 | /***/ (function(module, exports) { 852 | 853 | "use strict"; 854 | 855 | exports.__esModule = true; 856 | /** 857 | * Constants for token types 858 | */ 859 | exports["default"] = { 860 | WHITESPACE: "whitespace", 861 | WORD: "word", 862 | STRING: "string", 863 | RESERVED: "reserved", 864 | RESERVED_TOPLEVEL: "reserved-toplevel", 865 | RESERVED_NEWLINE: "reserved-newline", 866 | OPERATOR: "operator", 867 | OPEN_PAREN: "open-paren", 868 | CLOSE_PAREN: "close-paren", 869 | LINE_COMMENT: "line-comment", 870 | BLOCK_COMMENT: "block-comment", 871 | NUMBER: "number", 872 | PLACEHOLDER: "placeholder" 873 | }; 874 | module.exports = exports["default"]; 875 | 876 | /***/ }), 877 | /* 9 */ 878 | /***/ (function(module, exports, __webpack_require__) { 879 | 880 | var root = __webpack_require__(1); 881 | 882 | /** Built-in value references. */ 883 | var Symbol = root.Symbol; 884 | 885 | module.exports = Symbol; 886 | 887 | 888 | /***/ }), 889 | /* 10 */ 890 | /***/ (function(module, exports, __webpack_require__) { 891 | 892 | var baseToString = __webpack_require__(11); 893 | 894 | /** 895 | * Converts `value` to a string. An empty string is returned for `null` 896 | * and `undefined` values. The sign of `-0` is preserved. 897 | * 898 | * @static 899 | * @memberOf _ 900 | * @since 4.0.0 901 | * @category Lang 902 | * @param {*} value The value to convert. 903 | * @returns {string} Returns the converted string. 904 | * @example 905 | * 906 | * _.toString(null); 907 | * // => '' 908 | * 909 | * _.toString(-0); 910 | * // => '-0' 911 | * 912 | * _.toString([1, 2, 3]); 913 | * // => '1,2,3' 914 | */ 915 | function toString(value) { 916 | return value == null ? '' : baseToString(value); 917 | } 918 | 919 | module.exports = toString; 920 | 921 | 922 | /***/ }), 923 | /* 11 */ 924 | /***/ (function(module, exports, __webpack_require__) { 925 | 926 | var Symbol = __webpack_require__(9), 927 | arrayMap = __webpack_require__(33), 928 | isArray = __webpack_require__(15), 929 | isSymbol = __webpack_require__(19); 930 | 931 | /** Used as references for various `Number` constants. */ 932 | var INFINITY = 1 / 0; 933 | 934 | /** Used to convert symbols to primitives and strings. */ 935 | var symbolProto = Symbol ? Symbol.prototype : undefined, 936 | symbolToString = symbolProto ? symbolProto.toString : undefined; 937 | 938 | /** 939 | * The base implementation of `_.toString` which doesn't convert nullish 940 | * values to empty strings. 941 | * 942 | * @private 943 | * @param {*} value The value to process. 944 | * @returns {string} Returns the string. 945 | */ 946 | function baseToString(value) { 947 | // Exit early for strings to avoid a performance hit in some environments. 948 | if (typeof value == 'string') { 949 | return value; 950 | } 951 | if (isArray(value)) { 952 | // Recursively convert values (susceptible to call stack limits). 953 | return arrayMap(value, baseToString) + ''; 954 | } 955 | if (isSymbol(value)) { 956 | return symbolToString ? symbolToString.call(value) : ''; 957 | } 958 | var result = (value + ''); 959 | return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; 960 | } 961 | 962 | module.exports = baseToString; 963 | 964 | 965 | /***/ }), 966 | /* 12 */ 967 | /***/ (function(module, exports) { 968 | 969 | /* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */ 970 | var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; 971 | 972 | module.exports = freeGlobal; 973 | 974 | /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) 975 | 976 | /***/ }), 977 | /* 13 */ 978 | /***/ (function(module, exports) { 979 | 980 | /** Used for built-in method references. */ 981 | var objectProto = Object.prototype; 982 | 983 | /** 984 | * Checks if `value` is likely a prototype object. 985 | * 986 | * @private 987 | * @param {*} value The value to check. 988 | * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. 989 | */ 990 | function isPrototype(value) { 991 | var Ctor = value && value.constructor, 992 | proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; 993 | 994 | return value === proto; 995 | } 996 | 997 | module.exports = isPrototype; 998 | 999 | 1000 | /***/ }), 1001 | /* 14 */ 1002 | /***/ (function(module, exports) { 1003 | 1004 | /** Used for built-in method references. */ 1005 | var funcProto = Function.prototype; 1006 | 1007 | /** Used to resolve the decompiled source of functions. */ 1008 | var funcToString = funcProto.toString; 1009 | 1010 | /** 1011 | * Converts `func` to its source code. 1012 | * 1013 | * @private 1014 | * @param {Function} func The function to convert. 1015 | * @returns {string} Returns the source code. 1016 | */ 1017 | function toSource(func) { 1018 | if (func != null) { 1019 | try { 1020 | return funcToString.call(func); 1021 | } catch (e) {} 1022 | try { 1023 | return (func + ''); 1024 | } catch (e) {} 1025 | } 1026 | return ''; 1027 | } 1028 | 1029 | module.exports = toSource; 1030 | 1031 | 1032 | /***/ }), 1033 | /* 15 */ 1034 | /***/ (function(module, exports) { 1035 | 1036 | /** 1037 | * Checks if `value` is classified as an `Array` object. 1038 | * 1039 | * @static 1040 | * @memberOf _ 1041 | * @since 0.1.0 1042 | * @category Lang 1043 | * @param {*} value The value to check. 1044 | * @returns {boolean} Returns `true` if `value` is an array, else `false`. 1045 | * @example 1046 | * 1047 | * _.isArray([1, 2, 3]); 1048 | * // => true 1049 | * 1050 | * _.isArray(document.body.children); 1051 | * // => false 1052 | * 1053 | * _.isArray('abc'); 1054 | * // => false 1055 | * 1056 | * _.isArray(_.noop); 1057 | * // => false 1058 | */ 1059 | var isArray = Array.isArray; 1060 | 1061 | module.exports = isArray; 1062 | 1063 | 1064 | /***/ }), 1065 | /* 16 */ 1066 | /***/ (function(module, exports, __webpack_require__) { 1067 | 1068 | var isFunction = __webpack_require__(17), 1069 | isLength = __webpack_require__(18); 1070 | 1071 | /** 1072 | * Checks if `value` is array-like. A value is considered array-like if it's 1073 | * not a function and has a `value.length` that's an integer greater than or 1074 | * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. 1075 | * 1076 | * @static 1077 | * @memberOf _ 1078 | * @since 4.0.0 1079 | * @category Lang 1080 | * @param {*} value The value to check. 1081 | * @returns {boolean} Returns `true` if `value` is array-like, else `false`. 1082 | * @example 1083 | * 1084 | * _.isArrayLike([1, 2, 3]); 1085 | * // => true 1086 | * 1087 | * _.isArrayLike(document.body.children); 1088 | * // => true 1089 | * 1090 | * _.isArrayLike('abc'); 1091 | * // => true 1092 | * 1093 | * _.isArrayLike(_.noop); 1094 | * // => false 1095 | */ 1096 | function isArrayLike(value) { 1097 | return value != null && isLength(value.length) && !isFunction(value); 1098 | } 1099 | 1100 | module.exports = isArrayLike; 1101 | 1102 | 1103 | /***/ }), 1104 | /* 17 */ 1105 | /***/ (function(module, exports, __webpack_require__) { 1106 | 1107 | var baseGetTag = __webpack_require__(2), 1108 | isObject = __webpack_require__(6); 1109 | 1110 | /** `Object#toString` result references. */ 1111 | var asyncTag = '[object AsyncFunction]', 1112 | funcTag = '[object Function]', 1113 | genTag = '[object GeneratorFunction]', 1114 | proxyTag = '[object Proxy]'; 1115 | 1116 | /** 1117 | * Checks if `value` is classified as a `Function` object. 1118 | * 1119 | * @static 1120 | * @memberOf _ 1121 | * @since 0.1.0 1122 | * @category Lang 1123 | * @param {*} value The value to check. 1124 | * @returns {boolean} Returns `true` if `value` is a function, else `false`. 1125 | * @example 1126 | * 1127 | * _.isFunction(_); 1128 | * // => true 1129 | * 1130 | * _.isFunction(/abc/); 1131 | * // => false 1132 | */ 1133 | function isFunction(value) { 1134 | if (!isObject(value)) { 1135 | return false; 1136 | } 1137 | // The use of `Object#toString` avoids issues with the `typeof` operator 1138 | // in Safari 9 which returns 'object' for typed arrays and other constructors. 1139 | var tag = baseGetTag(value); 1140 | return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; 1141 | } 1142 | 1143 | module.exports = isFunction; 1144 | 1145 | 1146 | /***/ }), 1147 | /* 18 */ 1148 | /***/ (function(module, exports) { 1149 | 1150 | /** Used as references for various `Number` constants. */ 1151 | var MAX_SAFE_INTEGER = 9007199254740991; 1152 | 1153 | /** 1154 | * Checks if `value` is a valid array-like length. 1155 | * 1156 | * **Note:** This method is loosely based on 1157 | * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). 1158 | * 1159 | * @static 1160 | * @memberOf _ 1161 | * @since 4.0.0 1162 | * @category Lang 1163 | * @param {*} value The value to check. 1164 | * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. 1165 | * @example 1166 | * 1167 | * _.isLength(3); 1168 | * // => true 1169 | * 1170 | * _.isLength(Number.MIN_VALUE); 1171 | * // => false 1172 | * 1173 | * _.isLength(Infinity); 1174 | * // => false 1175 | * 1176 | * _.isLength('3'); 1177 | * // => false 1178 | */ 1179 | function isLength(value) { 1180 | return typeof value == 'number' && 1181 | value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; 1182 | } 1183 | 1184 | module.exports = isLength; 1185 | 1186 | 1187 | /***/ }), 1188 | /* 19 */ 1189 | /***/ (function(module, exports, __webpack_require__) { 1190 | 1191 | var baseGetTag = __webpack_require__(2), 1192 | isObjectLike = __webpack_require__(7); 1193 | 1194 | /** `Object#toString` result references. */ 1195 | var symbolTag = '[object Symbol]'; 1196 | 1197 | /** 1198 | * Checks if `value` is classified as a `Symbol` primitive or object. 1199 | * 1200 | * @static 1201 | * @memberOf _ 1202 | * @since 4.0.0 1203 | * @category Lang 1204 | * @param {*} value The value to check. 1205 | * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. 1206 | * @example 1207 | * 1208 | * _.isSymbol(Symbol.iterator); 1209 | * // => true 1210 | * 1211 | * _.isSymbol('abc'); 1212 | * // => false 1213 | */ 1214 | function isSymbol(value) { 1215 | return typeof value == 'symbol' || 1216 | (isObjectLike(value) && baseGetTag(value) == symbolTag); 1217 | } 1218 | 1219 | module.exports = isSymbol; 1220 | 1221 | 1222 | /***/ }), 1223 | /* 20 */ 1224 | /***/ (function(module, exports) { 1225 | 1226 | module.exports = function(module) { 1227 | if(!module.webpackPolyfill) { 1228 | module.deprecate = function() {}; 1229 | module.paths = []; 1230 | // module.parent = undefined by default 1231 | module.children = []; 1232 | module.webpackPolyfill = 1; 1233 | } 1234 | return module; 1235 | } 1236 | 1237 | 1238 | /***/ }), 1239 | /* 21 */ 1240 | /***/ (function(module, exports, __webpack_require__) { 1241 | 1242 | "use strict"; 1243 | 1244 | exports.__esModule = true; 1245 | 1246 | var _repeat = __webpack_require__(69); 1247 | 1248 | var _repeat2 = _interopRequireDefault(_repeat); 1249 | 1250 | var _last = __webpack_require__(68); 1251 | 1252 | var _last2 = _interopRequireDefault(_last); 1253 | 1254 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1255 | 1256 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1257 | 1258 | var INDENT_TYPE_TOP_LEVEL = "top-level"; 1259 | var INDENT_TYPE_BLOCK_LEVEL = "block-level"; 1260 | 1261 | /** 1262 | * Manages indentation levels. 1263 | * 1264 | * There are two types of indentation levels: 1265 | * 1266 | * - BLOCK_LEVEL : increased by open-parenthesis 1267 | * - TOP_LEVEL : increased by RESERVED_TOPLEVEL words 1268 | */ 1269 | 1270 | var Indentation = function () { 1271 | /** 1272 | * @param {String} indent Indent value, default is " " (2 spaces) 1273 | */ 1274 | function Indentation(indent) { 1275 | _classCallCheck(this, Indentation); 1276 | 1277 | this.indent = indent || " "; 1278 | this.indentTypes = []; 1279 | } 1280 | 1281 | /** 1282 | * Returns current indentation string. 1283 | * @return {String} 1284 | */ 1285 | 1286 | 1287 | Indentation.prototype.getIndent = function getIndent() { 1288 | return (0, _repeat2["default"])(this.indent, this.indentTypes.length); 1289 | }; 1290 | 1291 | /** 1292 | * Increases indentation by one top-level indent. 1293 | */ 1294 | 1295 | 1296 | Indentation.prototype.increaseToplevel = function increaseToplevel() { 1297 | this.indentTypes.push(INDENT_TYPE_TOP_LEVEL); 1298 | }; 1299 | 1300 | /** 1301 | * Increases indentation by one block-level indent. 1302 | */ 1303 | 1304 | 1305 | Indentation.prototype.increaseBlockLevel = function increaseBlockLevel() { 1306 | this.indentTypes.push(INDENT_TYPE_BLOCK_LEVEL); 1307 | }; 1308 | 1309 | /** 1310 | * Decreases indentation by one top-level indent. 1311 | * Does nothing when the previous indent is not top-level. 1312 | */ 1313 | 1314 | 1315 | Indentation.prototype.decreaseTopLevel = function decreaseTopLevel() { 1316 | if ((0, _last2["default"])(this.indentTypes) === INDENT_TYPE_TOP_LEVEL) { 1317 | this.indentTypes.pop(); 1318 | } 1319 | }; 1320 | 1321 | /** 1322 | * Decreases indentation by one block-level indent. 1323 | * If there are top-level indents within the block-level indent, 1324 | * throws away these as well. 1325 | */ 1326 | 1327 | 1328 | Indentation.prototype.decreaseBlockLevel = function decreaseBlockLevel() { 1329 | while (this.indentTypes.length > 0) { 1330 | var type = this.indentTypes.pop(); 1331 | if (type !== INDENT_TYPE_TOP_LEVEL) { 1332 | break; 1333 | } 1334 | } 1335 | }; 1336 | 1337 | return Indentation; 1338 | }(); 1339 | 1340 | exports["default"] = Indentation; 1341 | module.exports = exports["default"]; 1342 | 1343 | /***/ }), 1344 | /* 22 */ 1345 | /***/ (function(module, exports, __webpack_require__) { 1346 | 1347 | "use strict"; 1348 | 1349 | exports.__esModule = true; 1350 | 1351 | var _tokenTypes = __webpack_require__(8); 1352 | 1353 | var _tokenTypes2 = _interopRequireDefault(_tokenTypes); 1354 | 1355 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1356 | 1357 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1358 | 1359 | var INLINE_MAX_LENGTH = 50; 1360 | 1361 | /** 1362 | * Bookkeeper for inline blocks. 1363 | * 1364 | * Inline blocks are parenthized expressions that are shorter than INLINE_MAX_LENGTH. 1365 | * These blocks are formatted on a single line, unlike longer parenthized 1366 | * expressions where open-parenthesis causes newline and increase of indentation. 1367 | */ 1368 | 1369 | var InlineBlock = function () { 1370 | function InlineBlock() { 1371 | _classCallCheck(this, InlineBlock); 1372 | 1373 | this.level = 0; 1374 | } 1375 | 1376 | /** 1377 | * Begins inline block when lookahead through upcoming tokens determines 1378 | * that the block would be smaller than INLINE_MAX_LENGTH. 1379 | * @param {Object[]} tokens Array of all tokens 1380 | * @param {Number} index Current token position 1381 | */ 1382 | 1383 | 1384 | InlineBlock.prototype.beginIfPossible = function beginIfPossible(tokens, index) { 1385 | if (this.level === 0 && this.isInlineBlock(tokens, index)) { 1386 | this.level = 1; 1387 | } else if (this.level > 0) { 1388 | this.level++; 1389 | } else { 1390 | this.level = 0; 1391 | } 1392 | }; 1393 | 1394 | /** 1395 | * Finishes current inline block. 1396 | * There might be several nested ones. 1397 | */ 1398 | 1399 | 1400 | InlineBlock.prototype.end = function end() { 1401 | this.level--; 1402 | }; 1403 | 1404 | /** 1405 | * True when inside an inline block 1406 | * @return {Boolean} 1407 | */ 1408 | 1409 | 1410 | InlineBlock.prototype.isActive = function isActive() { 1411 | return this.level > 0; 1412 | }; 1413 | 1414 | // Check if this should be an inline parentheses block 1415 | // Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2) 1416 | 1417 | 1418 | InlineBlock.prototype.isInlineBlock = function isInlineBlock(tokens, index) { 1419 | var length = 0; 1420 | var level = 0; 1421 | 1422 | for (var i = index; i < tokens.length; i++) { 1423 | var token = tokens[i]; 1424 | length += token.value.length; 1425 | 1426 | // Overran max length 1427 | if (length > INLINE_MAX_LENGTH) { 1428 | return false; 1429 | } 1430 | 1431 | if (token.type === _tokenTypes2["default"].OPEN_PAREN) { 1432 | level++; 1433 | } else if (token.type === _tokenTypes2["default"].CLOSE_PAREN) { 1434 | level--; 1435 | if (level === 0) { 1436 | return true; 1437 | } 1438 | } 1439 | 1440 | if (this.isForbiddenToken(token)) { 1441 | return false; 1442 | } 1443 | } 1444 | return false; 1445 | }; 1446 | 1447 | // Reserved words that cause newlines, comments and semicolons 1448 | // are not allowed inside inline parentheses block 1449 | 1450 | 1451 | InlineBlock.prototype.isForbiddenToken = function isForbiddenToken(_ref) { 1452 | var type = _ref.type, 1453 | value = _ref.value; 1454 | 1455 | return type === _tokenTypes2["default"].RESERVED_TOPLEVEL || type === _tokenTypes2["default"].RESERVED_NEWLINE || type === _tokenTypes2["default"].COMMENT || type === _tokenTypes2["default"].BLOCK_COMMENT || value === ";"; 1456 | }; 1457 | 1458 | return InlineBlock; 1459 | }(); 1460 | 1461 | exports["default"] = InlineBlock; 1462 | module.exports = exports["default"]; 1463 | 1464 | /***/ }), 1465 | /* 23 */ 1466 | /***/ (function(module, exports) { 1467 | 1468 | "use strict"; 1469 | 1470 | exports.__esModule = true; 1471 | 1472 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1473 | 1474 | /** 1475 | * Handles placeholder replacement with given params. 1476 | */ 1477 | var Params = function () { 1478 | /** 1479 | * @param {Object} params 1480 | */ 1481 | function Params(params) { 1482 | _classCallCheck(this, Params); 1483 | 1484 | this.params = params; 1485 | this.index = 0; 1486 | } 1487 | 1488 | /** 1489 | * Returns param value that matches given placeholder with param key. 1490 | * @param {Object} token 1491 | * @param {String} token.key Placeholder key 1492 | * @param {String} token.value Placeholder value 1493 | * @return {String} param or token.value when params are missing 1494 | */ 1495 | 1496 | 1497 | Params.prototype.get = function get(_ref) { 1498 | var key = _ref.key, 1499 | value = _ref.value; 1500 | 1501 | if (!this.params) { 1502 | return value; 1503 | } 1504 | if (key) { 1505 | return this.params[key]; 1506 | } 1507 | return this.params[this.index++]; 1508 | }; 1509 | 1510 | return Params; 1511 | }(); 1512 | 1513 | exports["default"] = Params; 1514 | module.exports = exports["default"]; 1515 | 1516 | /***/ }), 1517 | /* 24 */ 1518 | /***/ (function(module, exports, __webpack_require__) { 1519 | 1520 | "use strict"; 1521 | 1522 | exports.__esModule = true; 1523 | 1524 | var _Formatter = __webpack_require__(4); 1525 | 1526 | var _Formatter2 = _interopRequireDefault(_Formatter); 1527 | 1528 | var _Tokenizer = __webpack_require__(5); 1529 | 1530 | var _Tokenizer2 = _interopRequireDefault(_Tokenizer); 1531 | 1532 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1533 | 1534 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1535 | 1536 | var reservedWords = ["ABS", "ACTIVATE", "ALIAS", "ALL", "ALLOCATE", "ALLOW", "ALTER", "ANY", "ARE", "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSOCIATE", "ASUTIME", "ASYMMETRIC", "AT", "ATOMIC", "ATTRIBUTES", "AUDIT", "AUTHORIZATION", "AUX", "AUXILIARY", "AVG", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", "BLOB", "BOOLEAN", "BOTH", "BUFFERPOOL", "BY", "CACHE", "CALL", "CALLED", "CAPTURE", "CARDINALITY", "CASCADED", "CASE", "CAST", "CCSID", "CEIL", "CEILING", "CHAR", "CHARACTER", "CHARACTER_LENGTH", "CHAR_LENGTH", "CHECK", "CLOB", "CLONE", "CLOSE", "CLUSTER", "COALESCE", "COLLATE", "COLLECT", "COLLECTION", "COLLID", "COLUMN", "COMMENT", "COMMIT", "CONCAT", "CONDITION", "CONNECT", "CONNECTION", "CONSTRAINT", "CONTAINS", "CONTINUE", "CONVERT", "CORR", "CORRESPONDING", "COUNT", "COUNT_BIG", "COVAR_POP", "COVAR_SAMP", "CREATE", "CROSS", "CUBE", "CUME_DIST", "CURRENT", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_LC_CTYPE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_SCHEMA", "CURRENT_SERVER", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_TIMEZONE", "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CYCLE", "DATA", "DATABASE", "DATAPARTITIONNAME", "DATAPARTITIONNUM", "DATE", "DAY", "DAYS", "DB2GENERAL", "DB2GENRL", "DB2SQL", "DBINFO", "DBPARTITIONNAME", "DBPARTITIONNUM", "DEALLOCATE", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFAULTS", "DEFINITION", "DELETE", "DENSERANK", "DENSE_RANK", "DEREF", "DESCRIBE", "DESCRIPTOR", "DETERMINISTIC", "DIAGNOSTICS", "DISABLE", "DISALLOW", "DISCONNECT", "DISTINCT", "DO", "DOCUMENT", "DOUBLE", "DROP", "DSSIZE", "DYNAMIC", "EACH", "EDITPROC", "ELEMENT", "ELSE", "ELSEIF", "ENABLE", "ENCODING", "ENCRYPTION", "END", "END-EXEC", "ENDING", "ERASE", "ESCAPE", "EVERY", "EXCEPTION", "EXCLUDING", "EXCLUSIVE", "EXEC", "EXECUTE", "EXISTS", "EXIT", "EXP", "EXPLAIN", "EXTENDED", "EXTERNAL", "EXTRACT", "FALSE", "FENCED", "FETCH", "FIELDPROC", "FILE", "FILTER", "FINAL", "FIRST", "FLOAT", "FLOOR", "FOR", "FOREIGN", "FREE", "FULL", "FUNCTION", "FUSION", "GENERAL", "GENERATED", "GET", "GLOBAL", "GOTO", "GRANT", "GRAPHIC", "GROUP", "GROUPING", "HANDLER", "HASH", "HASHED_VALUE", "HINT", "HOLD", "HOUR", "HOURS", "IDENTITY", "IF", "IMMEDIATE", "IN", "INCLUDING", "INCLUSIVE", "INCREMENT", "INDEX", "INDICATOR", "INDICATORS", "INF", "INFINITY", "INHERIT", "INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INTEGER", "INTEGRITY", "INTERSECTION", "INTERVAL", "INTO", "IS", "ISOBID", "ISOLATION", "ITERATE", "JAR", "JAVA", "KEEP", "KEY", "LABEL", "LANGUAGE", "LARGE", "LATERAL", "LC_CTYPE", "LEADING", "LEAVE", "LEFT", "LIKE", "LINKTYPE", "LN", "LOCAL", "LOCALDATE", "LOCALE", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCATORS", "LOCK", "LOCKMAX", "LOCKSIZE", "LONG", "LOOP", "LOWER", "MAINTAINED", "MATCH", "MATERIALIZED", "MAX", "MAXVALUE", "MEMBER", "MERGE", "METHOD", "MICROSECOND", "MICROSECONDS", "MIN", "MINUTE", "MINUTES", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODULE", "MONTH", "MONTHS", "MULTISET", "NAN", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEW_TABLE", "NEXTVAL", "NO", "NOCACHE", "NOCYCLE", "NODENAME", "NODENUMBER", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NORMALIZE", "NORMALIZED", "NOT", "NULL", "NULLIF", "NULLS", "NUMERIC", "NUMPARTS", "OBID", "OCTET_LENGTH", "OF", "OFFSET", "OLD", "OLD_TABLE", "ON", "ONLY", "OPEN", "OPTIMIZATION", "OPTIMIZE", "OPTION", "ORDER", "OUT", "OUTER", "OVER", "OVERLAPS", "OVERLAY", "OVERRIDING", "PACKAGE", "PADDED", "PAGESIZE", "PARAMETER", "PART", "PARTITION", "PARTITIONED", "PARTITIONING", "PARTITIONS", "PASSWORD", "PATH", "PERCENTILE_CONT", "PERCENTILE_DISC", "PERCENT_RANK", "PIECESIZE", "PLAN", "POSITION", "POWER", "PRECISION", "PREPARE", "PREVVAL", "PRIMARY", "PRIQTY", "PRIVILEGES", "PROCEDURE", "PROGRAM", "PSID", "PUBLIC", "QUERY", "QUERYNO", "RANGE", "RANK", "READ", "READS", "REAL", "RECOVERY", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", "RELEASE", "RENAME", "REPEAT", "RESET", "RESIGNAL", "RESTART", "RESTRICT", "RESULT", "RESULT_SET_LOCATOR", "RETURN", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUND_CEILING", "ROUND_DOWN", "ROUND_FLOOR", "ROUND_HALF_DOWN", "ROUND_HALF_EVEN", "ROUND_HALF_UP", "ROUND_UP", "ROUTINE", "ROW", "ROWNUMBER", "ROWS", "ROWSET", "ROW_NUMBER", "RRN", "RUN", "SAVEPOINT", "SCHEMA", "SCOPE", "SCRATCHPAD", "SCROLL", "SEARCH", "SECOND", "SECONDS", "SECQTY", "SECURITY", "SENSITIVE", "SEQUENCE", "SESSION", "SESSION_USER", "SIGNAL", "SIMILAR", "SIMPLE", "SMALLINT", "SNAN", "SOME", "SOURCE", "SPECIFIC", "SPECIFICTYPE", "SQL", "SQLEXCEPTION", "SQLID", "SQLSTATE", "SQLWARNING", "SQRT", "STACKED", "STANDARD", "START", "STARTING", "STATEMENT", "STATIC", "STATMENT", "STAY", "STDDEV_POP", "STDDEV_SAMP", "STOGROUP", "STORES", "STYLE", "SUBMULTISET", "SUBSTRING", "SUM", "SUMMARY", "SYMMETRIC", "SYNONYM", "SYSFUN", "SYSIBM", "SYSPROC", "SYSTEM", "SYSTEM_USER", "TABLE", "TABLESAMPLE", "TABLESPACE", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", "TRAILING", "TRANSACTION", "TRANSLATE", "TRANSLATION", "TREAT", "TRIGGER", "TRIM", "TRUE", "TRUNCATE", "TYPE", "UESCAPE", "UNDO", "UNIQUE", "UNKNOWN", "UNNEST", "UNTIL", "UPPER", "USAGE", "USER", "USING", "VALIDPROC", "VALUE", "VARCHAR", "VARIABLE", "VARIANT", "VARYING", "VAR_POP", "VAR_SAMP", "VCAT", "VERSION", "VIEW", "VOLATILE", "VOLUMES", "WHEN", "WHENEVER", "WHILE", "WIDTH_BUCKET", "WINDOW", "WITH", "WITHIN", "WITHOUT", "WLM", "WRITE", "XMLELEMENT", "XMLEXISTS", "XMLNAMESPACES", "YEAR", "YEARS"]; 1537 | 1538 | var reservedToplevelWords = ["ADD", "AFTER", "ALTER COLUMN", "ALTER TABLE", "DELETE FROM", "EXCEPT", "FETCH FIRST", "FROM", "GROUP BY", "GO", "HAVING", "INSERT INTO", "INTERSECT", "LIMIT", "ORDER BY", "SELECT", "SET CURRENT SCHEMA", "SET SCHEMA", "SET", "UNION ALL", "UPDATE", "VALUES", "WHERE"]; 1539 | 1540 | var reservedNewlineWords = ["AND", "CROSS JOIN", "INNER JOIN", "JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "OR", "OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN"]; 1541 | 1542 | var tokenizer = void 0; 1543 | 1544 | var Db2Formatter = function () { 1545 | /** 1546 | * @param {Object} cfg Different set of configurations 1547 | */ 1548 | function Db2Formatter(cfg) { 1549 | _classCallCheck(this, Db2Formatter); 1550 | 1551 | this.cfg = cfg; 1552 | } 1553 | 1554 | /** 1555 | * Formats DB2 query to make it easier to read 1556 | * 1557 | * @param {String} query The DB2 query string 1558 | * @return {String} formatted string 1559 | */ 1560 | 1561 | 1562 | Db2Formatter.prototype.format = function format(query) { 1563 | if (!tokenizer) { 1564 | tokenizer = new _Tokenizer2["default"]({ 1565 | reservedWords: reservedWords, 1566 | reservedToplevelWords: reservedToplevelWords, 1567 | reservedNewlineWords: reservedNewlineWords, 1568 | stringTypes: ["\"\"", "''", "``", "[]"], 1569 | openParens: ["("], 1570 | closeParens: [")"], 1571 | indexedPlaceholderTypes: ["?"], 1572 | namedPlaceholderTypes: [":"], 1573 | lineCommentTypes: ["--"], 1574 | specialWordChars: ["#", "@"] 1575 | }); 1576 | } 1577 | return new _Formatter2["default"](this.cfg, tokenizer).format(query); 1578 | }; 1579 | 1580 | return Db2Formatter; 1581 | }(); 1582 | 1583 | exports["default"] = Db2Formatter; 1584 | module.exports = exports["default"]; 1585 | 1586 | /***/ }), 1587 | /* 25 */ 1588 | /***/ (function(module, exports, __webpack_require__) { 1589 | 1590 | "use strict"; 1591 | 1592 | exports.__esModule = true; 1593 | 1594 | var _Formatter = __webpack_require__(4); 1595 | 1596 | var _Formatter2 = _interopRequireDefault(_Formatter); 1597 | 1598 | var _Tokenizer = __webpack_require__(5); 1599 | 1600 | var _Tokenizer2 = _interopRequireDefault(_Tokenizer); 1601 | 1602 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1603 | 1604 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1605 | 1606 | var reservedWords = ["ALL", "ALTER", "ANALYZE", "AND", "ANY", "ARRAY", "AS", "ASC", "BEGIN", "BETWEEN", "BINARY", "BOOLEAN", "BREAK", "BUCKET", "BUILD", "BY", "CALL", "CASE", "CAST", "CLUSTER", "COLLATE", "COLLECTION", "COMMIT", "CONNECT", "CONTINUE", "CORRELATE", "COVER", "CREATE", "DATABASE", "DATASET", "DATASTORE", "DECLARE", "DECREMENT", "DELETE", "DERIVED", "DESC", "DESCRIBE", "DISTINCT", "DO", "DROP", "EACH", "ELEMENT", "ELSE", "END", "EVERY", "EXCEPT", "EXCLUDE", "EXECUTE", "EXISTS", "EXPLAIN", "FALSE", "FETCH", "FIRST", "FLATTEN", "FOR", "FORCE", "FROM", "FUNCTION", "GRANT", "GROUP", "GSI", "HAVING", "IF", "IGNORE", "ILIKE", "IN", "INCLUDE", "INCREMENT", "INDEX", "INFER", "INLINE", "INNER", "INSERT", "INTERSECT", "INTO", "IS", "JOIN", "KEY", "KEYS", "KEYSPACE", "KNOWN", "LAST", "LEFT", "LET", "LETTING", "LIKE", "LIMIT", "LSM", "MAP", "MAPPING", "MATCHED", "MATERIALIZED", "MERGE", "MINUS", "MISSING", "NAMESPACE", "NEST", "NOT", "NULL", "NUMBER", "OBJECT", "OFFSET", "ON", "OPTION", "OR", "ORDER", "OUTER", "OVER", "PARSE", "PARTITION", "PASSWORD", "PATH", "POOL", "PREPARE", "PRIMARY", "PRIVATE", "PRIVILEGE", "PROCEDURE", "PUBLIC", "RAW", "REALM", "REDUCE", "RENAME", "RETURN", "RETURNING", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "SATISFIES", "SCHEMA", "SELECT", "SELF", "SEMI", "SET", "SHOW", "SOME", "START", "STATISTICS", "STRING", "SYSTEM", "THEN", "TO", "TRANSACTION", "TRIGGER", "TRUE", "TRUNCATE", "UNDER", "UNION", "UNIQUE", "UNKNOWN", "UNNEST", "UNSET", "UPDATE", "UPSERT", "USE", "USER", "USING", "VALIDATE", "VALUE", "VALUED", "VALUES", "VIA", "VIEW", "WHEN", "WHERE", "WHILE", "WITH", "WITHIN", "WORK", "XOR"]; 1607 | 1608 | var reservedToplevelWords = ["DELETE FROM", "EXCEPT ALL", "EXCEPT", "EXPLAIN DELETE FROM", "EXPLAIN UPDATE", "EXPLAIN UPSERT", "FROM", "GROUP BY", "HAVING", "INFER", "INSERT INTO", "INTERSECT ALL", "INTERSECT", "LET", "LIMIT", "MERGE", "NEST", "ORDER BY", "PREPARE", "SELECT", "SET CURRENT SCHEMA", "SET SCHEMA", "SET", "UNION ALL", "UNION", "UNNEST", "UPDATE", "UPSERT", "USE KEYS", "VALUES", "WHERE"]; 1609 | 1610 | var reservedNewlineWords = ["AND", "INNER JOIN", "JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "OR", "OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN", "XOR"]; 1611 | 1612 | var tokenizer = void 0; 1613 | 1614 | var N1qlFormatter = function () { 1615 | /** 1616 | * @param {Object} cfg Different set of configurations 1617 | */ 1618 | function N1qlFormatter(cfg) { 1619 | _classCallCheck(this, N1qlFormatter); 1620 | 1621 | this.cfg = cfg; 1622 | } 1623 | 1624 | /** 1625 | * Format the whitespace in a N1QL string to make it easier to read 1626 | * 1627 | * @param {String} query The N1QL string 1628 | * @return {String} formatted string 1629 | */ 1630 | 1631 | 1632 | N1qlFormatter.prototype.format = function format(query) { 1633 | if (!tokenizer) { 1634 | tokenizer = new _Tokenizer2["default"]({ 1635 | reservedWords: reservedWords, 1636 | reservedToplevelWords: reservedToplevelWords, 1637 | reservedNewlineWords: reservedNewlineWords, 1638 | stringTypes: ["\"\"", "''", "``"], 1639 | openParens: ["(", "[", "{"], 1640 | closeParens: [")", "]", "}"], 1641 | namedPlaceholderTypes: ["$"], 1642 | lineCommentTypes: ["#", "--"] 1643 | }); 1644 | } 1645 | return new _Formatter2["default"](this.cfg, tokenizer).format(query); 1646 | }; 1647 | 1648 | return N1qlFormatter; 1649 | }(); 1650 | 1651 | exports["default"] = N1qlFormatter; 1652 | module.exports = exports["default"]; 1653 | 1654 | /***/ }), 1655 | /* 26 */ 1656 | /***/ (function(module, exports, __webpack_require__) { 1657 | 1658 | "use strict"; 1659 | 1660 | exports.__esModule = true; 1661 | 1662 | var _Formatter = __webpack_require__(4); 1663 | 1664 | var _Formatter2 = _interopRequireDefault(_Formatter); 1665 | 1666 | var _Tokenizer = __webpack_require__(5); 1667 | 1668 | var _Tokenizer2 = _interopRequireDefault(_Tokenizer); 1669 | 1670 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1671 | 1672 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1673 | 1674 | var reservedWords = ["A", "ACCESSIBLE", "AGENT", "AGGREGATE", "ALL", "ALTER", "ANY", "ARRAY", "AS", "ASC", "AT", "ATTRIBUTE", "AUTHID", "AVG", "BETWEEN", "BFILE_BASE", "BINARY_INTEGER", "BINARY", "BLOB_BASE", "BLOCK", "BODY", "BOOLEAN", "BOTH", "BOUND", "BULK", "BY", "BYTE", "C", "CALL", "CALLING", "CASCADE", "CASE", "CHAR_BASE", "CHAR", "CHARACTER", "CHARSET", "CHARSETFORM", "CHARSETID", "CHECK", "CLOB_BASE", "CLONE", "CLOSE", "CLUSTER", "CLUSTERS", "COALESCE", "COLAUTH", "COLLECT", "COLUMNS", "COMMENT", "COMMIT", "COMMITTED", "COMPILED", "COMPRESS", "CONNECT", "CONSTANT", "CONSTRUCTOR", "CONTEXT", "CONTINUE", "CONVERT", "COUNT", "CRASH", "CREATE", "CREDENTIAL", "CURRENT", "CURRVAL", "CURSOR", "CUSTOMDATUM", "DANGLING", "DATA", "DATE_BASE", "DATE", "DAY", "DECIMAL", "DEFAULT", "DEFINE", "DELETE", "DESC", "DETERMINISTIC", "DIRECTORY", "DISTINCT", "DO", "DOUBLE", "DROP", "DURATION", "ELEMENT", "ELSIF", "EMPTY", "ESCAPE", "EXCEPTIONS", "EXCLUSIVE", "EXECUTE", "EXISTS", "EXIT", "EXTENDS", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FIXED", "FLOAT", "FOR", "FORALL", "FORCE", "FROM", "FUNCTION", "GENERAL", "GOTO", "GRANT", "GROUP", "HASH", "HEAP", "HIDDEN", "HOUR", "IDENTIFIED", "IF", "IMMEDIATE", "IN", "INCLUDING", "INDEX", "INDEXES", "INDICATOR", "INDICES", "INFINITE", "INSTANTIABLE", "INT", "INTEGER", "INTERFACE", "INTERVAL", "INTO", "INVALIDATE", "IS", "ISOLATION", "JAVA", "LANGUAGE", "LARGE", "LEADING", "LENGTH", "LEVEL", "LIBRARY", "LIKE", "LIKE2", "LIKE4", "LIKEC", "LIMITED", "LOCAL", "LOCK", "LONG", "MAP", "MAX", "MAXLEN", "MEMBER", "MERGE", "MIN", "MINUS", "MINUTE", "MLSLABEL", "MOD", "MODE", "MONTH", "MULTISET", "NAME", "NAN", "NATIONAL", "NATIVE", "NATURAL", "NATURALN", "NCHAR", "NEW", "NEXTVAL", "NOCOMPRESS", "NOCOPY", "NOT", "NOWAIT", "NULL", "NULLIF", "NUMBER_BASE", "NUMBER", "OBJECT", "OCICOLL", "OCIDATE", "OCIDATETIME", "OCIDURATION", "OCIINTERVAL", "OCILOBLOCATOR", "OCINUMBER", "OCIRAW", "OCIREF", "OCIREFCURSOR", "OCIROWID", "OCISTRING", "OCITYPE", "OF", "OLD", "ON", "ONLY", "OPAQUE", "OPEN", "OPERATOR", "OPTION", "ORACLE", "ORADATA", "ORDER", "ORGANIZATION", "ORLANY", "ORLVARY", "OTHERS", "OUT", "OVERLAPS", "OVERRIDING", "PACKAGE", "PARALLEL_ENABLE", "PARAMETER", "PARAMETERS", "PARENT", "PARTITION", "PASCAL", "PCTFREE", "PIPE", "PIPELINED", "PLS_INTEGER", "PLUGGABLE", "POSITIVE", "POSITIVEN", "PRAGMA", "PRECISION", "PRIOR", "PRIVATE", "PROCEDURE", "PUBLIC", "RAISE", "RANGE", "RAW", "READ", "REAL", "RECORD", "REF", "REFERENCE", "RELEASE", "RELIES_ON", "REM", "REMAINDER", "RENAME", "RESOURCE", "RESULT_CACHE", "RESULT", "RETURN", "RETURNING", "REVERSE", "REVOKE", "ROLLBACK", "ROW", "ROWID", "ROWNUM", "ROWTYPE", "SAMPLE", "SAVE", "SAVEPOINT", "SB1", "SB2", "SB4", "SECOND", "SEGMENT", "SELF", "SEPARATE", "SEQUENCE", "SERIALIZABLE", "SHARE", "SHORT", "SIZE_T", "SIZE", "SMALLINT", "SOME", "SPACE", "SPARSE", "SQL", "SQLCODE", "SQLDATA", "SQLERRM", "SQLNAME", "SQLSTATE", "STANDARD", "START", "STATIC", "STDDEV", "STORED", "STRING", "STRUCT", "STYLE", "SUBMULTISET", "SUBPARTITION", "SUBSTITUTABLE", "SUBTYPE", "SUCCESSFUL", "SUM", "SYNONYM", "SYSDATE", "TABAUTH", "TABLE", "TDO", "THE", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_ABBR", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TIMEZONE_REGION", "TO", "TRAILING", "TRANSACTION", "TRANSACTIONAL", "TRIGGER", "TRUE", "TRUSTED", "TYPE", "UB1", "UB2", "UB4", "UID", "UNDER", "UNIQUE", "UNPLUG", "UNSIGNED", "UNTRUSTED", "USE", "USER", "USING", "VALIDATE", "VALIST", "VALUE", "VARCHAR", "VARCHAR2", "VARIABLE", "VARIANCE", "VARRAY", "VARYING", "VIEW", "VIEWS", "VOID", "WHENEVER", "WHILE", "WITH", "WORK", "WRAPPED", "WRITE", "YEAR", "ZONE"]; 1675 | 1676 | var reservedToplevelWords = ["ADD", "ALTER COLUMN", "ALTER TABLE", "BEGIN", "CONNECT BY", "DECLARE", "DELETE FROM", "DELETE", "END", "EXCEPT", "EXCEPTION", "FETCH FIRST", "FROM", "GROUP BY", "HAVING", "INSERT INTO", "INSERT", "INTERSECT", "LIMIT", "LOOP", "MODIFY", "ORDER BY", "SELECT", "SET CURRENT SCHEMA", "SET SCHEMA", "SET", "START WITH", "UNION ALL", "UNION", "UPDATE", "VALUES", "WHERE"]; 1677 | 1678 | var reservedNewlineWords = ["AND", "CROSS APPLY", "CROSS JOIN", "ELSE", "END", "INNER JOIN", "JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "OR", "OUTER APPLY", "OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN", "WHEN", "XOR"]; 1679 | 1680 | var tokenizer = void 0; 1681 | 1682 | var PlSqlFormatter = function () { 1683 | /** 1684 | * @param {Object} cfg Different set of configurations 1685 | */ 1686 | function PlSqlFormatter(cfg) { 1687 | _classCallCheck(this, PlSqlFormatter); 1688 | 1689 | this.cfg = cfg; 1690 | } 1691 | 1692 | /** 1693 | * Format the whitespace in a PL/SQL string to make it easier to read 1694 | * 1695 | * @param {String} query The PL/SQL string 1696 | * @return {String} formatted string 1697 | */ 1698 | 1699 | 1700 | PlSqlFormatter.prototype.format = function format(query) { 1701 | if (!tokenizer) { 1702 | tokenizer = new _Tokenizer2["default"]({ 1703 | reservedWords: reservedWords, 1704 | reservedToplevelWords: reservedToplevelWords, 1705 | reservedNewlineWords: reservedNewlineWords, 1706 | stringTypes: ["\"\"", "N''", "''", "``"], 1707 | openParens: ["(", "CASE"], 1708 | closeParens: [")", "END"], 1709 | indexedPlaceholderTypes: ["?"], 1710 | namedPlaceholderTypes: [":"], 1711 | lineCommentTypes: ["--"], 1712 | specialWordChars: ["_", "$", "#", ".", "@"] 1713 | }); 1714 | } 1715 | return new _Formatter2["default"](this.cfg, tokenizer).format(query); 1716 | }; 1717 | 1718 | return PlSqlFormatter; 1719 | }(); 1720 | 1721 | exports["default"] = PlSqlFormatter; 1722 | module.exports = exports["default"]; 1723 | 1724 | /***/ }), 1725 | /* 27 */ 1726 | /***/ (function(module, exports, __webpack_require__) { 1727 | 1728 | "use strict"; 1729 | 1730 | exports.__esModule = true; 1731 | 1732 | var _Formatter = __webpack_require__(4); 1733 | 1734 | var _Formatter2 = _interopRequireDefault(_Formatter); 1735 | 1736 | var _Tokenizer = __webpack_require__(5); 1737 | 1738 | var _Tokenizer2 = _interopRequireDefault(_Tokenizer); 1739 | 1740 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 1741 | 1742 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1743 | 1744 | var reservedWords = ["ACCESSIBLE", "ACTION", "AGAINST", "AGGREGATE", "ALGORITHM", "ALL", "ALTER", "ANALYSE", "ANALYZE", "AS", "ASC", "AUTOCOMMIT", "AUTO_INCREMENT", "BACKUP", "BEGIN", "BETWEEN", "BINLOG", "BOTH", "CASCADE", "CASE", "CHANGE", "CHANGED", "CHARACTER SET", "CHARSET", "CHECK", "CHECKSUM", "COLLATE", "COLLATION", "COLUMN", "COLUMNS", "COMMENT", "COMMIT", "COMMITTED", "COMPRESSED", "CONCURRENT", "CONSTRAINT", "CONTAINS", "CONVERT", "CREATE", "CROSS", "CURRENT_TIMESTAMP", "DATABASE", "DATABASES", "DAY", "DAY_HOUR", "DAY_MINUTE", "DAY_SECOND", "DEFAULT", "DEFINER", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", "DISTINCT", "DISTINCTROW", "DIV", "DO", "DROP", "DUMPFILE", "DUPLICATE", "DYNAMIC", "ELSE", "ENCLOSED", "END", "ENGINE", "ENGINES", "ENGINE_TYPE", "ESCAPE", "ESCAPED", "EVENTS", "EXEC", "EXECUTE", "EXISTS", "EXPLAIN", "EXTENDED", "FAST", "FETCH", "FIELDS", "FILE", "FIRST", "FIXED", "FLUSH", "FOR", "FORCE", "FOREIGN", "FULL", "FULLTEXT", "FUNCTION", "GLOBAL", "GRANT", "GRANTS", "GROUP_CONCAT", "HEAP", "HIGH_PRIORITY", "HOSTS", "HOUR", "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", "IF", "IFNULL", "IGNORE", "IN", "INDEX", "INDEXES", "INFILE", "INSERT", "INSERT_ID", "INSERT_METHOD", "INTERVAL", "INTO", "INVOKER", "IS", "ISOLATION", "KEY", "KEYS", "KILL", "LAST_INSERT_ID", "LEADING", "LEVEL", "LIKE", "LINEAR", "LINES", "LOAD", "LOCAL", "LOCK", "LOCKS", "LOGS", "LOW_PRIORITY", "MARIA", "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HOST", "MASTER_LOG_FILE", "MATCH", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", "MAX_ROWS", "MAX_UPDATES_PER_HOUR", "MAX_USER_CONNECTIONS", "MEDIUM", "MERGE", "MINUTE", "MINUTE_SECOND", "MIN_ROWS", "MODE", "MODIFY", "MONTH", "MRG_MYISAM", "MYISAM", "NAMES", "NATURAL", "NOT", "NOW()", "NULL", "OFFSET", "ON DELETE", "ON UPDATE", "ON", "ONLY", "OPEN", "OPTIMIZE", "OPTION", "OPTIONALLY", "OUTFILE", "PACK_KEYS", "PAGE", "PARTIAL", "PARTITION", "PARTITIONS", "PASSWORD", "PRIMARY", "PRIVILEGES", "PROCEDURE", "PROCESS", "PROCESSLIST", "PURGE", "QUICK", "RAID0", "RAID_CHUNKS", "RAID_CHUNKSIZE", "RAID_TYPE", "RANGE", "READ", "READ_ONLY", "READ_WRITE", "REFERENCES", "REGEXP", "RELOAD", "RENAME", "REPAIR", "REPEATABLE", "REPLACE", "REPLICATION", "RESET", "RESTORE", "RESTRICT", "RETURN", "RETURNS", "REVOKE", "RLIKE", "ROLLBACK", "ROW", "ROWS", "ROW_FORMAT", "SECOND", "SECURITY", "SEPARATOR", "SERIALIZABLE", "SESSION", "SHARE", "SHOW", "SHUTDOWN", "SLAVE", "SONAME", "SOUNDS", "SQL", "SQL_AUTO_IS_NULL", "SQL_BIG_RESULT", "SQL_BIG_SELECTS", "SQL_BIG_TABLES", "SQL_BUFFER_RESULT", "SQL_CACHE", "SQL_CALC_FOUND_ROWS", "SQL_LOG_BIN", "SQL_LOG_OFF", "SQL_LOG_UPDATE", "SQL_LOW_PRIORITY_UPDATES", "SQL_MAX_JOIN_SIZE", "SQL_NO_CACHE", "SQL_QUOTE_SHOW_CREATE", "SQL_SAFE_UPDATES", "SQL_SELECT_LIMIT", "SQL_SLAVE_SKIP_COUNTER", "SQL_SMALL_RESULT", "SQL_WARNINGS", "START", "STARTING", "STATUS", "STOP", "STORAGE", "STRAIGHT_JOIN", "STRING", "STRIPED", "SUPER", "TABLE", "TABLES", "TEMPORARY", "TERMINATED", "THEN", "TO", "TRAILING", "TRANSACTIONAL", "TRUE", "TRUNCATE", "TYPE", "TYPES", "UNCOMMITTED", "UNIQUE", "UNLOCK", "UNSIGNED", "USAGE", "USE", "USING", "VARIABLES", "VIEW", "WHEN", "WITH", "WORK", "WRITE", "YEAR_MONTH"]; 1745 | 1746 | var reservedToplevelWords = ["ADD", "AFTER", "ALTER COLUMN", "ALTER TABLE", "DELETE FROM", "EXCEPT", "FETCH FIRST", "FROM", "GROUP BY", "GO", "HAVING", "INSERT INTO", "INSERT", "INTERSECT", "LIMIT", "MODIFY", "ORDER BY", "SELECT", "SET CURRENT SCHEMA", "SET SCHEMA", "SET", "UNION ALL", "UNION", "UPDATE", "VALUES", "WHERE"]; 1747 | 1748 | var reservedNewlineWords = ["AND", "CROSS APPLY", "CROSS JOIN", "ELSE", "INNER JOIN", "JOIN", "LEFT JOIN", "LEFT OUTER JOIN", "OR", "OUTER APPLY", "OUTER JOIN", "RIGHT JOIN", "RIGHT OUTER JOIN", "WHEN", "XOR"]; 1749 | 1750 | var tokenizer = void 0; 1751 | 1752 | var StandardSqlFormatter = function () { 1753 | /** 1754 | * @param {Object} cfg Different set of configurations 1755 | */ 1756 | function StandardSqlFormatter(cfg) { 1757 | _classCallCheck(this, StandardSqlFormatter); 1758 | 1759 | this.cfg = cfg; 1760 | } 1761 | 1762 | /** 1763 | * Format the whitespace in a Standard SQL string to make it easier to read 1764 | * 1765 | * @param {String} query The Standard SQL string 1766 | * @return {String} formatted string 1767 | */ 1768 | 1769 | 1770 | StandardSqlFormatter.prototype.format = function format(query) { 1771 | if (!tokenizer) { 1772 | tokenizer = new _Tokenizer2["default"]({ 1773 | reservedWords: reservedWords, 1774 | reservedToplevelWords: reservedToplevelWords, 1775 | reservedNewlineWords: reservedNewlineWords, 1776 | stringTypes: ["\"\"", "N''", "''", "``", "[]"], 1777 | openParens: ["(", "CASE"], 1778 | closeParens: [")", "END"], 1779 | indexedPlaceholderTypes: ["?"], 1780 | namedPlaceholderTypes: ["@", ":"], 1781 | lineCommentTypes: ["#", "--"] 1782 | }); 1783 | } 1784 | return new _Formatter2["default"](this.cfg, tokenizer).format(query); 1785 | }; 1786 | 1787 | return StandardSqlFormatter; 1788 | }(); 1789 | 1790 | exports["default"] = StandardSqlFormatter; 1791 | module.exports = exports["default"]; 1792 | 1793 | /***/ }), 1794 | /* 28 */ 1795 | /***/ (function(module, exports, __webpack_require__) { 1796 | 1797 | var getNative = __webpack_require__(3), 1798 | root = __webpack_require__(1); 1799 | 1800 | /* Built-in method references that are verified to be native. */ 1801 | var DataView = getNative(root, 'DataView'); 1802 | 1803 | module.exports = DataView; 1804 | 1805 | 1806 | /***/ }), 1807 | /* 29 */ 1808 | /***/ (function(module, exports, __webpack_require__) { 1809 | 1810 | var getNative = __webpack_require__(3), 1811 | root = __webpack_require__(1); 1812 | 1813 | /* Built-in method references that are verified to be native. */ 1814 | var Map = getNative(root, 'Map'); 1815 | 1816 | module.exports = Map; 1817 | 1818 | 1819 | /***/ }), 1820 | /* 30 */ 1821 | /***/ (function(module, exports, __webpack_require__) { 1822 | 1823 | var getNative = __webpack_require__(3), 1824 | root = __webpack_require__(1); 1825 | 1826 | /* Built-in method references that are verified to be native. */ 1827 | var Promise = getNative(root, 'Promise'); 1828 | 1829 | module.exports = Promise; 1830 | 1831 | 1832 | /***/ }), 1833 | /* 31 */ 1834 | /***/ (function(module, exports, __webpack_require__) { 1835 | 1836 | var getNative = __webpack_require__(3), 1837 | root = __webpack_require__(1); 1838 | 1839 | /* Built-in method references that are verified to be native. */ 1840 | var Set = getNative(root, 'Set'); 1841 | 1842 | module.exports = Set; 1843 | 1844 | 1845 | /***/ }), 1846 | /* 32 */ 1847 | /***/ (function(module, exports, __webpack_require__) { 1848 | 1849 | var getNative = __webpack_require__(3), 1850 | root = __webpack_require__(1); 1851 | 1852 | /* Built-in method references that are verified to be native. */ 1853 | var WeakMap = getNative(root, 'WeakMap'); 1854 | 1855 | module.exports = WeakMap; 1856 | 1857 | 1858 | /***/ }), 1859 | /* 33 */ 1860 | /***/ (function(module, exports) { 1861 | 1862 | /** 1863 | * A specialized version of `_.map` for arrays without support for iteratee 1864 | * shorthands. 1865 | * 1866 | * @private 1867 | * @param {Array} [array] The array to iterate over. 1868 | * @param {Function} iteratee The function invoked per iteration. 1869 | * @returns {Array} Returns the new mapped array. 1870 | */ 1871 | function arrayMap(array, iteratee) { 1872 | var index = -1, 1873 | length = array == null ? 0 : array.length, 1874 | result = Array(length); 1875 | 1876 | while (++index < length) { 1877 | result[index] = iteratee(array[index], index, array); 1878 | } 1879 | return result; 1880 | } 1881 | 1882 | module.exports = arrayMap; 1883 | 1884 | 1885 | /***/ }), 1886 | /* 34 */ 1887 | /***/ (function(module, exports) { 1888 | 1889 | /** 1890 | * Converts an ASCII `string` to an array. 1891 | * 1892 | * @private 1893 | * @param {string} string The string to convert. 1894 | * @returns {Array} Returns the converted array. 1895 | */ 1896 | function asciiToArray(string) { 1897 | return string.split(''); 1898 | } 1899 | 1900 | module.exports = asciiToArray; 1901 | 1902 | 1903 | /***/ }), 1904 | /* 35 */ 1905 | /***/ (function(module, exports) { 1906 | 1907 | /** 1908 | * The base implementation of `_.findIndex` and `_.findLastIndex` without 1909 | * support for iteratee shorthands. 1910 | * 1911 | * @private 1912 | * @param {Array} array The array to inspect. 1913 | * @param {Function} predicate The function invoked per iteration. 1914 | * @param {number} fromIndex The index to search from. 1915 | * @param {boolean} [fromRight] Specify iterating from right to left. 1916 | * @returns {number} Returns the index of the matched value, else `-1`. 1917 | */ 1918 | function baseFindIndex(array, predicate, fromIndex, fromRight) { 1919 | var length = array.length, 1920 | index = fromIndex + (fromRight ? 1 : -1); 1921 | 1922 | while ((fromRight ? index-- : ++index < length)) { 1923 | if (predicate(array[index], index, array)) { 1924 | return index; 1925 | } 1926 | } 1927 | return -1; 1928 | } 1929 | 1930 | module.exports = baseFindIndex; 1931 | 1932 | 1933 | /***/ }), 1934 | /* 36 */ 1935 | /***/ (function(module, exports, __webpack_require__) { 1936 | 1937 | var baseFindIndex = __webpack_require__(35), 1938 | baseIsNaN = __webpack_require__(38), 1939 | strictIndexOf = __webpack_require__(59); 1940 | 1941 | /** 1942 | * The base implementation of `_.indexOf` without `fromIndex` bounds checks. 1943 | * 1944 | * @private 1945 | * @param {Array} array The array to inspect. 1946 | * @param {*} value The value to search for. 1947 | * @param {number} fromIndex The index to search from. 1948 | * @returns {number} Returns the index of the matched value, else `-1`. 1949 | */ 1950 | function baseIndexOf(array, value, fromIndex) { 1951 | return value === value 1952 | ? strictIndexOf(array, value, fromIndex) 1953 | : baseFindIndex(array, baseIsNaN, fromIndex); 1954 | } 1955 | 1956 | module.exports = baseIndexOf; 1957 | 1958 | 1959 | /***/ }), 1960 | /* 37 */ 1961 | /***/ (function(module, exports, __webpack_require__) { 1962 | 1963 | var baseGetTag = __webpack_require__(2), 1964 | isObjectLike = __webpack_require__(7); 1965 | 1966 | /** `Object#toString` result references. */ 1967 | var argsTag = '[object Arguments]'; 1968 | 1969 | /** 1970 | * The base implementation of `_.isArguments`. 1971 | * 1972 | * @private 1973 | * @param {*} value The value to check. 1974 | * @returns {boolean} Returns `true` if `value` is an `arguments` object, 1975 | */ 1976 | function baseIsArguments(value) { 1977 | return isObjectLike(value) && baseGetTag(value) == argsTag; 1978 | } 1979 | 1980 | module.exports = baseIsArguments; 1981 | 1982 | 1983 | /***/ }), 1984 | /* 38 */ 1985 | /***/ (function(module, exports) { 1986 | 1987 | /** 1988 | * The base implementation of `_.isNaN` without support for number objects. 1989 | * 1990 | * @private 1991 | * @param {*} value The value to check. 1992 | * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. 1993 | */ 1994 | function baseIsNaN(value) { 1995 | return value !== value; 1996 | } 1997 | 1998 | module.exports = baseIsNaN; 1999 | 2000 | 2001 | /***/ }), 2002 | /* 39 */ 2003 | /***/ (function(module, exports, __webpack_require__) { 2004 | 2005 | var isFunction = __webpack_require__(17), 2006 | isMasked = __webpack_require__(54), 2007 | isObject = __webpack_require__(6), 2008 | toSource = __webpack_require__(14); 2009 | 2010 | /** 2011 | * Used to match `RegExp` 2012 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 2013 | */ 2014 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; 2015 | 2016 | /** Used to detect host constructors (Safari). */ 2017 | var reIsHostCtor = /^\[object .+?Constructor\]$/; 2018 | 2019 | /** Used for built-in method references. */ 2020 | var funcProto = Function.prototype, 2021 | objectProto = Object.prototype; 2022 | 2023 | /** Used to resolve the decompiled source of functions. */ 2024 | var funcToString = funcProto.toString; 2025 | 2026 | /** Used to check objects for own properties. */ 2027 | var hasOwnProperty = objectProto.hasOwnProperty; 2028 | 2029 | /** Used to detect if a method is native. */ 2030 | var reIsNative = RegExp('^' + 2031 | funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') 2032 | .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' 2033 | ); 2034 | 2035 | /** 2036 | * The base implementation of `_.isNative` without bad shim checks. 2037 | * 2038 | * @private 2039 | * @param {*} value The value to check. 2040 | * @returns {boolean} Returns `true` if `value` is a native function, 2041 | * else `false`. 2042 | */ 2043 | function baseIsNative(value) { 2044 | if (!isObject(value) || isMasked(value)) { 2045 | return false; 2046 | } 2047 | var pattern = isFunction(value) ? reIsNative : reIsHostCtor; 2048 | return pattern.test(toSource(value)); 2049 | } 2050 | 2051 | module.exports = baseIsNative; 2052 | 2053 | 2054 | /***/ }), 2055 | /* 40 */ 2056 | /***/ (function(module, exports, __webpack_require__) { 2057 | 2058 | var baseGetTag = __webpack_require__(2), 2059 | isLength = __webpack_require__(18), 2060 | isObjectLike = __webpack_require__(7); 2061 | 2062 | /** `Object#toString` result references. */ 2063 | var argsTag = '[object Arguments]', 2064 | arrayTag = '[object Array]', 2065 | boolTag = '[object Boolean]', 2066 | dateTag = '[object Date]', 2067 | errorTag = '[object Error]', 2068 | funcTag = '[object Function]', 2069 | mapTag = '[object Map]', 2070 | numberTag = '[object Number]', 2071 | objectTag = '[object Object]', 2072 | regexpTag = '[object RegExp]', 2073 | setTag = '[object Set]', 2074 | stringTag = '[object String]', 2075 | weakMapTag = '[object WeakMap]'; 2076 | 2077 | var arrayBufferTag = '[object ArrayBuffer]', 2078 | dataViewTag = '[object DataView]', 2079 | float32Tag = '[object Float32Array]', 2080 | float64Tag = '[object Float64Array]', 2081 | int8Tag = '[object Int8Array]', 2082 | int16Tag = '[object Int16Array]', 2083 | int32Tag = '[object Int32Array]', 2084 | uint8Tag = '[object Uint8Array]', 2085 | uint8ClampedTag = '[object Uint8ClampedArray]', 2086 | uint16Tag = '[object Uint16Array]', 2087 | uint32Tag = '[object Uint32Array]'; 2088 | 2089 | /** Used to identify `toStringTag` values of typed arrays. */ 2090 | var typedArrayTags = {}; 2091 | typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = 2092 | typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = 2093 | typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = 2094 | typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = 2095 | typedArrayTags[uint32Tag] = true; 2096 | typedArrayTags[argsTag] = typedArrayTags[arrayTag] = 2097 | typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = 2098 | typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = 2099 | typedArrayTags[errorTag] = typedArrayTags[funcTag] = 2100 | typedArrayTags[mapTag] = typedArrayTags[numberTag] = 2101 | typedArrayTags[objectTag] = typedArrayTags[regexpTag] = 2102 | typedArrayTags[setTag] = typedArrayTags[stringTag] = 2103 | typedArrayTags[weakMapTag] = false; 2104 | 2105 | /** 2106 | * The base implementation of `_.isTypedArray` without Node.js optimizations. 2107 | * 2108 | * @private 2109 | * @param {*} value The value to check. 2110 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 2111 | */ 2112 | function baseIsTypedArray(value) { 2113 | return isObjectLike(value) && 2114 | isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; 2115 | } 2116 | 2117 | module.exports = baseIsTypedArray; 2118 | 2119 | 2120 | /***/ }), 2121 | /* 41 */ 2122 | /***/ (function(module, exports, __webpack_require__) { 2123 | 2124 | var isPrototype = __webpack_require__(13), 2125 | nativeKeys = __webpack_require__(55); 2126 | 2127 | /** Used for built-in method references. */ 2128 | var objectProto = Object.prototype; 2129 | 2130 | /** Used to check objects for own properties. */ 2131 | var hasOwnProperty = objectProto.hasOwnProperty; 2132 | 2133 | /** 2134 | * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. 2135 | * 2136 | * @private 2137 | * @param {Object} object The object to query. 2138 | * @returns {Array} Returns the array of property names. 2139 | */ 2140 | function baseKeys(object) { 2141 | if (!isPrototype(object)) { 2142 | return nativeKeys(object); 2143 | } 2144 | var result = []; 2145 | for (var key in Object(object)) { 2146 | if (hasOwnProperty.call(object, key) && key != 'constructor') { 2147 | result.push(key); 2148 | } 2149 | } 2150 | return result; 2151 | } 2152 | 2153 | module.exports = baseKeys; 2154 | 2155 | 2156 | /***/ }), 2157 | /* 42 */ 2158 | /***/ (function(module, exports) { 2159 | 2160 | /** Used as references for various `Number` constants. */ 2161 | var MAX_SAFE_INTEGER = 9007199254740991; 2162 | 2163 | /* Built-in method references for those with the same name as other `lodash` methods. */ 2164 | var nativeFloor = Math.floor; 2165 | 2166 | /** 2167 | * The base implementation of `_.repeat` which doesn't coerce arguments. 2168 | * 2169 | * @private 2170 | * @param {string} string The string to repeat. 2171 | * @param {number} n The number of times to repeat the string. 2172 | * @returns {string} Returns the repeated string. 2173 | */ 2174 | function baseRepeat(string, n) { 2175 | var result = ''; 2176 | if (!string || n < 1 || n > MAX_SAFE_INTEGER) { 2177 | return result; 2178 | } 2179 | // Leverage the exponentiation by squaring algorithm for a faster repeat. 2180 | // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. 2181 | do { 2182 | if (n % 2) { 2183 | result += string; 2184 | } 2185 | n = nativeFloor(n / 2); 2186 | if (n) { 2187 | string += string; 2188 | } 2189 | } while (n); 2190 | 2191 | return result; 2192 | } 2193 | 2194 | module.exports = baseRepeat; 2195 | 2196 | 2197 | /***/ }), 2198 | /* 43 */ 2199 | /***/ (function(module, exports) { 2200 | 2201 | /** 2202 | * The base implementation of `_.slice` without an iteratee call guard. 2203 | * 2204 | * @private 2205 | * @param {Array} array The array to slice. 2206 | * @param {number} [start=0] The start position. 2207 | * @param {number} [end=array.length] The end position. 2208 | * @returns {Array} Returns the slice of `array`. 2209 | */ 2210 | function baseSlice(array, start, end) { 2211 | var index = -1, 2212 | length = array.length; 2213 | 2214 | if (start < 0) { 2215 | start = -start > length ? 0 : (length + start); 2216 | } 2217 | end = end > length ? length : end; 2218 | if (end < 0) { 2219 | end += length; 2220 | } 2221 | length = start > end ? 0 : ((end - start) >>> 0); 2222 | start >>>= 0; 2223 | 2224 | var result = Array(length); 2225 | while (++index < length) { 2226 | result[index] = array[index + start]; 2227 | } 2228 | return result; 2229 | } 2230 | 2231 | module.exports = baseSlice; 2232 | 2233 | 2234 | /***/ }), 2235 | /* 44 */ 2236 | /***/ (function(module, exports) { 2237 | 2238 | /** 2239 | * The base implementation of `_.unary` without support for storing metadata. 2240 | * 2241 | * @private 2242 | * @param {Function} func The function to cap arguments for. 2243 | * @returns {Function} Returns the new capped function. 2244 | */ 2245 | function baseUnary(func) { 2246 | return function(value) { 2247 | return func(value); 2248 | }; 2249 | } 2250 | 2251 | module.exports = baseUnary; 2252 | 2253 | 2254 | /***/ }), 2255 | /* 45 */ 2256 | /***/ (function(module, exports, __webpack_require__) { 2257 | 2258 | var baseSlice = __webpack_require__(43); 2259 | 2260 | /** 2261 | * Casts `array` to a slice if it's needed. 2262 | * 2263 | * @private 2264 | * @param {Array} array The array to inspect. 2265 | * @param {number} start The start position. 2266 | * @param {number} [end=array.length] The end position. 2267 | * @returns {Array} Returns the cast slice. 2268 | */ 2269 | function castSlice(array, start, end) { 2270 | var length = array.length; 2271 | end = end === undefined ? length : end; 2272 | return (!start && end >= length) ? array : baseSlice(array, start, end); 2273 | } 2274 | 2275 | module.exports = castSlice; 2276 | 2277 | 2278 | /***/ }), 2279 | /* 46 */ 2280 | /***/ (function(module, exports, __webpack_require__) { 2281 | 2282 | var baseIndexOf = __webpack_require__(36); 2283 | 2284 | /** 2285 | * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol 2286 | * that is not found in the character symbols. 2287 | * 2288 | * @private 2289 | * @param {Array} strSymbols The string symbols to inspect. 2290 | * @param {Array} chrSymbols The character symbols to find. 2291 | * @returns {number} Returns the index of the last unmatched string symbol. 2292 | */ 2293 | function charsEndIndex(strSymbols, chrSymbols) { 2294 | var index = strSymbols.length; 2295 | 2296 | while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} 2297 | return index; 2298 | } 2299 | 2300 | module.exports = charsEndIndex; 2301 | 2302 | 2303 | /***/ }), 2304 | /* 47 */ 2305 | /***/ (function(module, exports, __webpack_require__) { 2306 | 2307 | var root = __webpack_require__(1); 2308 | 2309 | /** Used to detect overreaching core-js shims. */ 2310 | var coreJsData = root['__core-js_shared__']; 2311 | 2312 | module.exports = coreJsData; 2313 | 2314 | 2315 | /***/ }), 2316 | /* 48 */ 2317 | /***/ (function(module, exports, __webpack_require__) { 2318 | 2319 | var Symbol = __webpack_require__(9); 2320 | 2321 | /** Used for built-in method references. */ 2322 | var objectProto = Object.prototype; 2323 | 2324 | /** Used to check objects for own properties. */ 2325 | var hasOwnProperty = objectProto.hasOwnProperty; 2326 | 2327 | /** 2328 | * Used to resolve the 2329 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 2330 | * of values. 2331 | */ 2332 | var nativeObjectToString = objectProto.toString; 2333 | 2334 | /** Built-in value references. */ 2335 | var symToStringTag = Symbol ? Symbol.toStringTag : undefined; 2336 | 2337 | /** 2338 | * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. 2339 | * 2340 | * @private 2341 | * @param {*} value The value to query. 2342 | * @returns {string} Returns the raw `toStringTag`. 2343 | */ 2344 | function getRawTag(value) { 2345 | var isOwn = hasOwnProperty.call(value, symToStringTag), 2346 | tag = value[symToStringTag]; 2347 | 2348 | try { 2349 | value[symToStringTag] = undefined; 2350 | var unmasked = true; 2351 | } catch (e) {} 2352 | 2353 | var result = nativeObjectToString.call(value); 2354 | if (unmasked) { 2355 | if (isOwn) { 2356 | value[symToStringTag] = tag; 2357 | } else { 2358 | delete value[symToStringTag]; 2359 | } 2360 | } 2361 | return result; 2362 | } 2363 | 2364 | module.exports = getRawTag; 2365 | 2366 | 2367 | /***/ }), 2368 | /* 49 */ 2369 | /***/ (function(module, exports, __webpack_require__) { 2370 | 2371 | var DataView = __webpack_require__(28), 2372 | Map = __webpack_require__(29), 2373 | Promise = __webpack_require__(30), 2374 | Set = __webpack_require__(31), 2375 | WeakMap = __webpack_require__(32), 2376 | baseGetTag = __webpack_require__(2), 2377 | toSource = __webpack_require__(14); 2378 | 2379 | /** `Object#toString` result references. */ 2380 | var mapTag = '[object Map]', 2381 | objectTag = '[object Object]', 2382 | promiseTag = '[object Promise]', 2383 | setTag = '[object Set]', 2384 | weakMapTag = '[object WeakMap]'; 2385 | 2386 | var dataViewTag = '[object DataView]'; 2387 | 2388 | /** Used to detect maps, sets, and weakmaps. */ 2389 | var dataViewCtorString = toSource(DataView), 2390 | mapCtorString = toSource(Map), 2391 | promiseCtorString = toSource(Promise), 2392 | setCtorString = toSource(Set), 2393 | weakMapCtorString = toSource(WeakMap); 2394 | 2395 | /** 2396 | * Gets the `toStringTag` of `value`. 2397 | * 2398 | * @private 2399 | * @param {*} value The value to query. 2400 | * @returns {string} Returns the `toStringTag`. 2401 | */ 2402 | var getTag = baseGetTag; 2403 | 2404 | // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. 2405 | if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || 2406 | (Map && getTag(new Map) != mapTag) || 2407 | (Promise && getTag(Promise.resolve()) != promiseTag) || 2408 | (Set && getTag(new Set) != setTag) || 2409 | (WeakMap && getTag(new WeakMap) != weakMapTag)) { 2410 | getTag = function(value) { 2411 | var result = baseGetTag(value), 2412 | Ctor = result == objectTag ? value.constructor : undefined, 2413 | ctorString = Ctor ? toSource(Ctor) : ''; 2414 | 2415 | if (ctorString) { 2416 | switch (ctorString) { 2417 | case dataViewCtorString: return dataViewTag; 2418 | case mapCtorString: return mapTag; 2419 | case promiseCtorString: return promiseTag; 2420 | case setCtorString: return setTag; 2421 | case weakMapCtorString: return weakMapTag; 2422 | } 2423 | } 2424 | return result; 2425 | }; 2426 | } 2427 | 2428 | module.exports = getTag; 2429 | 2430 | 2431 | /***/ }), 2432 | /* 50 */ 2433 | /***/ (function(module, exports) { 2434 | 2435 | /** 2436 | * Gets the value at `key` of `object`. 2437 | * 2438 | * @private 2439 | * @param {Object} [object] The object to query. 2440 | * @param {string} key The key of the property to get. 2441 | * @returns {*} Returns the property value. 2442 | */ 2443 | function getValue(object, key) { 2444 | return object == null ? undefined : object[key]; 2445 | } 2446 | 2447 | module.exports = getValue; 2448 | 2449 | 2450 | /***/ }), 2451 | /* 51 */ 2452 | /***/ (function(module, exports) { 2453 | 2454 | /** Used to compose unicode character classes. */ 2455 | var rsAstralRange = '\\ud800-\\udfff', 2456 | rsComboMarksRange = '\\u0300-\\u036f', 2457 | reComboHalfMarksRange = '\\ufe20-\\ufe2f', 2458 | rsComboSymbolsRange = '\\u20d0-\\u20ff', 2459 | rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, 2460 | rsVarRange = '\\ufe0e\\ufe0f'; 2461 | 2462 | /** Used to compose unicode capture groups. */ 2463 | var rsZWJ = '\\u200d'; 2464 | 2465 | /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ 2466 | var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); 2467 | 2468 | /** 2469 | * Checks if `string` contains Unicode symbols. 2470 | * 2471 | * @private 2472 | * @param {string} string The string to inspect. 2473 | * @returns {boolean} Returns `true` if a symbol is found, else `false`. 2474 | */ 2475 | function hasUnicode(string) { 2476 | return reHasUnicode.test(string); 2477 | } 2478 | 2479 | module.exports = hasUnicode; 2480 | 2481 | 2482 | /***/ }), 2483 | /* 52 */ 2484 | /***/ (function(module, exports) { 2485 | 2486 | /** Used as references for various `Number` constants. */ 2487 | var MAX_SAFE_INTEGER = 9007199254740991; 2488 | 2489 | /** Used to detect unsigned integer values. */ 2490 | var reIsUint = /^(?:0|[1-9]\d*)$/; 2491 | 2492 | /** 2493 | * Checks if `value` is a valid array-like index. 2494 | * 2495 | * @private 2496 | * @param {*} value The value to check. 2497 | * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. 2498 | * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. 2499 | */ 2500 | function isIndex(value, length) { 2501 | var type = typeof value; 2502 | length = length == null ? MAX_SAFE_INTEGER : length; 2503 | 2504 | return !!length && 2505 | (type == 'number' || 2506 | (type != 'symbol' && reIsUint.test(value))) && 2507 | (value > -1 && value % 1 == 0 && value < length); 2508 | } 2509 | 2510 | module.exports = isIndex; 2511 | 2512 | 2513 | /***/ }), 2514 | /* 53 */ 2515 | /***/ (function(module, exports, __webpack_require__) { 2516 | 2517 | var eq = __webpack_require__(62), 2518 | isArrayLike = __webpack_require__(16), 2519 | isIndex = __webpack_require__(52), 2520 | isObject = __webpack_require__(6); 2521 | 2522 | /** 2523 | * Checks if the given arguments are from an iteratee call. 2524 | * 2525 | * @private 2526 | * @param {*} value The potential iteratee value argument. 2527 | * @param {*} index The potential iteratee index or key argument. 2528 | * @param {*} object The potential iteratee object argument. 2529 | * @returns {boolean} Returns `true` if the arguments are from an iteratee call, 2530 | * else `false`. 2531 | */ 2532 | function isIterateeCall(value, index, object) { 2533 | if (!isObject(object)) { 2534 | return false; 2535 | } 2536 | var type = typeof index; 2537 | if (type == 'number' 2538 | ? (isArrayLike(object) && isIndex(index, object.length)) 2539 | : (type == 'string' && index in object) 2540 | ) { 2541 | return eq(object[index], value); 2542 | } 2543 | return false; 2544 | } 2545 | 2546 | module.exports = isIterateeCall; 2547 | 2548 | 2549 | /***/ }), 2550 | /* 54 */ 2551 | /***/ (function(module, exports, __webpack_require__) { 2552 | 2553 | var coreJsData = __webpack_require__(47); 2554 | 2555 | /** Used to detect methods masquerading as native. */ 2556 | var maskSrcKey = (function() { 2557 | var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); 2558 | return uid ? ('Symbol(src)_1.' + uid) : ''; 2559 | }()); 2560 | 2561 | /** 2562 | * Checks if `func` has its source masked. 2563 | * 2564 | * @private 2565 | * @param {Function} func The function to check. 2566 | * @returns {boolean} Returns `true` if `func` is masked, else `false`. 2567 | */ 2568 | function isMasked(func) { 2569 | return !!maskSrcKey && (maskSrcKey in func); 2570 | } 2571 | 2572 | module.exports = isMasked; 2573 | 2574 | 2575 | /***/ }), 2576 | /* 55 */ 2577 | /***/ (function(module, exports, __webpack_require__) { 2578 | 2579 | var overArg = __webpack_require__(58); 2580 | 2581 | /* Built-in method references for those with the same name as other `lodash` methods. */ 2582 | var nativeKeys = overArg(Object.keys, Object); 2583 | 2584 | module.exports = nativeKeys; 2585 | 2586 | 2587 | /***/ }), 2588 | /* 56 */ 2589 | /***/ (function(module, exports, __webpack_require__) { 2590 | 2591 | /* WEBPACK VAR INJECTION */(function(module) {var freeGlobal = __webpack_require__(12); 2592 | 2593 | /** Detect free variable `exports`. */ 2594 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 2595 | 2596 | /** Detect free variable `module`. */ 2597 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 2598 | 2599 | /** Detect the popular CommonJS extension `module.exports`. */ 2600 | var moduleExports = freeModule && freeModule.exports === freeExports; 2601 | 2602 | /** Detect free variable `process` from Node.js. */ 2603 | var freeProcess = moduleExports && freeGlobal.process; 2604 | 2605 | /** Used to access faster Node.js helpers. */ 2606 | var nodeUtil = (function() { 2607 | try { 2608 | // Use `util.types` for Node.js 10+. 2609 | var types = freeModule && freeModule.require && freeModule.require('util').types; 2610 | 2611 | if (types) { 2612 | return types; 2613 | } 2614 | 2615 | // Legacy `process.binding('util')` for Node.js < 10. 2616 | return freeProcess && freeProcess.binding && freeProcess.binding('util'); 2617 | } catch (e) {} 2618 | }()); 2619 | 2620 | module.exports = nodeUtil; 2621 | 2622 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(20)(module))) 2623 | 2624 | /***/ }), 2625 | /* 57 */ 2626 | /***/ (function(module, exports) { 2627 | 2628 | /** Used for built-in method references. */ 2629 | var objectProto = Object.prototype; 2630 | 2631 | /** 2632 | * Used to resolve the 2633 | * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) 2634 | * of values. 2635 | */ 2636 | var nativeObjectToString = objectProto.toString; 2637 | 2638 | /** 2639 | * Converts `value` to a string using `Object.prototype.toString`. 2640 | * 2641 | * @private 2642 | * @param {*} value The value to convert. 2643 | * @returns {string} Returns the converted string. 2644 | */ 2645 | function objectToString(value) { 2646 | return nativeObjectToString.call(value); 2647 | } 2648 | 2649 | module.exports = objectToString; 2650 | 2651 | 2652 | /***/ }), 2653 | /* 58 */ 2654 | /***/ (function(module, exports) { 2655 | 2656 | /** 2657 | * Creates a unary function that invokes `func` with its argument transformed. 2658 | * 2659 | * @private 2660 | * @param {Function} func The function to wrap. 2661 | * @param {Function} transform The argument transform. 2662 | * @returns {Function} Returns the new function. 2663 | */ 2664 | function overArg(func, transform) { 2665 | return function(arg) { 2666 | return func(transform(arg)); 2667 | }; 2668 | } 2669 | 2670 | module.exports = overArg; 2671 | 2672 | 2673 | /***/ }), 2674 | /* 59 */ 2675 | /***/ (function(module, exports) { 2676 | 2677 | /** 2678 | * A specialized version of `_.indexOf` which performs strict equality 2679 | * comparisons of values, i.e. `===`. 2680 | * 2681 | * @private 2682 | * @param {Array} array The array to inspect. 2683 | * @param {*} value The value to search for. 2684 | * @param {number} fromIndex The index to search from. 2685 | * @returns {number} Returns the index of the matched value, else `-1`. 2686 | */ 2687 | function strictIndexOf(array, value, fromIndex) { 2688 | var index = fromIndex - 1, 2689 | length = array.length; 2690 | 2691 | while (++index < length) { 2692 | if (array[index] === value) { 2693 | return index; 2694 | } 2695 | } 2696 | return -1; 2697 | } 2698 | 2699 | module.exports = strictIndexOf; 2700 | 2701 | 2702 | /***/ }), 2703 | /* 60 */ 2704 | /***/ (function(module, exports, __webpack_require__) { 2705 | 2706 | var asciiToArray = __webpack_require__(34), 2707 | hasUnicode = __webpack_require__(51), 2708 | unicodeToArray = __webpack_require__(61); 2709 | 2710 | /** 2711 | * Converts `string` to an array. 2712 | * 2713 | * @private 2714 | * @param {string} string The string to convert. 2715 | * @returns {Array} Returns the converted array. 2716 | */ 2717 | function stringToArray(string) { 2718 | return hasUnicode(string) 2719 | ? unicodeToArray(string) 2720 | : asciiToArray(string); 2721 | } 2722 | 2723 | module.exports = stringToArray; 2724 | 2725 | 2726 | /***/ }), 2727 | /* 61 */ 2728 | /***/ (function(module, exports) { 2729 | 2730 | /** Used to compose unicode character classes. */ 2731 | var rsAstralRange = '\\ud800-\\udfff', 2732 | rsComboMarksRange = '\\u0300-\\u036f', 2733 | reComboHalfMarksRange = '\\ufe20-\\ufe2f', 2734 | rsComboSymbolsRange = '\\u20d0-\\u20ff', 2735 | rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, 2736 | rsVarRange = '\\ufe0e\\ufe0f'; 2737 | 2738 | /** Used to compose unicode capture groups. */ 2739 | var rsAstral = '[' + rsAstralRange + ']', 2740 | rsCombo = '[' + rsComboRange + ']', 2741 | rsFitz = '\\ud83c[\\udffb-\\udfff]', 2742 | rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', 2743 | rsNonAstral = '[^' + rsAstralRange + ']', 2744 | rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', 2745 | rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', 2746 | rsZWJ = '\\u200d'; 2747 | 2748 | /** Used to compose unicode regexes. */ 2749 | var reOptMod = rsModifier + '?', 2750 | rsOptVar = '[' + rsVarRange + ']?', 2751 | rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', 2752 | rsSeq = rsOptVar + reOptMod + rsOptJoin, 2753 | rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; 2754 | 2755 | /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ 2756 | var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); 2757 | 2758 | /** 2759 | * Converts a Unicode `string` to an array. 2760 | * 2761 | * @private 2762 | * @param {string} string The string to convert. 2763 | * @returns {Array} Returns the converted array. 2764 | */ 2765 | function unicodeToArray(string) { 2766 | return string.match(reUnicode) || []; 2767 | } 2768 | 2769 | module.exports = unicodeToArray; 2770 | 2771 | 2772 | /***/ }), 2773 | /* 62 */ 2774 | /***/ (function(module, exports) { 2775 | 2776 | /** 2777 | * Performs a 2778 | * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) 2779 | * comparison between two values to determine if they are equivalent. 2780 | * 2781 | * @static 2782 | * @memberOf _ 2783 | * @since 4.0.0 2784 | * @category Lang 2785 | * @param {*} value The value to compare. 2786 | * @param {*} other The other value to compare. 2787 | * @returns {boolean} Returns `true` if the values are equivalent, else `false`. 2788 | * @example 2789 | * 2790 | * var object = { 'a': 1 }; 2791 | * var other = { 'a': 1 }; 2792 | * 2793 | * _.eq(object, object); 2794 | * // => true 2795 | * 2796 | * _.eq(object, other); 2797 | * // => false 2798 | * 2799 | * _.eq('a', 'a'); 2800 | * // => true 2801 | * 2802 | * _.eq('a', Object('a')); 2803 | * // => false 2804 | * 2805 | * _.eq(NaN, NaN); 2806 | * // => true 2807 | */ 2808 | function eq(value, other) { 2809 | return value === other || (value !== value && other !== other); 2810 | } 2811 | 2812 | module.exports = eq; 2813 | 2814 | 2815 | /***/ }), 2816 | /* 63 */ 2817 | /***/ (function(module, exports, __webpack_require__) { 2818 | 2819 | var toString = __webpack_require__(10); 2820 | 2821 | /** 2822 | * Used to match `RegExp` 2823 | * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). 2824 | */ 2825 | var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, 2826 | reHasRegExpChar = RegExp(reRegExpChar.source); 2827 | 2828 | /** 2829 | * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", 2830 | * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. 2831 | * 2832 | * @static 2833 | * @memberOf _ 2834 | * @since 3.0.0 2835 | * @category String 2836 | * @param {string} [string=''] The string to escape. 2837 | * @returns {string} Returns the escaped string. 2838 | * @example 2839 | * 2840 | * _.escapeRegExp('[lodash](https://lodash.com/)'); 2841 | * // => '\[lodash\]\(https://lodash\.com/\)' 2842 | */ 2843 | function escapeRegExp(string) { 2844 | string = toString(string); 2845 | return (string && reHasRegExpChar.test(string)) 2846 | ? string.replace(reRegExpChar, '\\$&') 2847 | : string; 2848 | } 2849 | 2850 | module.exports = escapeRegExp; 2851 | 2852 | 2853 | /***/ }), 2854 | /* 64 */ 2855 | /***/ (function(module, exports, __webpack_require__) { 2856 | 2857 | var baseIsArguments = __webpack_require__(37), 2858 | isObjectLike = __webpack_require__(7); 2859 | 2860 | /** Used for built-in method references. */ 2861 | var objectProto = Object.prototype; 2862 | 2863 | /** Used to check objects for own properties. */ 2864 | var hasOwnProperty = objectProto.hasOwnProperty; 2865 | 2866 | /** Built-in value references. */ 2867 | var propertyIsEnumerable = objectProto.propertyIsEnumerable; 2868 | 2869 | /** 2870 | * Checks if `value` is likely an `arguments` object. 2871 | * 2872 | * @static 2873 | * @memberOf _ 2874 | * @since 0.1.0 2875 | * @category Lang 2876 | * @param {*} value The value to check. 2877 | * @returns {boolean} Returns `true` if `value` is an `arguments` object, 2878 | * else `false`. 2879 | * @example 2880 | * 2881 | * _.isArguments(function() { return arguments; }()); 2882 | * // => true 2883 | * 2884 | * _.isArguments([1, 2, 3]); 2885 | * // => false 2886 | */ 2887 | var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { 2888 | return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && 2889 | !propertyIsEnumerable.call(value, 'callee'); 2890 | }; 2891 | 2892 | module.exports = isArguments; 2893 | 2894 | 2895 | /***/ }), 2896 | /* 65 */ 2897 | /***/ (function(module, exports, __webpack_require__) { 2898 | 2899 | /* WEBPACK VAR INJECTION */(function(module) {var root = __webpack_require__(1), 2900 | stubFalse = __webpack_require__(70); 2901 | 2902 | /** Detect free variable `exports`. */ 2903 | var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; 2904 | 2905 | /** Detect free variable `module`. */ 2906 | var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; 2907 | 2908 | /** Detect the popular CommonJS extension `module.exports`. */ 2909 | var moduleExports = freeModule && freeModule.exports === freeExports; 2910 | 2911 | /** Built-in value references. */ 2912 | var Buffer = moduleExports ? root.Buffer : undefined; 2913 | 2914 | /* Built-in method references for those with the same name as other `lodash` methods. */ 2915 | var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; 2916 | 2917 | /** 2918 | * Checks if `value` is a buffer. 2919 | * 2920 | * @static 2921 | * @memberOf _ 2922 | * @since 4.3.0 2923 | * @category Lang 2924 | * @param {*} value The value to check. 2925 | * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. 2926 | * @example 2927 | * 2928 | * _.isBuffer(new Buffer(2)); 2929 | * // => true 2930 | * 2931 | * _.isBuffer(new Uint8Array(2)); 2932 | * // => false 2933 | */ 2934 | var isBuffer = nativeIsBuffer || stubFalse; 2935 | 2936 | module.exports = isBuffer; 2937 | 2938 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(20)(module))) 2939 | 2940 | /***/ }), 2941 | /* 66 */ 2942 | /***/ (function(module, exports, __webpack_require__) { 2943 | 2944 | var baseKeys = __webpack_require__(41), 2945 | getTag = __webpack_require__(49), 2946 | isArguments = __webpack_require__(64), 2947 | isArray = __webpack_require__(15), 2948 | isArrayLike = __webpack_require__(16), 2949 | isBuffer = __webpack_require__(65), 2950 | isPrototype = __webpack_require__(13), 2951 | isTypedArray = __webpack_require__(67); 2952 | 2953 | /** `Object#toString` result references. */ 2954 | var mapTag = '[object Map]', 2955 | setTag = '[object Set]'; 2956 | 2957 | /** Used for built-in method references. */ 2958 | var objectProto = Object.prototype; 2959 | 2960 | /** Used to check objects for own properties. */ 2961 | var hasOwnProperty = objectProto.hasOwnProperty; 2962 | 2963 | /** 2964 | * Checks if `value` is an empty object, collection, map, or set. 2965 | * 2966 | * Objects are considered empty if they have no own enumerable string keyed 2967 | * properties. 2968 | * 2969 | * Array-like values such as `arguments` objects, arrays, buffers, strings, or 2970 | * jQuery-like collections are considered empty if they have a `length` of `0`. 2971 | * Similarly, maps and sets are considered empty if they have a `size` of `0`. 2972 | * 2973 | * @static 2974 | * @memberOf _ 2975 | * @since 0.1.0 2976 | * @category Lang 2977 | * @param {*} value The value to check. 2978 | * @returns {boolean} Returns `true` if `value` is empty, else `false`. 2979 | * @example 2980 | * 2981 | * _.isEmpty(null); 2982 | * // => true 2983 | * 2984 | * _.isEmpty(true); 2985 | * // => true 2986 | * 2987 | * _.isEmpty(1); 2988 | * // => true 2989 | * 2990 | * _.isEmpty([1, 2, 3]); 2991 | * // => false 2992 | * 2993 | * _.isEmpty({ 'a': 1 }); 2994 | * // => false 2995 | */ 2996 | function isEmpty(value) { 2997 | if (value == null) { 2998 | return true; 2999 | } 3000 | if (isArrayLike(value) && 3001 | (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || 3002 | isBuffer(value) || isTypedArray(value) || isArguments(value))) { 3003 | return !value.length; 3004 | } 3005 | var tag = getTag(value); 3006 | if (tag == mapTag || tag == setTag) { 3007 | return !value.size; 3008 | } 3009 | if (isPrototype(value)) { 3010 | return !baseKeys(value).length; 3011 | } 3012 | for (var key in value) { 3013 | if (hasOwnProperty.call(value, key)) { 3014 | return false; 3015 | } 3016 | } 3017 | return true; 3018 | } 3019 | 3020 | module.exports = isEmpty; 3021 | 3022 | 3023 | /***/ }), 3024 | /* 67 */ 3025 | /***/ (function(module, exports, __webpack_require__) { 3026 | 3027 | var baseIsTypedArray = __webpack_require__(40), 3028 | baseUnary = __webpack_require__(44), 3029 | nodeUtil = __webpack_require__(56); 3030 | 3031 | /* Node.js helper references. */ 3032 | var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; 3033 | 3034 | /** 3035 | * Checks if `value` is classified as a typed array. 3036 | * 3037 | * @static 3038 | * @memberOf _ 3039 | * @since 3.0.0 3040 | * @category Lang 3041 | * @param {*} value The value to check. 3042 | * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. 3043 | * @example 3044 | * 3045 | * _.isTypedArray(new Uint8Array); 3046 | * // => true 3047 | * 3048 | * _.isTypedArray([]); 3049 | * // => false 3050 | */ 3051 | var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; 3052 | 3053 | module.exports = isTypedArray; 3054 | 3055 | 3056 | /***/ }), 3057 | /* 68 */ 3058 | /***/ (function(module, exports) { 3059 | 3060 | /** 3061 | * Gets the last element of `array`. 3062 | * 3063 | * @static 3064 | * @memberOf _ 3065 | * @since 0.1.0 3066 | * @category Array 3067 | * @param {Array} array The array to query. 3068 | * @returns {*} Returns the last element of `array`. 3069 | * @example 3070 | * 3071 | * _.last([1, 2, 3]); 3072 | * // => 3 3073 | */ 3074 | function last(array) { 3075 | var length = array == null ? 0 : array.length; 3076 | return length ? array[length - 1] : undefined; 3077 | } 3078 | 3079 | module.exports = last; 3080 | 3081 | 3082 | /***/ }), 3083 | /* 69 */ 3084 | /***/ (function(module, exports, __webpack_require__) { 3085 | 3086 | var baseRepeat = __webpack_require__(42), 3087 | isIterateeCall = __webpack_require__(53), 3088 | toInteger = __webpack_require__(72), 3089 | toString = __webpack_require__(10); 3090 | 3091 | /** 3092 | * Repeats the given string `n` times. 3093 | * 3094 | * @static 3095 | * @memberOf _ 3096 | * @since 3.0.0 3097 | * @category String 3098 | * @param {string} [string=''] The string to repeat. 3099 | * @param {number} [n=1] The number of times to repeat the string. 3100 | * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. 3101 | * @returns {string} Returns the repeated string. 3102 | * @example 3103 | * 3104 | * _.repeat('*', 3); 3105 | * // => '***' 3106 | * 3107 | * _.repeat('abc', 2); 3108 | * // => 'abcabc' 3109 | * 3110 | * _.repeat('abc', 0); 3111 | * // => '' 3112 | */ 3113 | function repeat(string, n, guard) { 3114 | if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { 3115 | n = 1; 3116 | } else { 3117 | n = toInteger(n); 3118 | } 3119 | return baseRepeat(toString(string), n); 3120 | } 3121 | 3122 | module.exports = repeat; 3123 | 3124 | 3125 | /***/ }), 3126 | /* 70 */ 3127 | /***/ (function(module, exports) { 3128 | 3129 | /** 3130 | * This method returns `false`. 3131 | * 3132 | * @static 3133 | * @memberOf _ 3134 | * @since 4.13.0 3135 | * @category Util 3136 | * @returns {boolean} Returns `false`. 3137 | * @example 3138 | * 3139 | * _.times(2, _.stubFalse); 3140 | * // => [false, false] 3141 | */ 3142 | function stubFalse() { 3143 | return false; 3144 | } 3145 | 3146 | module.exports = stubFalse; 3147 | 3148 | 3149 | /***/ }), 3150 | /* 71 */ 3151 | /***/ (function(module, exports, __webpack_require__) { 3152 | 3153 | var toNumber = __webpack_require__(73); 3154 | 3155 | /** Used as references for various `Number` constants. */ 3156 | var INFINITY = 1 / 0, 3157 | MAX_INTEGER = 1.7976931348623157e+308; 3158 | 3159 | /** 3160 | * Converts `value` to a finite number. 3161 | * 3162 | * @static 3163 | * @memberOf _ 3164 | * @since 4.12.0 3165 | * @category Lang 3166 | * @param {*} value The value to convert. 3167 | * @returns {number} Returns the converted number. 3168 | * @example 3169 | * 3170 | * _.toFinite(3.2); 3171 | * // => 3.2 3172 | * 3173 | * _.toFinite(Number.MIN_VALUE); 3174 | * // => 5e-324 3175 | * 3176 | * _.toFinite(Infinity); 3177 | * // => 1.7976931348623157e+308 3178 | * 3179 | * _.toFinite('3.2'); 3180 | * // => 3.2 3181 | */ 3182 | function toFinite(value) { 3183 | if (!value) { 3184 | return value === 0 ? value : 0; 3185 | } 3186 | value = toNumber(value); 3187 | if (value === INFINITY || value === -INFINITY) { 3188 | var sign = (value < 0 ? -1 : 1); 3189 | return sign * MAX_INTEGER; 3190 | } 3191 | return value === value ? value : 0; 3192 | } 3193 | 3194 | module.exports = toFinite; 3195 | 3196 | 3197 | /***/ }), 3198 | /* 72 */ 3199 | /***/ (function(module, exports, __webpack_require__) { 3200 | 3201 | var toFinite = __webpack_require__(71); 3202 | 3203 | /** 3204 | * Converts `value` to an integer. 3205 | * 3206 | * **Note:** This method is loosely based on 3207 | * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). 3208 | * 3209 | * @static 3210 | * @memberOf _ 3211 | * @since 4.0.0 3212 | * @category Lang 3213 | * @param {*} value The value to convert. 3214 | * @returns {number} Returns the converted integer. 3215 | * @example 3216 | * 3217 | * _.toInteger(3.2); 3218 | * // => 3 3219 | * 3220 | * _.toInteger(Number.MIN_VALUE); 3221 | * // => 0 3222 | * 3223 | * _.toInteger(Infinity); 3224 | * // => 1.7976931348623157e+308 3225 | * 3226 | * _.toInteger('3.2'); 3227 | * // => 3 3228 | */ 3229 | function toInteger(value) { 3230 | var result = toFinite(value), 3231 | remainder = result % 1; 3232 | 3233 | return result === result ? (remainder ? result - remainder : result) : 0; 3234 | } 3235 | 3236 | module.exports = toInteger; 3237 | 3238 | 3239 | /***/ }), 3240 | /* 73 */ 3241 | /***/ (function(module, exports, __webpack_require__) { 3242 | 3243 | var isObject = __webpack_require__(6), 3244 | isSymbol = __webpack_require__(19); 3245 | 3246 | /** Used as references for various `Number` constants. */ 3247 | var NAN = 0 / 0; 3248 | 3249 | /** Used to match leading and trailing whitespace. */ 3250 | var reTrim = /^\s+|\s+$/g; 3251 | 3252 | /** Used to detect bad signed hexadecimal string values. */ 3253 | var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; 3254 | 3255 | /** Used to detect binary string values. */ 3256 | var reIsBinary = /^0b[01]+$/i; 3257 | 3258 | /** Used to detect octal string values. */ 3259 | var reIsOctal = /^0o[0-7]+$/i; 3260 | 3261 | /** Built-in method references without a dependency on `root`. */ 3262 | var freeParseInt = parseInt; 3263 | 3264 | /** 3265 | * Converts `value` to a number. 3266 | * 3267 | * @static 3268 | * @memberOf _ 3269 | * @since 4.0.0 3270 | * @category Lang 3271 | * @param {*} value The value to process. 3272 | * @returns {number} Returns the number. 3273 | * @example 3274 | * 3275 | * _.toNumber(3.2); 3276 | * // => 3.2 3277 | * 3278 | * _.toNumber(Number.MIN_VALUE); 3279 | * // => 5e-324 3280 | * 3281 | * _.toNumber(Infinity); 3282 | * // => Infinity 3283 | * 3284 | * _.toNumber('3.2'); 3285 | * // => 3.2 3286 | */ 3287 | function toNumber(value) { 3288 | if (typeof value == 'number') { 3289 | return value; 3290 | } 3291 | if (isSymbol(value)) { 3292 | return NAN; 3293 | } 3294 | if (isObject(value)) { 3295 | var other = typeof value.valueOf == 'function' ? value.valueOf() : value; 3296 | value = isObject(other) ? (other + '') : other; 3297 | } 3298 | if (typeof value != 'string') { 3299 | return value === 0 ? value : +value; 3300 | } 3301 | value = value.replace(reTrim, ''); 3302 | var isBinary = reIsBinary.test(value); 3303 | return (isBinary || reIsOctal.test(value)) 3304 | ? freeParseInt(value.slice(2), isBinary ? 2 : 8) 3305 | : (reIsBadHex.test(value) ? NAN : +value); 3306 | } 3307 | 3308 | module.exports = toNumber; 3309 | 3310 | 3311 | /***/ }), 3312 | /* 74 */ 3313 | /***/ (function(module, exports, __webpack_require__) { 3314 | 3315 | var baseToString = __webpack_require__(11), 3316 | castSlice = __webpack_require__(45), 3317 | charsEndIndex = __webpack_require__(46), 3318 | stringToArray = __webpack_require__(60), 3319 | toString = __webpack_require__(10); 3320 | 3321 | /** Used to match leading and trailing whitespace. */ 3322 | var reTrimEnd = /\s+$/; 3323 | 3324 | /** 3325 | * Removes trailing whitespace or specified characters from `string`. 3326 | * 3327 | * @static 3328 | * @memberOf _ 3329 | * @since 4.0.0 3330 | * @category String 3331 | * @param {string} [string=''] The string to trim. 3332 | * @param {string} [chars=whitespace] The characters to trim. 3333 | * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. 3334 | * @returns {string} Returns the trimmed string. 3335 | * @example 3336 | * 3337 | * _.trimEnd(' abc '); 3338 | * // => ' abc' 3339 | * 3340 | * _.trimEnd('-_-abc-_-', '_-'); 3341 | * // => '-_-abc' 3342 | */ 3343 | function trimEnd(string, chars, guard) { 3344 | string = toString(string); 3345 | if (string && (guard || chars === undefined)) { 3346 | return string.replace(reTrimEnd, ''); 3347 | } 3348 | if (!string || !(chars = baseToString(chars))) { 3349 | return string; 3350 | } 3351 | var strSymbols = stringToArray(string), 3352 | end = charsEndIndex(strSymbols, stringToArray(chars)) + 1; 3353 | 3354 | return castSlice(strSymbols, 0, end).join(''); 3355 | } 3356 | 3357 | module.exports = trimEnd; 3358 | 3359 | 3360 | /***/ }) 3361 | /******/ ]) 3362 | }; 3363 | 3364 | 3365 | 3366 | function sqlformat(sql) { 3367 | formater = factory() 3368 | return formater.format(sql, {language: 'sql', indent: ' '}) 3369 | } 3370 | 3371 | 3372 | // console.log(sqlformat('SELECT * FROM table1')) 3373 | """ 3374 | 3375 | 3376 | 3377 | def sqlformat(sql): 3378 | # sql 美化 3379 | ctx = js2py.EvalJs() 3380 | ctx.execute(js) 3381 | result = ctx.sqlformat(sql) 3382 | return result 3383 | 3384 | 3385 | 3386 | -------------------------------------------------------------------------------- /sqlx.py: -------------------------------------------------------------------------------- 1 | # sqlx 是一种扩展 sql 的语言 2 | # 目标是打造 "易读易写 方便维护" 的 sql 脚本 3 | # 语法参考 test.sqlx 4 | 5 | # Python3.3 6 | 7 | import os 8 | import sys 9 | import re 10 | import traceback 11 | import pprint 12 | import random 13 | import copy 14 | 15 | 16 | VERSION = '0.2.0' 17 | 18 | 19 | # 构建后添加的头部文字 20 | HEADER = '-- ======== Generated By Sqlx ========\n-- https://github.com/taojy123/sqlx' 21 | 22 | # sqlx 语法注释标记 23 | COMMENT_PREFIX = '-- !' 24 | 25 | # 目前支持的关系运算符 26 | OPERATORS = ['>', '<', '>=', '<=', '==', '!='] 27 | 28 | # 定义转义符 29 | ESCAPE = '\\' 30 | 31 | 32 | class SqlxException(Exception): 33 | 34 | def __init__(self, message): 35 | self.message = message 36 | 37 | def __str__(self): 38 | return self.message 39 | 40 | 41 | def make_sure(flag, message='something went wrong!'): 42 | if not flag: 43 | raise SqlxException(message) 44 | 45 | 46 | def escape(content, escape_map=None): 47 | # 转义处理,先只传原文,语法处理后再次调用该函数,将第一次访问的 escape_map 传入 48 | if escape_map is None: 49 | escape_map = {} 50 | items = re.findall(r'\\\S', content) 51 | for item in items: 52 | value = item[1] 53 | # 如果出现重复随机数会出错,概率太低,不特殊处理了 54 | n = random.randint(1, 99999999) 55 | # 为兼容 python3.3 只能以 .format 方式代替 f'' 56 | key = '[escape{n}]'.format(**locals()) 57 | escape_map[key] = value 58 | content = content.replace(item, key) 59 | return content, escape_map 60 | else: 61 | make_sure(isinstance(escape_map, dict)) 62 | for key, value in escape_map.items(): 63 | content = content.replace(key, value) 64 | return content 65 | 66 | 67 | def remove_space_line(content): 68 | # 移除空行 69 | new_lines = [] 70 | for line in content.splitlines(): 71 | if line.strip(): 72 | new_lines.append(line) 73 | return '\n'.join(new_lines) 74 | 75 | 76 | def remove_gap(content, n): 77 | # 移除过多的空行 比如传入参数为 5 ,则会将文本中 5 个空行替换为 1 个空行 78 | target = '\n' * n 79 | while target in content: 80 | content = content.replace(target, '\n') 81 | return content 82 | 83 | def get_indent(s): 84 | # 获取字符串前有多少个前导空格 85 | return len(s) - len(s.lstrip()) 86 | 87 | 88 | def render(content, var_map, func_map, local_map=None): 89 | # render sqlt content to sql 90 | 91 | key_map = {} 92 | key_map.update(var_map) 93 | if local_map: 94 | key_map.update(local_map) 95 | 96 | # 处理 for 循环,暂时不支持嵌套 97 | for_funcs = re.findall(r'(\{\s*%\s*for\s+(.+?)\s+in\s+(.+?)\s*%\s*\}(.*?)\{\s*%\s*endfor\s*%\s*\})', content, re.S) 98 | for full_func, for_names, for_values, for_content in for_funcs: 99 | for_names = for_names.split('|') 100 | for_values = for_values.split(',') 101 | for_values = [t.split('|') for t in for_values] 102 | # {% for n|m in 1|a,2|b,3|c %} ... {% endfor %} 103 | # => 104 | # for_names = ['n', 'm'] 105 | # for_values = [['1', 'a'], ['2', 'b'], ['3', 'c']] 106 | rendered_funcs = [] 107 | for values in for_values: 108 | local_map = {} 109 | local_map.update(key_map) 110 | for for_name, for_value in zip(for_names, values): 111 | local_map[for_name] = for_value 112 | # local_map => {n: 1, m: a} 113 | rendered_func = render(for_content, var_map, func_map, local_map) 114 | rendered_func = remove_space_line(rendered_func) 115 | rendered_funcs.append(rendered_func) 116 | 117 | rendered_funcs = '\n'.join(rendered_funcs) 118 | content = content.replace(full_func, rendered_funcs) 119 | 120 | # 处理 if 判断,暂时不支持嵌套 121 | if_funcs = re.findall(r'(\{\s*%\s*if(.+?)%\s*\}(.*?)\{\s*%\s*endif\s*%\s*\})', content, re.S) 122 | for full_func, condition, if_content in if_funcs: 123 | # {% if a > b %} ... {% else %} ... {% endif %} 124 | if_content = re.sub(r'\{\s*%\s*else\s*%\s*\}', r'{% else %}', if_content) 125 | ts = if_content.split(r'{% else %}') 126 | make_sure(len(ts) in [1, 2], '{full_func} 内容编写错误!'.format(**locals())) 127 | if_content = ts[0] 128 | if len(ts) == 2: 129 | else_content = ts[1] 130 | else: 131 | else_content = '' 132 | 133 | a1 = a2 = None 134 | for op in OPERATORS: 135 | if op in condition: 136 | make_sure(condition.count(op) == 1, '{condition} 判定条件编写错误!'.format(**locals())) 137 | a1, a2 = condition.split(op) 138 | a1 = a1.strip() 139 | a2 = a2.strip() 140 | break 141 | make_sure(a1 and a2, '{condition} 未找到合法的关系运算符!'.format(**locals())) 142 | 143 | # 判断项默认以字符串类型比较 144 | # 如果以 $ 开头后接变量名,则转为对应的变量值 145 | if a1.startswith('$') and a1[1:] in key_map: 146 | a1 = key_map[a1[1:]] 147 | 148 | if a2.startswith('$') and a2[1:] in key_map: 149 | a2 = key_map[a2[1:]] 150 | 151 | # 先尝试将两个变量转为数字类型再比较 152 | try: 153 | a1 = float(a1) 154 | except ValueError as e: 155 | pass 156 | try: 157 | a2 = float(a2) 158 | except ValueError as e: 159 | pass 160 | 161 | a1 = repr(a1) 162 | a2 = repr(a2) 163 | s = '{a1} {op} {a2}'.format(**locals()) 164 | 165 | try: 166 | result = eval(s) 167 | except Exception as e: 168 | print(condition) 169 | print(s) 170 | raise e 171 | 172 | make_sure(result in (True, False)) 173 | 174 | if result: 175 | rendering_content = if_content 176 | else: 177 | rendering_content = else_content 178 | 179 | rendered_func = render(rendering_content, var_map, func_map, key_map) 180 | rendered_func = remove_space_line(rendered_func) 181 | content = content.replace(full_func, rendered_func) 182 | 183 | # 处理 var 替换和 func (func) 替换 184 | tags = re.findall(r'\{.+?\}', content) 185 | tags = set(tags) 186 | rendered_map = {} 187 | for tag in tags: 188 | key = tag.strip('{}').strip() 189 | if '(' not in key: 190 | make_sure(key in key_map, '`{tag}` var 引用未找到!'.format(**locals())) 191 | value = key_map[key] 192 | # 对于简单的变量替换,直接 replace 就行了 193 | content = content.replace(tag, value) 194 | else: 195 | rs = re.findall(r'(.+?)\((.*?)\)', key) 196 | make_sure(len(rs) == 1, '`{tag}` func 引用语法不正确!'.format(**locals())) 197 | func_name, params = rs[0] 198 | make_sure(func_name in func_map, '`{tag}` func 引用未找到!'.format(**locals())) 199 | func_content = func_map[func_name]['content'] 200 | param_names = func_map[func_name]['params'] 201 | params = params.split(',') 202 | params = [param.strip() for param in params if param.strip()] 203 | make_sure(len(param_names) == len(params), '{tag} func 参数数量不正确!'.format(**locals())) 204 | local_map = copy.copy(key_map) 205 | for name, value in zip(param_names, params): 206 | if value.startswith('$') and value[1:] in key_map: 207 | value = key_map[value[1:]] 208 | local_map[name] = value 209 | rendered_func = render(func_content, var_map, func_map, local_map) 210 | # 对于块替换,为了更好的视觉体验,先将渲染后的块内容保存下来,接下来用到 211 | rendered_map[tag] = rendered_func 212 | 213 | lines = content.splitlines() 214 | new_lines = [] 215 | for line in lines: 216 | for tag in rendered_map.keys(): 217 | if tag in line: 218 | # 遍历每一行,替换行中的块内容,并加上合适的缩进 219 | # 例如 `select * from {myfunc()} where 1=1` 渲染后得到: 220 | # select * from 221 | # ( 222 | # SELECT 223 | # id, name 224 | # FROM 225 | # mytable 226 | # ) AS myfunc 227 | # where 1=1 228 | n = get_indent(line) 229 | n = n - 4 if n >= 4 else 0 # 假设用户会在 func 中缩进 4 格 230 | rendered_func = rendered_map[tag] 231 | rendered_func = rendered_func.replace('\n', '\n' + ' ' * n) 232 | rendered_func = '\n' + ' ' * n + rendered_func + '\n' + ' ' * n 233 | # 先尝试替换 tag 两边有空格的情况 234 | tag2 = ' {tag} '.format(**locals()) 235 | line = line.replace(tag2 , rendered_func) 236 | line = line.replace(tag, rendered_func) 237 | new_lines.append(line) 238 | content = '\n'.join(new_lines) 239 | 240 | return content 241 | 242 | 243 | def handle_import(content, path, var_map, func_map): 244 | # 处理 import 和 sqlx 注释 245 | # 通过 import 可以引入现有的 sqlx 脚本文件作,但只能导入其中的 var 和 func 246 | # 如果在当前脚本有重复同名变量或 func,会被覆盖以当前脚本为准 247 | # import xxx 248 | 249 | make_sure(isinstance(var_map, dict)) 250 | make_sure(isinstance(func_map, dict)) 251 | if not path: 252 | path = os.getcwd() 253 | make_sure(os.path.isdir(path), '{path} 脚本所在目录不正确!'.format(**locals())) 254 | 255 | # 插入第一行空行 256 | new_lines = [''] 257 | lines = content.splitlines() 258 | for line in lines: 259 | 260 | if line.startswith(COMMENT_PREFIX): 261 | continue 262 | 263 | if COMMENT_PREFIX in line: 264 | i = line.find(COMMENT_PREFIX) 265 | line = line[:i] 266 | 267 | if line.lower().startswith('import '): 268 | items = line.split() 269 | make_sure(len(items) == 2, '`{line}` import 语法不正确!'.format(**locals())) 270 | var, script_name = items 271 | script_name += '.sqlx' 272 | script_path = os.path.join(path, script_name) 273 | make_sure(os.path.isfile(script_path), '{script_path} 导入模块路径不正确!'.format(**locals())) 274 | 275 | script_content = open(script_path, encoding='utf8').read() 276 | script_content = handle_import(script_content, path, var_map, func_map) 277 | script_content = handle_var(script_content, var_map) 278 | script_content = handle_func(script_content, func_map) 279 | 280 | continue 281 | 282 | new_lines.append(line) 283 | 284 | sqlx_content = '\n'.join(new_lines) 285 | 286 | # pprint.pprint(var_map) 287 | # pprint.pprint(func_map) 288 | return sqlx_content 289 | 290 | 291 | def handle_var(content, var_map): 292 | # 处理 var 293 | # var a = xxx 294 | make_sure(isinstance(var_map, dict)) 295 | new_lines = [] 296 | lines = content.splitlines() 297 | for line in lines: 298 | # 兼容老版本 define 写法 299 | if line.lower().startswith('var ') or line.lower().startswith('define '): 300 | # `var a = xxx` 与 `var a xxx` 两种写法都可以 301 | line = line.replace('=', ' ', 1) 302 | items = line.split() 303 | make_sure(len(items) == 3, '`{line}` var 语法不正确!'.format(**locals())) 304 | var, key, value = items 305 | var_map[key] = value 306 | continue 307 | new_lines.append(line) 308 | 309 | sqlx_content = '\n'.join(new_lines) 310 | 311 | # pprint.pprint(var_map) 312 | return sqlx_content 313 | 314 | 315 | def handle_func(content, func_map): 316 | make_sure(isinstance(func_map, dict)) 317 | # 处理 func 318 | # func foo() 319 | # ... 320 | # end 321 | 322 | # foo() 后面加不加:都可以 323 | func_pattern = r'\nfunc\s+(.+?)\((.*?)\)[:\s]*\n(.*?)\nend' 324 | funcs = re.findall(func_pattern, content, re.S) 325 | content = re.sub(func_pattern, '', content, flags=re.S) 326 | 327 | # 兼容老版本 block foo() ... endblock 写法 328 | func_pattern_old = r'\nblock\s+(.+?)\((.*?)\)[:\s]*\n(.*?)\nendblock' 329 | funcs += re.findall(func_pattern_old, content, re.S) 330 | content = re.sub(func_pattern_old, '', content, flags=re.S) 331 | 332 | for func in funcs: 333 | func_name, params, func_content = func 334 | params = params.split(',') 335 | params = [param.strip() for param in params if param.strip()] 336 | func_map[func_name] = { 337 | 'params': params, 338 | 'content': func_content, 339 | } 340 | # pprint.pprint(func_map) 341 | return content 342 | 343 | 344 | def build(content, pretty=False, path=''): 345 | # build sqlx content to sql 346 | 347 | content, escape_map = escape(content) 348 | 349 | var_map = {} 350 | func_map = {} 351 | 352 | content = handle_import(content, path, var_map, func_map) 353 | content = handle_var(content, var_map) 354 | content = handle_func(content, func_map) 355 | 356 | sql = render(content, var_map, func_map) 357 | sql = sql.strip() 358 | sql = escape(sql, escape_map) 359 | sql = remove_gap(sql, 5) 360 | header = HEADER 361 | sql = '{header}\n\n{sql}\n'.format(**locals()) 362 | 363 | # print(sql) 364 | 365 | if pretty: 366 | import sqlformat 367 | sql = sqlformat.sqlformat(sql) 368 | 369 | return sql 370 | 371 | 372 | def auto(path='.', pretty=False): 373 | 374 | import pyperclip 375 | 376 | # pip intall sqlx 377 | # sqlx [path/to/sqlxfiles] 378 | version = VERSION 379 | print('==== sqlx v{version} ===='.format(**locals())) 380 | 381 | args = sys.argv 382 | if len(args) > 1: 383 | path = args[1] 384 | 385 | if 'pretty' in args: 386 | pretty = True 387 | 388 | if os.path.isdir(path): 389 | files = os.listdir(path) 390 | files = [file for file in files if file.endswith('.sqlx')] 391 | elif os.path.isfile(path) and path.endswith('.sqlx'): 392 | files = [path] 393 | else: 394 | print('Usage: sqlx path/to/sqlxfiles') 395 | return 1 396 | 397 | for file in files: 398 | # build xx.sqlx to dist/xx.sql 399 | 400 | print('building', file) 401 | 402 | # sqlx 脚本所在目录 403 | dirname, filename = os.path.split(file) 404 | 405 | # 要生成的 sql 所在目录 406 | distname = os.path.join(dirname, 'dist') 407 | 408 | # 要生成的 sql 文件路径 409 | filename = os.path.join(distname, filename[:-1]) 410 | 411 | if not os.path.isdir(distname): 412 | os.makedirs(distname) 413 | 414 | sqlx_content = '' 415 | for encoding in ['utf8', 'gbk']: 416 | try: 417 | sqlx_content = open(file, encoding=encoding).read() 418 | break 419 | except Exception as e: 420 | encoding = None 421 | 422 | if not encoding: 423 | print(file, 'read failed!') 424 | continue 425 | 426 | sql_content = build(sqlx_content, pretty, dirname) 427 | copied = '' 428 | if os.path.isfile(filename): 429 | old_content = open(filename, encoding=encoding).read() 430 | if sql_content != old_content: 431 | pyperclip.copy(sql_content) 432 | copied = 'and Copied' 433 | else: 434 | pyperclip.copy(sql_content) 435 | copied = 'and Copied' 436 | open(filename, 'w', encoding=encoding).write(sql_content) 437 | print('{filename} Built {copied}'.format(**locals())) 438 | 439 | 440 | if __name__ == '__main__': 441 | try: 442 | auto() 443 | except: 444 | traceback.print_exc() 445 | print('See https://github.com/taojy123/sqlx/blob/master/README.md for help') 446 | input('Press Enter to Exit..') 447 | 448 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import sqlx 2 | 3 | my_script = r""" 4 | define cc dd 5 | SELECT * FROM table1 WHERE name = 'aa\{bb\}{cc}' 6 | """ 7 | 8 | sql = sqlx.build(my_script) 9 | print(sql) -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # todo 2 | 3 | 4 | - define ok 5 | - block ok 6 | - for ok 7 | - if ok 8 | - PYPI ok 9 | - readme ok 10 | - escape ok 11 | - 自动复制 ok 12 | - import ok 13 | - unittest 14 | - SublimeText 插件 ok 15 | - if 嵌套 16 | - for 嵌套 17 | - VSCode 插件 18 | --------------------------------------------------------------------------------