Skip to content

Commit a40d571

Browse files
author
Adedoyin Ogunjobi
committed
add feature to prevent invalid tunables
changes to scripts.js dont let users save invalud key or value move tunables.json and add feature Document allowed tunables and error handling Added section on allowed tunables and their validation process. Exclude tunables.json from RAT and prettier documentation + more tunables + verifiy values
1 parent 7c99986 commit a40d571

7 files changed

Lines changed: 278 additions & 11 deletions

File tree

constants/tunables.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"allowExpressionResultCoercion": "boolean",
3+
"allowExternalPathExpressions": "boolean",
4+
"allowSignedIntegerLength1Bit": "boolean",
5+
6+
"blobChunkSizeInBytes": "number",
7+
8+
"defaultEmptyElementParsePolicy": "string",
9+
10+
"escalateWarningsToErrors": "boolean",
11+
12+
"generatedNamespacePrefixStem": "string",
13+
14+
"initialElementOccurrencesHint": "number",
15+
"initialRegexMatchLimitInCharacters": "number",
16+
17+
"infosetWalkerSkipMin": "number",
18+
"infosetWalkerSkipMax": "number",
19+
20+
"invalidRestrictionPolicy": {
21+
"type": "enum",
22+
"values": ["error", "ignore", "validate"]
23+
},
24+
25+
"maxBinaryDecimalVirtualPoint": "number",
26+
"maxByteArrayOutputStreamBufferSizeInBytes": "number",
27+
"maxDataDumpSizeInBytes": "number",
28+
"maxHexBinaryLengthInBytes": "number",
29+
30+
"maxLengthForVariableLengthDelimiterDisplay": "number",
31+
"maxLookaheadFunctionBits": "number",
32+
33+
"maxOccursBounds": "number",
34+
35+
"maxSkipLengthInBytes": "number",
36+
37+
"maxValidYear": "number",
38+
39+
"maximumRegexMatchLengthInCharacters": "number",
40+
"maximumSimpleElementSizeInCharacters": "number",
41+
42+
"minBinaryDecimalVirtualPoint": "number",
43+
"minValidYear": "number",
44+
45+
"outputStreamChunkSizeInBytes": "number",
46+
47+
"parseUnparsePolicy": "string",
48+
49+
"releaseUnneededInfoset": "boolean",
50+
51+
"requireBitOrderProperty": "boolean",
52+
"requireEmptyElementParsePolicyProperty": "boolean",
53+
54+
"requireEncodingErrorPolicyProperty": "boolean",
55+
"requireFloatingProperty": "boolean",
56+
"requireTextBidiProperty": "boolean",
57+
"requireTextStandardBaseProperty": "boolean",
58+
59+
"saxUnparseEventBatchSize": "number",
60+
61+
"suppressSchemaDefinitionWarnings": "string",
62+
63+
"tempFilePath": "string",
64+
65+
"unqualifiedPathStepPolicy": {
66+
"type": "enum",
67+
"values": [
68+
"noNamespace",
69+
"defaultNamespace",
70+
"preferDefaultNamespace"
71+
]
72+
},
73+
74+
"unparseSuspensionWaitOld": "number",
75+
"unparseSuspensionWaitYoung": "number"
76+
}

doc/Wiki.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,23 @@ Tunables are configured using **Key** and **Value** fields in the launch configu
372372

373373
Use the **“+ Add Tunable”** button to add additional entries. Each row can be removed using the **“X”** button.
374374

375+
Tunables are case sensitive, and only allowed tunables will be allowed to be saved in the wizard.
376+
375377
Tunables control runtime behavior and performance characteristics. Most tunables have default values, so you only need to specify a value if you want to override them.
376378

377379
<img width="790" height="176" alt="tunables_gui" src="https://github.com/user-attachments/assets/f78d5471-bfff-4cfb-b6cf-62c787a8e31b" />
378380

379381
<img width="360" height="177" alt="tunables_launchjson" src="https://github.com/user-attachments/assets/0d70044d-d04c-4f47-958c-175c6e67f3f9" />
380382

383+
### List of allowed Tunables
384+
385+
In order to prevent unexpected tunables from being ran, there is a list of allowed tunables at `constants/tunables.json` which contains all valid tunables. Tunables are case sensitive and the values type must match what is expected. For example boolean values will only allow true or false. If a invalid tunable is saved in the `launch.json` , when you attempt to run daffodil you will encounter a error saying `Cancel` or `Ignore invalid tunable`. Cancel will send you back where you fix the error, and Ignore invalid tunable runs daffodil but does not register the invalid tunable. The tunable will stay in your launch.json however. The tunables.json file will be updated as new tunables are added and removed.
386+
387+
The validation for tunable values is reasonably loose to allow for possibly unknown tunables to be applied. For example suppressSchemaDefinitionWarnings documentation didn't explicitly list all the possible values, but unqualifiedPathStepPolicy explicitly stated the allowed values so only those values are allowing.
388+
389+
<img width="914" height="718" alt="image" src="https://github.com/user-attachments/assets/22b24b29-de7e-4ec9-b012-85fe8f1bb54c" />
390+
391+
381392
### Reference
382393
- https://daffodil.apache.org/tunables/
383394

project/Rat.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ object Rat {
5252
file("build/package/NOLICENSE"),
5353
file("build/package/NONOTICE"),
5454
file("src/tests/data/test.txt"),
55+
file("constants/tunables.json"),
5556
file("debugger/src/test/data/emptyData.xml"),
5657
file("debugger/src/test/data/emptyInfoset.xml"),
5758
file("debugger/src/test/data/notInfoset.xml"),

src/adapter/activateDaffodilDebug.ts

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as rootCompletion from '../rootCompletion'
1818
import { tmpdir } from 'os'
1919
import JSZip from 'jszip'
2020
import { rm } from 'node:fs/promises'
21+
import { getTunables } from './extension'
2122

2223
import {
2324
CancellationToken,
@@ -766,16 +767,15 @@ class DaffodilConfigurationProvider
766767
constructor(context: vscode.ExtensionContext) {
767768
this.context = context
768769
}
769-
770770
/**
771771
* Massage a debug configuration just before a debug session is being launched,
772772
* e.g. add all missing attributes to the debug configuration.
773773
*/
774-
resolveDebugConfiguration(
774+
async resolveDebugConfiguration(
775775
folder: WorkspaceFolder | undefined,
776776
config: DebugConfiguration,
777777
token?: CancellationToken
778-
): ProviderResult<DebugConfiguration> {
778+
): Promise<DebugConfiguration | undefined> {
779779
// if launch.json is missing or empty
780780
if (!config.type && !config.request && !config.name) {
781781
config = getConfig({ name: 'Launch', request: 'launch', type: 'dfdl' })
@@ -791,6 +791,62 @@ class DaffodilConfigurationProvider
791791
data: config.data || '${command:AskForDataName}',
792792
}
793793

794+
const validTunables = getTunables(this.context)
795+
const currentTunables = config.tunables ?? {}
796+
797+
const invalidTunables = Object.keys(currentTunables).filter(
798+
(name) => !(name in validTunables)
799+
)
800+
801+
const invalidValues = Object.entries(currentTunables)
802+
.filter(([name, value]) => {
803+
if (!(name in validTunables)) {
804+
return false
805+
}
806+
807+
const type = validTunables[name]
808+
809+
switch (type) {
810+
case 'boolean':
811+
return value !== 'true' && value !== 'false'
812+
813+
case 'number':
814+
return isNaN(Number(value))
815+
816+
case 'string':
817+
return typeof value !== 'string'
818+
819+
default:
820+
return false
821+
}
822+
})
823+
.map(([name]) => name)
824+
825+
const invalid = [...invalidTunables, ...invalidValues]
826+
827+
if (invalid.length > 0) {
828+
const messages = [
829+
...invalidTunables.map((name) => `${name} (invalid tunable)`),
830+
...invalidValues.map((name) => `${name} (invalid value)`),
831+
]
832+
833+
const choice = await vscode.window.showWarningMessage(
834+
`Invalid tunables found:\n\n${messages.join('\n')}`,
835+
{ modal: true },
836+
'Ignore Invalid Tunables'
837+
)
838+
839+
if (choice !== 'Ignore Invalid Tunables') {
840+
return undefined
841+
}
842+
843+
config.tunables = { ...config.tunables }
844+
845+
for (const invalidTunable of invalid) {
846+
delete config.tunables[invalidTunable]
847+
}
848+
}
849+
794850
let dataFolder = config.data
795851

796852
if (

src/adapter/extension.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import * as vscode from 'vscode'
2121
import * as position from '../position'
22+
import * as fs from 'fs'
23+
import * as path from 'path'
2224
import { ProviderResult } from 'vscode'
2325
import { DaffodilDebugSession } from './daffodilDebug'
2426
import {
@@ -45,6 +47,17 @@ export function deactivate() {
4547
position.deactivate()
4648
}
4749

50+
export function getTunables(
51+
context: vscode.ExtensionContext
52+
): Record<string, string> {
53+
const file = path.join(context.extensionPath, 'constants', 'tunables.json')
54+
55+
const data = fs.readFileSync(file, 'utf8')
56+
const json = JSON.parse(data)
57+
58+
return json
59+
}
60+
4861
export class InlineDebugAdapterFactory
4962
implements vscode.DebugAdapterDescriptorFactory
5063
{

src/launchWizard/launchWizard.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { DFDLDebugger } from '../classes/dfdlDebugger'
2222
import { VSCodeLaunchConfigArgs } from '../classes/vscode-launch'
2323
import { DataEditorConfig } from '../classes/dataEditor'
2424
import { parse as jsoncParse } from 'jsonc-parser'
25+
import * as path from 'path'
2526

2627
let launchWizard: LaunchWizard | undefined
2728

@@ -279,6 +280,20 @@ async function createWizard(ctx: vscode.ExtensionContext) {
279280
let panel = launchWiz.getPanel()
280281
panel.webview.html = launchWiz.getWebViewContent()
281282

283+
//Read in list of valid
284+
285+
const tunablesPath = path.join(
286+
ctx.extensionPath,
287+
'constants',
288+
'tunables.json'
289+
)
290+
291+
const tunables = JSON.parse(fs.readFileSync(tunablesPath, 'utf8'))
292+
panel.webview.postMessage({
293+
command: 'loadTunables',
294+
tunables: tunables,
295+
})
296+
282297
panel.webview.onDidReceiveMessage(
283298
async (message) => {
284299
switch (message.command) {
@@ -782,6 +797,11 @@ class LaunchWizard {
782797
<p class="setting-description">Key/value configuration options</p>
783798
784799
<table style="width: 100%; border-collapse: collapse; margin-top: 5px;">
800+
<style>
801+
td {
802+
vertical-align: top;
803+
}
804+
</style>
785805
<thead>
786806
<tr>
787807
<th style="text-align: left;">Key</th>

0 commit comments

Comments
 (0)