Skip to content
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

new: Support raw templates for code generation. #982

Merged
merged 5 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion crates/cli/src/commands/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,13 @@ pub async fn generate(name: String, options: GenerateOptions) -> AppResult {
FileState::Replace => color::muted("->"),
_ => color::muted("-->"),
},
color::muted_light(relative_dest.join(file.name).as_str())
color::muted_light(
file.dest_path
.strip_prefix(&cwd)
.unwrap_or(&file.dest_path)
.to_str()
.unwrap()
)
))?;
}

Expand Down
14 changes: 14 additions & 0 deletions crates/cli/tests/generate_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ fn renders_with_custom_vars_via_args() {
assert_snapshot!(fs::read_to_string(sandbox.path().join("./test/control.txt")).unwrap());
}

#[test]
fn handles_raw_files() {
let sandbox = generate_sandbox();

let assert = sandbox.run_moon(|cmd| {
cmd.arg("generate").arg("standard").arg("./test");
});

assert.success();

assert_snapshot!(fs::read_to_string(sandbox.path().join("./test/file.txt")).unwrap());
assert_snapshot!(fs::read_to_string(sandbox.path().join("./test/other.txt")).unwrap());
}

#[test]
fn interpolates_destination_path() {
let sandbox = generate_sandbox();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
source: crates/cli/tests/generate_test.rs
assertion_line: 56
expression: get_path_safe_output(&assert)
expression: assert.output_standardized()
---

Template title (dry run)
Some description of the template and its files.


created --> ./test/file.ts
created --> ./test/file.txt
created --> ./test/folder/nested-file.ts
created --> test/file.ts
created --> test/file.txt
created --> test/folder/nested-file.ts
created --> test/other.txt



Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
source: crates/cli/tests/generate_test.rs
assertion_line: 37
expression: get_path_safe_output(&assert)
expression: assert.output_standardized()
---

Template title
Some description of the template and its files.


created --> ./test/file.ts
created --> ./test/file.txt
created --> ./test/folder/nested-file.ts
created --> test/file.ts
created --> test/file.txt
created --> test/folder/nested-file.ts
created --> test/other.txt



Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
source: crates/cli/tests/generate_test.rs
expression: "fs::read_to_string(sandbox.path().join(\"./test/other.txt\")).unwrap()"
---
{% set my_var = 2 %}
{{ my_var }}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: crates/cli/tests/generate_test.rs
expression: "fs::read_to_string(sandbox.path().join(\"./test/file.txt\")).unwrap()"
---
2

Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
---
source: crates/cli/tests/generate_test.rs
assertion_line: 174
expression: get_path_safe_output(&assert)
expression: assert.output_standardized()
---

Variable testing
A template for testing all variable config combinations.


created --> ./test/control.txt
created --> ./test/expressions.txt
created --> ./test/file-default-0.txt
created --> ./test/filters.txt
created --> test/control.txt
created --> test/expressions.txt
created --> test/file-default-0.txt
created --> test/filters.txt



Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
source: crates/cli/tests/generate_test.rs
assertion_line: 81
expression: get_path_safe_output(&assert)
expression: assert.output_standardized()
---

Template title
Some description of the template and its files.


replaced -> ./test/file.ts
replaced -> ./test/file.txt
replaced -> ./test/folder/nested-file.ts
replaced -> test/file.ts
replaced -> test/file.txt
replaced -> test/folder/nested-file.ts
replaced -> test/other.txt



Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
---
source: crates/cli/tests/generate_test.rs
assertion_line: 108
expression: get_path_safe_output(&assert)
expression: assert.output_standardized()
---

Variable testing
A template for testing all variable config combinations.


replaced -> ./test/control.txt
replaced -> ./test/expressions.txt
replaced -> ./test/file-default-0.txt
replaced -> ./test/filters.txt
replaced -> test/control.txt
replaced -> test/expressions.txt
replaced -> test/file-default-0.txt
replaced -> test/filters.txt



4 changes: 2 additions & 2 deletions crates/core/archive/tests/tree_differ_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ fn loads_all_files() {
let sandbox = create_sandbox("generator");
let differ = TreeDiffer::load(sandbox.path(), &string_vec!["templates"]).unwrap();

assert_eq!(differ.files.len(), 21);
assert_eq!(differ.files.len(), 22);
}

#[test]
fn loads_using_globs() {
let sandbox = create_sandbox("generator");
let differ = TreeDiffer::load(sandbox.path(), &string_vec!["templates/**/*"]).unwrap();

assert_eq!(differ.files.len(), 21);
assert_eq!(differ.files.len(), 22);
}

#[test]
Expand Down
16 changes: 10 additions & 6 deletions nextgen/codegen/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,16 @@ impl Template {
// Do a second pass and render the content
for file in &mut files {
file.set_content(
self.engine
.render(file.name.as_str(), context)
.map_err(|error| CodegenError::RenderTemplateFileFailed {
path: file.source_path.clone(),
error,
})?,
if file.raw {
fs::read_file(&file.source_path)?
} else {
self.engine
.render(file.name.as_str(), context)
.map_err(|error| CodegenError::RenderTemplateFileFailed {
path: file.source_path.clone(),
error,
})?
},
dest,
)?;
}
Expand Down
10 changes: 9 additions & 1 deletion nextgen/codegen/src/template_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub struct TemplateFile {
/// Relative path from templates dir. Also acts as the Tera engine name.
pub name: RelativePathBuf,

/// Whether the file should not be rendered.
pub raw: bool,

/// Absolute path to source (in templates dir).
pub source_path: PathBuf,

Expand All @@ -35,6 +38,7 @@ pub struct TemplateFile {
impl TemplateFile {
pub fn new(name: RelativePathBuf, source_path: PathBuf) -> Self {
TemplateFile {
raw: name.as_str().contains(".raw"),
config: None,
content: String::new(),
dest_path: PathBuf::new(),
Expand Down Expand Up @@ -73,7 +77,11 @@ impl TemplateFile {
pub fn set_content<T: AsRef<str>>(&mut self, content: T, dest: &Path) -> miette::Result<()> {
let content = content.as_ref().trim_start();

self.dest_path = self.name.to_path(dest);
self.dest_path = if self.raw {
dest.join(self.name.as_str().replace(".raw", ""))
} else {
self.name.to_path(dest)
};

if content.starts_with("---") {
debug!(
Expand Down
2 changes: 2 additions & 0 deletions nextgen/codegen/tests/__fixtures__/template/file.raw.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% set my_var = 2 %}
{{ my_var }}
3 changes: 2 additions & 1 deletion nextgen/codegen/tests/__fixtures__/template/file.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
content
{% set my_var = 2 %}
{{ my_var }}
28 changes: 28 additions & 0 deletions nextgen/codegen/tests/template_file_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ use std::path::PathBuf;
mod template_file {
use super::*;

#[test]
fn marks_as_raw() {
let template = TemplateFile::new(RelativePathBuf::from("file.raw.txt"), PathBuf::new());

assert!(template.raw);

let template = TemplateFile::new(RelativePathBuf::from("file.raw"), PathBuf::new());

assert!(template.raw);

let template = TemplateFile::new(RelativePathBuf::from("file.txt.raw"), PathBuf::new());

assert!(template.raw);
}

mod mergeable {
use super::*;

Expand Down Expand Up @@ -56,6 +71,19 @@ mod template_file {
template
}

#[test]
fn removes_raw_from_path() {
let mut template =
TemplateFile::new(RelativePathBuf::from("file.raw.js"), PathBuf::new());
template
.set_content("{{ foo }}", &PathBuf::from("root"))
.unwrap();

assert_eq!(template.content, "{{ foo }}");
assert_eq!(template.config, None);
assert_eq!(template.dest_path, PathBuf::from("root/file.js"));
}

#[test]
fn sets_no_frontmatter() {
let template = create_file_with_content("export {};");
Expand Down
29 changes: 28 additions & 1 deletion nextgen/codegen/tests/template_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mod template {
.map(|f| f.source_path)
.collect::<Vec<_>>(),
vec![
fixture.join("file.raw.txt"),
fixture.join("file.ts"),
fixture.join("file.txt"),
fixture.join("folder/nested-file.ts")
Expand All @@ -61,6 +62,7 @@ mod template {
assert_eq!(
files,
vec![
"file.raw.txt",
"file.ts",
"file.txt",
"folder/nested-file.ts",
Expand All @@ -76,7 +78,7 @@ mod template {

template.load_files(&fixture, &create_context()).unwrap();

let file = &template.files[0];
let file = template.files.iter().find(|f| f.name == "file.ts").unwrap();

assert_eq!(file.content, "export {};\n");
assert_eq!(
Expand All @@ -86,6 +88,31 @@ mod template {
..TemplateFrontmatterConfig::default()
})
);

let file = template
.files
.iter()
.find(|f| f.name == "file.txt")
.unwrap();

assert_eq!(file.content, "2\n");
assert_eq!(file.config, None);
}

#[test]
fn doesnt_render_raw_files() {
let mut template = create_template();
let fixture = locate_fixture("template");

template.load_files(&fixture, &create_context()).unwrap();

let file = template
.files
.iter()
.find(|f| f.name == "file.raw.txt")
.unwrap();

assert_eq!(file.content, "{% set my_var = 2 %}\n{{ my_var }}\n");
}

#[test]
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#### 🚀 Updates

- Identifiers (project names, file groups, etc) can now be prefixed with underscores (`_`).
- **Codegen**
- Templates can be used as-is without rendering with [Tera](https://tera.netlify.app) by appending
a `.raw` extension.

#### 🐞 Fixes

Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/generator/templates/standard/file.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
content
{% set my_var = 2 %}
{{ my_var }}
2 changes: 2 additions & 0 deletions tests/fixtures/generator/templates/standard/other.raw.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% set my_var = 2 %}
{{ my_var }}
10 changes: 10 additions & 0 deletions website/docs/guides/codegen.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ toc_max_heading_level: 6
tags: [codegen, generator, scaffold, template]
---

import VersionLabel from '@site/src/components/Docs/VersionLabel';

Code generation provides an easy mechanism for automating common development workflows and file
structures. Whether it's scaffolding a new library or application, updating configuration, or
standardizing patterns.
Expand Down Expand Up @@ -88,6 +90,14 @@ be generated into the target destination, and _do not_ support frontmatter.
To ensure they are not generated, include the word "partial" anywhere in the file path. For example,
`partials/header.tpl` or `header.partial.tpl`.

#### Raws<VersionLabel version="1.11.0" />

Raw template files are another special type of file that bypass all Tera rendering, and are used
as-is instead. This is useful for files that contain syntax that conflicts with Tera.

To mark a file as raw, add a `.raw` extension, for example: `file.raw.js` or `file.js.raw`. When the
file is generated, the `.raw` extension will be removed.

#### Frontmatter

Frontmatter is a well-known concept for "per file configuration", and is achieved by inserting YAML
Expand Down