From 2737f5eaa1eae034965ea05c37e9e00063226e2f Mon Sep 17 00:00:00 2001 From: Michael Lin Date: Thu, 28 Sep 2023 18:04:40 -0700 Subject: [PATCH] Update to version v5.4.2 --- .eslintrc.js | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- CHANGELOG.md | 30 +- CODE_OF_CONDUCT.md | 28 +- NOTICE.txt | 9 +- README.md | 10 +- assets/Makefile | 2 +- .../documents/blog-samples-final.json | 2 +- bin/build.js | 92 +- bin/check.js | 133 +- bin/check_bucket_ownership.js | 71 +- bin/config.js | 62 +- bin/exports.js | 156 +- bin/json.js | 626 +- bin/launch.js | 425 +- bin/license.js | 95 +- bin/license.txt | 14 +- bin/name.js | 96 +- bin/wait.js | 137 +- deployment/build-s3-dist.sh | 14 +- .../README.md | 1 + docs/PII_Detection_And_Redaction/README.md | 6 +- .../{ => images}/settings.png | Bin docs/Technical Information.md | 24 +- .../VPC_support/README.md | 0 .../bot_routing/README.md | 2 +- .../images}/botroutingconfig.png | Bin .../README.md} | 0 .../README.md} | 0 docs/custom_domain_name_setup/README.md | 4 +- .../{ => images}/deploy_api_action.png | Bin .../{ => images}/stage_variables.png | Bin docs/custom_terminology_guide/README.md | 16 +- .../custom_terminology_disabled.png | Bin .../custom_terminology_enabled.png | Bin .../{ => images}/settings.png | Bin .../{ => images}/terminology1.png | Bin .../{ => images}/terminology_uploaded.png | Bin .../{ => images}/tools.png | Bin .../{ => images}/translate_question.png | Bin .../{ => images}/uploadterminology.png | Bin docs/excel_import/README.md | 12 +- .../{ => images}/DesignerMapping1.png | Bin .../{ => images}/DesignerMapping2.png | Bin .../excel_import/{ => images}/afterimport.png | Bin docs/excel_import/{ => images}/import.png | Bin docs/excel_import/{ => images}/schema.png | Bin docs/excel_import/{ => images}/schema2.png | Bin .../README.md} | 0 docs/intent_slot_matching/README.md | 6 +- .../{ => images}/qid_intent_slot_config.png | Bin .../{ => images}/slottype_config.png | Bin docs/kendra_crawler_guide/README.md | 13 +- .../{ => images}/IndexDialog.png | Bin .../{ => images}/NoIndexDialog.png | Bin .../{ => images}/cloudwatch.png | Bin .../{ => images}/settings.png | Bin .../{ => images}/tools.png | Bin .../README.md} | 6 +- docs/kendra_redirect/README.md | 2 +- .../{ => images}/kendra_redirect.png | Bin docs/lambda_hooks/README.md | 15 +- docs/{ => lambda_hooks}/lambda_hook_sdk.MD | 0 .../README.md} | 0 docs/overview/README.md | 14 +- docs/overview/image2.png | Bin 118886 -> 0 bytes docs/overview/images/image2.png | Bin 0 -> 162078 bytes docs/overview/{ => images}/image9.png | Bin docs/{qnabot_cli.md => qnabot_cli/README.md} | 4 +- .../README.md | 22 +- .../{ => images}/Import.png | Bin .../{ => images}/Import_qnabank.png | Bin .../{ => images}/add settings.jpg | Bin .../{ => images}/add_lex_button.png | Bin .../{ => images}/add_new_setting.png | Bin .../{ => images}/advanced.png | Bin .../{ => images}/import_dialog.png | Bin .../{ => images}/loaded_settings.png | Bin .../{ => images}/question_list.png | Bin .../{ => images}/response_card.png | Bin .../{ => images}/textract.png | Bin docs/settings.md | 3 +- .../tuning_accuracy_guide/README.md | 40 +- .../tuning_accuracy_guide/images}/image1.png | Bin .../tuning_accuracy_guide/images}/image10.png | Bin docs/tuning_accuracy_guide/images/image2.png | Bin 0 -> 162078 bytes .../tuning_accuracy_guide/images}/image3.png | Bin .../tuning_accuracy_guide/images}/image4.png | Bin .../tuning_accuracy_guide/images}/image5.png | Bin .../tuning_accuracy_guide/images}/image6.png | Bin .../tuning_accuracy_guide/images}/image7.png | Bin .../tuning_accuracy_guide/images}/image8.png | Bin .../tuning_accuracy_guide/images}/image9.png | Bin docs/using_cloud9/README.md | 10 +- docs/using_cloud9/{ => images}/cloudshell.png | Bin lambda/aws-sdk-layer/package-lock.json | 4 +- lambda/aws-sdk-layer/package.json | 4 +- lambda/cfn-lambda-layer/package-lock.json | 4 +- lambda/cfn-lambda-layer/package.json | 4 +- lambda/cfn/index.js | 113 +- lambda/cfn/lib/ApiDeployment.js | 154 +- lambda/cfn/lib/CognitoDomain.js | 81 +- lambda/cfn/lib/CognitoLogin.js | 92 +- lambda/cfn/lib/CognitoRole.js | 107 +- lambda/cfn/lib/CognitoUrl.js | 64 +- lambda/cfn/lib/ESCognitoClient.js | 100 +- lambda/cfn/lib/LambdaVersion.js | 41 +- lambda/cfn/lib/PostUpgradeImport.js | 153 +- lambda/cfn/lib/PreUpgradeExport.js | 112 +- lambda/cfn/lib/S3Clear.js | 103 +- lambda/cfn/lib/S3Lambda.js | 46 +- lambda/cfn/lib/S3Unzip.js | 118 +- lambda/cfn/lib/S3Version.js | 81 +- lambda/cfn/lib/Variable.js | 63 +- lambda/cfn/lib/base.js | 31 +- lambda/cfn/lib/lex.js | 787 +- lambda/cfn/lib/util/aws.js | 25 +- lambda/cfn/lib/util/promise.js | 95 +- lambda/cfn/lib/util/response.js | 109 +- lambda/cfn/package-lock.json | 4 +- lambda/cfn/package.json | 4 +- lambda/cfn/test/index.js | 190 +- lambda/cfn/test/lex.js | 102 +- lambda/cfn/test/mock/cert.pem | 15 - lambda/cfn/test/mock/index.js | 63 +- lambda/cfn/test/mock/key.pem | 15 - lambda/cfn/test/params/api.deploy.js | 44 +- lambda/cfn/test/params/base.js | 37 +- lambda/cfn/test/params/domain.js | 47 +- lambda/cfn/test/params/es.js | 58 +- lambda/cfn/test/params/login.js | 47 +- lambda/cfn/test/params/role.js | 77 +- lambda/cfn/test/params/s3-clear.js | 68 +- lambda/cfn/test/params/s3-unzip.js | 83 +- lambda/cfn/test/params/s3-version.js | 63 +- lambda/cfn/test/params/url.js | 53 +- lambda/cfn/test/params/var.js | 37 +- lambda/cfn/test/setup.js | 59 +- lambda/common-modules-layer/package-lock.json | 4 +- lambda/common-modules-layer/package.json | 4 +- lambda/connect/index.js | 77 +- lambda/connect/jest.config.js | 14 +- lambda/connect/package-lock.json | 4 +- lambda/connect/package.json | 2 +- lambda/connect/test/contactflow.fixtures.js | 14 +- lambda/connect/test/index.test.js | 18 +- lambda/es-proxy-layer/lib/aws.js | 10 +- lambda/es-proxy-layer/lib/cfn.js | 279 +- lambda/es-proxy-layer/lib/cleanmetrics.js | 76 +- .../lib/dialog-event/processDialogEvent.js | 44 + .../lib/dialog-event/processSlots.js | 79 + lambda/es-proxy-layer/lib/embeddings.js | 52 +- lambda/es-proxy-layer/lib/es-logging.js | 177 +- lambda/es-proxy-layer/lib/es_query.js | 194 +- lambda/es-proxy-layer/lib/esbodybuilder.js | 393 +- .../lib/fulfillment-event/encryptor.js | 20 + .../evaluateConditionalChaining.js | 109 + .../lib/fulfillment-event/getHit.js | 322 + .../lib/fulfillment-event/invokeLambda.js | 53 + .../lib/fulfillment-event/mergeNext.js | 67 + .../processFulfillmentEvent.js | 209 + .../lib/fulfillment-event/runKendraQuery.js | 54 + .../lib/fulfillment-event/runLlmQa.js | 98 + .../lib/fulfillment-event/updateResWithHit.js | 169 + lambda/es-proxy-layer/lib/handlebars.js | 541 +- lambda/es-proxy-layer/lib/handler.js | 167 +- .../lib/hits_topic_tiebreaker.js | 60 +- lambda/es-proxy-layer/lib/kendra.js | 956 +- lambda/es-proxy-layer/lib/kendraQuery.js | 293 +- lambda/es-proxy-layer/lib/kendraRetrieve.js | 195 +- lambda/es-proxy-layer/lib/keywords.js | 141 +- lambda/es-proxy-layer/lib/llm.js | 299 +- lambda/es-proxy-layer/lib/qid.js | 81 +- lambda/es-proxy-layer/lib/query.js | 881 +- lambda/es-proxy-layer/lib/request.js | 155 +- .../es-proxy-layer/lib/supportedLanguages.js | 631 +- lambda/es-proxy-layer/lib/translate.js | 169 +- lambda/es-proxy-layer/lib/utterances.js | 131 +- lambda/es-proxy-layer/package-lock.json | 5 +- lambda/es-proxy-layer/package.json | 5 +- lambda/export/createFAQ.js | 317 +- lambda/export/index.js | 97 +- lambda/export/kendraSync.js | 143 +- lambda/export/lib/clean.js | 62 +- lambda/export/lib/join.js | 59 +- lambda/export/lib/load.js | 121 +- lambda/export/lib/start.js | 77 +- lambda/export/lib/step.js | 48 +- lambda/export/package-lock.json | 4 +- lambda/export/package.json | 4 +- lambda/export/parseJSON.js | 93 +- lambda/export/test/automateSyncTest.js | 97 +- lambda/export/test/gen.js | 63 +- lambda/export/test/index.js | 81 +- lambda/export/test/syncEvent.json | 5 +- lambda/fulfillment/index.js | 55 +- lambda/fulfillment/lib/aws.js | 24 +- lambda/fulfillment/lib/middleware/1_parse.js | 242 +- .../lib/middleware/2_preprocess.js | 311 +- lambda/fulfillment/lib/middleware/3_query.js | 184 +- lambda/fulfillment/lib/middleware/4_hook.js | 98 +- .../fulfillment/lib/middleware/5_assemble.js | 204 +- lambda/fulfillment/lib/middleware/6_cache.js | 36 +- .../fulfillment/lib/middleware/7_userInfo.js | 75 +- lambda/fulfillment/lib/middleware/alexa.js | 292 +- lambda/fulfillment/lib/middleware/jwt.js | 109 +- lambda/fulfillment/lib/middleware/lex.js | 399 +- .../fulfillment/lib/middleware/lexRouter.js | 444 +- .../lib/middleware/multilanguage.js | 147 +- .../fulfillment/lib/middleware/sentiment.js | 55 +- .../lib/middleware/specialtyBotRouter.js | 415 +- lambda/fulfillment/lib/middleware/util.js | 159 +- lambda/fulfillment/lib/router/index.js | 78 +- lambda/fulfillment/lib/warmer/index.js | 239 +- lambda/fulfillment/package-lock.json | 4 +- lambda/fulfillment/package.json | 4 +- lambda/fulfillment/test/index.js | 170 +- lambda/fulfillment/test/lex/index.js | 13 + lambda/fulfillment/test/setup.js | 85 +- lambda/fulfillment/test/setupenv.js | 76 +- lambda/genesys/flowsv2/QnABot-CallFlow.yaml | 14 +- lambda/genesys/index.js | 58 +- lambda/genesys/jest.config.js | 14 +- lambda/genesys/package-lock.json | 4 +- lambda/genesys/package.json | 2 +- lambda/genesys/test/callflow.fixtures.yaml | 14 +- lambda/genesys/test/index.test.js | 18 +- lambda/import/convert-xlsx.js | 366 +- lambda/import/delete_existing_content.js | 95 +- lambda/import/index.js | 501 +- lambda/import/package-lock.json | 4 +- lambda/import/package.json | 4 +- lambda/import/test/gen.js | 48 +- lambda/import/test/index.js | 83 +- lambda/js_lambda_hook_sdk/jest.config.js | 14 +- .../lambda_hook_sdk/hooks.js | 216 +- lambda/js_lambda_hook_sdk/package-lock.json | 4 +- lambda/js_lambda_hook_sdk/package.json | 4 +- .../js_lambda_hook_sdk/test/hooks.fixtures.js | 14 +- lambda/js_lambda_hook_sdk/test/hooks.test.js | 14 +- .../kendra_webcrawler_schedule_updater.py | 46 +- .../kendra_webcrawler_status.py | 30 +- lambda/kendra-webcrawler/kendra_webcrawler.py | 92 +- lambda/lex-build/index.js | 27 +- lambda/lex-build/lib/alias.js | 37 +- lambda/lex-build/lib/aws.js | 10 +- lambda/lex-build/lib/bot.js | 97 +- lambda/lex-build/lib/connection.js | 35 +- lambda/lex-build/lib/delete.js | 59 +- lambda/lex-build/lib/index.js | 44 +- lambda/lex-build/lib/intent.js | 50 +- lambda/lex-build/lib/intentFallback.js | 52 +- lambda/lex-build/lib/lexv1bot.js | 155 +- lambda/lex-build/lib/lexv2bot.js | 66 +- lambda/lex-build/lib/qidsandquestions.js | 104 +- lambda/lex-build/lib/run.js | 70 +- lambda/lex-build/lib/slot.js | 54 +- lambda/lex-build/lib/statusv1.js | 44 +- lambda/lex-build/lib/statusv2.js | 44 +- lambda/lex-build/lib/utterances.js | 70 +- lambda/lex-build/lib/wait.js | 40 +- lambda/lex-build/package-lock.json | 4 +- lambda/lex-build/package.json | 4 +- lambda/lex-build/test/index.js | 31 +- lambda/lex-build/test/setup.js | 28 +- lambda/lexv2-build/handler.py | 1124 +- lambda/proxy-es/index.js | 53 +- lambda/proxy-es/package-lock.json | 4 +- lambda/proxy-es/package.json | 4 +- lambda/proxy-es/resource.js | 15 +- lambda/qnabot-common-layer/jest.config.js | 14 +- lambda/qnabot-common-layer/package-lock.json | 4 +- lambda/qnabot-common-layer/package.json | 2 +- lambda/qnabot-common-layer/qnabot/logging.js | 203 +- lambda/qnabot-common-layer/qnabot/settings.js | 106 +- .../test/logging.fixtures.js | 14 +- .../qnabot-common-layer/test/logging.test.js | 14 +- .../test/settings.fixtures.js | 14 +- .../qnabot-common-layer/test/settings.test.js | 14 +- lambda/schema/index.js | 25 +- lambda/schema/jest.config.js | 14 +- lambda/schema/package-lock.json | 4 +- lambda/schema/package.json | 2 +- lambda/schema/qna.js | 514 +- lambda/schema/quiz.js | 256 +- lambda/schema/slottype.js | 94 +- lambda/schema/test/index.test.js | 14 +- lambda/schema/text.js | 302 +- lambda/test.js | 30 +- lambda/testall/README.md | 2 +- lambda/testall/index.js | 109 +- lambda/testall/lib/clean.js | 65 +- lambda/testall/lib/lex.js | 135 +- lambda/testall/lib/load.js | 130 +- lambda/testall/lib/start.js | 82 +- lambda/testall/lib/step.js | 49 +- lambda/testall/package-lock.json | 4 +- lambda/testall/package.json | 4 +- lambda/translate/index.js | 137 +- lambda/translate/jest.config.js | 14 +- lambda/translate/package-lock.json | 4 +- lambda/translate/package.json | 2 +- lambda/translate/test/index.test.js | 14 +- lambda/translate/test/translate.fixtures.js | 14 +- ml_model/embedding/package-model.sh | 2 +- package-lock.json | 5819 ++++--- package.json | 27 +- run-all-tests.sh | 14 +- source/aws_solutions/core/__init__.py | 14 +- source/aws_solutions/core/config.py | 14 +- source/aws_solutions/core/helpers.py | 14 +- source/aws_solutions/core/logging.py | 14 +- source/aws_solutions/qnabot/cli/__init__.py | 14 +- source/aws_solutions/qnabot/cli/qnabot_cli.py | 16 +- .../qnabot/cli/qnabot_cli_helper.py | 14 +- source/requirements-test.txt | 2 +- source/run-pytest.py | 14 +- source/tests/__init__.py | 14 +- source/tests/aws_solutions/core/__init__.py | 14 +- .../tests/aws_solutions/core/test_helpers.py | 14 +- .../tests/aws_solutions/core/test_logging.py | 14 +- .../core/test_solution_config.py | 14 +- source/tests/aws_solutions/qnabot/__init__.py | 14 +- .../fixtures/cloudformation_fixtures.py | 14 +- .../qnabot/fixtures/s3_fixtures.py | 14 +- .../aws_solutions/qnabot/test_helpers.py | 14 +- source/tests/conftest.py | 14 +- templates/dev/README.md | 2 +- templates/dev/api.js | 116 +- templates/dev/bootstrap/handler.js | 97 +- templates/dev/bootstrap/index.js | 284 +- templates/dev/bucket.js | 227 +- templates/dev/cognito.js | 155 +- templates/dev/lambda.js | 119 +- templates/dev/master.js | 54 +- templates/examples/examples/cfn.js | 83 +- .../examples/examples/repromptDemo.json | 2 +- templates/examples/examples/index.js | 776 +- templates/examples/examples/js/Quiz.js | 369 +- templates/examples/examples/js/hook.js | 34 +- templates/examples/examples/package-lock.json | 4 +- templates/examples/examples/package.json | 4 +- templates/examples/examples/py/BotBroker.py | 126 +- .../examples/examples/py/ConnectCallback.py | 53 +- templates/examples/examples/py/Feedback.py | 96 +- templates/examples/examples/py/Next.py | 156 +- templates/examples/examples/py/Previous.py | 104 +- templates/examples/examples/py/hello.py | 19 +- .../examples/examples/responsebots-lexv2.js | 4187 ++--- templates/examples/examples/responsebots.js | 3060 ++-- templates/examples/extensions/README.md | 2 +- templates/examples/extensions/index.js | 667 +- .../CreateRecentTopicsResponse.js | 150 +- .../package-lock.json | 4 +- .../CreateRecentTopicsResponse/package.json | 4 +- .../CustomJSHook/CustomJSHook.js | 22 +- .../CustomJSHook/package-lock.json | 4 +- .../js_lambda_hooks/CustomJSHook/package.json | 4 +- .../CanvasLMSHook/CanvasLMSHelper.py | 292 +- .../CanvasLMSHook/CanvasLMSHook.py | 77 +- .../CustomPYHook/CustomPYHook.py | 13 + .../extensions/ui_imports/package-lock.json | 4 +- .../extensions/ui_imports/package.json | 4 +- .../extensions/ui_imports/ui_import.js | 91 +- templates/examples/index.js | 110 +- templates/examples/outputs.js | 77 +- templates/export/bucket.js | 111 +- templates/export/index.js | 114 +- templates/export/outputs.js | 21 +- templates/export/resources.js | 1219 +- templates/import/UpgradeAutoImport.js | 99 +- templates/import/bucket.js | 109 +- templates/import/index.js | 111 +- templates/import/outputs.js | 19 +- templates/import/resources.js | 333 +- templates/lib/response.js | 53 +- templates/master/UpgradeAutoExport.js | 157 +- templates/master/appregistry.js | 204 +- templates/master/assets.js | 145 +- templates/master/bucket.js | 502 +- templates/master/cfn/handler.js | 48 +- templates/master/cfn/index.js | 195 +- templates/master/cognito/index.js | 480 +- templates/master/cognito/style/client.scss | 1 - .../master/cognito/style/cognito-login.css | 3 +- templates/master/cognito/style/designer.scss | 3 +- templates/master/cognito/style/index.html | 8 +- templates/master/cognito/style/index.js | 39 +- templates/master/config.js | 190 +- templates/master/dashboard/body.js | 31 +- templates/master/dashboard/elasticsearch.js | 145 +- templates/master/dashboard/index.js | 35 +- templates/master/dashboard/lambdas.js | 77 +- templates/master/dashboard/tmp.js | 14 +- templates/master/dashboard/util.js | 95 +- templates/master/default-settings.js | 155 +- templates/master/dynamodb/index.js | 50 +- templates/master/elasticsearch/es.js | 135 +- templates/master/elasticsearch/firehose.js | 504 +- templates/master/elasticsearch/handler.js | 57 +- templates/master/elasticsearch/index.js | 19 +- .../master/elasticsearch/index_mappings.js | 146 +- .../master/elasticsearch/index_settings.js | 111 +- templates/master/elasticsearch/info.js | 101 +- templates/master/elasticsearch/proxy.js | 260 +- templates/master/examples.js | 77 +- templates/master/exportstack.js | 93 +- templates/master/importstack.js | 112 +- templates/master/index.js | 741 +- templates/master/kendrasns.js | 25 +- templates/master/lambda-layers.js | 327 +- templates/master/lambda.js | 61 +- templates/master/lex-build/index.js | 471 +- templates/master/lex-build/poll.js | 88 +- templates/master/lex-build/start.js | 68 +- templates/master/lex/bot.js | 295 +- templates/master/lex/config.js | 26 +- templates/master/lex/fulfillment.js | 1028 +- templates/master/lex/index.js | 19 +- templates/master/lexv2-build/index.js | 313 +- templates/master/proxy-es.js | 983 +- templates/master/proxy-lex/handler.js | 45 +- templates/master/proxy-lex/index.js | 254 +- templates/master/proxy-lex/status.js | 94 +- templates/master/proxy-lex/test.js | 48 +- templates/master/routes/bot/index.js | 102 +- templates/master/routes/bot/test.js | 91 +- templates/master/routes/error/test.js | 44 +- templates/master/routes/examples/handler.js | 126 +- templates/master/routes/examples/index.js | 354 +- templates/master/routes/examples/test.js | 95 +- templates/master/routes/health/index.js | 42 +- templates/master/routes/health/test.js | 34 +- templates/master/routes/images.js | 153 +- templates/master/routes/index.js | 21 +- templates/master/routes/jobs/handler.js | 61 +- templates/master/routes/jobs/index.js | 491 +- templates/master/routes/jobs/test.js | 48 +- templates/master/routes/login.js | 44 +- templates/master/routes/proxy.js | 187 +- templates/master/routes/qa/index.js | 176 +- templates/master/routes/qa/test.js | 125 +- templates/master/routes/root/index.js | 34 +- templates/master/routes/root/test.js | 28 +- templates/master/routes/services/index.js | 38 +- templates/master/routes/services/test.js | 28 +- templates/master/routes/test.js | 33 +- templates/master/routes/util/context.js | 65 +- templates/master/routes/util/lambda.js | 185 +- templates/master/routes/util/mock.js | 80 +- templates/master/routes/util/options.js | 87 +- templates/master/routes/util/redirect.js | 77 +- templates/master/routes/util/resource.js | 34 +- templates/master/routes/util/temp-test.js | 74 +- templates/master/s3.js | 234 +- .../master/sagemaker-embeddings-stack.js | 47 +- .../sagemaker-qa-summarize-llm-stack.js | 49 +- templates/master/schemaLambda.js | 148 +- templates/master/signup/index.js | 274 +- templates/master/signup/message.js | 32 +- templates/master/signup/signup.js | 33 +- templates/master/signup/test.js | 32 +- templates/master/test/hook.zip | Bin 460 -> 0 bytes templates/master/test/hook/index.js | 13 + templates/master/test/index.js | 15 +- templates/master/test/lex.js | 427 +- templates/master/test/quiz.js | 53 +- templates/master/test/routes.js | 86 +- templates/master/test/services.js | 37 +- templates/master/test/util.js | 123 +- templates/master/test/workflows/export.js | 71 +- templates/master/test/workflows/index.js | 128 +- templates/master/tstallstack.js | 61 +- templates/master/var.js | 187 +- templates/public-vpc-support/index.js | 249 +- templates/public/index.js | 193 +- templates/sagemaker-embeddings/index.js | 469 +- templates/sagemaker-qa-summarize-llm/index.js | 441 +- templates/testall/bucket.js | 73 +- templates/testall/index.js | 77 +- templates/testall/outputs.js | 21 +- templates/testall/resources.js | 208 +- templates/util.js | 1066 +- tuning_accuracy_guide/image2.png | Bin 118886 -> 0 bytes utility_scripts/configureAlerts.py | 13 + utility_scripts/configureCMK.py | 13 + utility_scripts/count_user_interactions.js | 115 +- .../create_kendra_faq_resources.js | 227 +- .../csv2json_converter/js/csvToArray.v2.1.js | 182 +- .../js/qnabot_csv2json_converter.js | 370 +- .../qnabot_csv2json_converter_ver_0_1.zip | Bin 6248 -> 0 bytes website/Makefile | 4 +- website/assets/gremlins.min.js | 205 +- website/config/base.config.js | 33 +- website/config/dev.config.js | 28 +- website/config/prod.config.js | 16 +- website/config/test.config.js | 30 +- website/config/webpack.config.js | 30 +- website/entry.js | 23 +- website/html/admin.pug | 5 +- website/html/client.pug | 4 +- website/js/admin.js | 128 +- website/js/admin.vue | 20 +- website/js/browser-check.js | 24 +- website/js/client.js | 172 +- website/js/client.vue | 18 +- website/js/components/alexa/index.vue | 36 +- website/js/components/alexa/steps.js | 81 +- website/js/components/connect/index.vue | 174 +- website/js/components/connect/steps.js | 95 +- website/js/components/customTranslate.vue | 141 +- website/js/components/designer/add.vue | 142 +- website/js/components/designer/alexa.vue | 74 +- website/js/components/designer/crawler.vue | 124 +- website/js/components/designer/delete.vue | 24 +- website/js/components/designer/display.vue | 42 +- website/js/components/designer/edit.vue | 141 +- website/js/components/designer/empty.js | 39 +- website/js/components/designer/event-bus.js | 16 +- website/js/components/designer/index.vue | 20 +- website/js/components/designer/input.vue | 202 +- .../js/components/designer/menu-questions.vue | 26 +- website/js/components/designer/menu-test.vue | 22 +- .../js/components/designer/menu-testall.vue | 58 +- website/js/components/designer/modal.vue | 3 +- website/js/components/designer/qa.vue | 20 +- website/js/components/designer/rebuild.vue | 24 +- website/js/components/designer/synckendra.vue | 37 +- website/js/components/export.vue | 45 +- website/js/components/genesys/index.vue | 53 +- website/js/components/genesys/steps.js | 75 +- website/js/components/hooks/code.js | 20 +- website/js/components/hooks/code.py | 13 + website/js/components/hooks/example.js | 126 +- website/js/components/hooks/index.vue | 49 +- website/js/components/hooks/steps.js | 89 +- website/js/components/import.vue | 67 +- website/js/components/kendraIndex.vue | 46 +- website/js/components/loading.vue | 20 +- website/js/components/settings.vue | 42 +- website/js/lib/client-auth.js | 127 +- website/js/lib/index.js | 18 +- website/js/lib/router.js | 127 +- website/js/lib/store/actions.js | 46 +- website/js/lib/store/api/actions/connect.js | 68 +- website/js/lib/store/api/actions/export.js | 237 +- website/js/lib/store/api/actions/genesys.js | 68 +- website/js/lib/store/api/actions/import.js | 229 +- website/js/lib/store/api/actions/index.js | 418 +- .../js/lib/store/api/actions/kendraIndex.js | 90 +- website/js/lib/store/api/actions/settings.js | 107 +- website/js/lib/store/api/actions/testall.js | 176 +- website/js/lib/store/api/actions/tmp.js | 40 +- website/js/lib/store/api/index.js | 37 +- website/js/lib/store/data/actions/add.js | 158 +- website/js/lib/store/data/actions/delete.js | 104 +- website/js/lib/store/data/actions/get.js | 141 +- website/js/lib/store/data/actions/index.js | 29 +- .../js/lib/store/data/actions/up-download.js | 166 +- website/js/lib/store/data/actions/util.js | 92 +- website/js/lib/store/data/getters.js | 45 +- website/js/lib/store/data/index.js | 37 +- website/js/lib/store/data/mutations.js | 96 +- website/js/lib/store/getters.js | 18 +- website/js/lib/store/index.js | 65 +- website/js/lib/store/mutations.js | 61 +- website/js/lib/store/page/actions.js | 70 +- website/js/lib/store/page/getters.js | 25 +- website/js/lib/store/page/index.js | 41 +- website/js/lib/store/page/mutations.js | 86 +- website/js/lib/store/page/util.js | 140 +- website/js/lib/store/user/actions.js | 240 +- website/js/lib/store/user/getters.js | 20 +- website/js/lib/store/user/index.js | 31 +- website/js/lib/store/user/mutations.js | 43 +- website/js/lib/validator.js | 50 +- website/js/test.js | 27 +- website/styles/fonts/material-icons.css | 19 + website/styles/pure-min.css | 1135 ++ website/styles/vuetify-min.css | 14481 ++++++++++++++++ 580 files changed, 53563 insertions(+), 30925 deletions(-) rename docs/PII_Detection_And_Redaction/{ => images}/settings.png (100%) rename VPCSupportREADME.md => docs/VPC_support/README.md (100%) rename BotRoutingREADME.md => docs/bot_routing/README.md (99%) rename docs/{ => bot_routing/images}/botroutingconfig.png (100%) rename docs/{canvaslms_integration.md => canvaslms_integration/README.md} (100%) rename docs/{connect_callback.md => connect_callback/README.md} (100%) rename docs/custom_domain_name_setup/{ => images}/deploy_api_action.png (100%) rename docs/custom_domain_name_setup/{ => images}/stage_variables.png (100%) rename docs/custom_terminology_guide/{ => images}/custom_terminology_disabled.png (100%) rename docs/custom_terminology_guide/{ => images}/custom_terminology_enabled.png (100%) rename docs/custom_terminology_guide/{ => images}/settings.png (100%) rename docs/custom_terminology_guide/{ => images}/terminology1.png (100%) rename docs/custom_terminology_guide/{ => images}/terminology_uploaded.png (100%) rename docs/custom_terminology_guide/{ => images}/tools.png (100%) rename docs/custom_terminology_guide/{ => images}/translate_question.png (100%) rename docs/custom_terminology_guide/{ => images}/uploadterminology.png (100%) rename docs/excel_import/{ => images}/DesignerMapping1.png (100%) rename docs/excel_import/{ => images}/DesignerMapping2.png (100%) rename docs/excel_import/{ => images}/afterimport.png (100%) rename docs/excel_import/{ => images}/import.png (100%) rename docs/excel_import/{ => images}/schema.png (100%) rename docs/excel_import/{ => images}/schema2.png (100%) rename docs/{Handlebars_README.md => handlebars/README.md} (100%) rename docs/intent_slot_matching/{ => images}/qid_intent_slot_config.png (100%) rename docs/intent_slot_matching/{ => images}/slottype_config.png (100%) rename docs/kendra_crawler_guide/{ => images}/IndexDialog.png (100%) rename docs/kendra_crawler_guide/{ => images}/NoIndexDialog.png (100%) rename docs/kendra_crawler_guide/{ => images}/cloudwatch.png (100%) rename docs/kendra_crawler_guide/{ => images}/settings.png (100%) rename docs/kendra_crawler_guide/{ => images}/tools.png (100%) rename docs/{Kendra_Fallback_README.md => kendra_fallback/README.md} (94%) rename docs/kendra_redirect/{ => images}/kendra_redirect.png (100%) rename docs/{ => lambda_hooks}/lambda_hook_sdk.MD (100%) rename docs/{multilanguage_support.md => multilanguage_support/README.md} (100%) delete mode 100755 docs/overview/image2.png create mode 100644 docs/overview/images/image2.png rename docs/overview/{ => images}/image9.png (100%) rename docs/{qnabot_cli.md => qnabot_cli/README.md} (97%) rename docs/recent_topics_lambda_hook_example/{ => images}/Import.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/Import_qnabank.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/add settings.jpg (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/add_lex_button.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/add_new_setting.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/advanced.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/import_dialog.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/loaded_settings.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/question_list.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/response_card.png (100%) rename docs/recent_topics_lambda_hook_example/{ => images}/textract.png (100%) rename tuning_accuracy_guide/AWS_QnABot_tuning_recognition_accuracy_guide.md => docs/tuning_accuracy_guide/README.md (92%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image1.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image10.png (100%) create mode 100644 docs/tuning_accuracy_guide/images/image2.png rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image3.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image4.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image5.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image6.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image7.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image8.png (100%) rename {tuning_accuracy_guide => docs/tuning_accuracy_guide/images}/image9.png (100%) rename docs/using_cloud9/{ => images}/cloudshell.png (100%) delete mode 100644 lambda/cfn/test/mock/cert.pem delete mode 100644 lambda/cfn/test/mock/key.pem create mode 100644 lambda/es-proxy-layer/lib/dialog-event/processDialogEvent.js create mode 100644 lambda/es-proxy-layer/lib/dialog-event/processSlots.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/encryptor.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/evaluateConditionalChaining.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/getHit.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/invokeLambda.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/mergeNext.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/processFulfillmentEvent.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/runKendraQuery.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/runLlmQa.js create mode 100644 lambda/es-proxy-layer/lib/fulfillment-event/updateResWithHit.js delete mode 100644 templates/master/test/hook.zip delete mode 100755 tuning_accuracy_guide/image2.png delete mode 100644 utility_scripts/csv2json_converter/qnabot_csv2json_converter_ver_0_1.zip create mode 100644 website/styles/fonts/material-icons.css create mode 100644 website/styles/pure-min.css create mode 100644 website/styles/vuetify-min.css diff --git a/.eslintrc.js b/.eslintrc.js index 5722a186c..942882731 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { env: { node: true }, - extends: ['eslint:recommended'], + extends: ['eslint:recommended', 'plugin:vue/recommended', 'airbnb-base'], rules: { indent: ['warn', 4], quotes: ['warn', 'single'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 268f9a99e..d5e7197ff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ To get the version of the solution, you can look at the description of the creat - [ ] Region: [e.g. us-east-1] - [ ] Was the solution modified from the version published on this repository? - [ ] If the answer to the previous question was yes, are the changes available on GitHub? -- [ ] Have you checked your [service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) for the sevices this solution uses? +- [ ] Have you checked your [service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) for the services this solution uses? - [ ] Were there any errors in the CloudWatch Logs? **Screenshots** diff --git a/CHANGELOG.md b/CHANGELOG.md index 75c9050c7..f89f21055 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.4.2] - 2023-09-30 +### Added +- Self-hosting web fonts. Font files used by QnABot UI are now served from QnABot server instead of using third party font provider. + +### Updated + +- Security patches for npm and pip packages +- Lambda runtimes updated to NodeJS 18 for CFN Bootstrap Lambda +- SonarQube Quality Gates fix +- Bluebird Promise Migration (Partial) + - Utilize native promises supported in JavaScript + - Full migration planned for v5.5.0. Done as a prerequisite for JavaScript SDK v3 migration planned for v6.0.0 + - Remaining changes to be implemented in v5.5.0 include ./website, ./cfn, & ./templates + +### Fixed +- Fixed request signing issue when using Custom domain ([issue #605](https://github.com/aws-solutions/qnabot-on-aws/issues/605)) +- Fixed voice integration with LLM response +- Fixed unsupported SSML tags +- Fixed Kendra API retrieval bug + ## [5.4.1] - 2023-07-27 ### Updated @@ -122,7 +142,7 @@ __*Note: we recommend that you first deploy these changes in a non-production en ### Updated - Security patches for npm and pip packages -- Added Support for latest LexV2 languages (see [Multi-language Support](docs/multilanguage_support.md)) +- Added Support for latest LexV2 languages (see [Multi-language Support](docs/multilanguage_support/README.md)) - Updated: - English (IN), Spanish (LATAM), Portuguese (PR), Mandarin (PRC) to use neural voice - New languages: @@ -192,10 +212,10 @@ __*Note: we recommend that you first deploy these changes in a non-production en - Intent and Slot matching (an early implementation). This new capability supports creating dedicated custom Intents for a QnABot {Item ID}. You can extend QnABot to support one or more related intents. For example, you might create an intent that makes a car reservation, or assists an agent during a live chat or call (via Amazon Connect). More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/intent_slot_matching/README.md - Support for using custom domain names for QnABot Designer and Client interfaces. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/custom_domain_name_setup/README.md -- AWS QnABot Command Line Interface (CLI) - the AWS QnABot CLI supports the capability to import and export questions and answers via command line. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/qnabot_cli.md +- AWS QnABot Command Line Interface (CLI) - the AWS QnABot CLI supports the capability to import and export questions and answers via command line. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/qnabot_cli/README.md - Kendra Redirect - with the Kendra Redirect feature, you can now include a Kendra query within a Item ID. More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/kendra_redirect/README.md - Integration with Canvas LMS (an early example implementation). Students use their schools' learning management system (LMS) to keep track of their assignments, grades, and their course work. With this integration, students will be able to ask QnABot about their grades, syllabus, enrollments, assignments, and announcements. - More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/canvaslms_integration.md + More details in README: https://github.com/aws-solutions/qnabot-on-aws/blob/main/docs/canvaslms_integration/README.md - Updated import functionality to support importing of QnABot questions and answers from a Excel file when uploaded to S3 data folder. - Added support for importing session attributes via Excel. - Updated runtime of Lambda functions (using Python runtime) to use Python runtime version 3.9. @@ -236,10 +256,10 @@ __*Note: we recommend that you first deploy these changes in a non-production en ### Added -- Expanded language support for voice and text interactions. Also included support for Neural voices for Lex language locales. See [supported languages](docs/multilanguage_support.md#supported-languages). +- Expanded language support for voice and text interactions. Also included support for Neural voices for Lex language locales. See [supported languages](docs/multilanguage_support/README.md#supported-languages). - Expanded `config.json` to support `LexV2BotLocaleIds` parameter. - Updated `LexV2BotLocaleIds` parameter in CloudFormation template to include link to supported languages. -- Updated [Multi Language Support readme](docs/multilanguage_support.md#supported-languages) and added supported languages section. +- Updated [Multi Language Support readme](docs/multilanguage_support/README.md#supported-languages) and added supported languages section. - Updated `ENABLE_MULTI_LANGUAGE_SUPPORT` setting in [Settings readme](docs/settings.md) with link to supported languages. ### Fixed diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index aa84cac18..a0ea08c6a 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,24 +1,4 @@ -# Amazon Open Source Code of Conduct - -This code of conduct provides guidance on participation in Amazon-managed open source communities, and outlines the process for reporting unacceptable behavior. As an organization and community, we are committed to providing an inclusive environment for everyone. Anyone violating this code of conduct may be removed and banned from the community. - -**Our open source communities endeavor to:** -* Use welcoming and inclusive language; -* Be respectful of differing viewpoints at all times; -* Accept constructive criticism and work together toward decisions; -* Focus on what is best for the community and users. - -**Our Responsibility.** As contributors, members, or bystanders we each individually have the responsibility to behave professionally and respectfully at all times. Disrespectful and unacceptable behaviors include, but are not limited to: -The use of violent threats, abusive, discriminatory, or derogatory language; -* Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, race, political or religious affiliation; -* Posting of sexually explicit or violent content; -* The use of sexualized language and unwelcome sexual attention or advances; -* Public or private [harassment](http://todogroup.org/opencodeofconduct/#definitions) of any kind; -* Publishing private information, such as physical or electronic address, without permission; -* Other conduct which could reasonably be considered inappropriate in a professional setting; -* Advocating for or encouraging any of the above behaviors. - -**Enforcement and Reporting Code of Conduct Issues.** -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting opensource-codeofconduct@amazon.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. - -**Attribution.** _This code of conduct is based on the [template](http://todogroup.org/opencodeofconduct) established by the [TODO Group](http://todogroup.org/) and the Scope section from the [Contributor Covenant version 1.4](http://contributor-covenant.org/version/1/4/)._ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. \ No newline at end of file diff --git a/NOTICE.txt b/NOTICE.txt index c96678891..9e2d3172a 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -20,6 +20,9 @@ This software includes third party software subject to the following copyrights: @babel/plugin-transform-runtime under the Massachusetts Institute of Technology (MIT) license @babel/preset-env under the Massachusetts Institute of Technology (MIT) license @babel/preset-stage-2 under the Massachusetts Institute of Technology (MIT) license +@fontsource/material-icons under the Apache License Version 2.0 +@fontsource/roboto under the Apache License Version 2.0 +@fontsource/varela-round under the Open Font License (OFL) 1.1 ajv under the Massachusetts Institute of Technology (MIT) license alexa-sdk under the Apache License Version 2.0 arrow under the Apache License Version 2.0 @@ -61,6 +64,7 @@ elasticsearch under the Apache License Version 2.0 exports-loader under the Massachusetts Institute of Technology (MIT) license express under the Massachusetts Institute of Technology (MIT) license faker under the Massachusetts Institute of Technology (MIT) license +file-loader under the Massachusetts Institute of Technology (MIT) license file-saver under the Massachusetts Institute of Technology (MIT) license filelock under the Unlicense license handlebars under the Massachusetts Institute of Technology (MIT) license @@ -143,4 +147,7 @@ webpack-bundle-analyzer under the Massachusetts Institute of Technology (MIT) li webpack-cli under the Massachusetts Institute of Technology (MIT) license webpack-dev-server under the Massachusetts Institute of Technology (MIT) license webpack-merge under the Massachusetts Institute of Technology (MIT) license -webpack-s3-plugin under the Massachusetts Institute of Technology (MIT) license \ No newline at end of file +webpack-s3-plugin under the Massachusetts Institute of Technology (MIT) license +typing_extensions under Python Software Foundation License +boolean.py under BSD-2-Clause +license-expression under Apache License Version 2.0 \ No newline at end of file diff --git a/README.md b/README.md index 51cdfdf8b..e21bb493a 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Alternatively, if you want to custom deploy QnABot on AWS, refer to the details Navigate to the root directory of QnABot (directory will be created once you have cloned this repo). -Install node.js moodules of QnABot: +Install node.js modules of QnABot: ```shell npm install @@ -117,8 +117,12 @@ Refer to [LICENSE.txt](LICENSE.txt) file for details. Refer to [CHANGELOG.md](CHANGELOG.md) file for details of new features in each version. -A [workshop](https://qnabot.workshop.aws) is also available -that walks you through QnABot features. +A [workshop](https://qnabot.workshop.aws) is also available that walks you through QnABot features. + +## Anonymous Metrics +This solution collects anonymous operational metrics to help AWS improve the +quality of features of the solution. For more information, including how to disable +this capability, please see the [implementation guide](https://docs.aws.amazon.com/solutions/latest/qnabot-on-aws/general-reference.html). --- diff --git a/assets/Makefile b/assets/Makefile index 22063bc3a..11c584879 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -1,3 +1,3 @@ DST=../build/assets.zip $(DST): ./* - echo "Building Assets"; zip -r -x Makefile -q $(DST) . + echo "Building Assets"; zip -FSr -x Makefile -q $(DST) . diff --git a/assets/examples/documents/blog-samples-final.json b/assets/examples/documents/blog-samples-final.json index 7afd957e8..dadcf6990 100644 --- a/assets/examples/documents/blog-samples-final.json +++ b/assets/examples/documents/blog-samples-final.json @@ -204,7 +204,7 @@ "t": "QnABot", "alt": { "markdown": "# QnaBot\nThe Q and A Bot uses [Amazon Lex](https://aws.amazon.com/lex) and [Alexa](https://developer.amazon.com/alexa) to provide a natural language interface for your FAQ knowledge base. Now your users can just ask a *question* and get a quick and relevant *answer*.", - "ssml": "QnABot is great. But I want to tell you a secret. I am not a real human.. Can you believe it? " + "ssml": "AWS QnA Bot is great. QnA Bot supports SSML using Polly's neural voice. I can speak very fast, or very slowly. I can speak quietly, or speak loud and clear. I can say tomato and tomato. Visit docs.aws.amazon.com/polly/latest/dg/supportedtags for more information." }, "l": "", "qid": "QnABot.001", diff --git a/bin/build.js b/bin/build.js index f626f4118..88ef8da6c 100755 --- a/bin/build.js +++ b/bin/build.js @@ -1,29 +1,35 @@ #! /usr/bin/env node -var Promise=require('bluebird') -var fs=Promise.promisifyAll(require('fs')) -process.env.AWS_PROFILE=require('../config.json').profile -process.env.AWS_DEFAULT_REGION=require('../config.json').profile -var aws=require('aws-sdk') -var chalk=require('chalk') -aws.config.setPromisesDependency(Promise) -aws.config.region=require('../config.json').region -var cf=new aws.CloudFormation() -var s3=new aws.S3() -var stringify=require("json-stringify-pretty-compact") -var check=require('./check') -var fs = require('fs'); -var outputs=require('./exports') +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ -if(!module.parent){ - var argv=require('commander') - var ran - var args=argv.version('1.0') +process.env.AWS_PROFILE = require('../config.json').profile; +process.env.AWS_DEFAULT_REGION = require('../config.json').profile; +const aws = require('aws-sdk'); +const chalk = require('chalk'); +aws.config.region = require('../config.json').region; +const stringify = require('json-stringify-pretty-compact'); +const check = require('./check'); +const fs = require('fs').promises; + +if (!module.parent) { + const argv = require('commander'); + const args = argv.version('1.0') .name(process.argv[1].split('/').reverse()[0]) - .option('--verbose',"silent") - .option('--stack ',"stack to build") - .option('--input ',"input file") - .option('--output ',"output file") - .parse(process.argv) + .option('--verbose', 'silent') + .option('--stack ', 'stack to build') + .option('--input ', 'input file') + .option('--output ', 'output file') + .parse(process.argv); const options = argv.opts(); if (options.stack || (options.input && options.output)) { @@ -34,36 +40,32 @@ if(!module.parent){ stack: options.stack, }); } else { - console.log(`error: required options not specified`); + console.log('error: required options not specified'); argv.outputHelp(); process.exit(1); } } -module.exports=create -async function create(options){ - var stack=options.stack - log('building '+(options.stack || options.input),stack,!options.silent) - var file=options.input || __dirname+'/../templates/'+stack - var output=options.output || `${__dirname}/../build/templates/${stack}.json` +module.exports = create; +async function create(options) { + const { stack } = options; + log(`building ${options.stack || options.input}`, stack, !options.silent); + const file = options.input || `${__dirname}/../templates/${stack}`; + const output = options.output || `${__dirname}/../build/templates/${stack}.json`; try { - var temp=await Promise.resolve(require(file)) - var template_string=typeof temp ==="object" ? JSON.stringify(temp) : temp + const temp = await require(file); + const template_string = typeof temp === 'object' ? JSON.stringify(temp) : temp; - log("writing to "+output,!options.silent) + log(`writing to ${output}`, !options.silent); - await fs.writeFileAsync(output,stringify(JSON.parse(template_string))) - await check(stack,{file:output}) - log(chalk.green(stack+" is valid"),!options.silent) - log('finished building '+stack,!options.silent) - }catch(error){ - log(chalk.red(stack+" failed:"+error),!options.silent) + await fs.writeFile(output, stringify(JSON.parse(template_string))); + await check(stack, { file: output }); + log(chalk.green(`${stack} is valid`), !options.silent); + log(`finished building ${stack}`, !options.silent); + } catch (error) { + log(chalk.red(`${stack} failed:${error}`), !options.silent); } } -function log(message,show){ - if(show){console.log(message)} +function log(message, show) { + if (show) { console.log(message); } } - - - - diff --git a/bin/check.js b/bin/check.js index b8e71d53d..9d690b033 100755 --- a/bin/check.js +++ b/bin/check.js @@ -1,83 +1,96 @@ #! /usr/bin/env node -var config=require('../config.json') -var fs=require('fs') -process.env.AWS_PROFILE=config.profile -process.env.AWS_DEFAULT_REGION=config.profile -var aws=require('aws-sdk') -var Promise=require('bluebird') -aws.config.setPromisesDependency(Promise) -aws.config.region=require('../config.json').region -var region=require('../config.json').region -var cf=new aws.CloudFormation() -var s3=new aws.S3() -var name=require('./name') +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ -module.exports=Promise.method(run) +const config = require('../config.json'); +const fs = require('fs').promises; + +process.env.AWS_PROFILE = config.profile; +process.env.AWS_DEFAULT_REGION = config.profile; +const aws = require('aws-sdk'); +aws.config.region = require('../config.json').region; +const { region } = require('../config.json'); + +const cf = new aws.CloudFormation(); +const s3 = new aws.S3(); +const name = require('./name'); + +module.exports = run; if (require.main === module) { - var argv=require('commander') - var ran - var args=argv.version('1.0') + const argv = require('commander'); + let ran; + argv.version('1.0') .name('npm run check') .arguments('') - .description("Check syntax of cloudformation templates") - .usage(" [options]") - .option("--file ","absolute path to template file") - .action(async function(stack,options){ - ran=true - try{ - var result=await run(stack,options) - console.log(`${stack} is Valid`) - }catch(e){ - console.log("Invalid") - console.log(e.message) + .description('Check syntax of cloudformation templates') + .usage(' [options]') + .option('--file ', 'absolute path to template file') + .action(async (stack, options) => { + ran = true; + try { + await run(stack, options); + console.log(`${stack} is Valid`); + } catch (e) { + console.log('Invalid'); + console.log(e.message); } }) - .parse(process.argv) - if(!ran){ - argv.outputHelp() + .parse(process.argv); + if (!ran) { + argv.outputHelp(); } } -async function run(stack,options={}){ - var name=stack || options.file.split('/') +async function run(stack, options = {}) { + const name = stack || options.file.split('/') .reverse() - .filter(x=>x) - .slice(0,2) - .reverse().join('-').split('.')[0] + .filter((x) => x) + .slice(0, 2) + .reverse() + .join('-') + .split('.')[0]; if (config.skipCheckTemplate) { console.log('Skipping check for CFN tempalate'); return new Promise((resolve, reject) => { resolve([]); }); - } else { - var template=await fs.readFileSync(options.file || `${__dirname}/../build/templates/${stack}.json`,'utf8') - console.log('resources: '+Object.keys(JSON.parse(template).Resources).length) - if(Buffer.byteLength(template)>51200){ - var exp=await bootstrap() - var Bucket=exp.Bucket - var prefix=exp.Prefix - var Key=`${prefix}/templates/${stack}.json` - var TemplateURL=`https://${Bucket}.s3.${region}.amazonaws.com/${Key}` - console.log(TemplateURL) - await s3.putObject({Bucket,Key,Body:template}).promise() - return cf.validateTemplate({TemplateURL}).promise() - }else{ - return cf.validateTemplate({ - TemplateBody:template - }).promise() - } } + const templateFile = options.file || `${__dirname}/../build/templates/${stack}.json`; + const template = await fs.readFile(templateFile, 'utf8'); + console.log(`resources: ${Object.keys(JSON.parse(template).Resources).length}`); + if (Buffer.byteLength(template) > 51200) { + const exp = await bootstrap(); + const { Bucket } = exp; + const prefix = exp.Prefix; + const Key = `${prefix}/templates/${stack}.json`; + const TemplateURL = `https://${Bucket}.s3.${region}.amazonaws.com/${Key}`; + console.log(TemplateURL); + await s3.putObject({ Bucket, Key, Body: template }).promise(); + return cf.validateTemplate({ TemplateURL }).promise(); + } + return cf.validateTemplate({ + TemplateBody: template, + }).promise(); } -async function bootstrap(){ - var outputs={} - var tmp=await cf.describeStacks({ - StackName:name("dev/bootstrap",{}) - }).promise() +async function bootstrap() { + const outputs = {}; + const tmp = await cf.describeStacks({ + StackName: name('dev/bootstrap', {}), + }).promise(); - tmp.Stacks[0].Outputs.forEach(x=>outputs[x.OutputKey]=x.OutputValue) - return outputs + tmp.Stacks[0].Outputs.forEach((x) => outputs[x.OutputKey] = x.OutputValue); + return outputs; } - diff --git a/bin/check_bucket_ownership.js b/bin/check_bucket_ownership.js index 3774e307c..f9aabf8cd 100755 --- a/bin/check_bucket_ownership.js +++ b/bin/check_bucket_ownership.js @@ -1,9 +1,22 @@ -const commander = require("commander"); -const aws = require("aws-sdk"); +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ + +const commander = require('commander'); +const aws = require('aws-sdk'); async function getAccountId() { let statusCode; - let account_id = ""; + let account_id = ''; try { const sts = new aws.STS(); const identity = await sts.getCallerIdentity().promise(); @@ -13,7 +26,7 @@ async function getAccountId() { statusCode = error.statusCode; console.error(`Error in getAccountId: ${error.statusCode}, ${error.code}: ${error.message}`); } - return { statusCode: statusCode, account_id: account_id }; + return { statusCode, account_id }; } async function checkBucketOwner(bucket) { @@ -25,7 +38,7 @@ async function checkBucketOwner(bucket) { return resp; } console.debug(`Validating bucket ownership for bucket ${bucket} with account_id ${accountResp.account_id}`); - let params = { + const params = { Bucket: bucket, ExpectedBucketOwner: accountResp.account_id, }; @@ -35,17 +48,17 @@ async function checkBucketOwner(bucket) { } catch (error) { resp = { statusCode: error.statusCode }; let msg = `Validation failed: ${error.statusCode}, ${error.code}`; - msg += error.message !== null ? `: ${error.message}\n` : "\n"; + msg += error.message !== null ? `: ${error.message}\n` : '\n'; if (error.statusCode === 404) { - msg += "Error code 404 above indicates bucket not found. Check if bucket exists.\n"; + msg += 'Error code 404 above indicates bucket not found. Check if bucket exists.\n'; } else if (error.statusCode === 403) { - msg += - "Error code 403 above indicates access denied. Check if the bucket is owned " + - "by another account. You should use caution before attempting to " + - "upload to this bucket. Correct the issue and retry the upload only after " + - "you are certain that the bucket exists and is owned by your account.\n" + - "If you want to bypass bucket ownership validation, then you can " + - "use --ignore-bucket-ownership-validation option.\n"; + msg + += 'Error code 403 above indicates access denied. Check if the bucket is owned ' + + 'by another account. You should use caution before attempting to ' + + 'upload to this bucket. Correct the issue and retry the upload only after ' + + 'you are certain that the bucket exists and is owned by your account.\n' + + 'If you want to bypass bucket ownership validation, then you can ' + + 'use --ignore-bucket-ownership-validation option.\n'; } console.error(msg); console.info(`Bucket ownership validation for bucket ${bucket} failed`); @@ -57,30 +70,30 @@ async function main() { const program = new commander.Command(); let resp = { statusCode: 200 }; program - .version("1.0") - .name("node bin/check_bucket_ownership") - .description("Check S3 bucket ownership") - .usage("[options]") - .option("--bucket ", "the bucket name") + .version('1.0') + .name('node bin/check_bucket_ownership') + .description('Check S3 bucket ownership') + .usage('[options]') + .option('--bucket ', 'the bucket name') .option( - "--ignore-bucket-ownership-validation", + '--ignore-bucket-ownership-validation', [ - "bypass bucket ownership validation. Only use this option ", - "if you trust owner of the bucket as being in another account. ", - "You should use caution before attempting to upload to this ", - "bucket.", - ].join("") + 'bypass bucket ownership validation. Only use this option ', + 'if you trust owner of the bucket as being in another account. ', + 'You should use caution before attempting to upload to this ', + 'bucket.', + ].join(''), ) - .action(async options => { + .action(async (options) => { if (options.ignoreBucketOwnershipValidation) { console.warn( - "WARNING: ignoring bucket ownership validation since --ignore-bucket-ownership-validation " + - "is selected." + 'WARNING: ignoring bucket ownership validation since --ignore-bucket-ownership-validation ' + + 'is selected.', ); resp = { statusCode: 200 }; } else { if (!options.bucket) { - console.log("error: required option '--bucket ' not specified"); + console.log('error: required option \'--bucket \' not specified'); process.exit(1); } resp = await checkBucketOwner(options.bucket); diff --git a/bin/config.js b/bin/config.js index c38968fff..79800e327 100644 --- a/bin/config.js +++ b/bin/config.js @@ -1,27 +1,37 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ -module.exports={ - "region":"us-east-1", - "profile":"default", - "publicBucket":"aws-bigdata-blog", - "publicPrefix":"artifacts/aws-ai-qna-bot", - "devEmail":"", - "devEncryption": "ENCRYPTED", - "devPublicOrPrivate": "PRIVATE", - "namespace":"dev", - "LexBotVersion":"LexV2 Only", - "LexV2BotLocaleIds": "en_US,es_US,fr_CA", - "stackNamePrefix":"QNA", - "skipCheckTemplate": false, - "noStackOutput": false, - "multiBucketDeployment": false, - "buildType": "Custom", - "FulfillmentConcurrency":1, - "EmbeddingsApi": "SAGEMAKER", - "QASummarizeApi": "SAGEMAKER", - "InstallLexResponseBots": true -} +module.exports = { + region: 'us-east-1', + profile: 'default', + publicBucket: 'aws-bigdata-blog', + publicPrefix: 'artifacts/aws-ai-qna-bot', + devEmail: '', + devEncryption: 'ENCRYPTED', + devPublicOrPrivate: 'PRIVATE', + namespace: 'dev', + LexBotVersion: 'LexV2 Only', + LexV2BotLocaleIds: 'en_US,es_US,fr_CA', + stackNamePrefix: 'QNA', + skipCheckTemplate: false, + noStackOutput: false, + multiBucketDeployment: false, + buildType: 'Custom', + FulfillmentConcurrency: 1, + EmbeddingsApi: 'SAGEMAKER', + QASummarizeApi: 'SAGEMAKER', + InstallLexResponseBots: true, +}; if (require.main === module) { if (process.argv.includes('buildType=AWSSolutions')) { @@ -31,8 +41,8 @@ if (require.main === module) { module.exports.skipCheckTemplate = true; module.exports.noStackOutput = true; } else { - module.exports.devEmail=process.argv[2] || "user@example.com" - module.exports.region=process.argv[3] || "us-east-1" + module.exports.devEmail = process.argv[2] || 'user@example.com'; + module.exports.region = process.argv[3] || 'us-east-1'; } - console.log(JSON.stringify(module.exports,null,2)) + console.log(JSON.stringify(module.exports, null, 2)); } diff --git a/bin/exports.js b/bin/exports.js index ccceaabb5..7e8317126 100755 --- a/bin/exports.js +++ b/bin/exports.js @@ -1,83 +1,89 @@ #! /usr/bin/env node -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -var config=require('../config.json') -var fs=require('fs') -process.env.AWS_PROFILE=config.profile -process.env.AWS_DEFAULT_REGION=config.profile -var aws=require('aws-sdk') -var Promise=require('bluebird') -aws.config.setPromisesDependency(Promise) -aws.config.region=require('../config.json').region -var name=require('./name') -var launch=require('./launch') -var _=require('lodash') -var cf=new aws.CloudFormation() +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ +const config = require('../config.json'); -module.exports=_.memoize(function(stack,options={}){ - if(!stack){ +process.env.AWS_PROFILE = config.profile; +process.env.AWS_DEFAULT_REGION = config.profile; +const aws = require('aws-sdk'); +aws.config.region = require('../config.json').region; +const name = require('./name'); +const launch = require('./launch'); +const _ = require('lodash'); - var exports={} +const cf = new aws.CloudFormation(); - return cf.listExports().promise() - .get('Exports') - .each(exp=>exports[exp.Name]=exp.Value) - .return(exports) - }else{ - var outputs={} - if (config.noStackOutput){ - return new Promise((resolve, reject) => { - resolve({ - Bucket : config.publicBucket, - Prefix : config.publicPrefix, - }); - }); - } else { - return new Promise(function(res,rej){ - next() - function next(){ - cf.describeStacks({ - StackName:name(stack,{}) - }).promise() - .catch(x=>x.message.match(/does not exist/), - ()=>launch.sure(stack,{wait:true}) - .then(()=>cf.describeStacks({ - StackName:name(stack,{}) - }).promise()) - ) - .then(function(result){ - var stack=result.Stacks[0] - if(["CREATE_COMPLETE", - "UPDATE_COMPLETE", - "UPDATE_ROLLBACK_COMPLETE" - ].includes(stack.StackStatus)){ - res(result) - }else if([ - "CREATE_IN_PROGRESS", - "UPDATE_IN_PROGRESS", - "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS", - "UPDATE_ROLLBACK_IN_PROGRESS", - "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS", - "REVIEW_IN_PROGRESS" - ].includes(stack.StackStatus)){ - setTimeout(()=>next(),5*1000) - }else{ - rej(stack.StackStatus) - } - }) +module.exports = _.memoize(async (stack, options = {}) => { + if (!stack) { + const exports = {}; + const listExportsData = await cf.listExports().promise(); + listExportsData.Exports.forEach((exp) => exports[exp.Name] = exp.Value); + return exports; + } + const outputs = {}; + if (config.noStackOutput) { + return { + Bucket: config.publicBucket, + Prefix: config.publicPrefix, + }; + } + const result = await new Promise(async (res, rej) => { + next(); + async function next() { + try { + const stackResult = await cf.describeStacks({ + StackName: name(stack, {}), + }).promise(); + const stackStatus = stackResult.Stacks[0].StackStatus; + if (['CREATE_COMPLETE', + 'UPDATE_COMPLETE', + 'UPDATE_ROLLBACK_COMPLETE', + ].includes(stackStatus)) { + res(stackResult); + } else if ([ + 'CREATE_IN_PROGRESS', + 'UPDATE_IN_PROGRESS', + 'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS', + 'UPDATE_ROLLBACK_IN_PROGRESS', + 'UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS', + 'REVIEW_IN_PROGRESS', + ].includes(stackStatus)) { + setTimeout(() => next(), 5 * 1000); + } else { + rej(stackStatus); } - }) - .then(x=>x.Stacks[0].Outputs) - .map(x=>outputs[x.OutputKey]=x.OutputValue) - .return(outputs) + } catch (x) { + if (x.message.match(/does not exist/)) { + await launch.sure(stack, { wait: true }); + const stackResult = await cf.describeStacks({ StackName: name(stack, {}) }).promise(); + res(stackResult); + } else { + throw x; + } + } } - } -},(stack,options)=>stack) + }); + result.Stacks[0].Outputs.forEach((x) => outputs[x.OutputKey] = x.OutputValue); + return outputs; +}, (stack, options) => stack); -if(!module.parent){ - module.exports(process.argv[2],{silent:true,quick:true}) - .then(exports=>console.log(JSON.stringify(exports,null,4))) - .catch(x=>console.log("error"+x)) +if (!module.parent) { + (async () => { + try { + const exports = await module.exports(process.argv[2], { silent: true, quick: true }); + console.log(JSON.stringify(exports, null, 4)); + } catch (x) { + console.log(`error${x}`); + } + })(); } - - diff --git a/bin/json.js b/bin/json.js index ff7576904..5ceadcab3 100755 --- a/bin/json.js +++ b/bin/json.js @@ -8,20 +8,17 @@ * See and */ -var VERSION = '9.0.6'; +const VERSION = '9.0.6'; +const util = require('util'); +const assert = require('assert'); +const path = require('path'); +const vm = require('vm'); +const fs = require('fs'); -var p = console.warn; -var util = require('util'); -var assert = require('assert'); -var path = require('path'); -var vm = require('vm'); -var fs = require('fs'); -var warn = console.warn; -var EventEmitter = require('events').EventEmitter; +const { warn } = console; +const { EventEmitter } = require('events'); - - -//--- exports for module usage +// --- exports for module usage exports.main = main; exports.getVersion = getVersion; @@ -31,25 +28,21 @@ exports.parseLookup = parseLookup; exports.lookupDatum = lookupDatum; exports.printDatum = printDatum; // DEPRECATED - - -//---- globals and constants +// ---- globals and constants // Output modes. -var OM_JSONY = 1; -var OM_JSON = 2; -var OM_INSPECT = 3; -var OM_COMPACT = 4; -var OM_FROM_NAME = { - 'jsony': OM_JSONY, - 'json': OM_JSON, - 'inspect': OM_INSPECT, - 'compact': OM_COMPACT +const OM_JSONY = 1; +const OM_JSON = 2; +const OM_INSPECT = 3; +const OM_COMPACT = 4; +const OM_FROM_NAME = { + jsony: OM_JSONY, + json: OM_JSON, + inspect: OM_INSPECT, + compact: OM_COMPACT, }; - - -//---- support functions +// ---- support functions function getVersion() { return VERSION; @@ -61,12 +54,12 @@ function getVersion() { * Only support objects that you get out of JSON, i.e. no functions. */ function objCopy(obj) { - var copy; + let copy; if (Array.isArray(obj)) { copy = obj.slice(); } else if (typeof (obj) === 'object') { copy = {}; - Object.keys(obj).forEach(function (k) { + Object.keys(obj).forEach((k) => { copy[k] = obj[k]; }); } else { @@ -79,23 +72,22 @@ if (util.format) { format = util.format; } else { // From : - var formatRegExp = /%[sdj%]/g; + const formatRegExp = /%[sdj%]/g; function format(f) { - var i; + let i; if (typeof (f) !== 'string') { - var objects = []; + const objects = []; for (i = 0; i < arguments.length; i++) { objects.push(util.inspect(arguments[i])); } return objects.join(' '); } i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function (x) { - if (i >= len) - return x; + const args = arguments; + const len = args.length; + let str = String(f).replace(formatRegExp, (x) => { + if (i >= len) return x; switch (x) { case '%s': return String(args[i++]); @@ -109,11 +101,11 @@ if (util.format) { return x; } }); - for (var x = args[i]; i < len; x = args[++i]) { + for (let x = args[i]; i < len; x = args[++i]) { if (x === null || typeof (x) !== 'object') { - str += ' ' + x; + str += ` ${x}`; } else { - str += ' ' + util.inspect(x); + str += ` ${util.inspect(x)}`; } } return str; @@ -125,20 +117,28 @@ if (util.format) { */ function _parseString(s) { /* JSSTYLED */ - var quoted = '"' + s.replace(/\\"/, '"').replace('"', '\\"') + '"'; + const quoted = `"${s.replace(/\\"/, '"').replace('"', '\\"')}"`; return eval(quoted); } // json_parse.js () /* BEGIN JSSTYLED */ // START json_parse -var json_parse=function(){"use strict";var a,b,c={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"},d,e=function(b){throw{name:"SyntaxError",message:b,at:a,text:d}},f=function(c){return c&&c!==b&&e("Expected '"+c+"' instead of '"+b+"'"),b=d.charAt(a),a+=1,b},g=function(){var a,c="";b==="-"&&(c="-",f("-"));while(b>="0"&&b<="9")c+=b,f();if(b==="."){c+=".";while(f()&&b>="0"&&b<="9")c+=b}if(b==="e"||b==="E"){c+=b,f();if(b==="-"||b==="+")c+=b,f();while(b>="0"&&b<="9")c+=b,f()}a=+c;if(!isFinite(a))e("Bad number");else return a},h=function(){var a,d,g="",h;if(b==='"')while(f()){if(b==='"')return f(),g;if(b==="\\"){f();if(b==="u"){h=0;for(d=0;d<4;d+=1){a=parseInt(f(),16);if(!isFinite(a))break;h=h*16+a}g+=String.fromCharCode(h)}else if(typeof c[b]=="string")g+=c[b];else break}else g+=b}e("Bad string")},i=function(){while(b&&b<=" ")f()},j=function(){switch(b){case"t":return f("t"),f("r"),f("u"),f("e"),!0;case"f":return f("f"),f("a"),f("l"),f("s"),f("e"),!1;case"n":return f("n"),f("u"),f("l"),f("l"),null}e("Unexpected '"+b+"'")},k,l=function(){var a=[];if(b==="["){f("["),i();if(b==="]")return f("]"),a;while(b){a.push(k()),i();if(b==="]")return f("]"),a;f(","),i()}}e("Bad array")},m=function(){var a,c={};if(b==="{"){f("{"),i();if(b==="}")return f("}"),c;while(b){a=h(),i(),f(":"),Object.hasOwnProperty.call(c,a)&&e('Duplicate key "'+a+'"'),c[a]=k(),i();if(b==="}")return f("}"),c;f(","),i()}}e("Bad object")};return k=function(){i();switch(b){case"{":return m();case"[":return l();case'"':return h();case"-":return g();default:return b>="0"&&b<="9"?g():j()}},function(c,f){var g;return d=c,a=0,b=" ",g=k(),i(),b&&e("Syntax error"),typeof f=="function"?function h(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&(d=h(e,c),d!==undefined?e[c]=d:delete e[c]);return f.call(a,b,e)}({"":g},""):g}}(); +const json_parse = (function () { + let a; let b; const c = { + '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t', + }; let d; const e = function (b) { + throw { + name: 'SyntaxError', message: b, at: a, text: d, + }; + }; const f = function (c) { return c && c !== b && e(`Expected '${c}' instead of '${b}'`), b = d.charAt(a), a += 1, b; }; const g = function () { let a; let c = ''; b === '-' && (c = '-', f('-')); while (b >= '0' && b <= '9')c += b, f(); if (b === '.') { c += '.'; while (f() && b >= '0' && b <= '9')c += b; } if (b === 'e' || b === 'E') { c += b, f(); if (b === '-' || b === '+')c += b, f(); while (b >= '0' && b <= '9')c += b, f(); }a = +c; if (!isFinite(a))e('Bad number'); else return a; }; const h = function () { let a; let d; let g = ''; let h; if (b === '"') while (f()) { if (b === '"') return f(), g; if (b === '\\') { f(); if (b === 'u') { h = 0; for (d = 0; d < 4; d += 1) { a = parseInt(f(), 16); if (!isFinite(a)) break; h = h * 16 + a; }g += String.fromCharCode(h); } else if (typeof c[b] === 'string')g += c[b]; else break; } else g += b; }e('Bad string'); }; const i = function () { while (b && b <= ' ')f(); }; const j = function () { switch (b) { case 't': return f('t'), f('r'), f('u'), f('e'), !0; case 'f': return f('f'), f('a'), f('l'), f('s'), f('e'), !1; case 'n': return f('n'), f('u'), f('l'), f('l'), null; }e(`Unexpected '${b}'`); }; let k; const l = function () { const a = []; if (b === '[') { f('['), i(); if (b === ']') return f(']'), a; while (b) { a.push(k()), i(); if (b === ']') return f(']'), a; f(','), i(); } }e('Bad array'); }; const m = function () { let a; const c = {}; if (b === '{') { f('{'), i(); if (b === '}') return f('}'), c; while (b) { a = h(), i(), f(':'), Object.hasOwnProperty.call(c, a) && e(`Duplicate key "${a}"`), c[a] = k(), i(); if (b === '}') return f('}'), c; f(','), i(); } }e('Bad object'); }; return k = function () { i(); switch (b) { case '{': return m(); case '[': return l(); case '"': return h(); case '-': return g(); default: return b >= '0' && b <= '9' ? g() : j(); } }, function (c, f) { let g; return d = c, a = 0, b = ' ', g = k(), i(), b && e('Syntax error'), typeof f === 'function' ? (function h(a, b) { let c; let d; const e = a[b]; if (e && typeof e === 'object') for (c in e)Object.prototype.hasOwnProperty.call(e, c) && (d = h(e, c), d !== undefined ? e[c] = d : delete e[c]); return f.call(a, b, e); }({ '': g }, '')) : g; }; +}()); // END json_parse /* END JSSTYLED */ function printHelp() { /* BEGIN JSSTYLED */ - var w = console.log; + const w = console.log; w('Usage:'); w(' | json [OPTIONS] [LOOKUPS...]'); w(' json -f FILE [OPTIONS] [LOOKUPS...]'); @@ -202,7 +202,7 @@ function printHelp() { w(' $ echo \'{"name": "trent", "age": 38}\' | json name'); w(' trent'); w(''); - w(" Use '-j' or '-o json' for explicit JSON, '-o json-N' for N-space indent:"); + w(' Use \'-j\' or \'-o json\' for explicit JSON, \'-o json-N\' for N-space indent:'); w(' $ echo \'{"name": "trent", "age": 38}\' | json -o json-0'); w(' {"name":"trent","age":38}'); w(''); @@ -222,7 +222,7 @@ function printHelp() { w(' --merge Merge adjacent objects into one. Keys in last '); w(' object win.'); w(' --deep-merge Same as "--merge", but will recurse into objects '); - w(' under the same key in both.') + w(' under the same key in both.'); w(' -a, --array Process input as an array of separate inputs'); w(' and output in tabular form.'); w(' -A Process input as a single object, i.e. stop'); @@ -266,7 +266,6 @@ function printHelp() { /* END JSSTYLED */ } - /** * Parse the command-line options and arguments into an object. * @@ -280,7 +279,7 @@ function printHelp() { * @throws {Error} If there is an error parsing argv. */ function parseArgv(argv) { - var parsed = { + const parsed = { args: [], help: false, quiet: false, @@ -298,30 +297,29 @@ function parseArgv(argv) { merge: null, // --merge -> 'shallow', --deep-merge -> 'deep' inputFiles: [], validate: false, - inPlace: false + inPlace: false, }; // Turn '-iH' into '-i -H', except for argument-accepting options. - var args = argv.slice(2); // drop ['node', 'scriptname'] - var newArgs = []; - var optTakesArg = { - 'd': true, - 'o': true, - 'D': true + let args = argv.slice(2); // drop ['node', 'scriptname'] + let newArgs = []; + const optTakesArg = { + d: true, + o: true, + D: true, }; - for (var i = 0; i < args.length; i++) { + for (let i = 0; i < args.length; i++) { if (args[i] === '--') { newArgs = newArgs.concat(args.slice(i)); break; } - if (args[i].charAt(0) === '-' && args[i].charAt(1) !== '-' && - args[i].length > 2) - { - var splitOpts = args[i].slice(1).split(''); - for (var j = 0; j < splitOpts.length; j++) { - newArgs.push('-' + splitOpts[j]) + if (args[i].charAt(0) === '-' && args[i].charAt(1) !== '-' + && args[i].length > 2) { + const splitOpts = args[i].slice(1).split(''); + for (let j = 0; j < splitOpts.length; j++) { + newArgs.push(`-${splitOpts[j]}`); if (optTakesArg[splitOpts[j]]) { - var optArg = splitOpts.slice(j + 1).join(''); + const optArg = splitOpts.slice(j + 1).join(''); if (optArg.length) { newArgs.push(optArg); } @@ -336,7 +334,7 @@ function parseArgv(argv) { endOfOptions = false; while (args.length > 0) { - var arg = args.shift(); + const arg = args.shift(); if (endOfOptions) { parsed.args.push(arg); break; @@ -361,13 +359,13 @@ function parseArgv(argv) { break; case '-o': case '--output': - var name = args.shift(); + let name = args.shift(); if (!name) { throw new Error('no argument given for "-o|--output" option'); } - var idx = name.lastIndexOf('-'); + const idx = name.lastIndexOf('-'); if (idx !== -1) { - var indent = name.slice(idx + 1); + const indent = name.slice(idx + 1); if (/^\d+$/.test(indent)) { parsed.jsonIndent = Number(indent); name = name.slice(0, idx); @@ -378,7 +376,7 @@ function parseArgv(argv) { } parsed.outputMode = OM_FROM_NAME[name]; if (parsed.outputMode === undefined) { - throw new Error('unknown output mode: "' + name + '"'); + throw new Error(`unknown output mode: "${name}"`); } break; case '-0': @@ -415,15 +413,16 @@ function parseArgv(argv) { if (parsed.lookupDelim.length !== 1) { throw new Error(format( 'invalid lookup delim "%s" (must be a single char)', - parsed.lookupDelim)); + parsed.lookupDelim, + )); } break; case '-e': - case '-E': // DEPRECATED in v9 + case '-E': // DEPRECATED in v9 parsed.exeSnippets.push(args.shift()); break; case '-c': - case '-C': // DEPRECATED in v9 + case '-C': // DEPRECATED in v9 parsed.condSnippets.push(args.shift()); break; case '-M': @@ -453,7 +452,7 @@ function parseArgv(argv) { break; default: // arguments if (!endOfOptions && arg.length > 0 && arg[0] === '-') { - throw new Error('unknown option "' + arg + '"'); + throw new Error(`unknown option "${arg}"`); } parsed.args.push(arg); break; @@ -465,22 +464,21 @@ function parseArgv(argv) { } if (parsed.outputKeys && parsed.args.length > 0) { throw new Error( - 'cannot use -k|--keys option and lookup arguments together'); + 'cannot use -k|--keys option and lookup arguments together', + ); } if (parsed.inPlace && parsed.inputFiles.length !== 1) { - throw new Error('must specify exactly one file with "-f FILE" to ' + - 'use -I/--in-place'); + throw new Error('must specify exactly one file with "-f FILE" to ' + + 'use -I/--in-place'); } if (parsed.inPlace && parsed.args.length > 0) { - throw new Error('lookups cannot be specified with in-place editing ' + - '(-I/--in-place), too easy to lose content'); + throw new Error('lookups cannot be specified with in-place editing ' + + '(-I/--in-place), too easy to lose content'); } return parsed; } - - /** * Streams chunks from given file paths or stdin. * @@ -493,18 +491,18 @@ function parseArgv(argv) { * - `emit('end')` when all streams are done */ function chunkEmitter(opts) { - var emitter = new EventEmitter(); - var streaming = true; - var chunks = []; - var leftover = ''; - var finishedHeaders = false; + const emitter = new EventEmitter(); + let streaming = true; + const chunks = []; + let leftover = ''; + let finishedHeaders = false; function stripHeaders(s) { // Take off a leading HTTP header if any and pass it through. while (true) { if (s.slice(0, 5) === 'HTTP/') { - var index = s.indexOf('\r\n\r\n'); - var sepLen = 4; + const index = s.indexOf('\r\n\r\n'); + const sepLen = 4; if (index == -1) { index = s.indexOf('\n\n'); sepLen = 2; @@ -513,7 +511,7 @@ function chunkEmitter(opts) { if (!opts.dropHeaders) { emit(s.slice(0, index + sepLen)); } - var is100Continue = ( + const is100Continue = ( s.slice(0, 21) === 'HTTP/1.1 100 Continue'); s = s.slice(index + sepLen); if (is100Continue) { @@ -526,15 +524,15 @@ function chunkEmitter(opts) { } break; } - //console.warn('stripHeaders done, finishedHeaders=%s', finishedHeaders) + // console.warn('stripHeaders done, finishedHeaders=%s', finishedHeaders) return s; } function emitChunks(block, emitter) { - //console.warn('emitChunks start: block="%s"', block) + // console.warn('emitChunks start: block="%s"', block) /* JSSTYLED */ - var splitter = /(})(\s*\n\s*)?({\s*")/; - var leftTrimmedBlock = block.trimLeft(); + const splitter = /(})(\s*\n\s*)?({\s*")/; + const leftTrimmedBlock = block.trimLeft(); if (leftTrimmedBlock && leftTrimmedBlock[0] !== '{') { // Currently only support streaming consecutive *objects*. streaming = false; @@ -554,8 +552,8 @@ function chunkEmitter(opts) { * '{"', * 'a":"b"}' ] */ - var bits = block.split(splitter); - //console.warn('emitChunks: bits (length %d): %j', bits.length, bits); + const bits = block.split(splitter); + // console.warn('emitChunks: bits (length %d): %j', bits.length, bits); if (bits.length === 1) { /* * An unwanted side-effect of using a regex to find @@ -586,9 +584,9 @@ function chunkEmitter(opts) { */ // An object must end with '}'. This is an early out to avoid // `JSON.parse` which I'm *presuming* is slower. - var trimmed = block.split(/\s*\r?\n/)[0]; + const trimmed = block.split(/\s*\r?\n/)[0]; if (trimmed[trimmed.length - 1] === '}') { - var obj; + let obj; try { obj = JSON.parse(block); } catch (e) { @@ -601,22 +599,21 @@ function chunkEmitter(opts) { } } return block; - } else { - var n = bits.length - 2; - var s; - s = bits[0] + bits[1]; + } + const n = bits.length - 2; + let s; + s = bits[0] + bits[1]; + emitter.emit('chunk', s, JSON.parse(s)); + for (let i = 3; i < n; i += 4) { + s = bits[i] + bits[i + 1] + bits[i + 2]; emitter.emit('chunk', s, JSON.parse(s)); - for (var i = 3; i < n; i += 4) { - s = bits[i] + bits[i + 1] + bits[i + 2]; - emitter.emit('chunk', s, JSON.parse(s)); - } - return bits[n] + bits[n + 1]; } + return bits[n] + bits[n + 1]; } function addDataListener(stream) { - stream.on('data', function (chunk) { - var s = leftover + chunk; + stream.on('data', (chunk) => { + let s = leftover + chunk; if (!finishedHeaders) { s = stripHeaders(s); } @@ -638,23 +635,25 @@ function chunkEmitter(opts) { if (opts.inputFiles.length > 0) { // Stream each file in order. - var i = 0; + let i = 0; function addErrorListener(file) { - file.on('error', function (err) { + file.on('error', (err) => { emitter.emit( 'error', - format('could not read "%s": %s', opts.inputFiles[i], e) + format('could not read "%s": %s', opts.inputFiles[i], e), ); }); } function addEndListener(file) { - file.on('end', function () { + file.on('end', () => { if (i < opts.inputFiles.length) { - var next = opts.inputFiles[i++]; - var nextFile = fs.createReadStream(next, - {encoding: 'utf8'}); + const next = opts.inputFiles[i++]; + const nextFile = fs.createReadStream( + next, + { encoding: 'utf8' }, + ); addErrorListener(nextFile); addEndListener(nextFile); addDataListener(nextFile); @@ -669,17 +668,19 @@ function chunkEmitter(opts) { } }); } - var first = fs.createReadStream(opts.inputFiles[i++], - {encoding: 'utf8'}); + const first = fs.createReadStream( + opts.inputFiles[i++], + { encoding: 'utf8' }, + ); addErrorListener(first); addEndListener(first); addDataListener(first); } else { // Streaming from stdin. - var stdin = process.openStdin(); + const stdin = process.openStdin(); stdin.setEncoding('utf8'); addDataListener(stdin); - stdin.on('end', function () { + stdin.on('end', () => { if (!streaming) { emitter.emit('chunk', chunks.join('')); } else if (leftover) { @@ -705,21 +706,21 @@ function chunkEmitter(opts) { function getInput(opts, callback) { if (opts.inputFiles.length === 0) { // Read from stdin. - var chunks = []; + const chunks = []; - var stdin = process.openStdin(); + const stdin = process.openStdin(); stdin.setEncoding('utf8'); - stdin.on('data', function (chunk) { + stdin.on('data', (chunk) => { chunks.push(chunk); }); - stdin.on('end', function () { + stdin.on('end', () => { callback(null, chunks.join('')); }); } else if (opts.inPlace) { - for (var i = 0; i < opts.inputFiles.length; i++) { - var file = opts.inputFiles[i]; - var content; + for (let i = 0; i < opts.inputFiles.length; i++) { + const file = opts.inputFiles[i]; + let content; try { content = fs.readFileSync(file, 'utf8'); } catch (e) { @@ -731,27 +732,29 @@ function getInput(opts, callback) { } } else { // Read input files. - var i = 0; - var chunks = []; + let i = 0; + const chunks = []; try { for (; i < opts.inputFiles.length; i++) { chunks.push(fs.readFileSync(opts.inputFiles[i], 'utf8')); } } catch (e) { return callback( - format('could not read "%s": %s', opts.inputFiles[i], e)); + format('could not read "%s": %s', opts.inputFiles[i], e), + ); } - callback(null, chunks.join(''), - (opts.inputFiles.length === 1 ? opts.inputFiles[0] : undefined)); + callback( + null, + chunks.join(''), + (opts.inputFiles.length === 1 ? opts.inputFiles[0] : undefined), + ); } } - function isInteger(s) { return (s.search(/^-?[0-9]+$/) == 0); } - /** * Parse a lookup string into a list of lookup bits. E.g.: * @@ -762,24 +765,24 @@ function isInteger(s) { * Optionally receives an alternative lookup delimiter (other than '.') */ function parseLookup(lookup, lookupDelim) { - var debug = function () {}; - //var debug = console.warn; + const debug = function () {}; + // const debug = console.warn; - var bits = []; - debug('\n*** ' + lookup + ' ***'); + let bits = []; + debug(`\n*** ${lookup} ***`); bits = []; lookupDelim = lookupDelim || '.'; - var bit = ''; - var states = [null]; - var escaped = false; - var ch = null; - for (var i = 0; i < lookup.length; ++i) { - var escaped = (!escaped && ch === '\\'); - var ch = lookup[i]; - debug('-- i=' + i + ', ch=' + JSON.stringify(ch) + ' escaped=' + - JSON.stringify(escaped)); - debug('states: ' + JSON.stringify(states)); + let bit = ''; + const states = [null]; + let escaped = false; + let ch = null; + for (let i = 0; i < lookup.length; ++i) { + escaped = (!escaped && ch === '\\'); + ch = lookup[i]; + debug(`-- i=${i}, ch=${JSON.stringify(ch)} escaped=${ + JSON.stringify(escaped)}`); + debug(`states: ${JSON.stringify(states)}`); if (escaped) { bit += ch; @@ -798,14 +801,14 @@ function parseLookup(lookup, lookupDelim) { states.push(ch); if (bit !== '') { bits.push(bit); - bit = '' + bit = ''; } bit += ch; break; case lookupDelim: if (bit !== '') { bits.push(bit); - bit = '' + bit = ''; } break; default: @@ -825,10 +828,9 @@ function parseLookup(lookup, lookupDelim) { case ']': states.pop(); if (states[states.length - 1] === null) { - var evaled = vm.runInNewContext( - '(' + bit.slice(1, -1) + ')', {}, ''); + const evaled = vm.runInNewContext(`(${bit.slice(1, -1)})`, {}, ''); bits.push(evaled); - bit = '' + bit = ''; } break; } @@ -841,7 +843,7 @@ function parseLookup(lookup, lookupDelim) { states.pop(); if (states[states.length - 1] === null) { bits.push(bit); - bit = '' + bit = ''; } break; } @@ -854,35 +856,34 @@ function parseLookup(lookup, lookupDelim) { states.pop(); if (states[states.length - 1] === null) { bits.push(bit); - bit = '' + bit = ''; } break; } break; } - debug('bit: ' + JSON.stringify(bit)); - debug('bits: ' + JSON.stringify(bits)); + debug(`bit: ${JSON.stringify(bit)}`); + debug(`bits: ${JSON.stringify(bits)}`); } if (bit !== '') { bits.push(bit); - bit = '' + bit = ''; } // Negative-intify: strings that are negative ints we change to a Number for // special handling in `lookupDatum`: Python-style negative array indexing. - var negIntPat = /^-\d+$/; - for (var i = 0; i < bits.length; i++) { + const negIntPat = /^-\d+$/; + for (let i = 0; i < bits.length; i++) { if (negIntPat.test(bits[i])) { bits[i] = Number(bits[i]); } } - debug(JSON.stringify(lookup) + ' -> ' + JSON.stringify(bits)); - return bits + debug(`${JSON.stringify(lookup)} -> ${JSON.stringify(bits)}`); + return bits; } - /** * Parse the given stdin input into: * { @@ -902,9 +903,9 @@ function parseLookup(lookup, lookupDelim) { function parseInput(buffer, obj, group, merge) { if (obj) { return { - datum: obj + datum: obj, }; - } else if (group) { + } if (group) { /** * Special case: Grouping (previously called auto-arrayification) * of unjoined list of objects: @@ -934,91 +935,89 @@ function parseInput(buffer, obj, group, merge) { * because shows that that * is not safe. */ - var newBuffer = buffer; + let newBuffer = buffer; /* JSSTYLED */ - [/(})\s*\n\s*({)/g, /(})({")/g].forEach(function (pat) { + [/(})\s*\n\s*({)/g, /(})({")/g].forEach((pat) => { newBuffer = newBuffer.replace(pat, '$1,\n$2'); }); - [/(\])\s*\n\s*(\[)/g].forEach(function (pat) { + [/(\])\s*\n\s*(\[)/g].forEach((pat) => { newBuffer = newBuffer.replace(pat, ',\n'); }); newBuffer = newBuffer.trim(); if (newBuffer[0] !== '[') { - newBuffer = '[\n' + newBuffer; + newBuffer = `[\n${newBuffer}`; } if (newBuffer.slice(-1) !== ']') { - newBuffer = newBuffer + '\n]\n'; + newBuffer += '\n]\n'; } try { return { - datum: JSON.parse(newBuffer) + datum: JSON.parse(newBuffer), }; } catch (e2) { return { - error: e2 + error: e2, }; } } else if (merge) { // See the 'Rules' above for limitations on boundaries for 'adjacent' // objects: KISS. - var newBuffer = buffer; + let newBuffer = buffer; /* JSSTYLED */ - [/(})\s*\n\s*({)/g, /(})({")/g].forEach(function (pat) { + [/(})\s*\n\s*({)/g, /(})({")/g].forEach((pat) => { newBuffer = newBuffer.replace(pat, '$1,\n$2'); }); - newBuffer = '[\n' + newBuffer + '\n]\n'; - var objs; + newBuffer = `[\n${newBuffer}\n]\n`; + let objs; try { objs = JSON.parse(newBuffer); } catch (e) { return { - error: e + error: e, }; } - var merged = objs[0]; + const merged = objs[0]; if (merge === 'shallow') { - for (var i = 1; i < objs.length; i++) { - var obj = objs[i]; - Object.keys(obj).forEach(function (k) { + for (let i = 1; i < objs.length; i++) { + const obj = objs[i]; + Object.keys(obj).forEach((k) => { merged[k] = obj[k]; }); } } else if (merge === 'deep') { function deepExtend(a, b) { - Object.keys(b).forEach(function (k) { - if (a[k] && b[k] && - toString.call(a[k]) === '[object Object]' && - toString.call(b[k]) === '[object Object]') - { - deepExtend(a[k], b[k]) + Object.keys(b).forEach((k) => { + if (a[k] && b[k] + && toString.call(a[k]) === '[object Object]' + && toString.call(b[k]) === '[object Object]') { + deepExtend(a[k], b[k]); } else { a[k] = b[k]; } }); } - for (var i = 1; i < objs.length; i++) { + for (let i = 1; i < objs.length; i++) { deepExtend(merged, objs[i]); } } else { throw new Error(format('unknown value for "merge": "%s"', merge)); } return { - datum: merged + datum: merged, }; } else { try { return { - datum: JSON.parse(buffer) + datum: JSON.parse(buffer), }; } catch (e) { return { - error: e + error: e, }; } } } - /** * Apply a lookup to the given datum. * @@ -1028,12 +1027,12 @@ function parseInput(buffer, obj, group, merge) { * @returns {Object} The result of the lookup. */ function lookupDatum(datum, lookup) { - var d = datum; - for (var i = 0; i < lookup.length; i++) { - var bit = lookup[i]; + let d = datum; + for (let i = 0; i < lookup.length; i++) { + const bit = lookup[i]; if (d === null) { return undefined; - } else if (typeof (bit) === 'number' && bit < 0) { + } if (typeof (bit) === 'number' && bit < 0) { d = d[d.length + bit]; } else { d = d[bit]; @@ -1045,7 +1044,6 @@ function lookupDatum(datum, lookup) { return d; } - /** * Output the given datasets. * @@ -1058,24 +1056,32 @@ function lookupDatum(datum, lookup) { * @param opts {Object} Parsed tool options. */ function printDatasets(datasets, filename, headers, opts) { - var isTTY = (filename ? false : process.stdout.isTTY) - var write = emit; + const isTTY = (filename ? false : process.stdout.isTTY); + let write = emit; if (filename) { - var tmpPath = path.resolve(path.dirname(filename), - format('.%s-json-%s-%s.tmp', path.basename(filename), process.pid, - Date.now())); - var stats = fs.statSync(filename); - var f = fs.createWriteStream(tmpPath, - {encoding: 'utf8', mode: stats.mode}); + const tmpPath = path.resolve( + path.dirname(filename), + format( + '.%s-json-%s-%s.tmp', + path.basename(filename), + process.pid, + Date.now(), + ), + ); + const stats = fs.statSync(filename); + const f = fs.createWriteStream( + tmpPath, + { encoding: 'utf8', mode: stats.mode }, + ); write = f.write.bind(f); } if (headers && headers.length > 0) { - write(headers) + write(headers); } - for (var i = 0; i < datasets.length; i++) { - var dataset = datasets[i]; - var output = stringifyDatum(dataset[0], opts, isTTY); - var sep = dataset[1]; + for (let i = 0; i < datasets.length; i++) { + const dataset = datasets[i]; + const output = stringifyDatum(dataset[0], opts, isTTY); + const sep = dataset[1]; if (output && output.length) { write(output); write(sep); @@ -1084,7 +1090,7 @@ function printDatasets(datasets, filename, headers, opts) { } } if (filename) { - f.on('open', function () { + f.on('open', () => { f.end(); fs.renameSync(tmpPath, filename); if (!opts.quiet) { @@ -1094,12 +1100,11 @@ function printDatasets(datasets, filename, headers, opts) { } } - /** * Stringify the given datum according to the given output options. */ function stringifyDatum(datum, opts, isTTY) { - var output = null; + let output = null; switch (opts.outputMode) { case OM_INSPECT: output = util.inspect(datum, false, Infinity, isTTY); @@ -1116,15 +1121,15 @@ function stringifyDatum(datum, opts, isTTY) { if (datum === undefined) { // pass } else if (Array.isArray(datum)) { - var bits = ['[\n']; - datum.forEach(function (d) { - bits.push(' ') + const bits = ['[\n']; + datum.forEach((d) => { + bits.push(' '); bits.push(JSON.stringify(d, null, 0).replace( /* JSSTYLED */ /,"(?![,:])/g, ', "')); bits.push(',\n'); }); - bits.push(bits.pop().slice(0, -2) + '\n') // drop last comma + bits.push(`${bits.pop().slice(0, -2)}\n`); // drop last comma bits.push(']'); output = bits.join(''); } else { @@ -1139,19 +1144,18 @@ function stringifyDatum(datum, opts, isTTY) { } break; default: - throw new Error('unknown output mode: ' + opts.outputMode); + throw new Error(`unknown output mode: ${opts.outputMode}`); } return output; } - /** * Print out a single result, considering input options. * * @deprecated */ function printDatum(datum, opts, sep, alwaysPrintSep) { - var output = stringifyDatum(datum, opts); + const output = stringifyDatum(datum, opts); if (output && output.length) { emit(output); emit(sep); @@ -1160,8 +1164,7 @@ function printDatum(datum, opts, sep, alwaysPrintSep) { } } - -var stdoutFlushed = true; +let stdoutFlushed = true; function emit(s) { // TODO:PERF If this is try/catch is too slow (too granular): move up to // mainline and be sure to only catch this particular error. @@ -1175,17 +1178,16 @@ function emit(s) { } } -process.stdout.on('error', function (err) { +process.stdout.on('error', (err) => { if (err.code === 'EPIPE') { // See . drainStdoutAndExit(0); } else { - warn(err) + warn(err); drainStdoutAndExit(1); } }); - /** * A hacked up version of 'process.exit' that will first drain stdout * before exiting. *WARNING: This doesn't stop event processing.* IOW, @@ -1196,16 +1198,16 @@ process.stdout.on('error', function (err) { * refer to regular files or TTY file descriptors." However, this hack might * still be necessary in a shell pipeline. */ -var drainingStdout = false; +let drainingStdout = false; function drainStdoutAndExit(code) { if (drainingStdout) { return; } drainingStdout = true; - process.stdout.on('drain', function () { + process.stdout.on('drain', () => { process.exit(code); }); - process.stdout.on('close', function () { + process.stdout.on('close', () => { process.exit(code); }); if (stdoutFlushed) { @@ -1213,7 +1215,6 @@ function drainStdoutAndExit(code) { } } - /** * Return a function for the given JS code that returns. * @@ -1227,103 +1228,102 @@ function funcWithReturnFromSnippet(js) { if (js.substring(js.length - 1) === ';') { js = js.substring(0, js.length - 1); } - js = 'return (' + js + ')'; + js = `return (${js})`; } return (new Function(js)); } - - -//---- mainline +// ---- mainline function main(argv) { - var opts; + let opts; try { opts = parseArgv(argv); } catch (e) { - warn('json: error: %s', e.message) + warn('json: error: %s', e.message); return drainStdoutAndExit(1); } - //warn(opts); + // warn(opts); if (opts.help) { printHelp(); return; } if (opts.version) { if (opts.outputMode === OM_JSON) { - var v = { + const v = { version: getVersion(), author: 'Trent Mick', - project: 'https://github.com/trentm/json' + project: 'https://github.com/trentm/json', }; console.log(JSON.stringify(v, null, opts.jsonIndent)); } else { - console.log('json ' + getVersion()); + console.log(`json ${getVersion()}`); console.log('written by Trent Mick'); console.log('https://github.com/trentm/json'); } return; } - var lookupStrs = opts.args; + const lookupStrs = opts.args; // Prepare condition and execution funcs (and vm scripts) for -c/-e. - var execVm = Boolean(process.env.JSON_EXEC && - process.env.JSON_EXEC === 'vm'); - var i; - var condFuncs = []; + const execVm = Boolean(process.env.JSON_EXEC + && process.env.JSON_EXEC === 'vm'); + let i; + const condFuncs = []; if (!execVm) { for (i = 0; i < opts.condSnippets.length; i++) { condFuncs[i] = funcWithReturnFromSnippet(opts.condSnippets[i]); } } - var condScripts = []; + const condScripts = []; if (execVm) { for (i = 0; i < opts.condSnippets.length; i++) { condScripts[i] = vm.createScript(opts.condSnippets[i]); } } - var cond = Boolean(condFuncs.length + condScripts.length); - var exeFuncs = []; + const cond = Boolean(condFuncs.length + condScripts.length); + const exeFuncs = []; if (!execVm) { for (i = 0; i < opts.exeSnippets.length; i++) { exeFuncs[i] = new Function(opts.exeSnippets[i]); } } - var exeScripts = []; + const exeScripts = []; if (execVm) { for (i = 0; i < opts.exeSnippets.length; i++) { exeScripts[i] = vm.createScript(opts.exeSnippets[i]); } } - var exe = Boolean(exeFuncs.length + exeScripts.length); + const exe = Boolean(exeFuncs.length + exeScripts.length); - var lookups = lookupStrs.map(function (lookup) { - return parseLookup(lookup, opts.lookupDelim); - }); + const lookups = lookupStrs.map((lookup) => parseLookup(lookup, opts.lookupDelim)); if (opts.group && opts.array && opts.outputMode !== OM_JSON) { // streaming - var chunker = chunkEmitter(opts); - chunker.on('error', function (error) { + const chunker = chunkEmitter(opts); + chunker.on('error', (error) => { warn('json: error: %s', err.message); return drainStdoutAndExit(1); }); chunker.on('chunk', parseChunk); } else if (opts.inPlace) { - assert.equal(opts.inputFiles.length, 1, - 'cannot handle more than one file with -I'); - getInput(opts, function (err, content, filename) { + assert.equal( + opts.inputFiles.length, + 1, + 'cannot handle more than one file with -I', + ); + getInput(opts, (err, content, filename) => { if (err) { - warn('json: error: %s', err.message) + warn('json: error: %s', err.message); return drainStdoutAndExit(1); } // Take off a leading HTTP header if any and pass it through. - var headers = []; + const headers = []; while (true) { if (content.slice(0, 5) === 'HTTP/') { - var index = content.indexOf('\r\n\r\n'); - var sepLen = 4; + let index = content.indexOf('\r\n\r\n'); + let sepLen = 4; if (index == -1) { index = content.indexOf('\n\n'); sepLen = 2; @@ -1332,7 +1332,7 @@ function main(argv) { if (!opts.dropHeaders) { headers.push(content.slice(0, index + sepLen)); } - var is100Continue = ( + const is100Continue = ( content.slice(0, 21) === 'HTTP/1.1 100 Continue'); content = content.slice(index + sepLen); if (is100Continue) { @@ -1346,16 +1346,16 @@ function main(argv) { }); } else { // not streaming - getInput(opts, function (err, buffer, filename) { + getInput(opts, (err, buffer, filename) => { if (err) { - warn('json: error: %s', err.message) + warn('json: error: %s', err.message); return drainStdoutAndExit(1); } // Take off a leading HTTP header if any and pass it through. while (true) { if (buffer.slice(0, 5) === 'HTTP/') { - var index = buffer.indexOf('\r\n\r\n'); - var sepLen = 4; + let index = buffer.indexOf('\r\n\r\n'); + let sepLen = 4; if (index == -1) { index = buffer.indexOf('\n\n'); sepLen = 2; @@ -1364,7 +1364,7 @@ function main(argv) { if (!opts.dropHeaders) { emit(buffer.slice(0, index + sepLen)); } - var is100Continue = ( + const is100Continue = ( buffer.slice(0, 21) === 'HTTP/1.1 100 Continue'); buffer = buffer.slice(index + sepLen); if (is100Continue) { @@ -1397,22 +1397,23 @@ function main(argv) { return; } // parseInput() -> {datum: , error: } - var input = parseInput(chunk, obj, opts.group, opts.merge); + const input = parseInput(chunk, obj, opts.group, opts.merge); if (input.error) { // Doesn't look like JSON. Just print it out and move on. if (!opts.quiet) { // Use JSON-js' "json_parse" parser to get more detail on the // syntax error. - var details = ''; - var normBuffer = chunk.replace(/\r\n|\n|\r/, '\n'); + let details = ''; + const normBuffer = chunk.replace(/\r\n|\n|\r/, '\n'); try { json_parse(normBuffer); details = input.error; } catch (err) { // err.at has the position. Get line/column from that. - var at = err.at - 1; // `err.at` looks to be 1-based. - var lines = chunk.split('\n'); - var line, col, pos = 0; + const at = err.at - 1; // `err.at` looks to be 1-based. + const lines = chunk.split('\n'); + let line; let col; let + pos = 0; for (line = 0; line < lines.length; line++) { pos += lines[line].length + 1; if (pos > at) { @@ -1420,16 +1421,19 @@ function main(argv) { break; } } - var spaces = ''; - for (var i = 0; i < col; i++) { + let spaces = ''; + for (let i = 0; i < col; i++) { spaces += '.'; } - details = err.message + ' at line ' + (line + 1) + - ', column ' + (col + 1) + ':\n ' + - lines[line] + '\n ' + spaces + '^'; + details = `${err.message} at line ${line + 1 + }, column ${col + 1}:\n ${ + lines[line]}\n ${spaces}^`; } - warn('json: error: %s is not JSON: %s', - filename ? '"' + filename + '"' : 'input', details); + warn( + 'json: error: %s is not JSON: %s', + filename ? `"${filename}"` : 'input', + details, + ); } if (!opts.validate) { emit(chunk); @@ -1442,18 +1446,18 @@ function main(argv) { if (opts.validate) { return drainStdoutAndExit(0); } - var data = input.datum; + let data = input.datum; // Process: items (-M, --items) if (opts.items) { if (!Array.isArray(data)) { - var key; - var array = []; + let key; + const array = []; for (key in data) { if (data.hasOwnProperty(key)) { array.push({ - key: key, - value: data[key] + key, + value: data[key], }); } } @@ -1462,17 +1466,18 @@ function main(argv) { } // Process: executions (-e, -E) - var i, j; + let i; let + j; if (!exe) { /* pass */ } else if (opts.array || (opts.array === null && Array.isArray(data))) { - var arrayified = false; + let arrayified = false; if (!Array.isArray(data)) { arrayified = true; data = [data]; } for (i = 0; i < data.length; i++) { - var datum = data[i]; + const datum = data[i]; for (j = 0; j < exeFuncs.length; j++) { exeFuncs[j].call(datum); } @@ -1496,16 +1501,16 @@ function main(argv) { if (!cond) { /* pass */ } else if (opts.array || (opts.array === null && Array.isArray(data))) { - var arrayified = false; + let arrayified = false; if (!Array.isArray(data)) { arrayified = true; data = [data]; } - var filtered = []; + const filtered = []; for (i = 0; i < data.length; i++) { - var datum = data[i]; - var datumCopy = objCopy(datum); - var keep = true; + const datum = data[i]; + const datumCopy = objCopy(datum); + let keep = true; // TODO(perf): Perhaps drop the 'datumCopy'? "this is a gun" for (j = 0; j < condFuncs.length; j++) { if (!condFuncs[j].call(datumCopy)) { @@ -1531,8 +1536,8 @@ function main(argv) { data = filtered; } } else { - var keep = true; - var dataCopy = objCopy(data); + let keep = true; + const dataCopy = objCopy(data); for (j = 0; j < condFuncs.length; j++) { // TODO(perf): Perhaps drop the 'dataCopy'? "this is a gun" if (!condFuncs[j].call(dataCopy)) { @@ -1554,17 +1559,17 @@ function main(argv) { } // Process: lookups - var lookupsAreIndeces = false; + let lookupsAreIndeces = false; if (lookups.length) { if (opts.array) { if (!Array.isArray(data)) data = [data]; - var table = []; + const table = []; for (j = 0; j < data.length; j++) { - var datum = data[j]; - var row = {}; + const datum = data[j]; + const row = {}; for (i = 0; i < lookups.length; i++) { - var lookup = lookups[i]; - var value = lookupDatum(datum, lookup); + const lookup = lookups[i]; + const value = lookupDatum(datum, lookup); if (value !== undefined) { row[lookup.join('.')] = value; } @@ -1579,18 +1584,17 @@ function main(argv) { if (Array.isArray(data)) { lookupsAreIndeces = true; for (i = 0; i < lookups.length; i++) { - if (lookups[i].length !== 1 || - isNaN(Number(lookups[i]))) - { + if (lookups[i].length !== 1 + || isNaN(Number(lookups[i]))) { lookupsAreIndeces = false; break; } } } - var row = {}; + const row = {}; for (i = 0; i < lookups.length; i++) { - var lookup = lookups[i]; - var value = lookupDatum(data, lookup); + const lookup = lookups[i]; + const value = lookupDatum(data, lookup); if (value !== undefined) { row[lookup.join('.')] = value; } @@ -1601,11 +1605,11 @@ function main(argv) { // --keys if (opts.outputKeys) { - var data = Object.keys(data); + const data = Object.keys(data); } // Output - var datasets = []; + const datasets = []; if (opts.outputMode === OM_JSON) { if (lookups.length === 1 && !opts.array) { /** @@ -1625,11 +1629,11 @@ function main(argv) { * array are more likely to be wanted as an array of selected * items rather than a 'JSON table' thing that we use otherwise. */ - var flattened = []; + const flattened = []; for (i = 0; i < lookups.length; i++) { - var lookupStr = lookups[i].join('.'); + const lookupStr = lookups[i].join('.'); if (data.hasOwnProperty(lookupStr)) { - flattened.push(data[lookupStr]) + flattened.push(data[lookupStr]); } } data = flattened; @@ -1641,7 +1645,7 @@ function main(argv) { if (opts.array) { // Output `data` as a 'table' of lookup results. for (j = 0; j < data.length; j++) { - var row = data[j]; + const row = data[j]; for (i = 0; i < lookups.length - 1; i++) { datasets.push([row[lookups[i].join('.')], opts.delim, true]); @@ -1672,9 +1676,9 @@ if (require.main === module) { // place. The real fix is that `.end()` shouldn't be called on stdout // in node core. Hopefully node v0.6.9 will fix that. Only guard // for v0.6.0..v0.6.8. - var nodeVer = process.versions.node.split('.').map(Number); + const nodeVer = process.versions.node.split('.').map(Number); if ([0, 6, 0] <= nodeVer && nodeVer <= [0, 6, 8]) { - var stdout = process.stdout; + const { stdout } = process; stdout.end = stdout.destroy = stdout.destroySoon = function () { /* pass */ }; diff --git a/bin/launch.js b/bin/launch.js index 14328681a..10b55c859 100755 --- a/bin/launch.js +++ b/bin/launch.js @@ -1,39 +1,52 @@ #! /usr/bin/env node -var config=require('../config.json') -process.env.AWS_PROFILE=config.profile -process.env.AWS_DEFAULT_REGION=config.profile -var aws=require('aws-sdk') -var Promise=require('bluebird') -aws.config.setPromisesDependency(Promise) -aws.config.region=require('../config.json').region -var region=require('../config.json').region -var _=require('lodash') -var fs=require('fs') -var cf=new aws.CloudFormation() -var build=require('./build') -var check=require('./check') -var argv=require('commander') -var name=require('./name') -var wait=require('./wait') -var s3=new aws.S3() +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ + +const config = require('../config.json'); + +process.env.AWS_PROFILE = config.profile; +process.env.AWS_DEFAULT_REGION = config.profile; +const aws = require('aws-sdk'); +aws.config.region = require('../config.json').region; +const { region } = require('../config.json'); +const _ = require('lodash'); +const fs = require('fs'); + +const cf = new aws.CloudFormation(); +const build = require('./build'); +const check = require('./check'); +const argv = require('commander'); +const name = require('./name'); +const wait = require('./wait'); + +const s3 = new aws.S3(); if (require.main === module) { - var args=argv.version('1.0') - .description("Manage Cloudformation stacks. stack name is path to template file relative to /templates") - .name("npm run stack") + const args = argv.version('1.0') + .description('Manage Cloudformation stacks. stack name is path to template file relative to /templates') + .name('npm run stack') .arguments('[stack] [op] [options]') - .option('-v, --verbose',"print additional debuging information") - .option('-d, --dry-run',"run command but do not launch any stacks") - .option('--no-check',"do not check stack syntax") - .option('-q --silent',"do output information") - .option('--operation ',"the opteration to do") - .option('--input ',"input template") - .option('--stack-name ',"stack name of the launched template") - .option('--no-wait',"do not wait for stack to complete") - .option('--no-interactive',"omit interactive elements of output (spinners etc.)") - .on('--help',()=>{ - log( -` + .option('-v, --verbose', 'print additional debuging information') + .option('-d, --dry-run', 'run command but do not launch any stacks') + .option('--no-check', 'do not check stack syntax') + .option('-q --silent', 'do output information') + .option('--operation ', 'the opteration to do') + .option('--input ', 'input template') + .option('--stack-name ', 'stack name of the launched template') + .option('--no-wait', 'do not wait for stack to complete') + .option('--no-interactive', 'omit interactive elements of output (spinners etc.)') + .on('--help', () => { + log(` Operations: up: launch a stack @@ -45,221 +58,217 @@ if (require.main === module) { Examples: npm run stack dev/bootstrap up -- --no-wait --verbose npm run stack -- --input ./test/cfn --operation make-sure --dry-run -`,{}) +`, {}); }) - .parse(process.argv) + .parse(process.argv); const options = argv.opts(); - var stack=!options.input ? argv.args[0] : argv.input.split('/') + const stack = !options.input ? argv.args[0] : argv.input.split('/') .reverse() - .filter(x=>x) - .slice(0,2) - .reverse().join('-').split('.')[0] - var op=options.operation || (options.input ? argv.args[0] : argv.args[1]) + .filter((x) => x) + .slice(0, 2) + .reverse() + .join('-') + .split('.')[0]; + const op = options.operation || (options.input ? argv.args[0] : argv.args[1]); try { - if( stack && op){ - switch(op){ - case "up": - up(stack,options || {}) - break; - case "update": - update(stack,options || {}) - break; - case "down": - down(stack,options || {}) - break; - case "restart": - log("restarting stack",options||{}) - down(stack,options || {}).then(()=>up(stack,options || {})) - break; - case "make-sure": - sure(stack,options) - break; - default: - argv.outputHelp() + if (stack && op) { + switch (op) { + case 'up': + up(stack, options || {}); + break; + case 'update': + update(stack, options || {}); + break; + case 'down': + down(stack, options || {}); + break; + case 'restart': + log('restarting stack', options || {}); + down(stack, options || {}).then(() => up(stack, options || {})); + break; + case 'make-sure': + sure(stack, options); + break; + default: + argv.outputHelp(); } - }else{ - argv.outputHelp() + } else { + argv.outputHelp(); } - }catch(e){ - log(e.message,options) + } catch (e) { + log(e.message, options); } } -async function syntax(stack,options){ - if(options.check){ - try{ - await check(stack,options) - log("Template Valid",options) - }catch(e){ - log(e.message,options) +async function syntax(stack, options) { + if (options.check) { + try { + await check(stack, options); + log('Template Valid', options); + } catch (e) { + log(e.message, options); } - }else{ - return Promise.resolve() } } -async function up(stack,options){ +async function up(stack, options) { await build({ - stack:stack, - input:options.input, - silent:options.silent - }) + stack, + input: options.input, + silent: options.silent, + }); try { - var StackName=options.stackName ? options.stackName : name(stack,{inc:true}) - log(`launching stack:${stack}`,options) - if(!options.dryRun){ - var template=fs.readFileSync( - `${__dirname}/../build/templates/${stack}.json` - ,'utf-8') - if(Buffer.byteLength(template)<51200){ - var create=await cf.createStack({ + const StackName = options.stackName ? options.stackName : name(stack, { inc: true }); + log(`launching stack:${stack}`, options); + if (!options.dryRun) { + const template = fs.readFileSync( + `${__dirname}/../build/templates/${stack}.json`, + 'utf-8', + ); + + let create; + if (Buffer.byteLength(template) < 51200) { + create = await cf.createStack({ StackName, - Capabilities:["CAPABILITY_NAMED_IAM","CAPABILITY_AUTO_EXPAND"], - DisableRollback:true, - TemplateBody:template - }).promise() - }else{ - var exp=await bootstrap() - var bucket=exp.Bucket - var prefix=exp.Prefix - var url=`https://${bucket}.s3.${region}.amazonaws.com/${prefix}/templates/${stack}.json` + Capabilities: ['CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], + DisableRollback: true, + TemplateBody: template, + }).promise(); + } else { + const exp = await bootstrap(); + const bucket = exp.Bucket; + const prefix = exp.Prefix; + const url = `https://${bucket}.s3.${region}.amazonaws.com/${prefix}/templates/${stack}.json`; await s3.putObject({ - Bucket:bucket, - Key:`${prefix}/templates/${stack}.json`, - Body:template - }).promise() - var create=await cf.createStack({ + Bucket: bucket, + Key: `${prefix}/templates/${stack}.json`, + Body: template, + }).promise(); + create = await cf.createStack({ StackName, - Capabilities:["CAPABILITY_NAMED_IAM","CAPABILITY_AUTO_EXPAND"], - DisableRollback:true, - TemplateURL:url - }).promise() + Capabilities: ['CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], + DisableRollback: true, + TemplateURL: url, + }).promise(); } - log(`stackname: ${StackName}`,options) - log(`stackId: ${create.StackId}`,options) - if(options.wait){ - return wait(stack,{show:!options.silent}) + log(`stackname: ${StackName}`, options); + log(`stackId: ${create.StackId}`, options); + if (options.wait) { + return wait(stack, { show: !options.silent }); } } - }catch(e){ - log("failed:"+e,options) - process.exit(1) + } catch (e) { + log(`failed:${e}`, options); + process.exit(1); } } -function update(stack,options){ - return build({ - stack:stack, - input:options.input, - silent:options.silent - }) - .then(()=>{ - var StackName=options.stackName ? options.stackName : name(stack) - log(`updating stack:${stack}`,options) - if(!options.dryRun){ - var template=fs.readFileSync( - `${__dirname}/../build/templates/${stack}.json` - ,'utf-8') - if(Buffer.byteLength(template)<51200){ - var start=cf.updateStack({ +async function update(stack, options) { + await build({ + stack, + input: options.input, + silent: options.silent, + }); + try { + const StackName = options.stackName ? options.stackName : name(stack); + log(`updating stack:${stack}`, options); + if (!options.dryRun) { + const template = fs.readFileSync(`${__dirname}/../build/templates/${stack}.json`, 'utf-8'); + let start; + if (Buffer.byteLength(template) < 51200) { + start = await cf.updateStack({ StackName, - Capabilities:["CAPABILITY_NAMED_IAM","CAPABILITY_AUTO_EXPAND"], - TemplateBody:template - }).promise() - }else{ - var start=bootstrap().then(function(exp){ - var bucket=exp.Bucket - var prefix=exp.Prefix - var url=`https://${bucket}.s3.${region}.amazonaws.com/${prefix}/templates/${stack}.json` - console.log(url) - return s3.putObject({ - Bucket:bucket, - Key:`${prefix}/templates/${stack}.json`, - Body:template - }).promise() - .then(()=>cf.updateStack({ - StackName, - Capabilities:["CAPABILITY_NAMED_IAM","CAPABILITY_AUTO_EXPAND"], - TemplateURL:url - }).promise()) - }) + Capabilities: ['CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], + TemplateBody: template, + }).promise(); + } else { + const exp = await bootstrap(); + const bucket = exp.Bucket; + const prefix = exp.Prefix; + const url = `https://${bucket}.s3.${region}.amazonaws.com/${prefix}/templates/${stack}.json`; + console.log(url); + await s3.putObject({ + Bucket: bucket, + Key: `${prefix}/templates/${stack}.json`, + Body: template, + }).promise(); + start = await cf.updateStack({ + StackName, + Capabilities: ['CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], + TemplateURL: url, + }).promise(); + } + const result = await start; + log(`stackname: ${StackName}`, options); + log(`stackId: ${result.StackId}`, options); + if (options.wait) { + return wait(stack, { show: !options.silent }); } - - return start.then(x=>{ - log(`stackname: ${StackName}`,options) - log(`stackId: ${x.StackId}`,options) - if(options.wait){ - return wait(stack,{show:!options.silent}) - } - }) } - }) - .catch(x=>{ - log("failed"+x,options) - process.exit(1) - }) + } catch (err) { + log(`failed${err}`, options); + process.exit(1); + } } -async function down(stack,options){ - var StackName=options.stackName ? options.stackName : name(stack) - log("terminating stack",options) - if(options.dryRun){ - return +async function down(stack, options) { + const StackName = options.stackName ? options.stackName : name(stack); + log('terminating stack', options); + if (options.dryRun) { + return; } - try{ - var down=await cf.describeStacks({ - StackName - }).promise() - var id=down.Stacks[0].StackId + try { + const down = await cf.describeStacks({ + StackName, + }).promise(); + const id = down.Stacks[0].StackId; await cf.deleteStack({ - StackName:id - }).promise() - if(options.wait){ - return wait(stack,{ - Id:id, - show:options.interactive - }) + StackName: id, + }).promise(); + if (options.wait) { + return wait(stack, { + Id: id, + show: options.interactive, + }); } - }catch(e){ - console.log(e) - if(!_.get(e,"message","").match(/.*does not exist$/)){ - log(e,options) - process.exit(1) + } catch (e) { + console.log(e); + if (!_.get(e, 'message', '').match(/.*does not exist$/)) { + log(e, options); + process.exit(1); } } } -async function sure(stack,options={}){ - var StackName=options.stackName ? options.stackName : name(stack) - log(`making sure stack ${stack} is up`,options) - try{ - await cf.describeStacks({StackName}).promise() - await wait(stack,{show:options.interactive && !options.silent}) - log(`${stack} is up as ${StackName}`,options) - }catch(e){ - if(_.get(e,"message","").match(/.*does not exist$/)){ - log("Stack does not exist",options) - return up(stack,options) - }else{ - throw e +async function sure(stack, options = {}) { + const StackName = options.stackName ? options.stackName : name(stack); + log(`making sure stack ${stack} is up`, options); + try { + await cf.describeStacks({ StackName }).promise(); + await wait(stack, { show: options.interactive && !options.silent }); + log(`${stack} is up as ${StackName}`, options); + } catch (e) { + if (_.get(e, 'message', '').match(/.*does not exist$/)) { + log('Stack does not exist', options); + return up(stack, options); } + throw e; } } -function log(message,options){ - if(!options.silent){ - console.log(message) +function log(message, options) { + if (!options.silent) { + console.log(message); } } -function bootstrap(){ - var outputs={} - return cf.describeStacks({ - StackName:name("dev/bootstrap",{}) - }).promise() - .then(x=>x.Stacks[0].Outputs) - .map(x=>outputs[x.OutputKey]=x.OutputValue) - .return(outputs) +async function bootstrap() { + const outputs = {}; + const tmp = await cf.describeStacks({ + StackName: name('dev/bootstrap', {}), + }).promise(); + tmp.Stacks[0].Outputs.forEach((x) => outputs[x.OutputKey] = x.OutputValue); + return outputs; } -exports.up=up -exports.down=down -exports.sure=sure -exports.update=update +exports.up = up; +exports.down = down; +exports.sure = sure; +exports.update = update; diff --git a/bin/license.js b/bin/license.js index 79c94580b..6575cd140 100755 --- a/bin/license.js +++ b/bin/license.js @@ -1,59 +1,64 @@ #! /usr/bin/env node -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ -var Promise=require('bluebird') -var fs=Promise.promisifyAll(require('fs')) -var readdir=Promise.promisify(require('recursive-readdir')) +const Promise = require('bluebird'); +const fs = Promise.promisifyAll(require('fs')); +const readdir = Promise.promisify(require('recursive-readdir')); -var files=readdir(__dirname+'/../') - .filter(x=>!x.match(/.*node_modules.*/)) +const files = readdir(`${__dirname}/../`) + .filter((x) => !x.match(/.*node_modules.*/)); -var jsfiles=files.filter(x=>x.match(/.*\.js$/)).tap(x=>console.log(x.length+" js files")) -var vuefiles=files.filter(x=>x.match(/.*\.vue$/)).tap(x=>console.log(x.length+" vue files")) +const jsfiles = files.filter((x) => x.match(/.*\.js$/)).tap((x) => console.log(`${x.length} js files`)); +const vuefiles = files.filter((x) => x.match(/.*\.vue$/)).tap((x) => console.log(`${x.length} vue files`)); Promise.join( jsfiles.map(js), - vuefiles.map(vue) -).tap(()=>console.log("done")) + vuefiles.map(vue), +).tap(() => console.log('done')); -var license=fs.readFileAsync(__dirname+'/license.txt','utf8') -.then(function(file){ - var tmp=file.split('\n') - return tmp.slice(0,tmp.length-1) +const license = fs.readFileAsync(`${__dirname}/license.txt`, 'utf8') + .then((file) => { + const tmp = file.split('\n'); + return tmp.slice(0, tmp.length - 1); + }); -}) - -function js(name){ - var source=fs.readFileAsync(name,'utf8').then(x=>x.split('\n')) - Promise.join(source,license) - .spread(function(file,license){ - var position=file[0].match('#!') ? 1 : 0 - if(!source[position+1].match("Copyright 2017-2017")){ - return fs.writeFileAsync(name,insert(file,license,position)) - } - }) +function js(name) { + const source = fs.readFileAsync(name, 'utf8').then((x) => x.split('\n')); + Promise.join(source, license) + .spread((file, license) => { + const position = file[0].match('#!') ? 1 : 0; + if (!source[position + 1].match('Copyright 2017-2017')) { + return fs.writeFileAsync(name, insert(file, license, position)); + } + }); } -function vue(name){ - var source=fs.readFileAsync(name,'utf8').then(x=>x.split('\n')) - Promise.join(source,license) - .spread(function(file,license){ - var position=file.findIndex(x=>x.match(' + diff --git a/website/js/components/hooks/steps.js b/website/js/components/hooks/steps.js index 49c9a0cd4..87e555151 100644 --- a/website/js/components/hooks/steps.js +++ b/website/js/components/hooks/steps.js @@ -1,11 +1,24 @@ -var stringify=require('json-stringify-pretty-compact') -var example=stringify(require('./example.js')) -var codeJS=require('raw-loader!./code.js') -var codePY=require('raw-loader!./code.py') +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/ -module.exports=[{ - title:"Create Lambda Function", - text:` +const stringify = require('json-stringify-pretty-compact'); +const example = stringify(require('./example.js')); +const codeJS = require('raw-loader!./code.js'); +const codePY = require('raw-loader!./code.py'); + +module.exports = [{ + title: 'Create Lambda Function', + text: ` 1. Create a lambda function with a name that starts with "qna-", for example: > qna-ExtraSpecial @@ -16,14 +29,14 @@ module.exports=[{ 3. Click "Copy Lambda Role" below and paste into Role 4. click "Create Function" `, -buttons:[{ - text:"Copy Lambda Role", - id:"Role", - loading:false -}] -},{ - title:"Write Code", - text:` + buttons: [{ + text: 'Copy Lambda Role', + id: 'Role', + loading: false, + }], +}, { + title: 'Write Code', + text: ` A minimal function would look like this ##### node.js @@ -45,28 +58,28 @@ The lambda handler must return the modified event object. ${example} ~~~ `, - buttons:[{ - text:"Copy node.js Code", - id:"code-js", - loading:false - },{ - text:"Copy python Code", - id:"code-py", - loading:false - },{ - text:"Copy Example Event", - id:"request", - loading:false - }] -},{ - title:"Add/Edit Question", - text:` + buttons: [{ + text: 'Copy node.js Code', + id: 'code-js', + loading: false, + }, { + text: 'Copy python Code', + id: 'code-py', + loading: false, + }, { + text: 'Copy Example Event', + id: 'request', + loading: false, + }], +}, { + title: 'Add/Edit Question', + text: ` For a new or existing question edit the Lambda field to contain the name or ARN of your created lambda function -` -},{ - title:"Test Question", - text:` +`, +}, { + title: 'Test Question', + text: ` Ask question in QnAClient to see your new response -` -} -] +`, +}, +]; diff --git a/website/js/components/import.vue b/website/js/components/import.vue index 1333b209d..99f4bf37e 100644 --- a/website/js/components/import.vue +++ b/website/js/components/import.vue @@ -1,8 +1,15 @@ - - +/********************************************************************************************************************* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * + * * + * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * + * with the License. A copy of the License is located at * + * * + * http://www.apache.org/licenses/ * + * * + * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * + * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * + * and limitations under the License. * + *********************************************************************************************************************/