Compare commits

..

167 Commits

Author SHA1 Message Date
Nora
9ed6b011a5 Merge pull request #2662 from github/v1.8.9
Some checks failed
Release / Release (push) Has been cancelled
Release / Publish to VS Code Marketplace (push) Has been cancelled
Release / Publish to Open VSX Registry (push) Has been cancelled
Release prep for v1.8.9
2023-08-03 10:52:15 +02:00
Nora
912254fd3c Update extensions/ql-vscode/CHANGELOG.md
Co-authored-by: Charis Kyriakou <charisk@users.noreply.github.com>
2023-08-03 10:31:41 +02:00
Nora
7eab911cc5 v1.8.9 2023-08-03 08:17:20 +00:00
Nora
80ae9a4b36 Merge pull request #2658 from github/nora-koen/data-extensions-editor-without-ql-submodule
Remove submodules dependency from data extension editor
2023-08-02 17:30:46 +02:00
Nora
868fae093d Reorder db language check 2023-08-02 14:25:39 +00:00
Andrew Eisenberg
1289ab509c Merge pull request #2659 from github/aeisenberg/download-pack-in-tests2
Install `java-all` and transitive dependencies
2023-08-01 07:43:40 -07:00
Nora
5f489212d4 Add test for setup 2023-08-01 12:39:30 +00:00
Nora
fea45ea04d wrap all describe blocks in external api usage test 2023-08-01 12:39:30 +00:00
Nora
a39e55590a Move query setup to query file 2023-08-01 12:39:30 +00:00
Nora
6e4641f2c1 Clean up runQyery test 2023-08-01 12:39:30 +00:00
Nora
553e5cb4a1 Remove automodel qll file 2023-08-01 12:39:29 +00:00
Nora
4c0f68f193 Adjust picker test 2023-08-01 12:39:29 +00:00
Nora
1ee9cdaadd Add test for error log 2023-08-01 12:39:29 +00:00
Nora
098437b463 Cleanup 2023-08-01 12:39:29 +00:00
Nora
558a70e3c8 Adjust external api query test 2023-08-01 12:39:29 +00:00
Nora
7c10447bb5 Add .github folder manually 2023-08-01 12:39:29 +00:00
Nora
9fd6cb8c1f Cleanup and install pack dependencies 2023-08-01 12:39:29 +00:00
Koen Vlaswinkel
f4da522953 wip: data extensions editor without ql submodule 2023-08-01 12:39:29 +00:00
Robert
6dfe1736f8 Merge pull request #2657 from github/robertbrignull/clean-test-dir
Add `npm run clean-test-dir`
2023-08-01 09:19:42 +01:00
Andrew Eisenberg
b46e0ab175 Install java-all and transitive dependencies
need to install all transitive dependencies of `java-all` as well. This
will do it.
2023-07-31 11:14:59 -07:00
Andrew Eisenberg
34fa629054 Merge pull request #2655 from github/aeisenberg/download-pack-in-tests
Download `codeql/java-all` in tests
2023-07-31 10:02:14 -07:00
Robert
5107086a93 Switch to using find 2023-07-31 11:09:31 +01:00
Robert
58c5c0e5f5 Add npm run clean-test-dir 2023-07-31 11:09:31 +01:00
Charis Kyriakou
5427b5718f Only show automodel button for Java (#2656) 2023-07-31 09:43:07 +00:00
Andrew Eisenberg
0cc399507f Download codeql/java-all in tests
An upcoming change in the CLI will require that the extensible
predicates that are targeted by a data extension needs to be available
in order for the `resolve extensions` command to succeed.

There are a handful of tests that are failing with this new CLI. This
change will update the tests so that the `codeql/java-all` pack is
available in the tests and ensures they pass.
2023-07-28 14:49:55 -07:00
Robert
bb9299e0e2 Merge pull request #2646 from github/robertbrignull/fix_alert_461
Split codeQL.copyVariantAnalysisRepoList into two commands
2023-07-28 10:56:35 +01:00
Robert
e8afa54584 Fix test by mocking the correct function 2023-07-28 10:26:52 +01:00
Robert
d94443e025 Merge pull request #2652 from github/robertbrignull/data_narrow
Make the data extensions editor look a little bit better at small screen sizes
2023-07-28 10:15:28 +01:00
Robert
0e5cb1a3e8 Merge pull request #2653 from github/robertbrignull/dependencies_versions
Change all dependencies to use ^ instead of ~
2023-07-28 10:09:57 +01:00
Robert
59958a5b32 Log a ui-interaction telemetry event when copying repository lists 2023-07-28 10:09:12 +01:00
Robert
3d9b2da514 Remove codeQL.copyVariantAnalysisRepoListView command and instead call copyRepoListToClipboard directly 2023-07-28 10:09:11 +01:00
Robert
3b8cea8df4 Remove codeQL.copyVariantAnalysisRepoListQueryHistory command and instead call copyRepoListToClipboard directly 2023-07-28 10:00:38 +01:00
Robert
6adf683c87 Merge branch 'main' into robertbrignull/dependencies_versions 2023-07-28 09:51:43 +01:00
Robert
37f1c62ee6 Merge branch 'main' into robertbrignull/data_narrow 2023-07-28 09:51:27 +01:00
Chuan-kai Lin
c1107d7423 Merge pull request #2649 from github/cklin/remove-legacy-query-server-test
legacy-query.test.ts: skip if CLI supports new query server
2023-07-27 09:48:36 -07:00
Chuan-kai Lin
72fa1c5583 legacy-query.test.ts: skip if CLI supports new query server 2023-07-27 09:10:04 -07:00
github-actions[bot]
5f65498e0a Bump CLI version from v2.14.0 to v2.14.1 for integration tests (#2650)
Co-authored-by: github-actions[bot] <github-actions@github.com>
2023-07-27 16:04:05 +00:00
Shati Patel
6e21706c15 Implement "Hide modeled APIs" checkbox and make it the default (#2651) 2023-07-27 15:49:41 +00:00
Robert
4dcca4e97c Change all dependencies to use ^ instead of ~ 2023-07-27 16:15:39 +01:00
Robert
84492d2fb9 Make sure the classifications don't wrap 2023-07-27 16:00:38 +01:00
Robert
a2c9ac792b Move the method classification to the start of the row 2023-07-27 15:57:45 +01:00
Robert
18704558d3 Make the method name column 50% 2023-07-27 15:57:34 +01:00
Robert
ca16dca7ed Merge pull request #2645 from github/robertbrignull/fix_alert_546
Don't alert for multiple usages of built-in VS Code commands
2023-07-27 15:20:39 +01:00
Robert
f05d5d9766 Split codeQL.copyVariantAnalysisRepoList into two commands 2023-07-27 12:22:19 +01:00
Robert
aacc243bae Don't report multiply usages of builtin VS Code commands 2023-07-27 11:24:18 +01:00
Robert
396dc3e915 Merge pull request #2644 from github/robertbrignull/fix_alert_384
Fix alert by rewriting query history scrubbed to do fewer file operations
2023-07-27 11:22:10 +01:00
Robert
d3b2d0fce8 Fix indentation in query 2023-07-27 11:14:14 +01:00
Robert
4d4cd4c2d6 Use getErrorMessage 2023-07-27 10:32:19 +01:00
Shati Patel
72512da3b5 Data extensions editor: Allow users to pick an existing database from their workspace (#2643) 2023-07-27 10:09:12 +01:00
Koen Vlaswinkel
c2ed98eb85 Merge pull request #2633 from github/koesie10/automodel-v2
Add LLM functionality using auto-model V2
2023-07-27 10:02:55 +02:00
Koen Vlaswinkel
bebe130fb0 Do not use mocked URI in locations test 2023-07-27 09:40:37 +02:00
Koen Vlaswinkel
db065584fa Merge remote-tracking branch 'origin/main' into koesie10/automodel-v2 2023-07-27 09:18:59 +02:00
Robert
844f25ed98 Rewrite query history scrubbed to do fewer file operations 2023-07-26 16:56:02 +01:00
Koen Vlaswinkel
546f668301 Move createMockUri to mocking helpers 2023-07-26 14:35:15 +02:00
Koen Vlaswinkel
a79753d0a5 Move all runAutoModelQuery arguments into the options object 2023-07-26 14:32:43 +02:00
Koen Vlaswinkel
32c44cdfe3 Rename Options to AutoModelQueriesOptions 2023-07-26 14:31:28 +02:00
Koen Vlaswinkel
de5dbea69f Use promisify for gzip 2023-07-26 14:28:45 +02:00
Robert
3f896751f3 Merge pull request #2640 from github/robertbrignull/fix_alert_547
Fix alert by replacing regex with path.basename
2023-07-26 11:18:40 +01:00
Robert
41f5beb619 Merge pull request #2638 from github/robertbrignull/data_new_header
Add new data extensions header UI elements
2023-07-26 11:12:25 +01:00
Koen Vlaswinkel
5e5535653b Merge pull request #2642 from github/koesie10/remove-path-browserify
Remove path-browserify
2023-07-26 12:09:47 +02:00
Robert
af50d90bcb Merge branch 'main' into robertbrignull/data_new_header 2023-07-26 10:29:22 +01:00
Robert
c5a4c53a1a Merge branch 'main' into robertbrignull/fix_alert_547 2023-07-26 10:26:24 +01:00
Koen Vlaswinkel
016940f2ce Remove path-browserify 2023-07-26 11:23:39 +02:00
Robert
e877695a14 Merge pull request #2641 from github/robertbrignull/LockFileForStandardQueryResult
Unexport LockFileForStandardQueryResult
2023-07-26 10:22:53 +01:00
Robert
e2256e28ba Unexport LockFileForStandardQueryResult 2023-07-26 10:06:55 +01:00
Robert
5c08083336 Merge pull request #2639 from github/robertbrignull/data_progress
Remove custom progress bar and use normal VS Code notification for progress
2023-07-26 10:05:05 +01:00
Robert
07b8732a31 Use custom implementation of basename instead of path-browserify version 2023-07-26 09:59:02 +01:00
Robert
3e49d05ef9 Text is uppercased automatically by styling 2023-07-26 09:51:51 +01:00
Koen Vlaswinkel
83cc9835e8 Merge pull request #2634 from github/koesie10/cleanup-query-resolver
Make query resolver more generic
2023-07-26 09:36:32 +02:00
Robert
c5af8bdcd7 Replace regex with path.basename 2023-07-25 17:29:34 +01:00
Robert
55b21c2add Remove custom progress bar and use normal VS Code notification for progress 2023-07-25 15:33:39 +01:00
Charis Kyriakou
b87fe94a92 Remove most recent commit information and sorting (#2637) 2023-07-25 14:15:08 +00:00
Robert
493de4c190 Add new header UI elements 2023-07-25 15:01:27 +01:00
Shati Patel
8f99ed2478 Data extensions editor: Change "already modeled" message (#2636) 2023-07-25 13:40:54 +00:00
Shati Patel
cdcbdc60fb Data extensions editor: Remove buttons that are no longer needed (#2635) 2023-07-25 14:12:16 +01:00
Robert
e1bbbd6e9c Merge pull request #2631 from github/robertbrignull/deadcode_ci
Add check for deadcode for CI
2023-07-25 13:09:44 +01:00
Koen Vlaswinkel
84de8ad252 Add creation of auto-model request V2 2023-07-25 10:35:19 +02:00
Koen Vlaswinkel
57bcfbbe29 Extract creation of lock file to more generic function 2023-07-25 10:03:01 +02:00
Koen Vlaswinkel
32656c1cb8 Extract query resolving to more generic functions 2023-07-25 10:03:01 +02:00
Robert
5572cece83 Convert find-deadcode to a script 2023-07-24 18:00:30 +01:00
Robert
08675e6713 Rename to tsconfig.deadcode.json 2023-07-24 17:27:39 +01:00
Robert
abee109dbd Merge branch 'main' into robertbrignull/deadcode_ci 2023-07-24 17:26:18 +01:00
Robert
ef27730e5e Merge pull request #2632 from github/robertbrignull/deadcode_changes
Remove or fix dead code / unused exports
2023-07-24 16:32:13 +01:00
Robert
10c6708db5 Fix reference to tsconfig.json 2023-07-24 14:29:01 +01:00
Robert
a618aed415 Mark fileMock and styleMock as allowable exports 2023-07-24 14:28:41 +01:00
Robert
8e8e0faa9e Unexport types that are unused outside of their source file 2023-07-24 14:22:23 +01:00
Robert
41ce5086e7 Mark the extension activation function as allowed to be exported but unused 2023-07-24 14:22:23 +01:00
Robert
a79b71cff6 Switch ALLOW_HTTP_SETTING for allowHttp() 2023-07-24 14:22:23 +01:00
Robert
f0318b0c84 Delete vsCodeGetConfiguration 2023-07-24 14:22:23 +01:00
Robert
814acfa74a Add find-deadcode to CI linting workflow 2023-07-24 11:23:04 +01:00
Robert
d73276c136 Add find-deadcode npm script 2023-07-24 11:23:01 +01:00
Robert
44b58280e8 Merge pull request #2628 from github/robertbrignull/disposable
Merge definitions of Disposable where possible
2023-07-24 11:20:39 +01:00
Robert
49a05c412c Delete pathRowClassName 2023-07-24 11:11:55 +01:00
Robert
f57bbc2b52 Delete decimalFormatter 2023-07-24 11:11:55 +01:00
Robert
e620120144 Delete getTestDirectory 2023-07-24 11:11:55 +01:00
Robert
6fbe95a334 Delete isRemoteSystemDefinedListDbItem 2023-07-24 11:11:55 +01:00
Robert
cb4dcc81ea Delete remoteDbKinds and localDbKinds 2023-07-24 11:11:55 +01:00
Robert
3126c8d1a8 Delete PAGE_SIZE 2023-07-24 11:11:55 +01:00
Robert
0d7814c778 Delete InspectionResult 2023-07-24 11:11:55 +01:00
Robert
f70ea71885 Delete isVariantAnalysisLiveResultsEnabled 2023-07-24 11:11:55 +01:00
Robert
04df20a732 Install ts-unused-exports 2023-07-24 11:10:19 +01:00
Robert
c7b556e748 Merge pull request #2624 from github/robertbrignull/autoClosingPairs
Delete autoClosingPairs from LanguageConfiguration to appease proposed API
2023-07-24 11:04:52 +01:00
Charis Kyriakou
8314a5486d Merge pull request #2627 from github/charisk/remove-deprecated-version-support
Remove conditionals and version constraints for unsupported CLI versions
2023-07-24 10:07:34 +01:00
Charis Kyriakou
e80ef7c1dc Remove CLI_VERSION_WITH_PER_QUERY_EVAL_LOG constraint 2023-07-24 08:24:07 +00:00
Robert
f1a928994a Merge all our DisposableObject definitions 2023-07-21 17:06:53 +01:00
Charis Kyriakou
0f594704d5 Remove CLI_VERSION_WITH_STRUCTURED_EVAL_LOG constraint 2023-07-21 15:37:56 +00:00
Charis Kyriakou
3064415068 Remove setting of evaluator log verbosity level 2023-07-21 15:33:07 +00:00
Charis Kyriakou
f03ef66596 Update handling of return value from packlist command 2023-07-21 15:31:57 +00:00
Robert
0617e3ec7f Merge pull request #2626 from github/robertbrignull/data-make-selected
Instead of resetting the database after importing, pass through makeSelected = false
2023-07-21 16:20:37 +01:00
Shati Patel
dacaf4e394 Update title in Data extensions editor tab (#2625) 2023-07-21 14:44:41 +01:00
Robert
e6566b910a Instead of resetting the database after importing, pass through makeSelected = false 2023-07-21 12:49:36 +01:00
Robert
778f839e8e Merge pull request #2623 from github/robertbrignull/data-model-dependency
Implement "model dependency" button in application mode
2023-07-21 12:10:15 +01:00
Robert
52711c5cc1 Delete autoClosingPairs from LanguageConfiguration to appease proposed API 2023-07-21 11:31:55 +01:00
Robert
d8687b5985 Merge pull request #2621 from github/robertbrignull/data-saving
Load existing modeled methods before saving, to avoid overwriting data
2023-07-20 08:54:29 +01:00
Robert
19ad237427 Pull out common code for importing and resetting the current database 2023-07-19 16:29:13 +01:00
Robert
bb246144c2 Add comments to createDataExtensionYamlsForFrameworkMode too 2023-07-19 16:22:00 +01:00
Robert
fa01b33dfa Implement modelDependency message 2023-07-19 16:14:44 +01:00
Robert
00780442dd Send modelDependency message 2023-07-19 16:14:44 +01:00
Robert
5b170d02eb Avoiding overwriting any existing modeled methods from the files 2023-07-19 11:44:12 +01:00
Robert
db4dc89e42 Split loadModeledMethods into loading all files individually and then merging them 2023-07-19 11:44:12 +01:00
Robert
b5b606d486 Make loadModeledMethodFiles return relative paths from the extension pack 2023-07-19 11:43:57 +01:00
Robert
f2c7c41117 Merge pull request #2406 from Marcono1234/location-url-column
Include column numbers in location URLs
2023-07-19 11:01:20 +01:00
Robert
152e194655 Merge branch 'main' into location-url-column 2023-07-19 09:58:46 +01:00
Robert
f12ba96389 Update CHANGELOG.md 2023-07-19 09:57:58 +01:00
Koen Vlaswinkel
add3296071 Merge pull request #2618 from github/dependabot/npm_and_yarn/extensions/ql-vscode/word-wrap-1.2.4
Bump word-wrap from 1.2.3 to 1.2.4 in /extensions/ql-vscode
2023-07-19 10:04:56 +02:00
Koen Vlaswinkel
a90b85c2a6 Merge pull request #2259 from github/koesie10/upgrade-storybook-7
Upgrade to Storybook 7
2023-07-19 09:51:13 +02:00
dependabot[bot]
3568d4a780 Bump word-wrap from 1.2.3 to 1.2.4 in /extensions/ql-vscode
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-18 23:40:55 +00:00
Robert
d3a5a5e669 Merge pull request #2611 from github/robertbrignull/data-unsaved-checkbox
Show whether changes to a method are saved or not
2023-07-18 16:31:46 +01:00
Robert
fc77a52c46 Merge pull request #2614 from github/robertbrignull/Locations
Move components for rendering locations to a separate file
2023-07-18 15:31:15 +01:00
Robert
5617331598 Pass in methodIsUnsaved instead of modifiedSignatures 2023-07-18 15:26:34 +01:00
Robert
76a7a266ff Rename jumpToLocationHandler => handleClick 2023-07-18 15:11:54 +01:00
Robert
b6c60b26cd Rename handleClick => onClick 2023-07-18 15:11:22 +01:00
Robert
30d8303320 Pull out getModelingStatus method and avoid useMemo 2023-07-18 15:07:26 +01:00
Robert
5c12a4b205 Merge pull request #2605 from github/robertbrignull/data-modeled-methods-tests
Refactor the code for loading/saving modeled methods to disk, and add tests
2023-07-18 14:34:21 +01:00
Koen Vlaswinkel
b830781e48 Replace deprecated uses of ComponentMeta and ComponentStory 2023-07-18 15:29:11 +02:00
Koen Vlaswinkel
8329dedd7f Upgrade to Storybook 7 2023-07-18 15:07:15 +02:00
Robert
70e04a1c99 Rename to MdelingStatusIndicator and move to a separate file 2023-07-18 10:59:08 +01:00
Marcono1234
768b95d3a9 Fix typo in CHANGELOG.md (#2617) 2023-07-17 19:39:38 +00:00
Shati Patel
8e4ee5df3d Update release test plan (#2616) 2023-07-17 19:05:25 +01:00
Alexander Eyers-Taylor
baa2a7fed3 Add comma as a word boundary charecter. (#2615)
* Add comma as a word boundary charecter.

* Add changelog for missing trailing commas.
2023-07-17 16:12:36 +00:00
Robert
1f16294d7e Avoid else blocks when we're returning early 2023-07-17 17:04:41 +01:00
Robert
679266c0b7 Remove unnecessarily forcing non-undefined 2023-07-17 17:02:59 +01:00
Robert
f1e96f7812 Use more standard name for callback 2023-07-17 17:02:16 +01:00
Robert
f8e6ccea23 Do event propogation cancelation before other work 2023-07-17 16:59:26 +01:00
Robert
8f46052459 Use optional call instead of explicit if-then 2023-07-17 16:58:52 +01:00
Robert
b210d83210 Use named Props interfaces instead of defining types inline 2023-07-17 16:58:08 +01:00
Robert
eaf8d68dd1 Remove all usages of NonClickableLocation outside of Location 2023-07-17 16:56:16 +01:00
Robert
c4ebee8e8d Have each component in a separate file 2023-07-17 16:56:15 +01:00
Robert
2962306094 Specify that tmp dir is under homedir on windows 2023-07-17 15:48:20 +01:00
Robert
a4c0365a95 Move components for rendering locations to a separate file 2023-07-17 14:36:08 +01:00
Shati Patel
2abc4d542b Merge pull request #2613 from github/version/bump-to-v1.8.9
Bump version to v1.8.9
2023-07-17 12:01:59 +01:00
github-actions[bot]
700b9bf348 Bump version to v1.8.9 2023-07-17 10:35:30 +00:00
Robert
9924f87473 Add a test that calls loadModeledMethods 2023-07-17 11:07:24 +01:00
Robert
f19b600287 Fix semantic merge conflict in imports 2023-07-17 11:07:10 +01:00
Robert
14200a5011 Merge branch 'main' into robertbrignull/data-modeled-methods-tests 2023-07-17 11:06:40 +01:00
Marcono1234
fffb692ca8 Include column numbers in location URLs 2023-07-15 22:00:21 +02:00
Robert
de7d65fc8b Replace checkbox with an icon that shows saved status 2023-07-14 16:16:30 +01:00
Robert
e73421dabb Track changed signatures instead of unsaved models 2023-07-14 16:16:27 +01:00
Robert
421fe11664 Normalize paths before doing string comparisons 2023-07-14 15:12:12 +01:00
Robert
1dcd048268 Move version check next to existing check 2023-07-14 14:20:58 +01:00
Robert
12511922ad Remove version check in resolveExtensions method 2023-07-14 14:15:07 +01:00
Robert
1782239c7c Add in CodeQL CLI version check for the "resolve extensions" command 2023-07-14 11:38:07 +01:00
Robert
752cf8ab16 Add some tests of listModelFiles 2023-07-13 10:29:52 +01:00
Robert
c512a11e7e Split out listModelFiles from loadModeledMethods 2023-07-13 09:50:54 +01:00
Robert
ba27230e3c Move loadModeledMethods to a separate file 2023-07-13 09:29:42 +01:00
Robert
52f7cac0a9 Move saveModeledMethods to a separate file 2023-07-13 09:20:00 +01:00
Robert
2db42e3eb0 Pull out createDataExtensionYamls into yaml.ts 2023-07-13 08:54:11 +01:00
173 changed files with 17801 additions and 34090 deletions

View File

@@ -15,134 +15,145 @@
* that should be changed to fix the alert.
*/
import javascript
import javascript
/**
* The name of a VS Code command.
*/
class CommandName extends string {
CommandName() { exists(CommandUsage e | e.getCommandName() = this) }
/**
* In how many ways is this command used. Will always be at least 1.
*/
int getNumberOfUsages() { result = count(this.getAUse()) }
/**
* The name of a VS Code command.
*/
class CommandName extends string {
CommandName() { exists(CommandUsage e | e.getCommandName() = this) }
/**
* Get a usage of this command.
*/
CommandUsage getAUse() { result.getCommandName() = this }
/**
* Get the canonical first usage of this command, to use for the location
* of the alert. The implementation of this ordering of usages is arbitrary
* and the usage given may not be the one that should be changed when fixing
* the alert.
*/
CommandUsage getFirstUsage() {
result =
max(CommandUsage use |
use = this.getAUse()
|
use
order by
use.getFile().getRelativePath(), use.getLocation().getStartLine(),
use.getLocation().getStartColumn()
)
}
}
/**
* Represents a single usage of a command, either from within code or
* from the command's definition in package.json
*/
abstract class CommandUsage extends Locatable {
abstract string getCommandName();
}
/**
* A usage of a command from the typescript code, by calling `executeCommand`.
*/
class CommandUsageCallExpr extends CommandUsage, CallExpr {
CommandUsageCallExpr() {
this.getCalleeName() = "executeCommand" and
this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
}
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* In how many ways is this command used. Will always be at least 1.
*/
int getNumberOfUsages() { result = count(this.getAUse()) }
/**
* A usage of a command from the typescript code, by calling `CommandManager.execute`.
*/
class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr {
CommandUsageCommandManagerMethodCallExpr() {
this.getCalleeName() = "execute" and
this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and
this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
}
/**
* Get a usage of this command.
*/
CommandUsage getAUse() { result.getCommandName() = this }
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* A usage of a command from any menu that isn't the command palette.
* This means a user could invoke the command by clicking on a button in
* something like a menu or a dropdown.
*/
class CommandUsagePackageJsonMenuItem extends CommandUsage, JsonObject {
CommandUsagePackageJsonMenuItem() {
exists(this.getPropValue("command")) and
exists(PackageJson packageJson, string menuName |
packageJson
.getPropValue("contributes")
.getPropValue("menus")
.getPropValue(menuName)
.getElementValue(_) = this and
menuName != "commandPalette"
)
}
override string getCommandName() { result = this.getPropValue("command").getStringValue() }
}
/**
* Is the given command disabled for use in the command palette by
* a block with a `"when": "false"` field.
*/
predicate isDisabledInCommandPalette(string commandName) {
exists(PackageJson packageJson, JsonObject commandPaletteObject |
packageJson
.getPropValue("contributes")
.getPropValue("menus")
.getPropValue("commandPalette")
.getElementValue(_) = commandPaletteObject and
commandPaletteObject.getPropValue("command").getStringValue() = commandName and
commandPaletteObject.getPropValue("when").getStringValue() = "false"
)
}
/**
* Represents a command being usable from the command palette.
* This means that a user could choose to manually invoke the command.
*/
class CommandUsagePackageJsonCommandPalette extends CommandUsage, JsonObject {
CommandUsagePackageJsonCommandPalette() {
this.getFile().getBaseName() = "package.json" and
exists(this.getPropValue("command")) and
exists(PackageJson packageJson |
packageJson.getPropValue("contributes").getPropValue("commands").getElementValue(_) = this
) and
not isDisabledInCommandPalette(this.getPropValue("command").getStringValue())
}
override string getCommandName() { result = this.getPropValue("command").getStringValue() }
}
from CommandName c
where c.getNumberOfUsages() > 1
select c.getFirstUsage(),
"The " + c + " command is used from " + c.getNumberOfUsages() + " locations"
/**
* Get the canonical first usage of this command, to use for the location
* of the alert. The implementation of this ordering of usages is arbitrary
* and the usage given may not be the one that should be changed when fixing
* the alert.
*/
CommandUsage getFirstUsage() {
result =
max(CommandUsage use |
use = this.getAUse()
|
use
order by
use.getFile().getRelativePath(), use.getLocation().getStartLine(),
use.getLocation().getStartColumn()
)
}
}
/**
* Matches one of the members of `BuiltInVsCodeCommands` from `extensions/ql-vscode/src/common/commands.ts`.
*/
class BuiltInVSCodeCommand extends string {
BuiltInVSCodeCommand() {
exists(TypeAliasDeclaration tad |
tad.getIdentifier().getName() = "BuiltInVsCodeCommands" and
tad.getDefinition().(InterfaceTypeExpr).getAMember().getName() = this
)
}
}
/**
* Represents a single usage of a command, either from within code or
* from the command's definition in package.json
*/
abstract class CommandUsage extends Locatable {
abstract string getCommandName();
}
/**
* A usage of a command from the typescript code, by calling `executeCommand`.
*/
class CommandUsageCallExpr extends CommandUsage, CallExpr {
CommandUsageCallExpr() {
this.getCalleeName() = "executeCommand" and
this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
}
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* A usage of a command from the typescript code, by calling `CommandManager.execute`.
*/
class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr {
CommandUsageCommandManagerMethodCallExpr() {
this.getCalleeName() = "execute" and
this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and
this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
}
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* A usage of a command from any menu that isn't the command palette.
* This means a user could invoke the command by clicking on a button in
* something like a menu or a dropdown.
*/
class CommandUsagePackageJsonMenuItem extends CommandUsage, JsonObject {
CommandUsagePackageJsonMenuItem() {
exists(this.getPropValue("command")) and
exists(PackageJson packageJson, string menuName |
packageJson
.getPropValue("contributes")
.getPropValue("menus")
.getPropValue(menuName)
.getElementValue(_) = this and
menuName != "commandPalette"
)
}
override string getCommandName() { result = this.getPropValue("command").getStringValue() }
}
/**
* Is the given command disabled for use in the command palette by
* a block with a `"when": "false"` field.
*/
predicate isDisabledInCommandPalette(string commandName) {
exists(PackageJson packageJson, JsonObject commandPaletteObject |
packageJson
.getPropValue("contributes")
.getPropValue("menus")
.getPropValue("commandPalette")
.getElementValue(_) = commandPaletteObject and
commandPaletteObject.getPropValue("command").getStringValue() = commandName and
commandPaletteObject.getPropValue("when").getStringValue() = "false"
)
}
/**
* Represents a command being usable from the command palette.
* This means that a user could choose to manually invoke the command.
*/
class CommandUsagePackageJsonCommandPalette extends CommandUsage, JsonObject {
CommandUsagePackageJsonCommandPalette() {
this.getFile().getBaseName() = "package.json" and
exists(this.getPropValue("command")) and
exists(PackageJson packageJson |
packageJson.getPropValue("contributes").getPropValue("commands").getElementValue(_) = this
) and
not isDisabledInCommandPalette(this.getPropValue("command").getStringValue())
}
override string getCommandName() { result = this.getPropValue("command").getStringValue() }
}
from CommandName c
where c.getNumberOfUsages() > 1 and not c instanceof BuiltInVSCodeCommand
select c.getFirstUsage(),
"The " + c + " command is used from " + c.getNumberOfUsages() + " locations"

View File

@@ -110,6 +110,11 @@ jobs:
run: |
npm run lint:scenarios
- name: Find deadcode
working-directory: extensions/ql-vscode
run: |
npm run find-deadcode
unit-test:
name: Unit Test
runs-on: ${{ matrix.os }}

View File

@@ -44,21 +44,21 @@ choose to go through some of the Optional Test Cases.
#### Test case 2: Running a problem query and viewing results
1. Open the [javascript UnsafeJQueryPlugin query](https://github.com/github/codeql/blob/main/javascript/ql/src/Security/CWE-079/UnsafeJQueryPlugin.ql).
1. Open the [javascript ReDoS query](https://github.com/github/codeql/blob/main/javascript/ql/src/Performance/ReDoS.ql).
2. Select the `babel/babel` database (or download it if you don't have one already)
3. Run a local query.
4. Once the query completes:
- Check that the result messages are rendered
- Check that alert locations can be clicked on
#### Test case 3: Running a non-probem query and viewing results
#### Test case 3: Running a non-problem query and viewing results
1. Open the [cpp FunLinesOfCode query](https://github.com/github/codeql/blob/main/cpp/ql/src/Metrics/Functions/FunLinesOfCode.ql).
2. Select the `google/brotli` database (or download it if you don't have one already)
3. Run a local query.
4. Once the query completes:
- Check that the results table is rendered
- Check that alert locations can be clicked on
- Check that result locations can be clicked on
#### Test case 3: Can use AST viewer
@@ -318,7 +318,6 @@ This requires running a MRVA query and seeing the results view.
1. Alphabetically
2. By number of results
3. By popularity
4. By most recent commit
9. Can filter repos
10. Shows correct statistics
1. Total number of results

View File

@@ -1,4 +1,4 @@
import type { StorybookConfig } from "@storybook/core-common";
import type { StorybookConfig } from "@storybook/react-webpack5";
const config: StorybookConfig = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
@@ -8,13 +8,13 @@ const config: StorybookConfig = {
"@storybook/addon-interactions",
"./vscode-theme-addon/preset.ts",
],
framework: "@storybook/react",
core: {
builder: "@storybook/builder-webpack5",
framework: {
name: "@storybook/react-webpack5",
options: {},
},
features: {
babelModeV7: true,
docs: {
autodocs: "tag",
},
};
module.exports = config;
export default config;

View File

@@ -1,4 +1,4 @@
import { addons } from "@storybook/addons";
import { addons } from "@storybook/manager-api";
import { themes } from "@storybook/theming";
addons.setConfig({

View File

@@ -1,31 +1,36 @@
import { Preview } from "@storybook/react";
import { themes } from "@storybook/theming";
import { action } from "@storybook/addon-actions";
// Allow all stories/components to use Codicons
import "@vscode/codicons/dist/codicon.css";
// https://storybook.js.org/docs/react/configure/overview#configure-story-rendering
export const parameters = {
// All props starting with `on` will automatically receive an action as a prop
actions: { argTypesRegex: "^on[A-Z].*" },
// All props matching these names will automatically get the correct control
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
// Use a dark theme to be aligned with VSCode
docs: {
theme: themes.dark,
},
backgrounds: {
// The background is injected by our theme CSS files
disable: true,
},
};
(window as any).acquireVsCodeApi = () => ({
postMessage: action("post-vscode-message"),
setState: action("set-vscode-state"),
});
// https://storybook.js.org/docs/react/configure/overview#configure-story-rendering
const preview: Preview = {
parameters: {
// All props starting with `on` will automatically receive an action as a prop
actions: { argTypesRegex: "^on[A-Z].*" },
// All props matching these names will automatically get the correct control
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
// Use a dark theme to be aligned with VSCode
docs: {
theme: themes.dark,
},
backgrounds: {
// The background is injected by our theme CSS files
disable: true,
},
},
};
export default preview;

View File

@@ -1,14 +1,12 @@
import * as React from "react";
import { FunctionComponent, useCallback } from "react";
import { useGlobals } from "@storybook/api";
import { useGlobals } from "@storybook/manager-api";
import {
IconButton,
Icons,
WithTooltip,
TooltipLinkList,
Link,
WithHideFn,
WithTooltip,
} from "@storybook/components";
import { themeNames, VSCodeTheme } from "./theme";
@@ -26,7 +24,7 @@ export const ThemeSelector: FunctionComponent = () => {
);
const createLinks = useCallback(
(onHide: () => void): Link[] =>
(onHide: () => void) =>
Object.values(VSCodeTheme).map((theme) => ({
id: theme,
onClick() {
@@ -44,8 +42,8 @@ export const ThemeSelector: FunctionComponent = () => {
<WithTooltip
placement="top"
trigger="click"
closeOnClick
tooltip={({ onHide }: WithHideFn) => (
closeOnOutsideClick
tooltip={({ onHide }: { onHide: () => void }) => (
<TooltipLinkList links={createLinks(onHide)} />
)}
>

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { addons, types } from "@storybook/addons";
import { addons, types } from "@storybook/manager-api";
import { ThemeSelector } from "./ThemeSelector";
const ADDON_ID = "vscode-theme-addon";

View File

@@ -1,4 +1,4 @@
export function config(entry = []) {
export function previewAnnotations(entry = []) {
return [...entry, require.resolve("./preview.ts")];
}

View File

@@ -1,6 +1,5 @@
import { useEffect, useGlobals } from "@storybook/addons";
import { useEffect } from "react";
import type {
AnyFramework,
PartialStoryFn as StoryFunction,
StoryContext,
} from "@storybook/csf";
@@ -34,11 +33,8 @@ const themeFiles: { [key in VSCodeTheme]: string } = {
.default,
};
export const withTheme = (
StoryFn: StoryFunction<AnyFramework>,
context: StoryContext<AnyFramework>,
) => {
const [{ vscodeTheme }] = useGlobals();
export const withTheme = (StoryFn: StoryFunction, context: StoryContext) => {
const { vscodeTheme } = context.globals;
useEffect(() => {
const styleSelectorId =

View File

@@ -1,5 +1,11 @@
# CodeQL for Visual Studio Code: Changelog
## 1.8.9 - 3 August 2023
- Remove "last updated" information and sorting from variant analysis results view. [#2637](https://github.com/github/vscode-codeql/pull/2637)
- Links to code on GitHub now include column numbers as well as line numbers. [#2406](https://github.com/github/vscode-codeql/pull/2406)
- No longer highlight trailing commas for jump to definition. [#2615](https://github.com/github/vscode-codeql/pull/2615)
## 1.8.8 - 17 July 2023
- Remove support for CodeQL CLI versions older than 2.9.4. [#2610](https://github.com/github/vscode-codeql/pull/2610)

View File

@@ -15,9 +15,6 @@ export const config: webpack.Configuration = {
devtool: isDevBuild ? "inline-source-map" : "source-map",
resolve: {
extensions: [".js", ".ts", ".tsx", ".json"],
fallback: {
path: require.resolve("path-browserify"),
},
},
module: {
rules: [

View File

@@ -30,5 +30,5 @@
"end": "^\\s*//\\s*#?endregion\\b"
}
},
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\.\\<\\>\\/\\?\\s]+)"
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\.\\<\\>\\/\\?\\s\\,]+)"
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "CodeQL for Visual Studio Code",
"author": "GitHub",
"private": true,
"version": "1.8.8",
"version": "1.8.9",
"publisher": "GitHub",
"license": "MIT",
"icon": "media/VS-marketplace-CodeQL-icon.png",
@@ -350,13 +350,11 @@
"enum": [
"alphabetically",
"popularity",
"mostRecentCommit",
"numberOfResults"
],
"enumDescriptions": [
"Sort repositories alphabetically in the results view.",
"Sort repositories by popularity in the results view.",
"Sort repositories by most recent commit in the results view.",
"Sort repositories by number of results in the results view."
],
"description": "The default sorting order for repositories in the variant analysis results view."
@@ -1077,17 +1075,17 @@
{
"command": "codeQLQueryHistory.showEvalLog",
"group": "4_queryHistory@1",
"when": "codeql.supportsEvalLog && viewItem == rawResultsItem || codeql.supportsEvalLog && viewItem == interpretedResultsItem || codeql.supportsEvalLog && viewItem == cancelledResultsItem"
"when": "viewItem == rawResultsItem || viewItem == interpretedResultsItem || viewItem == cancelledResultsItem"
},
{
"command": "codeQLQueryHistory.showEvalLogSummary",
"group": "4_queryHistory@2",
"when": "codeql.supportsEvalLog && viewItem == rawResultsItem || codeql.supportsEvalLog && viewItem == interpretedResultsItem || codeql.supportsEvalLog && viewItem == cancelledResultsItem"
"when": "viewItem == rawResultsItem || viewItem == interpretedResultsItem || viewItem == cancelledResultsItem"
},
{
"command": "codeQLQueryHistory.showEvalLogViewer",
"group": "4_queryHistory@3",
"when": "config.codeQL.canary && codeql.supportsEvalLog && viewItem == rawResultsItem || config.codeQL.canary && codeql.supportsEvalLog && viewItem == interpretedResultsItem || config.codeQL.canary && codeql.supportsEvalLog && viewItem == cancelledResultsItem"
"when": "config.codeQL.canary && viewItem == rawResultsItem || config.codeQL.canary && viewItem == interpretedResultsItem || config.codeQL.canary && viewItem == cancelledResultsItem"
},
{
"command": "codeQLQueryHistory.showQueryText",
@@ -1728,13 +1726,15 @@
"test:vscode-integration:no-workspace": "jest --projects test/vscode-tests/no-workspace",
"test:vscode-integration:minimal-workspace": "jest --projects test/vscode-tests/minimal-workspace",
"test:cli-integration": "jest --projects test/vscode-tests/cli-integration --verbose",
"clean-test-dir": "find . -type d -name .vscode-test -exec rm -r {} +",
"update-vscode": "node ./node_modules/vscode/bin/install",
"format": "prettier --write **/*.{ts,tsx} && eslint . --ext .ts,.tsx --fix",
"lint": "eslint . --ext .js,.ts,.tsx --max-warnings=0",
"lint:markdown": "markdownlint-cli2 \"../../**/*.{md,mdx}\" \"!**/node_modules/**\" \"!**/.vscode-test/**\" \"!**/build/cli/v*/**\"",
"find-deadcode": "ts-node scripts/find-deadcode.ts",
"format-staged": "lint-staged",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"lint:scenarios": "ts-node scripts/lint-scenarios.ts",
"check-types": "find . -type f -name \"tsconfig.json\" -not -path \"./node_modules/*\" | sed -r 's|/[^/]+$||' | sort | uniq | xargs -I {} sh -c \"echo Checking types in {} && cd {} && npx tsc --noEmit\"",
"postinstall": "patch-package",
@@ -1750,59 +1750,63 @@
"ajv": "^8.11.0",
"child-process-promise": "^2.2.1",
"chokidar": "^3.5.3",
"classnames": "~2.2.6",
"classnames": "^2.2.6",
"d3": "^7.6.1",
"d3-graphviz": "^5.0.2",
"fs-extra": "^11.1.1",
"immutable": "^4.0.0",
"js-yaml": "^4.1.0",
"minimatch": "^9.0.0",
"minimist": "~1.2.6",
"minimist": "^1.2.6",
"msw": "^1.2.0",
"nanoid": "^3.2.0",
"node-fetch": "~2.6.7",
"node-fetch": "^2.6.7",
"p-queue": "^6.0.0",
"path-browserify": "^1.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"semver": "~7.5.2",
"semver": "^7.5.2",
"source-map": "^0.7.4",
"source-map-support": "^0.5.21",
"stream": "^0.0.2",
"stream-chain": "~2.2.4",
"stream-json": "~1.7.3",
"stream-chain": "^2.2.4",
"stream-json": "^1.7.3",
"styled-components": "^5.3.3",
"tmp": "^0.1.0",
"tmp-promise": "~3.0.2",
"tree-kill": "~1.2.2",
"unzipper": "~0.10.5",
"tmp-promise": "^3.0.2",
"tree-kill": "^1.2.2",
"unzipper": "^0.10.5",
"vscode-extension-telemetry": "^0.1.6",
"vscode-jsonrpc": "^8.0.2",
"vscode-languageclient": "^8.0.2",
"vscode-test-adapter-api": "~1.7.0",
"vscode-test-adapter-util": "~0.7.0",
"zip-a-folder": "~2.0.0"
"vscode-test-adapter-api": "^1.7.0",
"vscode-test-adapter-util": "^0.7.0",
"zip-a-folder": "^2.0.0"
},
"devDependencies": {
"@babel/core": "^7.18.13",
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"@babel/preset-env": "^7.21.4",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.4",
"@faker-js/faker": "^8.0.2",
"@github/markdownlint-github": "^0.3.0",
"@octokit/plugin-throttling": "^5.0.1",
"@storybook/addon-actions": "^6.5.17-alpha.0",
"@storybook/addon-essentials": "^6.5.17-alpha.0",
"@storybook/addon-interactions": "^6.5.17-alpha.0",
"@storybook/addon-links": "^6.5.17-alpha.0",
"@storybook/builder-webpack5": "^6.5.17-alpha.0",
"@storybook/manager-webpack5": "^6.5.17-alpha.0",
"@storybook/react": "^6.5.17-alpha.0",
"@storybook/testing-library": "^0.0.13",
"@storybook/addon-actions": "^7.1.0",
"@storybook/addon-essentials": "^7.1.0",
"@storybook/addon-interactions": "^7.1.0",
"@storybook/addon-links": "^7.1.0",
"@storybook/components": "^7.1.0",
"@storybook/csf": "^0.1.1",
"@storybook/manager-api": "^7.1.0",
"@storybook/react": "^7.1.0",
"@storybook/react-webpack5": "^7.1.0",
"@storybook/theming": "^7.1.0",
"@testing-library/dom": "^9.3.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/child-process-promise": "^2.2.1",
"@types/classnames": "~2.2.9",
"@types/classnames": "^2.2.9",
"@types/d3": "^7.4.0",
"@types/d3-graphviz": "^2.6.6",
"@types/del": "^4.0.0",
@@ -1813,21 +1817,21 @@
"@types/gulp-sourcemaps": "0.0.32",
"@types/jest": "^29.0.2",
"@types/js-yaml": "^3.12.5",
"@types/jszip": "~3.1.6",
"@types/jszip": "^3.1.6",
"@types/nanoid": "^3.0.0",
"@types/node": "^16.11.25",
"@types/node-fetch": "~2.5.2",
"@types/node-fetch": "^2.5.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/sarif": "~2.1.2",
"@types/semver": "~7.2.0",
"@types/stream-chain": "~2.0.1",
"@types/stream-json": "~1.7.1",
"@types/sarif": "^2.1.2",
"@types/semver": "^7.2.0",
"@types/stream-chain": "^2.0.1",
"@types/stream-json": "^1.7.1",
"@types/styled-components": "^5.1.11",
"@types/tar-stream": "^2.2.2",
"@types/through2": "^2.0.36",
"@types/tmp": "^0.1.0",
"@types/unzipper": "~0.10.1",
"@types/unzipper": "^0.10.1",
"@types/vscode": "^1.67.0",
"@types/webpack": "^5.28.0",
"@types/webpack-env": "^1.18.0",
@@ -1837,8 +1841,9 @@
"@vscode/vsce": "^2.19.0",
"ansi-colors": "^4.1.1",
"applicationinsights": "^2.3.5",
"cosmiconfig": "^7.1.0",
"cross-env": "^7.0.3",
"css-loader": "~6.8.1",
"css-loader": "^6.8.1",
"del": "^6.0.0",
"esbuild": "^0.15.15",
"eslint": "^8.23.1",
@@ -1861,13 +1866,14 @@
"jest": "^29.0.3",
"jest-environment-jsdom": "^29.0.3",
"jest-runner-vscode": "^3.0.1",
"lint-staged": "~13.2.0",
"lint-staged": "^13.2.0",
"markdownlint-cli2": "^0.6.0",
"markdownlint-cli2-formatter-pretty": "^0.0.4",
"mini-css-extract-plugin": "^2.6.1",
"npm-run-all": "^4.1.5",
"patch-package": "^7.0.0",
"prettier": "^3.0.0",
"storybook": "^7.1.0",
"tar-stream": "^3.0.0",
"through2": "^4.0.2",
"ts-jest": "^29.0.1",
@@ -1875,6 +1881,7 @@
"ts-loader": "^9.4.2",
"ts-node": "^10.7.0",
"ts-protoc-gen": "^0.9.0",
"ts-unused-exports": "^9.0.5",
"typescript": "^5.0.2",
"webpack": "^5.76.0",
"webpack-cli": "^5.0.1"

View File

@@ -0,0 +1,47 @@
import { basename, join, relative, resolve } from "path";
import analyzeTsConfig from "ts-unused-exports";
import { containsPath, pathsEqual } from "../src/common/files";
import { exit } from "process";
function ignoreFile(file: string): boolean {
return (
containsPath("gulpfile.ts", file) ||
containsPath(join("src", "stories"), file) ||
pathsEqual(
join("test", "vscode-tests", "jest-runner-installed-extensions.ts"),
file,
) ||
basename(file) === "jest.config.ts" ||
basename(file) === "index.tsx" ||
basename(file) === "index.ts"
);
}
function main() {
const repositoryRoot = resolve(join(__dirname, ".."));
const result = analyzeTsConfig("tsconfig.deadcode.json");
let foundUnusedExports = false;
for (const [filepath, exportNameAndLocations] of Object.entries(result)) {
const relativeFilepath = relative(repositoryRoot, filepath);
if (ignoreFile(relativeFilepath)) {
continue;
}
foundUnusedExports = true;
console.log(relativeFilepath);
for (const exportNameAndLocation of exportNameAndLocations) {
console.log(` ${exportNameAndLocation.exportName}`);
}
console.log();
}
if (foundUnusedExports) {
exit(1);
}
}
main();

View File

@@ -1428,21 +1428,13 @@ export class CodeQLCliServer implements Disposable {
async packPacklist(dir: string, includeQueries: boolean): Promise<string[]> {
const args = includeQueries ? [dir] : ["--no-include-queries", dir];
// since 2.7.1, packlist returns an object with a "paths" property that is a list of packs.
// previous versions return a list of packs.
const results: { paths: string[] } | string[] =
await this.runJsonCodeQlCliCommand(
["pack", "packlist"],
args,
"Generating the pack list",
);
const results: { paths: string[] } = await this.runJsonCodeQlCliCommand(
["pack", "packlist"],
args,
"Generating the pack list",
);
// Once we no longer need to support 2.7.0 or earlier, we can remove this and assume all versions return an object.
if ("paths" in results) {
return results.paths;
} else {
return results;
}
return results.paths;
}
async packResolveDependencies(
@@ -1476,13 +1468,6 @@ export class CodeQLCliServer implements Disposable {
);
// this._version is only undefined upon config change, so we reset CLI-based context key only when necessary.
await this.app.commands.execute(
"setContext",
"codeql.supportsEvalLog",
newVersion.compare(
CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG,
) >= 0,
);
await this.app.commands.execute(
"setContext",
"codeql.supportsQuickEvalCount",
@@ -1807,21 +1792,9 @@ export class CliVersionConstraint {
);
/**
* CLI version where the `--evaluator-log` and related options to the query server were introduced,
* on a per-query server basis.
* CLI version where the `resolve extensions` subcommand exists.
*/
public static CLI_VERSION_WITH_STRUCTURED_EVAL_LOG = new SemVer("2.8.2");
/**
* CLI version that supports rotating structured logs to produce one per query.
*
* Note that 2.8.4 supports generating the evaluation logs and summaries,
* but 2.9.0 includes a new option to produce the end-of-query summary logs to
* the query server console. For simplicity we gate all features behind 2.9.0,
* but if a user is tied to the 2.8 release, we can enable evaluator logs
* and summaries for them.
*/
public static CLI_VERSION_WITH_PER_QUERY_EVAL_LOG = new SemVer("2.9.0");
public static CLI_VERSION_WITH_RESOLVE_EXTENSIONS = new SemVer("2.10.2");
/**
* CLI version that supports the `--sourcemap` option for log generation.
@@ -1882,15 +1855,9 @@ export class CliVersionConstraint {
);
}
async supportsStructuredEvalLog() {
async supportsResolveExtensions() {
return this.isVersionAtLeast(
CliVersionConstraint.CLI_VERSION_WITH_STRUCTURED_EVAL_LOG,
);
}
async supportsPerQueryEvalLog() {
return this.isVersionAtLeast(
CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG,
CliVersionConstraint.CLI_VERSION_WITH_RESOLVE_EXTENSIONS,
);
}

View File

@@ -718,7 +718,7 @@ export enum DistributionKind {
PathEnvironmentVariable,
}
export interface Distribution {
interface Distribution {
codeQlPath: string;
kind: DistributionKind;
}
@@ -776,22 +776,22 @@ type DistributionUpdateCheckResult =
| InvalidLocationResult
| UpdateAvailableResult;
export interface AlreadyCheckedRecentlyResult {
interface AlreadyCheckedRecentlyResult {
kind: DistributionUpdateCheckResultKind.AlreadyCheckedRecentlyResult;
}
export interface AlreadyUpToDateResult {
interface AlreadyUpToDateResult {
kind: DistributionUpdateCheckResultKind.AlreadyUpToDate;
}
/**
* The distribution could not be installed or updated because it is not managed by the extension.
*/
export interface InvalidLocationResult {
interface InvalidLocationResult {
kind: DistributionUpdateCheckResultKind.InvalidLocation;
}
export interface UpdateAvailableResult {
interface UpdateAvailableResult {
kind: DistributionUpdateCheckResultKind.UpdateAvailable;
updatedRelease: Release;
}
@@ -862,7 +862,7 @@ function warnDeprecatedLauncher() {
/**
* A release on GitHub.
*/
export interface Release {
interface Release {
assets: ReleaseAsset[];
/**
@@ -884,7 +884,7 @@ export interface Release {
/**
* An asset corresponding to a release on GitHub.
*/
export interface ReleaseAsset {
interface ReleaseAsset {
/**
* The id associated with the asset on GitHub.
*/

View File

@@ -1,5 +1,3 @@
export const PAGE_SIZE = 1000;
/**
* The single-character codes used in the bqrs format for the the kind
* of a result column. This namespace is intentionally not an enum, see
@@ -15,7 +13,7 @@ export namespace ColumnKindCode {
export const ENTITY = "e";
}
export type ColumnKind =
type ColumnKind =
| typeof ColumnKindCode.FLOAT
| typeof ColumnKindCode.INTEGER
| typeof ColumnKindCode.STRING
@@ -46,7 +44,7 @@ export function getResultSetSchema(
}
return undefined;
}
export interface PaginationInfo {
interface PaginationInfo {
"step-size": number;
offsets: number[];
}

View File

@@ -142,5 +142,7 @@ export function tryGetRemoteLocation(
fileLink,
resolvableLocation.startLine,
resolvableLocation.endLine,
resolvableLocation.startColumn,
resolvableLocation.endColumn,
);
}

View File

@@ -4,7 +4,6 @@ import type { AstItem } from "../language-support";
import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item";
import type { DatabaseItem } from "../databases/local-databases";
import type { QueryHistoryInfo } from "../query-history/query-history-info";
import type { RepositoriesFilterSortStateWithIds } from "../variant-analysis/shared/variant-analysis-filter-sort";
import type { TestTreeNode } from "../query-testing/test-tree-node";
import type {
VariantAnalysis,
@@ -56,7 +55,7 @@ export type ExplorerSelectionCommandFunction<Item> = (
// Builtin commands where the implementation is provided by VS Code and not by this extension.
// See https://code.visualstudio.com/api/references/commands
export type BuiltInVsCodeCommands = {
type BuiltInVsCodeCommands = {
// The codeQLDatabases.focus command is provided by VS Code because we've registered the custom view
"codeQLDatabases.focus": () => Promise<void>;
"markdown.showPreviewToSide": (uri: Uri) => Promise<void>;
@@ -244,10 +243,6 @@ export type VariantAnalysisCommands = {
scannedRepo: VariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysis,
) => Promise<void>;
"codeQL.copyVariantAnalysisRepoList": (
variantAnalysisId: number,
filterSort?: RepositoriesFilterSortStateWithIds,
) => Promise<void>;
"codeQL.loadVariantAnalysisRepoResults": (
variantAnalysisId: number,
repositoryFullName: string,

View File

@@ -76,11 +76,9 @@ export type GraphInterpretationData = {
dot: string[];
};
export type InterpretationData =
| SarifInterpretationData
| GraphInterpretationData;
type InterpretationData = SarifInterpretationData | GraphInterpretationData;
export interface InterpretationT<T> {
interface InterpretationT<T> {
sourceLocationPrefix: string;
numTruncatedResults: number;
numTotalResults: number;
@@ -106,7 +104,7 @@ export type SortedResultsMap = { [resultSet: string]: SortedResultSetInfo };
*
* As a result of receiving this message, listeners might want to display a loading indicator.
*/
export interface ResultsUpdatingMsg {
interface ResultsUpdatingMsg {
t: "resultsUpdating";
}
@@ -114,7 +112,7 @@ export interface ResultsUpdatingMsg {
* Message to set the initial state of the results view with a new
* query.
*/
export interface SetStateMsg {
interface SetStateMsg {
t: "setState";
resultsPath: string;
origResultsPaths: ResultsPaths;
@@ -143,7 +141,7 @@ export interface SetStateMsg {
* Message indicating that the results view should display interpreted
* results.
*/
export interface ShowInterpretedPageMsg {
interface ShowInterpretedPageMsg {
t: "showInterpretedPage";
interpretation: Interpretation;
database: DatabaseInfo;
@@ -173,7 +171,7 @@ export interface NavigateMsg {
* A message indicating that the results view should untoggle the
* "Show results in Problems view" checkbox.
*/
export interface UntoggleShowProblemsMsg {
interface UntoggleShowProblemsMsg {
t: "untoggleShowProblems";
}
@@ -203,7 +201,7 @@ export type FromResultsViewMsg =
* Message from the results view to open a database source
* file at the provided location.
*/
export interface ViewSourceFileMsg {
interface ViewSourceFileMsg {
t: "viewSourceFile";
loc: ResolvableLocationValue;
databaseUri: string;
@@ -212,7 +210,7 @@ export interface ViewSourceFileMsg {
/**
* Message from the results view to open a file in an editor.
*/
export interface OpenFileMsg {
interface OpenFileMsg {
t: "openFile";
/* Full path to the file to open. */
filePath: string;
@@ -274,7 +272,7 @@ export interface RawResultsSortState {
sortDirection: SortDirection;
}
export type InterpretedResultsSortColumn = "alert-message";
type InterpretedResultsSortColumn = "alert-message";
export interface InterpretedResultsSortState {
sortBy: InterpretedResultsSortColumn;
@@ -318,7 +316,7 @@ export type FromCompareViewMessage =
/**
* Message from the compare view to request opening a query.
*/
export interface OpenQueryMessage {
interface OpenQueryMessage {
readonly t: "openQuery";
readonly kind: "from" | "to";
}
@@ -406,12 +404,12 @@ export interface ParsedResultSets {
resultSet: ResultSet;
}
export interface SetVariantAnalysisMessage {
interface SetVariantAnalysisMessage {
t: "setVariantAnalysis";
variantAnalysis: VariantAnalysis;
}
export interface SetFilterSortStateMessage {
interface SetFilterSortStateMessage {
t: "setFilterSortState";
filterSortState: RepositoriesFilterSortState;
}
@@ -420,48 +418,48 @@ export type VariantAnalysisState = {
variantAnalysisId: number;
};
export interface SetRepoResultsMessage {
interface SetRepoResultsMessage {
t: "setRepoResults";
repoResults: VariantAnalysisScannedRepositoryResult[];
}
export interface SetRepoStatesMessage {
interface SetRepoStatesMessage {
t: "setRepoStates";
repoStates: VariantAnalysisScannedRepositoryState[];
}
export interface RequestRepositoryResultsMessage {
interface RequestRepositoryResultsMessage {
t: "requestRepositoryResults";
repositoryFullName: string;
}
export interface OpenQueryFileMessage {
interface OpenQueryFileMessage {
t: "openQueryFile";
}
export interface OpenQueryTextMessage {
interface OpenQueryTextMessage {
t: "openQueryText";
}
export interface CopyRepositoryListMessage {
interface CopyRepositoryListMessage {
t: "copyRepositoryList";
filterSort?: RepositoriesFilterSortStateWithIds;
}
export interface ExportResultsMessage {
interface ExportResultsMessage {
t: "exportResults";
filterSort?: RepositoriesFilterSortStateWithIds;
}
export interface OpenLogsMessage {
interface OpenLogsMessage {
t: "openLogs";
}
export interface CancelVariantAnalysisMessage {
interface CancelVariantAnalysisMessage {
t: "cancelVariantAnalysis";
}
export interface ShowDataFlowPathsMessage {
interface ShowDataFlowPathsMessage {
t: "showDataFlowPaths";
dataFlowPaths: DataFlowPaths;
}
@@ -483,7 +481,7 @@ export type FromVariantAnalysisMessage =
| CancelVariantAnalysisMessage
| ShowDataFlowPathsMessage;
export interface SetDataFlowPathsMessage {
interface SetDataFlowPathsMessage {
t: "setDataFlowPaths";
dataFlowPaths: DataFlowPaths;
}
@@ -492,71 +490,71 @@ export type ToDataFlowPathsMessage = SetDataFlowPathsMessage;
export type FromDataFlowPathsMessage = CommonFromViewMessages;
export interface SetExtensionPackStateMessage {
interface SetExtensionPackStateMessage {
t: "setDataExtensionEditorViewState";
viewState: DataExtensionEditorViewState;
}
export interface SetExternalApiUsagesMessage {
interface SetExternalApiUsagesMessage {
t: "setExternalApiUsages";
externalApiUsages: ExternalApiUsage[];
}
export interface ShowProgressMessage {
t: "showProgress";
step: number;
maxStep: number;
message: string;
}
export interface LoadModeledMethodsMessage {
interface LoadModeledMethodsMessage {
t: "loadModeledMethods";
modeledMethods: Record<string, ModeledMethod>;
}
export interface AddModeledMethodsMessage {
interface AddModeledMethodsMessage {
t: "addModeledMethods";
modeledMethods: Record<string, ModeledMethod>;
}
export interface SwitchModeMessage {
interface SwitchModeMessage {
t: "switchMode";
mode: Mode;
}
export interface JumpToUsageMessage {
interface JumpToUsageMessage {
t: "jumpToUsage";
location: ResolvableLocationValue;
}
export interface OpenExtensionPackMessage {
interface OpenDatabaseMessage {
t: "openDatabase";
}
interface OpenExtensionPackMessage {
t: "openExtensionPack";
}
export interface RefreshExternalApiUsages {
interface RefreshExternalApiUsages {
t: "refreshExternalApiUsages";
}
export interface SaveModeledMethods {
interface SaveModeledMethods {
t: "saveModeledMethods";
externalApiUsages: ExternalApiUsage[];
modeledMethods: Record<string, ModeledMethod>;
}
export interface GenerateExternalApiMessage {
interface GenerateExternalApiMessage {
t: "generateExternalApi";
}
export interface GenerateExternalApiFromLlmMessage {
interface GenerateExternalApiFromLlmMessage {
t: "generateExternalApiFromLlm";
externalApiUsages: ExternalApiUsage[];
modeledMethods: Record<string, ModeledMethod>;
}
interface ModelDependencyMessage {
t: "modelDependency";
}
export type ToDataExtensionsEditorMessage =
| SetExtensionPackStateMessage
| SetExternalApiUsagesMessage
| ShowProgressMessage
| LoadModeledMethodsMessage
| AddModeledMethodsMessage;
@@ -564,8 +562,10 @@ export type FromDataExtensionsEditorMessage =
| ViewLoadedMsg
| SwitchModeMessage
| RefreshExternalApiUsages
| OpenDatabaseMessage
| OpenExtensionPackMessage
| JumpToUsageMessage
| SaveModeledMethods
| GenerateExternalApiMessage
| GenerateExternalApiFromLlmMessage;
| GenerateExternalApiFromLlmMessage
| ModelDependencyMessage;

View File

@@ -4,8 +4,20 @@ export function createRemoteFileRef(
fileLink: FileLink,
startLine?: number,
endLine?: number,
startColumn?: number,
endColumn?: number,
): string {
if (startLine && endLine && startLine !== endLine) {
if (
startColumn &&
endColumn &&
startLine &&
endLine &&
// Verify that location information is valid; otherwise highlighting might be broken
((startLine === endLine && startColumn < endColumn) || startLine < endLine)
) {
// This relies on column highlighting of new code view on GitHub
return `${fileLink.fileLinkPrefix}/${fileLink.filePath}#L${startLine}C${startColumn}-L${endLine}C${endColumn}`;
} else if (startLine && endLine && startLine < endLine) {
return `${fileLink.fileLinkPrefix}/${fileLink.filePath}#L${startLine}-L${endLine}`;
} else if (startLine) {
return `${fileLink.fileLinkPrefix}/${fileLink.filePath}#L${startLine}`;

View File

@@ -2,7 +2,7 @@ import { NotificationLogger } from "./notification-logger";
import { AppTelemetry } from "../telemetry";
import { RedactableError } from "../errors";
export interface ShowAndLogOptions {
interface ShowAndLogOptions {
/**
* An alternate message that is added to the log, but not displayed in the popup.
* This is useful for adding extra detail to the logs that would be too noisy for the popup.

View File

@@ -9,6 +9,29 @@ export enum QueryLanguage {
Swift = "swift",
}
export function getLanguageDisplayName(language: string): string {
switch (language) {
case QueryLanguage.CSharp:
return "C#";
case QueryLanguage.Cpp:
return "C / C++";
case QueryLanguage.Go:
return "Go";
case QueryLanguage.Java:
return "Java";
case QueryLanguage.Javascript:
return "JavaScript";
case QueryLanguage.Python:
return "Python";
case QueryLanguage.Ruby:
return "Ruby";
case QueryLanguage.Swift:
return "Swift";
default:
return language;
}
}
export const PACKS_BY_QUERY_LANGUAGE = {
[QueryLanguage.Cpp]: ["codeql/cpp-queries"],
[QueryLanguage.CSharp]: [

View File

@@ -2,7 +2,7 @@ import * as Sarif from "sarif";
import type { HighlightedRegion } from "../variant-analysis/shared/analysis-result";
import { ResolvableLocationValue } from "../common/bqrs-cli-types";
export interface SarifLink {
interface SarifLink {
dest: number;
text: string;
}
@@ -24,7 +24,7 @@ type ParsedSarifLocation =
// that, and is appropriate for display in the UI.
| NoLocation;
export type SarifMessageComponent = string | SarifLink;
type SarifMessageComponent = string | SarifLink;
/**
* Unescape "[", "]" and "\\" like in sarif plain text messages
@@ -203,7 +203,7 @@ export function shouldHighlightLine(
* A line of code split into: plain text before the highlighted section, the highlighted
* text itself, and plain text after the highlighted section.
*/
export interface PartiallyHighlightedLine {
interface PartiallyHighlightedLine {
plainSection1: string;
highlightedSection: string;
plainSection2: string;

View File

@@ -2,16 +2,16 @@
* Contains an assortment of helper constants and functions for working with time, dates, and durations.
*/
export const ONE_SECOND_IN_MS = 1000;
export const ONE_MINUTE_IN_MS = ONE_SECOND_IN_MS * 60;
const ONE_SECOND_IN_MS = 1000;
const ONE_MINUTE_IN_MS = ONE_SECOND_IN_MS * 60;
export const ONE_HOUR_IN_MS = ONE_MINUTE_IN_MS * 60;
export const TWO_HOURS_IN_MS = ONE_HOUR_IN_MS * 2;
export const THREE_HOURS_IN_MS = ONE_HOUR_IN_MS * 3;
export const ONE_DAY_IN_MS = ONE_HOUR_IN_MS * 24;
// These are approximations
export const ONE_MONTH_IN_MS = ONE_DAY_IN_MS * 30;
export const ONE_YEAR_IN_MS = ONE_DAY_IN_MS * 365;
const ONE_MONTH_IN_MS = ONE_DAY_IN_MS * 30;
const ONE_YEAR_IN_MS = ONE_DAY_IN_MS * 365;
const durationFormatter = new Intl.RelativeTimeFormat("en", {
numeric: "auto",

View File

@@ -8,7 +8,7 @@ import { extLogger } from "../logging/vscode";
import { posix } from "path";
const path = posix;
export class File implements vscode.FileStat {
class File implements vscode.FileStat {
type: vscode.FileType;
ctime: number;
mtime: number;
@@ -26,7 +26,7 @@ export class File implements vscode.FileStat {
}
}
export class Directory implements vscode.FileStat {
class Directory implements vscode.FileStat {
type: vscode.FileType;
ctime: number;
mtime: number;
@@ -41,7 +41,7 @@ export class Directory implements vscode.FileStat {
}
}
export type Entry = File | Directory;
type Entry = File | Directory;
/**
* A map containing directory hierarchy information in a convenient form.
@@ -52,7 +52,7 @@ export type Entry = File | Directory;
* dirMap['/foo'] = {'bar': vscode.FileType.Directory}
* dirMap['/foo/bar'] = {'baz': vscode.FileType.File}
*/
export type DirectoryHierarchyMap = Map<string, Map<string, vscode.FileType>>;
type DirectoryHierarchyMap = Map<string, Map<string, vscode.FileType>>;
export type ZipFileReference = {
sourceArchiveZipPath: string;

View File

@@ -38,7 +38,7 @@ export type ProgressCallback = (p: ProgressUpdate) => void;
// Make certain properties within a type optional
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
export type ProgressOptions = Optional<VSCodeProgressOptions, "location">;
type ProgressOptions = Optional<VSCodeProgressOptions, "location">;
/**
* A task that reports progress.

View File

@@ -25,7 +25,7 @@ import { AppTelemetry } from "../telemetry";
// Key is injected at build time through the APP_INSIGHTS_KEY environment variable.
const key = "REPLACE-APP-INSIGHTS-KEY";
export enum CommandCompletion {
enum CommandCompletion {
Success = "Success",
Failed = "Failed",
Cancelled = "Cancelled",

View File

@@ -0,0 +1,12 @@
import { promisify } from "util";
import { gzip, gunzip } from "zlib";
/**
* Promisified version of zlib.gzip
*/
export const gzipEncode = promisify(gzip);
/**
* Promisified version of zlib.gunzip
*/
export const gzipDecode = promisify(gunzip);

View File

@@ -64,12 +64,6 @@ export class Setting {
}
}
export interface InspectionResult<T> {
globalValue?: T;
workspaceValue?: T;
workspaceFolderValue?: T;
}
const VSCODE_DEBUG_SETTING = new Setting("debug", undefined);
export const VSCODE_SAVE_BEFORE_START_SETTING = new Setting(
"saveBeforeStart",
@@ -592,10 +586,6 @@ export function isIntegrationTestMode() {
return process.env.INTEGRATION_TEST_MODE === "true";
}
export function isVariantAnalysisLiveResultsEnabled(): boolean {
return true;
}
// Settings for mocking the GitHub API.
const MOCK_GH_API_SERVER = new Setting("mockGitHubApiServer", ROOT_SETTING);
@@ -659,10 +649,7 @@ export function isCodespacesTemplate() {
const DATABASE_DOWNLOAD_SETTING = new Setting("databaseDownload", ROOT_SETTING);
export const ALLOW_HTTP_SETTING = new Setting(
"allowHttp",
DATABASE_DOWNLOAD_SETTING,
);
const ALLOW_HTTP_SETTING = new Setting("allowHttp", DATABASE_DOWNLOAD_SETTING);
export function allowHttp(): boolean {
return ALLOW_HTTP_SETTING.getValue<boolean>() || false;
@@ -717,6 +704,7 @@ export function showQueriesPanel(): boolean {
const DATA_EXTENSIONS = new Setting("dataExtensions", ROOT_SETTING);
const LLM_GENERATION = new Setting("llmGeneration", DATA_EXTENSIONS);
const LLM_GENERATION_V2 = new Setting("llmGenerationV2", DATA_EXTENSIONS);
const FRAMEWORK_MODE = new Setting("frameworkMode", DATA_EXTENSIONS);
const DISABLE_AUTO_NAME_EXTENSION_PACK = new Setting(
"disableAutoNameExtensionPack",
@@ -731,6 +719,10 @@ export function showLlmGeneration(): boolean {
return !!LLM_GENERATION.getValue<boolean>();
}
export function useLlmGenerationV2(): boolean {
return !!LLM_GENERATION_V2.getValue<boolean>();
}
export function enableFrameworkMode(): boolean {
return !!FRAMEWORK_MODE.getValue<boolean>();
}

View File

@@ -0,0 +1,34 @@
import { Credentials } from "../common/authentication";
import { OctokitResponse } from "@octokit/types";
export enum AutomodelMode {
Unspecified = "AUTOMODEL_MODE_UNSPECIFIED",
Framework = "AUTOMODEL_MODE_FRAMEWORK",
Application = "AUTOMODEL_MODE_APPLICATION",
}
export interface ModelRequest {
mode: AutomodelMode;
// Base64-encoded GZIP-compressed SARIF log
candidates: string;
}
export interface ModelResponse {
models: string;
}
export async function autoModelV2(
credentials: Credentials,
request: ModelRequest,
): Promise<ModelResponse> {
const octokit = await credentials.getOctokit();
const response: OctokitResponse<ModelResponse> = await octokit.request(
"POST /repos/github/codeql/code-scanning/codeql/auto-model",
{
data: request,
},
);
return response.data;
}

View File

@@ -0,0 +1,230 @@
import { CodeQLCliServer, SourceInfo } from "../codeql-cli/cli";
import { QueryRunner } from "../query-server";
import { DatabaseItem } from "../databases/local-databases";
import { ProgressCallback } from "../common/vscode/progress";
import * as Sarif from "sarif";
import { qlpackOfDatabase, resolveQueries } from "../local-queries";
import { extLogger } from "../common/logging/vscode";
import { Mode } from "./shared/mode";
import { QlPacksForLanguage } from "../databases/qlpack";
import { createLockFileForStandardQuery } from "../local-queries/standard-queries";
import { CancellationToken, CancellationTokenSource } from "vscode";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { showAndLogExceptionWithTelemetry, TeeLogger } from "../common/logging";
import { QueryResultType } from "../query-server/new-messages";
import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../common/errors";
import { interpretResultsSarif } from "../query-results";
import { join } from "path";
import { assertNever } from "../common/helpers-pure";
type AutoModelQueryOptions = {
queryTag: string;
mode: Mode;
cliServer: CodeQLCliServer;
queryRunner: QueryRunner;
databaseItem: DatabaseItem;
qlpack: QlPacksForLanguage;
sourceInfo: SourceInfo | undefined;
extensionPacks: string[];
queryStorageDir: string;
progress: ProgressCallback;
token: CancellationToken;
};
function modeTag(mode: Mode): string {
switch (mode) {
case Mode.Application:
return "application-mode";
case Mode.Framework:
return "framework-mode";
default:
assertNever(mode);
}
}
async function runAutoModelQuery({
queryTag,
mode,
cliServer,
queryRunner,
databaseItem,
qlpack,
sourceInfo,
extensionPacks,
queryStorageDir,
progress,
token,
}: AutoModelQueryOptions): Promise<Sarif.Log | undefined> {
// First, resolve the query that we want to run.
// All queries are tagged like this:
// internal extract automodel <mode> <queryTag>
// Example: internal extract automodel framework-mode candidates
const queries = await resolveQueries(
cliServer,
qlpack,
`Extract automodel ${queryTag}`,
{
kind: "problem",
"tags contain all": ["automodel", modeTag(mode), ...queryTag.split(" ")],
},
);
if (queries.length > 1) {
throw new Error(
`Found multiple auto model queries for ${mode} ${queryTag}. Can't continue`,
);
}
if (queries.length === 0) {
throw new Error(
`Did not found any auto model queries for ${mode} ${queryTag}. Can't continue`,
);
}
const queryPath = queries[0];
const { cleanup: cleanupLockFile } = await createLockFileForStandardQuery(
cliServer,
queryPath,
);
// Get metadata for the query. This is required to interpret the results. We already know the kind is problem
// (because of the constraint in resolveQueries), so we don't need any more checks on the metadata.
const metadata = await cliServer.resolveMetadata(queryPath);
const queryRun = queryRunner.createQueryRun(
databaseItem.databaseUri.fsPath,
{
queryPath,
quickEvalPosition: undefined,
quickEvalCountOnly: false,
},
false,
getOnDiskWorkspaceFolders(),
extensionPacks,
queryStorageDir,
undefined,
undefined,
);
const completedQuery = await queryRun.evaluate(
progress,
token,
new TeeLogger(queryRunner.logger, queryRun.outputDir.logPath),
);
await cleanupLockFile?.();
if (completedQuery.resultType !== QueryResultType.SUCCESS) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`Auto-model query ${queryTag} failed: ${
completedQuery.message ?? "No message"
}`,
);
return;
}
const interpretedResultsPath = join(
queryStorageDir,
`interpreted-results-${queryTag.replaceAll(" ", "-")}-${queryRun.id}.sarif`,
);
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- We only need the actual SARIF data, not the extra fields added by SarifInterpretationData
const { t, sortState, ...sarif } = await interpretResultsSarif(
cliServer,
metadata,
{
resultsPath: completedQuery.outputDir.bqrsPath,
interpretedResultsPath,
},
sourceInfo,
["--sarif-add-snippets"],
);
return sarif;
}
type AutoModelQueriesOptions = {
mode: Mode;
cliServer: CodeQLCliServer;
queryRunner: QueryRunner;
databaseItem: DatabaseItem;
queryStorageDir: string;
progress: ProgressCallback;
};
export type AutoModelQueriesResult = {
candidates: Sarif.Log;
};
export async function runAutoModelQueries({
mode,
cliServer,
queryRunner,
databaseItem,
queryStorageDir,
progress,
}: AutoModelQueriesOptions): Promise<AutoModelQueriesResult | undefined> {
// maxStep for this part is 1500
const maxStep = 1500;
const cancellationTokenSource = new CancellationTokenSource();
const qlpack = await qlpackOfDatabase(cliServer, databaseItem);
// CodeQL needs to have access to the database to be able to retrieve the
// snippets from it. The source location prefix is used to determine the
// base path of the database.
const sourceLocationPrefix = await databaseItem.getSourceLocationPrefix(
cliServer,
);
const sourceArchiveUri = databaseItem.sourceArchive;
const sourceInfo =
sourceArchiveUri === undefined
? undefined
: {
sourceArchive: sourceArchiveUri.fsPath,
sourceLocationPrefix,
};
const additionalPacks = getOnDiskWorkspaceFolders();
const extensionPacks = Object.keys(
await cliServer.resolveQlpacks(additionalPacks, true),
);
progress({
step: 0,
maxStep,
message: "Finding candidates and examples",
});
const candidates = await runAutoModelQuery({
mode,
queryTag: "candidates",
cliServer,
queryRunner,
databaseItem,
qlpack,
sourceInfo,
extensionPacks,
queryStorageDir,
progress: (update) => {
progress({
step: update.step,
maxStep,
message: "Finding candidates and examples",
});
},
token: cancellationTokenSource.token,
});
if (!candidates) {
return undefined;
}
return {
candidates,
};
}

View File

@@ -6,12 +6,14 @@ import { QueryRunner } from "../query-server";
import { DatabaseItem } from "../databases/local-databases";
import { interpretResultsSarif } from "../query-results";
import { ProgressCallback } from "../common/vscode/progress";
import { Mode } from "./shared/mode";
type Options = {
cliServer: CodeQLCliServer;
queryRunner: QueryRunner;
databaseItem: DatabaseItem;
queryStorageDir: string;
queryDir: string;
progress: ProgressCallback;
};
@@ -23,6 +25,7 @@ export async function getAutoModelUsages({
queryRunner,
databaseItem,
queryStorageDir,
queryDir,
progress,
}: Options): Promise<UsageSnippetsBySignature> {
const maxStep = 1500;
@@ -32,11 +35,12 @@ export async function getAutoModelUsages({
// This will re-run the query that was already run when opening the data extensions editor. This
// might be unnecessary, but this makes it really easy to get the path to the BQRS file which we
// need to interpret the results.
const queryResult = await runQuery("applicationModeQuery", {
const queryResult = await runQuery(Mode.Application, {
cliServer,
queryRunner,
queryStorageDir,
databaseItem,
queryDir,
progress: (update) =>
progress({
maxStep,

View File

@@ -0,0 +1,40 @@
import { AutomodelMode, ModelRequest } from "./auto-model-api-v2";
import { Mode } from "./shared/mode";
import { AutoModelQueriesResult } from "./auto-model-codeml-queries";
import { assertNever } from "../common/helpers-pure";
import * as Sarif from "sarif";
import { gzipEncode } from "../common/zlib";
/**
* Encode a SARIF log to the format expected by the server: JSON, GZIP-compressed, base64-encoded
* @param log SARIF log to encode
* @returns base64-encoded GZIP-compressed SARIF log
*/
export async function encodeSarif(log: Sarif.Log): Promise<string> {
const json = JSON.stringify(log);
const buffer = Buffer.from(json, "utf-8");
const compressed = await gzipEncode(buffer);
return compressed.toString("base64");
}
export async function createAutoModelV2Request(
mode: Mode,
result: AutoModelQueriesResult,
): Promise<ModelRequest> {
let requestMode: AutomodelMode;
switch (mode) {
case Mode.Application:
requestMode = AutomodelMode.Application;
break;
case Mode.Framework:
requestMode = AutomodelMode.Framework;
break;
default:
assertNever(mode);
}
return {
mode: requestMode,
candidates: await encodeSarif(result.candidates),
};
}

View File

@@ -9,7 +9,17 @@ import { join } from "path";
import { App } from "../common/app";
import { withProgress } from "../common/vscode/progress";
import { pickExtensionPack } from "./extension-pack-picker";
import { showAndLogErrorMessage } from "../common/logging";
import {
showAndLogErrorMessage,
showAndLogExceptionWithTelemetry,
} from "../common/logging";
import { dir } from "tmp-promise";
import { fetchExternalApiQueries } from "./queries";
import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../common/errors";
import { extLogger } from "../common/logging/vscode";
import { isQueryLanguage } from "../common/query-language";
import { setUpPack } from "./external-api-usage-query";
const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
@@ -60,10 +70,14 @@ export class DataExtensionsEditorModule {
return;
}
if (!SUPPORTED_LANGUAGES.includes(db.language)) {
const language = db.language;
if (
!SUPPORTED_LANGUAGES.includes(language) ||
!isQueryLanguage(language)
) {
void showAndLogErrorMessage(
this.app.logger,
`The data extensions editor is not supported for ${db.language} databases.`,
`The data extensions editor is not supported for ${language} databases.`,
);
return;
}
@@ -78,6 +92,16 @@ export class DataExtensionsEditorModule {
return;
}
if (
!(await this.cliServer.cliConstraints.supportsResolveExtensions())
) {
void showAndLogErrorMessage(
this.app.logger,
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_RESOLVE_EXTENSIONS.format()} or later.`,
);
return;
}
const modelFile = await pickExtensionPack(
this.cliServer,
db,
@@ -89,6 +113,21 @@ export class DataExtensionsEditorModule {
return;
}
const query = fetchExternalApiQueries[language];
if (!query) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`No external API usage query found for language ${language}`,
);
return;
}
// Create new temporary directory for query files and pack dependencies
const queryDir = (await dir({ unsafeCleanup: true })).path;
await setUpPack(queryDir, query, language);
await this.cliServer.packInstall(queryDir);
const view = new DataExtensionsEditorView(
this.ctx,
this.app,
@@ -96,6 +135,7 @@ export class DataExtensionsEditorModule {
this.cliServer,
this.queryRunner,
this.queryStorageDir,
queryDir,
db,
modelFile,
);

View File

@@ -5,7 +5,6 @@ import {
ViewColumn,
window,
} from "vscode";
import { join } from "path";
import { RequestError } from "@octokit/request-error";
import {
AbstractWebview,
@@ -15,14 +14,12 @@ import {
FromDataExtensionsEditorMessage,
ToDataExtensionsEditorMessage,
} from "../common/interface-types";
import { ProgressUpdate } from "../common/vscode/progress";
import { ProgressCallback, withProgress } from "../common/vscode/progress";
import { QueryRunner } from "../query-server";
import {
showAndLogExceptionWithTelemetry,
showAndLogErrorMessage,
} from "../common/logging";
import { outputFile, readFile } from "fs-extra";
import { load as loadYaml } from "js-yaml";
import { DatabaseItem, DatabaseManager } from "../databases/local-databases";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { asError, assertNever, getErrorMessage } from "../common/helpers-pure";
@@ -34,23 +31,34 @@ import { showResolvableLocation } from "../databases/local-databases/locations";
import { decodeBqrsToExternalApiUsages } from "./bqrs";
import { redactableError } from "../common/errors";
import { readQueryResults, runQuery } from "./external-api-usage-query";
import {
createDataExtensionYamlsForApplicationMode,
createDataExtensionYamlsForFrameworkMode,
loadDataExtensionYaml,
} from "./yaml";
import { ExternalApiUsage } from "./external-api-usage";
import { ModeledMethod } from "./modeled-method";
import { ExtensionPack } from "./shared/extension-pack";
import { autoModel, ModelRequest, ModelResponse } from "./auto-model-api";
import {
autoModelV2,
ModelRequest as ModelRequestV2,
ModelResponse as ModelResponseV2,
} from "./auto-model-api-v2";
import {
createAutoModelRequest,
parsePredictedClassifications,
} from "./auto-model";
import { enableFrameworkMode, showLlmGeneration } from "../config";
import {
enableFrameworkMode,
showLlmGeneration,
useLlmGenerationV2,
} from "../config";
import { getAutoModelUsages } from "./auto-model-usages-query";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { Mode } from "./shared/mode";
import { loadModeledMethods, saveModeledMethods } from "./modeled-method-fs";
import { join } from "path";
import { pickExtensionPack } from "./extension-pack-picker";
import { getLanguageDisplayName } from "../common/query-language";
import { runAutoModelQueries } from "./auto-model-codeml-queries";
import { createAutoModelV2Request } from "./auto-model-v2";
import { load as loadYaml } from "js-yaml";
import { loadDataExtensionYaml } from "./yaml";
export class DataExtensionsEditorView extends AbstractWebview<
ToDataExtensionsEditorMessage,
@@ -63,6 +71,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
private readonly cliServer: CodeQLCliServer,
private readonly queryRunner: QueryRunner,
private readonly queryStorageDir: string,
private readonly queryDir: string,
private readonly databaseItem: DatabaseItem,
private readonly extensionPack: ExtensionPack,
private mode: Mode = Mode.Application,
@@ -80,7 +89,9 @@ export class DataExtensionsEditorView extends AbstractWebview<
protected async getPanelConfig(): Promise<WebviewPanelConfig> {
return {
viewId: "data-extensions-editor",
title: "Data Extensions Editor",
title: `Modeling ${getLanguageDisplayName(
this.extensionPack.language,
)} (${this.extensionPack.name})`,
viewColumn: ViewColumn.Active,
preserveFocus: true,
view: "data-extensions-editor",
@@ -106,6 +117,13 @@ export class DataExtensionsEditorView extends AbstractWebview<
case "viewLoaded":
await this.onWebViewLoaded();
break;
case "openDatabase":
await this.app.commands.execute(
"revealInExplorer",
this.databaseItem.getSourceArchiveExplorerUri(),
);
break;
case "openExtensionPack":
await this.app.commands.execute(
@@ -123,9 +141,15 @@ export class DataExtensionsEditorView extends AbstractWebview<
break;
case "saveModeledMethods":
await this.saveModeledMethods(
await saveModeledMethods(
this.extensionPack,
this.databaseItem.name,
this.databaseItem.language,
msg.externalApiUsages,
msg.modeledMethods,
this.mode,
this.cliServer,
this.app.logger,
);
await Promise.all([this.setViewState(), this.loadExternalApiUsages()]);
@@ -140,6 +164,10 @@ export class DataExtensionsEditorView extends AbstractWebview<
msg.modeledMethods,
);
break;
case "modelDependency":
await this.modelDependency();
break;
case "switchMode":
this.mode = msg.mode;
@@ -163,12 +191,15 @@ export class DataExtensionsEditorView extends AbstractWebview<
}
private async setViewState(): Promise<void> {
const showLlmButton =
this.databaseItem.language === "java" && showLlmGeneration();
await this.postMessage({
t: "setDataExtensionEditorViewState",
viewState: {
extensionPack: this.extensionPack,
enableFrameworkMode: enableFrameworkMode(),
showLlmButton: showLlmGeneration(),
showLlmButton,
mode: this.mode,
},
});
@@ -194,79 +225,16 @@ export class DataExtensionsEditorView extends AbstractWebview<
}
}
protected async saveModeledMethods(
externalApiUsages: ExternalApiUsage[],
modeledMethods: Record<string, ModeledMethod>,
): Promise<void> {
let yamls: Record<string, string>;
switch (this.mode) {
case Mode.Application:
yamls = createDataExtensionYamlsForApplicationMode(
this.databaseItem.language,
externalApiUsages,
modeledMethods,
);
break;
case Mode.Framework:
yamls = createDataExtensionYamlsForFrameworkMode(
this.databaseItem.name,
this.databaseItem.language,
externalApiUsages,
modeledMethods,
);
break;
default:
assertNever(this.mode);
}
for (const [filename, yaml] of Object.entries(yamls)) {
await outputFile(join(this.extensionPack.path, filename), yaml);
}
void this.app.logger.log(`Saved data extension YAML`);
}
protected async loadExistingModeledMethods(): Promise<void> {
try {
const extensions = await this.cliServer.resolveExtensions(
this.extensionPack.path,
getOnDiskWorkspaceFolders(),
const modeledMethods = await loadModeledMethods(
this.extensionPack,
this.cliServer,
this.app.logger,
);
const modelFiles = new Set<string>();
if (this.extensionPack.path in extensions.data) {
for (const extension of extensions.data[this.extensionPack.path]) {
modelFiles.add(extension.file);
}
}
const existingModeledMethods: Record<string, ModeledMethod> = {};
for (const modelFile of modelFiles) {
const yaml = await readFile(modelFile, "utf8");
const data = loadYaml(yaml, {
filename: modelFile,
});
const modeledMethods = loadDataExtensionYaml(data);
if (!modeledMethods) {
void showAndLogErrorMessage(
this.app.logger,
`Failed to parse data extension YAML ${modelFile}.`,
);
continue;
}
for (const [key, value] of Object.entries(modeledMethods)) {
existingModeledMethods[key] = value;
}
}
await this.postMessage({
t: "loadModeledMethods",
modeledMethods: existingModeledMethods,
modeledMethods,
});
} catch (e: unknown) {
void showAndLogErrorMessage(
@@ -277,252 +245,350 @@ export class DataExtensionsEditorView extends AbstractWebview<
}
protected async loadExternalApiUsages(): Promise<void> {
const cancellationTokenSource = new CancellationTokenSource();
await withProgress(
async (progress) => {
try {
const cancellationTokenSource = new CancellationTokenSource();
const queryResult = await runQuery(this.mode, {
cliServer: this.cliServer,
queryRunner: this.queryRunner,
databaseItem: this.databaseItem,
queryStorageDir: this.queryStorageDir,
queryDir: this.queryDir,
progress: (update) => progress({ ...update, maxStep: 1500 }),
token: cancellationTokenSource.token,
});
if (!queryResult) {
return;
}
try {
const queryResult = await runQuery(
this.mode === Mode.Framework
? "frameworkModeQuery"
: "applicationModeQuery",
{
cliServer: this.cliServer,
queryRunner: this.queryRunner,
databaseItem: this.databaseItem,
queryStorageDir: this.queryStorageDir,
progress: (progressUpdate: ProgressUpdate) => {
void this.showProgress(progressUpdate, 1500);
},
token: cancellationTokenSource.token,
},
);
if (!queryResult) {
await this.clearProgress();
return;
}
progress({
message: "Decoding results",
step: 1100,
maxStep: 1500,
});
await this.showProgress({
message: "Decoding results",
step: 1100,
maxStep: 1500,
});
const bqrsChunk = await readQueryResults({
cliServer: this.cliServer,
bqrsPath: queryResult.outputDir.bqrsPath,
});
if (!bqrsChunk) {
return;
}
const bqrsChunk = await readQueryResults({
cliServer: this.cliServer,
bqrsPath: queryResult.outputDir.bqrsPath,
});
if (!bqrsChunk) {
await this.clearProgress();
return;
}
progress({
message: "Finalizing results",
step: 1450,
maxStep: 1500,
});
await this.showProgress({
message: "Finalizing results",
step: 1450,
maxStep: 1500,
});
const externalApiUsages = decodeBqrsToExternalApiUsages(bqrsChunk);
const externalApiUsages = decodeBqrsToExternalApiUsages(bqrsChunk);
await this.postMessage({
t: "setExternalApiUsages",
externalApiUsages,
});
await this.clearProgress();
} catch (err) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError(
asError(err),
)`Failed to load external API usages: ${getErrorMessage(err)}`,
);
}
await this.postMessage({
t: "setExternalApiUsages",
externalApiUsages,
});
} catch (err) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError(
asError(err),
)`Failed to load external API usages: ${getErrorMessage(err)}`,
);
}
},
{ cancellable: false },
);
}
protected async generateModeledMethods(): Promise<void> {
const tokenSource = new CancellationTokenSource();
await withProgress(
async (progress) => {
const tokenSource = new CancellationTokenSource();
let addedDatabase: DatabaseItem | undefined;
let addedDatabase: DatabaseItem | undefined;
// In application mode, we need the database of a specific library to generate
// the modeled methods. In framework mode, we'll use the current database.
if (this.mode === Mode.Application) {
const selectedDatabase = this.databaseManager.currentDatabaseItem;
// The external API methods are in the library source code, so we need to ask
// the user to import the library database. We need to have the database
// imported to the query server, so we need to register it to our workspace.
addedDatabase = await promptImportGithubDatabase(
this.app.commands,
this.databaseManager,
this.app.workspaceStoragePath ?? this.app.globalStoragePath,
this.app.credentials,
(update) => this.showProgress(update),
this.cliServer,
);
if (!addedDatabase) {
await this.clearProgress();
void this.app.logger.log("No database chosen");
return;
}
// The library database was set as the current database by importing it,
// but we need to set it back to the originally selected database.
await this.databaseManager.setCurrentDatabaseItem(selectedDatabase);
}
await this.showProgress({
step: 0,
maxStep: 4000,
message: "Generating modeled methods for library",
});
try {
await generateFlowModel({
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
databaseItem: addedDatabase ?? this.databaseItem,
onResults: async (modeledMethods) => {
const modeledMethodsByName: Record<string, ModeledMethod> = {};
for (const modeledMethod of modeledMethods) {
modeledMethodsByName[modeledMethod.signature] = modeledMethod;
// In application mode, we need the database of a specific library to generate
// the modeled methods. In framework mode, we'll use the current database.
if (this.mode === Mode.Application) {
addedDatabase = await this.promptChooseNewOrExistingDatabase(
progress,
);
if (!addedDatabase) {
return;
}
}
await this.postMessage({
t: "addModeledMethods",
modeledMethods: modeledMethodsByName,
progress({
step: 0,
maxStep: 4000,
message: "Generating modeled methods for library",
});
try {
await generateFlowModel({
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
databaseItem: addedDatabase ?? this.databaseItem,
onResults: async (modeledMethods) => {
const modeledMethodsByName: Record<string, ModeledMethod> = {};
for (const modeledMethod of modeledMethods) {
modeledMethodsByName[modeledMethod.signature] = modeledMethod;
}
await this.postMessage({
t: "addModeledMethods",
modeledMethods: modeledMethodsByName,
});
},
progress,
token: tokenSource.token,
});
},
progress: (update) => this.showProgress(update),
token: tokenSource.token,
});
} catch (e: unknown) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError(
asError(e),
)`Failed to generate flow model: ${getErrorMessage(e)}`,
);
}
if (addedDatabase) {
// After the flow model has been generated, we can remove the temporary database
// which we used for generating the flow model.
await this.showProgress({
step: 3900,
maxStep: 4000,
message: "Removing temporary database",
});
await this.databaseManager.removeDatabaseItem(addedDatabase);
}
await this.clearProgress();
} catch (e: unknown) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError(
asError(e),
)`Failed to generate flow model: ${getErrorMessage(e)}`,
);
}
},
{ cancellable: false },
);
}
private async generateModeledMethodsFromLlm(
externalApiUsages: ExternalApiUsage[],
modeledMethods: Record<string, ModeledMethod>,
): Promise<void> {
const maxStep = 3000;
await withProgress(async (progress) => {
const maxStep = 3000;
await this.showProgress({
step: 0,
maxStep,
message: "Retrieving usages",
progress({
step: 0,
maxStep,
message: "Retrieving usages",
});
let predictedModeledMethods: Record<string, ModeledMethod>;
if (useLlmGenerationV2()) {
const usages = await runAutoModelQueries({
mode: this.mode,
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
databaseItem: this.databaseItem,
progress: (update) => progress({ ...update, maxStep }),
});
if (!usages) {
return;
}
progress({
step: 1800,
maxStep,
message: "Creating request",
});
const request = await createAutoModelV2Request(this.mode, usages);
progress({
step: 2000,
maxStep,
message: "Sending request",
});
const response = await this.callAutoModelApiV2(request);
if (!response) {
return;
}
progress({
step: 2500,
maxStep,
message: "Parsing response",
});
const models = loadYaml(response.models, {
filename: "auto-model.yml",
});
const modeledMethods = loadDataExtensionYaml(models);
if (!modeledMethods) {
return;
}
predictedModeledMethods = modeledMethods;
} else {
const usages = await getAutoModelUsages({
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
queryDir: this.queryDir,
databaseItem: this.databaseItem,
progress: (update) => progress({ ...update, maxStep }),
});
progress({
step: 1800,
maxStep,
message: "Creating request",
});
const request = createAutoModelRequest(
this.databaseItem.language,
externalApiUsages,
modeledMethods,
usages,
this.mode,
);
progress({
step: 2000,
maxStep,
message: "Sending request",
});
const response = await this.callAutoModelApi(request);
if (!response) {
return;
}
progress({
step: 2500,
maxStep,
message: "Parsing response",
});
predictedModeledMethods = parsePredictedClassifications(
response.predicted || [],
);
}
progress({
step: 2800,
maxStep,
message: "Applying results",
});
await this.postMessage({
t: "addModeledMethods",
modeledMethods: predictedModeledMethods,
});
});
}
const usages = await getAutoModelUsages({
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
databaseItem: this.databaseItem,
progress: (update) => this.showProgress(update, maxStep),
private async modelDependency(): Promise<void> {
return withProgress(async (progress, token) => {
const addedDatabase = await this.promptChooseNewOrExistingDatabase(
progress,
);
if (!addedDatabase || token.isCancellationRequested) {
return;
}
const modelFile = await pickExtensionPack(
this.cliServer,
addedDatabase,
this.app.logger,
progress,
token,
);
if (!modelFile) {
return;
}
const view = new DataExtensionsEditorView(
this.ctx,
this.app,
this.databaseManager,
this.cliServer,
this.queryRunner,
this.queryStorageDir,
this.queryDir,
addedDatabase,
modelFile,
Mode.Framework,
);
await view.openView();
});
}
await this.showProgress({
step: 1800,
maxStep,
message: "Creating request",
});
const request = createAutoModelRequest(
this.databaseItem.language,
externalApiUsages,
modeledMethods,
usages,
this.mode,
private async promptChooseNewOrExistingDatabase(
progress: ProgressCallback,
): Promise<DatabaseItem | undefined> {
const language = this.databaseItem.language;
const databases = this.databaseManager.databaseItems.filter(
(db) => db.language === language,
);
if (databases.length === 0) {
return await this.promptImportDatabase(progress);
} else {
const local = {
label: "$(database) Use existing database",
detail: "Use database from the workspace",
};
const github = {
label: "$(repo) Import database",
detail: "Choose database from GitHub",
};
const newOrExistingDatabase = await window.showQuickPick([local, github]);
await this.showProgress({
step: 2000,
maxStep,
message: "Sending request",
});
if (!newOrExistingDatabase) {
void this.app.logger.log("No database chosen");
return;
}
const response = await this.callAutoModelApi(request);
if (!response) {
if (newOrExistingDatabase === local) {
const pickedDatabase = await window.showQuickPick(
databases.map((database) => ({
label: database.name,
description: database.language,
database,
})),
{
placeHolder: "Pick a database",
},
);
if (!pickedDatabase) {
void this.app.logger.log("No database chosen");
return;
}
return pickedDatabase.database;
} else {
return await this.promptImportDatabase(progress);
}
}
}
private async promptImportDatabase(
progress: ProgressCallback,
): Promise<DatabaseItem | undefined> {
// The external API methods are in the library source code, so we need to ask
// the user to import the library database. We need to have the database
// imported to the query server, so we need to register it to our workspace.
const makeSelected = false;
const addedDatabase = await promptImportGithubDatabase(
this.app.commands,
this.databaseManager,
this.app.workspaceStoragePath ?? this.app.globalStoragePath,
this.app.credentials,
progress,
this.cliServer,
this.databaseItem.language,
makeSelected,
);
if (!addedDatabase) {
void this.app.logger.log("No database chosen");
return;
}
await this.showProgress({
step: 2500,
maxStep,
message: "Parsing response",
});
const predictedModeledMethods = parsePredictedClassifications(
response.predicted || [],
);
await this.showProgress({
step: 2800,
maxStep,
message: "Applying results",
});
await this.postMessage({
t: "addModeledMethods",
modeledMethods: predictedModeledMethods,
});
await this.clearProgress();
}
/*
* Progress in this class is a bit weird. Most of the progress is based on running the query.
* Query progress is always between 0 and 1000. However, we still have some steps that need
* to be done after the query has finished. Therefore, the maximum step is 1500. This captures
* that there's 1000 steps of the query progress since that takes the most time, and then
* an additional 500 steps for the rest of the work. The progress doesn't need to be 100%
* accurate, so this is just a rough estimate.
*
* For generating the modeled methods for an external library, the max step is 4000. This is
* based on the following steps:
* - 1000 for the summary model
* - 1000 for the sink model
* - 1000 for the source model
* - 1000 for the neutral model
*/
private async showProgress(update: ProgressUpdate, maxStep?: number) {
await this.postMessage({
t: "showProgress",
step: update.step,
maxStep: maxStep ?? update.maxStep,
message: update.message,
});
}
private async clearProgress() {
await this.showProgress({
step: 0,
maxStep: 0,
message: "",
});
return addedDatabase;
}
private async callAutoModelApi(
@@ -531,8 +597,25 @@ export class DataExtensionsEditorView extends AbstractWebview<
try {
return await autoModel(this.app.credentials, request);
} catch (e) {
await this.clearProgress();
if (e instanceof RequestError && e.status === 429) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError(e)`Rate limit hit, please try again soon.`,
);
return null;
} else {
throw e;
}
}
}
private async callAutoModelApiV2(
request: ModelRequestV2,
): Promise<ModelResponseV2 | null> {
try {
return await autoModelV2(this.app.credentials, request);
} catch (e) {
if (e instanceof RequestError && e.status === 429) {
void showAndLogExceptionWithTelemetry(
this.app.logger,

View File

@@ -43,6 +43,10 @@ export async function pickExtensionPack(
// Get all existing extension packs in the workspace
const additionalPacks = getOnDiskWorkspaceFolders();
// the CLI doesn't check packs in the .github folder, so we need to add it manually
if (additionalPacks.length === 1) {
additionalPacks.push(`${additionalPacks[0]}/.github`);
}
const extensionPacksInfo = await cliServer.resolveQlpacks(
additionalPacks,
true,
@@ -88,7 +92,7 @@ export async function pickExtensionPack(
let extensionPack: ExtensionPack;
try {
extensionPack = await readExtensionPack(path);
extensionPack = await readExtensionPack(path, databaseItem.language);
} catch (e: unknown) {
void showAndLogErrorMessage(
logger,
@@ -253,7 +257,10 @@ async function autoCreateExtensionPack(
if (existingExtensionPackPaths?.length === 1) {
let extensionPack: ExtensionPack;
try {
extensionPack = await readExtensionPack(existingExtensionPackPaths[0]);
extensionPack = await readExtensionPack(
existingExtensionPackPaths[0],
language,
);
} catch (e: unknown) {
void showAndLogErrorMessage(
logger,
@@ -317,6 +324,7 @@ async function writeExtensionPack(
yamlPath: packYamlPath,
name: formatPackName(packName),
version: "0.0.0",
language,
extensionTargets: {
[`codeql/${language}-all`]: "*",
},
@@ -337,7 +345,10 @@ async function writeExtensionPack(
return extensionPack;
}
async function readExtensionPack(path: string): Promise<ExtensionPack> {
async function readExtensionPack(
path: string,
language: string,
): Promise<ExtensionPack> {
const qlpackPath = await getQlPackPath(path);
if (!qlpackPath) {
throw new Error(
@@ -374,6 +385,7 @@ async function readExtensionPack(path: string): Promise<ExtensionPack> {
yamlPath: qlpackPath,
name: qlpack.name,
version: qlpack.version,
language,
extensionTargets: qlpack.extensionTargets,
dataExtensions,
};

View File

@@ -1,71 +1,44 @@
import { CoreCompletedQuery, QueryRunner } from "../query-server";
import { dir } from "tmp-promise";
import { writeFile } from "fs-extra";
import { dump as dumpYaml } from "js-yaml";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { extLogger } from "../common/logging/vscode";
import { showAndLogExceptionWithTelemetry, TeeLogger } from "../common/logging";
import { isQueryLanguage } from "../common/query-language";
import { CancellationToken } from "vscode";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { DatabaseItem } from "../databases/local-databases";
import { ProgressCallback } from "../common/vscode/progress";
import { fetchExternalApiQueries } from "./queries";
import { QueryResultType } from "../query-server/new-messages";
import { join } from "path";
import { redactableError } from "../common/errors";
import { telemetryListener } from "../common/vscode/telemetry";
import { join } from "path";
import { Mode } from "./shared/mode";
import { writeFile } from "fs-extra";
import { Query } from "./queries/query";
import { QueryLanguage } from "../common/query-language";
import { dump } from "js-yaml";
export type RunQueryOptions = {
type RunQueryOptions = {
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
queryRunner: Pick<QueryRunner, "createQueryRun" | "logger">;
databaseItem: Pick<DatabaseItem, "contents" | "databaseUri" | "language">;
queryStorageDir: string;
queryDir: string;
progress: ProgressCallback;
token: CancellationToken;
};
export async function runQuery(
queryName: keyof Omit<Query, "dependencies">,
{
cliServer,
queryRunner,
databaseItem,
queryStorageDir,
progress,
token,
}: RunQueryOptions,
): Promise<CoreCompletedQuery | undefined> {
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
// This is intentionally not pretty code, as it will be removed soon.
// For a reference of what this should do in the future, see the previous implementation in
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
if (!isQueryLanguage(databaseItem.language)) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`Unsupported database language ${databaseItem.language}`,
export async function setUpPack(
queryDir: string,
query: Query,
language: QueryLanguage,
) {
Object.values(Mode).map(async (mode) => {
const queryFile = join(
queryDir,
`FetchExternalApis${mode.charAt(0).toUpperCase() + mode.slice(1)}Mode.ql`,
);
return;
}
const query = fetchExternalApiQueries[databaseItem.language];
if (!query) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`No external API usage query found for language ${databaseItem.language}`,
);
return;
}
const queryDir = (await dir({ unsafeCleanup: true })).path;
const queryFile = join(queryDir, "FetchExternalApis.ql");
await writeFile(queryFile, query[queryName], "utf8");
await writeFile(queryFile, query[`${mode}ModeQuery`], "utf8");
});
if (query.dependencies) {
for (const [filename, contents] of Object.entries(query.dependencies)) {
@@ -78,18 +51,42 @@ export async function runQuery(
name: "codeql/external-api-usage",
version: "0.0.0",
dependencies: {
[`codeql/${databaseItem.language}-all`]: "*",
[`codeql/${language}-all`]: "*",
},
};
const qlpackFile = join(queryDir, "codeql-pack.yml");
await writeFile(qlpackFile, dumpYaml(syntheticQueryPack), "utf8");
await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8");
}
export async function runQuery(
mode: Mode,
{
cliServer,
queryRunner,
databaseItem,
queryStorageDir,
queryDir,
progress,
token,
}: RunQueryOptions,
): Promise<CoreCompletedQuery | undefined> {
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
// This is intentionally not pretty code, as it will be removed soon.
// For a reference of what this should do in the future, see the previous implementation in
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
const additionalPacks = getOnDiskWorkspaceFolders();
const extensionPacks = Object.keys(
await cliServer.resolveQlpacks(additionalPacks, true),
);
const queryFile = join(
queryDir,
`FetchExternalApis${mode.charAt(0).toUpperCase() + mode.slice(1)}Mode.ql`,
);
const queryRun = queryRunner.createQueryRun(
databaseItem.databaseUri.fsPath,
{
@@ -125,7 +122,7 @@ export async function runQuery(
return completedQuery;
}
export type GetResultsOptions = {
type GetResultsOptions = {
cliServer: Pick<CodeQLCliServer, "bqrsInfo" | "bqrsDecode">;
bqrsPath: string;
};

View File

@@ -13,7 +13,7 @@ export enum CallClassification {
Generated = "generated",
}
export type Usage = Call & {
type Usage = Call & {
classification: CallClassification;
};

View File

@@ -14,7 +14,7 @@ import { QueryResultType } from "../query-server/new-messages";
import { file } from "tmp-promise";
import { writeFile } from "fs-extra";
import { dump } from "js-yaml";
import { qlpackOfDatabase } from "../language-support";
import { qlpackOfDatabase } from "../local-queries";
import { telemetryListener } from "../common/vscode/telemetry";
type FlowModelOptions = {

View File

@@ -14,7 +14,7 @@ import { basename, extname } from "../common/path";
const semverRegex =
/-[v=\s]*(?<version>([0-9]+)(\.([0-9]+)(?:(\.([0-9]+))?(?:[-.]?((?:[0-9]+|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:[0-9]+|\d*[a-zA-Z-][a-zA-Z0-9-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?)?)?)/g;
export interface Library {
interface Library {
name: string;
version?: string;
}

View File

@@ -0,0 +1,118 @@
import { outputFile, readFile } from "fs-extra";
import { ExternalApiUsage } from "./external-api-usage";
import { ModeledMethod } from "./modeled-method";
import { Mode } from "./shared/mode";
import { createDataExtensionYamls, loadDataExtensionYaml } from "./yaml";
import { join, relative } from "path";
import { ExtensionPack } from "./shared/extension-pack";
import { NotificationLogger, showAndLogErrorMessage } from "../common/logging";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { load as loadYaml } from "js-yaml";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { pathsEqual } from "../common/files";
export async function saveModeledMethods(
extensionPack: ExtensionPack,
databaseName: string,
language: string,
externalApiUsages: ExternalApiUsage[],
modeledMethods: Record<string, ModeledMethod>,
mode: Mode,
cliServer: CodeQLCliServer,
logger: NotificationLogger,
): Promise<void> {
const existingModeledMethods = await loadModeledMethodFiles(
extensionPack,
cliServer,
logger,
);
const yamls = createDataExtensionYamls(
databaseName,
language,
externalApiUsages,
modeledMethods,
existingModeledMethods,
mode,
);
for (const [filename, yaml] of Object.entries(yamls)) {
await outputFile(join(extensionPack.path, filename), yaml);
}
void logger.log(`Saved data extension YAML`);
}
async function loadModeledMethodFiles(
extensionPack: ExtensionPack,
cliServer: CodeQLCliServer,
logger: NotificationLogger,
): Promise<Record<string, Record<string, ModeledMethod>>> {
const modelFiles = await listModelFiles(extensionPack.path, cliServer);
const modeledMethodsByFile: Record<
string,
Record<string, ModeledMethod>
> = {};
for (const modelFile of modelFiles) {
const yaml = await readFile(join(extensionPack.path, modelFile), "utf8");
const data = loadYaml(yaml, {
filename: modelFile,
});
const modeledMethods = loadDataExtensionYaml(data);
if (!modeledMethods) {
void showAndLogErrorMessage(
logger,
`Failed to parse data extension YAML ${modelFile}.`,
);
continue;
}
modeledMethodsByFile[modelFile] = modeledMethods;
}
return modeledMethodsByFile;
}
export async function loadModeledMethods(
extensionPack: ExtensionPack,
cliServer: CodeQLCliServer,
logger: NotificationLogger,
): Promise<Record<string, ModeledMethod>> {
const existingModeledMethods: Record<string, ModeledMethod> = {};
const modeledMethodsByFile = await loadModeledMethodFiles(
extensionPack,
cliServer,
logger,
);
for (const modeledMethods of Object.values(modeledMethodsByFile)) {
for (const [key, value] of Object.entries(modeledMethods)) {
existingModeledMethods[key] = value;
}
}
return existingModeledMethods;
}
export async function listModelFiles(
extensionPackPath: string,
cliServer: CodeQLCliServer,
): Promise<Set<string>> {
const result = await cliServer.resolveExtensions(
extensionPackPath,
getOnDiskWorkspaceFolders(),
);
const modelFiles = new Set<string>();
for (const [path, extensions] of Object.entries(result.data)) {
if (pathsEqual(path, extensionPackPath)) {
for (const extension of extensions) {
modelFiles.add(relative(extensionPackPath, extension.file));
}
}
}
return modelFiles;
}

View File

@@ -4,6 +4,7 @@ export interface ExtensionPack {
name: string;
version: string;
language: string;
extensionTargets: Record<string, string>;
dataExtensions: string[];

View File

@@ -9,6 +9,8 @@ import {
import * as dataSchemaJson from "./data-schema.json";
import { sanitizeExtensionPackName } from "./extension-pack-name";
import { Mode } from "./shared/mode";
import { assertNever } from "../common/helpers-pure";
const ajv = new Ajv({ allErrors: true });
const dataSchemaValidate = ajv.compile(dataSchemaJson);
@@ -66,30 +68,83 @@ export function createDataExtensionYaml(
${extensions.join("\n")}`;
}
export function createDataExtensionYamls(
databaseName: string,
language: string,
externalApiUsages: ExternalApiUsage[],
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
mode: Mode,
) {
switch (mode) {
case Mode.Application:
return createDataExtensionYamlsForApplicationMode(
language,
externalApiUsages,
newModeledMethods,
existingModeledMethods,
);
case Mode.Framework:
return createDataExtensionYamlsForFrameworkMode(
databaseName,
language,
externalApiUsages,
newModeledMethods,
existingModeledMethods,
);
default:
assertNever(mode);
}
}
export function createDataExtensionYamlsForApplicationMode(
language: string,
externalApiUsages: ExternalApiUsage[],
modeledMethods: Record<string, ModeledMethod>,
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
): Record<string, string> {
const methodsByLibraryFilename: Record<string, ModeledMethod[]> = {};
const methodsByLibraryFilename: Record<
string,
Record<string, ModeledMethod>
> = {};
// We only want to generate a yaml file when it's a known external API usage
// and there are new modeled methods for it. This avoids us overwriting other
// files that may contain data we don't know about.
for (const externalApiUsage of externalApiUsages) {
const modeledMethod = modeledMethods[externalApiUsage.signature];
if (!modeledMethod) {
continue;
if (externalApiUsage.signature in newModeledMethods) {
methodsByLibraryFilename[
createFilenameForLibrary(externalApiUsage.library)
] = {};
}
}
const filename = createFilenameForLibrary(externalApiUsage.library);
// First populate methodsByLibraryFilename with any existing modeled methods.
for (const [filename, methods] of Object.entries(existingModeledMethods)) {
if (filename in methodsByLibraryFilename) {
for (const [signature, method] of Object.entries(methods)) {
methodsByLibraryFilename[filename][signature] = method;
}
}
}
methodsByLibraryFilename[filename] =
methodsByLibraryFilename[filename] || [];
methodsByLibraryFilename[filename].push(modeledMethod);
// Add the new modeled methods, potentially overwriting existing modeled methods
// but not removing existing modeled methods that are not in the new set.
for (const externalApiUsage of externalApiUsages) {
const method = newModeledMethods[externalApiUsage.signature];
if (method) {
const filename = createFilenameForLibrary(externalApiUsage.library);
methodsByLibraryFilename[filename][method.signature] = method;
}
}
const result: Record<string, string> = {};
for (const [filename, methods] of Object.entries(methodsByLibraryFilename)) {
result[filename] = createDataExtensionYaml(language, methods);
result[filename] = createDataExtensionYaml(
language,
Object.values(methods),
);
}
return result;
@@ -99,7 +154,8 @@ export function createDataExtensionYamlsForFrameworkMode(
databaseName: string,
language: string,
externalApiUsages: ExternalApiUsage[],
modeledMethods: Record<string, ModeledMethod>,
newModeledMethods: Record<string, ModeledMethod>,
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
prefix = "models/",
suffix = ".model",
): Record<string, string> {
@@ -108,16 +164,28 @@ export function createDataExtensionYamlsForFrameworkMode(
.slice(1)
.map((part) => sanitizeExtensionPackName(part))
.join("-");
const filename = `${prefix}${libraryName}${suffix}.yml`;
const methods = externalApiUsages
.map((externalApiUsage) => modeledMethods[externalApiUsage.signature])
.filter((modeledMethod) => modeledMethod !== undefined);
const methods: Record<string, ModeledMethod> = {};
// First populate methodsByLibraryFilename with any existing modeled methods.
for (const [signature, method] of Object.entries(
existingModeledMethods[filename] || {},
)) {
methods[signature] = method;
}
// Add the new modeled methods, potentially overwriting existing modeled methods
// but not removing existing modeled methods that are not in the new set.
for (const externalApiUsage of externalApiUsages) {
const modeledMethod = newModeledMethods[externalApiUsage.signature];
if (modeledMethod) {
methods[modeledMethod.signature] = modeledMethod;
}
}
return {
[`${prefix}${libraryName}${suffix}.yml`]: createDataExtensionYaml(
language,
methods,
),
[filename]: createDataExtensionYaml(language, Object.values(methods)),
};
}

View File

@@ -9,7 +9,7 @@ export interface DbConfig {
selected?: SelectedDbItem;
}
export interface DbConfigDatabases {
interface DbConfigDatabases {
variantAnalysis: RemoteDbConfig;
local: LocalDbConfig;
}
@@ -31,39 +31,39 @@ export enum SelectedDbItemKind {
VariantAnalysisRepository = "variantAnalysisRepository",
}
export interface SelectedLocalUserDefinedList {
interface SelectedLocalUserDefinedList {
kind: SelectedDbItemKind.LocalUserDefinedList;
listName: string;
}
export interface SelectedLocalDatabase {
interface SelectedLocalDatabase {
kind: SelectedDbItemKind.LocalDatabase;
databaseName: string;
listName?: string;
}
export interface SelectedRemoteSystemDefinedList {
interface SelectedRemoteSystemDefinedList {
kind: SelectedDbItemKind.VariantAnalysisSystemDefinedList;
listName: string;
}
export interface SelectedVariantAnalysisUserDefinedList {
interface SelectedVariantAnalysisUserDefinedList {
kind: SelectedDbItemKind.VariantAnalysisUserDefinedList;
listName: string;
}
export interface SelectedRemoteOwner {
interface SelectedRemoteOwner {
kind: SelectedDbItemKind.VariantAnalysisOwner;
ownerName: string;
}
export interface SelectedRemoteRepository {
interface SelectedRemoteRepository {
kind: SelectedDbItemKind.VariantAnalysisRepository;
repositoryName: string;
listName?: string;
}
export interface RemoteDbConfig {
interface RemoteDbConfig {
repositoryLists: RemoteRepositoryList[];
owners: string[];
repositories: string[];
@@ -74,7 +74,7 @@ export interface RemoteRepositoryList {
repositories: string[];
}
export interface LocalDbConfig {
interface LocalDbConfig {
lists: LocalList[];
databases: LocalDatabase[];
}

View File

@@ -30,7 +30,7 @@ import {
} from "../common/github-url-identifier-helper";
import { Credentials } from "../common/authentication";
import { AppCommandManager } from "../common/commands";
import { ALLOW_HTTP_SETTING } from "../config";
import { allowHttp } from "../config";
import { showAndLogInformationMessage } from "../common/logging";
/**
@@ -85,6 +85,8 @@ export async function promptImportInternetDatabase(
* @param credentials the credentials to use to authenticate with GitHub
* @param progress the progress callback
* @param cli the CodeQL CLI server
* @param language the language to download. If undefined, the user will be prompted to choose a language.
* @param makeSelected make the new database selected in the databases panel (default: true)
*/
export async function promptImportGithubDatabase(
commandManager: AppCommandManager,
@@ -93,6 +95,8 @@ export async function promptImportGithubDatabase(
credentials: Credentials | undefined,
progress: ProgressCallback,
cli?: CodeQLCliServer,
language?: string,
makeSelected = true,
): Promise<DatabaseItem | undefined> {
const githubRepo = await askForGitHubRepo(progress);
if (!githubRepo) {
@@ -106,10 +110,14 @@ export async function promptImportGithubDatabase(
credentials,
progress,
cli,
language,
makeSelected,
);
if (databaseItem) {
await commandManager.execute("codeQLDatabases.focus");
if (makeSelected) {
await commandManager.execute("codeQLDatabases.focus");
}
void showAndLogInformationMessage(
extLogger,
"Database downloaded and imported successfully.",
@@ -154,6 +162,7 @@ export async function askForGitHubRepo(
* @param progress the progress callback
* @param cli the CodeQL CLI server
* @param language the language to download. If undefined, the user will be prompted to choose a language.
* @param makeSelected make the new database selected in the databases panel (default: true)
**/
export async function downloadGitHubDatabase(
githubRepo: string,
@@ -163,6 +172,7 @@ export async function downloadGitHubDatabase(
progress: ProgressCallback,
cli?: CodeQLCliServer,
language?: string,
makeSelected = true,
): Promise<DatabaseItem | undefined> {
const nwo = getNwoFromGitHubUrl(githubRepo) || githubRepo;
if (!isValidGitHubNwo(nwo)) {
@@ -207,6 +217,7 @@ export async function downloadGitHubDatabase(
`${owner}/${name}`,
progress,
cli,
makeSelected,
);
}
@@ -265,6 +276,7 @@ export async function importArchiveDatabase(
* @param storagePath where to store the unzipped database.
* @param nameOverride a name for the database that overrides the default
* @param progress callback to send progress messages to
* @param makeSelected make the new database selected in the databases panel (default: true)
*/
async function databaseArchiveFetcher(
databaseUrl: string,
@@ -274,6 +286,7 @@ async function databaseArchiveFetcher(
nameOverride: string | undefined,
progress: ProgressCallback,
cli?: CodeQLCliServer,
makeSelected = true,
): Promise<DatabaseItem> {
progress({
message: "Getting database",
@@ -312,8 +325,6 @@ async function databaseArchiveFetcher(
});
await ensureZippedSourceLocation(dbPath);
const makeSelected = true;
const item = await databaseManager.openDatabase(
Uri.file(dbPath),
makeSelected,
@@ -360,7 +371,7 @@ function validateUrl(databaseUrl: string) {
throw new Error(`Invalid url: ${databaseUrl}`);
}
if (!ALLOW_HTTP_SETTING.getValue() && uri.scheme !== "https") {
if (!allowHttp() && uri.scheme !== "https") {
throw new Error("Must use https for downloading a database.");
}
}

View File

@@ -13,16 +13,16 @@ export enum ExpandedDbItemKind {
RemoteUserDefinedList = "remoteUserDefinedList",
}
export interface RootLocalExpandedDbItem {
interface RootLocalExpandedDbItem {
kind: ExpandedDbItemKind.RootLocal;
}
export interface LocalUserDefinedListExpandedDbItem {
interface LocalUserDefinedListExpandedDbItem {
kind: ExpandedDbItemKind.LocalUserDefinedList;
listName: string;
}
export interface RootRemoteExpandedDbItem {
interface RootRemoteExpandedDbItem {
kind: ExpandedDbItemKind.RootRemote;
}

View File

@@ -11,20 +11,6 @@ export enum DbItemKind {
RemoteRepo = "RemoteRepo",
}
export const remoteDbKinds = [
DbItemKind.RootRemote,
DbItemKind.RemoteSystemDefinedList,
DbItemKind.RemoteUserDefinedList,
DbItemKind.RemoteOwner,
DbItemKind.RemoteRepo,
];
export const localDbKinds = [
DbItemKind.RootLocal,
DbItemKind.LocalList,
DbItemKind.LocalDatabase,
];
export enum DbListKind {
Local = "Local",
Remote = "Remote",
@@ -103,12 +89,6 @@ export interface RemoteRepoDbItem {
parentListName?: string;
}
export function isRemoteSystemDefinedListDbItem(
dbItem: DbItem,
): dbItem is RemoteSystemDefinedListDbItem {
return dbItem.kind === DbItemKind.RemoteSystemDefinedList;
}
export function isRemoteUserDefinedListDbItem(
dbItem: DbItem,
): dbItem is RemoteUserDefinedListDbItem {
@@ -135,7 +115,7 @@ export function isLocalDatabaseDbItem(
return dbItem.kind === DbItemKind.LocalDatabase;
}
export type SelectableDbItem = RemoteDbItem | LocalDbItem;
type SelectableDbItem = RemoteDbItem | LocalDbItem;
export function isSelectableDbItem(dbItem: DbItem): dbItem is SelectableDbItem {
return SelectableDbItemKinds.includes(dbItem.kind);

View File

@@ -47,7 +47,7 @@ export interface AddListQuickPickItem extends QuickPickItem {
databaseKind: DbListKind;
}
export interface CodeSearchQuickPickItem extends QuickPickItem {
interface CodeSearchQuickPickItem extends QuickPickItem {
language: string;
}

View File

@@ -1,6 +1,6 @@
import { DbItem, DbItemKind, isSelectableDbItem } from "../db-item";
export type DbTreeViewItemAction =
type DbTreeViewItemAction =
| "canBeSelected"
| "canBeRemoved"
| "canBeRenamed"

View File

@@ -315,6 +315,7 @@ const MIN_VERSION = "1.67.0";
*
* @returns CodeQLExtensionInterface
*/
// ts-unused-exports:disable-next-line
export async function activate(
ctx: ExtensionContext,
): Promise<CodeQLExtensionInterface | undefined> {

View File

@@ -12,16 +12,13 @@ import { CodeQLCliServer } from "../../codeql-cli/cli";
import { DatabaseManager, DatabaseItem } from "../../databases/local-databases";
import { ProgressCallback } from "../../common/vscode/progress";
import { KeyType } from "./key-type";
import {
qlpackOfDatabase,
resolveQueries,
runContextualQuery,
} from "./query-resolver";
import { resolveQueries, runContextualQuery } from "./query-resolver";
import { CancellationToken, LocationLink, Uri } from "vscode";
import { QueryOutputDir } from "../../run-queries-shared";
import { QueryRunner } from "../../query-server";
import { QueryResultType } from "../../query-server/new-messages";
import { fileRangeFromURI } from "./file-range-from-uri";
import { qlpackOfDatabase } from "../../local-queries";
export const SELECT_QUERY_NAME = "#select";
export const SELECTED_SOURCE_FILE = "selectedSourceFile";

View File

@@ -1,14 +1,5 @@
import { writeFile, promises } from "fs-extra";
import { dump } from "js-yaml";
import { file } from "tmp-promise";
import { basename, dirname, resolve } from "path";
import { getOnDiskWorkspaceFolders } from "../../common/vscode/workspace-folders";
import {
getPrimaryDbscheme,
getQlPackForDbscheme,
QlPacksForLanguage,
} from "../../databases/qlpack";
import { QlPacksForLanguage } from "../../databases/qlpack";
import {
KeyType,
kindOfKeyType,
@@ -17,154 +8,22 @@ import {
} from "./key-type";
import { CodeQLCliServer } from "../../codeql-cli/cli";
import { DatabaseItem } from "../../databases/local-databases";
import { resolveQueries as resolveLocalQueries } from "../../local-queries/query-resolver";
import { extLogger } from "../../common/logging/vscode";
import {
showAndLogExceptionWithTelemetry,
TeeLogger,
} from "../../common/logging";
import { TeeLogger } from "../../common/logging";
import { CancellationToken } from "vscode";
import { ProgressCallback } from "../../common/vscode/progress";
import { CoreCompletedQuery, QueryRunner } from "../../query-server";
import { redactableError } from "../../common/errors";
import { QLPACK_FILENAMES } from "../../common/ql";
import { telemetryListener } from "../../common/vscode/telemetry";
export async function qlpackOfDatabase(
cli: Pick<CodeQLCliServer, "resolveQlpacks">,
db: Pick<DatabaseItem, "contents">,
): Promise<QlPacksForLanguage> {
if (db.contents === undefined) {
throw new Error("Database is invalid and cannot infer QLPack.");
}
const datasetPath = db.contents.datasetUri.fsPath;
const dbscheme = await getPrimaryDbscheme(datasetPath);
return await getQlPackForDbscheme(cli, dbscheme);
}
/**
* Finds the contextual queries with the specified key in a list of CodeQL packs.
*
* @param cli The CLI instance to use.
* @param qlpacks The list of packs to search.
* @param keyType The contextual query key of the query to search for.
* @returns The found queries from the first pack in which any matching queries were found.
*/
async function resolveQueriesFromPacks(
cli: CodeQLCliServer,
qlpacks: string[],
keyType: KeyType,
): Promise<string[]> {
const suiteFile = (
await file({
postfix: ".qls",
})
).path;
const suiteYaml = [];
for (const qlpack of qlpacks) {
suiteYaml.push({
from: qlpack,
queries: ".",
include: {
kind: kindOfKeyType(keyType),
"tags contain": tagOfKeyType(keyType),
},
});
}
await writeFile(suiteFile, dump(suiteYaml), "utf8");
const queries = await cli.resolveQueriesInSuite(
suiteFile,
getOnDiskWorkspaceFolders(),
);
return queries;
}
import { createLockFileForStandardQuery } from "../../local-queries/standard-queries";
export async function resolveQueries(
cli: CodeQLCliServer,
qlpacks: QlPacksForLanguage,
keyType: KeyType,
): Promise<string[]> {
const packsToSearch: string[] = [];
// The CLI can handle both library packs and query packs, so search both packs in order.
packsToSearch.push(qlpacks.dbschemePack);
if (qlpacks.queryPack !== undefined) {
packsToSearch.push(qlpacks.queryPack);
}
const queries = await resolveQueriesFromPacks(cli, packsToSearch, keyType);
if (queries.length > 0) {
return queries;
}
// No queries found. Determine the correct error message for the various scenarios.
const keyTypeName = nameOfKeyType(keyType);
const keyTypeTag = tagOfKeyType(keyType);
const joinedPacksToSearch = packsToSearch.join(", ");
const error = redactableError`No ${keyTypeName} queries (tagged "${keyTypeTag}") could be found in the \
current library path (tried searching the following packs: ${joinedPacksToSearch}). \
Try upgrading the CodeQL libraries. If that doesn't work, then ${keyTypeName} queries are not yet available \
for this language.`;
void showAndLogExceptionWithTelemetry(extLogger, telemetryListener, error);
throw error;
}
async function resolveContextualQuery(
cli: CodeQLCliServer,
query: string,
): Promise<{ packPath: string; createdTempLockFile: boolean }> {
// Contextual queries now live within the standard library packs.
// This simplifies distribution (you don't need the standard query pack to use the AST viewer),
// but if the library pack doesn't have a lockfile, we won't be able to find
// other pack dependencies of the library pack.
// Work out the enclosing pack.
const packContents = await cli.packPacklist(query, false);
const packFilePath = packContents.find((p) =>
QLPACK_FILENAMES.includes(basename(p)),
);
if (packFilePath === undefined) {
// Should not happen; we already resolved this query.
throw new Error(
`Could not find a CodeQL pack file for the pack enclosing the contextual query ${query}`,
);
}
const packPath = dirname(packFilePath);
const lockFilePath = packContents.find((p) =>
["codeql-pack.lock.yml", "qlpack.lock.yml"].includes(basename(p)),
);
let createdTempLockFile = false;
if (!lockFilePath) {
// No lock file, likely because this library pack is in the package cache.
// Create a lock file so that we can resolve dependencies and library path
// for the contextual query.
void extLogger.log(
`Library pack ${packPath} is missing a lock file; creating a temporary lock file`,
);
await cli.packResolveDependencies(packPath);
createdTempLockFile = true;
// Clear CLI server pack cache before installing dependencies,
// so that it picks up the new lock file, not the previously cached pack.
void extLogger.log("Clearing the CodeQL CLI server's pack cache");
await cli.clearCache();
// Install dependencies.
void extLogger.log(
`Installing package dependencies for library pack ${packPath}`,
);
await cli.packInstall(packPath);
}
return { packPath, createdTempLockFile };
}
async function removeTemporaryLockFile(packPath: string) {
const tempLockFilePath = resolve(packPath, "codeql-pack.lock.yml");
void extLogger.log(
`Deleting temporary package lock file at ${tempLockFilePath}`,
);
// It's fine if the file doesn't exist.
await promises.rm(resolve(packPath, "codeql-pack.lock.yml"), {
force: true,
return resolveLocalQueries(cli, qlpacks, nameOfKeyType(keyType), {
kind: kindOfKeyType(keyType),
"tags contain": [tagOfKeyType(keyType)],
});
}
@@ -178,10 +37,7 @@ export async function runContextualQuery(
token: CancellationToken,
templates: Record<string, string>,
): Promise<CoreCompletedQuery> {
const { packPath, createdTempLockFile } = await resolveContextualQuery(
cli,
query,
);
const { cleanup } = await createLockFileForStandardQuery(cli, query);
const queryRun = qs.createQueryRun(
db.databaseUri.fsPath,
{ queryPath: query, quickEvalPosition: undefined },
@@ -200,8 +56,6 @@ export async function runContextualQuery(
token,
new TeeLogger(qs.logger, queryRun.outputDir.logPath),
);
if (createdTempLockFile) {
await removeTemporaryLockFile(packPath);
}
await cleanup?.();
return results;
}

View File

@@ -27,11 +27,7 @@ import {
SELECTED_SOURCE_LINE,
SELECTED_SOURCE_COLUMN,
} from "./location-finder";
import {
qlpackOfDatabase,
resolveQueries,
runContextualQuery,
} from "./query-resolver";
import { resolveQueries, runContextualQuery } from "./query-resolver";
import {
isCanary,
NO_CACHE_AST_VIEWER,
@@ -39,6 +35,7 @@ import {
} from "../../config";
import { CoreCompletedQuery, QueryRunner } from "../../query-server";
import { AstBuilder } from "../ast-viewer/ast-builder";
import { qlpackOfDatabase } from "../../local-queries";
/**
* Runs templated CodeQL queries to find definitions in

View File

@@ -20,6 +20,7 @@ export function install() {
decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]].*$/,
increaseIndentPattern: /^((?!\/\/).)*(\{[^}"'`]*|\([^)"'`]*|\[[^\]"'`]*)$/,
};
delete langConfig.autoClosingPairs;
languages.setLanguageConfiguration("ql", langConfig);
languages.setLanguageConfiguration("qll", langConfig);

View File

@@ -1,5 +1,6 @@
export * from "./local-queries";
export * from "./local-query-run";
export * from "./query-resolver";
export * from "./quick-eval-code-lens-provider";
export * from "./quick-query";
export * from "./results-view";

View File

@@ -0,0 +1,131 @@
import { CodeQLCliServer } from "../codeql-cli/cli";
import { DatabaseItem } from "../databases/local-databases";
import {
getPrimaryDbscheme,
getQlPackForDbscheme,
QlPacksForLanguage,
} from "../databases/qlpack";
import { file } from "tmp-promise";
import { writeFile } from "fs-extra";
import { dump } from "js-yaml";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { redactableError } from "../common/errors";
import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { extLogger } from "../common/logging/vscode";
import { telemetryListener } from "../common/vscode/telemetry";
export async function qlpackOfDatabase(
cli: Pick<CodeQLCliServer, "resolveQlpacks">,
db: Pick<DatabaseItem, "contents">,
): Promise<QlPacksForLanguage> {
if (db.contents === undefined) {
throw new Error("Database is invalid and cannot infer QLPack.");
}
const datasetPath = db.contents.datasetUri.fsPath;
const dbscheme = await getPrimaryDbscheme(datasetPath);
return await getQlPackForDbscheme(cli, dbscheme);
}
export interface QueryConstraints {
kind?: string;
"tags contain"?: string[];
"tags contain all"?: string[];
}
/**
* Finds the queries with the specified kind and tags in a list of CodeQL packs.
*
* @param cli The CLI instance to use.
* @param qlpacks The list of packs to search.
* @param constraints Constraints on the queries to search for.
* @returns The found queries from the first pack in which any matching queries were found.
*/
async function resolveQueriesFromPacks(
cli: CodeQLCliServer,
qlpacks: string[],
constraints: QueryConstraints,
): Promise<string[]> {
const suiteFile = (
await file({
postfix: ".qls",
})
).path;
const suiteYaml = [];
for (const qlpack of qlpacks) {
suiteYaml.push({
from: qlpack,
queries: ".",
include: constraints,
});
}
await writeFile(
suiteFile,
dump(suiteYaml, {
noRefs: true, // CodeQL doesn't really support refs
}),
"utf8",
);
return await cli.resolveQueriesInSuite(
suiteFile,
getOnDiskWorkspaceFolders(),
);
}
/**
* Finds the queries with the specified kind and tags in a QLPack.
*
* @param cli The CLI instance to use.
* @param qlpacks The list of packs to search.
* @param name The name of the query to use in error messages.
* @param constraints Constraints on the queries to search for.
* @returns The found queries from the first pack in which any matching queries were found.
*/
export async function resolveQueries(
cli: CodeQLCliServer,
qlpacks: QlPacksForLanguage,
name: string,
constraints: QueryConstraints,
): Promise<string[]> {
const packsToSearch: string[] = [];
// The CLI can handle both library packs and query packs, so search both packs in order.
packsToSearch.push(qlpacks.dbschemePack);
if (qlpacks.queryPack !== undefined) {
packsToSearch.push(qlpacks.queryPack);
}
const queries = await resolveQueriesFromPacks(
cli,
packsToSearch,
constraints,
);
if (queries.length > 0) {
return queries;
}
// No queries found. Determine the correct error message for the various scenarios.
const humanConstraints = [];
if (constraints.kind !== undefined) {
humanConstraints.push(`kind "${constraints.kind}"`);
}
if (constraints["tags contain"] !== undefined) {
humanConstraints.push(`tagged "${constraints["tags contain"].join(" ")}"`);
}
if (constraints["tags contain all"] !== undefined) {
humanConstraints.push(
`tagged all of "${constraints["tags contain all"].join(" ")}"`,
);
}
const joinedPacksToSearch = packsToSearch.join(", ");
const error = redactableError`No ${name} queries (${humanConstraints.join(
", ",
)}) could be found in the \
current library path (tried searching the following packs: ${joinedPacksToSearch}). \
Try upgrading the CodeQL libraries. If that doesn't work, then ${name} queries are not yet available \
for this language.`;
void showAndLogExceptionWithTelemetry(extLogger, telemetryListener, error);
throw error;
}

View File

@@ -0,0 +1,77 @@
import { CodeQLCliServer } from "../codeql-cli/cli";
import { QLPACK_FILENAMES, QLPACK_LOCK_FILENAMES } from "../common/ql";
import { basename, dirname, resolve } from "path";
import { extLogger } from "../common/logging/vscode";
import { promises } from "fs-extra";
import { BaseLogger } from "../common/logging";
type LockFileForStandardQueryResult = {
cleanup?: () => Promise<void>;
};
/**
* Create a temporary query suite for a given query living within the standard library packs.
*
* This will create a lock file so the CLI can run the query without having the ql submodule.
*/
export async function createLockFileForStandardQuery(
cli: CodeQLCliServer,
queryPath: string,
logger: BaseLogger = extLogger,
): Promise<LockFileForStandardQueryResult> {
// These queries live within the standard library packs.
// This simplifies distribution (you don't need the standard query pack to use the AST viewer),
// but if the library pack doesn't have a lockfile, we won't be able to find
// other pack dependencies of the library pack.
// Work out the enclosing pack.
const packContents = await cli.packPacklist(queryPath, false);
const packFilePath = packContents.find((p) =>
QLPACK_FILENAMES.includes(basename(p)),
);
if (packFilePath === undefined) {
// Should not happen; we already resolved this query.
throw new Error(
`Could not find a CodeQL pack file for the pack enclosing the contextual query ${queryPath}`,
);
}
const packPath = dirname(packFilePath);
const lockFilePath = packContents.find((p) =>
QLPACK_LOCK_FILENAMES.includes(basename(p)),
);
let cleanup: (() => Promise<void>) | undefined = undefined;
if (!lockFilePath) {
// No lock file, likely because this library pack is in the package cache.
// Create a lock file so that we can resolve dependencies and library path
// for the contextual query.
void logger.log(
`Library pack ${packPath} is missing a lock file; creating a temporary lock file`,
);
await cli.packResolveDependencies(packPath);
cleanup = async () => {
const tempLockFilePath = resolve(packPath, "codeql-pack.lock.yml");
void logger.log(
`Deleting temporary package lock file at ${tempLockFilePath}`,
);
// It's fine if the file doesn't exist.
await promises.rm(resolve(packPath, "codeql-pack.lock.yml"), {
force: true,
});
};
// Clear CLI server pack cache before installing dependencies,
// so that it picks up the new lock file, not the previously cached pack.
void logger.log("Clearing the CodeQL CLI server's pack cache");
await cli.clearCache();
// Install dependencies.
void logger.log(
`Installing package dependencies for library pack ${packPath}`,
);
await cli.packInstall(packPath);
}
return { cleanup };
}

View File

@@ -1,5 +1,6 @@
import { SummaryEvent } from "./log-summary";
import { readJsonlFile } from "../common/jsonl-reader";
import { Disposable } from "../common/disposable-object";
/**
* Callback interface used to report diagnostics from a log scanner.
@@ -62,13 +63,6 @@ export interface EvaluationLogScannerProvider {
): EvaluationLogScanner;
}
/**
* Same as VSCode's `Disposable`, but avoids a dependency on VS Code.
*/
export interface Disposable {
dispose(): void;
}
export class EvaluationLogScannerSet {
private readonly scannerProviders = new Map<
number,

View File

@@ -4,11 +4,11 @@ export interface PipelineRun {
duplicationPercentages: number[];
}
export interface Ra {
interface Ra {
[key: string]: string[];
}
export type EvaluationStrategy =
type EvaluationStrategy =
| "COMPUTE_SIMPLE"
| "COMPUTE_RECURSIVE"
| "IN_LAYER"
@@ -58,30 +58,30 @@ export interface InLayer extends ResultEventBase {
predicateIterationMillis: number[];
}
export interface ComputedExtensional extends ResultEventBase {
interface ComputedExtensional extends ResultEventBase {
evaluationStrategy: "COMPUTED_EXTENSIONAL";
queryCausingWork?: string;
}
export interface NonComputedExtensional extends ResultEventBase {
interface NonComputedExtensional extends ResultEventBase {
evaluationStrategy: "EXTENSIONAL";
queryCausingWork?: string;
}
export interface SentinelEmpty extends SummaryEventBase {
interface SentinelEmpty extends SummaryEventBase {
evaluationStrategy: "SENTINEL_EMPTY";
sentinelRaHash: string;
}
export interface Cachaca extends ResultEventBase {
interface Cachaca extends ResultEventBase {
evaluationStrategy: "CACHACA";
}
export interface CacheHit extends ResultEventBase {
interface CacheHit extends ResultEventBase {
evaluationStrategy: "CACHE_HIT";
}
export type Extensional = ComputedExtensional | NonComputedExtensional;
type Extensional = ComputedExtensional | NonComputedExtensional;
export type SummaryEvent =
| ComputeSimple

View File

@@ -12,7 +12,7 @@ export interface PipelineInfo {
/**
* Location information for a single predicate in the RA.
*/
export interface PredicateSymbol {
interface PredicateSymbol {
/**
* `PipelineInfo` for each iteration. A non-recursive predicate will have a single iteration `0`.
*/

View File

@@ -10,7 +10,7 @@ import { EOL } from "os";
import { containsPath } from "../common/files";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
export interface QueryPack {
interface QueryPack {
path: string;
language: QueryLanguage | undefined;
}

View File

@@ -36,7 +36,6 @@ import {
} from "./query-status";
import { readQueryHistoryFromFile, writeQueryHistoryToFile } from "./store";
import { pathExists } from "fs-extra";
import { CliVersionConstraint } from "../codeql-cli/cli";
import { HistoryItemLabelProvider } from "./history-item-label-provider";
import { ResultsView, WebviewReveal } from "../local-queries";
import { EvalLogTreeBuilder, EvalLogViewer } from "../query-evaluation-logging";
@@ -95,7 +94,7 @@ const SHOW_QUERY_TEXT_QUICK_EVAL_MSG = `\
`;
export enum SortOrder {
enum SortOrder {
NameAsc = "NameAsc",
NameDesc = "NameDesc",
DateAsc = "DateAsc",
@@ -760,7 +759,7 @@ export class QueryHistoryManager extends DisposableObject {
private warnNoEvalLogs() {
void showAndLogWarningMessage(
this.app.logger,
`Evaluator log, summary, and viewer are not available for this run. Perhaps it failed before evaluation, or you are running with a version of CodeQL before ' + ${CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG}?`,
`Evaluator log, summary, and viewer are not available for this run. Perhaps it failed before evaluation?`,
);
}
@@ -953,8 +952,7 @@ export class QueryHistoryManager extends DisposableObject {
return;
}
await this.app.commands.execute(
"codeQL.copyVariantAnalysisRepoList",
await this.variantAnalysisManager.copyRepoListToClipboard(
item.variantAnalysis.id,
);
}

View File

@@ -1,4 +1,4 @@
import { pathExists, stat, remove, readFile } from "fs-extra";
import { pathExists, remove, readFile } from "fs-extra";
import { EOL } from "os";
import { join } from "path";
import { Disposable, ExtensionContext } from "vscode";
@@ -6,6 +6,7 @@ import { extLogger } from "../common/logging/vscode";
import { readDirFullPaths } from "../common/files";
import { QueryHistoryDirs } from "./query-history-dirs";
import { QueryHistoryManager } from "./query-history-manager";
import { getErrorMessage } from "../common/helpers-pure";
const LAST_SCRUB_TIME_KEY = "lastScrubTime";
@@ -132,46 +133,55 @@ async function scrubDirectory(
errorMsg?: string;
deleted: boolean;
}> {
const timestampFile = join(dir, "timestamp");
try {
let deleted = true;
if (!(await stat(dir)).isDirectory()) {
void extLogger.log(` ${dir} is not a directory. Deleting.`);
await remove(dir);
} else if (!(await pathExists(timestampFile))) {
void extLogger.log(` ${dir} has no timestamp file. Deleting.`);
await remove(dir);
} else if (!(await stat(timestampFile)).isFile()) {
void extLogger.log(` ${timestampFile} is not a file. Deleting.`);
if (await shouldScrubDirectory(dir, now, maxQueryTime)) {
await remove(dir);
return { deleted: true };
} else {
const timestampText = await readFile(timestampFile, "utf8");
const timestamp = parseInt(timestampText, 10);
if (Number.isNaN(timestamp)) {
void extLogger.log(
` ${dir} has invalid timestamp '${timestampText}'. Deleting.`,
);
await remove(dir);
} else if (now - timestamp > maxQueryTime) {
void extLogger.log(
` ${dir} is older than ${maxQueryTime / 1000} seconds. Deleting.`,
);
await remove(dir);
} else {
void extLogger.log(
` ${dir} is not older than ${maxQueryTime / 1000} seconds. Keeping.`,
);
deleted = false;
}
return { deleted: false };
}
return {
deleted,
};
} catch (err) {
return {
errorMsg: ` Could not delete '${dir}': ${err}`,
errorMsg: ` Could not delete '${dir}': ${getErrorMessage(err)}`,
deleted: false,
};
}
}
async function shouldScrubDirectory(
dir: string,
now: number,
maxQueryTime: number,
): Promise<boolean> {
const timestamp = await getTimestamp(join(dir, "timestamp"));
if (timestamp === undefined || Number.isNaN(timestamp)) {
void extLogger.log(` ${dir} timestamp is missing or invalid. Deleting.`);
return true;
} else if (now - timestamp > maxQueryTime) {
void extLogger.log(
` ${dir} is older than ${maxQueryTime / 1000} seconds. Deleting.`,
);
return true;
} else {
void extLogger.log(
` ${dir} is not older than ${maxQueryTime / 1000} seconds. Keeping.`,
);
return false;
}
}
async function getTimestamp(
timestampFile: string,
): Promise<number | undefined> {
try {
const timestampText = await readFile(timestampFile, "utf8");
return parseInt(timestampText, 10);
} catch (err) {
void extLogger.log(
` Could not read timestamp file '${timestampFile}': ${getErrorMessage(
err,
)}`,
);
return undefined;
}
}

View File

@@ -146,22 +146,11 @@ export class QueryServerClient extends DisposableObject {
args.push("--require-db-registration");
if (!(await this.cliServer.cliConstraints.supportsPerQueryEvalLog())) {
args.push("--old-eval-stats");
}
const structuredLogFile = `${this.opts.contextStoragePath}/structured-evaluator-log.json`;
await ensureFile(structuredLogFile);
if (await this.cliServer.cliConstraints.supportsStructuredEvalLog()) {
const structuredLogFile = `${this.opts.contextStoragePath}/structured-evaluator-log.json`;
await ensureFile(structuredLogFile);
args.push("--evaluator-log");
args.push(structuredLogFile);
// We hard-code the verbosity level to 5 and minify to false.
// This will be the behavior of the per-query structured logging in the CLI after 2.8.3.
args.push("--evaluator-log-level");
args.push("5");
}
args.push("--evaluator-log");
args.push(structuredLogFile);
if (this.config.debug) {
args.push("--debug", "--tuple-counting");

View File

@@ -129,10 +129,7 @@ async function runQuery(
dbDir: dbContents.datasetUri.fsPath,
workingSet: "default",
};
if (
generateEvalLog &&
(await qs.cliServer.cliConstraints.supportsPerQueryEvalLog())
) {
if (generateEvalLog) {
await qs.sendRequest(messages.startLog, {
db: dataset,
logPath: outputDir.evalLogPath,
@@ -149,10 +146,7 @@ async function runQuery(
await qs.sendRequest(messages.runQueries, params, token, progress);
} finally {
qs.unRegisterCallback(callbackId);
if (
generateEvalLog &&
(await qs.cliServer.cliConstraints.supportsPerQueryEvalLog())
) {
if (generateEvalLog) {
await qs.sendRequest(messages.endLog, {
db: dataset,
logPath: outputDir.evalLogPath,

View File

@@ -194,11 +194,6 @@ export class QueryServerClient extends DisposableObject {
args.push("--evaluator-log");
args.push(structuredLogFile);
// We hard-code the verbosity level to 5 and minify to false.
// This will be the behavior of the per-query structured logging in the CLI after 2.8.3.
args.push("--evaluator-log-level");
args.push("5");
if (this.config.debug) {
args.push("--debug", "--tuple-counting");
}

View File

@@ -1,4 +1,4 @@
import { dirname, extname } from "path";
import { extname } from "path";
import * as vscode from "vscode";
import {
TestAdapter,
@@ -41,14 +41,6 @@ export function getActualFile(testPath: string): string {
return getTestOutputFile(testPath, ".actual");
}
/**
* Get the directory containing the specified QL test.
* @param testPath The full path to the test file.
*/
export function getTestDirectory(testPath: string): string {
return dirname(testPath);
}
/**
* Gets the the full path to a particular output file of the specified QL test.
* @param testPath The full path to the QL test.

View File

@@ -7,7 +7,7 @@ import { basename } from "path";
import { App } from "../common/app";
import { TestTreeNode } from "./test-tree-node";
export type TestNode = TestTreeNode | TestItem;
type TestNode = TestTreeNode | TestItem;
/**
* Base class for both the legacy and new test services. Implements commands that are common to

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
@@ -16,9 +16,9 @@ export default {
</VariantAnalysisContainer>
),
],
} as ComponentMeta<typeof Alert>;
} as Meta<typeof Alert>;
const Template: ComponentStory<typeof Alert> = (args) => <Alert {...args} />;
const Template: StoryFn<typeof Alert> = (args) => <Alert {...args} />;
export const Warning = Template.bind({});
Warning.args = {

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { CodePaths } from "../../view/common";
import type { CodeFlow } from "../../variant-analysis/shared/analysis-result";
@@ -9,11 +9,9 @@ export default {
title: "Code Paths",
component: CodePaths,
decorators: [(Story) => <Story />],
} as ComponentMeta<typeof CodePaths>;
} as Meta<typeof CodePaths>;
const Template: ComponentStory<typeof CodePaths> = (args) => (
<CodePaths {...args} />
);
const Template: StoryFn<typeof CodePaths> = (args) => <CodePaths {...args} />;
export const PowerShell = Template.bind({});

View File

@@ -1,15 +1,15 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { FileCodeSnippet } from "../../view/common";
export default {
title: "File Code Snippet",
component: FileCodeSnippet,
} as ComponentMeta<typeof FileCodeSnippet>;
} as Meta<typeof FileCodeSnippet>;
const Template: ComponentStory<typeof FileCodeSnippet> = (args) => (
const Template: StoryFn<typeof FileCodeSnippet> = (args) => (
<FileCodeSnippet {...args} />
);

View File

@@ -1,20 +0,0 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { LastUpdated as LastUpdatedComponent } from "../../view/common/LastUpdated";
export default {
title: "Last Updated",
component: LastUpdatedComponent,
} as ComponentMeta<typeof LastUpdatedComponent>;
const Template: ComponentStory<typeof LastUpdatedComponent> = (args) => (
<LastUpdatedComponent {...args} />
);
export const LastUpdated = Template.bind({});
LastUpdated.args = {
lastUpdated: new Date(Date.now() - 3_600_000).toISOString(), // 1 hour ago
};

View File

@@ -1,15 +1,15 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import StarCountComponent from "../../view/common/StarCount";
export default {
title: "Star Count",
component: StarCountComponent,
} as ComponentMeta<typeof StarCountComponent>;
} as Meta<typeof StarCountComponent>;
const Template: ComponentStory<typeof StarCountComponent> = (args) => (
const Template: StoryFn<typeof StarCountComponent> = (args) => (
<StarCountComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import TextButtonComponent from "../../view/common/TextButton";
@@ -15,9 +15,9 @@ export default {
},
},
},
} as ComponentMeta<typeof TextButtonComponent>;
} as Meta<typeof TextButtonComponent>;
const Template: ComponentStory<typeof TextButtonComponent> = (args) => (
const Template: StoryFn<typeof TextButtonComponent> = (args) => (
<TextButtonComponent {...args} />
);

View File

@@ -1,8 +1,8 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { CodePaths, Codicon as CodiconComponent } from "../../../view/common";
import { Codicon as CodiconComponent } from "../../../view/common";
// To regenerate the icons, use the following command from the `extensions/ql-vscode` directory:
// jq -R '[inputs | [splits(", *")] as $row | $row[0]]' < node_modules/@vscode/codicons/dist/codicon.csv > src/stories/common/icon/vscode-icons.json
@@ -17,9 +17,9 @@ export default {
options: icons,
},
},
} as ComponentMeta<typeof CodePaths>;
} as Meta<typeof CodiconComponent>;
const Template: ComponentStory<typeof CodiconComponent> = (args) => (
const Template: StoryFn<typeof CodiconComponent> = (args) => (
<CodiconComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import {
CodePaths,
@@ -10,9 +10,9 @@ import {
export default {
title: "Icon/Error Icon",
component: ErrorIconComponent,
} as ComponentMeta<typeof CodePaths>;
} as Meta<typeof CodePaths>;
const Template: ComponentStory<typeof ErrorIconComponent> = (args) => (
const Template: StoryFn<typeof ErrorIconComponent> = (args) => (
<ErrorIconComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import {
CodePaths,
@@ -10,9 +10,9 @@ import {
export default {
title: "Icon/Success Icon",
component: SuccessIconComponent,
} as ComponentMeta<typeof CodePaths>;
} as Meta<typeof CodePaths>;
const Template: ComponentStory<typeof SuccessIconComponent> = (args) => (
const Template: StoryFn<typeof SuccessIconComponent> = (args) => (
<SuccessIconComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import {
CodePaths,
@@ -10,9 +10,9 @@ import {
export default {
title: "Icon/Warning Icon",
component: WarningIconComponent,
} as ComponentMeta<typeof CodePaths>;
} as Meta<typeof CodePaths>;
const Template: ComponentStory<typeof WarningIconComponent> = (args) => (
const Template: StoryFn<typeof WarningIconComponent> = (args) => (
<WarningIconComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { Mode } from "../../data-extensions-editor/shared/mode";
import { DataExtensionsEditor as DataExtensionsEditorComponent } from "../../view/data-extensions-editor/DataExtensionsEditor";
@@ -9,11 +9,11 @@ import { CallClassification } from "../../data-extensions-editor/external-api-us
export default {
title: "Data Extensions Editor/Data Extensions Editor",
component: DataExtensionsEditorComponent,
} as ComponentMeta<typeof DataExtensionsEditorComponent>;
} as Meta<typeof DataExtensionsEditorComponent>;
const Template: ComponentStory<typeof DataExtensionsEditorComponent> = (
args,
) => <DataExtensionsEditorComponent {...args} />;
const Template: StoryFn<typeof DataExtensionsEditorComponent> = (args) => (
<DataExtensionsEditorComponent {...args} />
);
export const DataExtensionsEditor = Template.bind({});
DataExtensionsEditor.args = {
@@ -24,6 +24,7 @@ DataExtensionsEditor.args = {
"/home/user/vscode-codeql-starter/codeql-custom-queries-java/sql2o/codeql-pack.yml",
name: "codeql/sql2o-models",
version: "0.0.0",
language: "java",
extensionTargets: {},
dataExtensions: [],
},

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { MethodRow as MethodRowComponent } from "../../view/data-extensions-editor/MethodRow";
import { CallClassification } from "../../data-extensions-editor/external-api-usage";
@@ -8,9 +8,9 @@ import { CallClassification } from "../../data-extensions-editor/external-api-us
export default {
title: "Data Extensions Editor/Method Row",
component: MethodRowComponent,
} as ComponentMeta<typeof MethodRowComponent>;
} as Meta<typeof MethodRowComponent>;
const Template: ComponentStory<typeof MethodRowComponent> = (args) => (
const Template: StoryFn<typeof MethodRowComponent> = (args) => (
<MethodRowComponent {...args} />
);

View File

@@ -1,15 +1,15 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { DataFlowPaths as DataFlowPathsComponent } from "../../view/data-flow-paths/DataFlowPaths";
import { createMockDataFlowPaths } from "../../../test/factories/variant-analysis/shared/data-flow-paths";
export default {
title: "Data Flow Paths/Data Flow Paths",
component: DataFlowPathsComponent,
} as ComponentMeta<typeof DataFlowPathsComponent>;
} as Meta<typeof DataFlowPathsComponent>;
const Template: ComponentStory<typeof DataFlowPathsComponent> = (args) => (
const Template: StoryFn<typeof DataFlowPathsComponent> = (args) => (
<DataFlowPathsComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import AnalysisAlertResult from "../../view/variant-analysis/AnalysisAlertResult";
import type { AnalysisAlert } from "../../variant-analysis/shared/analysis-result";
@@ -8,9 +8,9 @@ import type { AnalysisAlert } from "../../variant-analysis/shared/analysis-resul
export default {
title: "Variant Analysis/Analysis Alert Result",
component: AnalysisAlertResult,
} as ComponentMeta<typeof AnalysisAlertResult>;
} as Meta<typeof AnalysisAlertResult>;
const Template: ComponentStory<typeof AnalysisAlertResult> = (args) => (
const Template: StoryFn<typeof AnalysisAlertResult> = (args) => (
<AnalysisAlertResult {...args} />
);

View File

@@ -1,15 +1,15 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisFailureReason } from "../../variant-analysis/shared/variant-analysis";
import { FailureReasonAlert } from "../../view/variant-analysis/FailureReasonAlert";
export default {
title: "Variant Analysis/Failure reason alert",
component: FailureReasonAlert,
} as ComponentMeta<typeof FailureReasonAlert>;
} as Meta<typeof FailureReasonAlert>;
const Template: ComponentStory<typeof FailureReasonAlert> = (args) => (
const Template: StoryFn<typeof FailureReasonAlert> = (args) => (
<FailureReasonAlert {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { QueryDetails as QueryDetailsComponent } from "../../view/variant-analysis/QueryDetails";
@@ -29,9 +29,9 @@ export default {
},
},
},
} as ComponentMeta<typeof QueryDetailsComponent>;
} as Meta<typeof QueryDetailsComponent>;
const Template: ComponentStory<typeof QueryDetailsComponent> = (args) => (
const Template: StoryFn<typeof QueryDetailsComponent> = (args) => (
<QueryDetailsComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import {
@@ -27,9 +27,9 @@ export default {
</VariantAnalysisContainer>
),
],
} as ComponentMeta<typeof RepoRow>;
} as Meta<typeof RepoRow>;
const Template: ComponentStory<typeof RepoRow> = (args: RepoRowProps) => (
const Template: StoryFn<typeof RepoRow> = (args: RepoRowProps) => (
<RepoRow {...args} />
);

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import { useState } from "react";
import { ComponentMeta } from "@storybook/react";
import { Meta } from "@storybook/react";
import { RepositoriesFilter as RepositoriesFilterComponent } from "../../view/variant-analysis/RepositoriesFilter";
import { FilterKey } from "../../variant-analysis/shared/variant-analysis-filter-sort";
@@ -16,7 +16,7 @@ export default {
},
},
},
} as ComponentMeta<typeof RepositoriesFilterComponent>;
} as Meta<typeof RepositoriesFilterComponent>;
export const RepositoriesFilter = () => {
const [value, setValue] = useState(FilterKey.All);

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import { useState } from "react";
import { ComponentMeta } from "@storybook/react";
import { Meta } from "@storybook/react";
import { RepositoriesSearch as RepositoriesSearchComponent } from "../../view/variant-analysis/RepositoriesSearch";
@@ -15,7 +15,7 @@ export default {
},
},
},
} as ComponentMeta<typeof RepositoriesSearchComponent>;
} as Meta<typeof RepositoriesSearchComponent>;
export const RepositoriesSearch = () => {
const [value, setValue] = useState("");

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import { useState } from "react";
import { ComponentMeta } from "@storybook/react";
import { Meta } from "@storybook/react";
import { RepositoriesSearchSortRow as RepositoriesSearchSortRowComponent } from "../../view/variant-analysis/RepositoriesSearchSortRow";
import { defaultFilterSortState } from "../../variant-analysis/shared/variant-analysis-filter-sort";
@@ -16,7 +16,7 @@ export default {
},
},
},
} as ComponentMeta<typeof RepositoriesSearchSortRowComponent>;
} as Meta<typeof RepositoriesSearchSortRowComponent>;
export const RepositoriesSearchSortRow = () => {
const [value, setValue] = useState(defaultFilterSortState);

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import { useState } from "react";
import { ComponentMeta } from "@storybook/react";
import { Meta } from "@storybook/react";
import { RepositoriesSort as RepositoriesSortComponent } from "../../view/variant-analysis/RepositoriesSort";
import { SortKey } from "../../variant-analysis/shared/variant-analysis-filter-sort";
@@ -16,7 +16,7 @@ export default {
},
},
},
} as ComponentMeta<typeof RepositoriesSortComponent>;
} as Meta<typeof RepositoriesSortComponent>;
export const RepositoriesSort = () => {
const [value, setValue] = useState(SortKey.Alphabetically);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysis as VariantAnalysisComponent } from "../../view/variant-analysis/VariantAnalysis";
import {
@@ -18,9 +18,9 @@ import { createMockRepositoryWithMetadata } from "../../../test/factories/varian
export default {
title: "Variant Analysis/Variant Analysis",
component: VariantAnalysisComponent,
} as ComponentMeta<typeof VariantAnalysisComponent>;
} as Meta<typeof VariantAnalysisComponent>;
const Template: ComponentStory<typeof VariantAnalysisComponent> = (args) => (
const Template: StoryFn<typeof VariantAnalysisComponent> = (args) => (
<VariantAnalysisComponent {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisStatus } from "../../variant-analysis/shared/variant-analysis";
@@ -36,9 +36,9 @@ export default {
},
},
},
} as ComponentMeta<typeof VariantAnalysisActions>;
} as Meta<typeof VariantAnalysisActions>;
const Template: ComponentStory<typeof VariantAnalysisActions> = (args) => (
const Template: StoryFn<typeof VariantAnalysisActions> = (args) => (
<VariantAnalysisActions {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { faker } from "@faker-js/faker";
@@ -28,11 +28,11 @@ export default {
</VariantAnalysisContainer>
),
],
} as ComponentMeta<typeof VariantAnalysisAnalyzedRepos>;
} as Meta<typeof VariantAnalysisAnalyzedRepos>;
const Template: ComponentStory<typeof VariantAnalysisAnalyzedRepos> = (
args,
) => <VariantAnalysisAnalyzedRepos {...args} />;
const Template: StoryFn<typeof VariantAnalysisAnalyzedRepos> = (args) => (
<VariantAnalysisAnalyzedRepos {...args} />
);
const interpretedResultsForRepo = (
nwo: string,

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisHeader } from "../../view/variant-analysis/VariantAnalysisHeader";
@@ -59,9 +59,9 @@ export default {
},
},
},
} as ComponentMeta<typeof VariantAnalysisHeader>;
} as Meta<typeof VariantAnalysisHeader>;
const Template: ComponentStory<typeof VariantAnalysisHeader> = (args) => (
const Template: StoryFn<typeof VariantAnalysisHeader> = (args) => (
<VariantAnalysisHeader {...args} />
);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisLoading as VariantAnalysisLoadingComponent } from "../../view/variant-analysis/VariantAnalysisLoading";
@@ -16,9 +16,9 @@ export default {
),
],
argTypes: {},
} as ComponentMeta<typeof VariantAnalysisLoadingComponent>;
} as Meta<typeof VariantAnalysisLoadingComponent>;
const Template: ComponentStory<typeof VariantAnalysisLoadingComponent> = () => (
const Template: StoryFn<typeof VariantAnalysisLoadingComponent> = () => (
<VariantAnalysisLoadingComponent />
);

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import { useState } from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisOutcomePanels } from "../../view/variant-analysis/VariantAnalysisOutcomePanels";
@@ -27,11 +27,9 @@ export default {
</VariantAnalysisContainer>
),
],
} as ComponentMeta<typeof VariantAnalysisOutcomePanels>;
} as Meta<typeof VariantAnalysisOutcomePanels>;
const Template: ComponentStory<typeof VariantAnalysisOutcomePanels> = (
args,
) => {
const Template: StoryFn<typeof VariantAnalysisOutcomePanels> = (args) => {
const [filterSortState, setFilterSortState] =
useState<RepositoriesFilterSortState>(defaultFilterSortState);

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentMeta, ComponentStory } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisSkippedRepositoriesTab } from "../../view/variant-analysis/VariantAnalysisSkippedRepositoriesTab";
@@ -16,9 +16,9 @@ export default {
</VariantAnalysisContainer>
),
],
} as ComponentMeta<typeof VariantAnalysisSkippedRepositoriesTab>;
} as Meta<typeof VariantAnalysisSkippedRepositoriesTab>;
const Template: ComponentStory<typeof VariantAnalysisSkippedRepositoriesTab> = (
const Template: StoryFn<typeof VariantAnalysisSkippedRepositoriesTab> = (
args,
) => <VariantAnalysisSkippedRepositoriesTab {...args} />;

View File

@@ -1,6 +1,6 @@
import * as React from "react";
import { ComponentStory, ComponentMeta } from "@storybook/react";
import { Meta, StoryFn } from "@storybook/react";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisStats } from "../../view/variant-analysis/VariantAnalysisStats";
@@ -24,9 +24,9 @@ export default {
},
},
},
} as ComponentMeta<typeof VariantAnalysisStats>;
} as Meta<typeof VariantAnalysisStats>;
const Template: ComponentStory<typeof VariantAnalysisStats> = (args) => (
const Template: StoryFn<typeof VariantAnalysisStats> = (args) => (
<VariantAnalysisStats {...args} />
);

Some files were not shown because too many files have changed in this diff Show More