-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cc39469
Showing
9 changed files
with
1,289 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#! /usr/bin/env node | ||
|
||
const { parse } = require("./parse.js") | ||
const { readFileSync } = require("fs") | ||
const path = require("path") | ||
|
||
const file = process.argv[2] | ||
const src = readFileSync(file, "utf8") | ||
|
||
function checkDependencyReferences(donTree) { | ||
const undefinedDependencies = [ | ||
// { | ||
// target: "target", | ||
// dependency: "dep", | ||
// } | ||
] | ||
|
||
for (const [target, commands] of Object.entries(donTree)) { | ||
for (const command of commands) { | ||
if (command.type === "dependency") { | ||
for (const dep of command.dependencies) { | ||
if (!donTree.hasOwnProperty(dep)) { | ||
undefinedDependencies.push({ | ||
target, | ||
dependency: dep, | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return undefinedDependencies | ||
} | ||
|
||
function checkCircular(donTree, target, commands, stack = new Set()) { | ||
let commandNum = 0 | ||
|
||
for (const command of commands) { | ||
commandNum++ | ||
|
||
if (command.type === "dependency") { | ||
for (const depName of command.dependencies) { | ||
let depDepth = stack.size | ||
const dependencyStack = new Set(stack) | ||
|
||
dependencyStack.add(depName) | ||
|
||
if (dependencyStack.size === depDepth + 1) { | ||
// No circular reference for this dep, check further dependencies | ||
return checkCircular(donTree, target, donTree[depName], dependencyStack) | ||
} else { | ||
// Found circular reference | ||
return { | ||
target, | ||
via: Array.from(dependencyStack).slice(-1)[0], | ||
dependency: depName, | ||
commandNumber: commandNum, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return null | ||
} | ||
|
||
const absFile = path.resolve(__dirname, file) | ||
|
||
try { | ||
const parsed = parse(src) | ||
|
||
// Check for undefined dependencies | ||
let undefinedDependencies = checkDependencyReferences(parsed) | ||
|
||
if (undefinedDependencies.length) { | ||
console.error(absFile + "\nError:\n") | ||
|
||
for (const undep of undefinedDependencies) { | ||
console.error(` Target "${ undep.target }" references undefined dependency "${ undep.dependency }"`) | ||
} | ||
|
||
process.exit(1) | ||
} | ||
|
||
let circularDeps = [] | ||
|
||
for (const [target, commands] of Object.entries(parsed)) { | ||
const targetCircularDeps = checkCircular(parsed, target, commands, new Set([target])) | ||
|
||
if (targetCircularDeps) { | ||
circularDeps.push(targetCircularDeps) | ||
} | ||
} | ||
|
||
if (circularDeps.length) { | ||
console.error(absFile + "\nError:") | ||
|
||
for (const cirdep of circularDeps) { | ||
console.error(` Target "${ cirdep.target }" has circular dependency "${ cirdep.dependency }" via its dependency "${ cirdep.via }" on command ${ cirdep.commandNumber }`) | ||
} | ||
|
||
process.exit(1) | ||
} | ||
|
||
console.log(JSON.stringify(parsed, null, 4)) | ||
} catch(e) { | ||
const loc = e.location.start | ||
console.error(`${ absFile }:${ loc.line }:${ loc.column }\n${ e.name }: ${ e.message }`) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
{ | ||
function text_val(array) { | ||
return typeof array === "string" ? array : array.flat().join("") | ||
} | ||
} | ||
|
||
start | ||
= targets_arr:( tgt:target nl { return tgt } ) + { | ||
const targets = {} | ||
|
||
for (const target of targets_arr) { | ||
targets[target.name] = target.commands | ||
} | ||
|
||
return targets | ||
} | ||
|
||
target | ||
= tn:target_name ":" is nl | ||
commands:( ( command / command_dependency ) + ) { return { name: tn, commands } } | ||
|
||
command | ||
= main_ci:command_indent "- " ! ( "$" target_name ) cs:command_string nl | ||
multil_str:( multil_ci:command_indent ! "- " multil_cs:command_string nl { | ||
if (multil_ci === main_ci + " ") { | ||
const multiline_begin = multil_cs.slice(0, 2) | ||
|
||
if (multiline_begin !== "- " && multiline_begin !== "-") { | ||
return " " + multil_cs | ||
} else { | ||
return expected("Multi line commands can't start with a single hyphen, consider quoting the single hyphen") | ||
} | ||
} else { | ||
return expected("multi-line indent matching first line of command") | ||
} | ||
} | ||
) * { | ||
return { | ||
type: "command", | ||
command: text_val(cs) + text_val(multil_str), | ||
} | ||
} | ||
|
||
command_dependency | ||
= main_ci:command_indent "- " cs:dependency_string nl { | ||
return { | ||
type: "dependency", | ||
dependencies: cs, | ||
} | ||
} | ||
|
||
command_indent | ||
= " " " " * { return text() } | ||
|
||
target_name | ||
= [a-z0-9_-]i + { return text() } | ||
|
||
command_string | ||
= [^\n] + { return text() } | ||
|
||
dependency_string | ||
= "$" name:target_name is right:dependency_string { return [name].concat(right) } | ||
/ "$" name:target_name is { return [name] } | ||
|
||
// Inline space | ||
is | ||
= " " * { return text() } | ||
|
||
// White space | ||
ws | ||
= [ \n] + { return text() } | ||
|
||
// Newline | ||
nl | ||
= "\n" | ||
/ "\r\n" | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"name": "don", | ||
"version": "1.0.0", | ||
"description": "Make and YAML inspired build tool", | ||
"main": "don.js", | ||
"scripts": { | ||
"test": "node ./don.js test.don", | ||
"build": "pegjs -o parse.js don.pegjs" | ||
}, | ||
"keywords": [ | ||
"build", | ||
"tool", | ||
"javascript" | ||
], | ||
"author": "b-fuze", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"pegjs": "^0.10.0" | ||
} | ||
} |
Oops, something went wrong.