diff --git a/.github/READ_THIS.md b/.github/READ_THIS.md new file mode 100644 index 00000000000..41ea05d6311 --- /dev/null +++ b/.github/READ_THIS.md @@ -0,0 +1,29 @@ +# READ THIS + +_not named README because GitHub will display a README.md from this directory at the root_ + +## Workflows + +## Guidelines + +### Avoid caches + +We first disabled caches for publish due to the risk of cache poisoning. + +Later we found caches were allowing CI to pass when updating actions. They would +later fail when the caches were cycled. To avoid this, and after testing to ensure +the slowdown was acceptable, we have disabled all caching on actions/setup-node +and pnpm/action-setup. + +### Actions must be pinned to shas + +Actions are pinned to shas and this is a requirement of the GitHub organization. +This prevents the risk of a malicious action being used -- as releases can be reset +to different shas. + +To update actions to shas run `pnpm actions-up`. + +### Run Zizmor + +The workflow-lint.yml workflow runs [Zizmor](https://github.com/zizmorcore/zizmor) +on all workflows and actions to statically check for insecure patterns. diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b5cfa8f9fdb..cb111598d02 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -2,40 +2,43 @@ name: Setup node and pnpm description: Setup node and install dependencies using pnpm inputs: use_lockfile: - description: 'Whether to use the lockfile vs latest floating dependencies' + description: "Whether to use the lockfile vs latest floating dependencies" required: false - default: 'true' + default: "true" node-version: - description: 'The node version to use' + description: "The node version to use" required: false - default: '20' + default: "20" use-node-modules-cache: - description: 'Whether to use the node-modules cache' + description: "Whether to use the node-modules cache" required: false - default: 'true' + default: "false" # We don't want to use the cache. It causes false passes of CI when updating actions and workflows. runs: - using: 'composite' + using: "composite" steps: - name: Install pnpm uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 with: + cache: false + version: 10.33.2 run_install: false - name: Install Node.js (WITH cache) if: ${{ inputs.use-node-modules-cache == 'true' }} uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: - node-version: '${{ inputs.node-version }}' - registry-url: 'https://registry.npmjs.org' + node-version: "${{ inputs.node-version }}" + registry-url: "https://registry.npmjs.org" cache: pnpm - name: Install Node.js (NO cache) if: ${{ inputs.use-node-modules-cache != 'true' }} uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: - node-version: '${{ inputs.node-version }}' - registry-url: 'https://registry.npmjs.org' + package-manager-cache: false + node-version: "${{ inputs.node-version }}" + registry-url: "https://registry.npmjs.org" - run: pnpm install ${INSTALL_OPTIONS} env: diff --git a/.github/workflows/ci-jobs.yml b/.github/workflows/ci-jobs.yml index 73f644736d9..34f1f04b741 100644 --- a/.github/workflows/ci-jobs.yml +++ b/.github/workflows/ci-jobs.yml @@ -260,7 +260,7 @@ jobs: name: Perf script still works runs-on: ubuntu-latest timeout-minutes: 10 - if: ${{ !startsWith(github.ref, 'refs/tags/') }} # Don't run on tags + if: ${{ github.event_name == 'pull_request' || github.ref == 'refs/heads/main' }} # Only run on PRs and main steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c90741abdec..76ef654e54e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Generate Docs on: push: tags: - - 'v*' + - "v*" workflow_dispatch: inputs: ref: @@ -10,9 +10,9 @@ on: required: true description: Tag name or branch or ref to generate docs for -permissions: +permissions: contents: read - + jobs: generate-and-pr: runs-on: ubuntu-latest @@ -42,12 +42,14 @@ jobs: - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 name: Install pnpm with: + cache: false + version: 10.33.2 run_install: false - name: Set up Node.js uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: - node-version: '20' + node-version: "20" package-manager-cache: false - name: Install dependencies for ember-jsonapi-docs diff --git a/.github/workflows/publish-to-npm.yml b/.github/workflows/publish-to-npm.yml index 8ad17dec492..5a21e12e4b9 100644 --- a/.github/workflows/publish-to-npm.yml +++ b/.github/workflows/publish-to-npm.yml @@ -24,7 +24,7 @@ jobs: - uses: ./.github/actions/setup with: node-version: 20 - use-node-modules-cache: false + use-node-modules-cache: false # Absolutely no cache should be used when publishing due to the potential of cache-poisoning. - name: Update npm run: npm install -g npm@latest # npm >= 11.5.1 is needed - name: Build for Publish (Alpha) diff --git a/.github/workflows/smoke-test-app-template-updates.yml b/.github/workflows/smoke-test-app-template-updates.yml index 8b07719343a..874b567c609 100644 --- a/.github/workflows/smoke-test-app-template-updates.yml +++ b/.github/workflows/smoke-test-app-template-updates.yml @@ -3,7 +3,7 @@ name: Update smoke-test templates on: workflow_dispatch: schedule: - - cron: '0 9 * * 1' # weekly on Monday; job will self-gate to every 10 weeks + - cron: "0 9 * * 1" # weekly on Monday; job will self-gate to every 10 weeks permissions: contents: read @@ -43,9 +43,13 @@ jobs: - name: Setup Node.js uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: + package-manager-cache: false node-version: 20 - name: Setup pnpm - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 + uses: pnpm/action-setup@91ab88e2619ed1f46221f0ba42d1492c02baf788 # v6.0.6 + with: + cache: false + version: 10.33.2 - name: Generate ember-test-app using classic blueprint run: | set -euo pipefail @@ -61,7 +65,7 @@ jobs: run: pnpm install --no-frozen-lockfile - name: Create PR - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.SMOKE_TEST_TEMPLATE_GEN_TOKEN }} branch: smoke-tests/update-app-template @@ -86,9 +90,13 @@ jobs: - name: Setup Node.js uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: + package-manager-cache: false node-version: 20 - name: Setup pnpm - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 + uses: pnpm/action-setup@91ab88e2619ed1f46221f0ba42d1492c02baf788 # v6.0.6 + with: + cache: false + version: 10.33.2 - name: Generate v2-app-template run: | set -euo pipefail @@ -103,7 +111,7 @@ jobs: run: pnpm install --no-frozen-lockfile - name: Create PR - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.SMOKE_TEST_TEMPLATE_GEN_TOKEN }} branch: smoke-tests/update-v2-app-template diff --git a/CHANGELOG.md b/CHANGELOG.md index ee14276c1c0..e2ad657e834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Ember Changelog +## v7.1.0 (June 22, 2026) + +- [#21068](https://github.com/emberjs/ember.js/pull/21068) [FEATURE] Build in the `{{on}}` modifier as a keyword in strict-mode templates per [RFC# 997](https://rfcs.emberjs.com/id/0997-make-on-built-in). +- [#21299](https://github.com/emberjs/ember.js/pull/21299) [FEATURE] Build in the `{{fn}}` helper as a keyword in strict-mode templates per [RFC #998](https://rfcs.emberjs.com/id/0998-make-fn-built-in). +- [#21230](https://github.com/emberjs/ember.js/pull/21230) / [#21343](https://github.com/emberjs/ember.js/pull/21343) [FEATURE] Add a built-in `(element)`/ `{{element}}` helper for dynamic tag names in strict-mode templates per [RFC #389](https://rfcs.emberjs.com/id/0389-dynamic-tag-names). +- [#21334](https://github.com/emberjs/ember.js/pull/21334) [FEATURE] Build in the `{{hash}}` helper as a keyword in strict-mode templates per [RFC# 999](https://rfcs.emberjs.com/id/0999-make-hash-built-in). +- [#21336](https://github.com/emberjs/ember.js/pull/21336) [FEATURE] Build in the `{{array}}` helper as a keyword in strict-mode templates per [RFC#1000](https://rfcs.emberjs.com/id/1000-make-array-built-in). +- [#21337](https://github.com/emberjs/ember.js/pull/21337) [FEATURE] Build in `{{and}}`, `{{or}}`, `{{not}}` helpers as keywords in strict-mode templates per [RFC #562](https://rfcs.emberjs.com/id/0562-add-logical-operators/). +- [#21339](https://github.com/emberjs/ember.js/pull/21339) [FEATURE] Build in `{{eq}}` and `{{neq}}` helpers as keywords in strict-mode templates per [RFC #560](https://rfcs.emberjs.com/id/0560-add-equality-operators/). +- [#21342](https://github.com/emberjs/ember.js/pull/21342) [FEATURE] Build in the `{{lt}}`, `{{lte}}`, `{{gt}}`, `{{gte}}` helpers as keywords in strict-mode templates per [RFC# 561](https://rfcs.emberjs.com/id/0561-add-numeric-comparison-operators). +- [#21373](https://github.com/emberjs/ember.js/pull/21373) [BUGFIX] Fix newly added keywords polluting the JS namespace +- [#21232](https://github.com/emberjs/ember.js/pull/21232) [INTERNAL] Clean up scope bag, wire format, and debug render tree +- [#21350](https://github.com/emberjs/ember.js/pull/21350) [INTERNAL] Remove barrel file imports from internal code for better tree-shaking +- [#21402](https://github.com/emberjs/ember.js/pull/21402) [INTERNAL] Do not use any caches on release and lock publishing of `ember-source` to `npm` to require approval from select persons. +- [#21379](https://github.com/emberjs/ember.js/pull/21379) [CLEANUP] Remove old Component Lookup +- [#21468](https://github.com/emberjs/ember.js/pull/21468) [DOC] Update API docs to use template tag where appropriate + ## v7.0.0 (May 11, 2026) - [#21240](https://github.com/emberjs/ember.js/pull/21240) [CLEANUP] Remove deprecated amd bundles and `use-ember-modules` optional feature per [RFC #1101](https://rfcs.emberjs.com/id/1101-deprecate-ember-vendor-bundles). diff --git a/package.json b/package.json index 51e8d17d769..2bc96fc1282 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-source", - "version": "7.1.0-alpha.1", + "version": "7.1.0", "description": "A JavaScript framework for creating ambitious web applications", "keywords": [ "ember-addon" diff --git a/packages/@ember/-internals/glimmer/index.ts b/packages/@ember/-internals/glimmer/index.ts index 66afa93812e..abb5506b78f 100644 --- a/packages/@ember/-internals/glimmer/index.ts +++ b/packages/@ember/-internals/glimmer/index.ts @@ -1,6 +1,23 @@ /** [Glimmer](https://github.com/tildeio/glimmer) is a templating engine used by Ember.js that is compatible with a subset of the [Handlebars](http://handlebarsjs.com/) syntax. + Ember ships with two types of JavaScript classes for components: + + 1. Glimmer components, imported from `@glimmer/component`, which are the + default component's for Ember Octane (3.15) and more recent editions. + 2. Classic components, imported from `@ember/component`, which were the + default for older editions of Ember (pre 3.15) but are still supported. + + Below is the documentation for Classic components. If you are looking for the + API documentation for Template-only or Glimmer components, it is [available + here](/ember/release/modules/@glimmer%2Fcomponent). + + Note: Prior to Ember 6.8, by default, components were authored in paired `.hbs` and `.js` + files. This is still supported, but the default authoring format is now `.gjs` or "template tag". + The documentation for `@ember/component` still refers to the older authoring format. To read about + the new authoring format, see the + [Glimmer Component API documentation](/ember/release/modules/@glimmer%2Fcomponent). + ### Showing a property Templates manage the flow of an application's UI, and display state (through @@ -98,16 +115,24 @@ When designing components `{{yield}}` is used to denote where, inside the component's template, an optional block passed to the component should render: - ```app/templates/application.hbs - - First name: - + ```app/templates/application.gjs + import LabeledTextField from '../components/labeled-textfield'; + + ``` - ```app/components/labeled-textfield.hbs - + ```app/components/labeled-textfield.gjs + import { Input } from '@ember/component'; + + ``` Result: @@ -120,19 +145,34 @@ Additionally you can `yield` properties into the context for use by the consumer: - ```app/templates/application.hbs - - {{#if validationError}} -

{{validationError}}

- {{/if}} - First name: -
+ ```app/templates/application.gjs + import Component from '@glimmer/component'; + import LabeledTextField from '../components/labeled-textfield'; + + export default class Application extends Component { + firstNameValidator = (value) => { + // validates + } + + + } ``` - ```app/components/labeled-textfield.hbs - + ```app/components/labeled-textfield.gjs + import { Input } from '@ember/component'; + + ``` Result: @@ -146,17 +186,23 @@ `yield` can also be used with the `hash` helper: - ```app/templates/application.hbs - - Start date: {{range.start}} - End date: {{range.end}} - + ```app/templates/application.gjs + import DateRanges from '../components/date-ranges'; + + ``` - ```app/components/date-ranges.hbs -
- {{yield (hash start=@value.start end=@value.end)}} -
+ ```app/components/date-ranges.gjs + ``` Result: @@ -169,19 +215,25 @@ ``` Multiple values can be yielded as block params: - - ```app/templates/application.hbs - -

{{title}}

-

{{subtitle}}

- {{body}} -
- ``` - - ```app/components/banner.hbs -
- {{yield "Hello title" "hello subtitle" "body text"}} -
+ + ```app/templates/application.gjs + import Banner from '../components/banner'; + + + ``` + + ```app/components/banner.gjs + ``` Result: @@ -198,15 +250,19 @@ Multiple components can be yielded with the `hash` and `component` helper: - ```app/templates/application.hbs - - Banner title - Banner subtitle - A load of body text - + ```app/templates/application.gjs + import Banner from '../components/banner'; + + ``` - ```app/components/banner.js + ```app/components/banner.gjs import Title from './banner/title'; import Subtitle from './banner/subtitle'; import Body from './banner/body'; @@ -215,19 +271,19 @@ Title = Title; Subtitle = Subtitle; Body = Body; + + } ``` - ```app/components/banner.hbs -
- {{yield (hash - Title=this.Title - Subtitle=this.Subtitle - Body=(component this.Body defaultArg="some value") - )}} -
- ``` - Result: ```html @@ -240,12 +296,16 @@ A benefit of using this pattern is that the user of the component can change the order the components are displayed. - ```app/templates/application.hbs - - Banner subtitle - Banner title - A load of body text - + ```app/templates/application.gjs + import Banner from '../components/banner'; + + ``` Result: @@ -261,27 +321,33 @@ Another benefit to using `yield` with the `hash` and `component` helper is you can pass attributes and arguments to these components: - ```app/templates/application.hbs - - Banner subtitle - Banner title - A load of body text - + ```app/templates/application.gjs + import Banner from '../components/banner'; + + ``` - ```app/components/banner/subtitle.hbs + ```app/components/banner/subtitle.gjs {{!-- note the use of ..attributes --}}

{{yield}}

``` - ```app/components/banner/title.hbs - {{#if (eq @variant "loud")}} + ```app/components/banner/title.gjs + ``` Result: @@ -307,36 +373,28 @@ This component is invoked with a block: ```handlebars - {{#my-component}} + Hi Jen! - {{/my-component}} + ``` This component is invoked without a block: ```handlebars - {{my-component}} - ``` - - Using angle bracket invocation, this looks like: - - ```html - Hi Jen! {{! with a block}} - ``` - - ```html - {{! without a block}} + ``` This is useful when you want to create a component that can optionally take a block and then render a default template when it is not invoked with a block. - ```app/templates/components/my-component.hbs - {{#if (has-block)}} - Welcome {{yield}}, we are happy you're here! - {{else}} - Hey you! You're great! - {{/if}} + ```app/components/my-component.gjs + ``` @method has-block @@ -350,26 +408,10 @@ `{{(has-block-params)}}` indicates if the component was invoked with block params. This component is invoked with block params: - - ```handlebars - {{#my-component as |favoriteFlavor|}} - Hi Jen! - {{/my-component}} - ``` - - This component is invoked without block params: - + ```handlebars - {{#my-component}} - Hi Jenn! - {{/my-component}} - ``` - - With angle bracket syntax, block params look like this: - - ```handlebars - Hi Jen! + Hi Jen! ``` @@ -377,21 +419,23 @@ ```handlebars - Hi Jen! + Hi Jen! ``` This is useful when you want to create a component that can render itself differently when it is not invoked with block params. - ```app/templates/components/my-component.hbs - {{#if (has-block-params)}} - Welcome {{yield this.favoriteFlavor}}, we're happy you're here and hope you - enjoy your favorite ice cream flavor. - {{else}} - Welcome {{yield}}, we're happy you're here, but we're unsure what - flavor ice cream you would enjoy. - {{/if}} + ```app/components/my-component.gjs + ``` @method has-block-params diff --git a/packages/@ember/-internals/glimmer/lib/component.ts b/packages/@ember/-internals/glimmer/lib/component.ts index f61e446f829..b4f64601824 100644 --- a/packages/@ember/-internals/glimmer/lib/component.ts +++ b/packages/@ember/-internals/glimmer/lib/component.ts @@ -230,6 +230,12 @@ declare const SIGNATURE: unique symbol; API documentation for Template-only or Glimmer components, it is [available here](/ember/release/modules/@glimmer%2Fcomponent). + Note: Prior to Ember 6.8, by default, components were authored in paired `.hbs` and `.js` + files. This is still supported, but the default authoring format is now `.gjs` or "template tag". + The documentation for `@ember/component` still refers to the older authoring format. To read about + the new authoring format, see the + [Glimmer Component API documentation](/ember/release/modules/@glimmer%2Fcomponent). + ## Defining a Classic Component If you want to customize the component in order to handle events, transform @@ -256,7 +262,7 @@ declare const SIGNATURE: unique symbol; And then use it in the component's template: - ```app/templates/components/person-profile.hbs + ```app/components/person-profile.hbs

{{this.displayName}}

{{yield}} ``` @@ -644,7 +650,7 @@ declare const SIGNATURE: unique symbol; The `layout` property should be set to the default export of a template module, which is the name of a template file without the `.hbs` extension. - ```app/templates/components/person-profile.hbs + ```app/components/person-profile.hbs

Person's Title

{{yield}}
``` diff --git a/packages/@ember/-internals/glimmer/lib/components/input.ts b/packages/@ember/-internals/glimmer/lib/components/input.ts index cd9898555dc..07f67109a83 100644 --- a/packages/@ember/-internals/glimmer/lib/components/input.ts +++ b/packages/@ember/-internals/glimmer/lib/components/input.ts @@ -67,8 +67,12 @@ if (hasDOM) { /** The `Input` component lets you create an HTML `` element. - ```handlebars - + ```gjs + import { Input } from '@ember/component'; + + ``` creates an `` element with `type="text"` and value set to 987. diff --git a/packages/@ember/-internals/glimmer/lib/components/link-to.ts b/packages/@ember/-internals/glimmer/lib/components/link-to.ts index 4f11670388c..5b69b46e1f6 100644 --- a/packages/@ember/-internals/glimmer/lib/components/link-to.ts +++ b/packages/@ember/-internals/glimmer/lib/components/link-to.ts @@ -50,10 +50,14 @@ function isQueryParams(value: unknown): value is QueryParams { supplied model to the route as its `model` context of the route. The block for `LinkTo` becomes the contents of the rendered element: - ```handlebars - - Great Hamster Photos - + ```gjs + import { LinkTo } from '@ember/routing'; + + ``` This will result in: diff --git a/packages/@ember/-internals/glimmer/lib/components/textarea.ts b/packages/@ember/-internals/glimmer/lib/components/textarea.ts index 3ab5f40c178..874b0ccd0a4 100644 --- a/packages/@ember/-internals/glimmer/lib/components/textarea.ts +++ b/packages/@ember/-internals/glimmer/lib/components/textarea.ts @@ -15,7 +15,11 @@ import { type OpaqueInternalComponentConstructor, opaquify } from './internal'; This template: ```handlebars -