--- a/Cargo.lock +++ b/Cargo.lock @@ -156,6 +156,16 @@ ] [[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] name = "bumpalo" version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -453,6 +463,19 @@ ] [[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -548,9 +571,11 @@ checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" dependencies = [ "console", + "globset", "once_cell", "similar", "tempfile", + "walkdir", ] [[package]] @@ -797,6 +822,12 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] name = "logos" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1157,6 +1188,15 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "saphyr-parser-bw" version = "0.0.607" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1491,6 +1531,16 @@ ] [[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1545,6 +1595,15 @@ ] [[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ # Parsing, manifestification is implemented manually everywhere serde = "1.0.228" serde_json = "1.0.149" -serde-saphyr = {version = "0.0.17", default-features = false} +serde-saphyr = { version = "0.0.17", default-features = false } # Error handling anyhow = "1.0.101" @@ -63,7 +63,7 @@ mimallocator = "0.1.3" indoc = "2.0" -insta = "1.46" +insta = { version = "1.46", features = ["glob"] } tempfile = "3.24" pathdiff = "0.2.3" hashbrown = "0.16.1" --- a/crates/jrsonnet-formatter/src/lib.rs +++ b/crates/jrsonnet-formatter/src/lib.rs @@ -13,7 +13,7 @@ Arg, ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart, DestructRest, Expr, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal, Member, Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix, Text, - UnaryOperator, Visibility, + TextKind, UnaryOperator, Visibility, }, AstNode, AstToken as _, SyntaxToken, }; @@ -25,7 +25,6 @@ mod children; mod comments; -#[cfg(test)] mod tests; fn with_indent_eoi(cond: ConditionResolver, o: PrintItems, e: EndingComments) -> PrintItems { @@ -200,6 +199,18 @@ impl Printable for Text { fn print(&self, out: &mut PrintItems) { + if matches!(self.kind(), TextKind::StringBlock) { + let text = self.text(); + + for (i, ele) in text.split("\n").enumerate() { + if i != 0 { + p!(out, nl); + } + // TODO: Trim and recreate whitespace + p!(out, string(ele.to_string())); + } + return; + } p!(out, string(format!("{}", self))); } } --- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__args.snap +++ /dev/null @@ -1,36 +0,0 @@ ---- -source: crates/jrsonnet-formatter/src/tests.rs -expression: "reformat(indoc!(\"\n\t\t\t{\n\t\t\t\tshort: aaa(1,2,3,4,5),\n\t\t\t\tlong: bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),\n\t\t\t\tshort_in_long: bbb(aaa(1,2,3,4,5), 123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),\n\t\t\t\tlong_in_short: aaa(1,2,3,4,5,bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123)),\n\t\t\t}\n\t\t\"))" ---- -{ - short: aaa(1, 2, 3, 4, 5), - long: bbb( - 123123123123123123123, - 12312312321123123123, - 123123123123312123123, - 123123123123123123312, - 123123123123312321123, - ), - short_in_long: bbb( - aaa(1, 2, 3, 4, 5), - 123123123123123123123, - 12312312321123123123, - 123123123123312123123, - 123123123123123123312, - 123123123123312321123, - ), - long_in_short: aaa( - 1, - 2, - 3, - 4, - 5, - bbb( - 123123123123123123123, - 12312312321123123123, - 123123123123312123123, - 123123123123123123312, - 123123123123312321123, - ), - ), -} --- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__asserts.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: crates/jrsonnet-formatter/src/tests.rs -expression: "reformat(indoc!(\"\n\t\t\t{\n\t\t\t\tassert 1 > 0 : 'one should be greater than zero',\n\t\t\t\tassert true,\n\t\t\t\tvalue: 42,\n\t\t\t}\n\t\t\"))" ---- -{ - assert 1 > 0: 'one should be greater than zero', - assert true, - value: 42, -} --- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__complex_comments.snap +++ /dev/null @@ -1,62 +0,0 @@ ---- -source: crates/jrsonnet-formatter/src/tests.rs -expression: "reformat(indoc!(\"{\n\t\t comments: {\n\t\t\t_: '',\n\t\t\t// Plain comment\n\t\t\ta: '',\n\n\t\t\t# Plain comment with empty line before\n\t\t\tb: '',\n\t\t\t/*Single-line multiline comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Single-line multiline doc comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Multiline doc\n\t\t\tComment\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/*\n\n\tMulti-line\n\n\tcomment\n\t\t\t*/\n\t\t\td: '',\n\n\t\t\te: '', // Inline comment\n\n\t\t\tk: '',\n\n\t\t\t// Text after everything\n\t\t },\n\t\t comments2: {\n\t\t\tk: '',\n\t\t\t// Text after everything, but no newline above\n\t\t },\n spacing: {\n a: '',\n\n b: '',\n },\n noSpacing: {\n a: '',\n b: '',\n },\n\n\t\t\t smallObjectWithEnding: {/*Ending comment*/},\n\t\t\t smallObjectWithFieldAndEnding: {a: 11/*Ending comment*/},\n\t\t\t smallObjectWithFieldAndEnding2: {/*Start*/a: 11/*Ending comment*/},\n }\"))" ---- -{ - comments: { - _: '', - // Plain comment - a: '', - - # Plain comment with empty line before - b: '', - /* Single-line multiline comment */ - c: '', - - /** - * Single-line multiline doc comment - */ - c: '', - - /** - * Multiline doc - * Comment - */ - c: '', - - /* - Multi-line - - comment - */ - d: '', - - e: '', // Inline comment - - k: '', - - // Text after everything - }, - comments2: { - k: '', - // Text after everything, but no newline above - }, - spacing: { - a: '', - - b: '', - }, - noSpacing: { - a: '', - b: '', - }, - - smallObjectWithEnding: { - /* Ending comment */ - }, - smallObjectWithFieldAndEnding: { a: 11 /* Ending comment */ }, - smallObjectWithFieldAndEnding2: { - /* Start */ - a: 11, /* Ending comment */ - }, -} --- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__complex_nested.snap +++ /dev/null @@ -1,41 +0,0 @@ ---- -source: crates/jrsonnet-formatter/src/tests.rs -expression: "reformat(indoc!(\"\n\t\t\t{\n\t\t\t\tkubernetes: {\n\t\t\t\t deployment: {\n\t\t\t\t\tapiVersion: 'apps/v1',\n\t\t\t\t\tkind: 'Deployment',\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t name: 'myapp',\n\t\t\t\t\t labels: { app: 'myapp', version: 'v1' },\n\t\t\t\t\t},\n\t\t\t\t\tspec: {\n\t\t\t\t\t replicas: 3,\n\t\t\t\t\t selector: { matchLabels: { app: 'myapp' } },\n\t\t\t\t\t template: {\n\t\t\t\t\t\t metadata: { labels: { app: 'myapp' } },\n\t\t\t\t\t\t spec: {\n\t\t\t\t\t\t\tcontainers: [\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t name: 'myapp',\n\t\t\t\t\t\t\t\t image: 'myapp:latest',\n\t\t\t\t\t\t\t\t ports: [{ containerPort: 8080 }],\n\t\t\t\t\t\t\t\t env: [\n\t\t\t\t\t\t\t\t\t{ name: 'FOO', value: 'bar' },\n\t\t\t\t\t\t\t\t\t{ name: 'BAZ', valueFrom: { secretKeyRef: { name: 'mysecret', key: 'password' } } },\n\t\t\t\t\t\t\t\t ],\n\t\t\t\t\t\t\t },\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t },\n\t\t\t\t\t },\n\t\t\t\t\t},\n\t\t\t\t },\n\t\t\t },\n\t\t\t}\n\t\t\"))" ---- -{ - kubernetes: { - deployment: { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - name: 'myapp', - labels: { app: 'myapp', version: 'v1' }, - }, - spec: { - replicas: 3, - selector: { matchLabels: { app: 'myapp' } }, - template: { - metadata: { labels: { app: 'myapp' } }, - spec: { - containers: [ - { - name: 'myapp', - image: 'myapp:latest', - ports: [ - { containerPort: 8080 }, - ], - env: [ - { name: 'FOO', value: 'bar' }, - { - name: 'BAZ', - valueFrom: { secretKeyRef: { name: 'mysecret', key: 'password' } }, - }, - ], - }, - ], - }, - }, - }, - }, - }, -} --- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__self_super.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: crates/jrsonnet-formatter/src/tests.rs -expression: "reformat(indoc!(\"\n\t\t\tlocal base = {\n\t\t\t foo: 'bar',\n\t\t\t method():: self.foo,\n\t\t\t};\n\n\t\t\tbase {\n\t\t\t foo: super.foo + '-extended',\n\t\t\t result: self.method(),\n\t\t\t}\n\t\t\"))" ---- -local base = { - foo: 'bar', - method( - ):: self.foo, -}; -base { - foo: super.foo + '-extended', - result: self.method(), -} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@args.jsonnet.snap @@ -0,0 +1,37 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/args.jsonnet +--- +{ + short: aaa(1, 2, 3, 4, 5), + long: bbb( + 123123123123123123123, + 12312312321123123123, + 123123123123312123123, + 123123123123123123312, + 123123123123312321123, + ), + short_in_long: bbb( + aaa(1, 2, 3, 4, 5), + 123123123123123123123, + 12312312321123123123, + 123123123123312123123, + 123123123123123123312, + 123123123123312321123, + ), + long_in_short: aaa( + 1, + 2, + 3, + 4, + 5, + bbb( + 123123123123123123123, + 12312312321123123123, + 123123123123312123123, + 123123123123123123312, + 123123123123312321123, + ), + ), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@asserts.jsonnet.snap @@ -0,0 +1,10 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/asserts.jsonnet +--- +{ + assert 1 > 0: 'one should be greater than zero', + assert true, + value: 42, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@basic_array.jsonnet.snap @@ -0,0 +1,12 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/basic_array.jsonnet +--- +[ + 1, + 2, + 3, + 4, + 5, +] --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@basic_object.jsonnet.snap @@ -0,0 +1,6 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/basic_object.jsonnet +--- +{ foo: 'bar', baz: 'qux', nested: { a: 1, b: 2 } } --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@comments.jsonnet.snap @@ -0,0 +1,16 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/comments.jsonnet +--- +// File header comment +{ + // Comment above field + foo: 'bar', + /* Block comment */ + baz: 'qux', + nested: { + // Hash comment + value: 42, + }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@complex_comments.jsonnet.snap @@ -0,0 +1,63 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/complex_comments.jsonnet +--- +{ + comments: { + _: '', + // Plain comment + a: '', + + # Plain comment with empty line before + b: '', + /* Single-line multiline comment */ + c: '', + + /** + * Single-line multiline doc comment + */ + c: '', + + /** + * Multiline doc + * Comment + */ + c: '', + + /* + Multi-line + + comment + */ + d: '', + + e: '', // Inline comment + + k: '', + + // Text after everything + }, + comments2: { + k: '', + // Text after everything, but no newline above + }, + spacing: { + a: '', + + b: '', + }, + noSpacing: { + a: '', + b: '', + }, + + smallObjectWithEnding: { + /* Ending comment */ + }, + smallObjectWithFieldAndEnding: { a: 11 /* Ending comment */ }, + smallObjectWithFieldAndEnding2: { + /* Start */ + a: 11, /* Ending comment */ + }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@complex_nested.jsonnet.snap @@ -0,0 +1,42 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/complex_nested.jsonnet +--- +{ + kubernetes: { + deployment: { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + name: 'myapp', + labels: { app: 'myapp', version: 'v1' }, + }, + spec: { + replicas: 3, + selector: { matchLabels: { app: 'myapp' } }, + template: { + metadata: { labels: { app: 'myapp' } }, + spec: { + containers: [ + { + name: 'myapp', + image: 'myapp:latest', + ports: [ + { containerPort: 8080 }, + ], + env: [ + { name: 'FOO', value: 'bar' }, + { + name: 'BAZ', + valueFrom: { secretKeyRef: { name: 'mysecret', key: 'password' } }, + }, + ], + }, + ], + }, + }, + }, + }, + }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@comprehensions.jsonnet.snap @@ -0,0 +1,29 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/comprehensions.jsonnet +--- +{ + arr: [x for x in [ + 1, + 2, + 3, + ]], + filtered: [x for x in [ + 1, + 2, + 3, + 4, + 5, + ] if x > 2], + obj: { + [k]: v, + for k in [ + 'a', + 'b', + ]for v in [ + 1, + 2, + ] + }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@conditionals.jsonnet.snap @@ -0,0 +1,9 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/conditionals.jsonnet +--- +{ + simple: if true then 'yes' else 'no', + nested: if 1 > 0 then if 2 > 1 then 'a' else 'b' else 'c', +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@functions.jsonnet.snap @@ -0,0 +1,20 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/functions.jsonnet +--- +{ + simple( + x, + ):: x * 2, + with_default( + x, + y = 10, + ):: x + y, + multiline( + a, + b, + c, + ):: a + b + c, + called: self.simple(5), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@imports.jsonnet.snap @@ -0,0 +1,11 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/imports.jsonnet +--- +local a = import 'a.libsonnet'; +local m = import 'm.libsonnet'; +local z = import 'z.libsonnet'; +{ + result: a + m + z, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@local_vars.jsonnet.snap @@ -0,0 +1,12 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/local_vars.jsonnet +--- +local x = 10; +local y = 20; +local sum = x + y; +{ + local inner = 5, + result: sum + inner, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@operators.jsonnet.snap @@ -0,0 +1,18 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/operators.jsonnet +--- +{ + arithmetic: 1 + 2 * 3 - 4 / 2, + comparison: 1 < 2 && 3 > 2 || false, + string_concat: 'hello' + ' ' + 'world', + object_concat: { a: 1 } + { b: 2 }, + array_concat: [ + 1, + 2, + ] + [ + 3, + 4, + ], +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@self_super.jsonnet.snap @@ -0,0 +1,14 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/self_super.jsonnet +--- +local base = { + foo: 'bar', + method( + ):: self.foo, +}; +base { + foo: super.foo + '-extended', + result: self.method(), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@std_functions.jsonnet.snap @@ -0,0 +1,22 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/std_functions.jsonnet +--- +{ + length: std.length( + [ + 1, + 2, + 3, + ], + ), + type: std.type('hello'), + format: std.format( + 'Hello, %s!', + [ + 'world', + ], + ), + manifest: std.manifestJsonEx({ foo: 'bar' }, ' '), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__snapshots@string_styles.jsonnet.snap @@ -0,0 +1,14 @@ +--- +source: crates/jrsonnet-formatter/src/tests.rs +expression: reformat(&input) +input_file: crates/jrsonnet-formatter/src/tests/string_styles.jsonnet +--- +{ + double_quote: 'hello world', + single_quote: 'hello world', + escaped: 'line1\nline2', + multiline: ||| + This is a + multiline string + |||, +} --- a/crates/jrsonnet-formatter/src/tests.rs +++ b/crates/jrsonnet-formatter/src/tests.rs @@ -1,5 +1,10 @@ +#![cfg(test)] + +use std::fs; + use dprint_core::formatting::{PrintItems, PrintOptions}; use indoc::indoc; +use insta::{assert_snapshot, glob}; use crate::Printable; @@ -13,155 +18,18 @@ out }, PrintOptions { - indent_width: 2, + indent_width: 3, max_width: 100, - use_tabs: true, + use_tabs: false, new_line_text: "\n", }, ) } #[test] -fn complex_comments() { - insta::assert_snapshot!(reformat(indoc!( - "{ - comments: { - _: '', - // Plain comment - a: '', - - # Plain comment with empty line before - b: '', - /*Single-line multiline comment - - */ - c: '', - - /**Single-line multiline doc comment - - */ - c: '', - - /**Multiline doc - Comment - */ - c: '', - - /* - - Multi-line - - comment - */ - d: '', - - e: '', // Inline comment - - k: '', - - // Text after everything - }, - comments2: { - k: '', - // Text after everything, but no newline above - }, - spacing: { - a: '', - - b: '', - }, - noSpacing: { - a: '', - b: '', - }, - - smallObjectWithEnding: {/*Ending comment*/}, - smallObjectWithFieldAndEnding: {a: 11/*Ending comment*/}, - smallObjectWithFieldAndEnding2: {/*Start*/a: 11/*Ending comment*/}, - }" - ))); -} - -#[test] -fn args() { - insta::assert_snapshot!(reformat(indoc!( - " - { - short: aaa(1,2,3,4,5), - long: bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123), - short_in_long: bbb(aaa(1,2,3,4,5), 123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123), - long_in_short: aaa(1,2,3,4,5,bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123)), - } - " - ))); -} - -#[test] -fn asserts() { - insta::assert_snapshot!(reformat(indoc!( - " - { - assert 1 > 0 : 'one should be greater than zero', - assert true, - value: 42, - } - " - ))); -} - -#[test] -fn complex_nested() { - insta::assert_snapshot!(reformat(indoc!( - " - { - kubernetes: { - deployment: { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - name: 'myapp', - labels: { app: 'myapp', version: 'v1' }, - }, - spec: { - replicas: 3, - selector: { matchLabels: { app: 'myapp' } }, - template: { - metadata: { labels: { app: 'myapp' } }, - spec: { - containers: [ - { - name: 'myapp', - image: 'myapp:latest', - ports: [{ containerPort: 8080 }], - env: [ - { name: 'FOO', value: 'bar' }, - { name: 'BAZ', valueFrom: { secretKeyRef: { name: 'mysecret', key: 'password' } } }, - ], - }, - ], - }, - }, - }, - }, - }, - } - " - ))); -} - -#[test] -fn self_super() { - insta::assert_snapshot!(reformat(indoc!( - " - local base = { - foo: 'bar', - method():: self.foo, - }; - - base { - foo: super.foo + '-extended', - result: self.method(), - } - " - ))); +fn snapshots() { + glob!("tests/*.jsonnet", |path| { + let input = fs::read_to_string(path).expect("read test file"); + assert_snapshot!(reformat(&input)); + }); } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/args.jsonnet @@ -0,0 +1,7 @@ + + { + short: aaa(1,2,3,4,5), + long: bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123), + short_in_long: bbb(aaa(1,2,3,4,5), 123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123), + long_in_short: aaa(1,2,3,4,5,bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123)), + } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/asserts.jsonnet @@ -0,0 +1,6 @@ + + { + assert 1 > 0 : 'one should be greater than zero', + assert true, + value: 42, + } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/basic_array.jsonnet @@ -0,0 +1 @@ +[1, 2, 3, 4, 5] --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/basic_object.jsonnet @@ -0,0 +1 @@ +{ foo: 'bar', baz: 'qux', nested: { a: 1, b: 2 } } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/comments.jsonnet @@ -0,0 +1,11 @@ +// File header comment +{ + // Comment above field + foo: 'bar', + /* Block comment */ + baz: 'qux', + nested: { + // Hash comment + value: 42, + }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/complex_comments.jsonnet @@ -0,0 +1,55 @@ +{ + comments: { + _: '', + // Plain comment + a: '', + + # Plain comment with empty line before + b: '', + /*Single-line multiline comment + + */ + c: '', + + /**Single-line multiline doc comment + + */ + c: '', + + /**Multiline doc + Comment + */ + c: '', + + /* + + Multi-line + + comment + */ + d: '', + + e: '', // Inline comment + + k: '', + + // Text after everything + }, + comments2: { + k: '', + // Text after everything, but no newline above + }, + spacing: { + a: '', + + b: '', + }, + noSpacing: { + a: '', + b: '', + }, + + smallObjectWithEnding: {/*Ending comment*/}, + smallObjectWithFieldAndEnding: {a: 11/*Ending comment*/}, + smallObjectWithFieldAndEnding2: {/*Start*/a: 11/*Ending comment*/}, + } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/complex_nested.jsonnet @@ -0,0 +1,33 @@ + + { + kubernetes: { + deployment: { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + name: 'myapp', + labels: { app: 'myapp', version: 'v1' }, + }, + spec: { + replicas: 3, + selector: { matchLabels: { app: 'myapp' } }, + template: { + metadata: { labels: { app: 'myapp' } }, + spec: { + containers: [ + { + name: 'myapp', + image: 'myapp:latest', + ports: [{ containerPort: 8080 }], + env: [ + { name: 'FOO', value: 'bar' }, + { name: 'BAZ', valueFrom: { secretKeyRef: { name: 'mysecret', key: 'password' } } }, + ], + }, + ], + }, + }, + }, + }, + }, + } --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/comprehensions.jsonnet @@ -0,0 +1,5 @@ +{ + arr: [x for x in [1, 2, 3]], + filtered: [x for x in [1, 2, 3, 4, 5] if x > 2], + obj: { [k]: v for k in ['a', 'b'] for v in [1, 2] }, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/conditionals.jsonnet @@ -0,0 +1,7 @@ +{ + simple: if true then 'yes' else 'no', + nested: if 1 > 0 then + if 2 > 1 then 'a' else 'b' + else + 'c', +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/functions.jsonnet @@ -0,0 +1,10 @@ +{ + simple(x):: x * 2, + with_default(x, y=10):: x + y, + multiline( + a, + b, + c, + ):: a + b + c, + called: self.simple(5), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/imports.jsonnet @@ -0,0 +1,7 @@ +local a = import 'a.libsonnet'; +local m = import 'm.libsonnet'; +local z = import 'z.libsonnet'; + +{ + result: a + m + z, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/local_vars.jsonnet @@ -0,0 +1,8 @@ +local x = 10; +local y = 20; +local sum = x + y; + +{ + local inner = 5, + result: sum + inner, +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/operators.jsonnet @@ -0,0 +1,7 @@ +{ + arithmetic: 1 + 2 * 3 - 4 / 2, + comparison: 1 < 2 && 3 > 2 || false, + string_concat: 'hello' + ' ' + 'world', + object_concat: { a: 1 } + { b: 2 }, + array_concat: [1, 2] + [3, 4], +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/self_super.jsonnet @@ -0,0 +1,9 @@ +local base = { + foo: 'bar', + method():: self.foo, +}; + +base { + foo: super.foo + '-extended', + result: self.method(), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/std_functions.jsonnet @@ -0,0 +1,6 @@ +{ + length: std.length([1, 2, 3]), + type: std.type('hello'), + format: std.format('Hello, %s!', ['world']), + manifest: std.manifestJsonEx({ foo: 'bar' }, ' '), +} --- /dev/null +++ b/crates/jrsonnet-formatter/src/tests/string_styles.jsonnet @@ -0,0 +1,9 @@ +{ + double_quote: 'hello world', + single_quote: 'hello world', + escaped: 'line1\nline2', + multiline: ||| + This is a + multiline string + |||, +} --- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__plain_call.snap +++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__plain_call.snap @@ -5,49 +5,49 @@ SOURCE_FILE@0..37 EXPR@0..36 EXPR_BINARY@0..36 - EXPR@0..3 + EXPR@0..31 EXPR_VAR@0..3 NAME@0..3 IDENT@0..3 "std" - SUFFIX_INDEX@3..10 - DOT@3..4 "." - NAME@4..10 - IDENT@4..10 "substr" - SUFFIX_APPLY@10..31 - ARGS_DESC@10..31 - L_PAREN@10..11 "(" - ARG@11..12 - EXPR@11..12 - EXPR_VAR@11..12 - NAME@11..12 - IDENT@11..12 "a" - COMMA@12..13 "," - WHITESPACE@13..14 " " - ARG@14..15 - EXPR@14..15 - EXPR_NUMBER@14..15 - FLOAT@14..15 "0" - COMMA@15..16 "," - WHITESPACE@16..17 " " - ARG@17..30 - EXPR@17..30 - EXPR_VAR@17..20 - NAME@17..20 - IDENT@17..20 "std" - SUFFIX_INDEX@20..27 - DOT@20..21 "." - NAME@21..27 - IDENT@21..27 "length" - SUFFIX_APPLY@27..30 - ARGS_DESC@27..30 - L_PAREN@27..28 "(" - ARG@28..29 - EXPR@28..29 - EXPR_VAR@28..29 - NAME@28..29 - IDENT@28..29 "b" - R_PAREN@29..30 ")" - R_PAREN@30..31 ")" + SUFFIX_INDEX@3..10 + DOT@3..4 "." + NAME@4..10 + IDENT@4..10 "substr" + SUFFIX_APPLY@10..31 + ARGS_DESC@10..31 + L_PAREN@10..11 "(" + ARG@11..12 + EXPR@11..12 + EXPR_VAR@11..12 + NAME@11..12 + IDENT@11..12 "a" + COMMA@12..13 "," + WHITESPACE@13..14 " " + ARG@14..15 + EXPR@14..15 + EXPR_NUMBER@14..15 + FLOAT@14..15 "0" + COMMA@15..16 "," + WHITESPACE@16..17 " " + ARG@17..30 + EXPR@17..30 + EXPR_VAR@17..20 + NAME@17..20 + IDENT@17..20 "std" + SUFFIX_INDEX@20..27 + DOT@20..21 "." + NAME@21..27 + IDENT@21..27 "length" + SUFFIX_APPLY@27..30 + ARGS_DESC@27..30 + L_PAREN@27..28 "(" + ARG@28..29 + EXPR@28..29 + EXPR_VAR@28..29 + NAME@28..29 + IDENT@28..29 "b" + R_PAREN@29..30 ")" + R_PAREN@30..31 ")" WHITESPACE@31..32 " " EQ@32..34 "==" WHITESPACE@34..35 " " --- /dev/null +++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__string_block_trim.snap @@ -0,0 +1,9 @@ +--- +source: crates/jrsonnet-rowan-parser/src/tests.rs +expression: "|||-\n\tTrimmed text block\n|||\n" +--- +SOURCE_FILE@0..29 + EXPR@0..28 + EXPR_STRING@0..28 + STRING_BLOCK@0..28 "|||-\n\tTrimmed text bl ..." + WHITESPACE@28..29 "\n" --- a/crates/jrsonnet-rowan-parser/src/string_block.rs +++ b/crates/jrsonnet-rowan-parser/src/string_block.rs @@ -52,6 +52,14 @@ self.rest().chars().next() } + fn eat_if(&mut self, f: impl Fn(char) -> bool) -> usize { + if self.peek().map(f).unwrap_or(false) { + self.index += 1; + return 1; + } + 0 + } + fn eat_while(&mut self, f: impl Fn(char) -> bool) -> usize { if self.index == self.source.len() { return 0; @@ -133,6 +141,8 @@ offset: lex.span().end, }; + ctx.eat_if(|v| v == '-'); + // Skip whitespaces ctx.eat_while(|r| r == ' ' || r == '\t' || r == '\r'); --- a/crates/jrsonnet-rowan-parser/src/tests.rs +++ b/crates/jrsonnet-rowan-parser/src/tests.rs @@ -55,7 +55,6 @@ let src = indoc::indoc!($test); let result = process(&src); insta::assert_snapshot!(stringify!($name), result, src); - } )+}; } @@ -204,6 +203,12 @@ super_nesting => r#" super.a + super.b "# + + string_block_trim => r#" + |||- + Trimmed text block + ||| + "# ); #[test]