diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index cc2c31fc8..2d52c374c 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -26,6 +26,7 @@ "sanitize-filename": "^1.6.3", "sax": "^1.2.4", "temp": "^0.9.1", + "text-table": "^0.2.0", "title-case": "^3.0.2", "valid-url": "^1.0.9", "winston": "^3.3.3", @@ -47,6 +48,7 @@ "@types/readline-sync": "^1.4.3", "@types/sax": "^1.2.1", "@types/temp": "^0.8.34", + "@types/text-table": "^0.2.3", "@types/valid-url": "^1.0.3", "@typescript-eslint/eslint-plugin": "^5.33.0", "@typescript-eslint/parser": "^5.33.0", @@ -92,17 +94,89 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.22.6", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz", @@ -143,12 +217,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -206,22 +280,22 @@ "dev": true }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -313,9 +387,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -345,13 +419,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -430,9 +504,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -604,33 +678,33 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -648,13 +722,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1577,6 +1651,12 @@ "@types/node": "*" } }, + "node_modules/@types/text-table": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@types/text-table/-/text-table-0.2.3.tgz", + "integrity": "sha512-MUW7DN7e178wJ2dB9rHuhwUWRUJGrl8fCng37BEWV0r2r5VpzkRFRiMfnX6sjXlu4tMn41lrjzsVh/z1XrKc+A==", + "dev": true + }, "node_modules/@types/valid-url": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/valid-url/-/valid-url-1.0.3.tgz", @@ -7152,8 +7232,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/through2": { "version": "2.0.5", @@ -7880,12 +7959,71 @@ } }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/compat-data": { @@ -7918,12 +8056,12 @@ } }, "@babel/generator": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", - "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -7973,19 +8111,19 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -8053,9 +8191,9 @@ "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -8076,13 +8214,13 @@ } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -8145,9 +8283,9 @@ } }, "@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -8268,30 +8406,30 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -8305,13 +8443,13 @@ } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -9091,6 +9229,12 @@ "@types/node": "*" } }, + "@types/text-table": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@types/text-table/-/text-table-0.2.3.tgz", + "integrity": "sha512-MUW7DN7e178wJ2dB9rHuhwUWRUJGrl8fCng37BEWV0r2r5VpzkRFRiMfnX6sjXlu4tMn41lrjzsVh/z1XrKc+A==", + "dev": true + }, "@types/valid-url": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/valid-url/-/valid-url-1.0.3.tgz", @@ -13215,8 +13359,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "through2": { "version": "2.0.5", diff --git a/package.json b/package.json index d4a4f6ca4..5a327cafd 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@types/readline-sync": "^1.4.3", "@types/sax": "^1.2.1", "@types/temp": "^0.8.34", + "@types/text-table": "^0.2.3", "@types/valid-url": "^1.0.3", "@typescript-eslint/eslint-plugin": "^5.33.0", "@typescript-eslint/parser": "^5.33.0", @@ -101,6 +102,7 @@ "sanitize-filename": "^1.6.3", "sax": "^1.2.4", "temp": "^0.9.1", + "text-table": "^0.2.0", "title-case": "^3.0.2", "valid-url": "^1.0.9", "winston": "^3.3.3", diff --git a/src/app.ts b/src/app.ts index bb35ea527..3917f282b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,7 +31,8 @@ import { getRandomPun, setIgnoredWarnings, getLocalSushiVersion, - checkSushiVersion + checkSushiVersion, + writeFSHIndex } from './utils'; const FSH_VERSION = '3.0.0-ballot'; @@ -282,7 +283,8 @@ async function runBuild(input: string, program: OptionValues, helpText: string) logger.info('Converting FSH to FHIR resources...'); const outPackage = exportFHIR(tank, defs); - writeFHIRResources(outDir, outPackage, defs, program.snapshot); + const skippedResources = writeFHIRResources(outDir, outPackage, defs, program.snapshot); + writeFSHIndex(outDir, outPackage, input, skippedResources); if (program.preprocessed) { logger.info('Writing preprocessed FSH...'); diff --git a/src/export/CodeSystemExporter.ts b/src/export/CodeSystemExporter.ts index 4409c3709..297700689 100644 --- a/src/export/CodeSystemExporter.ts +++ b/src/export/CodeSystemExporter.ts @@ -289,6 +289,11 @@ export class CodeSystemExporter { cleanResource(codeSystem, (prop: string) => ['_sliceName', '_primitive'].includes(prop)); this.updateCount(codeSystem, fshDefinition); this.pkg.codeSystems.push(codeSystem); + this.pkg.fshMap.set(codeSystem.getFileName(), { + ...fshDefinition.sourceInfo, + fshName: fshDefinition.name, + fshType: 'CodeSystem' + }); return codeSystem; } diff --git a/src/export/InstanceExporter.ts b/src/export/InstanceExporter.ts index 18dcb6d6c..12d14e97a 100644 --- a/src/export/InstanceExporter.ts +++ b/src/export/InstanceExporter.ts @@ -850,6 +850,13 @@ export class InstanceExporter implements Fishable { this.checkForNamelessSlices(fshDefinition, instanceDef, instanceOfStructureDefinition); cleanResource(instanceDef); this.pkg.instances.push(instanceDef); + if (fshDefinition.usage !== 'Inline') { + this.pkg.fshMap.set(instanceDef.getFileName(), { + ...fshDefinition.sourceInfo, + fshName: fshDefinition.name, + fshType: fshDefinition.constructorName + }); + } // Once all rules are set, we should ensure that we did not add a duplicate profile URL anywhere // if any of the duplicates have child elements, such as extension, merge them diff --git a/src/export/Package.ts b/src/export/Package.ts index a73d4a909..4938eeca2 100644 --- a/src/export/Package.ts +++ b/src/export/Package.ts @@ -4,7 +4,7 @@ import { findImposeProfiles } from '../fhirtypes/common'; import { StructureDefinition, InstanceDefinition, ValueSet, CodeSystem } from '../fhirtypes'; -import { Configuration } from '../fshtypes'; +import { Configuration, SourceInfo } from '../fshtypes'; import { Fishable, Type, Metadata } from '../utils/Fishable'; export class Package implements Fishable { @@ -16,6 +16,9 @@ export class Package implements Fishable { public readonly valueSets: ValueSet[] = []; public readonly codeSystems: CodeSystem[] = []; + public readonly fshMap: Map = + new Map(); + constructor(public readonly config: Configuration) {} fish( diff --git a/src/export/StructureDefinitionExporter.ts b/src/export/StructureDefinitionExporter.ts index 746245ef3..4e5ec522b 100644 --- a/src/export/StructureDefinitionExporter.ts +++ b/src/export/StructureDefinitionExporter.ts @@ -1316,6 +1316,11 @@ export class StructureDefinitionExporter implements Fishable { } else { this.pkg.profiles.push(structDef); } + this.pkg.fshMap.set(structDef.getFileName(), { + ...fshDefinition.sourceInfo, + fshName: fshDefinition.name, + fshType: fshDefinition.constructorName + }); this.preprocessStructureDefinition(fshDefinition, structDef.type === 'Extension'); diff --git a/src/export/ValueSetExporter.ts b/src/export/ValueSetExporter.ts index d772c6426..80fd358aa 100644 --- a/src/export/ValueSetExporter.ts +++ b/src/export/ValueSetExporter.ts @@ -413,6 +413,11 @@ export class ValueSetExporter { cleanResource(vs, (prop: string) => ['_sliceName', '_primitive'].includes(prop)); this.pkg.valueSets.push(vs); + this.pkg.fshMap.set(vs.getFileName(), { + ...fshDefinition.sourceInfo, + fshName: fshDefinition.name, + fshType: 'ValueSet' + }); return vs; } } diff --git a/src/utils/Processing.ts b/src/utils/Processing.ts index c7db442f0..54e2047c0 100644 --- a/src/utils/Processing.ts +++ b/src/utils/Processing.ts @@ -24,6 +24,7 @@ import { Configuration } from '../fshtypes'; import { axiosGet } from './axiosUtils'; import { ImplementationGuideDependsOn } from '../fhirtypes'; import { FHIRVersionName, getFHIRVersionInfo } from '../utils/FHIRVersionUtils'; +import table from 'text-table'; const EXT_PKG_TO_FHIR_PKG_MAP: { [key: string]: string } = { 'hl7.fhir.extensions.r2': 'hl7.fhir.r2.core#1.0.2', @@ -509,6 +510,7 @@ export function writeFHIRResources( ) { logger.info('Exporting FHIR resources as JSON...'); let count = 0; + const skippedResources: string[] = []; const predefinedResources = defs.allPredefinedResources(); const writeResources = ( resources: { @@ -543,6 +545,7 @@ export function writeFHIRResources( 'If you do want the FSH definition to be ignored, please comment the definition out ' + 'to remove this error.' ); + skippedResources.push(resource.getFileName()); } }); }; @@ -564,6 +567,42 @@ export function writeFHIRResources( writeResources(outPackage.instances.filter(i => i._instanceMeta.usage !== 'Inline')); logger.info(`Exported ${count} FHIR resources as JSON.`); + return skippedResources; +} + +export function writeFSHIndex( + outDir: string, + outPackage: Package, + inputDir: string, + skippedResources: string[] = [] +) { + const index: string[][] = []; + const otherIndex: any[] = []; + for (const [fileName, fshInfo] of outPackage.fshMap) { + if (!skippedResources.includes(fileName)) { + const relativeInput = path.relative(inputDir, fshInfo.file); + index.push([ + fshInfo.fshName, + fshInfo.fshType, + relativeInput, + `${fshInfo.location.startLine} - ${fshInfo.location.endLine}`, + fileName + ]); + otherIndex.push({ + fshFile: relativeInput, + fshName: fshInfo.fshName, + fshType: fshInfo.fshType, + startLine: fshInfo.location.startLine, + endLine: fshInfo.location.endLine, + outputFile: fileName + }); + } + } + // write txt with nice formatting + index.unshift(['Name', 'Type', 'File', 'Lines', 'Output']); + fs.outputFileSync(path.join(outDir, 'fsh-generated', 'fsh-index.txt'), table(index)); + // write json for machine usage + fs.outputJsonSync(path.join(outDir, 'fsh-generated', 'fsh-index.json'), otherIndex); } export function writePreprocessedFSH(outDir: string, inDir: string, tank: FSHTank) { diff --git a/test/export/CodeSystemExporter.test.ts b/test/export/CodeSystemExporter.test.ts index 5c8b0285e..ef38e95be 100644 --- a/test/export/CodeSystemExporter.test.ts +++ b/test/export/CodeSystemExporter.test.ts @@ -12,6 +12,7 @@ import { minimalConfig } from '../utils/minimalConfig'; describe('CodeSystemExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; + let pkg: Package; let exporter: CodeSystemExporter; beforeAll(() => { @@ -22,7 +23,7 @@ describe('CodeSystemExporter', () => { beforeEach(() => { doc = new FSHDocument('fileName'); const input = new FSHTank([doc], minimalConfig); - const pkg = new Package(input.config); + pkg = new Package(input.config); const fisher = new TestFisher(input, defs, pkg); exporter = new CodeSystemExporter(input, pkg, fisher); loggerSpy.reset(); @@ -48,6 +49,26 @@ describe('CodeSystemExporter', () => { }); }); + it('should add source info for the exported code system to the package', () => { + const codeSystem = new FshCodeSystem('MyCodeSystem') + .withFile('Codes.fsh') + .withLocation([2, 5, 29, 33]); + doc.codeSystems.set(codeSystem.name, codeSystem); + const exported = exporter.export().codeSystems; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('CodeSystem-MyCodeSystem.json')).toEqual({ + file: 'Codes.fsh', + location: { + startLine: 2, + startColumn: 5, + endLine: 29, + endColumn: 33 + }, + fshName: 'MyCodeSystem', + fshType: 'CodeSystem' + }); + }); + it('should export a code system with additional metadata', () => { const codeSystem = new FshCodeSystem('MyCodeSystem'); codeSystem.id = 'CodeSystem1'; diff --git a/test/export/InstanceExporter.test.ts b/test/export/InstanceExporter.test.ts index 075233523..ae7ef6054 100644 --- a/test/export/InstanceExporter.test.ts +++ b/test/export/InstanceExporter.test.ts @@ -42,6 +42,7 @@ describe('InstanceExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; let tank: FSHTank; + let pkg: Package; let sdExporter: StructureDefinitionExporter; let csExporter: CodeSystemExporter; let vsExporter: ValueSetExporter; @@ -57,7 +58,7 @@ describe('InstanceExporter', () => { loggerSpy.reset(); doc = new FSHDocument('fileName'); tank = new FSHTank([doc], minimalConfig); - const pkg = new Package(tank.config); + pkg = new Package(tank.config); const fisher = new TestFisher(tank, defs, pkg); sdExporter = new StructureDefinitionExporter(tank, pkg, fisher); csExporter = new CodeSystemExporter(tank, pkg, fisher); @@ -84,6 +85,27 @@ describe('InstanceExporter', () => { expect(exported.length).toBe(1); }); + it('should add source info for the exported instance to the package', () => { + const instance = new Instance('MyInstance') + .withFile('Examples.fsh') + .withLocation([25, 3, 52, 33]); + instance.instanceOf = 'Patient'; + doc.instances.set(instance.name, instance); + const exported = exporter.export().instances; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('Patient-MyInstance.json')).toEqual({ + file: 'Examples.fsh', + location: { + startLine: 25, + startColumn: 3, + endLine: 52, + endColumn: 33 + }, + fshName: 'MyInstance', + fshType: 'Instance' + }); + }); + it('should export multiple instances', () => { const instanceFoo = new Instance('Foo'); instanceFoo.instanceOf = 'Patient'; diff --git a/test/export/StructureDefinition.ExtensionExporter.test.ts b/test/export/StructureDefinition.ExtensionExporter.test.ts index 633457df9..f0567665e 100644 --- a/test/export/StructureDefinition.ExtensionExporter.test.ts +++ b/test/export/StructureDefinition.ExtensionExporter.test.ts @@ -13,6 +13,7 @@ import { ContainsRule, AssignmentRule, CaretValueRule } from '../../src/fshtypes describe('ExtensionExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; + let pkg: Package; let exporter: StructureDefinitionExporter; beforeAll(() => { @@ -28,7 +29,7 @@ describe('ExtensionExporter', () => { loggerSpy.reset(); doc = new FSHDocument('fileName'); const input = new FSHTank([doc], minimalConfig); - const pkg = new Package(input.config); + pkg = new Package(input.config); const fisher = new TestFisher(input, defs, pkg); exporter = new StructureDefinitionExporter(input, pkg, fisher); }); @@ -45,6 +46,26 @@ describe('ExtensionExporter', () => { expect(exported.length).toBe(1); }); + it('should add source info for the exported extension to the package', () => { + const extension = new Extension('Foo') + .withFile('GoodExtensions.fsh') + .withLocation([38, 4, 49, 15]); + doc.extensions.set(extension.name, extension); + const exported = exporter.export().extensions; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('StructureDefinition-Foo.json')).toEqual({ + file: 'GoodExtensions.fsh', + location: { + startLine: 38, + startColumn: 4, + endLine: 49, + endColumn: 15 + }, + fshName: 'Foo', + fshType: 'Extension' + }); + }); + it('should export multiple extensions', () => { const extensionFoo = new Extension('Foo'); const extensionBar = new Extension('Bar'); diff --git a/test/export/StructureDefinition.LogicalExporter.test.ts b/test/export/StructureDefinition.LogicalExporter.test.ts index 917d28649..8b8b7a91b 100644 --- a/test/export/StructureDefinition.LogicalExporter.test.ts +++ b/test/export/StructureDefinition.LogicalExporter.test.ts @@ -23,6 +23,7 @@ import { readFileSync } from 'fs-extra'; describe('LogicalExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; + let pkg: Package; let exporter: StructureDefinitionExporter; beforeAll(() => { @@ -34,7 +35,7 @@ describe('LogicalExporter', () => { loggerSpy.reset(); doc = new FSHDocument('fileName'); const input = new FSHTank([doc], minimalConfig); - const pkg = new Package(input.config); + pkg = new Package(input.config); const fisher = new TestFisher(input, defs, pkg); exporter = new StructureDefinitionExporter(input, pkg, fisher); }); @@ -51,6 +52,26 @@ describe('LogicalExporter', () => { expect(exported.length).toBe(1); }); + it('should add source info for the exported logical model to the package', () => { + const logical = new Logical('Toasty') + .withFile('AlwaysLogical.fsh') + .withLocation([48, 4, 59, 15]); + doc.logicals.set(logical.name, logical); + const exported = exporter.export().logicals; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('StructureDefinition-Toasty.json')).toEqual({ + file: 'AlwaysLogical.fsh', + location: { + startLine: 48, + startColumn: 4, + endLine: 59, + endColumn: 15 + }, + fshName: 'Toasty', + fshType: 'Logical' + }); + }); + it('should export multiple logical models', () => { const logicalFoo = new Logical('Foo'); const logicalBar = new Logical('Bar'); diff --git a/test/export/StructureDefinition.ProfileExporter.test.ts b/test/export/StructureDefinition.ProfileExporter.test.ts index b4ddacdef..c6df97455 100644 --- a/test/export/StructureDefinition.ProfileExporter.test.ts +++ b/test/export/StructureDefinition.ProfileExporter.test.ts @@ -18,6 +18,7 @@ import { MismatchedTypeError } from '../../src/errors'; describe('ProfileExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; + let pkg: Package; let exporter: StructureDefinitionExporter; beforeAll(() => { @@ -29,7 +30,7 @@ describe('ProfileExporter', () => { loggerSpy.reset(); doc = new FSHDocument('fileName'); const input = new FSHTank([doc], minimalConfig); - const pkg = new Package(input.config); + pkg = new Package(input.config); const fisher = new TestFisher(input, defs, pkg); exporter = new StructureDefinitionExporter(input, pkg, fisher); }); @@ -47,6 +48,25 @@ describe('ProfileExporter', () => { expect(exported.length).toBe(1); }); + it('should add source info for the exported profile to the package', () => { + const profile = new Profile('Foo').withFile('SomeProfiles.fsh').withLocation([28, 4, 39, 15]); + profile.parent = 'Basic'; + doc.profiles.set(profile.name, profile); + const exported = exporter.export().profiles; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('StructureDefinition-Foo.json')).toEqual({ + file: 'SomeProfiles.fsh', + location: { + startLine: 28, + startColumn: 4, + endLine: 39, + endColumn: 15 + }, + fshName: 'Foo', + fshType: 'Profile' + }); + }); + it('should export multiple profiles', () => { const profileFoo = new Profile('Foo'); profileFoo.parent = 'Basic'; diff --git a/test/export/StructureDefinition.ResourceExporter.test.ts b/test/export/StructureDefinition.ResourceExporter.test.ts index 1fc8eebe0..0b8755b46 100644 --- a/test/export/StructureDefinition.ResourceExporter.test.ts +++ b/test/export/StructureDefinition.ResourceExporter.test.ts @@ -52,6 +52,24 @@ describe('ResourceExporter', () => { expect(exported.length).toBe(1); }); + it('should add source info for the exported resource to the package', () => { + const resource = new Resource('Tree').withFile('Treesource.fsh').withLocation([68, 4, 72, 15]); + doc.resources.set(resource.name, resource); + const exported = exporter.export().resources; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('StructureDefinition-Tree.json')).toEqual({ + file: 'Treesource.fsh', + location: { + startLine: 68, + startColumn: 4, + endLine: 72, + endColumn: 15 + }, + fshName: 'Tree', + fshType: 'Resource' + }); + }); + it('should export multiple resources', () => { const resourceFoo = new Resource('Foo'); const resourceBar = new Resource('Bar'); diff --git a/test/export/ValueSetExporter.test.ts b/test/export/ValueSetExporter.test.ts index 641870c5b..50321382c 100644 --- a/test/export/ValueSetExporter.test.ts +++ b/test/export/ValueSetExporter.test.ts @@ -27,6 +27,7 @@ import { minimalConfig } from '../utils/minimalConfig'; describe('ValueSetExporter', () => { let defs: FHIRDefinitions; let doc: FSHDocument; + let pkg: Package; let exporter: ValueSetExporter; beforeAll(() => { @@ -38,7 +39,7 @@ describe('ValueSetExporter', () => { loggerSpy.reset(); doc = new FSHDocument('fileName'); const input = new FSHTank([doc], minimalConfig); - const pkg = new Package(input.config); + pkg = new Package(input.config); const fisher = new TestFisher(input, defs, pkg); exporter = new ValueSetExporter(input, pkg, fisher); loggerSpy.reset(); @@ -63,6 +64,24 @@ describe('ValueSetExporter', () => { }); }); + it('should add source info for the exported value set to the package', () => { + const valueSet = new FshValueSet('MyValueSet').withFile('VS.fsh').withLocation([3, 6, 30, 34]); + doc.valueSets.set(valueSet.name, valueSet); + const exported = exporter.export().valueSets; + expect(exported.length).toBe(1); + expect(pkg.fshMap.get('ValueSet-MyValueSet.json')).toEqual({ + file: 'VS.fsh', + location: { + startLine: 3, + startColumn: 6, + endLine: 30, + endColumn: 34 + }, + fshName: 'MyValueSet', + fshType: 'ValueSet' + }); + }); + it('should export multiple value sets', () => { const breakfast = new FshValueSet('BreakfastVS'); const lunch = new FshValueSet('LunchVS'); diff --git a/test/utils/Processing.test.ts b/test/utils/Processing.test.ts index c8e04babf..dfab4864f 100644 --- a/test/utils/Processing.test.ts +++ b/test/utils/Processing.test.ts @@ -30,7 +30,8 @@ import { writePreprocessedFSH, getLocalSushiVersion, getLatestSushiVersion, - checkSushiVersion + checkSushiVersion, + writeFSHIndex } from '../../src/utils/Processing'; import { FHIRDefinitions } from '../../src/fhirdefs'; import { Package } from '../../src/export'; @@ -1718,6 +1719,19 @@ describe('Processing', () => { temp.cleanupSync(); }); + describe('return value', () => { + afterEach(() => { + temp.cleanupSync(); + }); + + it('should return a list of filenames for skipped resources', () => { + const skippedResources = writeFHIRResources(tempIGPubRoot, outPackage, defs, false); + expect(skippedResources).toHaveLength(2); + expect(skippedResources).toContain('StructureDefinition-my-duplicate-profile.json'); + expect(skippedResources).toContain('Patient-my-duplicate-instance.json'); + }); + }); + describe('IG Publisher mode', () => { beforeAll(() => { writeFHIRResources(tempIGPubRoot, outPackage, defs, false); @@ -1836,6 +1850,151 @@ describe('Processing', () => { }); }); + describe('#writeFSHIndex()', () => { + let tempIGPubRoot: string; + let fshRoot: string; + let outPackage: Package; + + beforeAll(() => { + tempIGPubRoot = temp.mkdirSync('output-ig-dir'); + const input = path.join(__dirname, 'fixtures', 'valid-yaml'); + fshRoot = path.join(input, 'good-ig', 'input', 'fsh'); + const config = readConfig(input); + outPackage = new Package(config); + + outPackage.fshMap.set('StructureDefinition-my-profile.json', { + fshName: 'MyProfile', + fshType: 'Profile', + file: path.join(fshRoot, 'SomeThings.fsh'), + location: { + startLine: 1, + startColumn: 1, + endLine: 5, + endColumn: 28 + } + }); + + outPackage.fshMap.set('StructureDefinition-my-extension.json', { + fshName: 'MyExtension', + fshType: 'Extension', + file: path.join(fshRoot, 'SomeThings.fsh'), + location: { + startLine: 7, + startColumn: 1, + endLine: 15, + endColumn: 23 + } + }); + + outPackage.fshMap.set('Observation-secret-observation.json', { + fshName: 'SecretObservation', + fshType: 'Instance', + file: path.join(fshRoot, 'secrets', 'SecretThings.fsh'), + location: { + startLine: 2, + startColumn: 1, + endLine: 39, + endColumn: 55 + } + }); + }); + + it('should create text and json index files that contain each resource in the package', () => { + writeFSHIndex(tempIGPubRoot, outPackage, fshRoot, []); + const textIndex = path.join(tempIGPubRoot, 'fsh-generated', 'fsh-index.txt'); + const jsonIndex = path.join(tempIGPubRoot, 'fsh-generated', 'fsh-index.json'); + expect(fs.existsSync(textIndex)).toBeTrue(); + expect(fs.existsSync(jsonIndex)).toBeTrue(); + + const textContents = fs.readFileSync(textIndex, 'utf-8'); + expect(textContents).toMatch( + /MyProfile\s+Profile\s+SomeThings\.fsh\s+1 - 5\s+StructureDefinition-my-profile\.json/s + ); + expect(textContents).toMatch( + /MyExtension\s+Extension\s+SomeThings\.fsh\s+7 - 15\s+StructureDefinition-my-extension\.json/s + ); + const secretRegex = new RegExp( + `SecretObservation\\s+Instance\\s+secrets\\${path.sep}SecretThings\\.fsh\\s+2 - 39\\s+Observation-secret-observation\\.json`, + 's' + ); + expect(textContents).toMatch(secretRegex); + + const jsonContents = fs.readJsonSync(jsonIndex); + expect(jsonContents).toHaveLength(3); + expect(jsonContents).toContainEqual({ + fshFile: 'SomeThings.fsh', + fshName: 'MyProfile', + fshType: 'Profile', + startLine: 1, + endLine: 5, + outputFile: 'StructureDefinition-my-profile.json' + }); + expect(jsonContents).toContainEqual({ + fshFile: 'SomeThings.fsh', + fshName: 'MyExtension', + fshType: 'Extension', + startLine: 7, + endLine: 15, + outputFile: 'StructureDefinition-my-extension.json' + }); + expect(jsonContents).toContainEqual({ + fshFile: path.join('secrets', 'SecretThings.fsh'), + fshName: 'SecretObservation', + fshType: 'Instance', + startLine: 2, + endLine: 39, + outputFile: 'Observation-secret-observation.json' + }); + }); + + it('should not include a resource in the package if it is in the list of resources to skip', () => { + writeFSHIndex(tempIGPubRoot, outPackage, fshRoot, ['StructureDefinition-my-extension.json']); + const textIndex = path.join(tempIGPubRoot, 'fsh-generated', 'fsh-index.txt'); + const jsonIndex = path.join(tempIGPubRoot, 'fsh-generated', 'fsh-index.json'); + expect(fs.existsSync(textIndex)).toBeTrue(); + expect(fs.existsSync(jsonIndex)).toBeTrue(); + + const textContents = fs.readFileSync(textIndex, 'utf-8'); + expect(textContents).toMatch( + /MyProfile\s+Profile\s+SomeThings\.fsh\s+1 - 5\s+StructureDefinition-my-profile\.json/s + ); + const secretRegex = new RegExp( + `SecretObservation\\s+Instance\\s+secrets\\${path.sep}SecretThings\\.fsh\\s+2 - 39\\s+Observation-secret-observation\\.json`, + 's' + ); + expect(textContents).toMatch(secretRegex); + + expect(textContents).not.toMatch('MyExtension'); + + const jsonContents = fs.readJsonSync(jsonIndex); + expect(jsonContents).toHaveLength(2); + expect(jsonContents).toContainEqual({ + fshFile: 'SomeThings.fsh', + fshName: 'MyProfile', + fshType: 'Profile', + startLine: 1, + endLine: 5, + outputFile: 'StructureDefinition-my-profile.json' + }); + expect(jsonContents).toContainEqual({ + fshFile: path.join('secrets', 'SecretThings.fsh'), + fshName: 'SecretObservation', + fshType: 'Instance', + startLine: 2, + endLine: 39, + outputFile: 'Observation-secret-observation.json' + }); + expect(jsonContents).not.toContainEqual({ + fshFile: 'SomeThings.fsh', + fshName: 'MyExtension', + fshType: 'Extension', + startLine: 7, + endLine: 15, + outputFile: 'StructureDefinition-my-extension.json' + }); + }); + }); + describe('#writePreprocessedFSH', () => { let tank: FSHTank; let tempIn: string;