profile
viewpoint
Filip Stanis fstanis London, UK https://twitter.com/FilipStanis Developer Advocate @Google

ampproject/worker-dom 2327

The same DOM API and Frameworks you know, but in a Web Worker.

ampproject/amp-by-example 774

DEPRECATED: AMP by Example has been merged into amp.dev

ampproject/amp.dev 363

The AMP Project Website.

ampproject/amp-toolbox 286

A collection of AMP tools making it easier to publish and host AMP pages.

fstanis/epaper 5

Go library for Waveshare 4.3inch e-Paper

fstanis/hivecli 3

CLI for Hive smart home devices.

alankent/amp-nuxt-trial 2

Experimenting using Nuxt with AMP

fstanis/go-hive 1

Unofficial Go wrapper library for the British Gas Hive API.

fstanis/amp-by-example 0

A hands-on introduction to Accelerated Mobile Pages (AMP) focusing on code and live samples.

Pull request review commentampproject/amphtml

Support verifying a sender using messagingToken

 export class WindowPortEmulator {    */   addEventListener(eventType, handler) {     this.win_.addEventListener('message', (event) => {-      if (event.origin == this.origin_ && event.source == this.target_) {+      if (+        (event.data.messagingToken === this.token_ ||+          event.origin == this.origin_) &&

Just a small suggestion: if I understand correctly, this means having a messaging token completely disables the origin checking behaviour.

Would it be possible to keep both (i.e. change || to && here)? Then you can just use 'null' as the origin parameter when you create a WindowPortEmulator when there's no origin (this is what we do for the AMP for Email viewer).

Enriqe

comment created time in 13 days

push eventfstanis/docs

Filip Stanis

commit sha 99389f418198cf09c66e83137e2bb1a7dc818917

harden import email

view details

push time in 14 days

PR opened ampproject/amp.dev

Reviewers
Improvements to "import email" logic

This fixes a bug where Content-Type can contain more parameters (like encoding) and overall makes the content type parser more true to RFC 2045.

+35 -17

0 comment

2 changed files

pr created time in 14 days

create barnchfstanis/docs

branch : fiximport

created branch time in 14 days

issue commentgolang/go

x/net/webdav: FileSystem interface should include CopyFile

BTW happy to send a PR, just wanted to get an opinion on whether this kind of API change is a good idea first.

fstanis

comment created time in 14 days

issue commentemersion/go-webdav

FileSystem interface: provide context, make FileInfo an interface

FileInfo is just a metadata container, why would it need to be an interface?

For example, for Google Drive it's convenient to keep additional information, such as an ID. Using an interface means I can reuse the same internal structure, as opposed to making a copy to be compatible with go-webdav. An interface also gives a guarantee that go-webdav doesn't mutate the structs.

I agree on the GC overhead for a slice of points, but this may be premature optimization. Specifically, I'm worried that many file system implementations would keep a cache of FileInfo objects somewhere in a different structure (e.g. a tree) and would then need to construct a slice when Readdir is called, effectively copying a lot of data. With pointers, there would only be slice construction overhead, the underlying data wouldn't be copied.

fstanis

comment created time in 16 days

issue openedemersion/go-webdav

FileSystem interface: provide context, make FileInfo an interface

Just a suggestion: I was looking to potentially use this project instead of golang.org/x/net/webdav and noticed the FileSystem interface is slightly different:

  1. go-webdav doesn't pass a Context to its calls.
  2. FileInfo is a struct and not an interface.
  3. Readdir returns a []FileInfo (slice of values) but Stat returns a *FileInfo (pointer).

I was wondering if you'd consider changing this in the future? Specifically, the first two are useful for when a file system is actually remote like e.g. Dropbox or Google Drive. And using pointers in the slice is just good for consistency (and also, deep copying a slice of values has a larger overhead).

created time in 16 days

issue openedgolang/go

x/net/webdav: FileSystem interface should include CopyFile

WebDAV requires support for the COPY method (defined in RFC 2518 section 8.8). Go's WebDAV server implementation in golang.org/x/net/webdav implements it, however the current implementation simply calls FileSystem.OpenFile on the source and destination and uses io.Copy to pipe the content.

While this is fine in some cases, I really think that the user should be able to override / implement this by adding a CopyFile method to the FileSystem interface. Two major reasons I see:

  • The current implementation is inefficient on filesystems that support copy-on-write.
  • The current implementation is inefficient on remote filesystems (effectively, it will pull a file locally and send it back).

created time in 16 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);+      this.cache.set(key, value);+    } catch (error) {+      value = defaultValue;+    }+    return value;+  }++  async set(key, value) {+    const cacheFile = this.createCacheFileName(key);+    try {+      this.cache[key] = value;

I think the test worked because it was always getting a cache miss and loading from a file. You could maybe add a test that clears the folder on the filesystem after a set to make sure it loads it from the LRU.

sebastianbenz

comment created time in 19 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);+      this.cache.set(key, value);+    } catch (error) {+      value = defaultValue;+    }+    return value;+  }++  async set(key, value) {+    const cacheFile = this.createCacheFileName(key);+    try {+      this.cache[key] = value;+      if (!existsSync(this.opts.baseDir)) {+        mkdirSync(this.opts.baseDir);+      }+      return writeFileAsync(cacheFile, JSON.stringify(value, null, ''), 'utf-8');+    } catch (e) {+      // could not write file+    }+  }++  async clear() {+    try {+      return await this.deleteDir_(this.opts.baseDir);+    } catch (e) {+      // doesn't exist+    }+  }++  createCacheFileName(key) {+    const keyHash = crypto.createHash('md5').update(key).digest('hex');+    return join(this.opts.baseDir, keyHash + '.json');+  }++  async deleteDir_(dir) {+    let entries = await readdirAsync(dir, {withFileTypes: true});+    await Promise.all(+      entries.map((entry) => {+        let fullPath = path.join(dir, entry.name);+        return entry.isDirectory() ? this.deleteDir_(fullPath) : unlinkAsync(fullPath);

Thinking about this further, there's another danger here: if there's a symlink outside this directory (worst case, to ~ or /), this will delete everything it can. You can argue that's not very likely, but I'd prefer if this was impossible.

A few options:

  • Ignore directories and only delete files (since directories are never created this way anyway).
  • Check if a directory is a symlink first.
  • Resolve symlinks and check if the directory has the initial directory as a prefix.

Regarding fs.rmdir, you can add an if to check if it's available and fallback to your own implementation if not. But probably not needed anyway. Just make sure it doesn't recursively delete my home folder. :)

sebastianbenz

comment created time in 19 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);
const content = await fs.readFile(cacheFile); // returns Buffer
this.cache.set(key, value); // Buffer in Map
...
fs.writeFile(cacheFile, value); // writes Buffer to file, no need to specify encoding

JSON.parse also works on a Buffer, by coercing it to string first (i.e. JSON.parse(str) === JSON.parse(Buffer.from(str))).

sebastianbenz

comment created time in 19 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');

Nit: you're importing path twice. Also, I suggest not destructuring, join can be very confusing (as opposed to path.join).

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

 async function fetchAmpRuntimeStyles_(config, ampUrlPrefix, ampRuntimeVersion) {   const runtimeCssUrl =     appendRuntimeVersion(ampUrlPrefix || AMP_CACHE_HOST, ampRuntimeVersion) + AMP_RUNTIME_CSS_PATH;   // Fetch runtime styles-  const response = await config.fetch(runtimeCssUrl);-  if (!response.ok) {-    config.log.error(-      `Could not fetch ${runtimeCssUrl}, failed with status ` + `${response.status}.`-    );+  const styles = await downloadAmpRuntimeStyles_(config, runtimeCssUrl);+  if (!styles) {+    config.log.error(`Could not download ${runtimeCssUrl}`);     if (ampUrlPrefix || ampRuntimeVersion) {       // Try to download latest from cdn.ampproject.org instead       return fetchAmpRuntimeStyles_(AMP_CACHE_HOST, await config.runtimeVersion.currentVersion());     } else {       return '';     }   }-  return response.text();+  return styles;+}++/**+ * @private+ */+async function downloadAmpRuntimeStyles_(config, runtimeCssUrl) {+  let styles;+  if (config.cache !== false) {+    styles = await cache.get(runtimeCssUrl);+  }+  if (!styles) {+    config.log.debug(`Downloading AMP runtime styles from ${runtimeCssUrl}`);+    const response = await config.fetch(runtimeCssUrl);

Something to think about: what if the URL redirected? You may want to store both in the cache (or not).

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);

Why must it be JSON? If you use a raw buffer, your cache becomes binary-compatible (and less error prone and less code).

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+#!/usr/bin/env node+const AmpOptimizer = require('../');+const ampOptimizer = AmpOptimizer.create();++async function warmupCaches() {+  // run a dummy transformation to pre-fill the caches+  await ampOptimizer.transformHtml('<h1>hello world</h1>', {

Nit: just return it.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

 async function fetchAmpRuntimeStyles_(config, ampUrlPrefix, ampRuntimeVersion) {   const runtimeCssUrl =     appendRuntimeVersion(ampUrlPrefix || AMP_CACHE_HOST, ampRuntimeVersion) + AMP_RUNTIME_CSS_PATH;   // Fetch runtime styles-  const response = await config.fetch(runtimeCssUrl);-  if (!response.ok) {-    config.log.error(-      `Could not fetch ${runtimeCssUrl}, failed with status ` + `${response.status}.`-    );+  const styles = await downloadAmpRuntimeStyles_(config, runtimeCssUrl);+  if (!styles) {+    config.log.error(`Could not download ${runtimeCssUrl}`);     if (ampUrlPrefix || ampRuntimeVersion) {       // Try to download latest from cdn.ampproject.org instead       return fetchAmpRuntimeStyles_(AMP_CACHE_HOST, await config.runtimeVersion.currentVersion());     } else {       return '';     }   }-  return response.text();+  return styles;+}++/**+ * @private+ */+async function downloadAmpRuntimeStyles_(config, runtimeCssUrl) {

As discussed, consider moving to a more generic fetch wrapper.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

 class AutoExtensionImporter {     if (!this.enabled) {       return;     }+    if (!params.validatorRules) {+      throw new Error('missing validation rules');+      this.log_.error('Missing validation rules, cannot auto import extensions');

Dead code, you already threw.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);+      this.cache.set(key, value);+    } catch (error) {+      value = defaultValue;+    }+    return value;+  }++  async set(key, value) {+    const cacheFile = this.createCacheFileName(key);+    try {+      this.cache[key] = value;+      if (!existsSync(this.opts.baseDir)) {+        mkdirSync(this.opts.baseDir);+      }+      return writeFileAsync(cacheFile, JSON.stringify(value, null, ''), 'utf-8');+    } catch (e) {+      // could not write file

Don't swallow this error on this level. For a cache, not being able to write a file is exceptional, even though it may be a no-op for whoever calls it.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);+      this.cache.set(key, value);+    } catch (error) {+      value = defaultValue;+    }+    return value;+  }++  async set(key, value) {+    const cacheFile = this.createCacheFileName(key);+    try {+      this.cache[key] = value;

this.cache.set(key, value), otherwise you're in for a lot of fun debugging. :)

Also, the tests should catch this - make sure to add one that calls get after set and checks for equality.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';++const {FileSystemCache} = require('@ampproject/toolbox-core');+const {join} = require('path');

As above: join is confusing, use path.join.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

 class MaxAge {     const maxAgeInMs = this.value * 1000;     return this.timestampInMs_ + maxAgeInMs < currentTimeInMs;   }++  /**+   * Returns a JSON compatible representation.+   * @returns {Object} the MaxAge data+   */+  toJson() {

Shouldn't this be toJSON? That will make it compatible with JSON.stringify, i.e. JSON.stringify(new MaxAge(...)) will work.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

 class MaxAge {     if (!match) {       return MaxAge.zero();     }-    const maxAge = parseInt(match[1], 10);+    return MaxAge.create(match[1]);+  }++  /**+   * Creates a new MaxAge instance from a number or string.+   *+   * @param {Number|String} maxAge the max age in seconds+   * @returns {MaxAge}+   */+  static create(maxAge) {+    if (!Number.isInteger(maxAge)) {+      maxAge = parseInt(maxAge, 10);+    }     return new MaxAge(Date.now(), maxAge);   } +  /**+   * @param {Number} timestampInMs time when max-age value was received+   * @param {Number} value max-age value in seconds+   **/+  static fromJson(timestampInMs, value) {

I don't like the name of this method - it takes the output of JSON.parse, but that's not immediately obvious from the name. Either make it take a string or remove all together, since it's just a (confusing) alias for the constructor.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(+    opts = {+      baseDir: join(__dirname, '.cache'),+    }+  ) {+    return new FileSystemCache(opts);+  }++  constructor(opts) {+    this.opts = opts;+    this.cache = new Map();+  }++  async get(key, defaultValue = null) {+    let value = this.cache.get(key);+    if (value) {+      return value;+    }+    const cacheFile = this.createCacheFileName(key);+    try {+      const content = await readFileAsync(cacheFile, 'utf-8');+      value = JSON.parse(content);+      this.cache.set(key, value);+    } catch (error) {+      value = defaultValue;+    }+    return value;+  }++  async set(key, value) {+    const cacheFile = this.createCacheFileName(key);+    try {+      this.cache[key] = value;+      if (!existsSync(this.opts.baseDir)) {+        mkdirSync(this.opts.baseDir);+      }+      return writeFileAsync(cacheFile, JSON.stringify(value, null, ''), 'utf-8');+    } catch (e) {+      // could not write file+    }+  }++  async clear() {+    try {+      return await this.deleteDir_(this.opts.baseDir);+    } catch (e) {+      // doesn't exist+    }+  }++  createCacheFileName(key) {+    const keyHash = crypto.createHash('md5').update(key).digest('hex');+    return join(this.opts.baseDir, keyHash + '.json');+  }++  async deleteDir_(dir) {+    let entries = await readdirAsync(dir, {withFileTypes: true});+    await Promise.all(+      entries.map((entry) => {+        let fullPath = path.join(dir, entry.name);+        return entry.isDirectory() ? this.deleteDir_(fullPath) : unlinkAsync(fullPath);

This is potentially dangerous: directories can be cyclic. That said, I guess this is not a big deal and hard to fix. I'd consider using fs.rmdir which is experimental or rimraf. Or add a max depth.

Actually, if I understand correctly, nested directories are never created by this cache. I'd throw if there are non-files in a directory.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');+const crypto = require('crypto');++const path = require('path');+const readFileAsync = promisify(readFile);+const writeFileAsync = promisify(writeFile);+const readdirAsync = promisify(readdir);+const rmdirAsync = promisify(rmdir);+const unlinkAsync = promisify(unlink);++class FileSystemCache {+  static get(

get to me implies a singleton-like pattern, but this actually creates a new instance (also, you used create below for a similar pattern). Also, do you really need this, since it doesn't do much other than provide a default (which you can just do in the constructor).

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');+const {promisify} = require('util');

Do we still need this? Unless you want to support Node.js 9 and below (which is probably no longer needed... oldest supported LTS is 10), use fs.promises.

sebastianbenz

comment created time in 20 days

Pull request review commentampproject/amp-toolbox

Optimizer: cache runtime artifacts on filesystem

+/**+ * Copyright 2020 The AMP HTML Authors. All Rights Reserved.+ *+ * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ *+ *      http://www.apache.org/licenses/LICENSE-2.0+ *+ * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS-IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ * See the License for the specific language governing permissions and+ * limitations under the License.+ */+'use strict';+const {join} = require('path');+const {rmdir, readdir, readFile, writeFile, unlink, existsSync, mkdirSync} = require('fs');

Considering you have this many imports, I'd argue destructuring isn't a good idea, some of these are more readable as part of fs (e.g. fs.unlink vs unlink).

sebastianbenz

comment created time in 20 days

startedemersion/go-webdav

started time in 20 days

PR opened google/fscrypt

Fix build on Raspbian

Currently, trying to build on Raspbian fails with the following error:

$ go get github.com/google/fscrypt/cmd/fscrypt
# github.com/google/fscrypt/keyring
go/src/github.com/google/fscrypt/keyring/fs_keyring.go:231:6: constant 3225445912 overflows int
go/src/github.com/google/fscrypt/keyring/fs_keyring.go:235:7: constant 3225445913 overflows int
+1 -1

0 comment

1 changed file

pr created time in 20 days

push eventfstanis/fscrypt

Filip Stanis

commit sha 54d58063f7e910d21c9bf91db95e73efa7ab1457

cast FS_IOC_REMOVE_ENCRYPTION_KEY to uintptr

view details

push time in 20 days

fork fstanis/fscrypt

Go tool for managing Linux filesystem encryption

fork in 20 days

issue commentampproject/amp.dev

The CSS "transition" property is listed as supported by AMP for Email, but is not supported by Gmail

Seems this is a bug in Gmail where fractional duration is not allowed in transition. As a workaround, you can use milliseconds until it's fixed: transition: transform 300ms ease which should work.

(BTW you can file Gmail AMP bugs using the process outlined here)

CC @zhangsu

sharkcrayon

comment created time in a month

PR opened ampproject/amp.dev

Reviewers
Add 5 more ESPs that support AMP
  • dotdigital
  • Elastic Email
  • Mailrelay
  • Mapp Cloud
  • Tripolis
+10 -1

0 comment

1 changed file

pr created time in a month

create barnchfstanis/docs

branch : esps

created branch time in a month

PR opened jbowens/codenames

Adds Serbian wordlist

This adds ~400 words in Serbian. 🇷🇸

Thank you for making this project public and free!

+2 -1

0 comment

1 changed file

pr created time in a month

push eventfstanis/codenames

Filip Stanis

commit sha ff2c7db5ff72b24f820c3a9fdff9a68def56fae1

Adds Serbian wordlist

view details

push time in a month

push eventfstanis/codenames

Filip Stanis

commit sha 55460a234d4438f67e7719614095bc7748a7f48b

Add Serbian wordlist

view details

push time in a month

push eventfstanis/codenames

Filip Stanis

commit sha 79399d4f1ed80db845ac6d617a4dc30e39a19dce

Add Serbian

view details

push time in a month

fork fstanis/codenames

Play codenames using a TV or computer for the board

https://www.horsepaste.com/

fork in a month

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 1213bbc2f85fd3d3d9deaca291e2c3149591fdc4

Add component tests (#52)

view details

push time in a month

PR merged ampproject/amp-email-viewer

Add component tests
+283 -20

0 comment

18 changed files

fstanis

pr closed time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 7460192fee97460bc335f33a9b99b2e572372dcd

Fix proxy for POST body, add viewer render preprocessing to tests (#51)

view details

Filip Stanis

commit sha 39e7e3cbf9ef69a945cb35721d64c0e9d9e1c6df

add component tests

view details

push time in a month

delete branch fstanis/amp-email-viewer

delete branch : fix5

delete time in a month

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 7460192fee97460bc335f33a9b99b2e572372dcd

Fix proxy for POST body, add viewer render preprocessing to tests (#51)

view details

push time in a month

PR opened ampproject/amp-email-viewer

Add component tests
+283 -20

0 comment

18 changed files

pr created time in a month

create barnchfstanis/amp-email-viewer

branch : tests

created branch time in a month

create barnchfstanis/amp-email-viewer

branch : fix5

created branch time in a month

PR opened ampproject/amp.dev

Reviewers
Add MagNews to supported ESP list
+2 -0

0 comment

1 changed file

pr created time in a month

create barnchampproject/amp.dev

branch : fstanis-patch-1

created branch time in a month

pull request commentampproject/amp.dev

Add MoonMail as an esp supporting amp

Could you move it to come after MindBox to preserve alphabetic order? Otherwise all good.

alexandresaiz

comment created time in a month

pull request commentampproject/amphtml

Drive by PR: Allow new enterkeyhint attribute on input

IIRC only the attribute itself would get removed when not whitelisted. Probably a good idea to ban it from email spec until there's consensus on what to do with it.

cramforce

comment created time in a month

create barnchfstanis/amp-email-viewer

branch : safeguard

created branch time in a month

push eventampproject/amp-email-viewer

Filip Stanis

commit sha a2dc9f1f95ec531b402a4fa09c3e6b74b2a0958c

Create interactive demo page (#47)

view details

push time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha ea8a6c5ce48c82f530f7d8f2c670f218b3be7a0a

adds demo page

view details

push time in a month

issue commentampproject/amphtml

text-decoration-skip-ink CSS property to be allowed in inline styles

This might be an issue for some email clients (e.g. Gmail) since it's experimental / not widely supported.

danielstockton

comment created time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 3f0bb91d152e49c54b81af49112c64d276b224f1

Add amp-bind test, fix runtime, allow bootstrap without CSP (#50)

view details

Filip Stanis

commit sha fae575bc87399ccce6820a1027190fdd72a23acf

adds demo page

view details

push time in a month

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 3f0bb91d152e49c54b81af49112c64d276b224f1

Add amp-bind test, fix runtime, allow bootstrap without CSP (#50)

view details

push time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 1b7925d44e129ef323ae388a701af30d4214d983

add amp-bind test, fix runtime, allow bootstrap without CSP

view details

push time in a month

create barnchfstanis/amp-email-viewer

branch : runtimefix

created branch time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha e0a7906564f17310f9d65ba71412bff02ecf260b

adds demo page

view details

push time in a month

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha acbf23f613fda8843bb8d279f5b417b716688531

Adds structure for building the runtime locally (#49)

view details

Filip Stanis

commit sha 34dce5d89fddf499b1b62c2df121ba55de20b3cd

adds demo page

view details

push time in 2 months

push eventampproject/amp-email-viewer

Filip Stanis

commit sha acbf23f613fda8843bb8d279f5b417b716688531

Adds structure for building the runtime locally (#49)

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 03422c2007e3a26210a2019b86fcc1ebf26ac9b1

Adds structure for building the runtime locally (#49)

view details

Filip Stanis

commit sha fa76305efa8a09502b8feee17016303cc5ad4d50

adds demo page

view details

push time in 2 months

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 03422c2007e3a26210a2019b86fcc1ebf26ac9b1

Adds structure for building the runtime locally (#49)

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 53d038098e96f1ec842e3eab78fd092d05c668d3

adds runtime build

view details

push time in 2 months

create barnchfstanis/amp-email-viewer

branch : localbuild

created branch time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 6b76ba4e4f0fbc47619be7f46020c1f0f8e11251

Adds development mode, fixes bugs, ands ability to skip proxy (#48)

view details

Filip Stanis

commit sha 46d7009dbbda9973c5c1c4aabd5e2471e44e4af3

adds demo page

view details

push time in 2 months

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 6b76ba4e4f0fbc47619be7f46020c1f0f8e11251

Adds development mode, fixes bugs, ands ability to skip proxy (#48)

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 7b3fae76b431091795cc67fa5b42054e84091bb6

adds development mode and ability to skip proxy

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 060ad8f5ea2badae7bb6e9f8e55011d5fd0c478a

update deps (#46)

view details

Filip Stanis

commit sha 04e556d30fe60a47ca53916eb8fd4a3efdba507e

adds demo page

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 02ef32a85c2e09fe88eb5bd25b40e173d78a85e5

adds development mode and ability to skip proxy

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 060ad8f5ea2badae7bb6e9f8e55011d5fd0c478a

update deps (#46)

view details

Filip Stanis

commit sha 0181819cea21a51d82130a9fd5ed3158b93d51a4

adds development mode and ability to skip proxy

view details

push time in 2 months

PR closed ampproject/amp-email-viewer

Update dependency css-tree to ^1.0.0-alpha9

This PR contains the following updates:

Package Type Update Change
css-tree dependencies patch ^1.0.0-alpha.39 -> ^1.0.0-alpha9

Release Notes

<details> <summary>csstree/csstree</summary>

v1.0.0-alpha9

Compare Source

  • Fixed <angle> generic according to specs that allow a <number> equals to zero to be used as valid value (#​30)

v1.0.0-alpha8

Compare Source

  • Fixed Scanner#skip() issue method when cursor is moving to the end of source
  • Simplified Progid node
  • Changed behaviour for bad selector processing, now parsing fails instead of selector ignoring
  • Fixed <id-selector> generic syntax
  • Added q unit for <length> generic syntax
  • Refactored syntax parser (performance)
  • Reduced startup time by implementing lazy syntax parsing (default syntax doesn't parse on module load)
  • Updated syntax dictionaries and used mdn/data instead of Template:CSSData
  • Renamed syntax.stringify() method to syntax.translate()
  • Simplified generic syntax functions, those functions receive a single AST node for checking and should return true or false
  • Added exception for values that contains var(), those values are always valid for now
  • Added more tests and increase code coverage to 98.5%

v1.0.0-alpha7

Compare Source

  • Added support for explicit descendant combinator (>>)
  • Implemented Type and Universal type nodes
  • Improved Number parsing by including sign and exponent (#​26)
  • Parse before, after, first-letter and first-line pseudos with single colon as PseudoElement
  • Changed FunctionalPseudo node type to PseudoClass
  • Fixed attribute selector name parsing (namespace edge cases)
  • Fixed location calculation for specified offset when eof is reached
  • Added more non-standard colors (#​25)
  • Removed obsolete Syntax#getAll() method
  • Fixed various edge cases, code clean up and performance improvements

v1.0.0-alpha6

Compare Source

  • More accurate positions for syntax mismatch errors
  • Added apple specific font keywords (#​20)
  • Changed Property node stucture from object to string
  • Renamed Ruleset node type to Rule
  • Removed Argument node type
  • Fixed Dimension and Percentage position computation
  • Fixed bad selector parsing (temporary solution)
  • Fixed location computation for CSS with very long lines that may lead to really long parsing with positions:true (even freeze)
  • Fixed line and column computation for SyntaxMatch error
  • Improved performance of parsing and translation. Now CSSTree is under 10ms in PostCSS benchmark.

v1.0.0-alpha5

Compare Source

v1.0.0-alpha4

Compare Source

v1.0.0-alpha3

Compare Source

v1.0.0-alpha25

Compare Source

  • Parser
    • Added fallback node as argument to onParseError() handler
    • Fixed raw consuming in tolerant mode when selector is invalid (greedy consuming and redundant warnings)
    • Fixed exception in tolerant mode caused by unknown at-rule with unclosed block
    • Changed handling of semicolons:
      • Hanging semicolon inside declaration blocks raise an error or turns into a Raw node in tolerant mode instead of being ignored
      • Semicolon outside of declaration blocks opens a Rule node as part of selector instead of being ignored
    • Aligned parseAtrulePrelude behaviour to parseRulePrelude
      • Removed Raw node wraping into AtrulePrelude when parseAtrulePrelude is disabled
      • Removed error emitting when at-rule has a custom prelude customer but no prelude is found (it should be validated by a lexer later)
  • Generator
    • Fixed performance issue with translateWithSourceMap(), flattening the string (because of mixing building string and indexing into it) turned it into a quadratic algorithm (approximate numbers can be found in the quiz created by this case)
  • Added support for a single solidus hack for property()
  • Minor fixes for custom errors

v1.0.0-alpha24

Compare Source

  • Improved CSSTree to be stable for standart build-in objects extension (#​58)
  • Parser
    • Renamed rule's selector to prelude. The reasons: spec names this part so, and this branch can contain not only a selector (SelectorList) but also a raw payload (Raw). What's changed:
      • Renamed Rule.selector to Rule.prelude
      • Renamed parseSelector parser option to parseRulePrelude
      • Removed option for selector parse in SelectorList
  • Lexer
    • Fixed undefined positions in a error when match a syntax to empty or white space only value
    • Improved Lexer#checkStructure()
      • Return a warning as an object with node reference and message
      • No exception on unknown node type, return a warning instead

v1.0.0-alpha23

Compare Source

  • Fixed Tokenizer#getRawLength()'s false positive balance match to the end of input in some cases (#​56)
  • Rename walker's entry point methods to be the same as CSSTree exposed methods (i.e. walk(), walkUp() etc)
  • Rename at-rule's expression to prelude (since spec names it so)
    • AtruleExpression node type → AtrulePrelude
    • Atrule.expression field → Atrule.prelude
    • parseAtruleExpression parser's option → parseAtrulePrelude
    • atruleExpression parse context → atrulePrelude
    • atruleExpression walk context reference → atrulePrelude

v1.0.0-alpha22

Compare Source

  • Parser
    • Fixed exception on parsing of unclosed {}-block in tolerant mode
    • Added tolerant mode support for DeclarationList
    • Added standalone entry point, i.e. default parser can be used via require('css-tree/lib/parser') (#​47)
  • Generator
    • Changed generator to produce +n when AnPlusB.a is +1 to be "round-trip" with parser
    • Added standalone entry point, i.e. default generators can be used via require('css-tree/lib/generator')
  • Walker
    • Added standalone entry point, i.e. default walkers can be used via require('css-tree/lib/walker') (#​47)
  • Lexer
    • Added default keyword to the list of invalid values for <custom-ident> (since it reversed per spec)
  • Convertors (toPlainObject() and fromPlainObject()) moved to lib/convertor (entry point is require('css-tree/lib/convertor'))

v1.0.0-alpha21

Compare Source

  • Tokenizer
    • Added Raw token type
    • Improved tokenization of url() with raw as url to be more spec complient
    • Added Tokenizer#balance array computation on token layout
    • Added Tokenizer#getRawLength() to compute a raw length with respect of block balance
    • Added Tokenizer#getTokenStart(offset) method to get token start offset by token index
    • Added idx and balance fields to each token of Tokenizer#dump() method result
  • Parser
    • Added onParseError option
    • Reworked node parsers that consume a Raw node to use a new approach. Since now a Raw node builds in parser#Raw() function only
    • Changed semantic of parser#Raw(), it takes 5 parameters now (it might to be changed in future)
    • Changed parser#tolerantParse() to pass a start token index to fallback function instead of source offset
    • Fixed AtruleExpression consuming in tolerant mode
    • Atrule handler to convert an empty AtruleExpression node into null
    • Changed AtruleExpression handler to always return a node (before it could return a null in some cases)
  • Lexer
    • Fixed comma match node for # multiplier
    • Added reference name to SyntaxReferenceError
  • Additional fixes on custom errors
  • Reduced possible corruption of base config by syntax.fork()

v1.0.0-alpha20

Compare Source

  • Tokenizer
    • Added Atrule token type (<at-rule-token> per spec)
    • Added Function token type (<function-token> per spec)
    • Added Url token type
    • Replaced Tokenizer#getTypes() method with Tokenizer#dump() to get all tokens as an array
    • Renamed Tokenizer.TYPE.Whitespace to Tokenizer.TYPE.WhiteSpace
    • Renamed Tokenizer.findWhitespaceEnd() to Tokenizer.findWhiteSpaceEnd()
  • Parser
    • Added initial implementation of tollerant mode (turn on by passing tolerant: true option). In this mode parse errors are never occour and any invalid part of CSS turns into a Raw node. Current safe points: Atrule, AtruleExpression, Rule, Selector and Declaration. Feature is experimental and further improvements are planned.
    • Changed Atrule.expression to contain a AtruleExpression node or null only (other node types is wrapping into a AtruleExpression node)
    • Renamed AttributeSelector.operator to AttributeSelector.matcher
  • Generator
    • translate() method is now can take a function as second argument, that recieves every generated chunk. When no function is passed, default handler is used, it concats all the chunks and method returns a string.
  • Lexer
    • Used mdn/data package as source of lexer's grammar instead of local dictionaries
    • Added x unit to <resolution> generic type
    • Improved match tree:
      • Omited Group (sequences) match nodes
      • Omited empty match nodes (for terms with zero or more multipliers)
      • Added ASTNode node type to contain a reference to AST node
      • Fixed node duplication (uncompleted match were added to tree)
      • Added AST node reference in match nodes
      • Added comma match node by # multiplier
    • Grammar
      • Changed translate() function to get a handler as third argument (optional). That handler recieves result of node traslation and can be used for decoration purposes. See example
      • Added SyntaxParseError to grammar export
      • Reworked group and multipliers representation in syntax tree:
        • Replaced Sequence for Group node type (Sequence node type removed)
        • Added explicit boolean property for Group
        • Only groups can have a multiplier now (other node types is wrapping into a single term implicit group when multiplier is applied)
        • Renamed nonEmpty Group's property to disallowEmpty
        • Added optimisation for syntax tree by dropping redundant root Group when it contains a single Group term (return this Group as a result)
    • Changed lexer's match functionality
      • Changed Lexer#matchProperty() and Lexer#matchType() to return an object instead of match tree. A match tree stores in matched field when AST is matched to grammar successfully, otherwise an error in error field. The result object also has some methods to test AST node against a match tree: getTrace(), isType(), isProperty() and isKeyword()
      • Added Lexer#matchDeclaration() method
      • Removed Lexer#lastMatchError (error stores in match result object in error field)
    • Added initial implementation of search for AST segments (new lexer methods: Lexer#findValueSegments(), Lexer#findDeclarationValueSegments() and Lexer#findAllSegments)
    • Implemented SyntaxReferenceError for unknown property and type references
  • Renamed field in resulting object of property() function: variablecustom
  • Fixed issue with readonly properties (e.g. line and column) of Error and exception on attempt to write in iOS Safari

v1.0.0-alpha2

Compare Source

  • Parser
    • Added fallback node as argument to onParseError() handler
    • Fixed raw consuming in tolerant mode when selector is invalid (greedy consuming and redundant warnings)
    • Fixed exception in tolerant mode caused by unknown at-rule with unclosed block
    • Changed handling of semicolons:
      • Hanging semicolon inside declaration blocks raise an error or turns into a Raw node in tolerant mode instead of being ignored
      • Semicolon outside of declaration blocks opens a Rule node as part of selector instead of being ignored
    • Aligned parseAtrulePrelude behaviour to parseRulePrelude
      • Removed Raw node wraping into AtrulePrelude when parseAtrulePrelude is disabled
      • Removed error emitting when at-rule has a custom prelude customer but no prelude is found (it should be validated by a lexer later)
  • Generator
    • Fixed performance issue with translateWithSourceMap(), flattening the string (because of mixing building string and indexing into it) turned it into a quadratic algorithm (approximate numbers can be found in the quiz created by this case)
  • Added support for a single solidus hack for property()
  • Minor fixes for custom errors

v1.0.0-alpha19

Compare Source

  • Extended List class with new methods:
    • List#prepend(item)
    • List#prependData(data)
    • List#insertData(data)
    • List#insertList(list)
    • List#replace(item, itemOrList)

v1.0.0-alpha18

Compare Source

  • Added atrule walk context (#​39)
  • Changed a result of generate method for AnPlusB, AttributeSelector, Function, MediaFeature and Ratio (1e95877)
  • Fixed typo in List exception messages (@​strarsis, #​42)
  • Improved tokenizer to convert an input to a string

v1.0.0-alpha17

Compare Source

  • Implemented new concept of syntax
    • Changed main exports to expose a default syntax
    • Defined initial CSS syntax
    • Implemented createSyntax() method to create a new syntax from scratch
    • Implemented fork() method to create a new syntax based on given via extension
  • Parser
    • Implemented mediaQueryList and mediaQuery parsing contexts
    • Implemented CDO and CDC node types
    • Implemented additional declaration property prefix hacks (# and +)
    • Added support for UTF-16LE BOM
    • Added support for @font-face at-rule
    • Added chroma() to legacy IE filter functions
    • Improved HexColor to consume hex only
    • Improved support for \0 and \9 hacks (#​2)
    • Relaxed number check for Ratio terms
      • Allowed fractal values as a Ratio term
      • Disallowed zero number as a Ratio term
    • Changed important clause parsing
      • Allowed any identifier for important (to support hacks like !ie)
      • Store true for important field in case identifier equals to important and string otherwise
    • Fixed parse error formatted message rendering to take into account tabs
    • Removed exposing of Parser class
    • Removed readSelectorSequence(), readSequenceFallback() and readSelectorSequenceFallback methods
    • Used single universal sequence consumer for AtruleExpression, Selector and Value
  • Generator
    • Reworked generator to use auto-generated functions based on syntax definition (additional work to be done in next releases)
    • Implemented translateMarkup(ast, before, after) method for complex cases
    • Reworked translateWithSourceMap to be more flexible (based on translateMarkup, additional work to be done in next releases)
  • Walker
    • Reworked walker to use auto-generated function based on syntax definition (additional work to be done in next releases)
  • Lexer
    • Prepared for better extensibility (additional work to be done in next releases)
    • Implemented checkStructure(ast) method to check AST structure based on syntax definition
    • Update syntax dictionaries to latest mdn/data
      • Add missing <'offset-position'> syntax
      • Extended <position> property with -webkit-sticky (@​sergejmueller, #​37)
    • Improved mismatch error position
  • Implemented script (gen:syntax) to generate AST format reference page (docs/ast.md) using syntax definition

v1.0.0-alpha16

Compare Source

  • Exposed Parser class
  • Added startOffset option to Tokenizer (constructor and setSource() method)
  • Added fallback functions for default (readSequenceFallback) and selector (readSelectorSequenceFallback) sequence readers
  • Fixed edge cases for AnPlusB
  • Fixed wrong whitespace ignoring in Selector consumer

v1.0.0-alpha15

Compare Source

  • Fixed broken atruleExpression context
  • Fixed vendor prefix detection in keyword() and property()
  • Fixed property() to not lowercase custom property names
  • Added variable boolean flag in property() result
  • Renamed scanner into tokenizer
  • Ranamed syntax into lexer
  • Moved docs/*.html files to csstree/docs repo
  • Added element() function for Value context (-moz-element() supported as well)
  • Merged Universal node type into Type
  • Renamed node types:
    • Id -> IdSelector
    • Class -> ClassSelector
    • Type -> TypeSelector
    • Attribute -> AttributeSelector
    • PseudoClass -> PseudoClassSelector
    • PseudoElement -> PseudoElementSelector
    • Hash -> HexColor
    • Space -> WhiteSpace
    • An+B -> AnPlusB
  • Removed Progid node type
  • Relaxed MediaQuery consumer to not validate syntax on parse and to include whitespaces in children sequence as is
  • Added WhiteSpace.value property to store whitespace sequence
  • Implemented parser options to specify what should be parsed in details (when option is false some part of CSS represents as balanced Raw):
    • parseAtruleExpression – to parse at-rule expressions (true by default)
    • parseSelector – to parse rule's selector (true by default)
    • parseValue - to parse declaration's value (true by default)
    • parseCustomProperty – to parse value and fallback of custom property (false by default)
  • Changed tokenization to stick leading hyphen minus to identifier token
  • Changed selector parsing:
    • Don't convert spaces into descendant combinator
    • Don't validate selector structure on parsing (selectors may be checked by lexer later)
  • Initial refactoring of docs
  • Various improvements and fixes

v1.0.0-alpha14

Compare Source

  • Implemented DeclarationList, MediaQueryList, MediaQuery, MediaFeature and Ratio node types
  • Implemented declarationList context (useful to parse HTML style attribute content)
  • Implemented custom consumers for @import, @media, @page and @supports at-rules
  • Implemented atrule option for parse() config, is used for atruleExpession context to specify custom consumer for at-rule if any
  • Added Scanner#skipWS(), Scanner#eatNonWS(), Scanner#consume() and Scanner#consumeNonWS() helper methods
  • Added custom consumers for known functional-pseudos, consume unknown functional-pseudo content as balanced Raw
  • Allowed any PseudoElement to be a functional-pseudo (#​33)
  • Improved walker implementations to reduce GC thrashing by reusing cursors
  • Changed Atrule.block to contain a Block node type only if any
  • Changed Block.loc positions to include curly brackets
  • Changed Atrule.expression to store a null if no expression
  • Changed parser to use StyleSheet node type only for top level node (when context is stylesheet, that's by default)
  • Changed Parentheses, Brackets and Function consumers to use passed sequence reader instead of its own
  • Changed Value and AtruleExpression consumers to use common sequence reader (that reader was used by Value consumer before)
  • Changed default sequence reader to exclude storage of spaces around Comma
  • Changed processing of custom properties:
    • Consume declaration value as balanced Raw
    • Consume var() fallback value as balanced Raw
    • Validate first argument of var() starts with double dash
    • Custom property's value and fallback includes spaces around
  • Fixed Nth to have a loc property
  • Fixed SelectorList.loc and Selector.loc positions to exclude spaces
  • Fixed issue Browserify build fail with default-syntax.json is not found error (#​32, @​philschatz)
  • Disallowed Type selector starting with dash (parser throws an error in this case now)
  • Disallowed empty selectors for Rule (not sure if it's correct but looks reasonable)
  • Removed >> combinator support until any browser support (no signals about that yet)
  • Removed PseudoElement.legacy property
  • Removed special case for :before, :after, :first-letter and :first-line to represent them as PseudoElement, now those pseudos are represented as PseudoClass nodes
  • Removed deprecated Syntax#match() method
  • Parser was splitted into modules and related changes, one step closer to an extensible parser
  • Various fixes and improvements, all changes have negligible impact on performance

v1.0.0-alpha13

Compare Source

  • Changed location storing in SyntaxMatchError
    • Changed property to store mismatch offset to mismatchOffset
    • Changed offset property to store bad node offset in source CSS if any
    • Added loc property that stores bad node loc if any

v1.0.0-alpha12

Compare Source

  • Fixed Syntax#matchProperty() method to always return a positive result for custom properties since syntax is never defined for them (#​31)
  • Implemented fromPlainObject() and toPlainObject() to convert plain object to AST or AST to plain object (currently converts List <-> Array)

v1.0.0-alpha11

Compare Source

  • Added support for :matches(<selector-list>) (#​28)
  • Added support for :has(<relative-selector-list>)
  • Added support for ::slotted(<compound-selector>)
  • Implemented Brackets node type
  • Implemented basic support for at-rule inside rule block (#​24)
  • Renamed Selector node type to SelectorList
  • Renamed SimpleSelector node type to Selector
  • Renamed UnicodeRange.name property to UnicodeRange.value
  • Replaced Negation node type for regular PseudoClass
  • Unified name of node property to store nested nodes, it always children now:
    • StyleSheet.rules -> StyleSheet.children
    • SelectorList.selectors -> SelectorList.children
    • Block.declarations -> Block.children
    • *.sequence -> *.children
  • Fixed edge cases in parsing Hex and UnicodeRange when number not an integer
  • Changed nth- pseudos parsing
    • Implemented An+B node type to represent expressions like 2n + 1 or -3n
    • Fixed edge cases when a or b is not an integer
    • Changed odd and even keywords processing, keywords are storing as Identifier node type now
    • Changed Nth node type format to store a nth-query and an optional selector
    • Implemented of clause for nth- pseudos (a.e. :nth-child(2n + 1 of li, img))
    • Limited Nth parsing rules to :nth-child(), :nth-last-child(), :nth-of-type() and :nth-last-of-type() pseudos
  • Changed the way to store locations
    • Renamed info node property to loc
    • Changed format of loc to store start and end positions

v1.0.0-alpha10

Compare Source

  • Reworked Scanner to be a single point to its functionality
  • Exposed Scanner class to be useful for external projects
  • Changed walk() function behaviour to traverse AST nodes in natural order
  • Implemented walkUp() function to traverse AST nodes from deepest to parent (behaves as walk() before)

</details>


Renovate configuration

:date: Schedule: At any time (no schedule defined).

:vertical_traffic_light: Automerge: Disabled by config. Please merge this manually once you are satisfied.

:recycle: Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

:no_bell: Ignore: Close this PR and you won't be reminded about this update again.


  • [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

This PR has been generated by WhiteSource Renovate. View repository job log here.

+1 -1

1 comment

1 changed file

renovate-bot

pr closed time in 2 months

pull request commentampproject/amp-email-viewer

Update dependency css-tree to ^1.0.0-alpha9

Done in #46

renovate-bot

comment created time in 2 months

delete branch fstanis/amp-email-viewer

delete branch : deps

delete time in 2 months

push eventampproject/amp-email-viewer

Filip Stanis

commit sha 060ad8f5ea2badae7bb6e9f8e55011d5fd0c478a

update deps (#46)

view details

push time in 2 months

create barnchfstanis/amp-email-viewer

branch : fixes

created branch time in 2 months

issue commentampproject/amphtml

amp4email scrollTo doesn't work

Unfortunately, scrolling in emails is a hard problem (this is a big issue for lightbox: #23170). The email is always fully in viewport, since it's rendered inside an iframe, so you'd need to scroll the parent page which is on a different origin.

lichinshao

comment created time in 2 months

issue commentampproject/amphtml

AMP4Email: Standardize email meta whitelists

scrollTo should probably not be in this list, since it doesn't really work in an iframe (context: #27460).

choumx

comment created time in 2 months

PR opened ampproject/amp-email-viewer

Create interactive demo page
+281 -65

0 comment

12 changed files

pr created time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha 3840a56eda105540682514a08bc9403e7f80edd8

Add interactive demo page

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha b6aa8e5791ebbc20136599c4f45818ed867c7747

Add interactive demo page

view details

push time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha fd70e1b49ba3751df9a08b3ab967f62359d422ee

Add interactive demo page

view details

push time in 2 months

PR opened ampproject/amp-email-viewer

Update all dependencies
+20 -20

0 comment

2 changed files

pr created time in 2 months

create barnchfstanis/amp-email-viewer

branch : deps

created branch time in 2 months

push eventfstanis/amp-email-viewer

Filip Stanis

commit sha d59d920368609648af1272ce1ea7b2f46f09740d

Add interactive demo page

view details

push time in 2 months

create barnchfstanis/amp-email-viewer

branch : demo

created branch time in 2 months

PR opened hteumeuleu/caniemail

Update AMP support

Update support status in Gmail and Outlook based on most recent public information.

+81 -81

0 comment

1 changed file

pr created time in 2 months

push eventfstanis/caniemail

Filip Stanis

commit sha c34685bdc7b51d592e58b01399c9fe3395fe0239

Update AMP support

view details

push time in 2 months

push eventfstanis/caniemail

Filip Stanis

commit sha 8e5a841b63afd5ae538e08e7508c4a3cc97c0b9f

Update AMP support

view details

push time in 2 months

push eventampproject/wg-amp4email

Filip Stanis

commit sha 35fa3cfa28a29f2cf7a306ad05e517d055b2ab6d

Update members

view details

push time in 2 months

issue openedampproject/amp.dev

amp-carousel not listed under supported components for AMP for Email

In the AMP Component Catalogue and the sidebar:

image

Likely related to the fact email doesn't support 0.2 but supports 0.1.

created time in 2 months

more