Skip to content

Commit

Permalink
Refactor readConfigFile
Browse files Browse the repository at this point in the history
  • Loading branch information
matz3 committed Mar 17, 2020
1 parent 0a46217 commit 2a66684
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 150 deletions.
70 changes: 43 additions & 27 deletions lib/projectPreprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class ProjectPreprocessor {
// Currently, specVersion is the indicator for configured projects

// Validate project config, but exclude additional properties
// TODO: Also exclude _level
const excludedProperties = ["id", "version", "path", "dependencies"];
const entries = Object.entries(project).filter(([key]) => {
return !excludedProperties.includes(key);
Expand All @@ -213,25 +214,7 @@ class ProjectPreprocessor {
return {};
}

let configs;

// A projects configPath property takes precedence over the default "<projectPath>/ui5.yaml" path
const configPath = project.configPath || path.join(project.path, "/ui5.yaml");
try {
configs = await this.readConfigFile(configPath);
} catch (err) {
if (err.name === "ValidationError") {
throw err;
}

const errorText = "Failed to read configuration for project " +
`${project.id} at "${configPath}". Error: ${err.message}`;

if (err.code !== "ENOENT") { // Something else than "File or directory does not exist"
throw new Error(errorText);
}
log.verbose(errorText);
}
const configs = await this.readConfigFile(project);

if (!configs || !configs.length) {
return {};
Expand Down Expand Up @@ -298,7 +281,11 @@ class ProjectPreprocessor {
return false; // ignore this project
}

if (project.specVersion !== "0.1" && project.specVersion !== "1.0" && project.specVersion !== "1.1") {
if (project.specVersion !== "0.1" &&
project.specVersion !== "1.0" &&
project.specVersion !== "1.1" &&
project.specVersion !== "2.0"
) {
throw new Error(
`Unsupported specification version ${project.specVersion} defined for project ` +
`${project.id}. Your UI5 CLI installation might be outdated. ` +
Expand Down Expand Up @@ -372,7 +359,8 @@ class ProjectPreprocessor {
throw new Error(`No specification version defined for extension ${extension.metadata.name}`);
} else if (extension.specVersion !== "0.1" &&
extension.specVersion !== "1.0" &&
extension.specVersion !== "1.1") {
extension.specVersion !== "1.1" &&
extension.specVersion !== "2.0") {
throw new Error(
`Unsupported specification version ${extension.specVersion} defined for extension ` +
`${extension.metadata.name}. Your UI5 CLI installation might be outdated. ` +
Expand Down Expand Up @@ -401,11 +389,39 @@ class ProjectPreprocessor {
}
}

async readConfigFile(configPath) {
const configFile = await readFile(configPath, {encoding: "utf8"});
const configs = parseYaml(configFile, {
filename: path
});
async readConfigFile(project) {
const configPath = project.configPath || path.join(project.path, "ui5.yaml");
let configFile;
try {
configFile = await readFile(configPath, {encoding: "utf8"});
} catch (err) {
const errorText = "Failed to read configuration for project " +
`${project.id} at "${configPath}". Error: ${err.message}`;

// Something else than "File or directory does not exist" or root project
if (err.code !== "ENOENT" /* || project._level === 0 TODO: check again */ ) {
throw new Error(errorText);
} else {
log.verbose(errorText);
return null;
}
}

let configs;

try {
configs = parseYaml(configFile, {
filename: configPath
});
} catch (err) {
const errorText = "Failed to parse configuration for project " +
`${project.id} at "${configPath}". Error: ${err.message}`;
if (err.name === "YAMLException") {
throw new Error(errorText);
} else {
throw err;
}
}

if (!configs || !configs.length) {
return configs;
Expand All @@ -415,7 +431,7 @@ class ProjectPreprocessor {
configs.map((config, documentIndex) => validate({
config,
project: {
id: "TODO"
id: project.id
},
yaml: {
path: configPath,
Expand Down
21 changes: 12 additions & 9 deletions lib/schema/ValidationError.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class ValidationError extends Error {
}

static analyzeYamlError({error, yaml}) {
if (!error.dataPath) {
throw new Error("TODO: no dataPath");
if (error.keyword === "required") {
return {line: -1, column: -1};
}

// Skip leading /
Expand All @@ -82,7 +82,7 @@ class ValidationError extends Error {
const propertyRegExp = new RegExp(`^[^#]*?${escapeStringRegExp(property)}`, "m");
const propertyMatch = propertyRegExp.exec(currentSubstring);
if (!propertyMatch) {
throw new Error(`Unable to find "${property}" within yaml:\n${yaml.source.substr(currentIndex)}`);
return {line: -1, column: -1};
}
newIndex = propertyMatch.index + propertyMatch[0].length;
} else {
Expand All @@ -94,7 +94,7 @@ class ValidationError extends Error {
for (const match of arrayIndicators) {
const indentationMatch = match[2].match(/([ ]*)-/);
if (!indentationMatch) {
throw new Error("Unable to find indentation!");
return {line: -1, column: -1};
}
const currentIndentation = indentationMatch[1].length;
if (firstIndentation === -1) {
Expand All @@ -110,7 +110,8 @@ class ValidationError extends Error {
a++;
}
if (!newIndex) {
throw new Error("Could not find array element!");
// Could not find array element
return {line: -1, column: -1};
}
}
currentIndex += newIndex;
Expand Down Expand Up @@ -158,10 +159,12 @@ class ValidationError extends Error {

static getYamlExtract({error, yaml}) {
const {line, column} = ValidationError.analyzeYamlError({error, yaml});
const sourceExtract = ValidationError.getSourceExtract(yaml.source, line, column);
return chalk.grey(yaml.path + ":" + line) +
"\n\n" +
sourceExtract;
if (line !== -1 && column !== -1) {
return chalk.grey(yaml.path + ":" + line) +
"\n\n" + ValidationError.getSourceExtract(yaml.source, line, column);
} else {
return chalk.grey(yaml.path) + "\n";
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions test/lib/projectPreprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,7 @@ metadata:
const preprocessor = new projectPreprocessor._ProjectPreprocessor({});

await t.notThrowsAsync(async () => {
await preprocessor.readConfigFile(configPath);
await preprocessor.readConfigFile({path: "/application", id: "id"});
});

t.is(validateSpy.callCount, 1, "validate should be called once");
Expand All @@ -2045,7 +2045,7 @@ metadata:
}
},
project: {
id: "TODO",
id: "id",
},
yaml: {
documentIndex: 0,
Expand Down Expand Up @@ -2080,7 +2080,7 @@ metadata:
const preprocessor = new projectPreprocessor._ProjectPreprocessor({});

await t.throwsAsync(async () => {
await preprocessor.readConfigFile(configPath);
await preprocessor.readConfigFile({path: "/application", id: "id"});
}, {
instanceOf: ValidationError,
name: "ValidationError"
Expand All @@ -2096,7 +2096,7 @@ metadata:
}
},
project: {
id: "TODO",
id: "id",
},
yaml: {
documentIndex: 0,
Expand Down
Loading

0 comments on commit 2a66684

Please sign in to comment.