diff --git a/.eslintrc.js b/._eslintrc.js
similarity index 99%
rename from .eslintrc.js
rename to ._eslintrc.js
index fb228fe9dea..6194b419432 100644
--- a/.eslintrc.js
+++ b/._eslintrc.js
@@ -100,7 +100,7 @@ module.exports = {
env: {
browser: true,
node: false,
- es6: true,
+ es2022: true,
},
overrides: [
{
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 83ff84998f3..00000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,54 +0,0 @@
-# unconventional js
-**/blueprints/*/*files/
-**/vendor/
-**/*.d.ts
-
-# compiled output
-**/dist/
-**/dist-control/
-**/dist-experiment/
-**/dist-tests/
-**/dist-test/
-**/tmp/
-**/unstable-preview-types/
-/packages/-ember-data/docs/
-/packages/tracking/
-/packages/request/
-/packages/store/addon/
-/packages/adapter/addon/
-/packages/serializer/addon/
-/packages/model/addon/
-/packages/json-api/addon/
-/packages/graph/addon/
-/packages/legacy-compat/addon/
-/packages/request-utils/addon/
-/packages/rest/addon/
-/packages/active-record/addon/
-/packages/data-worker/addon/
-/packages/core/
-/packages/holodeck/
-/packages/schema-record/
-/packages/schema/
-/tests/warp-drive__schema/
-/packages/diagnostic/
-
-**/DEBUG/
-
-# dependencies
-**/bower_components/
-**/node_modules/
-.broccoli-cache
-
-# misc
-**/coverage/
-!.*
-/.yarn/
-/.git/
-
-# ember-try
-**/.node_modules.ember-try/
-**/bower.json.ember-try
-**/package.json.ember-try
-
-# ember-data
-**/node-tests/fixtures/
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index c99d1fcd2e5..457573793c2 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -57,6 +57,12 @@ runs:
with:
bun-version: latest
+ - name: 'Setup local TurboRepo server'
+ if: ${{ inputs.repo-token }}
+ uses: felixmosh/turborepo-gh-artifacts@v2
+ with:
+ repo-token: ${{ inputs.repo-token }}
+
- name: Configure Parallel Builds
if: ${{ inputs.parallel-build == 'true' }}
shell: bash
diff --git a/.github/workflows/alpha-release.yml b/.github/workflows/alpha-release.yml
index ddad5090f0c..a4d9c9cd841 100644
--- a/.github/workflows/alpha-release.yml
+++ b/.github/workflows/alpha-release.yml
@@ -6,6 +6,11 @@ on:
- cron: '0 20 * * 2' # weekly (Tuesday) 12 PM PST
- cron: '0 20 * * 5' # weekly (Friday) 12 PM PST
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
jobs:
release:
name: Run publish script
@@ -26,6 +31,7 @@ jobs:
- uses: ./.github/actions/setup
with:
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Make sure git user is setup
run: |
git config --local user.email 'tomster@emberjs.com'
diff --git a/.github/workflows/asset-size-check.yml b/.github/workflows/asset-size-check.yml
index 419b1aa89a3..60da0891d31 100644
--- a/.github/workflows/asset-size-check.yml
+++ b/.github/workflows/asset-size-check.yml
@@ -9,6 +9,11 @@ on:
- synchronize
- ready_for_review
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: asset-size-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml
index e194605094c..0877955fa7e 100644
--- a/.github/workflows/beta-release.yml
+++ b/.github/workflows/beta-release.yml
@@ -3,6 +3,11 @@ name: Canary-Mirror-Beta Release
on:
workflow_dispatch:
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
jobs:
release:
name: Run publish script
@@ -25,6 +30,7 @@ jobs:
with:
build-addons: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Make sure git user is setup
run: |
git config --local user.email 'tomster@emberjs.com'
diff --git a/.github/workflows/compat-tests.yml b/.github/workflows/compat-tests.yml
index e0c9a182e46..9b66305fe2e 100644
--- a/.github/workflows/compat-tests.yml
+++ b/.github/workflows/compat-tests.yml
@@ -5,6 +5,11 @@ on:
branches:
- main
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: compat-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
@@ -19,6 +24,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run Tests
run: pnpm test:fastboot
embroider:
@@ -30,6 +36,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run Tests
run: pnpm test:embroider
env:
@@ -40,6 +47,8 @@ jobs:
steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4
- uses: ./.github/actions/setup
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies w/o lockfile
run: pnpm install --no-lockfile
- name: Basic Tests
@@ -58,5 +67,6 @@ jobs:
node-version: ${{ matrix.node-version }}
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Basic Tests
run: pnpm test
diff --git a/.github/workflows/deprecations-check.yml b/.github/workflows/deprecations-check.yml
index f4386f25098..b67656c0acf 100644
--- a/.github/workflows/deprecations-check.yml
+++ b/.github/workflows/deprecations-check.yml
@@ -3,6 +3,11 @@ name: 'Check Deprecations'
on:
workflow_dispatch:
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
jobs:
test-all-deprecations:
runs-on: ubuntu-latest
diff --git a/.github/workflows/docs-and-blueprint-tests.yml b/.github/workflows/docs-and-blueprint-tests.yml
index 4272c4599f2..6675b603cef 100644
--- a/.github/workflows/docs-and-blueprint-tests.yml
+++ b/.github/workflows/docs-and-blueprint-tests.yml
@@ -5,6 +5,11 @@ on:
branches:
- main
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: docs-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
@@ -18,7 +23,8 @@ jobs:
- uses: ./.github/actions/setup
with:
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Test Docs
run: pnpm test:docs
- name: Test Blueprints
- run: pnpm --filter blueprint-tests run test
+ run: pnpm test:blueprints
diff --git a/.github/workflows/infra-tests.yml b/.github/workflows/infra-tests.yml
index 7d35ecab11b..9e530053f54 100644
--- a/.github/workflows/infra-tests.yml
+++ b/.github/workflows/infra-tests.yml
@@ -9,6 +9,11 @@ on:
- synchronize
- ready_for_review
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: infra-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
@@ -24,6 +29,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: pnpm test infra compatWith 3.0
env:
COMPAT_WITH: '3.0'
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 61ff1704050..859b11d28e5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -12,6 +12,11 @@ on:
tags:
- '*'
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: ci-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
@@ -26,10 +31,11 @@ jobs:
with:
restore-lint-caches: true
install: true
- - name: Lint js
- run: pnpm lint:js
- - name: Check for TypeScript problems
- run: pnpm problems
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: Lint
+ run: pnpm lint
+ - name: Check Uncompiled Packages for TypeScript Compilation Errors
+ run: pnpm check:types
special-build-tests:
timeout-minutes: 20
@@ -40,6 +46,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- if: |
github.event_name == 'pull_request' && (
github.base_ref == 'main' || github.base_ref == 'beta'
@@ -82,6 +89,7 @@ jobs:
jobs: 2
parallel-build: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Check for Test Failure Retry
id: retry-test-failures
@@ -147,6 +155,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Basic tests with ${{ matrix.scenario }}
timeout-minutes: 12
env:
@@ -173,6 +182,7 @@ jobs:
with:
restore-broccoli-cache: true
install: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Basic tests with ${{ matrix.release }}
env:
CI: true
diff --git a/.github/workflows/partner-tests.yml b/.github/workflows/partner-tests.yml
index c1a3b19a65c..bf5b026d675 100644
--- a/.github/workflows/partner-tests.yml
+++ b/.github/workflows/partner-tests.yml
@@ -9,6 +9,11 @@ on:
- synchronize
- ready_for_review
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: partners-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
@@ -54,6 +59,7 @@ jobs:
restore-broccoli-cache: true
install: true
build-addons: true
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate package tarballs
run: node ./scripts/packages-for-commit.js
- name: Run Tests
diff --git a/.github/workflows/perf-check.yml b/.github/workflows/perf-check.yml
index 0b2edaf948c..9294d34a140 100644
--- a/.github/workflows/perf-check.yml
+++ b/.github/workflows/perf-check.yml
@@ -9,6 +9,11 @@ on:
- synchronize
- ready_for_review
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: perf-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
diff --git a/.github/workflows/perf-over-release.yml b/.github/workflows/perf-over-release.yml
index 3a89fb599ec..973863d2138 100644
--- a/.github/workflows/perf-over-release.yml
+++ b/.github/workflows/perf-over-release.yml
@@ -9,6 +9,11 @@ on:
- synchronize
- ready_for_review
+env:
+ TURBO_API: http://127.0.0.1:9080
+ TURBO_TOKEN: this-is-not-a-secret
+ TURBO_TEAM: myself
+
concurrency:
group: perf-release-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
diff --git a/.gitignore b/.gitignore
index 42cb9ef79da..1a322e6351d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,7 +22,7 @@ packages/rest/addon
packages/active-record/addon
packages/data-worker/addon
packages/schema-record/addon/
-packages/core/addon/
+packages/core-types/addon
# dependencies
bower_components
@@ -30,10 +30,11 @@ node_modules
scripts/asset-size-tracking/current-data.json
# misc
+.turbo/
.env*
.pnp*
.sass-cache
-/.eslintcache
+.eslintcache
/onnect.lock
coverage/*
libpeerconnection.log
@@ -65,6 +66,6 @@ benchmarks/results/*.json
/packages/*/DEBUG
/tests/*/DEBUG
-.vscode/
+!.vscode/
.idea/
*.iml
diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index 2dbbfb3c230..00000000000
--- a/.prettierrc
+++ /dev/null
@@ -1,3 +0,0 @@
-singleQuote: true
-trailingComma: 'es5'
-printWidth: 120
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 00000000000..65bfc3b8d4c
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ singleQuote: true,
+ trailingComma: 'es5',
+ printWidth: 120
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000000..1e8082415c2
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "files.associations": {
+ "turbo.json": "jsonc"
+ }
+}
\ No newline at end of file
diff --git a/@types/ember-data-qunit-asserts/index.d.ts b/@types/ember-data-qunit-asserts/index.d.ts
index aaa5bbac5a4..a700d301da9 100644
--- a/@types/ember-data-qunit-asserts/index.d.ts
+++ b/@types/ember-data-qunit-asserts/index.d.ts
@@ -1,6 +1,6 @@
import type { CacheOperation, NotificationType } from "@ember-data/store/-private/managers/notification-manager";
import type { StableDocumentIdentifier } from "@ember-data/store/-types/cache/identifier";
-import type { StableRecordIdentifier } from "@warp-drive/core";
+import type { StableRecordIdentifier } from "@warp-drive/core-types";
declare global {
interface DeprecationConfig {
diff --git a/@types/ember/index.d.ts b/@types/ember/index.d.ts
deleted file mode 100644
index 33a43970320..00000000000
--- a/@types/ember/index.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-import 'ember-source/types';
diff --git a/config/eslint/base.cjs b/config/eslint/base.cjs
new file mode 100644
index 00000000000..887487e8096
--- /dev/null
+++ b/config/eslint/base.cjs
@@ -0,0 +1,57 @@
+const path = require('path');
+const prettierPath = path.join(process.cwd(), '../../.prettierrc.js');
+const prettierConfig = require(prettierPath);
+
+function rules() {
+ return {
+ eqeqeq: 'error',
+ 'new-cap': ['error', { capIsNew: false }],
+ 'no-caller': 'error',
+ 'no-cond-assign': ['error', 'except-parens'],
+ 'no-console': 'error', // no longer recommended in eslint v6, this restores it
+ 'no-eq-null': 'error',
+ 'no-eval': 'error',
+ 'no-unused-vars': ['error', { args: 'none' }],
+
+ // Too many false positives
+ // See https://github.com/eslint/eslint/issues/11899 and similar
+ 'require-atomic-updates': 'off',
+
+ 'prefer-rest-params': 'off',
+ 'prefer-const': 'error',
+
+ "prettier/prettier": [
+ "error",
+ prettierConfig,
+ {
+ "usePrettierrc": false
+ }
+ ]
+ };
+}
+
+function plugins() {
+ return ['prettier'];
+}
+
+function extend() {
+ return ['eslint:recommended', 'plugin:prettier/recommended'];
+}
+
+function settings() {
+ return {
+ globals: {},
+ env: {
+ browser: true,
+ node: false,
+ es2022: true,
+ },
+ }
+}
+
+module.exports = {
+ rules,
+ plugins,
+ extend,
+ settings,
+};
diff --git a/config/eslint/ignore.cjs b/config/eslint/ignore.cjs
new file mode 100644
index 00000000000..32b454dc023
--- /dev/null
+++ b/config/eslint/ignore.cjs
@@ -0,0 +1,36 @@
+const RULES = [
+ // # unconventional js
+ 'blueprints/',
+ 'vendor',
+
+ // # Declaration files
+ '**/*.d.ts',
+
+ // # compiled output
+ 'dist',
+ 'dist-*',
+ 'tmp',
+ 'DEBUG',
+ 'DEBUG*',
+ 'tmp*',
+ '.git',
+ '.broccoli-cache',
+ 'unstable-preview-types',
+
+ // # Special Cases
+ 'docs',
+ 'coverage',
+ 'node_modules',
+ '.node_modules.ember-try',
+ 'package.json.ember-try',
+];
+
+function ignoreRules(allowAddon) {
+ const rules = allowAddon ? [] : ['addon'];
+
+ return rules.concat(RULES);
+}
+
+module.exports = {
+ ignoreRules
+};
diff --git a/config/eslint/imports.cjs b/config/eslint/imports.cjs
new file mode 100644
index 00000000000..97fc0a04ce6
--- /dev/null
+++ b/config/eslint/imports.cjs
@@ -0,0 +1,45 @@
+// See https://github.com/lydell/eslint-plugin-simple-import-sort#custom-grouping
+const ImportSortGroups = [
+ // Side effect imports.
+ [`^\u0000`],
+ // Glimmer & Ember Dependencies
+ [`^(@ember/|@glimmer|ember$)`],
+ // Packages.
+ // Things that start with a letter (or digit or underscore), or `@` followed by a letter.
+ // But not our packages or packages starting with ember-
+ // eslint-disable-next-line no-useless-escape
+ [`^(?!@ember\-data)(?!warp\-drive)(?!ember-)(@?\\w)`],
+ // Packages starting with ember-
+ // eslint-disable-next-line no-useless-escape
+ [`^ember\-`],
+ // Our Packages.
+ // Things that start with @ember-data
+ // eslint-disable-next-line no-useless-escape
+ [`^(@ember\-data|@warp\-drive)`],
+ // Absolute imports and other imports such as Vue-style `@/foo`.
+ // Anything that does not start with a dot.
+ ['^[^.]'],
+ // Relative imports.
+ // Anything that starts with a dot.
+ // eslint-disable-next-line no-useless-escape
+ [`^\.`],
+];
+
+function rules() {
+ return {
+ // Imports
+ 'import/first': 'error',
+ 'import/newline-after-import': 'error',
+ 'import/no-duplicates': 'error',
+ 'simple-import-sort/imports': ['error', { groups: ImportSortGroups }],
+ };
+}
+
+function plugins() {
+ return ['simple-import-sort', 'import'];
+}
+
+module.exports = {
+ plugins,
+ rules,
+};
diff --git a/config/eslint/isolation.cjs b/config/eslint/isolation.cjs
new file mode 100644
index 00000000000..c4b9c20c868
--- /dev/null
+++ b/config/eslint/isolation.cjs
@@ -0,0 +1,69 @@
+const RESTRICTED_IMPORTS = [
+ '@ember/-internals/metal',
+ '@ember/application',
+ '@ember/application/namespace',
+ '@ember/array',
+ '@ember/array/proxy',
+ '@ember/component',
+ '@ember/component/helper',
+ '@ember/controller',
+ '@ember/debug',
+ '@ember/debug/data-adapter',
+ '@ember/edition-utils',
+ '@ember/object',
+ '@ember/object/compat',
+ '@ember/object/computed',
+ '@ember/object/evented',
+ '@ember/object/internals',
+ '@ember/object/mixin',
+ '@ember/object/promise-proxy-mixin',
+ '@ember/object/proxy',
+ '@ember/owner',
+ '@ember/routing',
+ '@ember/routing/route',
+ '@ember/runloop',
+ '@ember/service',
+ '@ember/string',
+ '@ember/test-helpers',
+ '@ember/test-waiters',
+ '@ember/utils',
+ '@ember/version',
+ '@glimmer/component',
+ '@glimmer/env',
+ '@glimmer/runtime',
+ '@glimmer/tracking',
+ '@glimmer/tracking/primitives/cache',
+ '@glimmer/validator',
+ 'ember-inflector',
+ 'ember-qunit',
+ 'ember-source',
+ 'ember-source/types',
+ 'ember',
+ 'qunit',
+ 'testem'
+];
+function rules(options) {
+ return {
+ 'no-restricted-imports': [
+ 'error',
+ {
+ paths: options?.allowedImports ? RESTRICTED_IMPORTS.filter(
+ (path) => {
+ return !options.allowedImports.includes(path)
+ }
+ ) : RESTRICTED_IMPORTS,
+ },
+ ],
+ 'no-restricted-globals': [
+ 'error',
+ {
+ name: 'QUnit',
+ message: 'Please use the `qunit` import instead of referencing `QUnit` directly.',
+ },
+ ],
+ }
+}
+
+module.exports = {
+ rules
+};
diff --git a/config/eslint/node.cjs b/config/eslint/node.cjs
new file mode 100644
index 00000000000..75f82e0f190
--- /dev/null
+++ b/config/eslint/node.cjs
@@ -0,0 +1,25 @@
+function defaults(config) {
+ const result = {
+ files: !config?.useModules ? ['./babel.config.js', './.eslintrc.cjs', './index.js', './addon-main.cjs', './addon-main.js'] : [],
+ parserOptions: {
+ sourceType: config?.useModules ? 'module' : 'script',
+ ecmaVersion: 2022,
+ },
+ env: {
+ browser: false,
+ node: true,
+ es6: true,
+ },
+ globals: config?.globals || {},
+ };
+
+ if (config?.files) {
+ result.files.push(...config.files);
+ }
+
+ return result;
+}
+
+module.exports = {
+ defaults
+};
diff --git a/config/eslint/parser.cjs b/config/eslint/parser.cjs
new file mode 100644
index 00000000000..5c92be34f05
--- /dev/null
+++ b/config/eslint/parser.cjs
@@ -0,0 +1,19 @@
+function defaults() {
+ return {
+ parser: '@babel/eslint-parser',
+ root: true,
+ parserOptions: {
+ ecmaVersion: 2022,
+ sourceType: 'module',
+ babelOptions: {
+ // eslint-disable-next-line node/no-unpublished-require
+ plugins: [[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }]],
+ },
+ requireConfigFile: false,
+ },
+ };
+}
+
+module.exports = {
+ defaults
+};
diff --git a/config/eslint/typescript.cjs b/config/eslint/typescript.cjs
new file mode 100644
index 00000000000..502cc0fa1fc
--- /dev/null
+++ b/config/eslint/typescript.cjs
@@ -0,0 +1,62 @@
+function rules(config) {
+ return Object.assign({
+ '@typescript-eslint/no-explicit-any': 'error',
+ '@typescript-eslint/no-unused-vars': ['error', { args: 'none' }],
+ '@typescript-eslint/prefer-includes': 'error',
+ '@typescript-eslint/prefer-ts-expect-error': 'error',
+ '@typescript-eslint/ban-ts-comment': 'off',
+ '@typescript-eslint/no-redundant-type-constituents': 'off',
+ '@typescript-eslint/no-unsafe-declaration-merging': 'off',
+ '@typescript-eslint/no-misused-promises': 'off',
+ 'no-unused-vars': 'off',
+ 'prefer-const': 'error',
+ 'prefer-rest-params': 'off',
+ 'no-shadow': 'off',
+ '@typescript-eslint/no-shadow': 'error',
+ 'no-loop-func': 'off',
+ '@typescript-eslint/no-loop-func': 'error',
+ 'no-throw-literal': 'off',
+ '@typescript-eslint/no-throw-literal': 'error',
+ // '@typescript-eslint/prefer-readonly-parameter-types': 'error',
+ }, config?.rules ?? {});
+}
+
+function plugins() {
+ return ['@typescript-eslint'];
+}
+
+function extend() {
+ return [
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:@typescript-eslint/recommended-requiring-type-checking'
+ ];
+}
+
+function settings() {
+ return {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ sourceType: 'module',
+ ecmaVersion: 2022,
+ project: 'tsconfig.json'
+ }
+ }
+}
+
+function defaults(config) {
+ return {
+ files: config?.files || ['**/*.ts'],
+ ...settings(),
+ rules: rules(config),
+ plugins: plugins(),
+ extends: extend(),
+ };
+}
+
+module.exports = {
+ rules,
+ settings,
+ defaults,
+ plugins,
+ extend,
+}
diff --git a/config/package.json b/config/package.json
new file mode 100644
index 00000000000..869993ccdc2
--- /dev/null
+++ b/config/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "@warp-drive/internal-config",
+ "private": true,
+ "version": "5.5.0-alpha.11",
+ "dependencies": {
+ "@babel/core": "^7.23.2",
+ "@babel/eslint-parser": "^7.22.15",
+ "@babel/plugin-proposal-decorators": "^7.12.13",
+ "@typescript-eslint/eslint-plugin": "^6.8.0",
+ "@typescript-eslint/parser": "^6.8.0",
+ "eslint": "^8.52.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-prettier": "^5.0.1",
+ "eslint-plugin-simple-import-sort": "^10.0.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10",
+ "prettier": "^3.0.3",
+ "typescript": "~5.2.2"
+ },
+ "engines": {
+ "node": ">= 18.18.2"
+ },
+ "volta": {
+ "extends": "../../package.json"
+ },
+ "packageManager": "pnpm@8.9.2"
+}
\ No newline at end of file
diff --git a/config/rollup/external.js b/config/rollup/external.js
new file mode 100644
index 00000000000..eb6dcb4445b
--- /dev/null
+++ b/config/rollup/external.js
@@ -0,0 +1,16 @@
+const path = require('path');
+
+function external(manual = []) {
+ const pkg = require(path.join(process.cwd(), './package.json'));
+ const deps = Object.keys(pkg.dependencies || {});
+ const peers = Object.keys(pkg.peerDependencies || {});
+ const all = new Set([...deps, ...peers, ...manual]);
+
+ const result = [...all.keys()];
+ // console.log({ externals: result });
+ return result;
+}
+
+module.exports = {
+ external,
+}
diff --git a/contributing/setting-up-the-project.md b/contributing/setting-up-the-project.md
index f6a4a4f4d3c..ccdda8b080e 100644
--- a/contributing/setting-up-the-project.md
+++ b/contributing/setting-up-the-project.md
@@ -34,6 +34,6 @@ Currently the install command is also what builds all of the individual packages
Generally test and lint commands can be found in the `"scripts"` section of the root `package.json` manifest. Individual packages or test packages have additional commands in the `"scripts"` section of their own `package.json` manifest as well.
-Any command in script can be run using `pnpm` from the directory of that manifest. For instance, to run linting from the root: `pnpm lint:js`
+Any command in script can be run using `pnpm` from the directory of that manifest. For instance, to run linting from the root: `pnpm lint`
Github Actions workflows will generally use these same commands.
diff --git a/docs-generator/yuidoc.json b/docs-generator/yuidoc.json
index 9078d18d44d..3597e783f53 100644
--- a/docs-generator/yuidoc.json
+++ b/docs-generator/yuidoc.json
@@ -12,7 +12,7 @@
],
"paths": [
"../packages/-ember-data/addon",
- "../packages/core",
+ "../packages/core-types/src",
"../packages/debug/addon",
"../packages/private-build-infra/virtual-packages",
"../packages/adapter/src",
diff --git a/package.json b/package.json
index d7454fd4597..731200e0596 100644
--- a/package.json
+++ b/package.json
@@ -7,17 +7,20 @@
"url": "git+ssh://git@github.com:emberjs/data.git"
},
"scripts": {
+ "prepare": "pnpm build",
+ "build": "pnpm turbo build --filter=./packages/*",
"build:docs": "mkdir -p packages/-ember-data/dist && cd ./docs-generator && node ./compile-docs.js",
- "lint:js": "eslint --quiet --cache --cache-strategy=content --ext=js,ts .",
+ "lint": "pnpm run -r --workspace-concurrency=-1 --if-present lint",
"preinstall": "npx only-allow pnpm",
- "problems": "tsc -p tsconfig.json --noEmit --pretty false",
- "test": "pnpm --filter \"ember-data__*\" --filter \"warp-drive__*\" --filter main-test-app --filter builders-test-app run test",
- "test:production": "pnpm --filter main-test-app --filter ember-data__graph --filter ember-data__json-api run test:production",
+ "check:types": "pnpm run -r --workspace-concurrency=-1 --if-present check:types",
+ "test": "pnpm turbo test --concurrency=1",
+ "test:production": "pnpm turbo test:production --concurrency=1",
"test:try-one": "pnpm --filter main-test-app run test:try-one",
- "test:docs": "pnpm build:docs && pnpm --filter docs-tests test",
- "test:fastboot": "pnpm --filter fastboot-test-app test",
- "test:embroider": "pnpm --filter embroider-basic-compat test",
- "test:infra": "pnpm --filter @ember-data/unpublished-test-infra test",
+ "test:docs": "pnpm build:docs && pnpm run -r --workspace-concurrency=-1 --if-present test:blueprints",
+ "test:blueprints": "pnpm run -r --workspace-concurrency=-1 --if-present test:blueprints",
+ "test:fastboot": "pnpm run -r --workspace-concurrency=-1 --if-present test:fastboot",
+ "test:embroider": "pnpm run -r ---workspace-concurrency=-1 --if-present test:embroider",
+ "test:infra": "pnpm run -r --workspace-concurrency=-1 --if-present test:infra",
"test-external:ember-m3": "node ./scripts/test-external-partner-project.js ember-m3 https://github.com/hjdivad/ember-m3.git",
"test-external:ember-data-change-tracker": "node ./scripts/test-external-partner-project.js ember-data-change-tracker https://github.com/danielspaniel/ember-data-change-tracker.git",
"test-external:model-fragments": "node ./scripts/test-external-partner-project.js model-fragments https://github.com/lytics/ember-data-model-fragments.git",
@@ -30,53 +33,29 @@
"test-external:ember-data-relationship-tracker": "node ./scripts/test-external-partner-project.js ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git"
},
"devDependencies": {
- "@babel/core": "^7.23.2",
- "@babel/eslint-parser": "^7.22.15",
- "@babel/plugin-proposal-decorators": "^7.23.2",
- "@babel/plugin-transform-typescript": "^7.22.15",
- "@babel/runtime": "^7.23.2",
- "@ember/edition-utils": "^1.2.0",
- "@ember/optional-features": "^2.0.0",
- "@ember/string": "3.1.1",
- "@ember/test-helpers": "^3.2.0",
- "@glimmer/component": "^1.1.2",
- "@types/jquery": "^3.5.22",
- "@types/qunit": "^2.19.6",
- "@typescript-eslint/eslint-plugin": "^6.8.0",
- "@typescript-eslint/parser": "^6.8.0",
"chalk": "^4.1.2",
"co": "^4.6.0",
"command-line-args": "^5.2.1",
"common-tags": "^1.8.2",
"debug": "^4.3.4",
- "ember-cli": "~5.3.0",
- "ember-source": "~5.3.0",
- "eslint": "^8.51.0",
- "eslint-config-prettier": "^9.0.0",
- "eslint-plugin-ember": "^11.11.1",
- "eslint-plugin-ember-data-internal": "link:packages/unpublished-eslint-rules",
- "eslint-plugin-import": "^2.28.1",
- "eslint-plugin-mocha": "^10.2.0",
- "eslint-plugin-node": "^11.1.0",
- "eslint-plugin-prettier": "5.0.1",
- "eslint-plugin-qunit": "^8.0.1",
- "eslint-plugin-simple-import-sort": "^10.0.0",
"execa": "^5.1.1",
"fromentries": "^1.3.2",
"git-repo-info": "^2.1.1",
"git-repo-version": "^1.0.2",
"lerna-changelog": "^2.2.0",
- "loader.js": "^4.7.0",
- "prettier": "^3.0.3",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10",
"rimraf": "^5.0.5",
"semver": "^7.5.4",
+ "globby": "^13.2.2",
"silent-error": "^1.1.1",
- "typescript": "~5.2.2",
+ "bun-types": "^1.0.7",
"url": "^0.11.3",
- "webpack": "^5.89.0",
"yuidocjs": "^0.10.2",
"zlib": "1.0.5"
},
+ "dependencies": {
+ "turbo": "^1.10.15"
+ },
"engines": {
"node": ">= 18.18.2",
"yarn": "use pnpm",
@@ -107,6 +86,25 @@
"dependencies": {
"@glimmer/env": "^0.1.7"
}
+ },
+ "ember-cli-blueprint-test-helpers": {
+ "peerDependencies": {
+ "ember-cli": "*"
+ }
+ },
+ "ember-cli-fastboot": {
+ "peerDependencies": {
+ "ember-cli": "*",
+ "ember-source": "*"
+ }
+ },
+ "ember-cli-fastboot-testing": {
+ "peerDependencies": {
+ "ember-cli": "*",
+ "ember-cli-fastboot": "*",
+ "ember-source": "*",
+ "@ember/test-helpers": "*"
+ }
}
},
"overrides": {
@@ -114,6 +112,7 @@
"@embroider/macros": "^1.12.2",
"broccoli-funnel": "^3.0.8",
"broccoli-merge-trees": "^4.2.0",
+ "@glimmer/validator": "^0.84.3",
"ember-cli-babel": "^8.1.0",
"ember-cli-htmlbars": "^6.3.0",
"ember-cli-typescript": "^5.2.1",
diff --git a/packages/-ember-data/.eslintrc.cjs b/packages/-ember-data/.eslintrc.cjs
new file mode 100644
index 00000000000..e0b0ab38b64
--- /dev/null
+++ b/packages/-ember-data/.eslintrc.cjs
@@ -0,0 +1,26 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug', '@ember/test-helpers', 'qunit'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/-ember-data/addon/index.ts b/packages/-ember-data/addon/index.ts
index 427a76b365f..c9e851d4187 100644
--- a/packages/-ember-data/addon/index.ts
+++ b/packages/-ember-data/addon/index.ts
@@ -221,7 +221,7 @@ interface DSLibrary extends DS {
PromiseObject: typeof PromiseObject;
PromiseManyArray: typeof PromiseManyArray;
Model: typeof Model;
- attr: attr;
+ attr: typeof attr;
Errors: typeof Errors;
Snapshot: typeof Snapshot;
Adapter: typeof Adapter;
@@ -235,6 +235,7 @@ interface DSLibrary extends DS {
ConflictError: typeof ConflictError;
ServerError: typeof ServerError;
Serializer: typeof Serializer;
+ // @ts-expect-error untyped
DebugAdapter?: typeof import('@ember-data/debug').default;
ManyArray: typeof ManyArray;
RecordArrayManager: typeof RecordArrayManager;
@@ -280,6 +281,7 @@ DS.ServerError = ServerError;
DS.Serializer = Serializer;
if (macroCondition(dependencySatisfies('@ember-data/debug', '*'))) {
+ // @ts-expect-error untyped
DS.DebugAdapter = (importSync('@ember-data/debug') as typeof import('@ember-data/debug')).default;
}
diff --git a/packages/-ember-data/addon/store.ts b/packages/-ember-data/addon/store.ts
index 16f066a87c9..4236139c53a 100644
--- a/packages/-ember-data/addon/store.ts
+++ b/packages/-ember-data/addon/store.ts
@@ -1,4 +1,4 @@
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
import JSONAPICache from '@ember-data/json-api';
import {
@@ -17,7 +17,7 @@ import { buildSchema, instantiateRecord, modelFor, teardownRecord } from '@ember
import RequestManager from '@ember-data/request';
import Fetch from '@ember-data/request/fetch';
import BaseStore, { CacheHandler } from '@ember-data/store';
-import type { Cache } from '@ember-data/store/-types/cache/cache';
+import type { Cache } from '@warp-drive/core-types/cache';
import type { CacheCapabilitiesManager } from '@ember-data/store/-types/q/cache-store-wrapper';
import type { ModelSchema } from '@ember-data/store/-types/q/ds-model';
@@ -32,11 +32,11 @@ export default class Store extends BaseStore {
this.registerSchema(buildSchema(this));
}
- createCache(storeWrapper: CacheCapabilitiesManager): Cache {
+ override createCache(storeWrapper: CacheCapabilitiesManager): Cache {
return new JSONAPICache(storeWrapper);
}
- instantiateRecord(
+ override instantiateRecord(
this: ModelStore,
identifier: StableRecordIdentifier,
createRecordArgs: Record
@@ -44,11 +44,11 @@ export default class Store extends BaseStore {
return instantiateRecord.call(this, identifier, createRecordArgs);
}
- teardownRecord(record: Model): void {
+ override teardownRecord(record: Model): void {
teardownRecord.call(this, record);
}
- modelFor(type: string): ModelSchema {
+ override modelFor(type: string): ModelSchema {
return modelFor.call(this, type) || super.modelFor(type);
}
@@ -58,7 +58,7 @@ export default class Store extends BaseStore {
normalize = normalize;
serializeRecord = serializeRecord;
- destroy() {
+ override destroy() {
cleanup.call(this);
super.destroy();
}
diff --git a/packages/-ember-data/package.json b/packages/-ember-data/package.json
index d1d521d9328..7dfa5a62ef6 100644
--- a/packages/-ember-data/package.json
+++ b/packages/-ember-data/package.json
@@ -12,7 +12,35 @@
"test": "tests"
},
"scripts": {
- "prepack": "cd ../../ && pnpm build:docs"
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
+ "move-dts": "bun ../../scripts/copy-declarations.mjs addon",
+ "build:types": "tsc --build --force",
+ "build": "pnpm build:types && pnpm move-dts",
+ "prepack": "pnpm build && cd ../../ && pnpm build:docs",
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
+ },
+ "files": [
+ "dist/docs",
+ "ember-data-logo-dark.svg",
+ "ember-data-logo-light.svg",
+ "LICENSE.md",
+ "README.md",
+ "index.js",
+ "addon",
+ "addon-test-support",
+ "app",
+ "blueprints",
+ "unstable-preview-types"
+ ],
+ "exports": {
+ ".": {
+ "types": "./unstable-preview-types/index.d.ts",
+ "default": "./addon/index.js"
+ },
+ "./*": {
+ "types": "./unstable-preview-types/*.d.ts",
+ "default": "./addon/*.js"
+ }
},
"author": "",
"license": "MIT",
@@ -32,13 +60,15 @@
"@ember-data/serializer": "workspace:5.5.0-alpha.11",
"@ember-data/store": "workspace:5.5.0-alpha.11",
"@ember-data/tracking": "workspace:5.5.0-alpha.11",
- "@warp-drive/core": "workspace:5.5.0-alpha.11",
"@ember/edition-utils": "^1.2.0",
"@embroider/macros": "^1.13.2",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
"broccoli-merge-trees": "^4.2.0",
"ember-auto-import": "^2.6.3",
"ember-cli-babel": "^8.2.0",
"ember-inflector": "^4.0.2",
+ "typescript": "^5.2.2",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10",
"webpack": "^5.89.0"
},
"dependenciesMeta": {
@@ -80,6 +110,12 @@
},
"@ember/string": {
"injected": true
+ },
+ "@warp-drive/core-types": {
+ "injected": true
+ },
+ "ember-inflector": {
+ "injected": true
}
},
"devDependencies": {
@@ -87,7 +123,9 @@
"@ember/string": "3.1.1",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
- "ember-source": "~5.3.0"
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
+ "ember-source": "~5.3.0",
+ "eslint": "^8.51.0"
},
"engines": {
"node": ">= 18.18.2"
@@ -103,4 +141,4 @@
"extends": "../../package.json"
},
"packageManager": "pnpm@8.9.2"
-}
\ No newline at end of file
+}
diff --git a/packages/-ember-data/tsconfig.json b/packages/-ember-data/tsconfig.json
new file mode 100644
index 00000000000..b509e242f38
--- /dev/null
+++ b/packages/-ember-data/tsconfig.json
@@ -0,0 +1,44 @@
+{
+ "include": [
+ "addon/**/*",
+ ],
+ "baseUrl": ".",
+ "compilerOptions": {
+ "lib": ["DOM", "ESNext"],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "noEmit": false,
+ "noImplicitOverride": true,
+
+ // Enable faster builds
+ // but causes us to not rebuild properly
+ "incremental": false,
+
+ "declaration": true,
+ "declarationMap": true,
+ "declarationDir": "unstable-preview-types",
+ "emitDeclarationOnly": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "types": [
+ "ember-source/types",
+ ],
+
+ "paths": {
+ "ember-data/version": ["./addon/version.d.ts"],
+ "@ember-data/deprecations": ["../private-build-infra/virtual-packages/deprecations.d.ts"],
+ "@ember-data/packages": ["../private-build-infra/virtual-packages/packages.d.ts"],
+ "@ember-data/canary-features": ["../private-build-infra/virtual-packages/canary-features.d.ts"],
+ "@ember-data/debugging": ["../private-build-infra/virtual-packages/debugging.d.ts"],
+ "@ember-data/env": ["../private-build-infra/virtual-packages/env.d.ts"],
+ }
+ },
+}
diff --git a/packages/active-record/.eslintrc.cjs b/packages/active-record/.eslintrc.cjs
new file mode 100644
index 00000000000..440b732b749
--- /dev/null
+++ b/packages/active-record/.eslintrc.cjs
@@ -0,0 +1,26 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug', 'ember-inflector', '@ember/string'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/active-record/package.json b/packages/active-record/package.json
index bf801237f32..963054e11db 100644
--- a/packages/active-record/package.json
+++ b/packages/active-record/package.json
@@ -22,25 +22,39 @@
"extends": "../../package.json"
},
"dependencies": {
- "ember-cli-babel": "^8.2.0"
+ "ember-cli-babel": "^8.2.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10"
},
"peerDependencies": {
+ "@ember-data/request-utils": "workspace:5.5.0-alpha.11",
"@ember-data/store": "^4.12.0 || ^5.0.0",
- "@warp-drive/core": "workspace:5.5.0-alpha.11",
"@ember/string": "^3.1.1",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
"ember-inflector": "^4.0.2"
},
"dependenciesMeta": {
"ember-inflector": {
"injected": true
},
+ "@ember/string": {
+ "injected": true
+ },
+ "@warp-drive/internal-config": {
+ "injected": true
+ },
+ "@warp-drive/core-types": {
+ "injected": true
+ },
"@ember-data/store": {
"injected": true
},
- "@warp-drive/core": {
+ "@ember-data/request-utils": {
"injected": true
},
- "@ember/string": {
+ "@ember-data/request": {
+ "injected": true
+ },
+ "@ember-data/tracking": {
"injected": true
}
},
@@ -52,11 +66,19 @@
"ember-data-logo-dark.svg",
"ember-data-logo-light.svg"
],
+ "exports": {
+ "./*": {
+ "types": "./unstable-preview-types/*.d.ts",
+ "default": "./addon/*.js"
+ }
+ },
"scripts": {
- "build": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
- "start": "rollup --config --watch",
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
+ "build:types": "tsc --build --force",
+ "build:client": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
+ "build": "pnpm build:client && pnpm build:types",
"prepack": "pnpm build",
- "prepare": "pnpm build"
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
},
"ember-addon": {
"main": "addon-main.js",
@@ -73,15 +95,24 @@
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@babel/runtime": "^7.23.2",
+ "@ember-data/request": "workspace:5.5.0-alpha.11",
+ "@ember-data/request-utils": "workspace:5.5.0-alpha.11",
+ "@ember-data/store": "workspace:5.5.0-alpha.11",
+ "@ember-data/tracking": "workspace:5.5.0-alpha.11",
+ "@ember/string": "^3.1.1",
"@embroider/addon-dev": "^4.1.1",
+ "@glimmer/component": "^1.1.2",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
+ "ember-inflector": "^4.0.2",
+ "ember-source": "~5.3.0",
"rollup": "^4.1.4",
- "tslib": "^2.6.2",
"typescript": "^5.2.2",
"walk-sync": "^3.0.0"
},
"ember": {
"edition": "octane"
}
-}
\ No newline at end of file
+}
diff --git a/packages/active-record/rollup.config.mjs b/packages/active-record/rollup.config.mjs
index 095095d3db1..683b7c9b8b0 100644
--- a/packages/active-record/rollup.config.mjs
+++ b/packages/active-record/rollup.config.mjs
@@ -2,6 +2,8 @@ import { Addon } from '@embroider/addon-dev/rollup';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { external } from '@warp-drive/internal-config/rollup/external.js';
+
const addon = new Addon({
srcDir: 'src',
destDir: 'addon',
@@ -12,7 +14,7 @@ export default {
// You can augment this if you need to.
output: addon.output(),
- external: ['@ember/debug', '@ember-data/request-utils', 'ember-inflector', '@ember/string', '@ember-data/store'],
+ external: external(['@ember/debug']),
plugins: [
// These are the modules that users should be able to import from your
diff --git a/packages/active-record/src/-private/builders/-utils.ts b/packages/active-record/src/-private/builders/-utils.ts
index 0f41ea281a5..9cae4d3439b 100644
--- a/packages/active-record/src/-private/builders/-utils.ts
+++ b/packages/active-record/src/-private/builders/-utils.ts
@@ -1,5 +1,5 @@
import { type UrlOptions } from '@ember-data/request-utils';
-import type { CacheOptions, ConstrainedRequestOptions } from '@ember-data/store/-types/request';
+import type { CacheOptions, ConstrainedRequestOptions } from '@warp-drive/core-types/request';
export function copyForwardUrlOptions(urlOptions: UrlOptions, options: ConstrainedRequestOptions): void {
if ('host' in options) {
diff --git a/packages/active-record/src/-private/builders/find-record.ts b/packages/active-record/src/-private/builders/find-record.ts
index d15a92a4652..1b8cdde27a7 100644
--- a/packages/active-record/src/-private/builders/find-record.ts
+++ b/packages/active-record/src/-private/builders/find-record.ts
@@ -10,7 +10,7 @@ import type {
ConstrainedRequestOptions,
FindRecordRequestOptions,
RemotelyAccessibleIdentifier,
-} from '@ember-data/store/-types/request';
+} from '@warp-drive/core-types/request';
import { copyForwardUrlOptions, extractCacheOptions } from './-utils';
diff --git a/packages/active-record/src/-private/builders/query.ts b/packages/active-record/src/-private/builders/query.ts
index a3a176de5e5..1417e13044f 100644
--- a/packages/active-record/src/-private/builders/query.ts
+++ b/packages/active-record/src/-private/builders/query.ts
@@ -5,8 +5,9 @@ import { underscore } from '@ember/string';
import { pluralize } from 'ember-inflector';
-import { buildBaseURL, buildQueryParams, QueryParamsSource, type QueryUrlOptions } from '@ember-data/request-utils';
-import type { ConstrainedRequestOptions, QueryRequestOptions } from '@ember-data/store/-types/request';
+import { buildBaseURL, buildQueryParams, type QueryUrlOptions } from '@ember-data/request-utils';
+import type { QueryParamsSource } from '@warp-drive/core-types/params';
+import type { ConstrainedRequestOptions, QueryRequestOptions } from '@warp-drive/core-types/request';
import { copyForwardUrlOptions, extractCacheOptions } from './-utils';
diff --git a/packages/active-record/src/-private/builders/save-record.ts b/packages/active-record/src/-private/builders/save-record.ts
index 59382e75a9f..ef54bcd49df 100644
--- a/packages/active-record/src/-private/builders/save-record.ts
+++ b/packages/active-record/src/-private/builders/save-record.ts
@@ -1,8 +1,6 @@
import { assert } from '@ember/debug';
import { underscore } from '@ember/string';
-import type { StableExistingRecordIdentifier, StableRecordIdentifier } from '@warp-drive/core/identifier';
-
import { pluralize } from 'ember-inflector';
import {
@@ -12,12 +10,13 @@ import {
type UpdateRecordUrlOptions,
} from '@ember-data/request-utils';
import { recordIdentifierFor } from '@ember-data/store';
+import type { StableExistingRecordIdentifier, StableRecordIdentifier } from '@warp-drive/core-types/identifier';
import {
ConstrainedRequestOptions,
CreateRequestOptions,
DeleteRequestOptions,
UpdateRequestOptions,
-} from '@ember-data/store/-types/request';
+} from '@warp-drive/core-types/request';
import { copyForwardUrlOptions } from './-utils';
diff --git a/packages/active-record/tsconfig.json b/packages/active-record/tsconfig.json
new file mode 100644
index 00000000000..3c860b1fafe
--- /dev/null
+++ b/packages/active-record/tsconfig.json
@@ -0,0 +1,43 @@
+{
+ "include": [
+ "src/**/*"
+ ],
+ "baseUrl": ".",
+ "compilerOptions": {
+ "lib": ["DOM", "ESNext"],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "noEmit": false,
+ "noImplicitOverride": true,
+
+ // Enable faster builds
+ // but causes us to not rebuild properly
+ "incremental": false,
+
+ "declaration": true,
+ "declarationMap": true,
+ "declarationDir": "unstable-preview-types",
+ "emitDeclarationOnly": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "types": [
+ "ember-source/types"
+ ],
+
+ "paths": {
+ "@ember-data/deprecations": ["../private-build-infra/virtual-packages/deprecations.d.ts"],
+ "@ember-data/packages": ["../private-build-infra/virtual-packages/packages.d.ts"],
+ "@ember-data/canary-features": ["../private-build-infra/virtual-packages/canary-features.d.ts"],
+ "@ember-data/debugging": ["../private-build-infra/virtual-packages/debugging.d.ts"],
+ "@ember-data/env": ["../private-build-infra/virtual-packages/env.d.ts"],
+ }
+ },
+}
diff --git a/packages/adapter/.eslintrc.cjs b/packages/adapter/.eslintrc.cjs
new file mode 100644
index 00000000000..e3164c866f3
--- /dev/null
+++ b/packages/adapter/.eslintrc.cjs
@@ -0,0 +1,34 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: [
+ '@ember/object',
+ '@ember/application',
+ '@ember/service',
+ '@ember/debug',
+ 'ember-inflector',
+ '@ember/object/mixin',
+ '@ember/string',
+ ],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/adapter/package.json b/packages/adapter/package.json
index fff34db5aa0..bb4e29cf235 100644
--- a/packages/adapter/package.json
+++ b/packages/adapter/package.json
@@ -14,10 +14,12 @@
"author": "",
"directories": {},
"scripts": {
- "build": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
- "start": "rollup --config --watch",
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
+ "build:types": "tsc --build --force",
+ "build:client": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
+ "build": "pnpm build:client && pnpm build:types",
"prepack": "pnpm build",
- "prepare": "pnpm build"
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
},
"ember-addon": {
"main": "addon-main.js",
@@ -25,6 +27,7 @@
"version": 1
},
"files": [
+ "unstable-preview-types",
"blueprints",
"addon-main.js",
"addon",
@@ -33,7 +36,18 @@
"ember-data-logo-dark.svg",
"ember-data-logo-light.svg"
],
+ "exports": {
+ ".": {
+ "types": "./unstable-preview-types/index.d.ts",
+ "default": "./addon/index.js"
+ },
+ "./*": {
+ "types": "./unstable-preview-types/*.d.ts",
+ "default": "./addon/*.js"
+ }
+ },
"peerDependencies": {
+ "@ember-data/legacy-compat": "workspace:5.5.0-alpha.11",
"@ember-data/store": "workspace:5.5.0-alpha.11",
"@ember/string": "^3.1.1",
"ember-inflector": "^4.0.2"
@@ -44,13 +58,44 @@
},
"@ember/string": {
"injected": true
+ },
+ "@warp-drive/internal-config": {
+ "injected": true
+ },
+ "@warp-drive/core-types": {
+ "injected": true
+ },
+ "@ember-data/legacy-compat": {
+ "injected": true
+ },
+ "@ember-data/store": {
+ "injected": true
+ },
+ "ember-inflector": {
+ "injected": true
+ },
+ "@ember-data/request": {
+ "injected": true
+ },
+ "@ember-data/tracking": {
+ "injected": true
+ },
+ "@ember-data/graph": {
+ "injected": true
+ },
+ "@ember-data/json-api": {
+ "injected": true
+ },
+ "@ember-data/request-utils": {
+ "injected": true
}
},
"dependencies": {
"@ember-data/private-build-infra": "workspace:5.5.0-alpha.11",
"@embroider/macros": "^1.13.2",
"ember-cli-babel": "^8.2.0",
- "ember-cli-test-info": "^1.0.0"
+ "ember-cli-test-info": "^1.0.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10"
},
"devDependencies": {
"@babel/cli": "^7.23.0",
@@ -63,13 +108,24 @@
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@babel/runtime": "^7.23.2",
+ "@ember-data/graph": "workspace:5.5.0-alpha.11",
+ "@ember-data/json-api": "workspace:5.5.0-alpha.11",
+ "@ember-data/legacy-compat": "workspace:5.5.0-alpha.11",
+ "@ember-data/request": "workspace:5.5.0-alpha.11",
+ "@ember-data/request-utils": "workspace:5.5.0-alpha.11",
+ "@ember-data/store": "workspace:5.5.0-alpha.11",
+ "@ember-data/tracking": "workspace:5.5.0-alpha.11",
+ "@ember/string": "^3.1.1",
"@embroider/addon-dev": "^4.1.1",
"@glimmer/component": "^1.1.2",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
+ "@types/jquery": "^3.5.24",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
+ "ember-inflector": "^4.0.2",
"ember-source": "~5.3.0",
"rollup": "^4.1.4",
- "tslib": "^2.6.2",
"typescript": "^5.2.2",
"walk-sync": "^3.0.0",
"webpack": "^5.89.0"
@@ -81,4 +137,4 @@
"extends": "../../package.json"
},
"packageManager": "pnpm@8.9.2"
-}
\ No newline at end of file
+}
diff --git a/packages/adapter/rollup.config.mjs b/packages/adapter/rollup.config.mjs
index 129deff4c04..8daafecff0f 100644
--- a/packages/adapter/rollup.config.mjs
+++ b/packages/adapter/rollup.config.mjs
@@ -2,6 +2,8 @@ import { Addon } from '@embroider/addon-dev/rollup';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { external } from '@warp-drive/internal-config/rollup/external.js';
+
const addon = new Addon({
srcDir: 'src',
destDir: 'addon',
@@ -12,17 +14,15 @@ export default {
// You can augment this if you need to.
output: addon.output(),
- external: [
+ external: external([
'@embroider/macros',
'@ember/service', // inject the store to base Adapter
'@ember-data/store/-private',
- 'ember-inflector', // pluralize
'@ember/debug', // assert, deprecate
- '@ember/string', // dasherize, camelize
'@ember/object', // Adapter base, computed for headers
'@ember/object/mixin', // BuildURLMixin
'@ember/application', // getOwner
- ],
+ ]),
plugins: [
// These are the modules that users should be able to import from your
diff --git a/packages/adapter/src/-private/build-url-mixin.ts b/packages/adapter/src/-private/build-url-mixin.ts
index 0c76385fe98..93182157c4c 100644
--- a/packages/adapter/src/-private/build-url-mixin.ts
+++ b/packages/adapter/src/-private/build-url-mixin.ts
@@ -300,9 +300,9 @@ function buildURL(
*/
function _buildURL(this: MixtBuildURLMixin, modelName: string | null | undefined, id?: string | null): string {
let path: string;
- let url: string[] = [];
- let { host } = this;
- let prefix = this.urlPrefix();
+ const url: string[] = [];
+ const { host } = this;
+ const prefix = this.urlPrefix();
if (modelName) {
path = this.pathForType(modelName);
@@ -608,7 +608,8 @@ function urlForDeleteRecord(this: MixtBuildURLMixin, id: string, modelName: stri
@return {String} urlPrefix
*/
function urlPrefix(this: MixtBuildURLMixin, path?: string | null, parentURL?: string): string {
- let { host, namespace } = this;
+ const { namespace } = this;
+ let { host } = this;
if (!host || host === '/') {
host = '';
@@ -630,7 +631,7 @@ function urlPrefix(this: MixtBuildURLMixin, path?: string | null, parentURL?: st
}
// No path provided
- let url: string[] = [];
+ const url: string[] = [];
if (host) {
url.push(host);
}
@@ -669,7 +670,7 @@ function urlPrefix(this: MixtBuildURLMixin, path?: string | null, parentURL?: st
@return {String} path
**/
function pathForType(this: MixtBuildURLMixin, modelName: string): string {
- let camelized = camelize(modelName);
+ const camelized = camelize(modelName);
return pluralize(camelized);
}
diff --git a/packages/adapter/src/-private/utils/determine-body-promise.ts b/packages/adapter/src/-private/utils/determine-body-promise.ts
index 8c72f30eb20..2907dfe0c99 100644
--- a/packages/adapter/src/-private/utils/determine-body-promise.ts
+++ b/packages/adapter/src/-private/utils/determine-body-promise.ts
@@ -24,13 +24,13 @@ function _determineContent(response: Response, requestData: JQueryAjaxSettings,
return payload;
}
- let status = response.status;
- let payloadIsEmpty = payload === '' || payload === null;
- let statusIndicatesEmptyResponse = status === 204 || status === 205 || requestData.method === 'HEAD';
+ const status = response.status;
+ const payloadIsEmpty = payload === '' || payload === null;
+ const statusIndicatesEmptyResponse = status === 204 || status === 205 || requestData.method === 'HEAD';
if (DEBUG) {
if (payloadIsEmpty && !statusIndicatesEmptyResponse) {
- let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
+ const message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
if (payload === '') {
warn(message, {
id: 'ds.adapter.returned-empty-string-as-JSON',
diff --git a/packages/adapter/src/-private/utils/fetch.ts b/packages/adapter/src/-private/utils/fetch.ts
index f7cd1338562..8dd752dff91 100644
--- a/packages/adapter/src/-private/utils/fetch.ts
+++ b/packages/adapter/src/-private/utils/fetch.ts
@@ -41,10 +41,10 @@ export default function getFetchFunction(): FetchFunction {
// eslint-disable-next-line no-inner-declarations
function buildAbsoluteUrl(url: string) {
if (protocolRelativeRegex.test(url)) {
- let [host] = parseRequest(REQUEST);
+ const [host] = parseRequest(REQUEST);
url = host + url;
} else if (!httpRegex.test(url)) {
- let [host, protocol] = parseRequest(REQUEST);
+ const [host, protocol] = parseRequest(REQUEST);
url = protocol + '//' + host + url;
}
return url;
diff --git a/packages/adapter/src/-private/utils/parse-response-headers.ts b/packages/adapter/src/-private/utils/parse-response-headers.ts
index c95e429d0d9..3369092c308 100644
--- a/packages/adapter/src/-private/utils/parse-response-headers.ts
+++ b/packages/adapter/src/-private/utils/parse-response-headers.ts
@@ -10,7 +10,7 @@ export default function parseResponseHeaders(headersString: string): Record {
- let url = this.buildURL(type.modelName, ids, snapshots, 'findMany');
+ override findMany(store: Store, type: ModelSchema, ids: string[], snapshots: Snapshot[]): Promise {
+ const url = this.buildURL(type.modelName, ids, snapshots, 'findMany');
return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } });
}
- pathForType(modelName: string): string {
- let dasherized = dasherize(modelName);
+ override pathForType(modelName: string): string {
+ const dasherized = dasherize(modelName);
return pluralize(dasherized);
}
- updateRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
+ override updateRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
const data = serializeIntoHash(store, schema, snapshot);
const type = snapshot.modelName;
const id = snapshot.id;
assert(`Attempted to update the ${type} record, but the record has no id`, typeof id === 'string' && id.length > 0);
- let url = this.buildURL(type, id, snapshot, 'updateRecord');
+ const url = this.buildURL(type, id, snapshot, 'updateRecord');
return this.ajax(url, 'PATCH', { data: data });
}
diff --git a/packages/adapter/src/rest.ts b/packages/adapter/src/rest.ts
index f3cce065962..efbc151f136 100644
--- a/packages/adapter/src/rest.ts
+++ b/packages/adapter/src/rest.ts
@@ -1,3 +1,6 @@
+/* eslint-disable @typescript-eslint/no-unsafe-member-access */
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+/* eslint-disable @typescript-eslint/no-unsafe-return */
/**
@module @ember-data/adapter/rest
*/
@@ -8,9 +11,9 @@ import { computed } from '@ember/object';
import { DEBUG } from '@ember-data/env';
import type { Snapshot, SnapshotRecordArray } from '@ember-data/legacy-compat/-private';
import type { AdapterPayload } from '@ember-data/legacy-compat/legacy-network-handler/minimum-adapter-interface';
-import type { HTTPMethod } from '@ember-data/request/-private/types';
import type Store from '@ember-data/store';
import type { ModelSchema } from '@ember-data/store/-types/q/ds-model';
+import type { HTTPMethod } from '@warp-drive/core-types/request';
import { determineBodyPromise, fetch, parseResponseHeaders, serializeIntoHash, serializeQueryParams } from './-private';
import { MixtBuildURLMixin } from './-private/build-url-mixin';
@@ -38,11 +41,6 @@ export interface FetchRequestInit extends RequestInit {
url: string;
method: HTTPMethod;
type: HTTPMethod;
- contentType?: string | false;
- body?: any;
- data?: any;
- cache?: any;
- headers?: any;
}
export interface JQueryRequestInit extends JQueryAjaxSettings {
@@ -54,14 +52,14 @@ export interface JQueryRequestInit extends JQueryAjaxSettings {
export type RequestData = {
url: string;
method: HTTPMethod;
- [key: string]: any;
+ [key: string]: unknown;
};
type ResponseData = {
status: number;
textStatus: string;
- headers: Record;
- errorThrown?: any;
+ headers: Record;
+ errorThrown?: Error | string;
};
declare const jQuery: JQueryStatic | undefined;
@@ -337,6 +335,7 @@ declare const jQuery: JQueryStatic | undefined;
*/
class RESTAdapter extends Adapter.extend(BuildURLMixin) {
declare _fastboot: FastBoot;
+ declare _coalesceFindRequests: boolean;
declare host: string | null;
declare namespace: string | null;
@@ -356,11 +355,11 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
get fastboot() {
// Avoid computed property override deprecation in fastboot as suggested by:
// https://deprecations.emberjs.com/v3.x/#toc_computed-property-override
- let fastboot = this._fastboot;
+ const fastboot = this._fastboot;
if (fastboot) {
return fastboot;
}
- return (this._fastboot = (getOwner(this) as any).lookup('service:fastboot'));
+ return (this._fastboot = getOwner(this)!.lookup('service:fastboot') as FastBoot);
}
set fastboot(value: FastBoot) {
@@ -410,14 +409,14 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Object}
@public
*/
- sortQueryParams(obj): Record {
- let keys = Object.keys(obj);
- let len = keys.length;
+ sortQueryParams(obj: Record): Record {
+ const keys = Object.keys(obj);
+ const len = keys.length;
if (len < 2) {
return obj;
}
- let newQueryParams = {};
- let sortedKeys = keys.sort();
+ const newQueryParams: Record = {};
+ const sortedKeys = keys.sort();
for (let i = 0; i < len; i++) {
newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]];
@@ -473,15 +472,15 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@public
@type {boolean}
*/
- get coalesceFindRequests() {
- let coalesceFindRequests = this._coalesceFindRequests;
+ override get coalesceFindRequests() {
+ const coalesceFindRequests = this._coalesceFindRequests;
if (typeof coalesceFindRequests === 'boolean') {
return coalesceFindRequests;
}
return (this._coalesceFindRequests = false);
}
- set coalesceFindRequests(value: boolean) {
+ override set coalesceFindRequests(value: boolean) {
this._coalesceFindRequests = value;
}
@@ -567,9 +566,9 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Snapshot} snapshot
@return {Promise} promise
*/
- findRecord(store: Store, type: ModelSchema, id: string, snapshot: Snapshot): Promise {
- let url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
- let query: QueryState = this.buildQuery(snapshot);
+ override findRecord(store: Store, type: ModelSchema, id: string, snapshot: Snapshot): Promise {
+ const url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
+ const query: QueryState = this.buildQuery(snapshot);
return this.ajax(url, 'GET', { data: query });
}
@@ -589,14 +588,14 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {SnapshotRecordArray} snapshotRecordArray
@return {Promise} promise
*/
- findAll(
+ override findAll(
store: Store,
type: ModelSchema,
- sinceToken,
+ sinceToken: null,
snapshotRecordArray: SnapshotRecordArray
): Promise {
- let query: QueryState = this.buildQuery(snapshotRecordArray);
- let url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll');
+ const query: QueryState = this.buildQuery(snapshotRecordArray);
+ const url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll');
if (sinceToken) {
query.since = sinceToken;
@@ -625,8 +624,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Object} adapterOptions
@return {Promise} promise
*/
- query(store: Store, type: ModelSchema, query): Promise {
- let url = this.buildURL(type.modelName, null, null, 'query', query);
+ override query(store: Store, type: ModelSchema, query: Record): Promise {
+ const url = this.buildURL(type.modelName, null, null, 'query', query);
if (this.sortQueryParams) {
query = this.sortQueryParams(query);
@@ -655,13 +654,13 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Object} adapterOptions
@return {Promise} promise
*/
- queryRecord(
+ override queryRecord(
store: Store,
type: ModelSchema,
query: Record,
adapterOptions: Record
): Promise {
- let url = this.buildURL(type.modelName, null, null, 'queryRecord', query);
+ const url = this.buildURL(type.modelName, null, null, 'queryRecord', query);
if (this.sortQueryParams) {
query = this.sortQueryParams(query);
@@ -705,7 +704,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Promise} promise
*/
findMany(store: Store, type: ModelSchema, ids: string[], snapshots: Snapshot[]): Promise {
- let url = this.buildURL(type.modelName, ids, snapshots, 'findMany');
+ const url = this.buildURL(type.modelName, ids, snapshots, 'findMany');
return this.ajax(url, 'GET', { data: { ids: ids } });
}
@@ -752,8 +751,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
url: string,
relationship: Record
): Promise {
- let id = snapshot.id;
- let type = snapshot.modelName;
+ const id = snapshot.id;
+ const type = snapshot.modelName;
assert(
`Attempted to fetch the hasMany relationship for ${type}, but the record has no id`,
@@ -802,8 +801,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Promise} promise
*/
findBelongsTo(store: Store, snapshot: Snapshot, url: string, relationship): Promise {
- let id = snapshot.id;
- let type = snapshot.modelName;
+ const id = snapshot.id;
+ const type = snapshot.modelName;
assert(
`Attempted to fetch the belongsTo relationship for ${type}, but the record has no id`,
@@ -830,8 +829,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Snapshot} snapshot
@return {Promise} promise
*/
- createRecord(store: Store, type: ModelSchema, snapshot: Snapshot): Promise {
- let url = this.buildURL(type.modelName, null, snapshot, 'createRecord');
+ override createRecord(store: Store, type: ModelSchema, snapshot: Snapshot): Promise {
+ const url = this.buildURL(type.modelName, null, snapshot, 'createRecord');
const data = serializeIntoHash(store, type, snapshot);
@@ -855,12 +854,12 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Snapshot} snapshot
@return {Promise} promise
*/
- updateRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
+ override updateRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
const data = serializeIntoHash(store, schema, snapshot, {});
const type = snapshot.modelName;
const id = snapshot.id;
assert(`Attempted to update the ${type} record, but the record has no id`, typeof id === 'string' && id.length > 0);
- let url = this.buildURL(type, id, snapshot, 'updateRecord');
+ const url = this.buildURL(type, id, snapshot, 'updateRecord');
return this.ajax(url, 'PUT', { data });
}
@@ -877,7 +876,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Snapshot} snapshot
@return {Promise} promise
*/
- deleteRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
+ override deleteRecord(store: Store, schema: ModelSchema, snapshot: Snapshot): Promise {
const type = snapshot.modelName;
const id = snapshot.id;
assert(`Attempted to delete the ${type} record, but the record has no id`, typeof id === 'string' && id.length > 0);
@@ -893,15 +892,15 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
typeof id === 'string' && id.length > 0
);
- let url = this.buildURL(type, id, snapshot);
+ const url = this.buildURL(type, id, snapshot);
- let expandedURL = url.split('/');
+ const expandedURL = url.split('/');
// Case when the url is of the format ...something/:id
// We are decodeURIComponent-ing the lastSegment because if it represents
// the id, it has been encodeURIComponent-ified within `buildURL`. If we
// don't do this, then records with id having special characters are not
// coalesced correctly (see GH #4190 for the reported bug)
- let lastSegment: string = expandedURL[expandedURL.length - 1];
+ const lastSegment: string = expandedURL[expandedURL.length - 1];
if (decodeURIComponent(lastSegment) === id) {
expandedURL[expandedURL.length - 1] = '';
} else if (id && endsWith(lastSegment, '?id=' + id)) {
@@ -938,23 +937,23 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Array} an array of arrays of records, each of which is to be
loaded separately by `findMany`.
*/
- groupRecordsForFindMany(store: Store, snapshots: Snapshot[]): Snapshot[][] {
- let groups = new Map();
- let maxURLLength = this.maxURLLength;
+ override groupRecordsForFindMany(store: Store, snapshots: Snapshot[]): Snapshot[][] {
+ const groups: Map = new Map();
+ const maxURLLength = this.maxURLLength;
snapshots.forEach((snapshot) => {
- let baseUrl = this._stripIDFromURL(store, snapshot);
+ const baseUrl = this._stripIDFromURL(store, snapshot);
if (!groups.has(baseUrl)) {
groups.set(baseUrl, []);
}
- groups.get(baseUrl).push(snapshot);
+ groups.get(baseUrl)!.push(snapshot);
});
- let groupsArray: Snapshot[][] = [];
+ const groupsArray: Snapshot[][] = [];
groups.forEach((group, key) => {
- let paramNameLength = '&ids%5B%5D='.length;
- let splitGroups = splitGroupToFitInUrl(store, this, group, maxURLLength, paramNameLength);
+ const paramNameLength = '&ids%5B%5D='.length;
+ const splitGroups = splitGroupToFitInUrl(store, this, group, maxURLLength, paramNameLength);
splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup));
});
@@ -994,7 +993,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
*/
handleResponse(
status: number,
- headers: Record,
+ headers: Record,
payload: Payload,
requestData: RequestData
): Payload | AdapterError {
@@ -1004,8 +1003,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
return new InvalidError(typeof payload === 'object' && 'errors' in payload ? payload.errors : undefined);
}
- let errors = this.normalizeErrorResponse(status, headers, payload);
- let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData);
+ const errors = this.normalizeErrorResponse(status, headers, payload);
+ const detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData);
switch (status) {
case 401:
@@ -1082,19 +1081,21 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Promise} promise
*/
async ajax(url: string, type: HTTPMethod, options: JQueryAjaxSettings | RequestInit = {}): Promise {
- let requestData: RequestData = {
+ const requestData: RequestData = {
url: url,
method: type,
};
if (this.useFetch) {
- let hash: FetchRequestInit = this.ajaxOptions(url, type, options);
- let response = await this._fetchRequest(hash);
- let payload = await determineBodyPromise(response, requestData);
+ // @ts-expect-error poorly typed
+ const hash: FetchRequestInit = this.ajaxOptions(url, type, options);
+ const response = await this._fetchRequest(hash);
+ const payload = await determineBodyPromise(response, requestData);
if (response.ok && !(payload instanceof Error)) {
return fetchSuccessHandler(this, payload, response, requestData);
} else {
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
throw fetchErrorHandler(this, payload, response, null, requestData);
}
} else {
@@ -1109,18 +1110,18 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
*/
_ajaxRequest(options: JQueryRequestInit): void {
assert('You must install jQuery globally when `useFetch` is false', typeof jQuery !== 'undefined');
- jQuery.ajax(options);
+ void jQuery.ajax(options);
}
_fetchRequest(options: FetchRequestInit): Promise {
- let fetchFunction = fetch();
+ const fetchFunction = fetch();
return fetchFunction(options.url, options);
}
_ajax(options: FetchRequestInit | JQueryRequestInit): void {
if (this.useFetch) {
- this._fetchRequest(options as FetchRequestInit);
+ void this._fetchRequest(options as FetchRequestInit);
} else {
this._ajaxRequest(options as JQueryRequestInit);
}
@@ -1149,26 +1150,33 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
);
if (this.headers !== undefined) {
+ // @ts-expect-error poorly typed
reqOptions.headers = { ...this.headers, ...reqOptions.headers };
} else if (!options.headers) {
reqOptions.headers = {};
}
- let contentType = reqOptions.contentType || this._defaultContentType;
+ // @ts-expect-error poorly typed
+ const contentType = reqOptions.contentType || this._defaultContentType;
if (this.useFetch) {
+ // @ts-expect-error poorly typed
if (reqOptions.data && reqOptions.type !== 'GET' && reqOptions.headers) {
if (!reqOptions.headers['Content-Type'] && !reqOptions.headers['content-type']) {
reqOptions.headers['content-type'] = contentType;
}
}
+ // @ts-expect-error poorly typed
reqOptions = fetchOptions(reqOptions, this);
} else {
// GET requests without a body should not have a content-type header
// and may be unexpected by a server
+ // @ts-expect-error poorly typed
if (reqOptions.data && reqOptions.type !== 'GET') {
+ // @ts-expect-error poorly typed
reqOptions = { ...reqOptions, contentType };
}
+ // @ts-expect-error poorly typed
reqOptions = ajaxOptions(reqOptions, this);
}
@@ -1179,10 +1187,10 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
_ajaxURL(url: string): string {
if (this.fastboot?.isFastBoot) {
- let httpRegex = /^https?:\/\//;
- let protocolRelativeRegex = /^\/\//;
- let protocol = this.fastboot.request.protocol;
- let host = this.fastboot.request.host;
+ const httpRegex = /^https?:\/\//;
+ const protocolRelativeRegex = /^\/\//;
+ const protocol = this.fastboot.request.protocol;
+ const host = this.fastboot.request.host;
if (protocolRelativeRegex.test(url)) {
return `${protocol}${url}`;
@@ -1261,9 +1269,14 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@param {Object} requestData
@return {String} detailed error message
*/
- generatedDetailedMessage(status: number, headers, payload: Payload, requestData: RequestData): string {
+ generatedDetailedMessage(
+ status: number,
+ headers: Record,
+ payload: Payload,
+ requestData: RequestData
+ ): string {
let shortenedPayload;
- let payloadContentType = headers['content-type'] || 'Empty Content-Type';
+ const payloadContentType = headers['content-type'] || 'Empty Content-Type';
if (payloadContentType === 'text/html' && typeof payload === 'string' && payload.length > 250) {
shortenedPayload = '[Omitted Lengthy HTML]';
@@ -1273,8 +1286,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
shortenedPayload = payload;
}
- let requestDescription = requestData.method + ' ' + requestData.url;
- let payloadDescription = 'Payload (' + payloadContentType + ')';
+ const requestDescription = requestData.method + ' ' + requestData.url;
+ const payloadDescription = 'Payload (' + payloadContentType + ')';
return [
'Ember Data Request ' + requestDescription + ' returned a ' + status,
@@ -1294,10 +1307,10 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) {
@return {Object}
*/
buildQuery(snapshot: Snapshot | SnapshotRecordArray): QueryState {
- let query: QueryState = {};
+ const query: QueryState = {};
if (snapshot) {
- let { include } = snapshot;
+ const { include } = snapshot;
if (include) {
query.include = include;
@@ -1362,10 +1375,10 @@ function ajaxError(
// Adapter abort error to include any relevent info, e.g. request/response:
function handleAbort(requestData: RequestData, responseData: ResponseData): AbortError {
- let { method, url, errorThrown } = requestData;
- let { status } = responseData;
- let msg = `Request failed: ${method} ${url} ${errorThrown || ''}`;
- let errors = [{ title: 'Adapter Error', detail: msg.trim(), status }];
+ const { method, url, errorThrown } = requestData;
+ const { status } = responseData;
+ const msg = `Request failed: ${method} ${url} ${String(errorThrown ?? '')}`;
+ const errors = [{ title: 'Adapter Error', detail: msg.trim(), status }];
return new AbortError(errors);
}
@@ -1384,7 +1397,7 @@ function fetchSuccessHandler(
response: Response,
requestData: RequestData
): Promise {
- let responseData = fetchResponseData(response);
+ const responseData = fetchResponseData(response);
return ajaxSuccess(adapter, payload, requestData, responseData);
}
@@ -1394,11 +1407,12 @@ function fetchErrorHandler(
response: Response,
errorThrown,
requestData: RequestData
-): Error {
- let responseData = fetchResponseData(response);
+): Error | TimeoutError | Record {
+ const responseData = fetchResponseData(response);
if (responseData.status === 200 && payload instanceof Error) {
responseData.errorThrown = payload;
+ // @ts-expect-error poorly typed
payload = responseData.errorThrown.payload;
} else {
responseData.errorThrown = errorThrown;
@@ -1415,18 +1429,23 @@ function ajaxSuccessHandler(
jqXHR: JQuery.jqXHR,
requestData: RequestData
): Promise {
- let responseData = ajaxResponseData(jqXHR);
+ const responseData = ajaxResponseData(jqXHR);
return ajaxSuccess(adapter, payload, requestData, responseData);
}
-function ajaxErrorHandler(adapter: RESTAdapter, jqXHR: JQuery.jqXHR, errorThrown: string, requestData: RequestData) {
- let responseData = ajaxResponseData(jqXHR);
+function ajaxErrorHandler(
+ adapter: RESTAdapter,
+ jqXHR: JQuery.jqXHR,
+ errorThrown: Error | string,
+ requestData: RequestData
+) {
+ const responseData = ajaxResponseData(jqXHR);
responseData.errorThrown = errorThrown;
- let payload = adapter.parseErrorResponse(jqXHR.responseText);
+ const payload = adapter.parseErrorResponse(jqXHR.responseText);
if (DEBUG) {
- let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
- let validJSONString = !(responseData.textStatus === 'parsererror' && payload === '');
+ const message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`;
+ const validJSONString = !(responseData.textStatus === 'parsererror' && payload === '');
warn(message, validJSONString, {
id: 'ds.adapter.returned-empty-string-as-JSON',
});
@@ -1451,8 +1470,8 @@ function ajaxResponseData(jqXHR: JQuery.jqXHR): ResponseData {
};
}
-function headersToObject(headers: Headers): Record {
- let headersObject = {};
+function headersToObject(headers: Headers): Record {
+ const headersObject = {};
if (headers) {
headers.forEach((value, key) => (headersObject[key] = value));
@@ -1500,6 +1519,7 @@ export function fetchOptions(
if (Object.prototype.toString.call(options.data) === '[object Object]') {
options.body = JSON.stringify(options.data);
} else {
+ // @ts-expect-error poorly typed
options.body = options.data;
}
}
@@ -1519,7 +1539,7 @@ function ajaxOptions(options: JQueryRequestInit, adapter: RESTAdapter): JQueryRe
options.beforeSend = function (xhr) {
if (options.headers) {
Object.keys(options.headers).forEach((key) => {
- let headerValue = options.headers && options.headers[key];
+ const headerValue = options.headers && options.headers[key];
const isString = (value: unknown): value is string => typeof value === 'string';
if (isString(headerValue)) {
xhr.setRequestHeader(key, headerValue);
@@ -1539,13 +1559,13 @@ function execjQAjax(
const hash = adapter.ajaxOptions(requestData.url, requestData.method, options) as JQueryRequestInit;
return new Promise((resolve, reject) => {
- hash.success = function (payload, textStatus, jqXHR) {
- let response = ajaxSuccessHandler(adapter, payload, jqXHR, requestData);
+ hash.success = function (payload: Payload, textStatus, jqXHR) {
+ const response = ajaxSuccessHandler(adapter, payload, jqXHR, requestData);
resolve(response);
};
- hash.error = function (jqXHR, textStatus, errorThrown) {
- let error = ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData);
+ hash.error = function (jqXHR, textStatus, errorThrown: Error | string) {
+ const error = ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData);
reject(error);
};
@@ -1553,13 +1573,19 @@ function execjQAjax(
});
}
-function splitGroupToFitInUrl(store, adapter, group, maxURLLength, paramNameLength) {
+function splitGroupToFitInUrl(
+ store: Store,
+ adapter: RESTAdapter,
+ group: Snapshot[],
+ maxURLLength: number,
+ paramNameLength: number
+) {
let idsSize = 0;
- let baseUrl = adapter._stripIDFromURL(store, group[0]);
- let splitGroups: Snapshot[][] = [[]];
+ const baseUrl = adapter._stripIDFromURL(store, group[0]);
+ const splitGroups: Snapshot[][] = [[]];
group.forEach((snapshot) => {
- let additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength;
+ const additionalLength = encodeURIComponent(snapshot.id!).length + paramNameLength;
if (baseUrl.length + idsSize + additionalLength >= maxURLLength) {
idsSize = 0;
splitGroups.push([]);
@@ -1567,7 +1593,7 @@ function splitGroupToFitInUrl(store, adapter, group, maxURLLength, paramNameLeng
idsSize += additionalLength;
- let lastGroupIndex = splitGroups.length - 1;
+ const lastGroupIndex = splitGroups.length - 1;
splitGroups[lastGroupIndex].push(snapshot);
});
diff --git a/packages/adapter/tsconfig.json b/packages/adapter/tsconfig.json
new file mode 100644
index 00000000000..eda880a7c70
--- /dev/null
+++ b/packages/adapter/tsconfig.json
@@ -0,0 +1,47 @@
+{
+ "include": [
+ "src/**/*",
+ "../../@types/**/*",
+ ],
+ "baseUrl": ".",
+ "compilerOptions": {
+ "lib": ["DOM", "ESNext"],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "experimentalDecorators": true,
+ "noImplicitAny": false,
+ "allowJs": true,
+ "noEmit": false,
+ "noImplicitOverride": true,
+
+ // Enable faster builds
+ // but causes us to not rebuild properly
+ "incremental": false,
+
+ "declaration": true,
+ "declarationMap": true,
+ "declarationDir": "unstable-preview-types",
+ "emitDeclarationOnly": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "types": [
+ "ember-source/types",
+ "@types/jquery",
+ ],
+
+ "paths": {
+ "@ember-data/deprecations": ["../private-build-infra/virtual-packages/deprecations.d.ts"],
+ "@ember-data/packages": ["../private-build-infra/virtual-packages/packages.d.ts"],
+ "@ember-data/canary-features": ["../private-build-infra/virtual-packages/canary-features.d.ts"],
+ "@ember-data/debugging": ["../private-build-infra/virtual-packages/debugging.d.ts"],
+ "@ember-data/env": ["../private-build-infra/virtual-packages/env.d.ts"],
+ }
+ },
+}
diff --git a/packages/core-types/.eslintrc.cjs b/packages/core-types/.eslintrc.cjs
new file mode 100644
index 00000000000..94f092444d8
--- /dev/null
+++ b/packages/core-types/.eslintrc.cjs
@@ -0,0 +1,26 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/core/LICENSE.md b/packages/core-types/LICENSE.md
similarity index 100%
rename from packages/core/LICENSE.md
rename to packages/core-types/LICENSE.md
diff --git a/packages/core/NCC-1701-a-blue.svg b/packages/core-types/NCC-1701-a-blue.svg
similarity index 100%
rename from packages/core/NCC-1701-a-blue.svg
rename to packages/core-types/NCC-1701-a-blue.svg
diff --git a/packages/core/NCC-1701-a.svg b/packages/core-types/NCC-1701-a.svg
similarity index 100%
rename from packages/core/NCC-1701-a.svg
rename to packages/core-types/NCC-1701-a.svg
diff --git a/packages/core/README.md b/packages/core-types/README.md
similarity index 91%
rename from packages/core/README.md
rename to packages/core-types/README.md
index 4a3752c8f00..6286509020b 100644
--- a/packages/core/README.md
+++ b/packages/core-types/README.md
@@ -13,8 +13,8 @@
title="WarpDrive" />
-🛸 @warp-drive/core
-Provides core logic, utils and types for WarpDrive and EmberData
+🛸 @warp-drive/core-types
+Provides core types, type utils and constants for WarpDrive and EmberData
### ♥️ Credits
diff --git a/packages/core/addon-main.cjs b/packages/core-types/addon-main.cjs
similarity index 100%
rename from packages/core/addon-main.cjs
rename to packages/core-types/addon-main.cjs
diff --git a/packages/core/babel.config.js b/packages/core-types/babel.config.js
similarity index 50%
rename from packages/core/babel.config.js
rename to packages/core-types/babel.config.js
index 15100a5b69c..dac1037557b 100644
--- a/packages/core/babel.config.js
+++ b/packages/core-types/babel.config.js
@@ -1,8 +1,5 @@
const macros = require('@ember-data/private-build-infra/src/v2-babel-build-pack');
module.exports = {
- plugins: [
- ...macros,
- ['@babel/plugin-transform-typescript', { allowDeclareFields: true }]
- ],
+ plugins: [...macros, ['@babel/plugin-transform-typescript', { allowDeclareFields: true }]],
};
diff --git a/packages/core/package.json b/packages/core-types/package.json
similarity index 83%
rename from packages/core/package.json
rename to packages/core-types/package.json
index 6d05af0034d..bf0488622c0 100644
--- a/packages/core/package.json
+++ b/packages/core-types/package.json
@@ -1,5 +1,5 @@
{
- "name": "@warp-drive/core",
+ "name": "@warp-drive/core-types",
"version": "5.5.0-alpha.11",
"description": "Provides core logic, utils and types for WarpDrive and EmberData",
"keywords": [
@@ -8,16 +8,17 @@
"repository": {
"type": "git",
"url": "git+ssh://git@github.com:emberjs/data.git",
- "directory": "packages/core"
+ "directory": "packages/core-types"
},
"license": "MIT",
"author": "Chris Thoburn ",
"scripts": {
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
"build:types": "tsc --build --force",
"build:client": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
"build": "pnpm build:client && pnpm build:types",
"prepack": "pnpm build",
- "prepare": "pnpm build"
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
},
"files": [
"addon",
@@ -38,14 +39,17 @@
"default": "./addon/*.js"
}
},
- "peerDependencies": {},
"dependencies": {
"@ember-data/private-build-infra": "workspace:5.5.0-alpha.11",
- "ember-cli-babel": "^8.2.0"
+ "ember-cli-babel": "^8.2.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10"
},
"dependenciesMeta": {
"@ember-data/private-build-infra": {
"injected": true
+ },
+ "@warp-drive/internal-config": {
+ "injected": true
}
},
"devDependencies": {
@@ -59,14 +63,13 @@
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@babel/runtime": "^7.23.2",
- "@ember-data/store": "workspace:5.5.0-alpha.11",
"@embroider/addon-dev": "^4.1.1",
"@glimmer/component": "^1.1.2",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
"ember-source": "~5.3.0",
"rollup": "^4.1.4",
- "tslib": "^2.6.2",
"typescript": "^5.2.2",
"walk-sync": "^3.0.0",
"webpack": "^5.89.0"
@@ -86,4 +89,4 @@
"ember": {
"edition": "octane"
}
-}
\ No newline at end of file
+}
diff --git a/packages/core/rollup.config.mjs b/packages/core-types/rollup.config.mjs
similarity index 81%
rename from packages/core/rollup.config.mjs
rename to packages/core-types/rollup.config.mjs
index db00645ef7b..a87af668d2d 100644
--- a/packages/core/rollup.config.mjs
+++ b/packages/core-types/rollup.config.mjs
@@ -2,6 +2,8 @@ import { Addon } from '@embroider/addon-dev/rollup';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { external } from '@warp-drive/internal-config/rollup/external.js';
+
const addon = new Addon({
srcDir: 'src',
destDir: 'addon',
@@ -12,12 +14,12 @@ export default {
// You can augment this if you need to.
output: addon.output(),
- external: [],
+ external: external(),
plugins: [
// These are the modules that users should be able to import from your
// addon. Anything not listed here may get optimized away.
- addon.publicEntrypoints(['index.js', 'identifier.js']),
+ addon.publicEntrypoints(['index.js', 'identifier.js', 'request.js']),
nodeResolve({ extensions: ['.ts'] }),
babel({
diff --git a/packages/store/src/-types/cache/cache.ts b/packages/core-types/src/cache.ts
similarity index 93%
rename from packages/store/src/-types/cache/cache.ts
rename to packages/core-types/src/cache.ts
index 09fdd6cf0fb..9f1590b89a6 100644
--- a/packages/store/src/-types/cache/cache.ts
+++ b/packages/core-types/src/cache.ts
@@ -1,19 +1,25 @@
/**
* @module @ember-data/experimental-preview-types
*/
-import { StableRecordIdentifier } from '@warp-drive/core';
-
-import type { StructuredDataDocument, StructuredDocument } from '@ember-data/request';
-import { StoreRequestContext } from '@ember-data/store/-private/cache-handler';
-
-import { CollectionResourceRelationship, SingleResourceRelationship } from '../q/ember-data-json-api';
-import { JsonApiError } from '../q/record-data-json-api';
-import { ResourceBlob } from './aliases';
-import { Change } from './change';
-import { ResourceDocument, SingleResourceDataDocument } from './document';
+import { ResourceBlob } from './cache/aliases';
+import { Change } from './cache/change';
+import { Mutation } from './cache/mutations';
+import { Operation } from './cache/operations';
+import type { CollectionRelationship, ResourceRelationship } from './cache/relationship';
+import type { StableRecordIdentifier } from './identifier';
import { StableDocumentIdentifier } from './identifier';
-import { Mutation } from './mutations';
-import { Operation } from './operations';
+import type { Value } from './json/raw';
+import type { RequestContext, StructuredDataDocument, StructuredDocument } from './request';
+import { ResourceDocument, SingleResourceDataDocument } from './spec/document';
+import { ApiError } from './spec/error';
+
+/**
+ * A hash of changed attributes with the key being the attribute name and the value being an
+ * array of `[oldValue, newValue]`.
+ *
+ * @internal
+ */
+export type ChangedAttributesHash = Record;
export type RelationshipDiff =
| {
@@ -280,7 +286,7 @@ export interface Cache {
* @public
* @param identifier
*/
- willCommit(identifier: StableRecordIdentifier, context: StoreRequestContext): void;
+ willCommit(identifier: StableRecordIdentifier, context: RequestContext): void;
/**
* [LIFECYCLE] Signals to the cache that a resource
@@ -303,7 +309,7 @@ export interface Cache {
* @param identifier
* @param errors
*/
- commitWasRejected(identifier: StableRecordIdentifier, errors?: JsonApiError[]): void;
+ commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[]): void;
/**
* [LIFECYCLE] Signals to the cache that all data for a resource
@@ -342,7 +348,7 @@ export interface Cache {
* @param field
* @param value
*/
- setAttr(identifier: StableRecordIdentifier, field: string, value: unknown): void;
+ setAttr(identifier: StableRecordIdentifier, field: string, value: Value): void;
/**
* Query the cache for the changed attributes of a resource.
@@ -358,7 +364,7 @@ export interface Cache {
* @param identifier
* @returns {Record} { : [, ] }
*/
- changedAttrs(identifier: StableRecordIdentifier): Record;
+ changedAttrs(identifier: StableRecordIdentifier): ChangedAttributesHash;
/**
* Query the cache for whether any mutated attributes exist
@@ -448,7 +454,7 @@ export interface Cache {
identifier: StableRecordIdentifier,
field: string,
isCollection?: boolean
- ): SingleResourceRelationship | CollectionResourceRelationship;
+ ): ResourceRelationship | CollectionRelationship;
// Resource State
// ===============
@@ -474,7 +480,7 @@ export interface Cache {
* @param identifier
* @returns {JsonApiError[]}
*/
- getErrors(identifier: StableRecordIdentifier): JsonApiError[];
+ getErrors(identifier: StableRecordIdentifier): ApiError[];
/**
* Query the cache for whether a given resource has any available data
diff --git a/packages/store/src/-types/cache/aliases.ts b/packages/core-types/src/cache/aliases.ts
similarity index 100%
rename from packages/store/src/-types/cache/aliases.ts
rename to packages/core-types/src/cache/aliases.ts
diff --git a/packages/store/src/-types/cache/change.ts b/packages/core-types/src/cache/change.ts
similarity index 54%
rename from packages/store/src/-types/cache/change.ts
rename to packages/core-types/src/cache/change.ts
index 112b24789cc..07a821d0037 100644
--- a/packages/store/src/-types/cache/change.ts
+++ b/packages/core-types/src/cache/change.ts
@@ -1,6 +1,4 @@
-import { StableRecordIdentifier } from '@warp-drive/core';
-
-import { StableDocumentIdentifier } from './identifier';
+import type { StableDocumentIdentifier, StableRecordIdentifier } from '../identifier';
export interface Change {
identifier: StableRecordIdentifier | StableDocumentIdentifier;
diff --git a/packages/store/src/-types/cache/mutations.ts b/packages/core-types/src/cache/mutations.ts
similarity index 97%
rename from packages/store/src/-types/cache/mutations.ts
rename to packages/core-types/src/cache/mutations.ts
index 64d5bff6ed6..e7ff59bcf60 100644
--- a/packages/store/src/-types/cache/mutations.ts
+++ b/packages/core-types/src/cache/mutations.ts
@@ -1,4 +1,4 @@
-import { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '../identifier';
export interface AddToRelatedRecordsMutation {
op: 'addToRelatedRecords';
diff --git a/packages/store/src/-types/cache/operations.ts b/packages/core-types/src/cache/operations.ts
similarity index 92%
rename from packages/store/src/-types/cache/operations.ts
rename to packages/core-types/src/cache/operations.ts
index bbd5fda75b5..0a0d8dd280f 100644
--- a/packages/store/src/-types/cache/operations.ts
+++ b/packages/core-types/src/cache/operations.ts
@@ -1,4 +1,4 @@
-import { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '../identifier';
export interface Op {
op: string;
diff --git a/packages/store/src/-types/cache/relationship.ts b/packages/core-types/src/cache/relationship.ts
similarity index 78%
rename from packages/store/src/-types/cache/relationship.ts
rename to packages/core-types/src/cache/relationship.ts
index 988338d2d01..38e2939915c 100644
--- a/packages/store/src/-types/cache/relationship.ts
+++ b/packages/core-types/src/cache/relationship.ts
@@ -1,6 +1,5 @@
-import { StableRecordIdentifier } from '@warp-drive/core';
-
-import { Links, Meta, PaginationLinks } from '../q/ember-data-json-api';
+import type { StableRecordIdentifier } from '../identifier';
+import type { Links, Meta, PaginationLinks } from '../spec/raw';
// we request that it be in the stable form already.
export interface ResourceRelationship {
diff --git a/packages/graph/src/-private/-operations.ts b/packages/core-types/src/graph.ts
similarity index 81%
rename from packages/graph/src/-private/-operations.ts
rename to packages/core-types/src/graph.ts
index 4971c0c0420..57d1b9f2335 100644
--- a/packages/graph/src/-private/-operations.ts
+++ b/packages/core-types/src/graph.ts
@@ -1,9 +1,16 @@
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { CollectionRelationship, ResourceRelationship } from './cache/relationship';
+import type { StableRecordIdentifier } from './identifier';
+import type { CollectionResourceRelationship, SingleResourceRelationship } from './spec/raw';
-import type {
- CollectionResourceRelationship,
- SingleResourceRelationship,
-} from '@ember-data/store/-types/q/ember-data-json-api';
+export interface Graph {
+ identifiers: Map;
+
+ getData(identifier: StableRecordIdentifier, field: string): ResourceRelationship | CollectionRelationship;
+
+ remove(identifier: StableRecordIdentifier): void;
+ registerPolymorphicType(abstract: string, concrete: string): void;
+ destroy(): void;
+}
export interface Operation {
op: string;
diff --git a/packages/core/src/identifier.ts b/packages/core-types/src/identifier.ts
similarity index 98%
rename from packages/core/src/identifier.ts
rename to packages/core-types/src/identifier.ts
index 7fba3594b5d..58c8cb4f983 100644
--- a/packages/core/src/identifier.ts
+++ b/packages/core-types/src/identifier.ts
@@ -1,6 +1,7 @@
/**
@module @ember-data/store
*/
+
// provided for additional debuggability
export const DEBUG_CLIENT_ORIGINATED: unique symbol = Symbol('record-originated-on-client');
export const DEBUG_IDENTIFIER_BUCKET: unique symbol = Symbol('identifier-bucket');
@@ -26,6 +27,10 @@ export interface NewRecordIdentifier extends Identifier {
type: string;
}
+export type StableDocumentIdentifier = {
+ lid: string;
+};
+
/**
* An Identifier specific to a record which may or may not
* be present in the cache.
diff --git a/packages/core/src/index.ts b/packages/core-types/src/index.ts
similarity index 100%
rename from packages/core/src/index.ts
rename to packages/core-types/src/index.ts
diff --git a/packages/store/src/-types/json/raw.ts b/packages/core-types/src/json/raw.ts
similarity index 100%
rename from packages/store/src/-types/json/raw.ts
rename to packages/core-types/src/json/raw.ts
diff --git a/packages/core-types/src/params.ts b/packages/core-types/src/params.ts
new file mode 100644
index 00000000000..a2053f79e9c
--- /dev/null
+++ b/packages/core-types/src/params.ts
@@ -0,0 +1,6 @@
+export type SerializablePrimitive = string | number | boolean | null;
+export type Serializable = SerializablePrimitive | SerializablePrimitive[];
+export type QueryParamsSerializationOptions = {
+ arrayFormat?: 'bracket' | 'indices' | 'repeat' | 'comma';
+};
+export type QueryParamsSource = Record | URLSearchParams;
diff --git a/packages/core-types/src/request.ts b/packages/core-types/src/request.ts
new file mode 100644
index 00000000000..cd8bb41ca47
--- /dev/null
+++ b/packages/core-types/src/request.ts
@@ -0,0 +1,229 @@
+import type { StableRecordIdentifier } from './identifier';
+import type { QueryParamsSerializationOptions } from './params';
+import type { ResourceIdentifierObject } from './spec/raw';
+
+type Store = unknown;
+
+export const SkipCache = Symbol.for('wd:skip-cache');
+export const EnableHydration = Symbol.for('wd:enable-hydration');
+export const IS_FUTURE = Symbol('IS_FUTURE');
+export const STRUCTURED = Symbol('DOC');
+
+export type HTTPMethod = 'GET' | 'OPTIONS' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';
+
+export type CacheOptions = {
+ key?: string;
+ reload?: boolean;
+ backgroundReload?: boolean;
+};
+export type FindRecordRequestOptions = {
+ url: string;
+ method: 'GET';
+ headers: Headers;
+ cacheOptions: CacheOptions;
+ op: 'findRecord';
+ records: [ResourceIdentifierObject];
+};
+
+export type QueryRequestOptions = {
+ url: string;
+ method: 'GET';
+ headers: Headers;
+ cacheOptions: CacheOptions;
+ op: 'query';
+};
+
+export type PostQueryRequestOptions = {
+ url: string;
+ method: 'POST' | 'QUERY';
+ headers: Headers;
+ body: string;
+ cacheOptions: CacheOptions & { key: string };
+ op: 'query';
+};
+
+export type DeleteRequestOptions = {
+ url: string;
+ method: 'DELETE';
+ headers: Headers;
+ op: 'deleteRecord';
+ data: {
+ record: StableRecordIdentifier;
+ };
+};
+
+export type UpdateRequestOptions = {
+ url: string;
+ method: 'PATCH' | 'PUT';
+ headers: Headers;
+ op: 'updateRecord';
+ data: {
+ record: StableRecordIdentifier;
+ };
+};
+
+export type CreateRequestOptions = {
+ url: string;
+ method: 'POST';
+ headers: Headers;
+ op: 'createRecord';
+ data: {
+ record: StableRecordIdentifier;
+ };
+};
+
+export type RemotelyAccessibleIdentifier = {
+ id: string;
+ type: string;
+ lid?: string;
+};
+
+export type ConstrainedRequestOptions = {
+ reload?: boolean;
+ backgroundReload?: boolean;
+ host?: string;
+ namespace?: string;
+ resourcePath?: string;
+ urlParamsSettings?: QueryParamsSerializationOptions;
+};
+
+export type FindRecordOptions = ConstrainedRequestOptions & {
+ include?: string | string[];
+};
+
+export interface StructuredDataDocument {
+ [STRUCTURED]?: true;
+ request: ImmutableRequestInfo;
+ response: Response | ResponseInfo | null;
+ content: T;
+}
+export interface StructuredErrorDocument extends Error {
+ [STRUCTURED]?: true;
+ request: ImmutableRequestInfo;
+ response: Response | ResponseInfo | null;
+ error: string | object;
+ content?: T;
+}
+export type StructuredDocument = StructuredDataDocument | StructuredErrorDocument;
+
+interface Request {
+ controller?: AbortController;
+ /* Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. */
+ cache?: RequestCache;
+ /* Returns the credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. */
+ credentials?: RequestCredentials;
+ /* Returns the kind of resource requested by request, e.g., "document" or "script". */
+ destination?: RequestDestination;
+ /* Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header. */
+ headers?: Headers;
+ /* Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI] */
+ integrity?: string;
+ /* Returns a boolean indicating whether or not request can outlive the global in which it was created. */
+ keepalive?: boolean;
+ /* Returns request's HTTP method, which is "GET" by default. */
+ method?: HTTPMethod;
+ /* Returns the mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs. */
+ mode?: RequestMode;
+ /* Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. */
+ redirect?: RequestRedirect;
+ /* Returns the referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and "about:client" when defaulting to the global's default. This is used during fetching to determine the value of the `Referer` header of the request being made. */
+ referrer?: string;
+ /* Returns the referrer policy associated with request. This is used during fetching to compute the value of the request's referrer. */
+ referrerPolicy?: ReferrerPolicy;
+ /* Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. */
+ signal?: AbortSignal;
+ /* Returns the URL of request as a string. */
+ url?: string;
+ body?: BodyInit | null;
+}
+
+export type ImmutableHeaders = Headers & { clone?(): Headers; toJSON(): [string, string][] };
+
+export interface RequestInfo extends Request {
+ cacheOptions?: { key?: string; reload?: boolean; backgroundReload?: boolean; [SkipCache]?: true };
+ store?: Store;
+
+ op?: string;
+ records?: StableRecordIdentifier[];
+
+ disableTestWaiter?: boolean;
+ /*
+ * data that a handler should convert into
+ * the query (GET) or body (POST)
+ */
+ data?: Record;
+ /*
+ * options specifically intended for handlers
+ * to utilize to process the request
+ */
+ options?: Record;
+}
+
+export interface ImmutableRequestInfo {
+ readonly cacheOptions?: {
+ key?: string;
+ reload?: boolean;
+ backgroundReload?: boolean;
+ [SkipCache]?: true;
+ };
+ readonly store?: Store;
+
+ readonly op?: string;
+ readonly records?: StableRecordIdentifier[];
+
+ readonly disableTestWaiter?: boolean;
+ /* Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching. */
+ readonly cache?: RequestCache;
+ /* Returns the credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. */
+ readonly credentials?: RequestCredentials;
+ /* Returns the kind of resource requested by request, e.g., "document" or "script". */
+ readonly destination?: RequestDestination;
+ /* Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header. */
+ readonly headers?: Headers & { clone?(): Headers };
+ /* Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI] */
+ readonly integrity?: string;
+ /* Returns a boolean indicating whether or not request can outlive the global in which it was created. */
+ readonly keepalive?: boolean;
+ /* Returns request's HTTP method, which is "GET" by default. */
+ readonly method?: HTTPMethod;
+ /* Returns the mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs. */
+ readonly mode?: RequestMode;
+ /* Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default. */
+ readonly redirect?: RequestRedirect;
+ /* Returns the referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and "about:client" when defaulting to the global's default. This is used during fetching to determine the value of the `Referer` header of the request being made. */
+ readonly referrer?: string;
+ /* Returns the referrer policy associated with request. This is used during fetching to compute the value of the request's referrer. */
+ readonly referrerPolicy?: ReferrerPolicy;
+ /* Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler. */
+ readonly signal?: AbortSignal;
+ /* Returns the URL of request as a string. */
+ readonly url?: string;
+ /*
+ * data that a handler should convert into
+ * the query (GET) or body (POST)
+ */
+ readonly data?: Record;
+ /*
+ * options specifically intended for handlers
+ * to utilize to process the request
+ */
+ readonly options?: Record;
+}
+
+export interface ResponseInfo {
+ readonly headers: ImmutableHeaders; // to do, maybe not this?
+ readonly ok: boolean;
+ readonly redirected: boolean;
+ readonly status: number;
+ readonly statusText: string;
+ readonly type: string;
+ readonly url: string;
+}
+
+export interface RequestContext {
+ request: ImmutableRequestInfo;
+ id: number;
+
+ setStream(stream: ReadableStream): void;
+ setResponse(response: Response | ResponseInfo): void;
+}
diff --git a/packages/store/src/-types/q/record-data-schemas.ts b/packages/core-types/src/schema.ts
similarity index 96%
rename from packages/store/src/-types/q/record-data-schemas.ts
rename to packages/core-types/src/schema.ts
index 98df5e52b85..9a4e219ff4c 100644
--- a/packages/store/src/-types/q/record-data-schemas.ts
+++ b/packages/core-types/src/schema.ts
@@ -1,7 +1,7 @@
-/**
- @module @ember-data/store
+/*
+ @module @warp-drive/core-types
+ @internal
*/
-
export interface RelationshipSchema {
kind: 'belongsTo' | 'hasMany';
type: string; // related type
diff --git a/packages/store/src/-types/cache/document.ts b/packages/core-types/src/spec/document.ts
similarity index 83%
rename from packages/store/src/-types/cache/document.ts
rename to packages/core-types/src/spec/document.ts
index d92213f1a88..2fbb8956caf 100644
--- a/packages/store/src/-types/cache/document.ts
+++ b/packages/core-types/src/spec/document.ts
@@ -1,7 +1,6 @@
-import type { StableExistingRecordIdentifier } from '@warp-drive/core/identifier';
-
-import { Links, Meta, PaginationLinks } from '../q/ember-data-json-api';
-import { JsonApiError } from '../q/record-data-json-api';
+import type { StableExistingRecordIdentifier } from '../identifier';
+import type { ApiError } from './error';
+import type { Links, Meta, PaginationLinks } from './raw';
export interface ResourceMetaDocument {
// the url or cache-key associated with the structured document
@@ -37,7 +36,7 @@ export interface ResourceErrorDocument {
lid?: string;
links?: Links | PaginationLinks;
meta?: Meta;
- errors: JsonApiError[];
+ errors: ApiError[];
}
export type ResourceDocument =
diff --git a/packages/core-types/src/spec/error.ts b/packages/core-types/src/spec/error.ts
new file mode 100644
index 00000000000..d03eff16457
--- /dev/null
+++ b/packages/core-types/src/spec/error.ts
@@ -0,0 +1,19 @@
+import type { Link, Meta } from './raw';
+
+export interface ApiError {
+ id?: string;
+ title?: string;
+ detail?: string;
+ links?: {
+ about?: Link;
+ type?: Link;
+ };
+ status?: string;
+ code?: string;
+ source?: {
+ pointer: string;
+ parameter?: string;
+ header?: string;
+ };
+ meta?: Meta;
+}
diff --git a/packages/store/src/-types/q/ember-data-json-api.ts b/packages/core-types/src/spec/raw.ts
similarity index 94%
rename from packages/store/src/-types/q/ember-data-json-api.ts
rename to packages/core-types/src/spec/raw.ts
index 3046eecbff8..5e4446e8c33 100644
--- a/packages/store/src/-types/q/ember-data-json-api.ts
+++ b/packages/core-types/src/spec/raw.ts
@@ -1,7 +1,6 @@
-/**
- @module @ember-data/store
+/*
+ @module @warp-drive/core-types
*/
-
import { ArrayValue, ObjectValue } from '../json/raw';
export type Meta = ObjectValue;
@@ -141,4 +140,12 @@ export interface CollectionResourceDocument extends Document {
data: ExistingResourceObject[];
}
+/**
+ * A (RAW) JSON:API Formatted Document.
+ *
+ * These documents should follow the JSON:API spec but do not
+ * have the same level of guarantees as their `spec` counterparts.
+ *
+ * @internal
+ */
export type JsonApiDocument = EmptyResourceDocument | SingleResourceDocument | CollectionResourceDocument;
diff --git a/packages/core/tsconfig.json b/packages/core-types/tsconfig.json
similarity index 90%
rename from packages/core/tsconfig.json
rename to packages/core-types/tsconfig.json
index 9491d5b58ea..cc7842f7ca2 100644
--- a/packages/core/tsconfig.json
+++ b/packages/core-types/tsconfig.json
@@ -1,18 +1,11 @@
{
"include": ["src/**/*"],
"compilerOptions": {
- "target": "ES2022",
- "module": "ES2020",
- "moduleResolution": "node",
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
"skipLibCheck": true,
- "declarationDir": "unstable-preview-types",
- "emitDeclarationOnly": true,
"noEmit": false,
-
- // Enable faster builds
- // but causes us to not rebuild properly
- "incremental": false,
-
"allowJs": false,
"checkJs": false,
@@ -26,6 +19,7 @@
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"allowUnreachableCode": false,
+ "exactOptionalPropertyTypes": true,
"allowUnusedLabels": false,
"noEmitOnError": false,
"strictNullChecks": true,
@@ -34,10 +28,16 @@
"experimentalDecorators": true,
"pretty": true,
+ // Enable faster builds
+ // but causes us to not rebuild properly
+ "incremental": false,
+
// Support generation of source maps. Note: you must *also* enable source
// maps in your `ember-cli-babel` config and/or `babel.config.js`.
"declaration": true,
"declarationMap": true,
+ "declarationDir": "unstable-preview-types",
+ "emitDeclarationOnly": true,
"inlineSourceMap": true,
"inlineSources": true,
diff --git a/packages/debug/.eslintrc.cjs b/packages/debug/.eslintrc.cjs
new file mode 100644
index 00000000000..21f62606654
--- /dev/null
+++ b/packages/debug/.eslintrc.cjs
@@ -0,0 +1,25 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults()],
+};
diff --git a/packages/debug/package.json b/packages/debug/package.json
index ec101c0decc..02f3acc23bf 100644
--- a/packages/debug/package.json
+++ b/packages/debug/package.json
@@ -13,7 +13,10 @@
"license": "MIT",
"author": "",
"directories": {},
- "scripts": {},
+ "scripts": {
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
+ },
"peerDependencies": {
"@ember-data/store": "workspace:5.5.0-alpha.11",
"@ember/string": "^3.1.1"
@@ -27,6 +30,18 @@
},
"@ember-data/store": {
"injected": true
+ },
+ "@warp-drive/internal-config": {
+ "injected": true
+ },
+ "@ember-data/request": {
+ "injected": true
+ },
+ "@warp-drive/core-types": {
+ "injected": true
+ },
+ "@ember-data/tracking": {
+ "injected": true
}
},
"dependencies": {
@@ -36,8 +51,19 @@
"@embroider/macros": "^1.13.2",
"ember-auto-import": "^2.6.3",
"ember-cli-babel": "^8.2.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10",
"webpack": "^5.89.0"
},
+ "devDependencies": {
+ "@ember-data/request": "workspace:5.5.0-alpha.11",
+ "@ember-data/store": "workspace:5.5.0-alpha.11",
+ "@ember-data/tracking": "workspace:5.5.0-alpha.11",
+ "@ember/string": "^3.1.1",
+ "@glimmer/component": "^1.1.2",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
+ "ember-source": "~5.3.0"
+ },
"engines": {
"node": ">= 18.18.2"
},
@@ -46,4 +72,4 @@
"extends": "../../package.json"
},
"packageManager": "pnpm@8.9.2"
-}
\ No newline at end of file
+}
diff --git a/packages/diagnostic/.eslintrc.cjs b/packages/diagnostic/.eslintrc.cjs
new file mode 100644
index 00000000000..a94177fe64e
--- /dev/null
+++ b/packages/diagnostic/.eslintrc.cjs
@@ -0,0 +1,34 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug', '@ember/test-helpers'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [
+ node.defaults(),
+ node.defaults({ useModules: true, globals: { Bun: true }, files: ['./server/**'] }),
+ typescript.defaults({
+ rules: {
+ 'no-console': 'off',
+ },
+ }),
+ ],
+};
diff --git a/packages/diagnostic/addon-main.cjs b/packages/diagnostic/addon-main.cjs
index f868d6b91ec..d36b0c86dac 100644
--- a/packages/diagnostic/addon-main.cjs
+++ b/packages/diagnostic/addon-main.cjs
@@ -1,4 +1,5 @@
'use strict';
const { addonV1Shim } = require('@embroider/addon-shim');
+
module.exports = addonV1Shim(__dirname);
diff --git a/packages/diagnostic/package.json b/packages/diagnostic/package.json
index c101f21f8b2..ea367be9dc5 100644
--- a/packages/diagnostic/package.json
+++ b/packages/diagnostic/package.json
@@ -60,18 +60,19 @@
}
},
"scripts": {
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
"build:tests": "rm -rf dist-test && cp -R test dist-test && mkdir -p dist-test/@warp-drive && cp -R dist dist-test/@warp-drive/diagnostic",
"build:types": "tsc --build --force",
"build:runtime": "rollup --config",
- "build": "pnpm build:runtime && pnpm build:types && pnpm build:tests",
+ "build": "pnpm build:runtime && pnpm build:types",
"start": "rollup --config --watch",
"prepack": "pnpm build",
- "prepare": "pnpm build"
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
},
"peerDependencies": {
"@ember/test-helpers": ">= 3.2.0",
- "ember-cli-test-loader": ">= 3.1.0",
- "@embroider/addon-shim": ">= 1.8.6"
+ "@embroider/addon-shim": ">= 1.8.6",
+ "ember-cli-test-loader": ">= 3.1.0"
},
"peerDependenciesMeta": {
"@ember/test-helpers": {
@@ -87,6 +88,7 @@
"dependencies": {
"chalk": "^5.3.0",
"debug": "^4.3.4",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10",
"tmp": "^0.2.1"
},
"devDependencies": {
@@ -99,12 +101,15 @@
"@embroider/addon-dev": "^4.1.1",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
+ "bun-types": "^1.0.6",
+ "@ember/test-helpers": "^3.2.0",
+ "ember-source": "~5.3.0",
+ "@glimmer/component": "^1.1.2",
"ember-cli-test-loader": "^3.1.0",
"rollup": "^4.1.4",
- "tslib": "^2.6.2",
"typescript": "^5.2.2",
- "walk-sync": "^3.0.0",
- "bun-types": "^1.0.6"
+ "walk-sync": "^3.0.0"
},
"engines": {
"node": ">= 18.18.2"
@@ -120,5 +125,10 @@
},
"ember": {
"edition": "octane"
+ },
+ "dependenciesMeta": {
+ "@warp-drive/internal-config": {
+ "injected": true
+ }
}
-}
\ No newline at end of file
+}
diff --git a/packages/diagnostic/rollup.config.mjs b/packages/diagnostic/rollup.config.mjs
index c74dc4f6bcd..955ecdc8558 100644
--- a/packages/diagnostic/rollup.config.mjs
+++ b/packages/diagnostic/rollup.config.mjs
@@ -2,6 +2,8 @@ import { Addon } from '@embroider/addon-dev/rollup';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { external } from '@warp-drive/internal-config/rollup/external.js';
+
const addon = new Addon({
srcDir: 'src',
destDir: 'dist',
@@ -12,7 +14,7 @@ export default {
// You can augment this if you need to.
output: addon.output(),
- external: ["@ember/test-helpers", "ember-cli-test-loader/test-support/index"],
+ external: external(['@ember/test-helpers', 'ember-cli-test-loader/test-support/index']),
plugins: [
// These are the modules that users should be able to import from your
diff --git a/packages/diagnostic/server/browsers/index.js b/packages/diagnostic/server/browsers/index.js
index 2f5088c78ed..a9226421ddf 100644
--- a/packages/diagnostic/server/browsers/index.js
+++ b/packages/diagnostic/server/browsers/index.js
@@ -1,8 +1,9 @@
-import { debug } from "../utils/debug";
import os from 'os';
import path from 'path';
import tmp from 'tmp';
-import { isWin, platformName } from "../utils/platform";
+
+import { debug } from '../utils/debug';
+import { isWin, platformName } from '../utils/platform';
export function getHomeDir() {
return process.env.HOME || process.env.USERPROFILE;
@@ -14,7 +15,7 @@ function chromeWinPaths(name) {
homeDir + '\\Local Settings\\Application Data\\Google\\' + name + '\\Application\\chrome.exe',
homeDir + '\\AppData\\Local\\Google\\' + name + '\\Application\\chrome.exe',
'C:\\Program Files\\Google\\' + name + '\\Application\\Chrome.exe',
- 'C:\\Program Files (x86)\\Google\\' + name + '\\Application\\Chrome.exe'
+ 'C:\\Program Files (x86)\\Google\\' + name + '\\Application\\Chrome.exe',
];
}
@@ -22,50 +23,42 @@ function chromeDarwinPaths(name) {
const homeDir = getHomeDir();
return [
homeDir + '/Applications/' + name + '.app/Contents/MacOS/' + name,
- '/Applications/' + name + '.app/Contents/MacOS/' + name
+ '/Applications/' + name + '.app/Contents/MacOS/' + name,
];
}
const ChromePaths = {
win: chromeWinPaths,
darwin: chromeDarwinPaths,
-}
+};
const ChromeTags = {
win: {
stable: 'Chrome',
beta: 'Chrome Beta',
- canary: 'Chrome SxS'
+ canary: 'Chrome SxS',
},
darwin: {
stable: 'Google Chrome',
beta: 'Google Chrome Beta',
- canary: 'Google Chrome Canary'
- }
-}
+ canary: 'Google Chrome Canary',
+ },
+};
const ChromeExeNames = {
- stable: [
- 'google-chrome-stable',
- 'google-chrome',
- 'chrome'
- ],
- beta: [
- 'google-chrome-beta',
- ],
- canary: [
- 'google-chrome-unstable'
- ]
-}
+ stable: ['google-chrome-stable', 'google-chrome', 'chrome'],
+ beta: ['google-chrome-beta'],
+ canary: ['google-chrome-unstable'],
+};
async function executableExists(exe) {
const cmd = isWin() ? 'where' : 'which';
const result = Bun.spawnSync([cmd, exe], {
- stdout: 'inherit'
+ stdout: 'inherit',
});
return result.success;
-};
+}
async function isInstalled(browser) {
const result = await checkBrowser(browser.possiblePath, fileExists);
@@ -73,7 +66,7 @@ async function isInstalled(browser) {
return result;
}
- return checkBrowser(browser.possibleExe, function(exe) {
+ return checkBrowser(browser.possibleExe, function (exe) {
return executableExists(exe);
});
}
@@ -111,15 +104,21 @@ async function getChrome(browser, tag) {
const lookupInfo = {
name: browser.toLowerCase(),
possiblePath: paths,
- possibleExe: ChromeExeNames[tag]
+ possibleExe: ChromeExeNames[tag],
};
const result = await isInstalled(lookupInfo);
if (!result) {
- throw new Error(`Could not find ${lookupInfo.name} on your system (${platform}).\n\n\tChecked Paths:\n\t\t${lookupInfo.possiblePath.join('\n\t\t')}\n\tChecked Executable Names:\n\t\t${lookupInfo.possibleExe.join('\n\t\t')}`);
+ throw new Error(
+ `Could not find ${
+ lookupInfo.name
+ } on your system (${platform}).\n\n\tChecked Paths:\n\t\t${lookupInfo.possiblePath.join(
+ '\n\t\t'
+ )}\n\tChecked Executable Names:\n\t\t${lookupInfo.possibleExe.join('\n\t\t')}`
+ );
}
- debug(`Found ${lookupInfo.name} executable ${result}`)
+ debug(`Found ${lookupInfo.name} executable ${result}`);
return result;
}
@@ -151,7 +150,7 @@ export function getTmpDir(browser) {
const tmpDir = tmp.dirSync({
template: `${tmpPath}-XXXXXX`,
- unsafeCleanup: true
+ unsafeCleanup: true,
});
TMP_DIRS.set(browser, tmpDir);
@@ -164,7 +163,18 @@ export function recommendedArgs(browser, options = {}) {
}
const DEBUG = options.debug || debug.enabled;
const DEBUG_MEMORY = options.memory || process.env.DEBUG_MEMORY;
- const HEADLESS = 'headless' in options ? options.headless : true;
+ const SERVE = 'serve' in options ? options.serve : false;
+ const HEADLESS = 'headless' in options ? options.headless : !SERVE;
+ const useExisting = 'useExisting' in options ? options.useExisting : false;
+ const noLaunch = 'noLaunch' in options ? options.noLaunch : false;
+
+ if (noLaunch) {
+ return [];
+ }
+
+ if (useExisting) {
+ return ['--incognito'];
+ }
// See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
// For more details on these flags
diff --git a/packages/diagnostic/server/bun/fetch.js b/packages/diagnostic/server/bun/fetch.js
index f4ddc09197b..6f797dc531d 100644
--- a/packages/diagnostic/server/bun/fetch.js
+++ b/packages/diagnostic/server/bun/fetch.js
@@ -1,7 +1,8 @@
import chalk from 'chalk';
-import { info, debug } from '../utils/debug.js';
import path from 'path';
-import { INDEX_PATHS } from "../utils/const.js";
+
+import { INDEX_PATHS } from '../utils/const.js';
+import { debug, info } from '../utils/debug.js';
/** @type {import('bun-types')} */
@@ -15,11 +16,10 @@ export function handleBunFetch(config, state, req, server) {
return;
}
- let bId = url.searchParams.get('b') ?? null;
- let wId = url.searchParams.get('w') ?? null;
+ const bId = url.searchParams.get('b') ?? null;
+ const wId = url.searchParams.get('w') ?? null;
info(`[${chalk.cyan(req.method)}] ${url.pathname}`);
-
if (config.parallel > 1 && url.pathname === '/parallel-launcher') {
debug(`Serving parallel launcher`);
const dir = import.meta.dir;
@@ -36,8 +36,8 @@ export function handleBunFetch(config, state, req, server) {
debug(`Serving entry ${config._realEntry} for browser ${bId} window ${wId}`);
return new Response(Bun.file(config._realEntry));
}
- let _bId = bId ?? state.lastBowserId ?? state.browserId;
- let _wId = wId ?? state.lastWindowId ?? state.windowId;
+ const _bId = bId ?? state.lastBowserId ?? state.browserId;
+ const _wId = wId ?? state.lastWindowId ?? state.windowId;
debug(`Redirecting to ${config.entry} for browser ${_bId} window ${_wId}`);
// redirect to index.html
return Response.redirect(`${protocol}://${state.hostname}:${state.port}?b=${_bId}&w=${_wId}`, { status: 302 });
diff --git a/packages/diagnostic/server/bun/launch-browser.js b/packages/diagnostic/server/bun/launch-browser.js
index a92154d7e45..c3088411f3d 100644
--- a/packages/diagnostic/server/bun/launch-browser.js
+++ b/packages/diagnostic/server/bun/launch-browser.js
@@ -1,4 +1,5 @@
import chalk from 'chalk';
+
import { info, print } from '../utils/debug.js';
/** @type {import('bun-types')} */
@@ -25,7 +26,9 @@ export async function launchBrowsers(config, state) {
pages.push(`?b=${bId}&w=${state.windowId++}`);
}
- const launcherUrl = `${state.protocol}://${state.hostname}:${state.port}/parallel-launcher?p[]=${pages.join('&p[]=')}`;
+ const launcherUrl = `${state.protocol}://${state.hostname}:${state.port}/parallel-launcher?p[]=${pages.join(
+ '&p[]='
+ )}`;
args.push(launcherUrl);
} else {
args.push(`${state.protocol}://${state.hostname}:${state.port}?b=${bId}&w=${state.windowId++}`);
diff --git a/packages/diagnostic/server/bun/port.js b/packages/diagnostic/server/bun/port.js
index 5881b41cf67..95a27402636 100644
--- a/packages/diagnostic/server/bun/port.js
+++ b/packages/diagnostic/server/bun/port.js
@@ -13,7 +13,7 @@ export async function checkPort(port) {
data() {
debug(`Port ${port} received data 🙈`);
},
- }
+ },
});
debug(`Port ${port} is available, releasing it for server`);
server.stop(true);
diff --git a/packages/diagnostic/server/bun/socket-handler.js b/packages/diagnostic/server/bun/socket-handler.js
index 84ed8b2e28e..622bc6be353 100644
--- a/packages/diagnostic/server/bun/socket-handler.js
+++ b/packages/diagnostic/server/bun/socket-handler.js
@@ -1,6 +1,7 @@
-import { info, debug } from "../utils/debug.js";
import chalk from 'chalk';
-import { sinceStart } from "../utils/time.js";
+
+import { debug, info } from '../utils/debug.js';
+import { sinceStart } from '../utils/time.js';
export function buildHandler(config, state) {
return {
@@ -27,24 +28,33 @@ export function buildHandler(config, state) {
case 'suite-finish':
config.reporter.onSuiteFinish(msg);
- ws.send(JSON.stringify({ name: 'close' }));
- ws.close();
+ if (!config.serve) {
+ ws.send(JSON.stringify({ name: 'close' }));
+ ws.close();
+ }
state.completed++;
- debug(`${chalk.green('✅ [Complete]')} ${chalk.cyan(msg.browserId)}/${chalk.cyan(msg.windowId)} ${chalk.yellow('@' + sinceStart())}`);
+ debug(
+ `${chalk.green('✅ [Complete]')} ${chalk.cyan(msg.browserId)}/${chalk.cyan(msg.windowId)} ${chalk.yellow(
+ '@' + sinceStart()
+ )}`
+ );
if (state.completed === state.expected) {
const exitCode = config.reporter.onRunFinish(msg);
debug(`${chalk.green('✅ [All Complete]')} ${chalk.yellow('@' + sinceStart())}`);
- state.browsers.forEach((browser) => {
- browser.proc.kill();
- browser.proc.unref();
- });
- state.server.stop();
- if (config.cleanup) {
- debug(`Running configured cleanup hook`);
- await config.cleanup();
- debug(`Configured cleanup hook completed`);
+
+ if (!config.serve) {
+ state.browsers.forEach((browser) => {
+ browser.proc.kill();
+ browser.proc.unref();
+ });
+ state.server.stop();
+ if (config.cleanup) {
+ debug(`Running configured cleanup hook`);
+ await config.cleanup();
+ debug(`Configured cleanup hook completed`);
+ }
+ process.exit(exitCode);
}
- process.exit(exitCode);
}
break;
@@ -54,5 +64,5 @@ export function buildHandler(config, state) {
open(ws) {}, // a socket is opened
close(ws, code, message) {}, // a socket is closed
drain(ws) {}, // the socket is ready to receive more data
- }
-};
+ };
+}
diff --git a/packages/diagnostic/server/default-setup.js b/packages/diagnostic/server/default-setup.js
index 851fd3263c1..87dc0311065 100644
--- a/packages/diagnostic/server/default-setup.js
+++ b/packages/diagnostic/server/default-setup.js
@@ -1,10 +1,12 @@
/* eslint-disable no-console */
+import chalk from 'chalk';
import fs from 'fs';
import path from 'path';
+
+import { getBrowser, recommendedArgs } from './browsers/index.js';
import launch from './index.js';
-import chalk from 'chalk';
-import { recommendedArgs, getBrowser } from './browsers/index.js';
import DefaultReporter from './reporters/default.js';
+import { getFlags } from './utils/get-flags.js';
const CI_BROWSER = process.env.CI_BROWSER || 'Chrome';
const BROWSER_TAG = CI_BROWSER.toLowerCase();
@@ -19,29 +21,6 @@ try {
TEST_FAILURES = false;
}
const FAILURES = TEST_FAILURES ? TEST_FAILURES.trim().split(',') : false;
-const RETRY_TESTS = (process.env.CI ?? process.env.RETRY_TESTS) && FAILURES.length;
-const _parallel = process.env.DIAGNOSTIC_PARALLEL && !isNaN(Number(process.env.DIAGNOSTIC_PARALLEL)) ? Number(process.env.DIAGNOSTIC_PARALLEL) : 1;
-const parallel = _parallel > 1 && RETRY_TESTS && FAILURES.length < _parallel * 4 ? 1 : _parallel;
-
-if (RETRY_TESTS) {
- console.log(chalk.grey(`⚠️ Retrying ${chalk.bold(chalk.yellow(FAILURES.length))} failed tests: ${chalk.bold(chalk.white(FAILURES.join(',')))}`));
-} else if (FAILURES.length) {
- console.log(
- `⚠️ Found ${chalk.bold(chalk.yellow(FAILURES.length))} previously failed tests: ${chalk.bold(chalk.white(FAILURES.join(',')))}. Use RETRY_TESTS=1 to retry them.`,
- );
-}
-
-const TEST_PAGE_FLAGS = [
- process.env.DEBUG_MEMORY ? 'memory=1' : false,
- process.env.CI || process.env.DEBUG_MEMORY ? 'hideReport=1' : false,
- process.env.DEBUG_PERFORMANCE ? 'performance=1' : false,
- process.env.DEBUG ? 'debug=1' : false,
- RETRY_TESTS ? `testId=${FAILURES.join('&testId=')}` : false,
-].filter(Boolean);
-
-console.log(
- `\n\nLaunching with ${chalk.bold(chalk.cyan(CI_BROWSER))} (worker count ${chalk.bold(chalk.yellow(parallel))})\n\n`
-);
// default 13min per-browser test suite run timeout in seconds
const DEFAULT_SUITE_TIMEOUT = 780;
@@ -53,15 +32,65 @@ const SUITE_TIMEOUT = process.env.SUITE_TIMEOUT
: DEFAULT_SUITE_TIMEOUT;
export default async function launchDefault(overrides = {}) {
+ const flags = getFlags().filtered;
+ Object.assign(overrides, flags);
+
+ const RETRY_TESTS =
+ ('retry' in overrides ? overrides.retry : process.env.CI ?? process.env.RETRY_TESTS) && FAILURES.length;
+ const _parallel =
+ process.env.DIAGNOSTIC_PARALLEL && !isNaN(Number(process.env.DIAGNOSTIC_PARALLEL))
+ ? Number(process.env.DIAGNOSTIC_PARALLEL)
+ : 1;
+ const parallel = _parallel > 1 && RETRY_TESTS && FAILURES.length < _parallel * 4 ? 1 : _parallel;
+
+ if (RETRY_TESTS) {
+ console.log(
+ chalk.grey(
+ `⚠️ Retrying ${chalk.bold(chalk.yellow(FAILURES.length))} failed tests: ${chalk.bold(
+ chalk.white(FAILURES.join(','))
+ )}`
+ )
+ );
+ } else if (FAILURES.length) {
+ console.log(
+ `⚠️ Found ${chalk.bold(chalk.yellow(FAILURES.length))} previously failed tests: ${chalk.bold(
+ chalk.white(FAILURES.join(','))
+ )}. Use RETRY_TESTS=1 or --retry/-r to retry them.`
+ );
+ }
+ const DEBUG = Boolean(process.env.DEBUG ?? overrides.debug ?? false);
+
+ const TEST_PAGE_FLAGS = [
+ process.env.DEBUG_MEMORY ? 'memory=1' : false,
+ process.env.CI || process.env.DEBUG_MEMORY ? 'hideReport=1' : false,
+ process.env.DEBUG_PERFORMANCE ? 'performance=1' : false,
+ DEBUG ? 'debug=1' : false,
+ RETRY_TESTS ? `testId=${FAILURES.join('&testId=')}` : false,
+ ].filter(Boolean);
+
+ console.log(
+ `\n\nLaunching with ${chalk.bold(chalk.cyan(CI_BROWSER))} (worker count ${chalk.bold(chalk.yellow(parallel))})\n\n`
+ );
+
await launch({
+ // flag config
+ serve: overrides.serve ?? false,
+ noLaunch: overrides.noLaunch ?? false,
+ filter: overrides.filter ?? false,
+ debug: overrides.debug ?? false,
+ headless: overrides.headless ?? false,
+ useExisting: overrides.useExisting ?? false,
+
entry: overrides.entry ?? `./dist-test/tests/index.html?${TEST_PAGE_FLAGS.join('&')}`,
assets: overrides.assets ?? './dist-test',
parallel: overrides.parallel ?? parallel,
parallelMode: overrides.parallelMode ?? 'window', // 'tab' | 'browser' | 'window'
- reporter: overrides.reporter ?? new DefaultReporter({
- mode: process.env.DIAGNOSTIC_REPORTER_MODE || 'dot', // 'dot' | 'compact' | 'verbose'
- }),
+ reporter:
+ overrides.reporter ??
+ new DefaultReporter({
+ mode: process.env.DIAGNOSTIC_REPORTER_MODE || 'dot', // 'dot' | 'compact' | 'verbose'
+ }),
suiteTimeout: overrides.suiteTimeout ?? SUITE_TIMEOUT,
browserDisconnectTimeout: overrides.browserDisconnectTimeout ?? 15,
@@ -76,7 +105,6 @@ export default async function launchDefault(overrides = {}) {
command: browser,
args: recommendedArgs(BROWSER_TAG, overrides),
},
- }
+ },
});
-
}
diff --git a/packages/diagnostic/server/index.js b/packages/diagnostic/server/index.js
index 8742090d9aa..a1a9becd155 100644
--- a/packages/diagnostic/server/index.js
+++ b/packages/diagnostic/server/index.js
@@ -1,12 +1,12 @@
import chalk from 'chalk';
-import { getPort } from './utils/port.js';
-import { debug, error, print } from './utils/debug.js';
+
import { handleBunFetch } from './bun/fetch.js';
import { launchBrowsers } from './bun/launch-browser.js';
import { buildHandler } from './bun/socket-handler.js';
+import { debug, error, print } from './utils/debug.js';
+import { getPort } from './utils/port.js';
/** @type {import('bun-types')} */
-/* global Bun, globalThis */
const isBun = typeof Bun !== 'undefined';
export default async function launch(config) {
@@ -28,7 +28,7 @@ export default async function launch(config) {
};
const state = {
- browserId: 42,
+ browserId: 42,
lastBowserId: null,
windowId: 0,
lastWindowId: null,
@@ -37,7 +37,7 @@ export default async function launch(config) {
protocol,
browsers: new Map(),
completed: 0,
- expected: config.parallel ?? 1
+ expected: config.parallel ?? 1,
};
if (protocol === 'https') {
@@ -47,7 +47,7 @@ export default async function launch(config) {
serveOptions.tls = {
key: Bun.file(config.key),
cert: Bun.file(config.cert),
- }
+ };
}
try {
@@ -65,7 +65,7 @@ export default async function launch(config) {
port,
hostname,
protocol,
- url: `${protocol}://${hostname}:${port}`
+ url: `${protocol}://${hostname}:${port}`,
};
await launchBrowsers(config, state);
} catch (e) {
diff --git a/packages/diagnostic/server/reporters/default.js b/packages/diagnostic/server/reporters/default.js
index c57b9f7c35f..4df85f0f58b 100644
--- a/packages/diagnostic/server/reporters/default.js
+++ b/packages/diagnostic/server/reporters/default.js
@@ -1,5 +1,5 @@
-import fs from 'fs';
import chalk from 'chalk';
+import fs from 'fs';
import path from 'path';
const SLOW_TEST_COUNT = 50;
@@ -9,12 +9,12 @@ const DEFAULT_TEST_TIMEOUT = 21_000;
const failedTestsFile = path.join(process.cwd(), './diagnostic-failed-test-log.txt');
function indent(text, width = 2) {
- return text
- .split('\n')
- .map((line) => {
- return new Array(width).join('\t') + line;
- })
- .join('\n');
+ return text
+ .split('\n')
+ .map((line) => {
+ return new Array(width).join('\t') + line;
+ })
+ .join('\n');
}
const HEADER_STR = '===================================================================';
@@ -52,7 +52,7 @@ export default class CustomDotReporter {
this.pass = 0;
this.skip = 0;
this.todo = 0;
- this.fail= 0;
+ this.fail = 0;
// display info
this.shouldPrintHungTests = false;
@@ -78,7 +78,11 @@ export default class CustomDotReporter {
const elapsed = this.realStartTime - this.dateTimeZero;
this.write(
- `\n\n${HEADER_STR}\n Test Run Initiated\n\tSuite Start: ${chalk.cyan(new Date(this.realStartTime).toLocaleString('en-US'))} (elapsed ${chalk.cyan(elapsed.toLocaleString('en-US'))} ms)\n\tReporter Start: ${chalk.cyan(new Date().toLocaleString('en-US'))} (elapsed ${chalk.cyan(runDelta.toLocaleString('en-US'))} ms)\n${HEADER_STR}\n\n`,
+ `\n\n${HEADER_STR}\n Test Run Initiated\n\tSuite Start: ${chalk.cyan(
+ new Date(this.realStartTime).toLocaleString('en-US')
+ )} (elapsed ${chalk.cyan(elapsed.toLocaleString('en-US'))} ms)\n\tReporter Start: ${chalk.cyan(
+ new Date().toLocaleString('en-US')
+ )} (elapsed ${chalk.cyan(runDelta.toLocaleString('en-US'))} ms)\n${HEADER_STR}\n\n`
);
}
@@ -89,18 +93,18 @@ export default class CustomDotReporter {
onTestStart(report) {
this.getTab(report).running.set(report.data.testId, report);
report.testNo = this.startNumber++;
- report._testStarted = this.now();
- this.idsToStartNumber.set(`${report.browserId}:${report.windowId}:${report.data.testId}`, report.testNo);
- this.ensureTimeoutCheck();
+ report._testStarted = this.now();
+ this.idsToStartNumber.set(`${report.browserId}:${report.windowId}:${report.data.testId}`, report.testNo);
+ this.ensureTimeoutCheck();
report.launcherDescription = `${report.launcher}:${report.browserId}:${report.windowId}`;
- report.name = `${report.launcherDescription} #${report.testNo} ${chalk.magenta(
- '@ ' + (Math.round(report._testStarted / 10) / 100).toLocaleString('en-US') + 's',
- )} ${report.data.name}`;
+ report.name = `${report.launcherDescription} #${report.testNo} ${chalk.magenta(
+ '@ ' + (Math.round(report._testStarted / 10) / 100).toLocaleString('en-US') + 's'
+ )} ${report.data.name}`;
- if (process.env.DISPLAY_TEST_NAMES) {
- this.write(`\t\t⏱️ ${chalk.magenta(' Started')}: ${report.name}\n`);
- }
+ if (process.env.DISPLAY_TEST_NAMES) {
+ this.write(`\t\t⏱️ ${chalk.magenta(' Started')}: ${report.name}\n`);
+ }
}
onTestFinish(report) {
@@ -109,17 +113,17 @@ export default class CustomDotReporter {
const startNo = this.idsToStartNumber.get(startNoKey);
report.testNo = startNo ?? '';
- report.data.runDuration = report.data.runDuration ?? 0;
+ report.data.runDuration = report.data.runDuration ?? 0;
report.launcherDescription = `${report.launcher}:${report.browserId}:${report.windowId}`;
- if (tab.running.has(report.data.testId)) tab.running.delete(report.data.testId);
+ if (tab.running.has(report.data.testId)) tab.running.delete(report.data.testId);
- if (this.isCompactFormat) {
- this.displayFullResult(report, false);
- } else if (this.isDotFormat) {
- if (this.results.length === 0) this.displayDotLegend();
- this.displayDotResult(report);
- } else if (this.isVerboseFormat) {
+ if (this.isCompactFormat) {
+ this.displayFullResult(report, false);
+ } else if (this.isDotFormat) {
+ if (this.results.length === 0) this.displayDotLegend();
+ this.displayDotResult(report);
+ } else if (this.isVerboseFormat) {
this.displayFullResult(report, true);
} else {
throw new Error(`Unknown Reporter Mode ${this.config.mode}. Please use one of 'dot', 'compact', or 'verbose'`);
@@ -128,22 +132,22 @@ export default class CustomDotReporter {
const { data } = report;
this.results.push(report);
- this.total++;
- if (data.skipped) {
- this.skip++;
- } else if (data.passed && !data.todo) {
- this.pass++;
- } else if (!data.passed && data.todo) {
- this.todo++;
- } else {
+ this.total++;
+ if (data.skipped) {
+ this.skip++;
+ } else if (data.passed && !data.todo) {
+ this.pass++;
+ } else if (!data.passed && data.todo) {
+ this.todo++;
+ } else {
this.fail++;
}
- if (data.failed && !data.skipped && !data.todo) {
- this.lineFailures.push(report);
- this.failedTests.push(report);
+ if (data.failed && !data.skipped && !data.todo) {
+ this.lineFailures.push(report);
+ this.failedTests.push(report);
this.failedTestIds.add(data.testId);
- }
+ }
}
onGlobalFailure(report) {
@@ -154,18 +158,18 @@ export default class CustomDotReporter {
onSuiteFinish() {}
onRunFinish(runReport) {
- if (this.failedTests.length) {
- this.write(
- chalk.red(
- `\n\n${this.failedTests.length} Tests Failed. Complete stack traces for failures will print at the end.`,
- ),
- );
- }
+ if (this.failedTests.length) {
+ this.write(
+ chalk.red(
+ `\n\n${this.failedTests.length} Tests Failed. Complete stack traces for failures will print at the end.`
+ )
+ );
+ }
this.write(`\n\n`);
- this.reportPendingTests();
- this.reportSlowTests();
- this.reportFailedTests();
+ this.reportPendingTests();
+ this.reportSlowTests();
+ this.reportFailedTests();
this.summarizeResults();
@@ -180,23 +184,29 @@ export default class CustomDotReporter {
const realEndDate = new Date(realEndTime);
this.write(
- `\n\n${HEADER_STR}\n Test Run Complete\n\tSuite End: ${chalk.cyan(realEndDate.toLocaleString('en-US'))} (elapsed ${chalk.cyan(suiteElapsed.toLocaleString('en-US'))} ms)\n\tReporter End: ${chalk.cyan(endDate.toLocaleString('en-US'))} (elapsed ${chalk.cyan(runElapsed.toLocaleString('en-US'))} ms)\n\tRun Duration ${chalk.cyan(fullElapsed.toLocaleString('en-US'))} ms\n${HEADER_STR}\n\n`,
+ `\n\n${HEADER_STR}\n Test Run Complete\n\tSuite End: ${chalk.cyan(
+ realEndDate.toLocaleString('en-US')
+ )} (elapsed ${chalk.cyan(suiteElapsed.toLocaleString('en-US'))} ms)\n\tReporter End: ${chalk.cyan(
+ endDate.toLocaleString('en-US')
+ )} (elapsed ${chalk.cyan(runElapsed.toLocaleString('en-US'))} ms)\n\tRun Duration ${chalk.cyan(
+ fullElapsed.toLocaleString('en-US')
+ )} ms\n${HEADER_STR}\n\n`
);
return this.failedTests.length ? 1 : 0;
}
addLauncher(data) {
- this.launchers = this.launchers || {};
+ this.launchers = this.launchers || {};
this.tabs = this.tabs || new Map();
const { launcher, browserId, windowId } = data;
this.launchers[launcher] = this.launchers[launcher] || {};
- const browser = this.launchers[launcher][browserId] = this.launchers[launcher][browserId] || {
+ const browser = (this.launchers[launcher][browserId] = this.launchers[launcher][browserId] || {
launcher,
id: browserId,
tabs: new Set(),
- };
+ });
const tabId = `${browserId}:${windowId}`;
if (browser.tabs.has(tabId)) {
@@ -207,7 +217,7 @@ export default class CustomDotReporter {
this.tabs.set(tabId, {
running: new Map(),
});
- }
+ }
getTab(test) {
const { windowId, browserId } = test;
@@ -217,80 +227,78 @@ export default class CustomDotReporter {
}
now() {
- return performance.now() - this.startTime;
- }
+ return performance.now() - this.startTime;
+ }
displayDotLegend() {
- this.write('\n\tLegend\n\t=========');
- this.write(chalk.green('\n\tPass:\t.'));
- this.write(chalk.cyan('\n\tTodo:\tT'));
- this.write(chalk.yellow('\n\tSkip:\t*'));
- this.write(chalk.bold(chalk.red('\n\tFail:\tF')));
- this.write('\n\n\t');
- }
+ this.write('\n\tLegend\n\t=========');
+ this.write(chalk.green('\n\tPass:\t.'));
+ this.write(chalk.cyan('\n\tTodo:\tT'));
+ this.write(chalk.yellow('\n\tSkip:\t*'));
+ this.write(chalk.bold(chalk.red('\n\tFail:\tF')));
+ this.write('\n\n\t');
+ }
displayDotResult(report) {
// complete line
- if (this.currentLineChars > this.maxLineChars) {
- if (this.shouldPrintHungTests) {
- this.shouldPrintHungTests = false;
- this.reportHungTests();
- }
-
- this.totalLines++;
- this.currentLineChars = 0;
- const lineFailures = this.lineFailures;
- this.lineFailures = [];
-
- if (lineFailures.length) {
- this.write('\n\n');
- lineFailures.forEach((failure) => {
- this.displayFullResult(failure, false);
- });
- }
-
- if (this.totalLines % 5 === 0) {
- this.write(`\n${chalk.magenta((this.totalLines * this.maxLineChars).toLocaleString('en-US'))}⎡\t`);
- } else {
- this.write('\n\t');
- }
- }
+ if (this.currentLineChars > this.maxLineChars) {
+ if (this.shouldPrintHungTests) {
+ this.shouldPrintHungTests = false;
+ this.reportHungTests();
+ }
+
+ this.totalLines++;
+ this.currentLineChars = 0;
+ const lineFailures = this.lineFailures;
+ this.lineFailures = [];
+
+ if (lineFailures.length) {
+ this.write('\n\n');
+ lineFailures.forEach((failure) => {
+ this.displayFullResult(failure, false);
+ });
+ }
+
+ if (this.totalLines % 5 === 0) {
+ this.write(`\n${chalk.magenta((this.totalLines * this.maxLineChars).toLocaleString('en-US'))}⎡\t`);
+ } else {
+ this.write('\n\t');
+ }
+ }
const result = report.data;
- if (result.passed && !result.todo) {
- this.write(chalk.grey('.'));
- } else if (!result.passed && result.todo) {
- this.write(chalk.cyan('T'));
- } else if (result.skipped) {
- this.write(chalk.yellow('*'));
- } else {
- this.write(chalk.bold(chalk.red('F')));
- }
- this.currentLineChars += 1;
- }
+ if (result.passed && !result.todo) {
+ this.write(chalk.grey('.'));
+ } else if (!result.passed && result.todo) {
+ this.write(chalk.cyan('T'));
+ } else if (result.skipped) {
+ this.write(chalk.yellow('*'));
+ } else {
+ this.write(chalk.bold(chalk.red('F')));
+ }
+ this.currentLineChars += 1;
+ }
displayFullResult(report, verbose) {
const result = report.data;
- const name = `${chalk.grey(
- result.runDuration.toLocaleString('en-US') + 'ms',
- )} ${chalk.white('#' + report.testNo)} ${result.name} ${chalk.grey(report.launcherDescription)}`
+ const name = `${chalk.grey(result.runDuration.toLocaleString('en-US') + 'ms')} ${chalk.white(
+ '#' + report.testNo
+ )} ${result.name} ${chalk.grey(report.launcherDescription)}`;
if (result.passed && !result.todo) {
- this.write(`\t✅ ${chalk.green('Passed')}: ${name}\n`);
- } else if (!result.passed && result.todo) {
- this.write(chalk.cyan(`\t🛠️ TODO: ${name}\n`));
- } else if (result.skipped) {
- this.write(chalk.yellow(`\t⚠️ Skipped: ${name}\n`));
- } else {
- this.write(chalk.red(`\t💥 Failed: ${name}\n`));
- this.write(
- `\t\topen test locally: ${this.serverConfig.url}?testId=${result.testId}\n`,
- );
+ this.write(`\t✅ ${chalk.green('Passed')}: ${name}\n`);
+ } else if (!result.passed && result.todo) {
+ this.write(chalk.cyan(`\t🛠️ TODO: ${name}\n`));
+ } else if (result.skipped) {
+ this.write(chalk.yellow(`\t⚠️ Skipped: ${name}\n`));
+ } else {
+ this.write(chalk.red(`\t💥 Failed: ${name}\n`));
+ this.write(`\t\topen test locally: ${this.serverConfig.url}?testId=${result.testId}\n`);
// TODO - print individual failures in verbose mode
- }
+ }
}
- summarizeResults() {
+ summarizeResults() {
const lines = [
'Result',
'=========',
@@ -298,7 +306,7 @@ export default class CustomDotReporter {
chalk.green('# pass ' + this.pass),
chalk.yellow('# skip ' + this.skip),
chalk.cyan('# todo ' + this.todo),
- chalk.red('# fail ' + this.fail)
+ chalk.red('# fail ' + this.fail),
];
if (this.pass + this.skipped + this.todo === this.total) {
@@ -308,23 +316,22 @@ export default class CustomDotReporter {
this.write('\n\n\t');
this.write(lines.join('\n\t'));
this.write('\n\n');
- }
-
+ }
// special reporting functionality
// ===============================
/**
- * Periodically checks for hung tests and reports them
- */
- ensureTimeoutCheck() {
- if (this._timeoutId) {
- return;
- }
- this._timeoutId = setTimeout(() => {
- this.shouldPrintHungTests = true;
- }, DEFAULT_TEST_TIMEOUT / 3);
- }
+ * Periodically checks for hung tests and reports them
+ */
+ ensureTimeoutCheck() {
+ if (this._timeoutId) {
+ return;
+ }
+ this._timeoutId = setTimeout(() => {
+ this.shouldPrintHungTests = true;
+ }, DEFAULT_TEST_TIMEOUT / 3);
+ }
reportHungTests() {
let hasRunningTests = false;
@@ -338,19 +345,19 @@ export default class CustomDotReporter {
this.write(
chalk.grey(
`\n\n⚠️ ${chalk.yellow('Pending:')} ${chalk.white(report.name)} has been running for ${chalk.yellow(
- duration.toLocaleString('en-US') + 'ms',
- )}, this is likely a bug.\n`,
- ),
+ duration.toLocaleString('en-US') + 'ms'
+ )}, this is likely a bug.\n`
+ )
);
}
});
});
- this._timeoutId = null;
- if (hasRunningTests) {
- this.ensureTimeoutCheck();
- }
- }
+ this._timeoutId = null;
+ if (hasRunningTests) {
+ this.ensureTimeoutCheck();
+ }
+ }
/**
* Same as `reportHungTests` but is for use to report everything
@@ -374,47 +381,53 @@ export default class CustomDotReporter {
const duration = this.now() - report._testStarted;
- this.write(chalk.yellow(`\t⛔️ Stuck (${chalk.red(
- duration.toLocaleString('en-US') + ' ms',
- )}): (${report.data.testId}) ${chalk.white(report.name)} ${chalk.grey(report.launcherDescription)}\n`));
+ this.write(
+ chalk.yellow(
+ `\t⛔️ Stuck (${chalk.red(duration.toLocaleString('en-US') + ' ms')}): (${
+ report.data.testId
+ }) ${chalk.white(report.name)} ${chalk.grey(report.launcherDescription)}\n`
+ )
+ );
});
});
- }
-
- reportSlowTests() {
- const results = this.results;
- let totalDuration = 0;
- let testsToPrint = SLOW_TEST_COUNT;
- results.sort((a, b) => {
- return a.runDuration > b.runDuration ? -1 : 1;
- });
-
- this.write(
- `\n\n\t${chalk.yellow(
- `${results.length < SLOW_TEST_COUNT ? results.length : SLOW_TEST_COUNT} Longest Running Tests`,
- )}\n${HEADER_STR}\n`,
- );
- for (let i = 0; i < results.length; i++) {
- const { name, runDuration } = results[i].data;
-
- if (i < testsToPrint) {
- // this test is a known offender
- if (runDuration > DEFAULT_TIMEOUT + TIMEOUT_BUFFER) {
- this.write(`\n\t${i + 1}.\t[S] ${chalk.yellow(runDuration.toLocaleString('en-US') + 'ms')}\t${name}`);
- testsToPrint++;
- } else {
- this.write(`\n\t${i + 1}.\t${chalk.yellow(runDuration.toLocaleString('en-US') + 'ms')}\t${name}`);
- }
- }
- totalDuration += runDuration;
- }
- this.write(
- chalk.yellow(`\n\n\tAvg Duration of all ${results.length} tests: ${Math.round(totalDuration / results.length)}ms\n\n`),
- );
- }
-
- reportFailedTests() {
- this.failedTests.forEach((failure) => {
+ }
+
+ reportSlowTests() {
+ const results = this.results;
+ let totalDuration = 0;
+ let testsToPrint = SLOW_TEST_COUNT;
+ results.sort((a, b) => {
+ return a.runDuration > b.runDuration ? -1 : 1;
+ });
+
+ this.write(
+ `\n\n\t${chalk.yellow(
+ `${results.length < SLOW_TEST_COUNT ? results.length : SLOW_TEST_COUNT} Longest Running Tests`
+ )}\n${HEADER_STR}\n`
+ );
+ for (let i = 0; i < results.length; i++) {
+ const { name, runDuration } = results[i].data;
+
+ if (i < testsToPrint) {
+ // this test is a known offender
+ if (runDuration > DEFAULT_TIMEOUT + TIMEOUT_BUFFER) {
+ this.write(`\n\t${i + 1}.\t[S] ${chalk.yellow(runDuration.toLocaleString('en-US') + 'ms')}\t${name}`);
+ testsToPrint++;
+ } else {
+ this.write(`\n\t${i + 1}.\t${chalk.yellow(runDuration.toLocaleString('en-US') + 'ms')}\t${name}`);
+ }
+ }
+ totalDuration += runDuration;
+ }
+ this.write(
+ chalk.yellow(
+ `\n\n\tAvg Duration of all ${results.length} tests: ${Math.round(totalDuration / results.length)}ms\n\n`
+ )
+ );
+ }
+
+ reportFailedTests() {
+ this.failedTests.forEach((failure) => {
const result = failure.data;
this.write(chalk.red(`\n\t💥 Failed: ${result.runDuration.toLocaleString('en-US')}ms ${result.name}\n`));
@@ -422,7 +435,9 @@ export default class CustomDotReporter {
this.write(`\t\t${diagnostic.passed ? chalk.green('✅ Pass') : chalk.red('💥 Fail')} ${diagnostic.message}\n`);
if (!diagnostic.passed && 'expected' in diagnostic && 'actual' in diagnostic) {
- this.write(`\n\t\texpected: ${printValue(diagnostic.expected, 3)}\n\t\tactual: ${printValue(diagnostic.actual, 3)}\n`);
+ this.write(
+ `\n\t\texpected: ${printValue(diagnostic.expected, 3)}\n\t\tactual: ${printValue(diagnostic.actual, 3)}\n`
+ );
}
if (!diagnostic.passed && diagnostic.stack) {
@@ -439,7 +454,10 @@ export default class CustomDotReporter {
this.globalFailures.forEach((failure) => {
const result = failure.error;
- const label = result.name && result.message ? `[${result.name}] ${result.message}` : result.name || result.message || 'Unknown Error';
+ const label =
+ result.name && result.message
+ ? `[${result.name}] ${result.message}`
+ : result.name || result.message || 'Unknown Error';
this.write(chalk.red(`\n\t💥 Failed: ${label}\n`));
if (result.stack) {
@@ -452,51 +470,48 @@ export default class CustomDotReporter {
updateFailedTestCache() {
const failedTestIds = [...this.failedTestIds.entries()];
- const allFailuresAccounted = this.globalFailures.length === 0;
- const cacheFile = failedTestsFile;
+ const allFailuresAccounted = this.globalFailures.length === 0;
+ const cacheFile = failedTestsFile;
- if (allFailuresAccounted) {
- if (failedTestIds.length) {
- fs.writeFileSync(cacheFile, failedTestIds.join(','), { encoding: 'utf-8' });
+ if (allFailuresAccounted) {
+ if (failedTestIds.length) {
+ fs.writeFileSync(cacheFile, failedTestIds.join(','), { encoding: 'utf-8' });
this.write(
- chalk.yellow(
- `\n\nSaved ${chalk.white(failedTestIds.length)} Failed Tests for Retry with IDS ${chalk.white(
- failedTestIds.join(','),
- )} in ${chalk.grey(cacheFile)}`,
- ),
- );
-
- this.write(
- `\n\nTo run failed tests locally, ${chalk.cyan('visit')} ${chalk.white(
- `${this.serverConfig.url}?${failedTestIds.map((id) => `testId=${id}`).join('&')}`,
- )}`,
- );
- } else {
- remove(cacheFile);
- }
- } else {
- if (failedTestIds.length) {
- this.write(
- `\n\nTo run failed tests locally, ${chalk.cyan('visit')} ${chalk.white(
- `${this.serverConfig.url}?${failedTestIds.map((id) => `testId=${id}`).join('&')}`,
- )}`,
- );
- }
- this.write(
- chalk.red(`\n\n⚠️ Unable to save failed tests for retry, not all failures had test IDs, cleaning up`),
- );
- remove(cacheFile);
- }
- }
-}
+ chalk.yellow(
+ `\n\nSaved ${chalk.white(failedTestIds.length)} Failed Tests for Retry with IDS ${chalk.white(
+ failedTestIds.join(',')
+ )} in ${chalk.grey(cacheFile)}`
+ )
+ );
+ this.write(
+ `\n\nTo run failed tests locally, ${chalk.cyan('visit')} ${chalk.white(
+ `${this.serverConfig.url}?${failedTestIds.map((id) => `testId=${id}`).join('&')}`
+ )}`
+ );
+ } else {
+ remove(cacheFile);
+ }
+ } else {
+ if (failedTestIds.length) {
+ this.write(
+ `\n\nTo run failed tests locally, ${chalk.cyan('visit')} ${chalk.white(
+ `${this.serverConfig.url}?${failedTestIds.map((id) => `testId=${id}`).join('&')}`
+ )}`
+ );
+ }
+ this.write(chalk.red(`\n\n⚠️ Unable to save failed tests for retry, not all failures had test IDs, cleaning up`));
+ remove(cacheFile);
+ }
+ }
+}
// Instead of completely removing, we replace the contents with an empty string so that CI will still cache it.
// While this shouldn't ever really be necessary it's a bit more correct to make sure that the log gets cleared
// in the cache as well.
function remove(filePath) {
- fs.writeFileSync(filePath, '', { encoding: 'utf-8' });
+ fs.writeFileSync(filePath, '', { encoding: 'utf-8' });
}
function printValue(value, tabs = 0) {
diff --git a/packages/diagnostic/server/utils/const.js b/packages/diagnostic/server/utils/const.js
index 260e946588d..591dafed205 100644
--- a/packages/diagnostic/server/utils/const.js
+++ b/packages/diagnostic/server/utils/const.js
@@ -3,8 +3,4 @@ export const DEFAULT_HOST = 'localhost';
export const DEFAULT_PROTOCOL = 'http';
export const MAX_PORT_TRIES = 100;
-export const INDEX_PATHS = [
- '',
- '/',
- 'index.html',
-];
+export const INDEX_PATHS = ['', '/', 'index.html'];
diff --git a/packages/diagnostic/server/utils/get-flags.js b/packages/diagnostic/server/utils/get-flags.js
new file mode 100644
index 00000000000..ef94550a966
--- /dev/null
+++ b/packages/diagnostic/server/utils/get-flags.js
@@ -0,0 +1,63 @@
+export function getFlags() {
+ const raw = process.argv.slice(2);
+ for (let i = 0; i < raw.length; i++) {
+ const rawArg = raw[i];
+ if (rawArg.startsWith('--')) {
+ continue;
+ } else if (rawArg.startsWith('-')) {
+ const args = rawArg.slice(1);
+ if (args.length > 1) {
+ for (let j = 0; j < args.length; j++) {
+ raw.push(`-${args[j]}`);
+ }
+ }
+ }
+ }
+ const flags = new Set(raw);
+ const filtered = {};
+
+ // global flags
+ const debug = flags.has('--debug') || flags.has('-d');
+ const serve = flags.has('--serve') || flags.has('-s');
+ const noLaunch = flags.has('--no-launch') || flags.has('-n');
+ const filter = flags.has('--filter') || flags.has('-f');
+ const retry = flags.has('--retry') || flags.has('-r');
+ const headless = flags.has('--headless') || flags.has('-h');
+ const useExisting = flags.has('--use-existing') || flags.has('-e');
+
+ if (filter) {
+ filtered['filter'] = true;
+ }
+ if (debug) {
+ filtered['debug'] = true;
+ }
+ if (serve) {
+ filtered['serve'] = true;
+ }
+ if (noLaunch) {
+ filtered['noLaunch'] = true;
+ }
+ if (retry) {
+ filtered['retry'] = true;
+ }
+ if (headless) {
+ filtered['headless'] = true;
+ }
+ if (useExisting) {
+ filtered['useExisting'] = true;
+ }
+
+ return {
+ parsed: {
+ debug,
+ serve,
+ noLaunch,
+ filter,
+ retry,
+ headless,
+ useExisting,
+ },
+ filtered,
+ flags,
+ };
+}
diff --git a/packages/diagnostic/server/utils/platform.js b/packages/diagnostic/server/utils/platform.js
index cb731f0abee..8380edf1306 100644
--- a/packages/diagnostic/server/utils/platform.js
+++ b/packages/diagnostic/server/utils/platform.js
@@ -12,7 +12,7 @@ export function isWin(platform) {
}
return currentPlatform;
-};
+}
export function isMac(platform) {
if (platform) {
@@ -22,7 +22,6 @@ export function isMac(platform) {
return /^darwin/.test(os.platform());
}
-
export function isLinux(platform) {
if (platform) {
return /^linux/.test(platform);
diff --git a/packages/diagnostic/server/utils/port.js b/packages/diagnostic/server/utils/port.js
index b820e039764..a5630dd0aef 100644
--- a/packages/diagnostic/server/utils/port.js
+++ b/packages/diagnostic/server/utils/port.js
@@ -1,5 +1,5 @@
-import { debug } from './debug.js';
import { DEFAULT_PORT, MAX_PORT_TRIES } from './const.js';
+import { debug } from './debug.js';
async function discoverPort(defaultPort, checkPort) {
debug(`Discovering available port starting from default port of ${defaultPort}`);
diff --git a/packages/diagnostic/src/-types.ts b/packages/diagnostic/src/-types.ts
index 5404884eedb..95c15e211b9 100644
--- a/packages/diagnostic/src/-types.ts
+++ b/packages/diagnostic/src/-types.ts
@@ -1,10 +1,9 @@
-import { SuiteReport } from "./-types/report";
-
+import { SuiteReport } from './-types/report';
export type CompatTestReport = {
id: number;
name: string;
- items: { passed: boolean; message: string; }[];
+ items: { passed: boolean; message: string }[];
failed: number;
passed: number;
total: number;
@@ -12,7 +11,7 @@ export type CompatTestReport = {
skipped: boolean;
todo: boolean;
testId: string;
-}
+};
export interface Emitter {
emit(name: 'suite-start', data: SuiteReport): void;
@@ -25,7 +24,7 @@ export type ParamConfig = {
id: string;
label: string;
value: boolean;
-}
+};
export type GlobalHooksStorage = {
onSuiteStart: GlobalCallback[];
@@ -34,10 +33,20 @@ export type GlobalHooksStorage = {
afterModule: GlobalCallback[];
beforeEach: HooksCallback[];
afterEach: HooksCallback[];
-}
+};
-export type GlobalConfig = {
- params: { [key in 'concurrency' | 'tryCatch' | 'instrument' | 'hideReport' | 'memory' | 'groupLogs' | 'debug' | 'container']: ParamConfig };
+export type GlobalConfig = {
+ params: {
+ [key in
+ | 'concurrency'
+ | 'tryCatch'
+ | 'instrument'
+ | 'hideReport'
+ | 'memory'
+ | 'groupLogs'
+ | 'debug'
+ | 'container']: ParamConfig;
+ };
_current: SuiteReport | null;
useTestem: boolean;
useDiagnostic: boolean;
@@ -49,7 +58,7 @@ export type GlobalConfig = {
modules: number;
skipped: number;
todo: number;
- }
+ };
};
export interface Diagnostic {
@@ -70,7 +79,6 @@ export interface Diagnostic {
verifySteps(steps: string[], message?: string): void;
}
-
export interface TestContext {}
export type GlobalCallback = () => void | Promise;
@@ -87,7 +95,7 @@ export interface GlobalHooks extends Hooks {
}
export type HooksCallback = (this: TC, assert: Diagnostic) => void | Promise;
-export type ModuleCallback = ((hooks: Hooks) => void | Promise) | (() => void | Promise);
+export type ModuleCallback = ((hooks: Hooks) => void) | (() => void);
export type TestCallback = (this: TC, assert: Diagnostic) => void | Promise;
export interface TestInfo {
@@ -113,7 +121,7 @@ export interface ModuleInfo {
afterEach: HooksCallback[];
beforeModule: GlobalCallback[];
afterModule: GlobalCallback[];
- },
+ };
tests: OrderedMap>;
modules: OrderedMap>;
}
diff --git a/packages/diagnostic/src/-types/report.ts b/packages/diagnostic/src/-types/report.ts
index aa015c3bb7d..46e8a79f509 100644
--- a/packages/diagnostic/src/-types/report.ts
+++ b/packages/diagnostic/src/-types/report.ts
@@ -26,7 +26,7 @@ export interface TestReport {
diagnostics: DiagnosticReport[];
passed: boolean;
failed: boolean;
- }
+ };
module: ModuleReport;
}
export interface ModuleReport {
diff --git a/packages/diagnostic/src/-utils.ts b/packages/diagnostic/src/-utils.ts
index e76e7949351..21610605c68 100644
--- a/packages/diagnostic/src/-utils.ts
+++ b/packages/diagnostic/src/-utils.ts
@@ -1,5 +1,5 @@
/* global window, globalThis, global, self */
-import { HooksCallback,TestContext, ModuleInfo, GlobalHooksStorage } from "./-types";
+import { GlobalHooksStorage, HooksCallback, ModuleInfo, TestContext } from './-types';
export function assert(message: string, test: unknown): asserts test {
if (!test) {
@@ -7,14 +7,27 @@ export function assert(message: string, test: unknown): asserts test {
}
}
-export function getGlobal(): Window {
- // @ts-expect-error global is node only
- const g = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : null);
+export function getGlobal(): typeof globalThis {
+ // prettier-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
+ const g: typeof globalThis | null =
+ typeof globalThis !== 'undefined' ? globalThis
+ : typeof window !== 'undefined' ? window
+ // @ts-expect-error global is node only
+ : typeof global !== 'undefined' ? global
+ : typeof self !== 'undefined' ? self
+ : null;
+
assert(`Expected to find a global object`, g !== null);
- return g as unknown as Window;
+ return g as unknown as typeof globalThis;
}
-export function getChain(globalHooks: GlobalHooksStorage, module: ModuleInfo, parents: ModuleInfo[] | null, prop: 'beforeEach' | 'afterEach'): HooksCallback[] {
+export function getChain(
+ globalHooks: GlobalHooksStorage,
+ module: ModuleInfo,
+ parents: ModuleInfo[] | null,
+ prop: 'beforeEach' | 'afterEach'
+): HooksCallback[] {
const chain: HooksCallback[] = [];
if (globalHooks[prop].length) {
@@ -39,11 +52,11 @@ export function getChain(globalHooks: GlobalHooksStorage
return chain;
}
-export function generateHash (str: string) {
+export function generateHash(str: string) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
- hash = ((hash << 5) - hash) + str.charCodeAt(i);
+ hash = (hash << 5) - hash + str.charCodeAt(i);
hash |= 0;
}
diff --git a/packages/diagnostic/src/ember.ts b/packages/diagnostic/src/ember.ts
index 1975addee42..b3befd04044 100644
--- a/packages/diagnostic/src/ember.ts
+++ b/packages/diagnostic/src/ember.ts
@@ -1,19 +1,23 @@
import { getTestMetadata, setupContext, SetupContextOptions, teardownContext, TestContext } from '@ember/test-helpers';
+
import AbstractTestLoader from 'ember-cli-test-loader/test-support/index';
import type { Hooks } from './-types';
-
import { setupGlobalHooks } from './internals/config';
// fix bug with embroider/webpack/auto-import and test-loader
+// prettier-ignore
// @ts-expect-error
-const CLITestLoader: typeof AbstractTestLoader = AbstractTestLoader.default ? AbstractTestLoader.default : AbstractTestLoader;
+const CLITestLoader: typeof AbstractTestLoader = AbstractTestLoader.default
+ // @ts-expect-error
+ ? AbstractTestLoader.default as typeof AbstractTestLoader
+ : AbstractTestLoader;
export function setupTest(hooks: Hooks, opts?: SetupContextOptions) {
const options = { waitForSettled: false, ...opts };
hooks.beforeEach(async function () {
- let testMetadata = getTestMetadata(this);
+ const testMetadata = getTestMetadata(this);
testMetadata.framework = 'qunit';
await setupContext(this, options);
@@ -47,7 +51,7 @@ function loadTests() {
export function configure() {
setupGlobalHooks((hooks) => {
hooks.onSuiteFinish(() => {
- let length = moduleLoadFailures.length;
+ const length = moduleLoadFailures.length;
try {
if (length === 0) {
diff --git a/packages/diagnostic/src/emitters/diagnostic.ts b/packages/diagnostic/src/emitters/diagnostic.ts
index 57decc35623..66fc4330b2a 100644
--- a/packages/diagnostic/src/emitters/diagnostic.ts
+++ b/packages/diagnostic/src/emitters/diagnostic.ts
@@ -1,11 +1,11 @@
-import { CompatTestReport, Emitter } from "../-types";
-import { SuiteReport } from "../-types/report";
-import { assert } from "../-utils";
+import { CompatTestReport, Emitter } from '../-types';
+import { SuiteReport } from '../-types/report';
+import { assert } from '../-utils';
type EmitEvent = {
name: 'suite-start' | 'suite-finish' | 'test-start' | 'test-finish';
- data: SuiteReport | CompatTestReport
-}
+ data: SuiteReport | CompatTestReport;
+};
class DiagnosticEmitter implements Emitter {
socket: WebSocket;
@@ -30,7 +30,9 @@ class DiagnosticEmitter implements Emitter {
this.buffer = [];
if (!browserId || !windowId) {
- console.warn(`[Diagnostic] Expected to find a browserId and windowId in the url. Likely this page was not served by the diagnostic server. Remote reporting will not be available.`);
+ console.warn(
+ `[Diagnostic] Expected to find a browserId and windowId in the url. Likely this page was not served by the diagnostic server. Remote reporting will not be available.`
+ );
this.socket = null as unknown as WebSocket;
return;
}
@@ -50,7 +52,9 @@ class DiagnosticEmitter implements Emitter {
socket.onclose = (event) => {
this.connected = false;
if (event.wasClean) {
- console.log(`[Diagnostic] Remote Reporter Connection closed cleanly, code=${event.code} reason=${event.reason}`);
+ console.log(
+ `[Diagnostic] Remote Reporter Connection closed cleanly, code=${event.code} reason=${event.reason}`
+ );
} else {
console.error(`[Diagnostic] Remote Reporter Connection Died`, event);
}
@@ -60,8 +64,8 @@ class DiagnosticEmitter implements Emitter {
console.error(e);
throw new Error(`[Diagnostic] Remote Reporter Connection Failed`);
};
- socket.onmessage = (message) => {
- const msg = JSON.parse(message.data);
+ socket.onmessage = (message: MessageEvent) => {
+ const msg = JSON.parse(message.data) as { name: 'close' };
if (msg.name === 'close') {
window.close();
} else {
@@ -89,7 +93,10 @@ class DiagnosticEmitter implements Emitter {
return;
}
- assert(`Expected event.name to be one of 'suite-start', 'suite-finish', 'test-start' or 'test-finish'`, (['suite-start', 'suite-finish', 'test-start', 'test-finish']).includes(name));
+ assert(
+ `Expected event.name to be one of 'suite-start', 'suite-finish', 'test-start' or 'test-finish'`,
+ ['suite-start', 'suite-finish', 'test-start', 'test-finish'].includes(name)
+ );
assert(`Expected event.data to be defined`, typeof data !== 'undefined');
const event = { browserId: this.browserId, windowId: this.windowId, name, data, timestamp: Date.now() };
diff --git a/packages/diagnostic/src/emitters/testem.ts b/packages/diagnostic/src/emitters/testem.ts
index caf4bf67f32..e6dc4b228af 100644
--- a/packages/diagnostic/src/emitters/testem.ts
+++ b/packages/diagnostic/src/emitters/testem.ts
@@ -1,14 +1,16 @@
-/* global Testem */
-
-import { Emitter, CompatTestReport } from "../-types";
-import { SuiteReport } from "../-types/report";
-import { assert } from "../-utils";
+import { CompatTestReport, Emitter } from '../-types';
+import { SuiteReport } from '../-types/report';
+import { assert } from '../-utils';
type TestemSocket = {
emit(name: 'tests-start'): void; // suite-start
emit(name: 'all-test-results'): void; // suite-finish
emit(name: 'tests-start', data: CompatTestReport): void; // test-start
emit(name: 'test-result', data: CompatTestReport): void; // test-finish
+};
+
+interface TestemGlobal {
+ useCustomAdapter(callback: (socket: TestemSocket) => void): void;
}
class TestemEmitter implements Emitter {
@@ -23,7 +25,10 @@ class TestemEmitter implements Emitter {
emit(name: 'test-start', data: CompatTestReport): void;
emit(name: 'test-finish', data: CompatTestReport): void;
emit(name: 'suite-start' | 'suite-finish' | 'test-start' | 'test-finish', data: SuiteReport | CompatTestReport) {
- assert(`Expected event.name to be one of 'suite-start', 'suite-finish', 'test-start' or 'test-finish'`, (['suite-start', 'suite-finish', 'test-start', 'test-finish']).includes(name));
+ assert(
+ `Expected event.name to be one of 'suite-start', 'suite-finish', 'test-start' or 'test-finish'`,
+ ['suite-start', 'suite-finish', 'test-start', 'test-finish'].includes(name)
+ );
assert(`Expected event.data to be defined`, typeof data !== 'undefined');
if (name === 'suite-start') {
@@ -41,7 +46,7 @@ class TestemEmitter implements Emitter {
export function createTestemEmitter(): Promise {
return new Promise((resolve, reject) => {
// @ts-expect-error
- const _Testem = window.Testem;
+ const _Testem: TestemGlobal = window.Testem as TestemGlobal;
const hasTestem = typeof _Testem !== 'undefined';
if (!hasTestem) {
diff --git a/packages/diagnostic/src/index.ts b/packages/diagnostic/src/index.ts
index f27022f2d58..ad40e6025d9 100644
--- a/packages/diagnostic/src/index.ts
+++ b/packages/diagnostic/src/index.ts
@@ -1,18 +1,17 @@
-import { assert, generateHash } from "./-utils";
-import { ModuleInfo, TestInfo, ModuleCallback, TestCallback, OrderedMap, TestContext } from "./-types";
-import { SuiteReport } from "./-types/report";
+import { ModuleCallback, ModuleInfo, OrderedMap, TestCallback, TestContext, TestInfo } from './-types';
+import { SuiteReport } from './-types/report';
+import { assert, generateHash } from './-utils';
+import { Config, getCurrentModule, HooksDelegate, instrument, setCurrentModule } from './internals/config';
+import { DelegatingReporter } from './internals/delegating-reporter';
+import { runModule } from './internals/run';
-import { Config, HooksDelegate, getCurrentModule, instrument, setCurrentModule } from "./internals/config";
-import { DelegatingReporter } from "./internals/delegating-reporter";
-import { runModule } from "./internals/run";
-
-export { registerReporter } from "./internals/delegating-reporter";
-export { setupGlobalHooks, configure } from "./internals/config";
+export { registerReporter } from './internals/delegating-reporter';
+export { setupGlobalHooks, configure } from './internals/config';
const Modules: OrderedMap> = {
byName: new Map(),
- byOrder: []
-}
+ byOrder: [],
+};
export type { Diagnostic, Hooks as NestedHooks, GlobalHooks, TestContext } from './-types';
@@ -31,7 +30,7 @@ export function module(name: string, cb: M
beforeEach: [],
afterEach: [],
beforeModule: [],
- afterModule: []
+ afterModule: [],
};
const tests: OrderedMap> = { byName: new Map(), byOrder: [] };
const modules: OrderedMap> = { byName: new Map(), byOrder: [] };
@@ -138,8 +137,8 @@ export async function start() {
}
const promises: Promise[] = [];
- for (const module of Modules.byOrder) {
- await runModule(module, null, promises);
+ for (const _module of Modules.byOrder) {
+ await runModule(_module, null, promises);
}
if (promises.length) {
await Promise.all(promises);
@@ -149,6 +148,7 @@ export async function start() {
await hook();
}
report.end = instrument() && performance.mark('@warp-drive/diagnostic:end');
- report.measure = instrument() && performance.measure('@warp-drive/diagnostic:run', report.start.name, report.end.name);
+ report.measure =
+ instrument() && performance.measure('@warp-drive/diagnostic:run', report.start.name, report.end.name);
DelegatingReporter.onSuiteFinish(report);
}
diff --git a/packages/diagnostic/src/internals/config.ts b/packages/diagnostic/src/internals/config.ts
index 1465edfd852..01ecb0b166a 100644
--- a/packages/diagnostic/src/internals/config.ts
+++ b/packages/diagnostic/src/internals/config.ts
@@ -1,6 +1,14 @@
-/* global emit, Testem */
-import { assert } from "../-utils";
-import { GlobalHooks, GlobalCallback, TestContext, HooksCallback, GlobalConfig, ModuleInfo, ParamConfig } from "../-types";
+/* global Testem */
+import {
+ GlobalCallback,
+ GlobalConfig,
+ GlobalHooks,
+ HooksCallback,
+ ModuleInfo,
+ ParamConfig,
+ TestContext,
+} from '../-types';
+import { assert } from '../-utils';
export const Config: GlobalConfig = {
globalHooks: {
@@ -9,7 +17,7 @@ export const Config: GlobalConfig = {
beforeModule: [],
afterModule: [],
onSuiteStart: [],
- onSuiteFinish: []
+ onSuiteFinish: [],
},
// @ts-expect-error
useTestem: typeof Testem !== 'undefined',
@@ -20,42 +28,42 @@ export const Config: GlobalConfig = {
hideReport: {
id: 'hideReport',
label: 'Hide Report',
- value: true
+ value: true,
},
concurrency: {
id: 'concurrency',
label: 'Enable Concurrency',
- value: false
+ value: false,
},
memory: {
id: 'memory',
label: 'Instrument Memory',
- value: false
+ value: false,
},
instrument: {
id: 'performance',
label: 'Instrument Performance',
- value: true
+ value: true,
},
groupLogs: {
id: 'groupLogs',
label: 'Group Logs',
- value: true
+ value: true,
},
debug: {
id: 'debug',
label: 'Debug Mode',
- value: false
+ value: false,
},
container: {
id: 'container',
label: 'Hide Container',
- value: true
+ value: true,
},
tryCatch: {
id: 'tryCatch',
label: 'No Try/Catch',
- value: true
+ value: true,
},
},
totals: {
@@ -66,7 +74,7 @@ export const Config: GlobalConfig = {
todo: 0,
},
_current: null,
-}
+};
let currentModule: ModuleInfo;
let isResolvingGlobalHooks = false;
@@ -111,7 +119,7 @@ export const HooksDelegate = {
assert(`Cannot add a global onSuiteFinish hook inside of a module`, isResolvingGlobalHooks);
Config.globalHooks.onSuiteFinish.push(cb);
},
-}
+};
export function getCurrentModule(): ModuleInfo {
return currentModule;
@@ -141,10 +149,21 @@ export type ConfigOptions = {
useTestem: boolean;
useDiagnostic: boolean;
};
-const configOptions = ['concurrency', 'tryCatch', 'instrument', 'hideReport', 'memory', 'groupLogs', 'debug', 'container'] as const;
+const configOptions = [
+ 'concurrency',
+ 'tryCatch',
+ 'instrument',
+ 'hideReport',
+ 'memory',
+ 'groupLogs',
+ 'debug',
+ 'container',
+] as const;
export function configure(options: ConfigOptions): void {
if (options.useTestem && options.useDiagnostic) {
- throw new Error(`Cannot use both Testem and Diagnostic at the same time. Please remove one of these options or set it to false.`);
+ throw new Error(
+ `Cannot use both Testem and Diagnostic at the same time. Please remove one of these options or set it to false.`
+ );
}
if ('useTestem' in options && typeof options.useTestem === 'boolean') {
Config.useTestem = options.useTestem;
@@ -160,7 +179,7 @@ export function configure(options: ConfigOptions): void {
// @ts-expect-error
options.concurrency = options.concurrency > 1;
}
- configOptions.forEach(key => {
+ configOptions.forEach((key) => {
if (key in options && typeof options[key] === 'boolean') {
Config.params[key].value = options[key] as boolean;
}
@@ -180,7 +199,7 @@ export function getSettings() {
useDiagnostic: Config.useDiagnostic,
concurrency: Config.concurrency,
params: Config.params,
- }
+ };
}
export function instrument() {
diff --git a/packages/diagnostic/src/internals/delegating-reporter.ts b/packages/diagnostic/src/internals/delegating-reporter.ts
index 84921c6fec2..5dd1e24d87c 100644
--- a/packages/diagnostic/src/internals/delegating-reporter.ts
+++ b/packages/diagnostic/src/internals/delegating-reporter.ts
@@ -1,4 +1,4 @@
-import { Reporter, SuiteReport } from "../-types/report";
+import { Reporter, SuiteReport } from '../-types/report';
const Reporters = new Set();
export function registerReporter(reporter: Reporter) {
@@ -42,7 +42,7 @@ export const DelegatingReporter: Reporter = {
}
},
onModuleStart(report) {
- for (const reporter of Reporters) {
+ for (const reporter of Reporters) {
reporter.onModuleStart(report);
}
},
@@ -56,4 +56,4 @@ export const DelegatingReporter: Reporter = {
reporter.onDiagnostic(report);
}
},
-}
+};
diff --git a/packages/diagnostic/src/internals/diagnostic.ts b/packages/diagnostic/src/internals/diagnostic.ts
index eb83a37fca1..857a97f0096 100644
--- a/packages/diagnostic/src/internals/diagnostic.ts
+++ b/packages/diagnostic/src/internals/diagnostic.ts
@@ -1,6 +1,6 @@
-import { GlobalConfig, TestContext, TestInfo } from "../-types";
-import { DiagnosticReport, Reporter, TestReport } from "../-types/report";
-import equiv from "../legacy/equiv";
+import { GlobalConfig, TestContext, TestInfo } from '../-types';
+import { DiagnosticReport, Reporter, TestReport } from '../-types/report';
+import equiv from '../legacy/equiv';
class InternalCompat {
declare _diagnostic: Diagnostic;
@@ -19,7 +19,6 @@ class InternalCompat {
set expected(value) {
this._diagnostic.expected = value;
}
-
}
export class Diagnostic {
@@ -43,8 +42,12 @@ export class Diagnostic {
this.test = new InternalCompat(this);
}
- pushResult(result: Pick & { result?: boolean }): void {
- const diagnostic = Object.assign({ passed: result.passed ?? result.result }, result, { testId: this.__currentTest.id });
+ pushResult(
+ result: Pick & { result?: boolean }
+ ): void {
+ const diagnostic = Object.assign({ passed: result.passed ?? result.result }, result, {
+ testId: this.__currentTest.id,
+ });
this.__report.result.diagnostics.push(diagnostic);
if (!diagnostic.passed) {
@@ -59,14 +62,14 @@ export class Diagnostic {
if (actual !== expected) {
if (this.__config.params.tryCatch.value) {
try {
- throw new Error(message || `Expected ${actual} to equal ${expected}`);
+ throw new Error(message || `Expected ${String(actual)} to equal ${String(expected)}`);
} catch (err) {
this.pushResult({
message: message || 'equal',
stack: (err as Error).stack!,
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -75,7 +78,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -84,14 +87,14 @@ export class Diagnostic {
stack: '',
passed: true,
actual: true,
- expected: true
+ expected: true,
});
}
}
notEqual(actual: T, expected: T, message?: string): void {
if (actual === expected) {
- throw new Error(message || `Expected ${actual} to not equal ${expected}`);
+ throw new Error(message || `Expected ${String(actual)} to not equal ${String(expected)}`);
}
}
@@ -107,7 +110,7 @@ export class Diagnostic {
stack: (err as Error).stack!,
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -116,7 +119,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -125,7 +128,7 @@ export class Diagnostic {
stack: '',
passed: true,
actual: true,
- expected: true
+ expected: true,
});
}
}
@@ -142,7 +145,7 @@ export class Diagnostic {
stack: (err as Error).stack!,
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -151,7 +154,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual,
- expected
+ expected,
});
}
} else {
@@ -160,7 +163,7 @@ export class Diagnostic {
stack: '',
passed: true,
actual: true,
- expected: true
+ expected: true,
});
}
}
@@ -201,7 +204,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual: false,
- expected: true
+ expected: true,
});
}
if (this.__report.result.diagnostics.length === 0) {
@@ -210,7 +213,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual: false,
- expected: true
+ expected: true,
});
}
if (this._steps.length) {
@@ -219,7 +222,7 @@ export class Diagnostic {
stack: '',
passed: false,
actual: false,
- expected: true
+ expected: true,
});
}
}
@@ -236,23 +239,26 @@ export class Diagnostic {
throw new Error(`Expected function to throw ${expected}`);
}
- return resolved.then(() => {
- throw new Error(`Expected function to throw ${expected}`);
- }, (err) => {
- if (expected) {
- if (typeof expected === 'string') {
- this.equal(err.message, expected, message);
- } else {
- this.equal(expected.test(err.message), true, message);
+ return resolved.then(
+ () => {
+ throw new Error(`Expected function to throw ${expected}`);
+ },
+ (err: Error | string) => {
+ if (expected) {
+ if (typeof expected === 'string') {
+ this.equal(typeof err === 'string' ? err : err.message, expected, message);
+ } else {
+ this.equal(typeof err === 'string' ? err : expected.test(err.message), true, message);
+ }
}
}
- });
+ );
} catch (err) {
if (expected) {
if (typeof expected === 'string') {
this.equal(err instanceof Error ? err.message : err, expected, message);
} else {
- this.equal(expected.test(err instanceof Error ? err.message : err as string), true, message);
+ this.equal(expected.test(err instanceof Error ? err.message : (err as string)), true, message);
}
}
}
@@ -270,23 +276,26 @@ export class Diagnostic {
return;
}
- return resolved.then(() => {
- return;
- }, (err) => {
- if (expected) {
- if (typeof expected === 'string') {
- this.equal(err.message, expected, message);
- } else {
- this.equal(expected.test(err.message), true, message);
+ return resolved.then(
+ () => {
+ return;
+ },
+ (err: Error | string) => {
+ if (expected) {
+ if (typeof expected === 'string') {
+ this.equal(typeof err === 'string' ? err : err.message, expected, message);
+ } else {
+ this.equal(expected.test(typeof err === 'string' ? err : err.message), true, message);
+ }
}
}
- });
+ );
} catch (err) {
if (expected) {
if (typeof expected === 'string') {
this.equal(err instanceof Error ? err.message : err, expected, message);
} else {
- this.equal(expected.test(err instanceof Error ? err.message : err as string), true, message);
+ this.equal(expected.test(err instanceof Error ? err.message : (err as string)), true, message);
}
}
}
diff --git a/packages/diagnostic/src/internals/run.ts b/packages/diagnostic/src/internals/run.ts
index 438dfbe20cf..4745409ffda 100644
--- a/packages/diagnostic/src/internals/run.ts
+++ b/packages/diagnostic/src/internals/run.ts
@@ -1,11 +1,16 @@
-import { getChain } from "../-utils";
-import { ModuleInfo, HooksCallback, TestInfo, TestContext, } from "../-types";
-import { TestReport, ModuleReport } from "../-types/report";
-import { Diagnostic } from "./diagnostic";
-import { Config, groupLogs, instrument } from "./config";
-import { DelegatingReporter } from "./delegating-reporter";
-
-export async function runTest(moduleReport: ModuleReport, beforeChain: HooksCallback[], test: TestInfo, afterChain: HooksCallback[]) {
+import { HooksCallback, ModuleInfo, TestContext, TestInfo } from '../-types';
+import { ModuleReport, TestReport } from '../-types/report';
+import { getChain } from '../-utils';
+import { Config, groupLogs, instrument } from './config';
+import { DelegatingReporter } from './delegating-reporter';
+import { Diagnostic } from './diagnostic';
+
+export async function runTest(
+ moduleReport: ModuleReport,
+ beforeChain: HooksCallback[],
+ test: TestInfo,
+ afterChain: HooksCallback[]
+) {
const testContext = {} as TC;
const testReport: TestReport = {
id: test.id,
@@ -21,7 +26,7 @@ export async function runTest(moduleReport: ModuleReport
failed: false,
},
module: moduleReport,
- }
+ };
testReport.start = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:start`);
const Assert = new Diagnostic(DelegatingReporter, Config, test, testReport);
@@ -31,7 +36,9 @@ export async function runTest(moduleReport: ModuleReport
if (test.skip) {
groupLogs() && console.groupEnd();
testReport.end = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:end`);
- testReport.measure = instrument() && performance.measure(`test:${test.module.moduleName} > ${test.name}`, testReport.start.name, testReport.end.name);
+ testReport.measure =
+ instrument() &&
+ performance.measure(`test:${test.module.moduleName} > ${test.name}`, testReport.start.name, testReport.end.name);
DelegatingReporter.onTestFinish(testReport);
return;
@@ -63,12 +70,18 @@ export async function runTest(moduleReport: ModuleReport
groupLogs() && console.groupEnd();
testReport.end = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:end`);
- testReport.measure = instrument() && performance.measure(`test:${test.module.moduleName} > ${test.name}`, testReport.start.name, testReport.end.name);
+ testReport.measure =
+ instrument() &&
+ performance.measure(`test:${test.module.moduleName} > ${test.name}`, testReport.start.name, testReport.end.name);
DelegatingReporter.onTestFinish(testReport);
}
-export async function runModule(module: ModuleInfo, parents: ModuleInfo[] | null, promises: Promise[]) {
+export async function runModule(
+ module: ModuleInfo,
+ parents: ModuleInfo[] | null,
+ promises: Promise[]
+) {
groupLogs() && console.groupCollapsed(module.name);
const moduleReport: ModuleReport = {
name: module.moduleName,
@@ -77,7 +90,7 @@ export async function runModule(module: ModuleInfo,
measure: null,
passed: true,
failed: false,
- }
+ };
moduleReport.start = instrument() && performance.mark(`module:${module.moduleName}:start`);
DelegatingReporter.onModuleStart(moduleReport);
@@ -106,11 +119,10 @@ export async function runModule(module: ModuleInfo,
for (let i = 0; i < available; i++) {
const test = tests[currentTest++]!;
remainingTests--;
- const promise = runTest(moduleReport, beforeChain, test, afterChain)
- .finally(() => {
- const index = promises.indexOf(promise);
- promises.splice(index, 1);
- });
+ const promise = runTest(moduleReport, beforeChain, test, afterChain).finally(() => {
+ const index = promises.indexOf(promise);
+ promises.splice(index, 1);
+ });
promises.push(promise);
}
@@ -124,8 +136,6 @@ export async function runModule(module: ModuleInfo,
}
}
-
-
// run modules
for (const childModule of module.modules.byOrder) {
await runModule(childModule, [...(parents || []), module], promises);
@@ -140,6 +150,7 @@ export async function runModule(module: ModuleInfo,
}
groupLogs() && console.groupEnd();
moduleReport.end = instrument() && performance.mark(`module:${module.moduleName}:end`);
- moduleReport.measure = instrument() && performance.measure(`module:${module.moduleName}`, moduleReport.start.name, moduleReport.end.name);
+ moduleReport.measure =
+ instrument() && performance.measure(`module:${module.moduleName}`, moduleReport.start.name, moduleReport.end.name);
DelegatingReporter.onModuleFinish(moduleReport);
}
diff --git a/packages/diagnostic/src/legacy/equiv.ts b/packages/diagnostic/src/legacy/equiv.ts
index b53b64d50d6..c0aad6a076e 100644
--- a/packages/diagnostic/src/legacy/equiv.ts
+++ b/packages/diagnostic/src/legacy/equiv.ts
@@ -1,7 +1,8 @@
+/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call,@typescript-eslint/ban-types,@typescript-eslint/no-unsafe-member-access */
/*
* The utils below are from QUnit to support deepEqual.
*/
-export function objectType (obj: unknown) {
+export function objectType(obj: unknown) {
if (typeof obj === 'undefined') {
return 'undefined';
}
@@ -42,24 +43,24 @@ const BOXABLE_TYPES = new Set(['boolean', 'number', 'string']);
// Used for recursion detection, and to avoid repeated comparison.
//
// Elements are { a: val, b: val }.
-let memory: { a: unknown, b: unknown }[] = [];
+let memory: { a: unknown; b: unknown }[] = [];
-function useStrictEquality (a: unknown, b: unknown) {
+function useStrictEquality(a: unknown, b: unknown) {
return a === b;
}
-function useObjectValueEquality (a: object, b: object) {
+function useObjectValueEquality(a: object, b: object) {
return a === b || a.valueOf() === b.valueOf();
}
type HasConstructor = { constructor?: unknown };
-function compareConstructors (a: HasConstructor, b: HasConstructor) {
+function compareConstructors(a: HasConstructor, b: HasConstructor) {
// Comparing constructors is more strict than using `instanceof`
return getConstructor(a) === getConstructor(b);
}
-function getConstructor (obj: HasConstructor) {
+function getConstructor(obj: HasConstructor) {
const proto = Object.getPrototypeOf(obj);
// If the obj prototype descends from a null constructor, treat it
@@ -71,7 +72,7 @@ function getConstructor (obj: HasConstructor) {
return !proto || proto.constructor === null ? Object : obj.constructor;
}
-function getRegExpFlags (regexp: RegExp) {
+function getRegExpFlags(regexp: RegExp) {
// @ts-expect-error never narrowing is only true for modern browsers
return 'flags' in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0];
}
@@ -82,32 +83,31 @@ const objTypeCallbacks = {
null: useStrictEquality,
// Handle boxed boolean
boolean: useObjectValueEquality,
- number (a: number, b: number) {
+ number(a: number, b: number) {
// Handle NaN and boxed number
- return a === b ||
- a.valueOf() === b.valueOf() ||
- (isNaN(a.valueOf()) && isNaN(b.valueOf()));
+ return a === b || a.valueOf() === b.valueOf() || (isNaN(a.valueOf()) && isNaN(b.valueOf()));
},
// Handle boxed string
string: useObjectValueEquality,
symbol: useStrictEquality,
date: useObjectValueEquality,
- nan () {
+ nan() {
return true;
},
- regexp (a: RegExp, b: RegExp) {
- return a.source === b.source &&
-
+ regexp(a: RegExp, b: RegExp) {
+ return (
+ a.source === b.source &&
// Include flags in the comparison
- getRegExpFlags(a) === getRegExpFlags(b);
+ getRegExpFlags(a) === getRegExpFlags(b)
+ );
},
// identical reference only
function: useStrictEquality,
- array (a: unknown[], b: unknown[]) {
+ array(a: unknown[], b: unknown[]) {
if (a.length !== b.length) {
// Safe and faster
return false;
@@ -126,7 +126,7 @@ const objTypeCallbacks = {
// repetitions are not counted, so these are equivalent:
// a = new Set( [ X={}, Y=[], Y ] );
// b = new Set( [ Y, X, X ] );
- set (a: Set, b: Set) {
+ set(a: Set, b: Set) {
if (a.size !== b.size) {
// This optimization has certain quirks because of the lack of
// repetition counting. For instance, adding the same
@@ -222,7 +222,7 @@ const objTypeCallbacks = {
});
return outerEq;
- }
+ },
};
// Entry points from typeEquiv, based on `typeof`
@@ -230,7 +230,7 @@ const entryTypeCallbacks = {
undefined: useStrictEquality,
null: useStrictEquality,
boolean: useStrictEquality,
- number (a: number, b: number) {
+ number(a: number, b: number) {
// Handle NaN
return a === b || (isNaN(a) && isNaN(b));
},
@@ -238,7 +238,7 @@ const entryTypeCallbacks = {
symbol: useStrictEquality,
function: useStrictEquality,
- object (a: BetterObj, b: BetterObj) {
+ object(a: BetterObj, b: BetterObj) {
// Handle memory (skip recursion)
if (memory.some((pair) => pair.a === a && pair.b === b)) {
return true;
@@ -288,10 +288,10 @@ const entryTypeCallbacks = {
}
return objTypeCallbacks.array(aProperties.sort(), bProperties.sort());
- }
+ },
};
-function typeEquiv (a: unknown, b: unknown) {
+function typeEquiv(a: unknown, b: unknown): boolean {
// Optimization: Only perform type-specific comparison when pairs are not strictly equal.
if (a === b) {
return true;
@@ -302,15 +302,17 @@ function typeEquiv (a: unknown, b: unknown) {
if (aType !== bType) {
// Support comparing primitive to boxed primitives
// Try again after possibly unwrapping one
- return (aType === 'object' && BOXABLE_TYPES.has(objectType(a)) ? (a as String | Number).valueOf() : a) ===
- (bType === 'object' && BOXABLE_TYPES.has(objectType(b)) ? (b as String | Number).valueOf() : b);
+ return (
+ (aType === 'object' && BOXABLE_TYPES.has(objectType(a)) ? (a as string | number).valueOf() : a) ===
+ (bType === 'object' && BOXABLE_TYPES.has(objectType(b)) ? (b as string | number).valueOf() : b)
+ );
}
// @ts-expect-error
return entryTypeCallbacks[aType](a, b);
}
-function innerEquiv (a: unknown, b: unknown) {
+function innerEquiv(a: unknown, b: unknown): boolean {
const res = typeEquiv(a, b);
// Release any retained objects and reset recursion detection for next call
memory = [];
@@ -323,9 +325,9 @@ function innerEquiv (a: unknown, b: unknown) {
* @author Philippe Rathé
* @author David Chan
*/
-export default function equiv (a: unknown, b: unknown) {
+export default function equiv(a: unknown, b: unknown): boolean {
if (arguments.length === 2) {
- return (a === b) || innerEquiv(a, b);
+ return a === b || innerEquiv(a, b);
}
// Given 0 or 1 arguments, just return true (nothing to compare).
diff --git a/packages/diagnostic/src/reporters/dom.ts b/packages/diagnostic/src/reporters/dom.ts
index fd1c4685ad2..98585e11044 100644
--- a/packages/diagnostic/src/reporters/dom.ts
+++ b/packages/diagnostic/src/reporters/dom.ts
@@ -1,7 +1,6 @@
-/* global Testem */
-import { CompatTestReport, Emitter } from "../-types";
-import { DiagnosticReport, ModuleReport, Reporter, SuiteReport, TestReport } from "../-types/report";
-import { getSettings, updateConfigValue, updateSuiteState } from "../internals/config";
+import { CompatTestReport, Emitter } from '../-types';
+import { DiagnosticReport, ModuleReport, Reporter, SuiteReport, TestReport } from '../-types/report';
+import { getSettings, updateConfigValue, updateSuiteState } from '../internals/config';
type SuiteLayout = {
report: HTMLElement;
@@ -23,7 +22,7 @@ export class DOMReporter implements Reporter {
diagnosticsPassed: number;
modules: number;
modulesPassed: number;
- }
+ };
declare _pendingUpdate: number | null;
declare _socket: Emitter | null;
@@ -79,7 +78,7 @@ export class DOMReporter implements Reporter {
onTestFinish(test: TestReport): void {
this.stats.diagnostics += test.result.diagnostics.length;
- this.stats.diagnosticsPassed += test.result.diagnostics.filter(d => d.passed).length;
+ this.stats.diagnosticsPassed += test.result.diagnostics.filter((d) => d.passed).length;
if (this._socket) {
const compatTestReport = this.currentTests.get(test.id)!;
@@ -91,7 +90,7 @@ export class DOMReporter implements Reporter {
compatTestReport.todo = test.todo;
compatTestReport.total = test.result.diagnostics.length;
compatTestReport.runDuration = test.end!.startTime - test.start!.startTime;
- compatTestReport.items = test.result.diagnostics.map(d => {
+ compatTestReport.items = test.result.diagnostics.map((d) => {
// more expensive to serialize the whole diagnostic
if (this.settings.params.debug.value) {
return d;
@@ -278,8 +277,8 @@ function renderSuite(element: DocumentFragment, suiteReport: SuiteReport): Suite
input.checked = value.value;
function update() {
- value.value = input.checked;
- updateConfigValue(key, value.value);
+ value.value = input.checked;
+ updateConfigValue(key, value.value);
}
input.addEventListener('change', update);
diff --git a/packages/diagnostic/src/runners/dom.ts b/packages/diagnostic/src/runners/dom.ts
index c3c2c229d99..8eb7c5a9633 100644
--- a/packages/diagnostic/src/runners/dom.ts
+++ b/packages/diagnostic/src/runners/dom.ts
@@ -1,8 +1,8 @@
+import { registerReporter, start as _start } from '../';
+import type { Emitter } from '../-types';
import { assert, getGlobal } from '../-utils';
-import { start as _start, registerReporter } from '../';
-import { DOMReporter } from '../reporters/dom';
import { ConfigOptions, configure, getSettings } from '../internals/config';
-import type { Emitter } from '../-types';
+import { DOMReporter } from '../reporters/dom';
export async function start(config?: ConfigOptions) {
if (config) {
@@ -15,7 +15,10 @@ export async function start(config?: ConfigOptions) {
assert(`Expected to be in a browser environment`, typeof body !== 'undefined');
const container = context.document.getElementById('warp-drive__diagnostic');
- assert(`Expected to find a diagnostic container element. Make sure your html file has added `, container !== null);
+ assert(
+ `Expected to find a diagnostic container element. Make sure your html file has added `,
+ container !== null
+ );
const settings = getSettings();
let emitter: Emitter | null = null;
diff --git a/packages/diagnostic/test/example-tests.js b/packages/diagnostic/test/example-tests.js
index 881e3f92e5b..8a89e3e5f9c 100644
--- a/packages/diagnostic/test/example-tests.js
+++ b/packages/diagnostic/test/example-tests.js
@@ -1,21 +1,21 @@
import { module, test } from './@warp-drive/diagnostic/index.js';
import { start } from './@warp-drive/diagnostic/runners/dom.js';
-module('example-tests', function() {
- test('An example test', function(assert) {
+module('example-tests', function () {
+ test('An example test', function (assert) {
assert.ok(true, 'We ran a test');
});
- test('Another example test 2', function(assert) {
+ test('Another example test 2', function (assert) {
assert.ok(false, 'We ran another test 2');
assert.ok(true, 'We passed!');
});
- test('Another example test 3', function(assert) {
+ test('Another example test 3', function (assert) {
assert.ok(true, 'We ran another test 3');
});
});
start({
- useDiagnostic: true
+ useDiagnostic: true,
});
diff --git a/packages/diagnostic/tsconfig.json b/packages/diagnostic/tsconfig.json
index 5dcb2f4002d..46a4361f60c 100644
--- a/packages/diagnostic/tsconfig.json
+++ b/packages/diagnostic/tsconfig.json
@@ -1,7 +1,6 @@
{
"include": ["src/**/*"],
"compilerOptions": {
- // "composite": true,
"lib": ["DOM", "ESNext"],
"module": "esnext",
"target": "esnext",
diff --git a/packages/eslint-plugin-ember-data/package.json b/packages/eslint-plugin-ember-data/package.json
index 8d2cb1e9d7b..dc27b1811ef 100644
--- a/packages/eslint-plugin-ember-data/package.json
+++ b/packages/eslint-plugin-ember-data/package.json
@@ -11,5 +11,11 @@
},
"volta": {
"extends": "../../package.json"
+ },
+ "dependencies": {
+ "pnpm-sync-dependencies-meta-injected": "0.0.10"
+ },
+ "scripts": {
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
}
-}
\ No newline at end of file
+}
diff --git a/packages/graph/.eslintrc.cjs b/packages/graph/.eslintrc.cjs
new file mode 100644
index 00000000000..94f092444d8
--- /dev/null
+++ b/packages/graph/.eslintrc.cjs
@@ -0,0 +1,26 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/graph/addon-main.cjs b/packages/graph/addon-main.cjs
new file mode 100644
index 00000000000..1dbde47c342
--- /dev/null
+++ b/packages/graph/addon-main.cjs
@@ -0,0 +1,93 @@
+const requireModule = require('@ember-data/private-build-infra/src/utilities/require-module');
+const getEnv = require('@ember-data/private-build-infra/src/utilities/get-env');
+const detectModule = require('@ember-data/private-build-infra/src/utilities/detect-module');
+
+const pkg = require('./package.json');
+
+module.exports = {
+ name: pkg.name,
+
+ options: {
+ '@embroider/macros': {
+ setOwnConfig: {},
+ },
+ },
+
+ _emberDataConfig: null,
+ configureEmberData() {
+ if (this._emberDataConfig) {
+ return this._emberDataConfig;
+ }
+ const app = this._findHost();
+ const isProd = /production/.test(process.env.EMBER_ENV);
+ const hostOptions = app.options?.emberData || {};
+ const debugOptions = Object.assign(
+ {
+ LOG_PAYLOADS: false,
+ LOG_OPERATIONS: false,
+ LOG_MUTATIONS: false,
+ LOG_NOTIFICATIONS: false,
+ LOG_REQUESTS: false,
+ LOG_REQUEST_STATUS: false,
+ LOG_IDENTIFIERS: false,
+ LOG_GRAPH: false,
+ LOG_INSTANCE_CACHE: false,
+ },
+ hostOptions.debug || {}
+ );
+
+ const HAS_DEBUG_PACKAGE = detectModule(require, '@ember-data/debug', __dirname, pkg);
+ const HAS_META_PACKAGE = detectModule(require, 'ember-data', __dirname, pkg);
+
+ const includeDataAdapterInProduction =
+ typeof hostOptions.includeDataAdapterInProduction === 'boolean'
+ ? hostOptions.includeDataAdapterInProduction
+ : HAS_META_PACKAGE;
+
+ const includeDataAdapter = HAS_DEBUG_PACKAGE ? (isProd ? includeDataAdapterInProduction : true) : false;
+ const DEPRECATIONS = require('@ember-data/private-build-infra/src/deprecations')(hostOptions.compatWith || null);
+ const FEATURES = require('@ember-data/private-build-infra/src/features')(isProd);
+
+ const ALL_PACKAGES = requireModule('@ember-data/private-build-infra/virtual-packages/packages.js');
+ const MACRO_PACKAGE_FLAGS = Object.assign({}, ALL_PACKAGES.default);
+ delete MACRO_PACKAGE_FLAGS['HAS_DEBUG_PACKAGE'];
+
+ Object.keys(MACRO_PACKAGE_FLAGS).forEach((key) => {
+ MACRO_PACKAGE_FLAGS[key] = detectModule(require, MACRO_PACKAGE_FLAGS[key], __dirname, pkg);
+ });
+
+ // copy configs forward
+ const ownConfig = this.options['@embroider/macros'].setOwnConfig;
+ ownConfig.compatWith = hostOptions.compatWith || null;
+ ownConfig.debug = debugOptions;
+ ownConfig.deprecations = Object.assign(DEPRECATIONS, ownConfig.deprecations || {}, hostOptions.deprecations || {});
+ ownConfig.features = Object.assign({}, FEATURES);
+ ownConfig.includeDataAdapter = includeDataAdapter;
+ ownConfig.packages = MACRO_PACKAGE_FLAGS;
+ ownConfig.env = getEnv(ownConfig);
+
+ this._emberDataConfig = ownConfig;
+ return ownConfig;
+ },
+
+ included() {
+ this.configureEmberData();
+ return this._super.included.call(this, ...arguments);
+ },
+
+ treeForVendor() {
+ return;
+ },
+ treeForPublic() {
+ return;
+ },
+ treeForStyles() {
+ return;
+ },
+ treeForAddonStyles() {
+ return;
+ },
+ treeForApp() {
+ return;
+ },
+};
diff --git a/packages/graph/package.json b/packages/graph/package.json
index 27c45915989..4fb685194eb 100644
--- a/packages/graph/package.json
+++ b/packages/graph/package.json
@@ -11,29 +11,37 @@
"directory": "packages/graph"
},
"license": "MIT",
- "author": "",
+ "author": "Chris Thoburn ",
"scripts": {
- "build": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
- "start": "rollup --config --watch",
+ "lint": "eslint . --quiet --cache --cache-strategy=content --ext .js,.ts,.mjs,.cjs",
+ "build:types": "tsc --build --force",
+ "build:client": "rollup --config && babel ./addon --out-dir addon --plugins=../private-build-infra/src/transforms/babel-plugin-transform-ext.js",
+ "build": "pnpm build:client && pnpm build:types",
"prepack": "pnpm build",
- "prepare": "pnpm build"
- },
- "ember-addon": {
- "main": "addon-main.js",
- "type": "addon",
- "version": 1
+ "_syncPnpm": "pnpm sync-dependencies-meta-injected"
},
"files": [
- "addon-main.js",
+ "unstable-preview-types",
+ "addon-main.cjs",
"addon",
"README.md",
"LICENSE.md",
"ember-data-logo-dark.svg",
"ember-data-logo-light.svg"
],
+ "exports": {
+ ".": {
+ "types": "./unstable-preview-types/index.d.ts",
+ "default": "./addon/index.js"
+ },
+ "./*": {
+ "types": "./unstable-preview-types/*.d.ts",
+ "default": "./addon/*.js"
+ }
+ },
"peerDependencies": {
"@ember-data/store": "workspace:5.5.0-alpha.11",
- "@warp-drive/core": "workspace:5.5.0-alpha.11"
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11"
},
"dependenciesMeta": {
"@ember-data/private-build-infra": {
@@ -41,13 +49,29 @@
},
"@ember-data/store": {
"injected": true
+ },
+ "@warp-drive/core-types": {
+ "injected": true
+ },
+ "@warp-drive/internal-config": {
+ "injected": true
+ },
+ "@ember-data/request": {
+ "injected": true
+ },
+ "@ember-data/tracking": {
+ "injected": true
+ },
+ "@ember/string": {
+ "injected": true
}
},
"dependencies": {
"@ember-data/private-build-infra": "workspace:5.5.0-alpha.11",
"@ember/edition-utils": "^1.2.0",
"@embroider/macros": "^1.13.2",
- "ember-cli-babel": "^8.2.0"
+ "ember-cli-babel": "^8.2.0",
+ "pnpm-sync-dependencies-meta-injected": "0.0.10"
},
"devDependencies": {
"@babel/cli": "^7.23.0",
@@ -60,25 +84,35 @@
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@babel/runtime": "^7.23.2",
+ "@ember-data/request": "workspace:5.5.0-alpha.11",
+ "@ember-data/store": "workspace:5.5.0-alpha.11",
+ "@ember-data/tracking": "workspace:5.5.0-alpha.11",
+ "@ember/string": "^3.1.1",
"@embroider/addon-dev": "^4.1.1",
"@glimmer/component": "^1.1.2",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
+ "@warp-drive/core-types": "workspace:5.5.0-alpha.11",
+ "@warp-drive/internal-config": "workspace:5.5.0-alpha.11",
"ember-source": "~5.3.0",
"rollup": "^4.1.4",
- "tslib": "^2.6.2",
"typescript": "^5.2.2",
"walk-sync": "^3.0.0",
"webpack": "^5.89.0"
},
- "ember": {
- "edition": "octane"
- },
"engines": {
"node": ">= 18.18.2"
},
"volta": {
"extends": "../../package.json"
},
- "packageManager": "pnpm@8.9.2"
-}
\ No newline at end of file
+ "packageManager": "pnpm@8.9.0",
+ "ember-addon": {
+ "main": "addon-main.cjs",
+ "type": "addon",
+ "version": 1
+ },
+ "ember": {
+ "edition": "octane"
+ }
+}
diff --git a/packages/graph/rollup.config.mjs b/packages/graph/rollup.config.mjs
index 551c5147bc5..29a69782cbe 100644
--- a/packages/graph/rollup.config.mjs
+++ b/packages/graph/rollup.config.mjs
@@ -2,6 +2,8 @@ import { Addon } from '@embroider/addon-dev/rollup';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
+import { external } from '@warp-drive/internal-config/rollup/external.js';
+
const addon = new Addon({
srcDir: 'src',
destDir: 'addon',
@@ -12,11 +14,11 @@ export default {
// You can augment this if you need to.
output: addon.output(),
- external: [
+ external: external([
'@embroider/macros',
'@ember-data/store/-private',
'@ember/debug', // assert, deprecate
- ],
+ ]),
plugins: [
// These are the modules that users should be able to import from your
diff --git a/packages/graph/src/-private/-diff.ts b/packages/graph/src/-private/-diff.ts
index b777fe6964a..67397f11f09 100644
--- a/packages/graph/src/-private/-diff.ts
+++ b/packages/graph/src/-private/-diff.ts
@@ -1,9 +1,8 @@
import { assert, deprecate } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { DEPRECATE_NON_UNIQUE_PAYLOADS } from '@ember-data/deprecations';
import { DEBUG } from '@ember-data/env';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
import { isBelongsTo } from './-utils';
import { assertPolymorphicType } from './debug/assert-polymorphic-type';
@@ -208,10 +207,10 @@ export function computeLocalState(storage: CollectionEdge): StableRecordIdentifi
return storage.localState;
}
- let state = storage.remoteState.slice();
+ const state = storage.remoteState.slice();
storage.removals?.forEach((v) => {
- let index = state.indexOf(v);
+ const index = state.indexOf(v);
state.splice(index, 1);
});
diff --git a/packages/graph/src/-private/-edge-definition.ts b/packages/graph/src/-private/-edge-definition.ts
index fdca332c1a5..e4043e78558 100644
--- a/packages/graph/src/-private/-edge-definition.ts
+++ b/packages/graph/src/-private/-edge-definition.ts
@@ -1,10 +1,9 @@
import { assert } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { DEBUG } from '@ember-data/env';
import type Store from '@ember-data/store';
-import type { RelationshipSchema } from '@ember-data/store/-types/q/record-data-schemas';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { RelationshipSchema } from '@warp-drive/core-types/schema';
import { expandingGet, expandingSet, getStore } from './-utils';
import { assertInheritedSchema } from './debug/assert-polymorphic-type';
@@ -172,8 +171,8 @@ function syncMeta(definition: UpgradedMeta, inverseDefinition: UpgradedMeta) {
}
function upgradeMeta(meta: RelationshipSchema): UpgradedMeta {
- let niceMeta: UpgradedMeta = {} as UpgradedMeta;
- let options = meta.options;
+ const niceMeta: UpgradedMeta = {} as UpgradedMeta;
+ const options = meta.options;
niceMeta.kind = meta.kind;
niceMeta.key = meta.name;
niceMeta.type = meta.type;
@@ -196,18 +195,18 @@ function upgradeMeta(meta: RelationshipSchema): UpgradedMeta {
function assertConfiguration(info: EdgeDefinition, type: string, key: string) {
if (DEBUG) {
- let isSelfReferential = info.isSelfReferential;
+ const isSelfReferential = info.isSelfReferential;
if (isSelfReferential) {
return true;
}
- let _isRHS =
+ const _isRHS =
key === info.rhs_relationshipName &&
(type === info.rhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
(info.lhs_isPolymorphic && info.rhs_modelNames.includes(type))); // polymorphic
- let _isLHS =
+ const _isLHS =
key === info.lhs_relationshipName &&
(type === info.lhs_baseModelName || // base or non-polymorphic
// if the other side is polymorphic then we need to scan our modelNames
@@ -291,8 +290,8 @@ function assertConfiguration(info: EdgeDefinition, type: string, key: string) {
}
export function isLHS(info: EdgeDefinition, type: string, key: string): boolean {
- let isSelfReferential = info.isSelfReferential;
- let isRelationship = key === info.lhs_relationshipName;
+ const isSelfReferential = info.isSelfReferential;
+ const isRelationship = key === info.lhs_relationshipName;
if (DEBUG) {
assertConfiguration(info, type, key);
@@ -311,8 +310,8 @@ export function isLHS(info: EdgeDefinition, type: string, key: string): boolean
}
export function isRHS(info: EdgeDefinition, type: string, key: string): boolean {
- let isSelfReferential = info.isSelfReferential;
- let isRelationship = key === info.rhs_relationshipName;
+ const isSelfReferential = info.isSelfReferential;
+ const isRelationship = key === info.rhs_relationshipName;
if (DEBUG) {
assertConfiguration(info, type, key);
@@ -353,9 +352,9 @@ export function upgradeDefinition(
!isImplicit
);
- let relationships = storeWrapper.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
+ const relationships = storeWrapper.getSchemaDefinitionService().relationshipsDefinitionFor(identifier);
assert(`Expected to have a relationship definition for ${type} but none was found.`, relationships);
- let meta = relationships[propertyName];
+ const meta = relationships[propertyName];
if (!meta) {
// TODO potentially we should just be permissive here since this is an implicit relationship
@@ -413,11 +412,11 @@ export function upgradeDefinition(
inverseDefinition = null;
} else {
// CASE: We have an explicit inverse or were able to resolve one
- let inverseDefinitions = storeWrapper
+ const inverseDefinitions = storeWrapper
.getSchemaDefinitionService()
.relationshipsDefinitionFor({ type: inverseType });
assert(`Expected to have a relationship definition for ${inverseType} but none was found.`, inverseDefinitions);
- let metaFromInverse = inverseDefinitions[inverseKey];
+ const metaFromInverse = inverseDefinitions[inverseKey];
assert(
`Expected a relationship schema for '${inverseType}.${inverseKey}' to match the inverse of '${type}.${propertyName}', but no relationship schema was found.`,
metaFromInverse
@@ -495,8 +494,8 @@ export function upgradeDefinition(
cached.hasInverse !== false
);
- let _isLHS = cached.lhs_baseModelName === baseType;
- let modelNames = _isLHS ? cached.lhs_modelNames : cached.rhs_modelNames;
+ const _isLHS = cached.lhs_baseModelName === baseType;
+ const modelNames = _isLHS ? cached.lhs_modelNames : cached.rhs_modelNames;
// make this lookup easier in the future by caching the key
modelNames.push(type);
expandingSet(cache, type, propertyName, cached);
diff --git a/packages/graph/src/-private/-utils.ts b/packages/graph/src/-private/-utils.ts
index 28258d41936..ef2d6fbf0bd 100644
--- a/packages/graph/src/-private/-utils.ts
+++ b/packages/graph/src/-private/-utils.ts
@@ -1,15 +1,14 @@
import { assert, inspect, warn } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { LOG_GRAPH } from '@ember-data/debugging';
import type { Store } from '@ember-data/store/-private';
import { peekCache } from '@ember-data/store/-private';
import type { CacheCapabilitiesManager } from '@ember-data/store/-types/q/cache-store-wrapper';
-import { ResourceIdentifierObject } from '@ember-data/store/-types/q/ember-data-json-api';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { UpdateRelationshipOperation } from '@warp-drive/core-types/graph';
+import { ResourceIdentifierObject } from '@warp-drive/core-types/spec/raw';
import { UpgradedMeta } from './-edge-definition';
-import type { UpdateRelationshipOperation } from './-operations';
import { coerceId } from './coerce-id';
import type { CollectionEdge } from './edges/collection';
import type { ImplicitEdge } from './edges/implicit';
@@ -22,12 +21,12 @@ export function getStore(wrapper: CacheCapabilitiesManager | { _store: Store }):
}
export function expandingGet(cache: Record>, key1: string, key2: string): T | undefined {
- let mainCache = (cache[key1] = cache[key1] || Object.create(null));
+ const mainCache = (cache[key1] = cache[key1] || Object.create(null));
return mainCache[key2];
}
export function expandingSet(cache: Record>, key1: string, key2: string, value: T): void {
- let mainCache = (cache[key1] = cache[key1] || Object.create(null));
+ const mainCache = (cache[key1] = cache[key1] || Object.create(null));
mainCache[key2] = value;
}
@@ -149,7 +148,7 @@ export function removeIdentifierCompletelyFromRelationship(
} else if (isHasMany(relationship)) {
relationship.remoteMembers.delete(value);
relationship.additions?.delete(value);
- let wasInRemovals = relationship.removals?.delete(value);
+ const wasInRemovals = relationship.removals?.delete(value);
const canonicalIndex = relationship.remoteState.indexOf(value);
if (canonicalIndex !== -1) {
diff --git a/packages/graph/src/-private/debug/assert-polymorphic-type.ts b/packages/graph/src/-private/debug/assert-polymorphic-type.ts
index 3a61559a36d..7ffeb77b12c 100644
--- a/packages/graph/src/-private/debug/assert-polymorphic-type.ts
+++ b/packages/graph/src/-private/debug/assert-polymorphic-type.ts
@@ -1,7 +1,7 @@
import { assert } from '@ember/debug';
import { DEBUG } from '@ember-data/env';
import type { UpgradedMeta } from '../-edge-definition';
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { CacheCapabilitiesManager } from '@ember-data/store/-types/q/cache-store-wrapper';
/*
diff --git a/packages/graph/src/-private/edges/collection.ts b/packages/graph/src/-private/edges/collection.ts
index 7157dab3ff3..fcadc7673dc 100644
--- a/packages/graph/src/-private/edges/collection.ts
+++ b/packages/graph/src/-private/edges/collection.ts
@@ -1,7 +1,6 @@
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
-import type { CollectionRelationship } from '@ember-data/store/-types/cache/relationship';
-import type { Links, Meta, PaginationLinks } from '@ember-data/store/-types/q/ember-data-json-api';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { CollectionRelationship } from '@warp-drive/core-types/cache/relationship';
+import type { Links, Meta, PaginationLinks } from '@warp-drive/core-types/spec/raw';
import { computeLocalState } from '../-diff';
import type { UpgradedMeta } from '../-edge-definition';
@@ -53,7 +52,7 @@ export function createCollectionEdge(definition: UpgradedMeta, identifier: Stabl
}
export function legacyGetCollectionRelationshipData(source: CollectionEdge): CollectionRelationship {
- let payload: CollectionRelationship = {};
+ const payload: CollectionRelationship = {};
if (source.state.hasReceivedData) {
payload.data = computeLocalState(source);
diff --git a/packages/graph/src/-private/edges/implicit.ts b/packages/graph/src/-private/edges/implicit.ts
index 091dee757f4..89d7074eb5e 100644
--- a/packages/graph/src/-private/edges/implicit.ts
+++ b/packages/graph/src/-private/edges/implicit.ts
@@ -1,4 +1,4 @@
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { UpgradedMeta } from '../-edge-definition';
diff --git a/packages/graph/src/-private/edges/resource.ts b/packages/graph/src/-private/edges/resource.ts
index 98160e05ac1..e3156694e1d 100644
--- a/packages/graph/src/-private/edges/resource.ts
+++ b/packages/graph/src/-private/edges/resource.ts
@@ -1,7 +1,6 @@
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
-import { ResourceRelationship } from '@ember-data/store/-types/cache/relationship';
-import type { Links, Meta, PaginationLinks } from '@ember-data/store/-types/q/ember-data-json-api';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { ResourceRelationship } from '@warp-drive/core-types/cache/relationship';
+import type { Links, Meta, PaginationLinks } from '@warp-drive/core-types/spec/raw';
import type { UpgradedMeta } from '../-edge-definition';
import type { RelationshipState } from '../-state';
@@ -41,7 +40,7 @@ export function createResourceEdge(definition: UpgradedMeta, identifier: StableR
export function legacyGetResourceRelationshipData(source: ResourceEdge): ResourceRelationship {
let data: StableRecordIdentifier | null | undefined;
- let payload: ResourceRelationship = {};
+ const payload: ResourceRelationship = {};
if (source.localState) {
data = source.localState;
}
diff --git a/packages/graph/src/-private/graph.ts b/packages/graph/src/-private/graph.ts
index cdd86e433a3..a0708a4d816 100644
--- a/packages/graph/src/-private/graph.ts
+++ b/packages/graph/src/-private/graph.ts
@@ -1,23 +1,22 @@
import { assert } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { LOG_GRAPH } from '@ember-data/debugging';
import { DEBUG } from '@ember-data/env';
-import type { RelationshipDiff } from '@ember-data/store/-types/cache/cache';
-import type { CollectionRelationship, ResourceRelationship } from '@ember-data/store/-types/cache/relationship';
import { MergeOperation } from '@ember-data/store/-types/q/cache';
import type { CacheCapabilitiesManager } from '@ember-data/store/-types/q/cache-store-wrapper';
-
-import { rollbackRelationship } from './-diff';
-import type { EdgeCache, UpgradedMeta } from './-edge-definition';
-import { isLHS, upgradeDefinition } from './-edge-definition';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { RelationshipDiff } from '@warp-drive/core-types/cache';
+import type { CollectionRelationship, ResourceRelationship } from '@warp-drive/core-types/cache/relationship';
import type {
DeleteRecordOperation,
LocalRelationshipOperation,
RemoteRelationshipOperation,
UnknownOperation,
-} from './-operations';
+} from '@warp-drive/core-types/graph';
+
+import { rollbackRelationship } from './-diff';
+import type { EdgeCache, UpgradedMeta } from './-edge-definition';
+import { isLHS, upgradeDefinition } from './-edge-definition';
import {
assertValidRelationshipPayload,
forAllRelatedIdentifiers,
@@ -105,7 +104,7 @@ export class Graph {
}
has(identifier: StableRecordIdentifier, propertyName: string): boolean {
- let relationships = this.identifiers.get(identifier);
+ const relationships = this.identifiers.get(identifier);
if (!relationships) {
return false;
}
@@ -269,7 +268,7 @@ export class Graph {
// cleans up the graph but retains some nodes
// to allow for rematerialization
Object.keys(relationships).forEach((key) => {
- let rel = relationships[key]!;
+ const rel = relationships[key]!;
if (!rel) {
return;
}
@@ -556,7 +555,7 @@ export class Graph {
}
this._willSyncLocal = false;
- let updated = this._updatedRelationships;
+ const updated = this._updatedRelationships;
this._updatedRelationships = new Set();
updated.forEach((rel) => notifyChange(this, rel.identifier, rel.definition.key));
}
@@ -656,7 +655,7 @@ function notifyInverseOfDematerialization(
return;
}
- let relationship = graph.get(inverseIdentifier, inverseKey);
+ const relationship = graph.get(inverseIdentifier, inverseKey);
assert(`expected no implicit`, !isImplicit(relationship));
// For remote members, it is possible that inverseRecordData has already been associated to
@@ -765,7 +764,7 @@ function addPending(
definition: UpgradedMeta,
op: RemoteRelationshipOperation & { field: string }
): void {
- let lc = (cache[definition.kind as 'hasMany' | 'belongsTo'] =
+ const lc = (cache[definition.kind as 'hasMany' | 'belongsTo'] =
cache[definition.kind as 'hasMany' | 'belongsTo'] || new Map>());
let lc2 = lc.get(definition.inverseType);
if (!lc2) {
diff --git a/packages/graph/src/-private/normalize-link.ts b/packages/graph/src/-private/normalize-link.ts
index 56b1472b1fe..c05a2c99ce2 100644
--- a/packages/graph/src/-private/normalize-link.ts
+++ b/packages/graph/src/-private/normalize-link.ts
@@ -1,4 +1,4 @@
-import type { Link, LinkObject } from '@ember-data/store/-types/q/ember-data-json-api';
+import type { Link, LinkObject } from '@warp-drive/core-types/spec/raw';
/*
This method normalizes a link to an "links object". If the passed link is
diff --git a/packages/graph/src/-private/operations/add-to-related-records.ts b/packages/graph/src/-private/operations/add-to-related-records.ts
index aeb7fe5d82f..65d37e06f35 100644
--- a/packages/graph/src/-private/operations/add-to-related-records.ts
+++ b/packages/graph/src/-private/operations/add-to-related-records.ts
@@ -1,9 +1,9 @@
import { assert } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { AddToRelatedRecordsOperation } from '@warp-drive/core-types/graph';
import { _addLocal } from '../-diff';
-import type { AddToRelatedRecordsOperation } from '../-operations';
import { isHasMany, notifyChange } from '../-utils';
import type { CollectionEdge } from '../edges/collection';
import type { Graph } from '../graph';
diff --git a/packages/graph/src/-private/operations/remove-from-related-records.ts b/packages/graph/src/-private/operations/remove-from-related-records.ts
index 397c36cca08..a7d7536065e 100644
--- a/packages/graph/src/-private/operations/remove-from-related-records.ts
+++ b/packages/graph/src/-private/operations/remove-from-related-records.ts
@@ -1,9 +1,9 @@
import { assert } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { RemoveFromRelatedRecordsOperation } from '@warp-drive/core-types/graph';
import { _removeLocal } from '../-diff';
-import type { RemoveFromRelatedRecordsOperation } from '../-operations';
import { isHasMany, notifyChange } from '../-utils';
import type { CollectionEdge } from '../edges/collection';
import type { Graph } from '../graph';
diff --git a/packages/graph/src/-private/operations/replace-related-record.ts b/packages/graph/src/-private/operations/replace-related-record.ts
index f6bbda97bb5..58b7efd8366 100644
--- a/packages/graph/src/-private/operations/replace-related-record.ts
+++ b/packages/graph/src/-private/operations/replace-related-record.ts
@@ -1,11 +1,10 @@
import { assert, deprecate } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE } from '@ember-data/deprecations';
import { DEBUG } from '@ember-data/env';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { ReplaceRelatedRecordOperation } from '@warp-drive/core-types/graph';
-import type { ReplaceRelatedRecordOperation } from '../-operations';
import { isBelongsTo, isNew, notifyChange } from '../-utils';
import { assertPolymorphicType } from '../debug/assert-polymorphic-type';
import type { Graph } from '../graph';
diff --git a/packages/graph/src/-private/operations/replace-related-records.ts b/packages/graph/src/-private/operations/replace-related-records.ts
index ff0b57f3b74..86188fbd6cd 100644
--- a/packages/graph/src/-private/operations/replace-related-records.ts
+++ b/packages/graph/src/-private/operations/replace-related-records.ts
@@ -1,12 +1,11 @@
import { assert, deprecate } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { DEPRECATE_RELATIONSHIP_REMOTE_UPDATE_CLEARING_LOCAL_STATE } from '@ember-data/deprecations';
import { DEBUG } from '@ember-data/env';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { ReplaceRelatedRecordsOperation } from '@warp-drive/core-types/graph';
import { _addLocal, _removeLocal, _removeRemote, diffCollection } from '../-diff';
-import type { ReplaceRelatedRecordsOperation } from '../-operations';
import { isBelongsTo, isHasMany, isNew, notifyChange } from '../-utils';
import { assertPolymorphicType } from '../debug/assert-polymorphic-type';
import type { CollectionEdge } from '../edges/collection';
diff --git a/packages/graph/src/-private/operations/update-relationship.ts b/packages/graph/src/-private/operations/update-relationship.ts
index c0640c01b0e..48f94e2213a 100644
--- a/packages/graph/src/-private/operations/update-relationship.ts
+++ b/packages/graph/src/-private/operations/update-relationship.ts
@@ -1,14 +1,10 @@
import { assert, warn } from '@ember/debug';
-import type { StableRecordIdentifier } from '@warp-drive/core';
-
import { IdentifierCache } from '@ember-data/store/-private/caches/identifier-cache';
-import type {
- ExistingResourceIdentifierObject,
- NewResourceIdentifierObject,
-} from '@ember-data/store/-types/q/ember-data-json-api';
+import type { StableRecordIdentifier } from '@warp-drive/core-types';
+import type { UpdateRelationshipOperation } from '@warp-drive/core-types/graph';
+import type { ExistingResourceIdentifierObject, NewResourceIdentifierObject } from '@warp-drive/core-types/spec/raw';
-import type { UpdateRelationshipOperation } from '../-operations';
import { isBelongsTo, isHasMany, notifyChange } from '../-utils';
import type { Graph } from '../graph';
import _normalizeLink from '../normalize-link';
@@ -91,12 +87,12 @@ export default function updateRelationshipOperation(graph: Graph, op: UpdateRela
}
if (payload.links) {
- let originalLinks = relationship.links;
+ const originalLinks = relationship.links;
relationship.links = payload.links;
if (payload.links.related) {
- let relatedLink = _normalizeLink(payload.links.related);
- let currentLink = originalLinks && originalLinks.related ? _normalizeLink(originalLinks.related) : null;
- let currentLinkHref = currentLink ? currentLink.href : null;
+ const relatedLink = _normalizeLink(payload.links.related);
+ const currentLink = originalLinks && originalLinks.related ? _normalizeLink(originalLinks.related) : null;
+ const currentLinkHref = currentLink ? currentLink.href : null;
if (relatedLink && relatedLink.href && relatedLink.href !== currentLinkHref) {
warn(
@@ -132,7 +128,7 @@ export default function updateRelationshipOperation(graph: Graph, op: UpdateRela
*/
relationship.state.hasFailedLoadAttempt = false;
if (hasRelationshipDataProperty) {
- let relationshipIsEmpty = payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0);
+ const relationshipIsEmpty = payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0);
// we don't need to notify here as the update op we pushed in above will notify once
// membership is in the correct state.
diff --git a/packages/graph/tsconfig.json b/packages/graph/tsconfig.json
new file mode 100644
index 00000000000..ff2940749aa
--- /dev/null
+++ b/packages/graph/tsconfig.json
@@ -0,0 +1,44 @@
+{
+ "include": [
+ "src/**/*",
+ ],
+ "baseUrl": ".",
+ "compilerOptions": {
+ "lib": ["DOM", "ESNext"],
+ "module": "esnext",
+ "target": "esnext",
+ "moduleResolution": "bundler",
+ "moduleDetection": "force",
+ "rootDir": "src",
+ "strict": true,
+ "downlevelIteration": true,
+ "skipLibCheck": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "noEmit": false,
+ "noImplicitOverride": true,
+
+ // Enable faster builds
+ // but causes us to not rebuild properly
+ "incremental": false,
+
+ "declaration": true,
+ "declarationMap": true,
+ "declarationDir": "unstable-preview-types",
+ "emitDeclarationOnly": true,
+ "inlineSourceMap": true,
+ "inlineSources": true,
+ "types": [
+ "ember-source/types"
+ ],
+
+ "paths": {
+ "@ember-data/deprecations": ["../private-build-infra/virtual-packages/deprecations.d.ts"],
+ "@ember-data/packages": ["../private-build-infra/virtual-packages/packages.d.ts"],
+ "@ember-data/canary-features": ["../private-build-infra/virtual-packages/canary-features.d.ts"],
+ "@ember-data/debugging": ["../private-build-infra/virtual-packages/debugging.d.ts"],
+ "@ember-data/env": ["../private-build-infra/virtual-packages/env.d.ts"],
+ }
+ },
+}
diff --git a/packages/holodeck/.eslintrc.cjs b/packages/holodeck/.eslintrc.cjs
new file mode 100644
index 00000000000..94f092444d8
--- /dev/null
+++ b/packages/holodeck/.eslintrc.cjs
@@ -0,0 +1,26 @@
+const imports = require('@warp-drive/internal-config/eslint/imports.cjs');
+const parser = require('@warp-drive/internal-config/eslint/parser.cjs');
+const isolation = require('@warp-drive/internal-config/eslint/isolation.cjs');
+const ignore = require('@warp-drive/internal-config/eslint/ignore.cjs');
+const node = require('@warp-drive/internal-config/eslint/node.cjs');
+const base = require('@warp-drive/internal-config/eslint/base.cjs');
+const typescript = require('@warp-drive/internal-config/eslint/typescript.cjs');
+
+module.exports = {
+ ...parser.defaults(),
+
+ plugins: [...base.plugins(), ...imports.plugins()],
+ extends: [...base.extend()],
+ rules: Object.assign(
+ base.rules(),
+ imports.rules(),
+ isolation.rules({
+ allowedImports: ['@ember/debug'],
+ }),
+ {}
+ ),
+
+ ignorePatterns: ignore.ignoreRules(),
+
+ overrides: [node.defaults(), typescript.defaults()],
+};
diff --git a/packages/holodeck/client/index.ts b/packages/holodeck/client/index.ts
index ff5989a6b4a..68f7dfb4e3f 100644
--- a/packages/holodeck/client/index.ts
+++ b/packages/holodeck/client/index.ts
@@ -2,13 +2,11 @@ import type { Handler, NextFn, RequestContext, RequestInfo, StructuredDataDocume
import type { ScaffoldGenerator } from './mock';
-const TEST_IDS = new WeakMap