Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@ module.exports = {
requireConfigFile: false,
},
rules: {
'import/extensions': ['error', { js: 'always' }], // require js file extensions in imports
// Globally require .js file extensions in imports
'import/extensions': ['error', { js: 'always' }],
'linebreak-style': ['error', 'unix'], // enforce unix linebreaks
'no-param-reassign': [2, { props: false }], // allow modifying properties of param
},
overrides: [
{
files: ['scripts/**/*.mjs', 'scripts/**/*.js'],
env: { node: true },
rules: {
// Allow .mjs extensions in build scripts only
'import/extensions': ['error', { js: 'always', mjs: 'always' }],
},
},
],
};
10 changes: 1 addition & 9 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@ jobs:
- run: npm ci
- run: npm run lint
- run: npm run test
- run: npm run build
- name: Check gzipped dist size
run: |
gz_size=$(gzip -c dist/faintly.js | wc -c)
echo "Gzipped size: ${gz_size} bytes"
if [ "$gz_size" -gt 5120 ]; then
echo "Error: dist/faintly.js gzipped size ${gz_size} exceeds 5KB (5120 bytes)"
exit 1
fi
- run: npm run build:strict
- name: Commit dist if changed
run: |
git config user.name "github-actions[bot]"
Expand Down
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ Authoritative guide for AI/code agents contributing to this repository.
- **Lint (auto-fix)**: `npm run lint:fix`
- **Unit tests + coverage**: `npm test`
- **Performance tests**: `npm run test:perf`
- **Build bundle**: `npm run build` → outputs `dist/faintly.js`
- **Build (watch)**: `npm run build:watch`
- **Build bundle**: `npm run build` → outputs `dist/faintly.js` and prints gzipped size (warns if over limit)
- **Build (strict)**: `npm run build:strict` → fails if gzipped size exceeds 5120 bytes
- **Clean**: `npm run clean`

### Tests and coverage
Expand Down Expand Up @@ -49,7 +49,7 @@ Authoritative guide for AI/code agents contributing to this repository.

### CI behavior (GitHub Actions)
- Workflow: `.github/workflows/main.yaml` runs on pull requests (open/sync/reopen).
- Steps: checkout → Node 20 → `npm ci` → `npm run lint` → `npm test` → `npm run build` → gzip size check (<= 5120 bytes).
- Steps: checkout → Node 20 → `npm ci` → `npm run lint` → `npm test` → `npm run build:strict`.
- The workflow will attempt to commit updated `dist/` artifacts back to the PR branch if they changed.

### Repo layout
Expand All @@ -63,7 +63,7 @@ Authoritative guide for AI/code agents contributing to this repository.
2. Make focused edits under `src/` and relevant tests under `test/`.
3. Run `npm run lint:fix` then `npm run lint` and resolve any remaining issues.
4. Run `npm test` and ensure coverage stays at 100%.
5. Run `npm run build` and verify `dist/faintly.js` updates (if source changed).
5. Run `npm run build:strict` and verify `dist/faintly.js` updates (if source changed).
6. Ensure gzipped size of `dist/faintly.js` remains <= 5120 bytes (CI will enforce).
7. Update `README.md` if you change public behavior or usage.
8. Commit changes; open a PR. CI will validate and may commit updated `dist/` to the PR branch.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Faintly supports the following directives.
* `data-fly-repeat` - Repeat an element for each item of a collection. Attribute value should be an expression that resolves to a collection of Nodes/Elements.
* `data-fly-attributes` - Set attributes on the element. Attribute value should be an expression that resolves to a collection of key/value pairs.
* `data-fly-content` - Replace the elements content/children. Attribute value should be an expression that resolves to a Node/Element/String, or a collection there-of.
* Content has precedence over include: if both `data-fly-content` and `data-fly-include` are present on the same element, only content is executed.
* `data-fly-include` - Replace the elements content/children with another template. Attribute value can be:
* the name of a template: `data-fly-include="a-template-name"`
* the absolute path to a template file: `data-fly-include="/blocks/some-block/some-template.html"`
Expand All @@ -89,11 +90,15 @@ Faintly supports the following directives.
> Directives are evaluated in a fixed order, as listed above, regardless of the order you place them on the element.
>
> This means, for example, that the context item set in `data-fly-repeat` can be used in `data-fly-include` on the same element, but not in a `data-fly-test`.
>
> When `data-fly-include` runs, the included template is fully rendered before being inserted and the element's children are not traversed again. This prevents double-processing. Conversely, when `data-fly-content` runs, the injected nodes are traversed so that any directives/expressions inside them are processed.

## Expressions

Faintly supports a simple expression syntax for resolving data from the rendering context. It supports only object dot-notation, but will call (optionally async) functions as well. This means that if you need to do something that can't be expressed in dot-notation, then you need to define a custom function for it, and add that function to the rendering context.

For `data-fly-include`, HTML text, and normal attributes, wrap your expression in `${}`.
For `data-fly-include`, HTML text, and normal attributes, wrap your expression in `${}`.

Escaping: use a leading backslash to prevent evaluation of an expression in text/attributes, e.g. `\${some.value}` will remain literal `${some.value}`.

In all other `data-fly-*` attributes, just set the expression directly as the attribute value, no wrapping needed.
8 changes: 5 additions & 3 deletions dist/faintly.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var dp = new DOMParser();
async function resolveTemplate(context) {
context.template = context.template || {};
context.template.path = context.template.path || `${context.codeBasePath}/blocks/${context.blockName}/${context.blockName}.html`;
const templateId = `faintly-template-${context.template.path}#${context.template.name || ""}`.toLowerCase().replace(/[^0-9a-z]/gi, "-");
const templateId = `faintly-template-${context.template.path}#${context.template.name || ""}`.toLowerCase().replace(/[^0-9a-z]/g, "-");
let template = document.getElementById(templateId);
if (!template) {
const resp = await fetch(context.template.path);
Expand All @@ -12,7 +12,7 @@ async function resolveTemplate(context) {
const templateDom = dp.parseFromString(markup, "text/html");
templateDom.querySelectorAll("template").forEach((t) => {
const name = t.getAttribute("data-fly-name") || "";
t.id = `faintly-template-${context.template.path}#${name}`.toLowerCase().replace(/[^0-9a-z]/gi, "-");
t.id = `faintly-template-${context.template.path}#${name}`.toLowerCase().replace(/[^0-9a-z]/g, "-");
document.body.append(t);
});
}
Expand Down Expand Up @@ -198,7 +198,9 @@ async function processNode(node, context) {
const repeated = await processRepeat(node, context);
if (repeated) return;
await processAttributes(node, context);
processChildren = await processContent(node, context) || await processInclude(node, context) || true;
const hadContent = await processContent(node, context);
const hadInclude = hadContent ? false : await processInclude(node, context);
processChildren = !hadInclude;
await resolveUnwrap(node, context);
} else if (node.nodeType === Node.TEXT_NODE) {
await processTextExpressions(node, context);
Expand Down
Loading