in server/src/server.ts [160:309]
function runLinter(document: TextDocument): void {
let uri = document.uri;
if (isRunningLinterOn[uri]) {
connection.sendNotification('cfn/busy');
return;
}
let file_to_lint = URI.parse(uri).fsPath;
let is_cfn = isCloudFormation(document.getText(), uri.toString());
connection.sendNotification('cfn/isPreviewable', is_cfn);
let build_graph = isPreviewing[uri];
if (is_cfn) {
let args = ['--format', 'json'];
if (build_graph) {
args.push('--build-graph');
}
if (IgnoreRules.length > 0) {
for (var ignoreRule of IgnoreRules) {
args.push('--ignore-checks');
args.push(ignoreRule);
}
}
if (AppendRules.length > 0) {
for (var appendRule of AppendRules) {
args.push('--append-rules');
args.push(appendRule);
}
}
if (OverrideSpecPath !== "") {
args.push('--override-spec', OverrideSpecPath);
}
args.push('--', `"${file_to_lint}"`);
connection.console.log(`Running... ${Path} ${args}`);
isRunningLinterOn[uri] = true;
let child = spawn(
Path,
args,
{
cwd: workspaceRoot,
shell: true
}
);
let diagnostics: Diagnostic[] = [];
let filename = uri.toString();
let start = 0;
let end = Number.MAX_VALUE;
child.on('error', function (err) {
let errorMessage = `Unable to start cfn-lint (${err}). Is cfn-lint installed correctly?`;
connection.console.log(errorMessage);
let lineNumber = 0;
let diagnostic: Diagnostic = {
range: {
start: { line: lineNumber, character: start },
end: { line: lineNumber, character: end }
},
severity: DiagnosticSeverity.Error,
message: '[cfn-lint] ' + errorMessage
};
diagnostics.push(diagnostic);
return;
});
child.stderr.on("data", (data: Buffer) => {
let err = data.toString();
connection.console.log(err);
let lineNumber = 0;
let diagnostic: Diagnostic = {
range: {
start: { line: lineNumber, character: start },
end: { line: lineNumber, character: end }
},
severity: DiagnosticSeverity.Warning,
message: '[cfn-lint] ' + err + '\nGo to https://github.com/aws-cloudformation/cfn-python-lint/#install for more help'
};
diagnostics.push(diagnostic);
return;
});
let stdout = "";
child.stdout.on("data", (data: Buffer) => {
stdout = stdout.concat(data.toString());
});
child.on('exit', function (code, signal) {
connection.console.log('child process exited with ' +
`code ${code} and signal ${signal}`);
let tmp = stdout.toString();
let obj;
try {
obj = JSON.parse(tmp);
} catch (err) {
let lineNumber = 0;
let diagnostic: Diagnostic = {
range: {
start: { line: lineNumber, character: start },
end: { line: lineNumber, character: end }
},
severity: DiagnosticSeverity.Warning,
message: '[cfn-lint] ' + err + '\nGo to https://github.com/aws-cloudformation/cfn-python-lint/#install for more help'
};
diagnostics.push(diagnostic);
return;
}
for (let element of obj) {
let lineNumber = (Number.parseInt(element.Location.Start.LineNumber) - 1);
let columnNumber = (Number.parseInt(element.Location.Start.ColumnNumber) - 1);
let lineNumberEnd = (Number.parseInt(element.Location.End.LineNumber) - 1);
let columnNumberEnd = (Number.parseInt(element.Location.End.ColumnNumber) - 1);
let diagnostic: Diagnostic = {
range: {
start: { line: lineNumber, character: columnNumber },
end: { line: lineNumberEnd, character: columnNumberEnd }
},
severity: convertSeverity(element.Level),
message: '[cfn-lint] ' + element.Rule.Id + ': ' + element.Message
};
diagnostics.push(diagnostic);
};
});
child.on("close", () => {
//connection.console.log(`Validation finished for(code:${code}): ${Files.uriToFilePath(uri)}`);
connection.sendDiagnostics({ uri: filename, diagnostics });
isRunningLinterOn[uri] = false;
if (build_graph) {
connection.console.log('preview file is available');
connection.sendNotification('cfn/previewIsAvailable', uri);
}
});
} else {
connection.console.log("Don't believe this is a CloudFormation template. " + uri.toString() +
". If it is please add AWSTemplateFormatVersion: '2010-09-09' (YAML) or " +
" \"AWSTemplateFormatVersion\": \"2010-09-09\" (JSON) into the root level of the document.");
}
}