-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use yaml
package when selecting build configs
#351
Conversation
src/commands/openYAMLConfigFile.ts
Outdated
// The range returned from the `yaml` package doesn't include newlines | ||
// So count newlines and include them in the range we return | ||
for (const char of configDocumentText.slice(0, buildConfigOffset)) { | ||
newlines += char === '\n' ? 1 : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be another way to do this without the for-loop.
Will, you might have already looked at this, but wondering if we can use this method instead?
eemeli/yaml#127 (comment)
Also, should we track this issue? In case there is an improvement from the yaml side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion - now this is using only the yaml
package to get ranges. I don't think we need to track the issue though. From the looks of it they've already rejected the feature request to include newline counts in ranges
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally only okay with disabling lint on a per-line basis. In this case, we can just fix the lint problems instead of disabling them - see suggestions
src/commands/openYAMLConfigFile.ts
Outdated
type YamlNode = YAMLMap | YAMLSeq | Pair | undefined; | ||
const yamlNodes: YamlNode[] = []; | ||
let yamlNode: YamlNode = parsedYaml.get('jobs'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to hard-code "jobs" if we just use the root "contents"
type YamlNode = YAMLMap | YAMLSeq | Pair | undefined; | |
const yamlNodes: YamlNode[] = []; | |
let yamlNode: YamlNode = parsedYaml.get('jobs'); | |
type YamlNode = YAMLMap | YAMLSeq | Pair | Scalar | undefined | null; | |
const yamlNodes: YamlNode[] = []; | |
let yamlNode: YamlNode = parsedYaml.contents; |
src/commands/openYAMLConfigFile.ts
Outdated
if (yamlNode.hasOwnProperty('key') && yamlNode['key'].value === buildConfigToSelect && yamlNode.hasOwnProperty('value')) { | ||
const configValue = <Scalar>yamlNode['value']; | ||
const range = <number[] | undefined>configValue.range; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing lint errors
if (yamlNode.hasOwnProperty('key') && yamlNode['key'].value === buildConfigToSelect && yamlNode.hasOwnProperty('value')) { | |
const configValue = <Scalar>yamlNode['value']; | |
const range = <number[] | undefined>configValue.range; | |
if ('key' in yamlNode && (<Scalar>yamlNode.key).value === buildConfigToSelect && 'value' in yamlNode) { | |
const configValue = <Scalar>yamlNode.value; | |
const range = configValue.range; |
src/commands/openYAMLConfigFile.ts
Outdated
} else if (yamlNode.hasOwnProperty('items')) { | ||
yamlNodes.push(...yamlNode['items']) | ||
} else if (yamlNode.hasOwnProperty('value') && yamlNode['value'].hasOwnProperty('items')) { | ||
yamlNodes.push(...yamlNode['value']['items']) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing lint errors and seems easier to pop yamlNode.value
onto the queue rather than dig into items
in multiple places
} else if (yamlNode.hasOwnProperty('items')) { | |
yamlNodes.push(...yamlNode['items']) | |
} else if (yamlNode.hasOwnProperty('value') && yamlNode['value'].hasOwnProperty('items')) { | |
yamlNodes.push(...yamlNode['value']['items']) | |
} | |
} else if ('items' in yamlNode) { | |
yamlNodes.push(...yamlNode.items); | |
} else if ('value' in yamlNode && typeof yamlNode.value === 'object') { | |
yamlNodes.push(yamlNode.value) | |
} |
src/commands/openYAMLConfigFile.ts
Outdated
async function getSelection(configDocument: TextDocument, buildConfigToSelect: BuildConfig): Promise<Range | undefined> { | ||
const configRegex: RegExp = new RegExp(`${buildConfigToSelect}:`); | ||
/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, no-prototype-builtins, @typescript-eslint/no-unsafe-assignment */ | ||
export async function getSelection(configDocument: TextDocument, buildConfigToSelect: BuildConfig): Promise<Range | undefined> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the code is a bit complex and has some sketchy "any" types, I'd probably rename this to tryGetSelection
and add a big try/catch that just returns undefined
if an error happens. This function already allows | undefined
in the return type anyways
test/selectBuildConfigs.test.ts
Outdated
const workspacePath: string = getWorkspacePath('testWorkspace'); | ||
|
||
test(title, async () => { | ||
const configDocument: TextDocument = await workspace.openTextDocument(join(workspacePath, 'testWorkflows', testCase.workflowFileName)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than use separate yml files in the "testWorkflows" directory, I'd prefer you just put the test data in this file (like, as a const
), for a few reasons:
- Using the file system and/or VS Code APIs can slow tests down. It's worth it for end-to-end tests, but overkill for unit tests IMO
- You can easily manipulate the test data with template literals and whatnot
- Idk just seems easier to read when the test data is in the same file.
I feel like the only downside is this file can get pretty long, but it just doesn't bother me 🤷♂️. One way to help with that is to scope your test data down to smaller cases. For example, you might have one test running against an "actual" yml file seen in the wild, but the other tests are usually just testing specific edge cases without the full "yml" file necessary.
yaml
package when selecting build configs
test/selectBuildConfigs.test.ts
Outdated
interface ISelectBuildConfigTestCase { | ||
workflowIndex: number; | ||
buildConfig: BuildConfig; | ||
expectedSelection: undefined | { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't think I've ever seen anyone list undefined first in a | type haha
test/selectBuildConfigs.test.ts
Outdated
expectedSelection = new Range(expectedStart, expectedEnd); | ||
} | ||
|
||
assert.ok(expectedSelection && selection?.isEqual(expectedSelection) || selection === expectedSelection, 'Actual and expected selections do not match'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to use assert.strictEquals()
here. Using assert.ok
seems kind of roundabout here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with assert.ok
because comparing two ranges uses their isEqual()
function. I updated the assert to hopefully make it look more purposeful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, okay, makse sense.
azure_static_web_apps_api_token: $\{{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_ROCK_0D992521E }} | ||
action: "close" | ||
|
||
`]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we try location paths with special characters and maybe some foreign characters? (Chinese or Korean or something seems plausible)
Yaml values without quotes are supported now as well:
Fixes #349