swiftgen / stencilswiftkit Goto Github PK
View Code? Open in Web Editor NEWA framework bringing additional nodes & filters to Stencil dedicated to Swift code generation
License: MIT License
A framework bringing additional nodes & filters to Stencil dedicated to Swift code generation
License: MIT License
I'm using Sourcery, I can't create my own filters and I've tried many times to increment an Integer, I'd like to ask if it's possible to add this as a new filter for numbers here at StencilSwiftKit (or please help me how I'd achieve this without a new filter)
For context what I'd like to do in Stencil:
{{ forloop.counter + 5 }}
Unfortunately this is not yet supported (see for reference: stencilproject/Stencil#117)
I'd like to propose a new filter that would look similar to this:
{{ forloop.counter|increment:5 }}
Any thoughts? Again if I can do that with the existing filter please let me know
So we can write complex if
conditions like the {% macro className %}
in multiple lines to make it more readable and have it compact the output. Until Stencil supports ejs-line newline-stripping tags
I am trying to filter an array using map
. In this case I filter Sourcery variables:
{% map type.allVariables into vars using variable %}{% if variable.readAccess != "private" and variable.readAccess != "fileprivate" and not variable.isComputed %}{{ variable }}{% endif %}{% endmap %}
Afterwards I want to print these filtered vars.
{% for variable in vars where variable != "" %}{{ variable.name }}: {{ variable.name }}{% if not forloop.last %}, {% endif %}{% endfor %}
A get following Exception:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<TtGCs19_SwiftStringStorageVs6UInt16 0x7fb2a2df64f0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.'
My guess is the problem lies here:
The MapNode expects the mapped 0utput to be a String.
I could dig into this and provide a fix if you recognize it as an issue.
From the code gen PR: SwiftGen/SwiftGen#188
https://github.com/uberbruns/CasingTools
why bother?
I was expecting the snakeToCamelCase to have a lower case letter for first.
eg.
func AccumulatorNumAccumulated()
->
func accumulatorNumAccumulated()
while I have been able to get some code smashed out using stencil
https://github.com/johndpope/tensorflow/blob/swift/tensorflow/swift/misc/OperationDefinitions.stencil
https://github.com/johndpope/tensorflow/blob/swift/tensorflow/swift/misc/Operations.swift
I'm using this code
func {{ op._storage._name}}(scope:Scope, {% for arg in op._storage._inputArg %} {{arg.name}}:tf.Output,{{arg.type}} {% endfor %}) -> ({% for arg in op._storage._outputArg %} {{arg.name}}:tf.Output, {% endfor %}) {
but end up with this extra , at end
func AccumulatorApplyGradient(scope:Scope, handle:tf.Output, local_step:tf.Output, gradient:tf.Output**,** ) -> () {
I noticed this c++ template which is used to generate swift classes in antlr has this syntax
https://github.com/janyou/ANTLR-Swift-Target/blob/master/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg
eg.
public static let <lexer.tokens:{k | =<lexer.tokens.(k)>}; separator=", ", wrap, anchor>
it might be worth cherry picking some of the logic here.
Slightly unrelated / (and not an issue) but you maybe interested
This is every language gramma file from antlr spat out as swift tokens / parsers
https://github.com/johndpope/ANTLR-Swift-Target/tree/master/gen/grammars-v4
These base tokens / parsers are generated via c++ template(stg) in antlr then java.
https://github.com/johndpope/Antlr-Swift-runtime
I had envisaged one day that these could be generated from swift.
perhaps with this library
This blocks krzysztofzablocki/Sourcery#259
Thanks!
it would be useful to have a list of swift reserved words that that could be separately maintained.
I came across this just today
https://github.com/apple/swift-protobuf/tree/master/Reference
kind of fits the bill.
https://github.com/apple/swift-protobuf/blob/master/Reference/generated_swift_names_fields.pb.swift
Having trouble using the java / c++ code generation tool with antlr.
being able to plug in a list would pay dividends down the track.
related.
antlr/antlr4#1851
I'm running into an issue building StencilSwiftKit with SPM using Swift 4.2.
/.build/checkouts/StencilSwiftKit.git-5443537928707802040/Sources/SwiftIdentifier.swift:16:55: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
private let headRanges: [CountableClosedRange<Int>] = [
It looks like the same issue was detected by the Swift source compatibility suite: https://bugs.swift.org/browse/SR-8046
Has anyone else seen this / know of a work around?
As discussed in #127, we need to decide what to do with Swift 4.2.
Do we expect lots of people to still use Swift 4.2? Any platform that supports Swift 4.2 also supports Swift 5, so we may as well drop it?
I'm getting the following warning:
'stencilswiftkit' dependency on 'https://github.com/stencilproject/Stencil.git' conflicts with dependency on 'https://github.com/kylef/Stencil.git' which has the same identity 'stencil'. this will be escalated to an error in future versions of SwiftPM.
My project is required to build without warnings, so this is preventing the use of SwiftGen. Thanks
I have confirmed this sample working fine.
stencil string
{% for article in operations %}
<li>{{ article.title }} by {{ article.author }}</li>
{% endfor %}
struct Article {
let name: String
let author: String
}
let articleContext = [
"articles": [
Article(name: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"),
Article(name: "Memory Management with ARC", author: "Kyle Fuller"),
]
]
let environment = stencilSwiftEnvironment()
let template = StencilSwiftTemplate(templateString:stencilString,environment:environment)
let generated = try template.render(["articles": articleContext["articles"]])
For my case, I have some swift protobuffer classes that are auto generated by Apple.
here's the actual class
https://github.com/johndpope/swift-grpc-tensorflow/blob/master/Sources/op_def.pb.swift
Basically it implements SwiftProtobuf.Message
public struct Tensorflow_OpDef: SwiftProtobuf.Message (protocol only)
from what I can see - the only difference between the
struct Article
and
struct Tensorflow_OpDef
is the getters / setters
public var name: String {
get {return _storage._name}
set {_uniqueStorage()._name = newValue}
}
when I reference the internal code / then it works.
{% for op in operations %}
name:{{ op.**_storage._name** }}
{% endfor %}
Expected
{% for op in operations %}
name:{{ op.name }}
{% endfor %}
doesn't render any results.
(I get that this may not be fixable. but maybe some warnings could be added to help debug.)
So I have a macro
{% macro someMacro someParameter %}
And when I attempt to invoke it like this:
{% call someMacro myType.storedVariables|annotated:"someAnnotation" %}
I get this fatal exception:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<SourceryRuntime.Struct 0x7f94a2e1a5a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key storedVariables|annotated:"json".'
Calling the macro without the filter on storedVariables works just fine:
{% call someMacro myType.storedVariables %}
This issue is to update Stencil dependency to the latest release, which should be either 0.15.2 or 0.16.0 if windows-support gets merged soon.
hello swiftgen team!
i am working with stencil in the context of a custom swiftgen template.
i am attempting to iterate over a list of dictionaries and extract all the unique keys which will then represent the cases of an enum.
something like this:
{% macro extractUniqueKeys dictionaries %}
public enum AnalyticsPropertyKey: String {
{% for dict in dictionaries %}
{% for key,value in dict %}
// Only want to execute setting key name and declaring case if I haven't already found that key!
{% set keyName %}{{key|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{% endset %}
case {{keyName}} = "{{key}}"
{% endfor %}
{% endfor %}
}
{% endmacro %}
Is there a way to do this? I also asked on the stencil repo, in case that's the better forum. thank you!
Hello ๐
Currently StencilSwiftKit stable branch depends on Stencil 0.14.0, which depends on PathKit 1.0.0. But last tagged version (StencilSwiftKit 2.7.2) depends on Stencil 0.13.1, which depends on PathKit 0.9.0. The change of major version in PathKit makes it impossible to use a fixed StencilSwiftKit version, if you also depend on other packages that depend on PathKit 1.0.0.
Would it be possible to have a new release of StencilSwiftKit so it is possible to depend on it and on PathKit 1.0.0 at the same time without having to use StencilSwiftKit stable branch?
want a output with {{ }} like {{(key)}}, how can I keep {{ }} ?
Example:
args.forEach { key, value in
result = result.replacingOccurrences(of: "{{(key)}}", with: value)
}
but output comes as:
args.forEach { key, value in
result = result.replacingOccurrences(of: "", with: value)
}
Generated output example:
...enum UniversLTStd: String, FontConvertible {
case 65Bold = "UniversLTStd-Bold"
case 67BoldCondensed = "UniversLTStd-BoldCn"
case 57Condensed = "UniversLTStd-Cn"
case 47LightCondensed = "UniversLTStd-LightCn"
case 47LightCondensedOblique = "UniversLTStd-LightCnObl"
case 59UltraCondensed = "UniversLTStd-UltraCn"
}...
Is there a particular reason the filters are scoped internal
? It would be nice if they were public
to use the filters directly in other customs filters.
I have this simple custom template:
// swiftlint:disable all
// Generated using SwiftGen โ https://github.com/SwiftGen/SwiftGen
{% if files %}
{% macro fileBlock file %}
{% call documentBlock file.document %}
{% endmacro %}
{% macro documentBlock document %}
{% for key,value in document.metadata.properties %}
{% if key == "tests" %}
{% for testKey,testValue in value.properties %}
{%- set propertyName %}{{testKey|lowerFirstWord}}{% endset -%}
case {{propertyName}} = "{{testKey}}"
{% endfor %}
{% endif %}
{% endfor %}
{% endmacro %}
import Foundation
// MARK: - ABTest Names
enum ABTestNames: String {
{% for file in files %}
{% call fileBlock file %}
{% endfor %}
}
{% endif %}
It reads from multiple JSON files and creates an enum with the keys of the elements in the "tests" property.
The problem is that some of these keys are the same in different files and I want to remove the duplicated elements.
Is there a way to do that?
Implements these issues:
I have been trying to use the map function but without success.
I used this documentation sample https://github.com/SwiftGen/StencilSwiftKit/blob/master/Documentation/tag-map.md
// map the list without item name
{% map list into result1 %}{{maploop.item|uppercase}}{% endmap %}
// map with item name
{% map list into result2 using item %}{{item}}{{item|uppercase}}{% endmap %}
// map using the counter variable
{% map list into result3 using item %}{{maploop.counter}} - {{item}}{% endmap %}
This is what it is rendering, always empty.
// map the list without item name
// map with item name
// map using the counter variable
Some of our current filters accept a boolean parameter, which isn't always clear "what" that parameter is for:
For some of our other filters, we already use a "mode" string parameter, that says a bit more about what it does:
all
or leading
normal
or pretty
Suggestions for modes:
lowercase
or none
trim-empty
or none
I've posted a question here about looping a single value:
I wonder if there is anything that StencilSwiftKit has declared that allows this?
I've a lot of similar templates with a lot of common macros, I'd like to just have a copy of each single macro stored inside a common file included by all templates. Unfortunately it looks like I can't just {% include .. %} a macro template and use the macros defined there. When I do call them they are not defined. Is it possible to export macros in a way that could be used from the "outer" context ? thanks in advance
This was proposed in #58. The idea is that at the moment all strings filters from Filters+Strings...
expect String
parameter and throw exception if it's not satisfied, however we could change this rule to accept all parameters that can be described as a string, which CustomStringConvertable
is made for ๐
We'll also make use of it in Sourcery
I'm currently using this through SwiftGen
for generating localized strings.
If I have the strings PDF-title
it returns the identifier PDFTitle
, but if it's passed PDF
it results in the string Pdf
which isn't the correct capitalization for an abbreviation. It seems like there is a difference in behaviour if the passed string has some capitals vs all capitals.
When mutating a variable inside a for-loop, these changes get reverted on loop exit.
This is quite unlike most programming languages. Unfortunately this makes you use more boilerplate code inside templates than necessary.
The current modes will always uppercase the first letter of each component, which is detrimental for some users that prefer to have the same keys as (for example) in their strings files.
Our current modes are:
normal
: converts to a valid identifier, uppercases first letter of each componentpretty
: same as normal + snakeToCamelCase
I propose adding some sort of raw
mode, that only converts to a valid identifier, leaving the rest of the string as is. If need be, we can consider renaming the current modes to new names that better reflect their functionality.
For backwards compatibility, if we rename modes, we can always keep the old names as aliases for a few versions.
I'm not sure if I consider this a breaking change:
Migrated to PathKit for url filters. The dirname will return '.' for a filename without base directory.
I think it's more of a bug fix TBH (we're bringing the output in line with PathKit).
Depending on our choice, the version'll be 2.6.0 or 3.0.0.
The file has grown a lot since the addition of new filters by #54. The splitting of the file will improve readability and reduce complexity.
Is it possible to use StencilSwiftKit with Sourcery? If yes, how can I do this?
I've done my due diligence but I can't seem to find a way to do this:
{% for i in range(1,5) %}
... do something with i ...
{% endfor %}
I apologize beforehand if there's an obvious way to do it but I can't seem to find it.
The closest thing I've been to a solution is using an array that has at least the number of elements I want, doing a map to get the counter and then filter the counters outside the range (which is way too ugly)
I also tried to create an array variable using {% set %} to no use.
And I also tried "1,2,3,4"|split but there's no such filter.
Am I missing something obvious?
In a template, if I try:
value|replace:"\n","\\n"
The search and replace strings become "\\n"
and "\\\\n"
respectively. I think we should un-escape these backslashes, so that users correctly can search for newlines (for example). Or is this something that we should handle in Stencil itself?
Trying to add comments to my custom template for colors from .xcassets Catalog. But seems there is no that data.
Is it possible to get data from Contents.json from each color? Actually, there is contains a data for that...
Currently we have the next data in {asset} variable in templates:
["type": "color", "value": "backgroundGreen", "name": "backgroundGreen"]
Actually the result should be like this:
/// x339933
static let backgroundGreen = UIColor(name: "backgroundGreen")
This will really be helpful for development since you can't remember all values for each name. When you checking UI design and colors - that comment will help to quickly find the right value without "xcassets" Catalog checking.
Thanks!
I'm trying to create a variable that is updated within the scope of a for
tag, but have been unsuccessful:
In the following example, lastCaseName
is never mutated, always taking the value initial
.
Is this possible with Stencil or perhaps swifttemplate
?
{% for root in types.implementing.BeRoot %}
{% set lastCaseName %}initial{% endset %}
class func reduce(_ state: State, with event: Event) -> State {
switch(state.mode, event) {
{% for case in root.cases %}
case (.{{ lastCaseName }}, .did{{ lastCaseName|upperFirstLetter }}):
return state.with { $0.mode = {{ case.name }} }
{% set lastCaseName %}{{ case.name }}{% endset %}
{% endfor %}
return state
}
}
{% endfor %}
Some Filters were created at a time when Stencil didn't support filter parameters yet.
As a result, we have some filters that have been duplicated to allow some variations, but now that Stencil filters support parameters, these duplications can be removed and changed to a filter parameter instead.
One typical example is filters StringFilters.snakeToCamelCase
+ StringFilters.snakeToCamelCaseNoPrefix
that can be unified to a single StringFilters.snakeToCamelCase
filter with a parameter (prefix: Bool
)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.