Giter Club home page Giter Club logo

swift-html's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swift-html's Issues

srcset init() should sort by "size"

When a 'srcset' attribute is converted from a dictionary to a string, the ordering should be fixed, e.g. sort by size.description ?

Without this:

  • Every time I render my output, the arbitrary order changes, and, as I commit my output to git, I have a load of commits that are just making unnecessary changes to the order of the resolutions in the srcsets. It messes up my git history.
  • I'm hoping to adopt snapshot testing, and it's going to break that too.

Need to put comment inside of any parent tag

I'm trying to construct an HTML document with an IE-specific directive in the <head> tag. It looks like a comment:

<!--[if IE]><meta http-equiv='X-UA-Compatible' content='IE=edge'><![endif]-->

Problem is, I can't put this comment in the <head> tag. I get this compile message:

  • Type 'ChildOf<Tag.Head>' has no member 'comment'

It would be great to be able to put some kinds of nodes like .comment, also probably .raw nodes, at any place in a tree.

Need querying and manipulation operators similar to DOM manipulation operations

Other than Node.isEmpty() and Node.append(), we don't really have any way to manipulate the tree of Node objects in the swift-html library.

I would like to suggest that we have a number of functions that are similar to DOM manipulation operations available in JavaScript and other languages.

The current structure of the Node (especially with the copious use of the "fragment") makes it difficult to dig in and make manipulations to the nodes. So adding a familiar API layer to this will make it easier to build a web document out of Nodes.

For instance:

appendChild()
insertBefore(node)
removeChiild(child)
remove()
parentNode()
querySelector()
querySelectorAll()
getElementByID(id)
replaceChilden()

Decide whether or not to escape attribute names

We do a good job of escaping the things that need to be escaped via what the HTML spec says, but right now we don't escape the name of attributes at all. This means you can do the following to inject an XSS:

let badAttribute = Attribute<Tag.A>("></a><script>alert('!');</script>", "foo")
a([badAttribute], ["XSS"])

and that renders as:

<a ></a><script>alert('!');</script>="foo">XSS</a>

which executes an alert.

However, this isn't really a big deal in the vast majority of uses of this library. There isn't really a big need for tag names specified by user input. After chatting today we came up with the following pros and cons for escaping this:

Pros:

  • Might as well, we escape everything else...
  • We want to support Codable with Node, and that opens up a bigger vector of abuse. If you can deserialize HTML from a string stored anywhere you open yourself up to a lot of different ways bad attributes can sneak in.

Cons:

  • It's not clear how we should escape the invalid characters. The spec says what characters are invalid, but there is no way to "recover" from the presence of those characters. It's entirely user error to use those characters. I'm thinking the best thing to do is just completely remove them.
  • No other library escapes attribute names it seems.

Alternatives:

  • Escape only when decoding/encoding a Node.
  • Force attribute names to be StaticString, but then that doesn't allow for codable. We could at the very least make the Attribute initializer take only static strings for the key field.

Could not find module & "unexclaim" sample issue

Hi everyone
I try to use swift-html in my project.

Currently I have two Issues:

  1. On my Mac M1, when I try to build App I get following error:
    "Could not find module 'Html' for target 'x86_64-apple-ios-simulator'; found: arm64, arm64-apple-ios-simulator, at:"
    Screenshot 2022-02-10 at 15 55 17

  2. I try to use sample function unexclaim() from readme.
    But I get this Issue:
    Screenshot 2022-02-10 at 15 56 42

Maybe someone has hint for me?

Bests from Swiss Mountains

Philippe

Can't install from SPM

Output error:

error: the package PackageReference(identity: "swift-html", name: nil, path: "https://github.com/pointfreeco/swift-html.git", isLocal: false) @ 0.1.0 contains revisioned dependencies:
    PackageReference(identity: "swift-snapshot-testing", name: nil, path: "https://github.com/pointfreeco/swift-snapshot-testing.git", isLocal: false) @ 69b48c8

I guess it needs to use a version number tag for the swift-snapshot-testing dependency.

.div will take array literal but not an Array<Node>() instance

Mostly out of curiosity, I can work around this, but I'm not understanding why this works this way:

Here I can't pass an Array<Node>...
image

...but I can pass an array literal

image

Node is an Enum, and one of its cases is .fragment([Node]) so I see how the array literal works, but I don't understand why the Array<Node> instance doesn't.

HTML 5

is there any plan to update for HTML 5 ?

CSS dsl

Hello! Nice work with the library, I'm already working with it to create my personal website😊

From the playground:

Some simple CSS for our page. This can be written right inline to our DSL, we could also load it from a file on disk, or better yet, we could create another DSL for modeling it 😉

I agree on this. Once you get used to modeling html this way, working with that multiline string css stylesheet feels even worse than before. It would also help people with more experience with swift but not with css, since it would provide autocompletion, compile safety and documentation within Xcode.

Now say I wanted to contribute and start working on it, is this library the good place for it or would you prefer a separate module?

"Type expression ambiguous" error

Whenever I use a variable for contents of Node I get compile error that says:

Type of expression is ambiguous without more context

I'm unclear why this is the case and what I would need to do to fix it.
image

        guard let age: String = test.studentAgeAtTimeOfTest() else { return "error" }

        let htmlTree =
            html([
                head([

                    ]),
                body([
                    h1(["Student is \(age) years old"])
                    ])
                ])

Inside <dl>, wrapping <dd>, <dt> elements inside <div> doesn't seem to work

From quick help for dl:

Each term-description group consists of one or more terms (represented by <dt> elements) possibly as children of a <div> element child, and one or more descriptions (represented by <dd> elements possibly as children of a <div> element child), ignoring any nodes other than <dt> and <dd> element children, and <dt> and <dd> elements that are children of <div> element children within a single <dl> element.

But, trying the following causes compiler error Type 'ChildOf<Tag.Dl>' has no member 'div'

      .dl(
        .div(
            .dt("term"),
            .dd("description")
        )
      )

(maybe-not-so-really) indirect enum Node

Hi guys! First of all, thank you for this great lib, you've done a great job with this and I love your work!

I was trying to kinda of rewrite your lib for fun in a playground and the compiler allowed me to declare the Node enum without marking the .element case as indirect. I wondered if that depends on the fact that children is actually an array of Nodes and not a single Node... If that's the case you might want to drop the indirect modifier, too!

I don't even know if that might have benefit performance / memory wise, maybe the Swift compiler is smart enough and has never introduced the "indirect reference / pointer" to the node in question ever.

error: type 'Node' has no member 'document'; did you mean 'comment'?

mkdir Pot
cd Pot
swift package init --type executable 

add swift-html to Package.swift

// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
  name: "Pot",
  dependencies: [
    .package(url: "https://github.com/pointfreeco/swift-html.git", from: "0.2.0")
  ],
  targets: [
    .target(
      name: "Pot",
      dependencies: ["Html"]),
    .testTarget(
      name: "PotTests",
      dependencies: ["Pot"])
  ]
)

cat Sources/Pot/main.swift

import Html

let document: Node = .document(
  .html(
    .body(
      .h1("Welcome!"),
      .p("You’ve found our site!")
    )
  )
)

print(render(document))
$ swift build
Compile Swift Module 'Pot' (1 sources)
/Users/nix/Documents/Pot/Sources/Pot/main.swift:3:23: error: type 'Node' has no member 'document'; did you mean 'comment'?
let document: Node = .document(
                      ^~~~~~~~
                      comment
Html.Node:2:10: note: 'comment' declared here
    case comment(String)
         ^
error: terminated(1): /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/nix/Documents/Pot/.build/debug.yaml main output:
    

Added typesafety for multiple tags

Hey! Really like the library. I was playing around with it and saw that it was possible to do something like

.document(
  .html(
    .body(
      .html()
    )
  )
)

And tags like .div and .script can be used anywhere in .document.
.script can also be used anywhere within .html which are all examples of invalid html.
I was playing around a bit and it would be quite easy to improve on this behavior by

  • introducing an extension on ChildOf for doctype.
  • remove general extensions from ChildOf for script tags (and some others) and move these instead to specific extensions of ChildOf (introducing a little bit more code)
  • move all tags that are only used inside a body tag to an extension of ChildOf where Element == Tag.Body All these static functions would also return a ChildOf<Tag.Body> instead of the previous Node type. Then we can use them nested as well!

I've got this working locally and works quite nice! :) Let me know if you're interested in a PR for this behavior!

Carthage support?

Until Carthage gets SPM support (Carthage/Carthage#1945), would you consider accepting a PR that would add an Xcode project to build the library? To improve Xcode support out of the box.

Need documentation explaining how to build documents piece-by-piece especially with helper functions

So far all of the examples I've seen are for building up a .document from a complete set of sub-nodes all at once, but realistically a web page is going to be built up dynamically. I want to create a element and adjust the sub-tags based on logic in the program, then build up the piece by piece, and then finally assemble into .html and into a final .document for rendering.

After some exploration in the documentation and test methods I am for instance able to create an .html node like this:

		let htmlUsingHelper = Node.html(
			.body(
				.h1("Welcome!"),
				.p("You’ve found our site!")
			)
		)

But then why can't I do something similar to create a .head like this?

		let headUsingHelper = Node.head(
			.meta(attributes: [.charset(.utf8)]),
			.title(self.title)
		)

That has 3 compile errors!

Maybe there is a workaround by avoiding the "helper functions" but it would be so nice to be able to manipulate fragments with the helper functions and then assemble them into a full .document (or fragment) as needed.

BTW is the dot-syntax you are using here in the Swift language documented somewhere? It doesn't seem to be like functional programming where "." is used to chain the result of one function into another function (e.g. in SwiftUI), but something different altogether. If you can point your users to a starting point here, it might be easier to figure out how to make use of the framework beyond the surface level. Thanks!

Preserve tabs

If I have a string like this:

let note = "I love tacos.\n\n\tI love every kind of taco."

and I use it for the text in a paragraph, the element preserves the new lines, but tab is lost.

Is there something I can do to fix this?

Snapshot Testing Version Mixmatch

error: the library 'HtmlSnapshotTesting' requires macos 10.13, but depends on the product 'SnapshotTesting' which requires macos 10.15; consider changing the library 'HtmlSnapshotTesting' to require macos 10.15 or later, or the product 'SnapshotTesting' to require macos 10.13 or earlier.

unexclaim() example no longer compiles

swift run
/Users/dstevenson/src/swift/SongsToTheSiren/Sources/SongsToTheSiren/Page.swift:76:37: error: static member 'map' cannot be used on instance of type 'Node'
        return .element(tag, attrs, children.map(unexclaim))
                                    ^~~~~~~~
                                    Node
/Users/dstevenson/src/swift/SongsToTheSiren/Sources/SongsToTheSiren/Page.swift:76:50: error: missing argument for parameter 'name' in call
        return .element(tag, attrs, children.map(unexclaim))
                                                 ^
                                                 name: <#String#>,
/Users/dstevenson/src/swift/SongsToTheSiren/.build/checkouts/swift-html/Sources/Html/Elements.swift:489:22: note: 'map(name:attributes:_:)' declared here
  public static func map(name: String, attributes: [Attribute<Tag.Map>] = [], _ content: ChildOf<Tag.Map>...)
                     ^
/Users/dstevenson/src/swift/SongsToTheSiren/Sources/SongsToTheSiren/Page.swift:76:50: error: cannot convert value of type '(HtmlNode) -> HtmlNode' (aka '(Node) -> Node') to expected argument type 'ChildOf<Tag.Map>'
        return .element(tag, attrs, children.map(unexclaim))
                                                 ^

error: Html.playground:30:10: error: type of expression is ambiguous without more context

I've come across this error running the included playground:

error: Html.playground:30:10: error: type of expression is ambiguous without more context
    head([

This is on swift-4.2 but the playground also fails in 4.1.2 for me (although I believe it was a different error message).

The issue is that in in the section

let doc = html([
    head([
        style(stylesheet)
        ]),

stylesheet is a String after assignment while style has the signature

public func style(_ content: StaticString) -> ChildOf<Tag.Head> {

This is fixable by either declaring

let stylesheet = style("""
...

and using

let doc = html([
    head([
        stylesheet
        ]),

or changing style to

public func style(_ content: String) -> ChildOf<Tag.Head> {

The latter seems to be the more lenient variant but I'm wondering if there was a deeper reason to constrain it to StaticString?

Use of elements not in the library

Hello, I have been able to make some examples work using the library but how would I add an element to the body that's not in the swift-html library? For example if a script is used and it gives access to some new element that's not a ".h1", ".p", ".div" etc. how would that be done? Would really appreciate any suggestions to solve this, thank you.

Adding Html as a dependency results in error.

When I add the swift-html package as a dependency I get the following error:
product dependency 'Html' in package 'swift-html' not found
Not sure what to do here, have the feeling it has to do with tools versioning could that be?

package dependency looks as follows:
.package(url: "https://github.com/pointfreeco/swift-html.git", from: "0.3.1"),
target dependency: (needed for 5.2)
.product(name: "Html", package: "swift-html"),

Suggest documentation warning of error message "Cannot infer contextual base in reference to member ______"

I've been getting this error message as I build up HTML code, and I finally realized that what was wrong was a missing comma, for instance after the .header(…) here. It might be good to document the error message phrase _"Cannot infer contextual base in reference to member _____" for people who encounter this error in the future.

Screen Shot 2020-06-30 at 8 44 58 PM

(This is using Xcode 12 beta; don't know how it will appear in older or newer versions of the Swift compiler…)

Font statics are of type Audio

Should these be of type Font?

public static let collection = Audio(rawValue: "collection")
public static let otf = Audio(rawValue: "otf")
public static let sfnt = Audio(rawValue: "sfnt")
public static let ttf = Audio(rawValue: "ttf")
public static let woff = Audio(rawValue: "woff")
public static let woff2 = Audio(rawValue: "woff2")

Roadmap? Swift 4, 5

I found version "0.3.0" did not run on a Swift 4.2.1 system.

What is the plan relative to support/features for Swift 4 and Swift 5? Relative to the release numbers?

Is the 0.2.x Swift 4 version expected to have any new features and/or support updates?

Version differences? Or, maybe the version with Swift 5 so much better, that I should not prefer to spend too much time with the Swift 4 version??

Some roadmap-ish section would be generally helpful if the READMEmd. Thanks.

Constructing lists dynamically

I'm probably missing out something, but is it possible to add .li dynamically to .ul?
The following does not seem to work:

var list = Node.ul()
list.append(.li("Item"))

Cheers

Ambiguous reference to member 'style'

image

I'm sure this must be basic...but I'm not seeing why I get this error.

let htmlTree =
    Node.document(
        .html(
            .head(),
            .body(attributes: [.style(safe: "margin: 10px 35px 20px")], [.div(.text("Test"))])
        ))

HTML character entity incorrectly escaped

Maybe I'm doing this incorrectly, but it seems that if include an html entity such as ° (degrees), as follows

let div:Node = .div( .h3(.text("90&deg;")) )

then the output in the rendered html document is 90&amp;deg;.

Not sure if this is a bug or just me missing the correct method to include an character entity?

Helper function namespacing

First, thank you for the library, it’s a real joy to use! 🦄 The context-driven autocompletion feels like someone is reading my mind sometimes :) And the sheer amount of implemented HTML is impressive. (Did you use some kind of code generation or automation?)

The only thing I have trouble with is what all big DSLs in Swift seem to struggle with, and that’s namespace clashes. The compiler seems to get into a corner very often, ending up with hard-to-read error messages:

// error: expected expression in list of expressions
// error: consecutive statements on a line must be separated by ';'
// error: expected identifier in class declaration
let foo = small(class("sample"), "whatever")

Here the problem is easy to spot, but with more complex expressions one has to decompose them into pieces when the whole thing doesn’t compile at the first try. I usually end up prefixing the troublesome cases (Html.class), but it’s slightly annoying. People who are just starting with DSLs might be pretty confused by error messages such as “being unable to infer T somewhere”, there’s not much to hang on. Do you also run into this problem often? Is there some better solution than prefixing a lot?

<template> elements have no helper

I was contemplating Bootstrap Vue to see if it fit with this library.

I noticed that the <template> element is not handled in the library helper functions. It is sort of a fragment "thing" but is distinct in that you may possibly exclude it from being modified as it is not actually displayed in the main DOM, (ex. the redact example)

There should at least be example documentation on how it should be coded as an element and allowed in the document / fragment.

elements rb,rtc,data also do not appear in the Tag enum?

Add support for nested lists

This should be valid but currently isn't:

ul([
  li(["1"]),
  li(["2"]),
  ul([
    li(["2a"]),
    li(["2b"])
  ])
])

I'm currently working around this by using the un-typechecked element(...) initializer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.