Skip to content

Commit

Permalink
Allow nancy to write to stdout when output is a single file
Browse files Browse the repository at this point in the history
  • Loading branch information
rrthomas committed Oct 30, 2024
1 parent abf0dad commit bedf66c
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 19 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ A simple templating system.
positional arguments:
INPUT-PATH list of input directories, or a single file
OUTPUT output directory, or file
OUTPUT output directory, or file ('-' for stdout)
optional arguments:
-h, --help show this help message and exit
Expand Down Expand Up @@ -71,6 +71,10 @@ convenient to expand a single file using the command:

`nancy INPUT-FILE OUTPUT-FILE`

Also, when the output is a single file, the special filename `-` may be used
to cause Nancy to print the result to standard output instead of writing it
to a file.

For each directory in the input tree, Nancy creates a corresponding
directory, if it does not already exist.

Expand Down
4 changes: 4 additions & 0 deletions README.nancy.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ convenient to expand a single file using the command:

`nancy INPUT-FILE OUTPUT-FILE`

Also, when the output is a single file, the special filename `-` may be used
to cause Nancy to print the result to standard output instead of writing it
to a file.

For each directory in the input tree, Nancy creates a corresponding
directory, if it does not already exist.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@sc3d/nancy",
"description": "Simple templating system",
"version": "7.3.1",
"version": "7.4.0",
"author": "Reuben Thomas",
"bin": {
"nancy": "bin/run.js"
Expand Down
2 changes: 1 addition & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const parser = new ArgumentParser({
+ 'are merged in left-to-right order.',
})
parser.add_argument('input', {metavar: 'INPUT-PATH', help: 'list of input directories, or a single file'})
parser.add_argument('output', {metavar: 'OUTPUT', help: 'output directory, or file'})
parser.add_argument('output', {metavar: 'OUTPUT', help: "output directory, or file ('-' for stdout)"})
parser.add_argument('--path', {help: "path to build relative to input tree [default: '']"})
parser.add_argument('--version', {
action: 'version',
Expand Down
16 changes: 14 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,18 @@ export function expand(inputs: string[], outputPath: string, buildPath = ''): vo
debug(`Processing file '${filePath}'`)
if (templateRegex.exec(filePath)) {
debug(`Expanding '${baseFile}' to '${outputFile}'`)
fs.writeFileSync(outputFile, expandFile(baseFile, filePath))
const output = expandFile(baseFile, filePath)
if (outputFile === '-') {
process.stdout.write(output)
} else {
fs.writeFileSync(outputFile, output)
}
} else if (!noCopyRegex.exec(filePath)) {
fs.copyFileSync(filePath, outputFile)
if (outputFile === '-') {
process.stdout.write(fs.readFileSync(filePath))
} else {
fs.copyFileSync(filePath, outputFile)
}
}
}

Expand All @@ -244,6 +253,9 @@ export function expand(inputs: string[], outputPath: string, buildPath = ''): vo
}
if (isDirectory(dirent)) {
const outputDir = getOutputPath(object)
if (outputDir === '-') {
throw new Error("cannot output multiple files to stdout ('-')")
}
debug(`Entering directory '${object}'`)
fs.ensureDirSync(outputDir)
for (const childDirent of dirent) {
Expand Down
61 changes: 47 additions & 14 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,40 +28,65 @@ function assertFileObjEqual(obj: string, expected: string) {
)
}

function test(inputDirs: string[], expected: string, buildPath?: string) {
const outputDir = temporaryDirectory()
const outputObj = path.join(outputDir, 'output')
function test(inputDirs: string[], expected: string, buildPath?: string, outputDir?: string) {
let tmpDir
let outputObj
if (outputDir === undefined) {
tmpDir = temporaryDirectory()
outputObj = path.join(tmpDir, 'output')
} else {
outputObj = outputDir
}
if (buildPath !== undefined) {
expand(inputDirs, outputObj, buildPath)
} else {
expand(inputDirs, outputObj)
}
assertFileObjEqual(outputObj, expected)
fs.rmSync(outputDir, {recursive: true})
if (tmpDir !== undefined) {
fs.rmSync(tmpDir, {recursive: true})
}
}

function failingTest(inputDirs: string[], expected: string, buildPath?: string) {
const outputDir = temporaryDirectory()
function failingTest(
inputDirs: string[],
expected: string,
buildPath?: string,
outputDir?: string,
) {
const expectedDir = temporaryDirectory()
try {
test(inputDirs, outputDir, buildPath)
test(inputDirs, expectedDir, buildPath, outputDir)
} catch (error: any) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect(error.message).to.contain(expected)
return
} finally {
fs.rmSync(outputDir, {recursive: true})
fs.rmSync(expectedDir, {recursive: true})
}
throw new Error('test passed unexpectedly')
}

async function cliTest(args: string[], expected: string) {
const outputDir = temporaryDirectory()
const outputObj = path.join(outputDir, 'output')
async function cliTest(args: string[], expected: string, outputDir?: string) {
let tmpDir
let outputObj
if (outputDir === undefined) {
tmpDir = temporaryDirectory()
outputObj = path.join(tmpDir, 'output')
} else {
outputObj = outputDir
}
try {
await run(args.concat(outputObj))
assertFileObjEqual(outputObj, expected)
const res = await run(args.concat(outputObj))
if (tmpDir !== undefined) {
assertFileObjEqual(outputObj, expected)
} else {
expect(res.stdout).to.equal(fs.readFileSync(expected, 'utf-8'))
}
} finally {
fs.rmSync(outputDir, {recursive: true})
if (tmpDir !== undefined) {
fs.rmSync(tmpDir, {recursive: true})
}
}
}

Expand Down Expand Up @@ -192,6 +217,10 @@ describe('nancy', function t() {
failingTest([process.cwd()], 'missing close brace', 'missing-close-brace.nancy.txt')
})

it('Trying to output multiple files to stdout should cause an error', async () => {
failingTest(['webpage-src'], 'cannot output multiple files to stdout', undefined, '-')
})

// CLI tests
it('--help should produce output', async () => {
const proc = run(['--help'])
Expand All @@ -203,6 +232,10 @@ describe('nancy', function t() {
await cliTest(['file-root-relative-include.nancy.txt'], 'file-root-relative-include-expected.txt')
})

it('Output to stdout of a single file should work', async () => {
await cliTest(['file-root-relative-include.nancy.txt'], 'file-root-relative-include-expected.txt', '-')
})

it('Missing command-line argument should cause an error', async () => {
await failingCliTest([], 'the following arguments are required')
})
Expand Down

0 comments on commit bedf66c

Please sign in to comment.